Fixed saved biome scoreboards

- Keep Studio board refreshes alive while saved biome data loads
- Sample mantle-aware biome environments and clear prior world values
- Report permanent failures once per display context
- Localize loading states and verify recovery and Jigsaw transitions
This commit is contained in:
Brian Neumann-Fopiano committed 2026-09-06 12:11:41 -04:00
1 parent 5570923d30
commit 3425c05e8b
23 files changed
+383 -3

No files matched your search

@@ -35,6 +35,14 @@ public final class BukkitUiMessages {
"iris.bukkit.scoreboard.biome",
C.AQUA + "Biome" + C.GRAY + ": {biome}"
);
public static final TextKey SCOREBOARD_BIOME_LOADING = TextKey.of(
"iris.bukkit.scoreboard.biome_loading",
"Loading"
);
public static final TextKey SCOREBOARD_BIOME_UNAVAILABLE = TextKey.of(
"iris.bukkit.scoreboard.biome_unavailable",
"Unavailable"
);
public static final TextKey SCOREBOARD_HEIGHT = TextKey.of(
"iris.bukkit.scoreboard.height",
C.AQUA + "Height" + C.GRAY + ": {height}"
@@ -56,6 +64,8 @@ public final class BukkitUiMessages {
SCOREBOARD_CARVING,
SCOREBOARD_REGION,
SCOREBOARD_BIOME,
SCOREBOARD_BIOME_LOADING,
SCOREBOARD_BIOME_UNAVAILABLE,
SCOREBOARD_HEIGHT,
SCOREBOARD_SLOPE,
SCOREBOARD_BLOCK_UPDATES
@@ -25,7 +25,9 @@ import art.arcane.iris.spi.IrisLogging;
import art.arcane.iris.core.IrisSettings;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.core.tools.IrisToolbelt;
import art.arcane.iris.engine.framework.BiomeEnvironment;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.history.SavedBiomeUnavailableException;
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
import art.arcane.volmlib.util.board.Board;
import art.arcane.volmlib.util.board.BoardProvider;
@@ -358,6 +360,8 @@ public class BoardSVC implements IrisService, BoardProvider {
private volatile BoardView view;
private volatile boolean cancelled;
private volatile boolean ordinaryTickScheduled;
private UUID ordinaryWorldId;
private BiomeFailureContext reportedBiomeFailure;
public PlayerBoard(Player player) {
this.player = player;
@@ -377,10 +381,12 @@ public class BoardSVC implements IrisService, BoardProvider {
yieldBoard(player, this);
return;
}
boolean switched = view != BoardView.ORDINARY;
UUID worldId = player.getWorld().getUID();
boolean switched = view != BoardView.ORDINARY || !worldId.equals(ordinaryWorldId);
view = BoardView.ORDINARY;
jigsawContext = null;
if (switched) {
ordinaryWorldId = worldId;
updateOrdinary();
board.update();
}
@@ -515,14 +521,42 @@ public class BoardSVC implements IrisService, BoardProvider {
}
lines.add("&7&m ");
lines.add(IrisLanguage.text(BukkitUiMessages.SCOREBOARD_REGION, MessageArgument.untrusted("region", engine.getRegion(x, y, z).getName())));
lines.add(IrisLanguage.text(BukkitUiMessages.SCOREBOARD_BIOME, MessageArgument.untrusted("biome", engine.getBiomeOrMantle(x, y, z).getName())));
String regionName;
String biomeName;
try {
BiomeEnvironment environment = engine.getBiomeOrMantleEnvironment(x, y, z);
regionName = environment.region().getName();
biomeName = environment.biome().getName();
reportedBiomeFailure = null;
} catch (SavedBiomeUnavailableException failure) {
regionName = IrisLanguage.text(failure.isLoading()
? BukkitUiMessages.SCOREBOARD_BIOME_LOADING
: BukkitUiMessages.SCOREBOARD_BIOME_UNAVAILABLE);
biomeName = regionName;
if (!failure.isLoading()) {
reportBiomeFailure(failure, engine, loc);
}
}
lines.add(IrisLanguage.text(BukkitUiMessages.SCOREBOARD_REGION, MessageArgument.untrusted("region", regionName)));
lines.add(IrisLanguage.text(BukkitUiMessages.SCOREBOARD_BIOME, MessageArgument.untrusted("biome", biomeName)));
lines.add(IrisLanguage.text(BukkitUiMessages.SCOREBOARD_HEIGHT, MessageArgument.trusted("height", Math.round(engine.getHeight(x, z)))));
lines.add(IrisLanguage.text(BukkitUiMessages.SCOREBOARD_SLOPE, MessageArgument.trusted("slope", Form.f(engine.getSlope(x, z), 2))));
lines.add(IrisLanguage.text(BukkitUiMessages.SCOREBOARD_BLOCK_UPDATES, MessageArgument.trusted("updates", Form.f(engine.getBlockUpdatesPerSecond()))));
lines.add("&7&m ");
this.lines = lines;
}
private void reportBiomeFailure(SavedBiomeUnavailableException failure, Engine engine, Location location) {
World world = Objects.requireNonNull(location.getWorld());
BiomeFailureContext context = new BiomeFailureContext(world.getUID(), engine,
location.getBlockX() >> 4, location.getBlockZ() >> 4, failure.getMessage());
if (context.equals(reportedBiomeFailure)) {
return;
}
reportedBiomeFailure = context;
IrisLogging.reportError("Unable to display saved Iris biome information in " + world.getName()
+ " at " + location.getBlockX() + ", " + location.getBlockY() + ", " + location.getBlockZ() + ".", failure);
}
}
private void yieldBoard(Player player, PlayerBoard playerBoard) {
@@ -536,4 +570,7 @@ public class BoardSVC implements IrisService, BoardProvider {
ORDINARY,
JIGSAW
}
private record BiomeFailureContext(UUID worldId, Engine engine, int chunkX, int chunkZ, String reason) {
}
}
@@ -559,6 +559,18 @@ public class IrisEngine implements Engine {
}
}
@Override
public BiomeEnvironment getBiomeOrMantleEnvironment(int x, int y, int z) {
Optional<BiomeEnvironment> saved = resolveSavedBiomeEnvironment(x, y, z, false);
if (saved.isPresent()) {
return saved.get();
}
try (GenerationHistoryRuntimeRouter.CoordinateScope ignored =
openGenerationHistoryCoordinateScopeUnchecked(x, z, "resolve a mantle biome environment")) {
return Engine.super.getBiomeOrMantleEnvironment(x, y, z);
}
}
@Override
public BiomeEnvironment getSurfaceBiomeEnvironment(int x, int z) {
Optional<BiomeEnvironment> saved = resolveSavedBiomeEnvironment(x, 0, z, true);
@@ -97,6 +97,10 @@ public interface Engine extends DataProvider, Fallible, BlockUpdater, Renderer,
return new BiomeEnvironment(0L, getBiome(x, y, z), getRegion(x, y, z), getDimension(), getData());
}
default BiomeEnvironment getBiomeOrMantleEnvironment(int x, int y, int z) {
return new BiomeEnvironment(0L, getBiomeOrMantle(x, y, z), getRegion(x, y, z), getDimension(), getData());
}
default BiomeEnvironment getSurfaceBiomeEnvironment(int x, int z) {
return new BiomeEnvironment(0L, getSurfaceBiome(x, z), getRegion(x, z), getDimension(), getData());
}
@@ -1358,6 +1358,8 @@
"iris.bukkit.scoreboard.carving": "§dCarving§7: {state}",
"iris.bukkit.scoreboard.region": "§bRegion§7: {region}",
"iris.bukkit.scoreboard.biome": "§bBiom§7: {biome}",
"iris.bukkit.scoreboard.biome_loading": "Wird geladen",
"iris.bukkit.scoreboard.biome_unavailable": "Nicht verfügbar",
"iris.bukkit.scoreboard.height": "§bHöhe§7: {height}",
"iris.bukkit.scoreboard.slope": "§bSteigung§7: {slope}",
"iris.bukkit.scoreboard.block_updates": "§bBUD/s§7: {updates}",
@@ -1358,6 +1358,8 @@
"iris.bukkit.scoreboard.carving": "§dTallado§7: {state}",
"iris.bukkit.scoreboard.region": "§bRegión§7: {region}",
"iris.bukkit.scoreboard.biome": "§bBioma§7: {biome}",
"iris.bukkit.scoreboard.biome_loading": "Cargando",
"iris.bukkit.scoreboard.biome_unavailable": "No disponible",
"iris.bukkit.scoreboard.height": "§bAltura§7: {height}",
"iris.bukkit.scoreboard.slope": "§bPendiente§7: {slope}",
"iris.bukkit.scoreboard.block_updates": "§bBUD/s§7: {updates}",
@@ -1358,6 +1358,8 @@
"iris.bukkit.scoreboard.carving": "§dKaiverrus§7: {state}",
"iris.bukkit.scoreboard.region": "§bAlue§7: {region}",
"iris.bukkit.scoreboard.biome": "§bBiometri§7: {biome}",
"iris.bukkit.scoreboard.biome_loading": "Ladataan",
"iris.bukkit.scoreboard.biome_unavailable": "Ei saatavilla",
"iris.bukkit.scoreboard.height": "§bKorkeus§7: {height}",
"iris.bukkit.scoreboard.slope": "§bRivi§7: {slope}",
"iris.bukkit.scoreboard.block_updates": "§bBUDName/s§7: {updates}",
@@ -1358,6 +1358,8 @@
"iris.bukkit.scoreboard.carving": "§dSculpture§7: {state}",
"iris.bukkit.scoreboard.region": "§bRégion§7: {region}",
"iris.bukkit.scoreboard.biome": "§bBiome§7: {biome}",
"iris.bukkit.scoreboard.biome_loading": "Chargement",
"iris.bukkit.scoreboard.biome_unavailable": "Indisponible",
"iris.bukkit.scoreboard.height": "§bHauteur§7: {height}",
"iris.bukkit.scoreboard.slope": "§bPente§7: {slope}",
"iris.bukkit.scoreboard.block_updates": "§bBUD/s§7: {updates}",
@@ -1358,6 +1358,8 @@
"iris.bukkit.scoreboard.carving": "§dעבודה§7: {state}",
"iris.bukkit.scoreboard.region": "§bאזור§7: {region}",
"iris.bukkit.scoreboard.biome": "§bביומי§7: {biome}",
"iris.bukkit.scoreboard.biome_loading": "בטעינה",
"iris.bukkit.scoreboard.biome_unavailable": "לא זמין",
"iris.bukkit.scoreboard.height": "§bגובה§7: {height}",
"iris.bukkit.scoreboard.slope": "§bסלייפ§7: {slope}",
"iris.bukkit.scoreboard.block_updates": "§bBUD/s§7: {updates}",
@@ -1358,6 +1358,8 @@
"iris.bukkit.scoreboard.carving": "§dCarving§7: {state}",
"iris.bukkit.scoreboard.region": "§bRegione§7: {region}",
"iris.bukkit.scoreboard.biome": "§bBioma§7: {biome}",
"iris.bukkit.scoreboard.biome_loading": "Caricamento",
"iris.bukkit.scoreboard.biome_unavailable": "Non disponibile",
"iris.bukkit.scoreboard.height": "§bAltezza§7: {height}",
"iris.bukkit.scoreboard.slope": "§bPendenza§7: {slope}",
"iris.bukkit.scoreboard.block_updates": "§bBUD/s§7: {updates}",
@@ -1358,6 +1358,8 @@
"iris.bukkit.scoreboard.carving": "§dカービング§7: {state}",
"iris.bukkit.scoreboard.region": "§bリージョン§7: {region}",
"iris.bukkit.scoreboard.biome": "§bバイオーム§7: {biome}",
"iris.bukkit.scoreboard.biome_loading": "読み込み中",
"iris.bukkit.scoreboard.biome_unavailable": "利用不可",
"iris.bukkit.scoreboard.height": "§b高さ§7: {height}",
"iris.bukkit.scoreboard.slope": "§bスロープ§7: {slope}",
"iris.bukkit.scoreboard.block_updates": "§bBUD/s§7: {updates}",
@@ -1358,6 +1358,8 @@
"iris.bukkit.scoreboard.carving": "§d조각 중§7: {state}",
"iris.bukkit.scoreboard.region": "§b주요 특징§7: {region}",
"iris.bukkit.scoreboard.biome": "§b바이오메트§7: {biome}",
"iris.bukkit.scoreboard.biome_loading": "불러오는 중",
"iris.bukkit.scoreboard.biome_unavailable": "사용 불가",
"iris.bukkit.scoreboard.height": "§b고도:§7: {height}",
"iris.bukkit.scoreboard.slope": "§b기울기§7: {slope}",
"iris.bukkit.scoreboard.block_updates": "§bBUD/s§7: {updates}",
@@ -1358,6 +1358,8 @@
"iris.bukkit.scoreboard.carving": "§dRaižyti§7: {state}",
"iris.bukkit.scoreboard.region": "§bRegionas§7: {region}",
"iris.bukkit.scoreboard.biome": "§bBiomas§7: {biome}",
"iris.bukkit.scoreboard.biome_loading": "Įkeliama",
"iris.bukkit.scoreboard.biome_unavailable": "Nepasiekiama",
"iris.bukkit.scoreboard.height": "§bAukštis§7: {height}",
"iris.bukkit.scoreboard.slope": "§bSpop§7: {slope}",
"iris.bukkit.scoreboard.block_updates": "§bBID/s§7: {updates}",
@@ -1358,6 +1358,8 @@
"iris.bukkit.scoreboard.carving": "§dsnijden§7: {state}",
"iris.bukkit.scoreboard.region": "§bGebieden§7: {region}",
"iris.bukkit.scoreboard.biome": "§bBiomeName§7: {biome}",
"iris.bukkit.scoreboard.biome_loading": "Laden",
"iris.bukkit.scoreboard.biome_unavailable": "Niet beschikbaar",
"iris.bukkit.scoreboard.height": "§bHoogte§7: {height}",
"iris.bukkit.scoreboard.slope": "§bHelling§7: {slope}",
"iris.bukkit.scoreboard.block_updates": "§bBUD./s§7: {updates}",
@@ -1358,6 +1358,8 @@
"iris.bukkit.scoreboard.carving": "§dRzeźba§7: {state}",
"iris.bukkit.scoreboard.region": "§bObszar§7: {region}",
"iris.bukkit.scoreboard.biome": "§bBioma§7: {biome}",
"iris.bukkit.scoreboard.biome_loading": "Ładowanie",
"iris.bukkit.scoreboard.biome_unavailable": "Niedostępne",
"iris.bukkit.scoreboard.height": "§bWysokość§7: {height}",
"iris.bukkit.scoreboard.slope": "§bNachylenie§7: {slope}",
"iris.bukkit.scoreboard.block_updates": "§bPOD/s§7: {updates}",
@@ -1358,6 +1358,8 @@
"iris.bukkit.scoreboard.carving": "§dEsculpir§7: {state}",
"iris.bukkit.scoreboard.region": "§bRegião§7: {region}",
"iris.bukkit.scoreboard.biome": "§bBioma§7: {biome}",
"iris.bukkit.scoreboard.biome_loading": "A carregar",
"iris.bukkit.scoreboard.biome_unavailable": "Indisponível",
"iris.bukkit.scoreboard.height": "§bAltura§7: {height}",
"iris.bukkit.scoreboard.slope": "§bDeslize§7: {slope}",
"iris.bukkit.scoreboard.block_updates": "§bBUD./s§7: {updates}",
@@ -1358,6 +1358,8 @@
"iris.bukkit.scoreboard.carving": "§dрезьба§7: {state}",
"iris.bukkit.scoreboard.region": "§bрегион§7: {region}",
"iris.bukkit.scoreboard.biome": "§bбиом§7: {biome}",
"iris.bukkit.scoreboard.biome_loading": "Загрузка",
"iris.bukkit.scoreboard.biome_unavailable": "Недоступно",
"iris.bukkit.scoreboard.height": "§bвысота§7: {height}",
"iris.bukkit.scoreboard.slope": "§bСклон§7: {slope}",
"iris.bukkit.scoreboard.block_updates": "§bБУД/s§7: {updates}",
@@ -1358,6 +1358,8 @@
"iris.bukkit.scoreboard.carving": "§dAraba§7: {state}",
"iris.bukkit.scoreboard.region": "§bBölge Bölgesi§7: {region}",
"iris.bukkit.scoreboard.biome": "§bBiyome§7: {biome}",
"iris.bukkit.scoreboard.biome_loading": "Yükleniyor",
"iris.bukkit.scoreboard.biome_unavailable": "Kullanılamıyor",
"iris.bukkit.scoreboard.height": "§bYükseklik§7: {height}",
"iris.bukkit.scoreboard.slope": "§bSlopee§7: {slope}",
"iris.bukkit.scoreboard.block_updates": "§bBUDÜ/s§7: {updates}",
@@ -1358,6 +1358,8 @@
"iris.bukkit.scoreboard.carving": "§dQuan tâm§7: {state}",
"iris.bukkit.scoreboard.region": "§bVùng§7: {region}",
"iris.bukkit.scoreboard.biome": "§bĐôi§7: {biome}",
"iris.bukkit.scoreboard.biome_loading": "Đang tải",
"iris.bukkit.scoreboard.biome_unavailable": "Không khả dụng",
"iris.bukkit.scoreboard.height": "§bChiều cao§7: {height}",
"iris.bukkit.scoreboard.slope": "§bTrượt§7: {slope}",
"iris.bukkit.scoreboard.block_updates": "§bBAD/s§7: {updates}",
@@ -1358,6 +1358,8 @@
"iris.bukkit.scoreboard.carving": "§d雕刻§7: {state}",
"iris.bukkit.scoreboard.region": "§b地区§7: {region}",
"iris.bukkit.scoreboard.biome": "§b生物团§7: {biome}",
"iris.bukkit.scoreboard.biome_loading": "加载中",
"iris.bukkit.scoreboard.biome_unavailable": "不可用",
"iris.bukkit.scoreboard.height": "§b高度§7: {height}",
"iris.bukkit.scoreboard.slope": "§b斜坡§7: {slope}",
"iris.bukkit.scoreboard.block_updates": "§b学生会/s§7: {updates}",
@@ -1358,6 +1358,8 @@
"iris.bukkit.scoreboard.carving": "§d雕刻§7: {state}",
"iris.bukkit.scoreboard.region": "§b地區§7: {region}",
"iris.bukkit.scoreboard.biome": "§b生物團§7: {biome}",
"iris.bukkit.scoreboard.biome_loading": "載入中",
"iris.bukkit.scoreboard.biome_unavailable": "無法使用",
"iris.bukkit.scoreboard.height": "§b高度§7: {height}",
"iris.bukkit.scoreboard.slope": "§b斜坡§7: {slope}",
"iris.bukkit.scoreboard.block_updates": "§b學生會/s§7: {updates}",