Skip to content

Commit eda7367

Browse files
committed
World Border and Map Recentering
1 parent b5a5ce2 commit eda7367

File tree

5 files changed

+137
-46
lines changed

5 files changed

+137
-46
lines changed

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ You can adjust your own maximum zoom (I recommend 6000) using the command ```/sm
1919

2020
![Zoomies](https://i.imgur.com/utIgDkp.png)
2121

22+
### World Border Limit
23+
Limit the SeedMap and Minimap to a server's world border size so the map only shows that area (centered at 0,0).
24+
25+
Set it with ```/sm:config WorldBorder 8000``` to show a border from -8000 to +8000 on both axes. Use 0 to disable.
26+
27+
### Double Click Recenter
28+
Double clicking anywhere on the map will recenter the map to the players location.
29+
2230
### Directional Arrow
2331
This change was accepted upstream, however in my fork I have adjusted the size of it as well as the icon itself giving it a white fill.
2432

@@ -105,4 +113,4 @@ If the server you're in already has a seed in the database, or it has just been
105113
You can enable/disable this with ```/sm:config AutoApplySeedCrackerSeed true/false```
106114

107115
### Notes
108-
If using the original SeedMapper after using my fork you must erase my ```config.json``` first due to the mismatch of settings.
116+
If using the original SeedMapper after using my fork you must erase my ```config.json``` first due to the mismatch of settings.

src/main/java/dev/xpple/seedmapper/config/Configs.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,17 @@ private static void setSeedMapMinPixelsPerBiome(double minPixelsPerBiome) {
138138
PixelsPerBiome = clampSeedMapZoom(PixelsPerBiome);
139139
}
140140

141+
@Config(comment = "getWorldBorderComment", setter = @Config.Setter("setWorldBorder"))
142+
public static int WorldBorder = 0;
143+
144+
private static Component getWorldBorderComment() {
145+
return Component.translatable("config.worldBorder.comment");
146+
}
147+
148+
private static void setWorldBorder(int worldBorder) {
149+
WorldBorder = Math.max(0, worldBorder);
150+
}
151+
141152
private static double clampSeedMapZoom(double pixelsPerBiome) {
142153
double min = Math.max(SeedMapScreen.MIN_PIXELS_PER_BIOME, SeedMapMinPixelsPerBiome);
143154
return Math.clamp(pixelsPerBiome, min, SeedMapScreen.MAX_PIXELS_PER_BIOME);

src/main/java/dev/xpple/seedmapper/seedmap/SeedMapMinimapScreen.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,10 @@ private void drawCenterCross(GuiGraphics guiGraphics, double centerX, double cen
196196
int cx = (int) Math.round(centerX);
197197
int cy = (int) Math.round(centerY);
198198
int crossHalf = 3;
199+
int outlineColor = 0xFF_000000;
199200
int color = 0xFF_FFFFFF;
201+
guiGraphics.fill(cx - crossHalf - 1, cy - 1, cx + crossHalf + 2, cy + 2, outlineColor);
202+
guiGraphics.fill(cx - 1, cy - crossHalf - 1, cx + 2, cy + crossHalf + 2, outlineColor);
200203
guiGraphics.fill(cx - crossHalf, cy, cx + crossHalf + 1, cy + 1, color);
201204
guiGraphics.fill(cx, cy - crossHalf, cx + 1, cy + crossHalf + 1, color);
202205
}
@@ -248,7 +251,7 @@ protected void setPixelsPerBiome(double pixelsPerBiome) {
248251
Configs.PixelsPerBiome = clamped;
249252
try {
250253
this.minimapPixelsPerBiome = clamped;
251-
this.updateAllFeatureWidgetPositions();
254+
this.moveCenter(this.getCenterQuart());
252255
} finally {
253256
Configs.PixelsPerBiome = previous;
254257
}

src/main/java/dev/xpple/seedmapper/seedmap/SeedMapScreen.java

Lines changed: 112 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
import net.minecraft.util.ARGB;
9090
import net.minecraft.util.Mth;
9191
import net.minecraft.util.RandomSource;
92+
import net.minecraft.util.Util;
9293
import net.minecraft.world.SimpleContainer;
9394
import net.minecraft.world.item.Item;
9495
import 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

src/main/resources/assets/seedmapper/lang/en_us.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@
9797

9898
"config.oreAirCheck.comment": "Whether or not SeedMapper should use in-game air checks to invalidate ore positions.",
9999
"config.devMode.comment": "Enables certain debug commands.",
100+
"config.worldBorder.comment": "Limits the seed map to a square world border radius in blocks. Use 0 to disable.",
100101

101102
"key.seedMap": "Seed map",
102103

0 commit comments

Comments
 (0)