8989import net .minecraft .util .ARGB ;
9090import net .minecraft .util .Mth ;
9191import net .minecraft .util .RandomSource ;
92+ import net .minecraft .util .Util ;
9293import net .minecraft .world .SimpleContainer ;
9394import net .minecraft .world .item .Item ;
9495import net .minecraft .world .item .enchantment .Enchantment ;
@@ -201,6 +202,36 @@ private static double tileSizePixels() {
201202 return TilePos .TILE_SIZE_CHUNKS * SCALED_CHUNK_SIZE * Configs .PixelsPerBiome ;
202203 }
203204
205+ private boolean isWorldBorderEnabled () {
206+ return Configs .WorldBorder > 0 ;
207+ }
208+
209+ private double worldBorderHalfBlocks () {
210+ return Configs .WorldBorder ;
211+ }
212+
213+ private double worldBorderHalfQuart () {
214+ return Configs .WorldBorder / 4.0D ;
215+ }
216+
217+ private boolean isWithinWorldBorder (BlockPos pos ) {
218+ if (!this .isWorldBorderEnabled ()) {
219+ return true ;
220+ }
221+ double half = this .worldBorderHalfBlocks ();
222+ return Math .abs (pos .getX ()) <= half && Math .abs (pos .getZ ()) <= half ;
223+ }
224+
225+ private QuartPos2f clampCenterToWorldBorder (QuartPos2f newCenter ) {
226+ if (!this .isWorldBorderEnabled ()) {
227+ return newCenter ;
228+ }
229+ double halfBorderQuart = this .worldBorderHalfQuart ();
230+ float clampedX = (float ) Math .clamp ((double ) newCenter .x (), -halfBorderQuart , halfBorderQuart );
231+ float clampedZ = (float ) Math .clamp ((double ) newCenter .z (), -halfBorderQuart , halfBorderQuart );
232+ return new QuartPos2f (clampedX , clampedZ );
233+ }
234+
204235 private static final Object2ObjectMap <WorldIdentifier , Object2ObjectMap <TilePos , int []>> biomeDataCache = new Object2ObjectOpenHashMap <>();
205236 private static final Object2ObjectMap <WorldIdentifier , Object2ObjectMap <ChunkPos , ChunkStructureData >> structureDataCache = new Object2ObjectOpenHashMap <>();
206237 public static final Object2ObjectMap <WorldIdentifier , TwoDTree > strongholdDataCache = new Object2ObjectOpenHashMap <>();
@@ -300,6 +331,12 @@ public static void reopenIfOpen(int generatorFlags) {
300331 private @ Nullable FeatureWidget markerWidget = null ;
301332 private @ Nullable ChestLootWidget chestLootWidget = null ;
302333 private @ Nullable ContextMenu contextMenu = null ;
334+ private long lastMapClickTime = 0L ;
335+ private double lastMapClickX = Double .NaN ;
336+ private double lastMapClickY = Double .NaN ;
337+
338+ private static final long DOUBLE_CLICK_MS = 250L ;
339+ private static final double DOUBLE_CLICK_DISTANCE_SQ = 16.0D ;
303340
304341 private static final Identifier DIRECTION_ARROW_TEXTURE = Identifier .fromNamespaceAndPath (SeedMapper .MOD_ID , "textures/gui/arrow.png" );
305342
@@ -422,35 +459,41 @@ private void drawTile(GuiGraphics guiGraphics, Tile tile) {
422459 TilePos tilePos = tile .pos ();
423460 QuartPos2f relTileQuart = QuartPos2f .fromQuartPos (QuartPos2 .fromTilePos (tilePos )).subtract (this .centerQuart );
424461 double tileSizePixels = tileSizePixels ();
425- double minX = this .centerX + Configs .PixelsPerBiome * relTileQuart .x ();
426- double minY = this .centerY + Configs .PixelsPerBiome * relTileQuart .z ();
427- double maxX = minX + tileSizePixels ;
428- double maxY = minY + tileSizePixels ;
429-
430- if (maxX < this .horizontalPadding () || minX > this .horizontalPadding () + this .seedMapWidth ) {
431- return ;
432- }
433- if (maxY < this .verticalPadding () || minY > this .verticalPadding () + this .seedMapHeight ) {
462+ double tileMinX = this .centerX + Configs .PixelsPerBiome * relTileQuart .x ();
463+ double tileMinY = this .centerY + Configs .PixelsPerBiome * relTileQuart .z ();
464+ double tileMaxX = tileMinX + tileSizePixels ;
465+ double tileMaxY = tileMinY + tileSizePixels ;
466+
467+ double limitMinX = this .horizontalPadding ();
468+ double limitMaxX = this .horizontalPadding () + this .seedMapWidth ;
469+ double limitMinY = this .verticalPadding ();
470+ double limitMaxY = this .verticalPadding () + this .seedMapHeight ;
471+
472+ if (this .isWorldBorderEnabled ()) {
473+ double halfBorderQuart = this .worldBorderHalfQuart ();
474+ double borderMinX = this .centerX + Configs .PixelsPerBiome * (-halfBorderQuart - this .centerQuart .x ());
475+ double borderMaxX = this .centerX + Configs .PixelsPerBiome * (halfBorderQuart - this .centerQuart .x ());
476+ double borderMinY = this .centerY + Configs .PixelsPerBiome * (-halfBorderQuart - this .centerQuart .z ());
477+ double borderMaxY = this .centerY + Configs .PixelsPerBiome * (halfBorderQuart - this .centerQuart .z ());
478+ limitMinX = Math .max (limitMinX , borderMinX );
479+ limitMaxX = Math .min (limitMaxX , borderMaxX );
480+ limitMinY = Math .max (limitMinY , borderMinY );
481+ limitMaxY = Math .min (limitMaxY , borderMaxY );
482+ }
483+
484+ double minX = Math .max (tileMinX , limitMinX );
485+ double maxX = Math .min (tileMaxX , limitMaxX );
486+ double minY = Math .max (tileMinY , limitMinY );
487+ double maxY = Math .min (tileMaxY , limitMaxY );
488+
489+ if (maxX <= minX || maxY <= minY ) {
434490 return ;
435491 }
436492
437- float u0 , u1 , v0 , v1 ;
438- if (minX < this .horizontalPadding ()) {
439- u0 = (float ) ((this .horizontalPadding () - minX ) / tileSizePixels );
440- minX = this .horizontalPadding ();
441- } else u0 = 0 ;
442- if (maxX > this .horizontalPadding () + this .seedMapWidth ) {
443- u1 = 1 - (float ) ((maxX - this .horizontalPadding () - this .seedMapWidth ) / tileSizePixels );
444- maxX = this .horizontalPadding () + this .seedMapWidth ;
445- } else u1 = 1 ;
446- if (minY < this .verticalPadding ()) {
447- v0 = (float ) ((this .verticalPadding () - minY ) / tileSizePixels );
448- minY = this .verticalPadding ();
449- } else v0 = 0 ;
450- if (maxY > this .verticalPadding () + this .seedMapHeight ) {
451- v1 = 1 - (float ) ((maxY - this .verticalPadding () - this .seedMapHeight ) / tileSizePixels );
452- maxY = this .verticalPadding () + this .seedMapHeight ;
453- } else v1 = 1 ;
493+ float u0 = (float ) ((minX - tileMinX ) / tileSizePixels );
494+ float u1 = (float ) ((maxX - tileMinX ) / tileSizePixels );
495+ float v0 = (float ) ((minY - tileMinY ) / tileSizePixels );
496+ float v1 = (float ) ((maxY - tileMinY ) / tileSizePixels );
454497 int drawMinX = (int ) Math .round (minX );
455498 int drawMinY = (int ) Math .round (minY );
456499 int drawMaxX = (int ) Math .round (maxX );
@@ -511,6 +554,10 @@ private Tile createSlimeChunkTile(TilePos tilePos, BitSet slimeChunkData) {
511554 }
512555 }
513556
557+ if (!this .isWithinWorldBorder (pos )) {
558+ return null ;
559+ }
560+
514561 FeatureWidget widget = new FeatureWidget (feature , variantTexture , pos );
515562 if (!widget .withinBounds ()) {
516563 return null ;
@@ -1257,7 +1304,7 @@ private String getBiomeName(BlockPos pos) {
12571304 }
12581305
12591306 protected void moveCenter (QuartPos2f newCenter ) {
1260- this .centerQuart = newCenter ;
1307+ this .centerQuart = this . clampCenterToWorldBorder ( newCenter ) ;
12611308
12621309 this .featureWidgets .removeIf (widget -> {
12631310 widget .updatePosition ();
@@ -1338,6 +1385,27 @@ public boolean mouseClicked(MouseButtonEvent mouseButtonEvent, boolean doubleCli
13381385 return true ;
13391386 }
13401387 int button = mouseButtonEvent .button ();
1388+ if (button == InputConstants .MOUSE_BUTTON_LEFT ) {
1389+ double mouseX = mouseButtonEvent .x ();
1390+ double mouseY = mouseButtonEvent .y ();
1391+ boolean withinMap = mouseX >= this .horizontalPadding () && mouseX <= this .horizontalPadding () + this .seedMapWidth
1392+ && mouseY >= this .verticalPadding () && mouseY <= this .verticalPadding () + this .seedMapHeight ;
1393+ if (withinMap ) {
1394+ long now = Util .getMillis ();
1395+ double dx = mouseX - this .lastMapClickX ;
1396+ double dy = mouseY - this .lastMapClickY ;
1397+ boolean isDoubleClick = (now - this .lastMapClickTime ) <= DOUBLE_CLICK_MS
1398+ && (dx * dx + dy * dy ) <= DOUBLE_CLICK_DISTANCE_SQ ;
1399+ if (isDoubleClick || doubleClick ) {
1400+ this .lastMapClickTime = 0L ;
1401+ this .moveCenter (QuartPos2f .fromQuartPos (QuartPos2 .fromBlockPos (this .playerPos )));
1402+ return true ;
1403+ }
1404+ this .lastMapClickTime = now ;
1405+ this .lastMapClickX = mouseX ;
1406+ this .lastMapClickY = mouseY ;
1407+ }
1408+ }
13411409 if (this .contextMenu != null && this .contextMenu .mouseClicked (mouseButtonEvent )) {
13421410 return true ;
13431411 }
@@ -2443,7 +2511,21 @@ protected void renderSeedMap(GuiGraphics guiGraphics, int mouseX, int mouseY, fl
24432511 });
24442512 }
24452513
2446- // draw player position
2514+ // calculate spawn point
2515+ if (this .toggleableFeatures .contains (MapFeature .WORLD_SPAWN ) && Configs .ToggledFeatures .contains (MapFeature .WORLD_SPAWN )) {
2516+ BlockPos spawnPoint = spawnDataCache .computeIfAbsent (this .worldIdentifier , _ -> this .calculateSpawnData ());
2517+ this .addFeatureWidget (guiGraphics , MapFeature .WORLD_SPAWN , spawnPoint );
2518+ }
2519+
2520+ // draw feature icons (centralized) so overlays can control rendering order/visibility
2521+ this .drawFeatureIcons (guiGraphics );
2522+
2523+ // draw marker
2524+ if (this .markerWidget != null && this .markerWidget .withinBounds () && this .shouldDrawMarkerWidget ()) {
2525+ FeatureWidget .drawFeatureIcon (guiGraphics , this .markerWidget .featureTexture , this .markerWidget .x , this .markerWidget .y , -1 );
2526+ }
2527+
2528+ // draw player position on top of all icons
24472529 if (this .toggleableFeatures .contains (MapFeature .PLAYER_ICON ) && Configs .ToggledFeatures .contains (MapFeature .PLAYER_ICON ) && this .shouldDrawPlayerIcon ()) {
24482530 QuartPos2f relPlayerQuart = QuartPos2f .fromQuartPos (QuartPos2 .fromBlockPos (this .playerPos )).subtract (this .centerQuart );
24492531 int playerMinX = this .centerX + Mth .floor (Configs .PixelsPerBiome * relPlayerQuart .x ()) - 10 ;
@@ -2473,20 +2555,6 @@ protected void renderSeedMap(GuiGraphics guiGraphics, int mouseX, int mouseY, fl
24732555 }
24742556 }
24752557
2476- // calculate spawn point
2477- if (this .toggleableFeatures .contains (MapFeature .WORLD_SPAWN ) && Configs .ToggledFeatures .contains (MapFeature .WORLD_SPAWN )) {
2478- BlockPos spawnPoint = spawnDataCache .computeIfAbsent (this .worldIdentifier , _ -> this .calculateSpawnData ());
2479- this .addFeatureWidget (guiGraphics , MapFeature .WORLD_SPAWN , spawnPoint );
2480- }
2481-
2482- // draw feature icons (centralized) so overlays can control rendering order/visibility
2483- this .drawFeatureIcons (guiGraphics );
2484-
2485- // draw marker
2486- if (this .markerWidget != null && this .markerWidget .withinBounds () && this .shouldDrawMarkerWidget ()) {
2487- FeatureWidget .drawFeatureIcon (guiGraphics , this .markerWidget .featureTexture , this .markerWidget .x , this .markerWidget .y , -1 );
2488- }
2489-
24902558 // draw chest loot widget
24912559 if (this .shouldRenderChestLootWidget () && this .chestLootWidget != null ) {
24922560 this .chestLootWidget .render (guiGraphics , mouseX , mouseY , this .font );
@@ -2579,6 +2647,7 @@ protected void drawCenteredPlayerDirectionArrow(GuiGraphics guiGraphics, double
25792647
25802648 protected ObjectSet <FeatureWidget > getFeatureWidgets () { return this .featureWidgets ; }
25812649 protected FeatureWidget getMarkerWidget () { return this .markerWidget ; }
2650+ protected QuartPos2f getCenterQuart () { return this .centerQuart ; }
25822651
25832652 protected void drawFeatureIcon (GuiGraphics guiGraphics , MapFeature .Texture texture , int x , int y , int width , int height , int colour ) {
25842653 // Draw icon with requested width/height so minimap scaling works
@@ -2599,9 +2668,8 @@ protected void setPixelsPerBiome(double pixelsPerBiome) {
25992668 double min = Math .max (MIN_PIXELS_PER_BIOME , Configs .SeedMapMinPixelsPerBiome );
26002669 double p = Math .clamp (pixelsPerBiome , min , MAX_PIXELS_PER_BIOME );
26012670 Configs .PixelsPerBiome = p ;
2602- // update widget positions so icons move when zoom changes
26032671 try {
2604- this .updateAllFeatureWidgetPositions ( );
2672+ this .moveCenter ( this . centerQuart );
26052673 } catch (Throwable ignored ) {}
26062674 }
26072675
0 commit comments