mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-23 16:44:06 +00:00
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:
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}",
|
||||
|
||||
@@ -0,0 +1,282 @@
|
||||
package art.arcane.iris.core.service;
|
||||
|
||||
import art.arcane.iris.core.IrisSettings;
|
||||
import art.arcane.iris.core.loader.IrisData;
|
||||
import art.arcane.iris.core.runtime.jigsaw.JigsawStudioMode;
|
||||
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.mantle.EngineMantle;
|
||||
import art.arcane.iris.engine.object.IrisBiome;
|
||||
import art.arcane.iris.engine.object.IrisDimension;
|
||||
import art.arcane.iris.engine.object.IrisRegion;
|
||||
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
|
||||
import art.arcane.iris.spi.IrisLogging;
|
||||
import art.arcane.iris.spi.IrisPlatform;
|
||||
import art.arcane.iris.spi.IrisPlatforms;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import art.arcane.iris.spi.PlatformRegistries;
|
||||
import art.arcane.iris.util.common.scheduling.J;
|
||||
import art.arcane.volmlib.util.board.Board;
|
||||
import art.arcane.volmlib.util.board.BoardSettings;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
||||
import org.junit.Test;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.mockito.MockedConstruction;
|
||||
import org.mockito.MockedStatic;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.same;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doCallRealMethod;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.mockConstruction;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class BoardSVCSavedBiomeTest {
|
||||
private static IrisPlatform previousPlatform;
|
||||
|
||||
@BeforeClass
|
||||
public static void bindPlatform() {
|
||||
previousPlatform = IrisPlatforms.isBound() ? IrisPlatforms.get() : null;
|
||||
IrisPlatforms.unbind();
|
||||
IrisPlatform platform = mock(IrisPlatform.class);
|
||||
PlatformRegistries registries = mock(PlatformRegistries.class);
|
||||
when(platform.registries()).thenReturn(registries);
|
||||
when(registries.block(anyString())).thenReturn(mock(PlatformBlockState.class));
|
||||
IrisPlatforms.bind(platform);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void restorePlatform() {
|
||||
IrisPlatforms.unbind();
|
||||
if (previousPlatform != null) {
|
||||
IrisPlatforms.bind(previousPlatform);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void worldEntryLoadingKeepsRefreshAliveAndRecoversWithoutMovement() throws Exception {
|
||||
try (Fixture fixture = new Fixture()) {
|
||||
fixture.biomeFailure = new SavedBiomeUnavailableException("Saved biome is loading", true);
|
||||
|
||||
fixture.service.on(new PlayerChangedWorldEvent(fixture.player, mock(World.class)));
|
||||
|
||||
assertTrue(fixture.lines().contains("Loading"));
|
||||
assertEquals(1, fixture.ticks.size());
|
||||
fixture.logging.verifyNoInteractions();
|
||||
|
||||
fixture.biomeFailure = null;
|
||||
fixture.environment = environment("Saved region", "Saved biome");
|
||||
fixture.tick();
|
||||
|
||||
assertTrue(fixture.lines().contains("Saved region"));
|
||||
assertTrue(fixture.lines().contains("Saved biome"));
|
||||
assertFalse(fixture.lines().contains("Loading"));
|
||||
assertEquals(1, fixture.ticks.size());
|
||||
verify(fixture.engine, times(2)).getBiomeOrMantleEnvironment(8, 160, 8);
|
||||
verify(fixture.engine, never()).getRegion(anyInt(), anyInt(), anyInt());
|
||||
verify(fixture.engine, never()).getBiomeOrMantle(anyInt(), anyInt(), anyInt());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unsavedBiomeUsesTheMantleOverride() throws Exception {
|
||||
try (Fixture fixture = new Fixture()) {
|
||||
IrisBiome natural = mock(IrisBiome.class);
|
||||
IrisBiome flooded = mock(IrisBiome.class);
|
||||
when(natural.getName()).thenReturn("Natural cave");
|
||||
when(flooded.getName()).thenReturn("Flooded cave");
|
||||
when(fixture.engine.getHeight(8, 8)).thenReturn(200);
|
||||
when(fixture.engine.getCaveBiome(8, 160, 8)).thenReturn(natural);
|
||||
when(fixture.engine.getCaveOrMantleBiome(8, 160, 8)).thenReturn(flooded);
|
||||
when(fixture.engine.getDimension()).thenReturn(fixture.environment.dimension());
|
||||
when(fixture.engine.getData()).thenReturn(fixture.environment.data());
|
||||
doCallRealMethod().when(fixture.engine).getBiome(8, 160, 8);
|
||||
doCallRealMethod().when(fixture.engine).getBiomeOrMantle(8, 160, 8);
|
||||
doCallRealMethod().when(fixture.engine).getBiomeEnvironment(8, 160, 8);
|
||||
doCallRealMethod().when(fixture.engine).getBiomeOrMantleEnvironment(8, 160, 8);
|
||||
|
||||
fixture.service.updatePlayer(fixture.player);
|
||||
|
||||
assertTrue(fixture.lines().contains("Flooded cave"));
|
||||
assertFalse(fixture.lines().contains("Natural cave"));
|
||||
verify(fixture.engine, never()).getBiomeEnvironment(anyInt(), anyInt(), anyInt());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unavailableBiomeReportsOncePerContextAndKeepsRefreshing() throws Exception {
|
||||
try (Fixture fixture = new Fixture()) {
|
||||
fixture.biomeFailure = new SavedBiomeUnavailableException("Saved pack is missing", false);
|
||||
fixture.service.updatePlayer(fixture.player);
|
||||
|
||||
assertTrue(fixture.lines().contains("Unavailable"));
|
||||
assertFalse(fixture.lines().contains("Loading"));
|
||||
fixture.biomeFailure = new SavedBiomeUnavailableException("Saved pack is missing", false);
|
||||
fixture.tick();
|
||||
fixture.logging.verify(() -> IrisLogging.reportError(anyString(),
|
||||
any(SavedBiomeUnavailableException.class)), times(1));
|
||||
|
||||
fixture.location = new Location(fixture.world, 24, 96, 8);
|
||||
fixture.tick();
|
||||
|
||||
fixture.logging.verify(() -> IrisLogging.reportError(anyString(),
|
||||
any(SavedBiomeUnavailableException.class)), times(2));
|
||||
assertEquals(1, fixture.ticks.size());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void changingWorldClearsThePreviousBiomeWhileTheNewOneLoads() throws Exception {
|
||||
try (Fixture fixture = new Fixture()) {
|
||||
fixture.environment = environment("Previous region", "Previous biome");
|
||||
fixture.service.updatePlayer(fixture.player);
|
||||
assertTrue(fixture.lines().contains("Previous biome"));
|
||||
World previous = fixture.world;
|
||||
fixture.world = world("second-studio");
|
||||
fixture.location = new Location(fixture.world, 8, 96, 8);
|
||||
fixture.biomeFailure = new SavedBiomeUnavailableException("Saved biome is loading", true);
|
||||
|
||||
fixture.service.on(new PlayerChangedWorldEvent(fixture.player, previous));
|
||||
|
||||
assertTrue(fixture.lines().contains("Loading"));
|
||||
assertFalse(fixture.lines().contains("Previous region"));
|
||||
assertFalse(fixture.lines().contains("Previous biome"));
|
||||
assertEquals(1, fixture.ticks.size());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jigsawViewDoesNotQueryBiomesAndOrdinaryViewStillRetries() throws Exception {
|
||||
try (Fixture fixture = new Fixture()) {
|
||||
fixture.biomeFailure = new SavedBiomeUnavailableException("Saved biome is loading", true);
|
||||
JigsawStudioBoardContext context = new JigsawStudioBoardContext(
|
||||
fixture.world.getUID(), UUID.randomUUID(), "village", JigsawStudioMode.PLANAR_JIGSAW,
|
||||
"Corner", "Corner", "mossy", JigsawStudioBoardState.SAVED, "Open the chest");
|
||||
|
||||
fixture.service.applyJigsawContext(fixture.player, context);
|
||||
|
||||
assertEquals(BoardSVC.jigsawLines(context), fixture.service.getLines(fixture.player));
|
||||
verify(fixture.engine, never()).getBiomeOrMantleEnvironment(anyInt(), anyInt(), anyInt());
|
||||
assertTrue(fixture.ticks.isEmpty());
|
||||
|
||||
fixture.service.clearJigsawContext(fixture.player);
|
||||
|
||||
assertTrue(fixture.lines().contains("Loading"));
|
||||
assertFalse(fixture.lines().contains("Jigsaw Studio"));
|
||||
assertEquals(1, fixture.ticks.size());
|
||||
}
|
||||
}
|
||||
|
||||
private static BiomeEnvironment environment(String regionName, String biomeName) {
|
||||
IrisRegion region = mock(IrisRegion.class);
|
||||
IrisBiome biome = mock(IrisBiome.class);
|
||||
when(region.getName()).thenReturn(regionName);
|
||||
when(biome.getName()).thenReturn(biomeName);
|
||||
return new BiomeEnvironment(1L, biome, region, mock(IrisDimension.class), mock(IrisData.class));
|
||||
}
|
||||
|
||||
private static World world(String name) {
|
||||
World world = mock(World.class);
|
||||
when(world.getUID()).thenReturn(UUID.randomUUID());
|
||||
when(world.getName()).thenReturn(name);
|
||||
when(world.getMinHeight()).thenReturn(-64);
|
||||
return world;
|
||||
}
|
||||
|
||||
private static void setField(BoardSVC service, String name, Object value) throws ReflectiveOperationException {
|
||||
Field field = BoardSVC.class.getDeclaredField(name);
|
||||
field.setAccessible(true);
|
||||
field.set(service, value);
|
||||
}
|
||||
|
||||
private static final class Fixture implements AutoCloseable {
|
||||
private final MockedStatic<J> scheduling = mockStatic(J.class);
|
||||
private final MockedStatic<IrisToolbelt> toolbelt = mockStatic(IrisToolbelt.class);
|
||||
private final MockedStatic<IrisSettings> settings = mockStatic(IrisSettings.class);
|
||||
private final MockedStatic<IrisLogging> logging = mockStatic(IrisLogging.class);
|
||||
private final MockedConstruction<Board> boards = mockConstruction(Board.class,
|
||||
(board, context) -> when(board.ownsScoreboardAssignment()).thenReturn(true));
|
||||
private final BoardSVC service = new BoardSVC();
|
||||
private final Player player = mock(Player.class);
|
||||
private final Engine engine = mock(Engine.class);
|
||||
private final ArrayDeque<Runnable> ticks = new ArrayDeque<>();
|
||||
private World world = world("first-studio");
|
||||
private Location location = new Location(world, 8, 96, 8);
|
||||
private BiomeEnvironment environment = environment("Ready region", "Ready biome");
|
||||
private SavedBiomeUnavailableException biomeFailure;
|
||||
|
||||
private Fixture() throws ReflectiveOperationException {
|
||||
setField(service, "boardEnabled", true);
|
||||
setField(service, "settings", BoardSettings.builder().boardProvider(service).build());
|
||||
settings.when(IrisSettings::get).thenReturn(new IrisSettings());
|
||||
when(player.getUniqueId()).thenReturn(UUID.randomUUID());
|
||||
when(player.isOnline()).thenReturn(true);
|
||||
when(player.getWorld()).thenAnswer(invocation -> world);
|
||||
when(player.getLocation()).thenAnswer(invocation -> location);
|
||||
scheduling.when(() -> J.isOwnedByCurrentRegion(player)).thenReturn(true);
|
||||
scheduling.when(() -> J.runEntity(same(player), any(Runnable.class))).thenAnswer(invocation -> {
|
||||
invocation.getArgument(1, Runnable.class).run();
|
||||
return true;
|
||||
});
|
||||
scheduling.when(() -> J.runEntity(same(player), any(Runnable.class), eq(20), any(Runnable.class)))
|
||||
.thenAnswer(invocation -> ticks.add(invocation.getArgument(1, Runnable.class)));
|
||||
PlatformChunkGenerator generator = mock(PlatformChunkGenerator.class);
|
||||
when(generator.isStudio()).thenReturn(true);
|
||||
when(generator.getEngine()).thenReturn(engine);
|
||||
toolbelt.when(() -> IrisToolbelt.access(any(World.class))).thenReturn(generator);
|
||||
when(engine.getGeneratedPerSecond()).thenReturn(10D);
|
||||
EngineMantle mantle = mock(EngineMantle.class);
|
||||
when(engine.getMantle()).thenReturn(mantle);
|
||||
doAnswer(invocation -> sampledEnvironment()).when(engine).getBiomeEnvironment(anyInt(), anyInt(), anyInt());
|
||||
doAnswer(invocation -> sampledEnvironment()).when(engine).getBiomeOrMantleEnvironment(anyInt(), anyInt(), anyInt());
|
||||
doAnswer(invocation -> sampledEnvironment().region()).when(engine).getRegion(anyInt(), anyInt(), anyInt());
|
||||
doAnswer(invocation -> sampledEnvironment().biome()).when(engine).getBiomeOrMantle(anyInt(), anyInt(), anyInt());
|
||||
}
|
||||
|
||||
private BiomeEnvironment sampledEnvironment() {
|
||||
if (biomeFailure != null) {
|
||||
throw biomeFailure;
|
||||
}
|
||||
return environment;
|
||||
}
|
||||
|
||||
private String lines() {
|
||||
return String.join("\n", service.getLines(player));
|
||||
}
|
||||
|
||||
private void tick() {
|
||||
assertFalse("The ordinary scoreboard must schedule its next refresh", ticks.isEmpty());
|
||||
ticks.remove().run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
boards.close();
|
||||
logging.close();
|
||||
settings.close();
|
||||
toolbelt.close();
|
||||
scheduling.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -645,6 +645,7 @@ public class IrisEngineGenerationRuntimeScopeTest {
|
||||
when(saved.resolveCaveBase(19, -3)).thenReturn(Optional.of(environment));
|
||||
|
||||
assertSame(environment, engine.getBiomeEnvironment(19, 20, -3));
|
||||
assertSame(environment, engine.getBiomeOrMantleEnvironment(19, 20, -3));
|
||||
assertSame(environment, engine.getSurfaceBiomeEnvironment(19, -3));
|
||||
assertSame(environment.biome(), engine.getBiome(19, 20, -3));
|
||||
assertSame(environment.biome(), engine.getBiomeOrMantle(19, 20, -3));
|
||||
|
||||
Reference in new issue
Block a user