diff --git a/pom.xml b/pom.xml
index 0192532..c20c7f7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -67,7 +67,7 @@
-LOCAL
- 1.4.0
+ 1.4.1
BentoBoxWorld_ChunkBlock
bentobox-world
diff --git a/src/main/java/world/bentobox/chunkblock/panels/ChunksDialog.java b/src/main/java/world/bentobox/chunkblock/panels/ChunksDialog.java
index 53954ff..c39829f 100644
--- a/src/main/java/world/bentobox/chunkblock/panels/ChunksDialog.java
+++ b/src/main/java/world/bentobox/chunkblock/panels/ChunksDialog.java
@@ -30,20 +30,14 @@
/**
* The territory map of {@code /ch chunks} drawn as a dialog: one button per chunk, laid
* out in a grid. When the island's territory can exceed the 13-wide viewport, a control
- * row is prepended with two view-mode buttons (island center / player position) and a
- * directional arrow pointing toward the off-screen target.
+ * row is prepended: pan arrows that slide the viewport half a screen per click, a jump
+ * button to the island center, a jump button to the player's own position, and an
+ * indicator in the middle that points at whichever of those two is off-screen.
*
* @author tastybento
*/
public class ChunksDialog {
- /**
- * Whether the viewport is centered on the island center or on the player's position.
- */
- enum ViewMode {
- ISLAND_CENTER, PLAYER_CENTER
- }
-
/**
* Widest map that still fits the dialog. A grid this wide is {@value #MAX_RADIUS} * 2
* + 1 buttons across, which is as much as the dialog screen holds before the outer
@@ -51,6 +45,9 @@ enum ViewMode {
*/
static final int MAX_RADIUS = 6;
+ /** How many chunks one pan-arrow click slides the viewport: half a screen. */
+ static final int PAN_STEP = MAX_RADIUS;
+
/** Button size in dialog units. Roughly square once the client adds its own padding. */
private static final int BUTTON_WIDTH = 26;
@@ -71,35 +68,35 @@ enum ViewMode {
private final User user;
private final Island island;
private final int radius;
- private final ViewMode viewMode;
private final int viewDx;
private final int viewDz;
private final boolean scrollable;
ChunksDialog(ChunkBlock addon, User user, Island island) {
- this(addon, user, island, ViewMode.ISLAND_CENTER);
+ this(addon, user, island, 0, 0);
}
- ChunksDialog(ChunkBlock addon, User user, Island island, ViewMode viewMode) {
+ /**
+ * @param viewDx requested viewport center, chunks east of the island center
+ * @param viewDz requested viewport center, chunks south of the island center; both are
+ * clamped so the viewport never scrolls past the edge of the claimable map
+ */
+ ChunksDialog(ChunkBlock addon, User user, Island island, int viewDx, int viewDz) {
this.addon = addon;
this.user = user;
this.island = island;
- this.viewMode = viewMode;
ChunkManager cm = addon.getChunkManager();
- this.scrollable = cm.maxRingRadius(island) > MAX_RADIUS;
+ int maxRing = cm.maxRingRadius(island);
+ this.scrollable = maxRing > MAX_RADIUS;
if (scrollable) {
this.radius = MAX_RADIUS;
- if (viewMode == ViewMode.PLAYER_CENTER && isPlayerOnIsland()) {
- int centerChunkX = island.getCenter().getBlockX() >> 4;
- int centerChunkZ = island.getCenter().getBlockZ() >> 4;
- this.viewDx = (user.getLocation().getBlockX() >> 4) - centerChunkX;
- this.viewDz = (user.getLocation().getBlockZ() >> 4) - centerChunkZ;
- } else {
- this.viewDx = 0;
- this.viewDz = 0;
- }
+ // The viewport center stops radius short of the edge so the last screen ends
+ // exactly on the outermost ring instead of scrolling into the void
+ int limit = Math.max(0, maxRing - radius);
+ this.viewDx = Math.clamp(viewDx, -limit, limit);
+ this.viewDz = Math.clamp(viewDz, -limit, limit);
} else {
this.radius = Math.min(MAX_RADIUS, cm.currentRing(island) + 1);
this.viewDx = 0;
@@ -117,20 +114,21 @@ enum ViewMode {
* which case the caller should fall back to the chat map
*/
public static boolean show(@NonNull ChunkBlock addon, @NonNull User user, @NonNull Island island) {
- return show(addon, user, island, ViewMode.ISLAND_CENTER, null);
+ return show(addon, user, island, 0, 0, null);
}
/**
- * @param viewMode which point the viewport is centered on
+ * @param viewDx viewport center chunk offset east of the island center
+ * @param viewDz viewport center chunk offset south of the island center
* @param selection the chunk description to show above the map, or null for none
*/
- private static boolean show(ChunkBlock addon, User user, Island island, ViewMode viewMode,
+ private static boolean show(ChunkBlock addon, User user, Island island, int viewDx, int viewDz,
@Nullable Component selection) {
if (!Dialogs.isSupported() || !user.isPlayer()) {
return false;
}
try {
- new ChunksDialog(addon, user, island, viewMode).open(selection);
+ new ChunksDialog(addon, user, island, viewDx, viewDz).open(selection);
return true;
} catch (Exception | LinkageError e) {
addon.logError("Could not show the chunks dialog: " + e.getMessage());
@@ -173,20 +171,27 @@ private void open(@Nullable Component selection) {
}
// ------------------------------------------------------------------
- // Control row (view-mode toggle + directional arrow)
+ // Control row: [◎] ─ ─ ─ [◀] [▲] [•] [▼] [▶] ─ ─ ─ [◇]
// ------------------------------------------------------------------
private List controlRow(int columns) {
+ int mid = columns / 2;
List row = new ArrayList<>(columns);
for (int i = 0; i < columns; i++) {
if (i == 0) {
- row.add(modeButton(ViewMode.ISLAND_CENTER, "◎", "◉", NamedTextColor.GOLD,
- REFERENCE + "view-island"));
+ row.add(islandJumpButton());
} else if (i == columns - 1) {
- row.add(modeButton(ViewMode.PLAYER_CENTER, "◇", "◆", NamedTextColor.AQUA,
- REFERENCE + "view-player"));
- } else if (i == columns / 2) {
- row.add(directionArrowButton());
+ row.add(playerJumpButton());
+ } else if (i == mid - 2) {
+ row.add(panButton("◀", -PAN_STEP, 0, "pan-west", canPan(-1, 0)));
+ } else if (i == mid - 1) {
+ row.add(panButton("▲", 0, -PAN_STEP, "pan-north", canPan(0, -1)));
+ } else if (i == mid) {
+ row.add(indicatorButton());
+ } else if (i == mid + 1) {
+ row.add(panButton("▼", 0, PAN_STEP, "pan-south", canPan(0, 1)));
+ } else if (i == mid + 2) {
+ row.add(panButton("▶", PAN_STEP, 0, "pan-east", canPan(1, 0)));
} else {
row.add(spacerButton());
}
@@ -194,14 +199,51 @@ private List controlRow(int columns) {
return row;
}
- private ActionButton modeButton(ViewMode mode, String inactiveGlyph, String activeGlyph,
- NamedTextColor color, String tooltipKey) {
- boolean active = viewMode == mode;
- String glyph = active ? activeGlyph : inactiveGlyph;
- NamedTextColor buttonColor = active ? NamedTextColor.WHITE : color;
- return ActionButton.builder(Component.text(glyph, buttonColor))
+ /**
+ * Whether panning one step toward (signX, signZ) would reveal anything: the viewport
+ * must not already touch that edge of the claimable map.
+ */
+ private boolean canPan(int signX, int signZ) {
+ int maxRing = addon.getChunkManager().maxRingRadius(island);
+ if (signX != 0) {
+ return signX < 0 ? viewDx - radius > -maxRing : viewDx + radius < maxRing;
+ }
+ return signZ < 0 ? viewDz - radius > -maxRing : viewDz + radius < maxRing;
+ }
+
+ private ActionButton panButton(String glyph, int stepX, int stepZ, String tooltipKey, boolean enabled) {
+ if (!enabled) {
+ return spacerButton();
+ }
+ return ActionButton.builder(Component.text(glyph, NamedTextColor.WHITE))
+ .tooltip(text(REFERENCE + tooltipKey)).width(BUTTON_WIDTH)
+ .action(DialogAction.customClick((view, audience) -> moveViewport(viewDx + stepX, viewDz + stepZ),
+ ClickCallback.Options.builder().uses(1).lifetime(CALLBACK_LIFETIME).build()))
+ .build();
+ }
+
+ private ActionButton islandJumpButton() {
+ boolean active = viewDx == 0 && viewDz == 0;
+ return jumpButton(active ? "◉" : "◎", active, NamedTextColor.GOLD, REFERENCE + "view-island", 0, 0);
+ }
+
+ private ActionButton playerJumpButton() {
+ int[] player = playerChunkOffset();
+ if (player == null) {
+ return spacerButton();
+ }
+ // Compare against where the jump would actually land, which is the clamped spot
+ ChunksDialog target = new ChunksDialog(addon, user, island, player[0], player[1]);
+ boolean active = viewDx == target.viewDx && viewDz == target.viewDz;
+ return jumpButton(active ? "◆" : "◇", active, NamedTextColor.AQUA, REFERENCE + "view-player", player[0],
+ player[1]);
+ }
+
+ private ActionButton jumpButton(String glyph, boolean active, NamedTextColor color, String tooltipKey,
+ int targetDx, int targetDz) {
+ return ActionButton.builder(Component.text(glyph, active ? NamedTextColor.WHITE : color))
.tooltip(text(tooltipKey)).width(BUTTON_WIDTH)
- .action(DialogAction.customClick((view, audience) -> switchMode(mode),
+ .action(DialogAction.customClick((view, audience) -> moveViewport(targetDx, targetDz),
ClickCallback.Options.builder().uses(1).lifetime(CALLBACK_LIFETIME).build()))
.build();
}
@@ -210,42 +252,32 @@ private ActionButton spacerButton() {
return ActionButton.builder(Component.text("─", NamedTextColor.DARK_GRAY)).width(BUTTON_WIDTH).build();
}
- private ActionButton directionArrowButton() {
- int targetDx;
- int targetDz;
- NamedTextColor arrowColor;
- String tooltipKey;
- ViewMode targetMode;
-
- if (viewMode == ViewMode.ISLAND_CENTER) {
- if (!isPlayerOnIsland()) {
- return spacerButton();
- }
- int centerChunkX = island.getCenter().getBlockX() >> 4;
- int centerChunkZ = island.getCenter().getBlockZ() >> 4;
- targetDx = (user.getLocation().getBlockX() >> 4) - centerChunkX;
- targetDz = (user.getLocation().getBlockZ() >> 4) - centerChunkZ;
- arrowColor = NamedTextColor.AQUA;
- tooltipKey = REFERENCE + "arrow-to-player";
- targetMode = ViewMode.PLAYER_CENTER;
- } else {
- targetDx = 0;
- targetDz = 0;
- arrowColor = NamedTextColor.GOLD;
- tooltipKey = REFERENCE + "arrow-to-island";
- targetMode = ViewMode.ISLAND_CENTER;
+ /**
+ * The middle of the control row: an arrow pointing at the island center when it has
+ * been panned off-screen (clicking jumps home), otherwise at the player when they are
+ * off-screen (clicking jumps to them), otherwise a plain dot.
+ */
+ private ActionButton indicatorButton() {
+ if (offScreen(0, 0)) {
+ return indicatorArrow(-viewDx, -viewDz, NamedTextColor.GOLD, REFERENCE + "arrow-to-island", 0, 0);
}
-
- int relDx = targetDx - viewDx;
- int relDz = targetDz - viewDz;
- if (Math.abs(relDx) <= radius && Math.abs(relDz) <= radius) {
- return ActionButton.builder(Component.text("•", NamedTextColor.DARK_GRAY)).width(BUTTON_WIDTH).build();
+ int[] player = playerChunkOffset();
+ if (player != null && offScreen(player[0], player[1])) {
+ return indicatorArrow(player[0] - viewDx, player[1] - viewDz, NamedTextColor.AQUA,
+ REFERENCE + "arrow-to-player", player[0], player[1]);
}
+ return ActionButton.builder(Component.text("•", NamedTextColor.DARK_GRAY)).width(BUTTON_WIDTH).build();
+ }
+
+ private boolean offScreen(int dx, int dz) {
+ return Math.abs(dx - viewDx) > radius || Math.abs(dz - viewDz) > radius;
+ }
- String arrow = directionGlyph(relDx, relDz);
- return ActionButton.builder(Component.text(arrow, arrowColor))
+ private ActionButton indicatorArrow(int relDx, int relDz, NamedTextColor color, String tooltipKey,
+ int targetDx, int targetDz) {
+ return ActionButton.builder(Component.text(directionGlyph(relDx, relDz), color))
.tooltip(text(tooltipKey)).width(BUTTON_WIDTH)
- .action(DialogAction.customClick((view, audience) -> switchMode(targetMode),
+ .action(DialogAction.customClick((view, audience) -> moveViewport(targetDx, targetDz),
ClickCallback.Options.builder().uses(1).lifetime(CALLBACK_LIFETIME).build()))
.build();
}
@@ -260,6 +292,18 @@ static String directionGlyph(int relDx, int relDz) {
return ARROWS[((sector % 8) + 8) % 8];
}
+ /**
+ * @return the chunk the player is standing on as an offset from the island center, or
+ * null when the player is not in the island's world
+ */
+ private int @Nullable [] playerChunkOffset() {
+ if (island.getWorld() == null || !Util.sameWorld(island.getWorld(), user.getLocation().getWorld())) {
+ return null;
+ }
+ return new int[] { (user.getLocation().getBlockX() >> 4) - (island.getCenter().getBlockX() >> 4),
+ (user.getLocation().getBlockZ() >> 4) - (island.getCenter().getBlockZ() >> 4) };
+ }
+
// ------------------------------------------------------------------
// Map buttons
// ------------------------------------------------------------------
@@ -281,15 +325,19 @@ private ActionButton button(Cell cell) {
}
/**
- * Puts the map back up with the clicked chunk named at the top. Clicking any button
- * closes the dialog, so a map that stays put has to be shown again.
+ * Puts the map back up with the clicked chunk named at the top, keeping the panned
+ * position. Clicking any button closes the dialog, so a map that stays put has to be
+ * shown again.
*/
private void reopen(Component selection) {
- Bukkit.getScheduler().runTask(addon.getPlugin(), () -> show(addon, user, island, viewMode, selection));
+ Bukkit.getScheduler().runTask(addon.getPlugin(), () -> show(addon, user, island, viewDx, viewDz, selection));
}
- private void switchMode(ViewMode mode) {
- Bukkit.getScheduler().runTask(addon.getPlugin(), () -> show(addon, user, island, mode, null));
+ /**
+ * Reopens the map with the viewport centered on the given offset (clamped to the map).
+ */
+ private void moveViewport(int newDx, int newDz) {
+ Bukkit.getScheduler().runTask(addon.getPlugin(), () -> show(addon, user, island, newDx, newDz, null));
}
/**
@@ -323,14 +371,18 @@ private static String offset(int value) {
return value > 0 ? "+" + value : String.valueOf(value);
}
- private boolean isPlayerOnIsland() {
- return island.getWorld() != null && Util.sameWorld(island.getWorld(), user.getLocation().getWorld());
- }
-
boolean isScrollable() {
return scrollable;
}
+ int getViewDx() {
+ return viewDx;
+ }
+
+ int getViewDz() {
+ return viewDz;
+ }
+
/**
* Translates a locale key straight to a component. Going through the user rather than
* parsing the translated string here keeps every message on BentoBox's own path,
diff --git a/src/main/resources/locales/cs.yml b/src/main/resources/locales/cs.yml
index 3446f6b..92eb2e8 100644
--- a/src/main/resources/locales/cs.yml
+++ b/src/main/resources/locales/cs.yml
@@ -74,6 +74,10 @@ chunkblock:
close: "Zavřít"
view-island: "Vycentrovat na ostrov"
view-player: "Vycentrovat na vaši pozici"
+ pan-north: "Posunout mapu na sever"
+ pan-south: "Posunout mapu na jih"
+ pan-east: "Posunout mapu na východ"
+ pan-west: "Posunout mapu na západ"
arrow-to-island: "Střed vašeho ostrova je tímto směrem"
arrow-to-player: "Jste tímto směrem"
tooltip:
diff --git a/src/main/resources/locales/de.yml b/src/main/resources/locales/de.yml
index 0899a06..bf06082 100644
--- a/src/main/resources/locales/de.yml
+++ b/src/main/resources/locales/de.yml
@@ -74,6 +74,10 @@ chunkblock:
close: "Schließen"
view-island: "Auf Insel zentrieren"
view-player: "Auf deine Position zentrieren"
+ pan-north: "Karte nach Norden verschieben"
+ pan-south: "Karte nach Süden verschieben"
+ pan-east: "Karte nach Osten verschieben"
+ pan-west: "Karte nach Westen verschieben"
arrow-to-island: "Dein Inselzentrum ist in dieser Richtung"
arrow-to-player: "Du bist in dieser Richtung"
tooltip:
diff --git a/src/main/resources/locales/en-US.yml b/src/main/resources/locales/en-US.yml
index eea9612..31473b4 100755
--- a/src/main/resources/locales/en-US.yml
+++ b/src/main/resources/locales/en-US.yml
@@ -68,6 +68,10 @@ chunkblock:
close: "Close"
view-island: "Center on your island"
view-player: "Center on your position"
+ pan-north: "Scroll the map north"
+ pan-south: "Scroll the map south"
+ pan-east: "Scroll the map east"
+ pan-west: "Scroll the map west"
arrow-to-island: "Your island center is this way"
arrow-to-player: "You are this way"
tooltip:
diff --git a/src/main/resources/locales/es.yml b/src/main/resources/locales/es.yml
index fc41aa7..c34daa5 100644
--- a/src/main/resources/locales/es.yml
+++ b/src/main/resources/locales/es.yml
@@ -74,6 +74,10 @@ chunkblock:
close: "Cerrar"
view-island: "Centrar en tu isla"
view-player: "Centrar en tu posición"
+ pan-north: "Desplazar el mapa al norte"
+ pan-south: "Desplazar el mapa al sur"
+ pan-east: "Desplazar el mapa al este"
+ pan-west: "Desplazar el mapa al oeste"
arrow-to-island: "El centro de tu isla está en esta dirección"
arrow-to-player: "Estás en esta dirección"
tooltip:
diff --git a/src/main/resources/locales/fr.yml b/src/main/resources/locales/fr.yml
index 91dc63a..bce0d1f 100644
--- a/src/main/resources/locales/fr.yml
+++ b/src/main/resources/locales/fr.yml
@@ -74,6 +74,10 @@ chunkblock:
close: "Fermer"
view-island: "Centrer sur votre île"
view-player: "Centrer sur votre position"
+ pan-north: "Faire défiler la carte vers le nord"
+ pan-south: "Faire défiler la carte vers le sud"
+ pan-east: "Faire défiler la carte vers l'est"
+ pan-west: "Faire défiler la carte vers l'ouest"
arrow-to-island: "Le centre de votre île est par ici"
arrow-to-player: "Vous êtes par ici"
tooltip:
diff --git a/src/main/resources/locales/hr.yml b/src/main/resources/locales/hr.yml
index 555afac..d18019c 100644
--- a/src/main/resources/locales/hr.yml
+++ b/src/main/resources/locales/hr.yml
@@ -74,6 +74,10 @@ chunkblock:
close: "Zatvori"
view-island: "Centriraj na otok"
view-player: "Centriraj na tvoju poziciju"
+ pan-north: "Pomakni kartu na sjever"
+ pan-south: "Pomakni kartu na jug"
+ pan-east: "Pomakni kartu na istok"
+ pan-west: "Pomakni kartu na zapad"
arrow-to-island: "Centar tvog otoka je u ovom smjeru"
arrow-to-player: "Ti si u ovom smjeru"
tooltip:
diff --git a/src/main/resources/locales/hu.yml b/src/main/resources/locales/hu.yml
index aad31a9..5f9d614 100644
--- a/src/main/resources/locales/hu.yml
+++ b/src/main/resources/locales/hu.yml
@@ -75,6 +75,10 @@ chunkblock:
close: "Bezárás"
view-island: "Középre a szigetedre"
view-player: "Középre a pozíciódra"
+ pan-north: "Térkép görgetése északra"
+ pan-south: "Térkép görgetése délre"
+ pan-east: "Térkép görgetése keletre"
+ pan-west: "Térkép görgetése nyugatra"
arrow-to-island: "A szigeted közepe erre van"
arrow-to-player: "Te erre vagy"
tooltip:
diff --git a/src/main/resources/locales/id.yml b/src/main/resources/locales/id.yml
index c3543ed..d6f4da4 100644
--- a/src/main/resources/locales/id.yml
+++ b/src/main/resources/locales/id.yml
@@ -74,6 +74,10 @@ chunkblock:
close: "Tutup"
view-island: "Pusatkan ke pulau"
view-player: "Pusatkan ke posisi Anda"
+ pan-north: "Geser peta ke utara"
+ pan-south: "Geser peta ke selatan"
+ pan-east: "Geser peta ke timur"
+ pan-west: "Geser peta ke barat"
arrow-to-island: "Pusat pulau Anda ada di arah ini"
arrow-to-player: "Anda ada di arah ini"
tooltip:
diff --git a/src/main/resources/locales/it.yml b/src/main/resources/locales/it.yml
index aa38b37..08ad4bf 100644
--- a/src/main/resources/locales/it.yml
+++ b/src/main/resources/locales/it.yml
@@ -74,6 +74,10 @@ chunkblock:
close: "Chiudi"
view-island: "Centra sulla tua isola"
view-player: "Centra sulla tua posizione"
+ pan-north: "Scorri la mappa a nord"
+ pan-south: "Scorri la mappa a sud"
+ pan-east: "Scorri la mappa a est"
+ pan-west: "Scorri la mappa a ovest"
arrow-to-island: "Il centro della tua isola è in questa direzione"
arrow-to-player: "Ti trovi in questa direzione"
tooltip:
diff --git a/src/main/resources/locales/ja.yml b/src/main/resources/locales/ja.yml
index b933bea..2f59abe 100644
--- a/src/main/resources/locales/ja.yml
+++ b/src/main/resources/locales/ja.yml
@@ -71,6 +71,10 @@ chunkblock:
close: "閉じる"
view-island: "島の中心に表示"
view-player: "現在地に表示"
+ pan-north: "マップを北へスクロール"
+ pan-south: "マップを南へスクロール"
+ pan-east: "マップを東へスクロール"
+ pan-west: "マップを西へスクロール"
arrow-to-island: "島の中心はこの方向です"
arrow-to-player: "あなたはこの方向にいます"
tooltip:
diff --git a/src/main/resources/locales/pl.yml b/src/main/resources/locales/pl.yml
index c74a818..d667720 100644
--- a/src/main/resources/locales/pl.yml
+++ b/src/main/resources/locales/pl.yml
@@ -71,6 +71,10 @@ chunkblock:
close: "Zamknij"
view-island: "Wyśrodkuj na wyspę"
view-player: "Wyśrodkuj na twoją pozycję"
+ pan-north: "Przewiń mapę na północ"
+ pan-south: "Przewiń mapę na południe"
+ pan-east: "Przewiń mapę na wschód"
+ pan-west: "Przewiń mapę na zachód"
arrow-to-island: "Centrum twojej wyspy jest w tym kierunku"
arrow-to-player: "Jesteś w tym kierunku"
tooltip:
diff --git a/src/main/resources/locales/pt.yml b/src/main/resources/locales/pt.yml
index 7616ee5..13fa156 100644
--- a/src/main/resources/locales/pt.yml
+++ b/src/main/resources/locales/pt.yml
@@ -71,6 +71,10 @@ chunkblock:
close: "Fechar"
view-island: "Centralizar na ilha"
view-player: "Centralizar na sua posição"
+ pan-north: "Rolar o mapa para o norte"
+ pan-south: "Rolar o mapa para o sul"
+ pan-east: "Rolar o mapa para o leste"
+ pan-west: "Rolar o mapa para o oeste"
arrow-to-island: "O centro da sua ilha está nesta direção"
arrow-to-player: "Você está nesta direção"
tooltip:
diff --git a/src/main/resources/locales/ru.yml b/src/main/resources/locales/ru.yml
index c215fff..354b378 100644
--- a/src/main/resources/locales/ru.yml
+++ b/src/main/resources/locales/ru.yml
@@ -73,6 +73,10 @@ chunkblock:
close: "Закрыть"
view-island: "Центрировать на острове"
view-player: "Центрировать на вашей позиции"
+ pan-north: "Прокрутить карту на север"
+ pan-south: "Прокрутить карту на юг"
+ pan-east: "Прокрутить карту на восток"
+ pan-west: "Прокрутить карту на запад"
arrow-to-island: "Центр вашего острова в этом направлении"
arrow-to-player: "Вы находитесь в этом направлении"
tooltip:
diff --git a/src/main/resources/locales/tr.yml b/src/main/resources/locales/tr.yml
index 691fddd..e3ba4b9 100644
--- a/src/main/resources/locales/tr.yml
+++ b/src/main/resources/locales/tr.yml
@@ -74,6 +74,10 @@ chunkblock:
close: "Kapat"
view-island: "Adanıza ortala"
view-player: "Konumunuza ortala"
+ pan-north: "Haritayı kuzeye kaydır"
+ pan-south: "Haritayı güneye kaydır"
+ pan-east: "Haritayı doğuya kaydır"
+ pan-west: "Haritayı batıya kaydır"
arrow-to-island: "Ada merkeziniz bu yönde"
arrow-to-player: "Bu yöndesiniz"
tooltip:
diff --git a/src/main/resources/locales/uk.yml b/src/main/resources/locales/uk.yml
index a90d6f6..4d6f26e 100644
--- a/src/main/resources/locales/uk.yml
+++ b/src/main/resources/locales/uk.yml
@@ -74,6 +74,10 @@ chunkblock:
close: "Закрити"
view-island: "Центрувати на острові"
view-player: "Центрувати на вашій позиції"
+ pan-north: "Прокрутити карту на північ"
+ pan-south: "Прокрутити карту на південь"
+ pan-east: "Прокрутити карту на схід"
+ pan-west: "Прокрутити карту на захід"
arrow-to-island: "Центр вашого острова в цьому напрямку"
arrow-to-player: "Ви знаходитесь у цьому напрямку"
tooltip:
diff --git a/src/main/resources/locales/vi.yml b/src/main/resources/locales/vi.yml
index 410d620..9ee0be9 100644
--- a/src/main/resources/locales/vi.yml
+++ b/src/main/resources/locales/vi.yml
@@ -74,6 +74,10 @@ chunkblock:
close: "Đóng"
view-island: "Căn giữa theo đảo"
view-player: "Căn giữa theo vị trí của bạn"
+ pan-north: "Cuộn bản đồ về phía bắc"
+ pan-south: "Cuộn bản đồ về phía nam"
+ pan-east: "Cuộn bản đồ về phía đông"
+ pan-west: "Cuộn bản đồ về phía tây"
arrow-to-island: "Trung tâm đảo của bạn ở hướng này"
arrow-to-player: "Bạn ở hướng này"
tooltip:
diff --git a/src/main/resources/locales/zh-CN.yml b/src/main/resources/locales/zh-CN.yml
index 174990a..1a1732f 100644
--- a/src/main/resources/locales/zh-CN.yml
+++ b/src/main/resources/locales/zh-CN.yml
@@ -73,6 +73,10 @@ chunkblock:
close: "关闭"
view-island: "以岛屿为中心"
view-player: "以你的位置为中心"
+ pan-north: "向北滚动地图"
+ pan-south: "向南滚动地图"
+ pan-east: "向东滚动地图"
+ pan-west: "向西滚动地图"
arrow-to-island: "你的岛屿中心在这个方向"
arrow-to-player: "你在这个方向"
tooltip:
diff --git a/src/main/resources/locales/zh-TW.yml b/src/main/resources/locales/zh-TW.yml
index 8905b7b..b1f4139 100644
--- a/src/main/resources/locales/zh-TW.yml
+++ b/src/main/resources/locales/zh-TW.yml
@@ -222,6 +222,10 @@ chunkblock:
close: '關閉'
view-island: "以島嶼為中心"
view-player: "以你的位置為中心"
+ pan-north: "向北捲動地圖"
+ pan-south: "向南捲動地圖"
+ pan-east: "向東捲動地圖"
+ pan-west: "向西捲動地圖"
arrow-to-island: "你的島嶼中心在這個方向"
arrow-to-player: "你在這個方向"
tooltip:
diff --git a/src/test/java/world/bentobox/chunkblock/panels/ChunksDialogTest.java b/src/test/java/world/bentobox/chunkblock/panels/ChunksDialogTest.java
index 98a34eb..ecf91ed 100644
--- a/src/test/java/world/bentobox/chunkblock/panels/ChunksDialogTest.java
+++ b/src/test/java/world/bentobox/chunkblock/panels/ChunksDialogTest.java
@@ -88,24 +88,31 @@ void testIsNotScrollableWhenTerritoryFitsViewport() {
}
@Test
- void testPlayerCenteredViewportShiftsMap() {
+ void testPannedViewportShiftsMap() {
when(island.getProtectionRange()).thenReturn(240);
- when(playerLocation.getBlockX()).thenReturn(8 + 160);
- when(playerLocation.getBlockZ()).thenReturn(8);
- level = 100000;
- // Claim enough to reach ring 10
- for (int d = 1; d <= 10; d++) {
- cm.claim(island, d, 0);
- }
- ChunksDialog dialog = new ChunksDialog(addon, user, island, ChunksDialog.ViewMode.PLAYER_CENTER);
+ // Pan the viewport 8 chunks east: visible range is dx 2..14, island center off-screen
+ ChunksDialog dialog = new ChunksDialog(addon, user, island, 8, 0);
int width = 2 * ChunksDialog.MAX_RADIUS + 1;
assertEquals(width * width, dialog.cells().size());
- // The player is at chunk offset +10, so the viewport should be centered there.
- // The center chunk (0,0) should be visible if it's within radius of the viewport center.
- // viewDx=10, radius=6 → visible range is 4..16, so island center at 0 is NOT visible.
- boolean centerVisible = dialog.cells().stream()
- .anyMatch(c -> c.dx() == 0 && c.dz() == 0);
- assertFalse(centerVisible);
+ assertFalse(dialog.cells().stream().anyMatch(c -> c.dx() == 0 && c.dz() == 0));
+ assertTrue(dialog.cells().stream().anyMatch(c -> c.dx() == 14 && c.dz() == 0));
+ }
+
+ @Test
+ void testViewportClampsAtMapEdge() {
+ when(island.getProtectionRange()).thenReturn(240);
+ // maxRingRadius = (240-8)/16 = 14; clamp limit = 14 - 6 = 8
+ ChunksDialog dialog = new ChunksDialog(addon, user, island, 100, -100);
+ assertEquals(8, dialog.getViewDx());
+ assertEquals(-8, dialog.getViewDz());
+ }
+
+ @Test
+ void testNonScrollableIgnoresRequestedViewport() {
+ when(island.getProtectionRange()).thenReturn(100);
+ ChunksDialog dialog = new ChunksDialog(addon, user, island, 5, 5);
+ assertEquals(0, dialog.getViewDx());
+ assertEquals(0, dialog.getViewDz());
}
@Test
@@ -143,13 +150,9 @@ void testMapIsCappedAtTheWidestGridTheDialogHolds() {
}
@Test
- void testPlayerCenteredFallsBackToIslandCenterWhenNotOnIsland() {
+ void testDefaultViewportShowsIslandCenter() {
when(island.getProtectionRange()).thenReturn(240);
- when(playerLocation.getWorld()).thenReturn(null);
- // Player is not in the island world → viewport should center on island
- ChunksDialog dialog = new ChunksDialog(addon, user, island, ChunksDialog.ViewMode.PLAYER_CENTER);
- boolean centerVisible = dialog.cells().stream()
- .anyMatch(c -> c.dx() == 0 && c.dz() == 0);
- assertTrue(centerVisible);
+ ChunksDialog dialog = new ChunksDialog(addon, user, island);
+ assertTrue(dialog.cells().stream().anyMatch(c -> c.dx() == 0 && c.dz() == 0));
}
}