Skip to content

Commit 4805ef5

Browse files
committed
Bugfixes & Improvements (17.0.4)
1 parent ba0be11 commit 4805ef5

File tree

3 files changed

+323
-115
lines changed

3 files changed

+323
-115
lines changed

src/main/java/com/griefprevention/visualization/impl/FakeBlockVisualization.java

Lines changed: 143 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@
2626
public class FakeBlockVisualization extends BlockBoundaryVisualization
2727
{
2828

29-
protected final boolean waterTransparent;
30-
3129
/**
3230
* Construct a new {@code FakeBlockVisualization}.
3331
*
@@ -37,9 +35,6 @@ public class FakeBlockVisualization extends BlockBoundaryVisualization
3735
*/
3836
public FakeBlockVisualization(@NotNull World world, @NotNull IntVector visualizeFrom, int height) {
3937
super(world, visualizeFrom, height);
40-
41-
// Water is considered transparent based on whether the visualization is initiated in water.
42-
waterTransparent = visualizeFrom.toBlock(world).getType() == Material.WATER;
4338
}
4439

4540
@Override
@@ -49,9 +44,9 @@ public FakeBlockVisualization(@NotNull World world, @NotNull IntVector visualize
4944
return switch (boundary.type())
5045
{
5146
case SUBDIVISION_3D -> addExactBlockElement(Material.IRON_BLOCK.createBlockData());
52-
case SUBDIVISION -> addBlockElement(Material.IRON_BLOCK.createBlockData());
47+
case SUBDIVISION -> addExactBlockElement(Material.IRON_BLOCK.createBlockData());
5348
case ADMIN_CLAIM -> {
54-
BlockData orangeGlass = Material.ORANGE_STAINED_GLASS.createBlockData();
49+
BlockData orangeGlass = Material.GLOWSTONE.createBlockData();
5550
yield addBlockElement(orangeGlass);
5651
}
5752
case INITIALIZE_ZONE -> addBlockElement(Material.DIAMOND_BLOCK.createBlockData());
@@ -72,7 +67,7 @@ public FakeBlockVisualization(@NotNull World world, @NotNull IntVector visualize
7267
return switch (boundary.type())
7368
{
7469
case ADMIN_CLAIM -> addBlockElement(Material.PUMPKIN.createBlockData());
75-
case SUBDIVISION -> addBlockElement(Material.WHITE_WOOL.createBlockData());
70+
case SUBDIVISION -> addExactBlockElement(Material.WHITE_WOOL.createBlockData());
7671
case SUBDIVISION_3D -> addExactBlockElement(Material.WHITE_WOOL.createBlockData()); // exact placement for 3D sides
7772
case INITIALIZE_ZONE -> addBlockElement(Material.DIAMOND_BLOCK.createBlockData());
7873
case CONFLICT_ZONE -> addBlockElement(Material.NETHERRACK.createBlockData());
@@ -174,7 +169,7 @@ private void drawMainClaim(@NotNull Player player, @NotNull Boundary boundary) {
174169
}
175170

176171
// Add side markers along Z axis (east and west sides) - following terrain
177-
for (int z = Math.max(minZ + STEP, minZ + STEP); z < maxZ - STEP / 2 && z < maxZ - STEP / 2; z += STEP) {
172+
for (int z = Math.max(minZ + STEP, minZ + STEP); z < maxZ - STEP / 2 && z < maxZ - 2; z += STEP) {
178173
if (z > minZ + 1 && z < maxZ - 1) {
179174
int terrainY = getSurfaceYAt(minX, z, player);
180175
addDisplayedForMainClaim(displayZone, new IntVector(minX, terrainY, z), addSide, boundary.type()); // West side
@@ -261,58 +256,108 @@ private void draw2DSubdivision(@NotNull Player player, @NotNull Boundary boundar
261256

262257
// From each corner, place one white wool block along the interior X side and one along the interior Z side
263258
// NW corner interior directions: +X, +Z
264-
if (minX + 1 <= maxX) addDisplayLocation(new IntVector(minX + 1, nwY, minZ), wool, boundary.type());
265-
if (minZ + 1 <= maxZ) addDisplayLocation(new IntVector(minX, nwY, minZ + 1), wool, boundary.type());
259+
if (minX + 1 <= maxX) {
260+
int stubY = getSurfaceYAt(minX + 1, minZ, player);
261+
addDisplayLocation(new IntVector(minX + 1, stubY, minZ), wool, boundary.type());
262+
}
263+
if (minZ + 1 <= maxZ) {
264+
int stubY = getSurfaceYAt(minX, minZ + 1, player);
265+
addDisplayLocation(new IntVector(minX, stubY, minZ + 1), wool, boundary.type());
266+
}
266267

267268
// SW corner interior directions: +X, -Z
268-
if (minX + 1 <= maxX) addDisplayLocation(new IntVector(minX + 1, swY, maxZ), wool, boundary.type());
269-
if (maxZ - 1 >= minZ) addDisplayLocation(new IntVector(minX, swY, maxZ - 1), wool, boundary.type());
269+
if (minX + 1 <= maxX) {
270+
int stubY = getSurfaceYAt(minX + 1, maxZ, player);
271+
addDisplayLocation(new IntVector(minX + 1, stubY, maxZ), wool, boundary.type());
272+
}
273+
if (maxZ - 1 >= minZ) {
274+
int stubY = getSurfaceYAt(minX, maxZ - 1, player);
275+
addDisplayLocation(new IntVector(minX, stubY, maxZ - 1), wool, boundary.type());
276+
}
270277

271278
// NE corner interior directions: -X, +Z
272-
if (maxX - 1 >= minX) addDisplayLocation(new IntVector(maxX - 1, neY, minZ), wool, boundary.type());
273-
if (minZ + 1 <= maxZ) addDisplayLocation(new IntVector(maxX, neY, minZ + 1), wool, boundary.type());
279+
if (maxX - 1 >= minX) {
280+
int stubY = getSurfaceYAt(maxX - 1, minZ, player);
281+
addDisplayLocation(new IntVector(maxX - 1, stubY, minZ), wool, boundary.type());
282+
}
283+
if (minZ + 1 <= maxZ) {
284+
int stubY = getSurfaceYAt(maxX, minZ + 1, player);
285+
addDisplayLocation(new IntVector(maxX, stubY, minZ + 1), wool, boundary.type());
286+
}
274287

275288
// SE corner interior directions: -X, -Z
276-
if (maxX - 1 >= minX) addDisplayLocation(new IntVector(maxX - 1, seY, maxZ), wool, boundary.type());
277-
if (maxZ - 1 >= minZ) addDisplayLocation(new IntVector(maxX, seY, maxZ - 1), wool, boundary.type());
289+
if (maxX - 1 >= minX) {
290+
int stubY = getSurfaceYAt(maxX - 1, maxZ, player);
291+
addDisplayLocation(new IntVector(maxX - 1, stubY, maxZ), wool, boundary.type());
292+
}
293+
if (maxZ - 1 >= minZ) {
294+
int stubY = getSurfaceYAt(maxX, maxZ - 1, player);
295+
addDisplayLocation(new IntVector(maxX, stubY, maxZ - 1), wool, boundary.type());
296+
}
278297
}
279298

280299
/**
281-
* Gets the surface Y coordinate at a specific x,z position
282-
* For main claims, allows 1-block occurrences to pass through to the next block below
300+
* Gets the surface Y coordinate at a specific x,z position with grass block handling
301+
* This ensures visualizations snap to grass_block instead of grass, matching GlowingVisualization
283302
*/
284303
private int getSurfaceYAt(int x, int z, Player player) {
285304
if (!world.isChunkLoaded(x >> 4, z >> 4)) {
286305
return player != null ? player.getLocation().getBlockY() - 1 : world.getMinHeight() + 63;
287306
}
288-
307+
289308
// Start from the highest block at this x,z position
290309
int y = world.getMaxHeight() - 1;
291-
boolean foundSolid = false;
292-
293-
// Find the highest non-air, non-transparent block
310+
311+
// Find the highest non-air block (including water as valid surface)
294312
while (y >= world.getMinHeight()) {
295313
Block block = world.getBlockAt(x, y, z);
296-
297-
// If we find a solid block after finding air, we've found the surface
298-
if (foundSolid && !isTransparent(block)) {
299-
// For main claims, we want to allow 1-block occurrences to pass through
300-
// So we return the block below the surface
301-
return y;
302-
}
303-
304-
// If we find air, mark that we've found the surface
305-
if (block.getType() == Material.AIR) {
306-
foundSolid = true;
314+
315+
// If we find a non-air block, we've found the surface
316+
if (block.getType() != Material.AIR) {
317+
// For transparent blocks (except water), find the actual surface below
318+
if (isTransparent(block) && block.getType() != Material.WATER) {
319+
return findSurfaceBelowTransparentBlocks(x, z, y);
320+
}
321+
return y; // Return the Y of the highest non-air block (e.g., water, glass, or solid)
307322
}
308-
323+
309324
y--;
310325
}
311-
326+
312327
// If we get here, return the minimum height
313328
return world.getMinHeight();
314329
}
315330

331+
/**
332+
* Finds the actual surface Y coordinate below a stack of transparent blocks
333+
* @param x The x coordinate
334+
* @param z The z coordinate
335+
* @param startY The Y coordinate where transparent blocks start
336+
* @return The Y coordinate of the actual surface below the transparent blocks
337+
*/
338+
private int findSurfaceBelowTransparentBlocks(int x, int z, int startY) {
339+
int y = startY;
340+
341+
// Count how many transparent blocks are stacked
342+
int transparentBlockCount = 0;
343+
while (y >= world.getMinHeight() && isTransparent(world.getBlockAt(x, y, z)) && world.getBlockAt(x, y, z).getType() != Material.WATER) {
344+
transparentBlockCount++;
345+
y--;
346+
}
347+
348+
// The surface is the first non-transparent block we find
349+
Block surfaceBlock = world.getBlockAt(x, y, z);
350+
351+
// If we found a valid surface block, return its Y coordinate
352+
if (surfaceBlock.getType() != Material.AIR) {
353+
return y;
354+
}
355+
356+
// If no valid surface found, return the original Y minus the transparent block count
357+
// This handles cases where transparent blocks are floating above air
358+
return startY - transparentBlockCount;
359+
}
360+
316361
/**
317362
* Add a display element if accessible (override to use terrain-level placement for main claims)
318363
*/
@@ -380,10 +425,20 @@ private void addDisplayLocation(@NotNull IntVector coordinate, @NotNull BlockDat
380425
coordinate.x() >= this.displayZone.getMinX() && coordinate.x() <= this.displayZone.getMaxX() &&
381426
coordinate.y() >= this.displayZone.getMinY() && coordinate.y() <= this.displayZone.getMaxY() &&
382427
coordinate.z() >= this.displayZone.getMinZ() && coordinate.z() <= this.displayZone.getMaxZ()) {
383-
// Use the explicit block data provided by the caller (e.g., iron for corners),
384-
// so corners render correctly and sides use their own side material via addSideElements.
385-
Consumer<@NotNull IntVector> addElement = addBlockElement(blockData);
386-
addElement.accept(coordinate);
428+
// For 2D subdivisions, use exact placement to avoid moving blocks from glass surfaces
429+
// Other visualization types use getVisibleLocation for terrain snapping
430+
if (blockData.getMaterial() == Material.IRON_BLOCK || blockData.getMaterial() == Material.WHITE_WOOL) {
431+
// This is a 2D subdivision - use exact placement
432+
Block exactLocation = coordinate.toBlock(world);
433+
elements.add(new FakeBlockElement(coordinate, exactLocation.getBlockData(), blockData));
434+
} else {
435+
// Other visualization types - use terrain snapping
436+
Block visibleLocation = getVisibleLocation(coordinate);
437+
int x = coordinate.x();
438+
int y = visibleLocation.getY();
439+
int z = coordinate.z();
440+
elements.add(new FakeBlockElement(new IntVector(x, y, z), visibleLocation.getBlockData(), blockData));
441+
}
387442
}
388443
}
389444

@@ -497,18 +552,20 @@ private void addDisplayed3D(
497552
}
498553

499554
/**
500-
* Create a {@link Consumer} that adds an appropriate {@link FakeBlockElement} for the given {@link IntVector}.
555+
* Create a {@link Consumer} that adds a {@link FakeBlockElement} at a terrain-snapped location (not exact coordinates).
556+
* This is used for most visualization types to ensure blocks appear at visible surface levels.
501557
*
502558
* @param fakeData the fake {@link BlockData}
503-
* @return the function for determining a visible fake block location
559+
* @return the function for placing a fake block at a terrain-snapped location
504560
*/
505561
private @NotNull Consumer<@NotNull IntVector> addBlockElement(@NotNull BlockData fakeData)
506562
{
507563
return vector -> {
508-
// Obtain visible location from starting point.
509564
Block visibleLocation = getVisibleLocation(vector);
510-
// Create an element using our fake data and the determined block's real data.
511-
elements.add(new FakeBlockElement(new IntVector(visibleLocation), visibleLocation.getBlockData(), fakeData));
565+
int x = vector.x();
566+
int y = visibleLocation.getY();
567+
int z = vector.z();
568+
elements.add(new FakeBlockElement(new IntVector(x, y, z), visibleLocation.getBlockData(), fakeData));
512569
};
513570
}
514571

@@ -528,6 +585,20 @@ private void addDisplayed3D(
528585
};
529586
}
530587

588+
/**
589+
* Checks if a material is a glass block that should be treated as a solid surface
590+
* @param material The material to check
591+
* @return true if the material is a glass block
592+
*/
593+
private boolean isGlassBlock(Material material) {
594+
return material == Material.GLASS ||
595+
material == Material.GLASS_PANE ||
596+
material == Material.TINTED_GLASS ||
597+
material.name().contains("GLASS") ||
598+
material.name().endsWith("_GLASS") ||
599+
material.name().endsWith("_GLASS_PANE");
600+
}
601+
531602
/**
532603
* Find a location that should be visible to players. This causes the visualization to "cling" to the ground.
533604
*
@@ -537,11 +608,24 @@ private void addDisplayed3D(
537608
private Block getVisibleLocation(@NotNull IntVector vector)
538609
{
539610
Block block = vector.toBlock(world);
611+
612+
// Special handling for water surfaces
613+
if (block.getType() == Material.WATER) {
614+
return block; // Stay at water surface
615+
}
616+
617+
// Check if the block is glass - if so, treat it as solid and stay on it
618+
if (isGlassBlock(block.getType())) {
619+
return block; // Stay at glass surface
620+
}
621+
540622
BlockFace direction = (isTransparent(block)) ? BlockFace.DOWN : BlockFace.UP;
541623

542624
while (block.getY() >= world.getMinHeight() &&
543625
block.getY() < world.getMaxHeight() - 1 &&
544-
(!isTransparent(block.getRelative(BlockFace.UP)) || isTransparent(block)))
626+
(!isTransparent(block.getRelative(BlockFace.UP)) || isTransparent(block)) &&
627+
block.getType() != Material.WATER &&
628+
!isGlassBlock(block.getType()))
545629
{
546630
block = block.getRelative(direction);
547631
}
@@ -559,13 +643,23 @@ protected boolean isTransparent(@NotNull Block block)
559643
{
560644
Material blockMaterial = block.getType();
561645

562-
// Custom per-material definitions.
646+
// Check if it's glass first - glass should be treated as solid for visualization purposes
647+
if (isGlassBlock(blockMaterial)) {
648+
return false; // Glass is not transparent for visualization purposes
649+
}
650+
651+
// Custom per-material definitions matching GlowingVisualization
563652
switch (blockMaterial)
564653
{
565654
case WATER:
566-
return waterTransparent;
655+
return true; // Treat water as transparent so visualizations float on water surface
656+
case SNOW_BLOCK:
657+
return true;
567658
case SNOW:
568659
return false;
660+
default:
661+
// Fall through to the general logic below
662+
break;
569663
}
570664

571665
if (blockMaterial.isAir()
@@ -576,7 +670,7 @@ protected boolean isTransparent(@NotNull Block block)
576670
|| Tag.WALL_SIGNS.isTagged(blockMaterial))
577671
return true;
578672

579-
return block.getType().isTransparent();
673+
return !block.getType().isOccluding();
580674
}
581675

582676
}

0 commit comments

Comments
 (0)