diff --git a/core/src/main/java/com/volmit/iris/core/gui/PaletteCatalog.java b/core/src/main/java/com/volmit/iris/core/gui/PaletteCatalog.java index 3505928bd..a4d19cf6a 100644 --- a/core/src/main/java/com/volmit/iris/core/gui/PaletteCatalog.java +++ b/core/src/main/java/com/volmit/iris/core/gui/PaletteCatalog.java @@ -54,7 +54,7 @@ record PaletteCatalog(List regions, List biomesOutsideRegio } BiomeEntry biome(String key) { - return biomes.get(key); + return key == null ? null : biomes.get(key); } RegionEntry region(String key) { diff --git a/core/src/main/java/com/volmit/iris/core/gui/PaletteNavigator.java b/core/src/main/java/com/volmit/iris/core/gui/PaletteNavigator.java index e6d06b7dc..51112f2cc 100644 --- a/core/src/main/java/com/volmit/iris/core/gui/PaletteNavigator.java +++ b/core/src/main/java/com/volmit/iris/core/gui/PaletteNavigator.java @@ -27,7 +27,6 @@ import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.DefaultListCellRenderer; import javax.swing.DefaultListModel; -import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; @@ -72,12 +71,11 @@ final class PaletteNavigator extends JPanel { private static final String DETAIL_COLOR = "#8890A0"; private final Listener listener; - private final boolean followsPlayer; + private final boolean showsPlayerLocation; private final CardLayout cards = new CardLayout(); private final JPanel cardPanel = new JPanel(cards); private final JLabel regionLabel = new JLabel(); - private final JLabel biomeLabel = new JLabel(); - private final JCheckBox followCheckBox = new JCheckBox("Follow me", true); + private final JLabel positionLabel = new JLabel(); private final DefaultListModel hereRows = new DefaultListModel<>(); private final JList hereList = new JList<>(hereRows); private final JTextField searchField = new JTextField(); @@ -90,9 +88,9 @@ final class PaletteNavigator extends JPanel { private int selectedLayer; private boolean updatingSelection; - PaletteNavigator(boolean followsPlayer, Listener listener) { + PaletteNavigator(boolean showsPlayerLocation, Listener listener) { super(new BorderLayout()); - this.followsPlayer = followsPlayer; + this.showsPlayerLocation = showsPlayerLocation; this.listener = listener; setBackground(SIDEBAR_BACKGROUND); cardPanel.add(buildHereCard(), HERE_CARD); @@ -109,13 +107,8 @@ final class PaletteNavigator extends JPanel { } void showLocation(PlayerLocation nextLocation) { - String previousBiome = location == null ? null : location.biomeKey(); location = nextLocation; refreshHere(); - boolean enteredNewBiome = nextLocation.biomeKey() != null && !nextLocation.biomeKey().equals(previousBiome); - if (enteredNewBiome && followCheckBox.isSelected()) { - chooseBiome(nextLocation.biomeKey(), selectedLayer); - } } void markSelected(String biomeKey, int layer) { @@ -139,7 +132,7 @@ final class PaletteNavigator extends JPanel { JToggleButton overview = createTab("Overview", OVERVIEW_CARD, group); bar.add(here); bar.add(overview); - (followsPlayer ? here : overview).doClick(); + (showsPlayerLocation ? here : overview).doClick(); return bar; } @@ -174,17 +167,11 @@ final class PaletteNavigator extends JPanel { BorderFactory.createMatteBorder(1, 0, 1, 0, BORDER), BorderFactory.createEmptyBorder(9, 12, 9, 12) )); - for (JLabel label : List.of(regionLabel, biomeLabel)) { + for (JLabel label : List.of(regionLabel, positionLabel)) { label.setForeground(PRIMARY_TEXT); label.setFont(ITEM_FONT); location.add(label); } - followCheckBox.setOpaque(false); - followCheckBox.setForeground(SECONDARY_TEXT); - followCheckBox.setFont(ITEM_FONT); - followCheckBox.setToolTipText("Open the biome you walk into"); - followCheckBox.setVisible(followsPlayer); - location.add(followCheckBox); hereList.setBackground(SIDEBAR_BACKGROUND); hereList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); @@ -267,7 +254,7 @@ final class PaletteNavigator extends JPanel { updatingSelection = true; try { hereRows.clear(); - if (!followsPlayer) { + if (!showsPlayerLocation) { showHereMessage("Run /iris std pal in-game", "to see where you are standing."); return; } @@ -278,7 +265,7 @@ final class PaletteNavigator extends JPanel { switch (location.status()) { case OFFLINE -> showHereMessage("You are offline.", " "); case OUTSIDE_IRIS_WORLD -> showHereMessage("You are not in an Iris world.", " "); - case IN_BIOME -> showHereRows(location.regionKey(), location.biomeKey()); + case IN_REGION -> showHereRows(location); } selectInHereList(); } finally { @@ -288,22 +275,16 @@ final class PaletteNavigator extends JPanel { private void showHereMessage(String firstLine, String secondLine) { regionLabel.setText(firstLine); - biomeLabel.setText(secondLine); + positionLabel.setText(secondLine); } - private void showHereRows(String regionKey, String biomeKey) { - RegionEntry region = catalog.region(regionKey); - BiomeEntry biome = catalog.biome(biomeKey); - regionLabel.setText(labeled("Region", region == null ? regionKey : region.name(), regionKey)); - biomeLabel.setText(labeled("Biome", biome == null ? biomeKey : biome.name(), biomeKey)); - if (biome != null) { - hereRows.addElement(HereRow.header("Layers here")); - for (int layer = 0; layer < biome.layerSummaries().size(); layer++) { - hereRows.addElement(new HereRow(layerText(layer, biome), biomeKey, layer, false)); - } - if (biome.layerSummaries().isEmpty()) { - hereRows.addElement(HereRow.header("This biome has no palette layers")); - } + private void showHereRows(PlayerLocation here) { + RegionEntry region = catalog.region(here.regionKey()); + regionLabel.setText(labeled("Region", region == null ? here.regionKey() : region.name(), here.regionKey())); + positionLabel.setText(here.isBelowSurfaceBiome() ? "Underground, below the surface biome" : "On the surface"); + addBiomeLayers("Surface biome", here.surfaceBiomeKey()); + if (here.isBelowSurfaceBiome()) { + addBiomeLayers("Biome at your position", here.biomeAtPositionKey()); } if (region == null) { return; @@ -311,12 +292,25 @@ final class PaletteNavigator extends JPanel { hereRows.addElement(HereRow.header("Other biomes in this region")); for (String otherKey : region.allBiomeKeys()) { BiomeEntry other = catalog.biome(otherKey); - if (!otherKey.equals(biomeKey) && other != null) { + boolean shownAbove = otherKey.equals(here.surfaceBiomeKey()) || otherKey.equals(here.biomeAtPositionKey()); + if (!shownAbove && other != null) { hereRows.addElement(new HereRow(biomeText(other), otherKey, -1, false)); } } } + private void addBiomeLayers(String title, String biomeKey) { + BiomeEntry biome = catalog.biome(biomeKey); + if (biome == null) { + return; + } + hereRows.addElement(HereRow.header(title)); + hereRows.addElement(new HereRow(biomeText(biome), biomeKey, -1, false)); + for (int layer = 0; layer < biome.layerSummaries().size(); layer++) { + hereRows.addElement(new HereRow(layerText(layer, biome), biomeKey, layer, false)); + } + } + private void rebuildOverview() { if (catalog == null) { return; @@ -470,6 +464,9 @@ final class PaletteNavigator extends JPanel { private static final class HereRowRenderer extends DefaultListCellRenderer { private static final long serialVersionUID = 2785341117408251320L; + private static final int HEADER_INDENT = 11; + private static final int BIOME_INDENT = 20; + private static final int LAYER_INDENT = 34; @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean selected, boolean focus) { @@ -480,7 +477,7 @@ final class PaletteNavigator extends JPanel { setFont(row.header() ? HEADER_FONT : ITEM_FONT); setForeground(row.header() ? ACCENT : selected ? PRIMARY_TEXT : SECONDARY_TEXT); setBackground(selected && selectable ? FIELD_BACKGROUND.brighter() : SIDEBAR_BACKGROUND); - int indent = row.header() ? 11 : 20; + int indent = row.header() ? HEADER_INDENT : row.layer() >= 0 ? LAYER_INDENT : BIOME_INDENT; setBorder(BorderFactory.createEmptyBorder(row.header() ? 11 : 4, indent, 4, 10)); return this; } diff --git a/core/src/main/java/com/volmit/iris/core/gui/PlayerLocationTracker.java b/core/src/main/java/com/volmit/iris/core/gui/PlayerLocationTracker.java index b240c5c1c..00eb1cc88 100644 --- a/core/src/main/java/com/volmit/iris/core/gui/PlayerLocationTracker.java +++ b/core/src/main/java/com/volmit/iris/core/gui/PlayerLocationTracker.java @@ -75,12 +75,18 @@ final class PlayerLocationTracker { if (engine == null) { return PlayerLocation.OUTSIDE_IRIS_WORLD; } - IrisRegion region = engine.getRegion(player.getLocation()); - IrisBiome biome = engine.getBiomeOrMantle(player.getLocation()); - if (region == null || biome == null) { + Location position = player.getLocation(); + IrisRegion region = engine.getRegion(position); + String surfaceBiome = keyOf(engine.getSurfaceBiome(position.getBlockX(), position.getBlockZ())); + String biomeAtPosition = keyOf(engine.getBiomeOrMantle(position)); + if (region == null || region.getLoadKey() == null || surfaceBiome == null) { return PlayerLocation.OUTSIDE_IRIS_WORLD; } - return new PlayerLocation(Status.IN_BIOME, region.getLoadKey(), biome.getLoadKey()); + return new PlayerLocation(Status.IN_REGION, region.getLoadKey(), surfaceBiome, biomeAtPosition); + } + + private static String keyOf(IrisBiome biome) { + return biome == null ? null : biome.getLoadKey(); } private static Engine engineAt(Location location) { @@ -94,12 +100,17 @@ final class PlayerLocationTracker { enum Status { OFFLINE, OUTSIDE_IRIS_WORLD, - IN_BIOME + IN_REGION } - record PlayerLocation(Status status, String regionKey, String biomeKey) { - static final PlayerLocation OFFLINE = new PlayerLocation(Status.OFFLINE, null, null); - static final PlayerLocation OUTSIDE_IRIS_WORLD = new PlayerLocation(Status.OUTSIDE_IRIS_WORLD, null, null); + // Biomes are 3D: underground, the biome at the player's position can differ from the surface biome above it. + record PlayerLocation(Status status, String regionKey, String surfaceBiomeKey, String biomeAtPositionKey) { + static final PlayerLocation OFFLINE = new PlayerLocation(Status.OFFLINE, null, null, null); + static final PlayerLocation OUTSIDE_IRIS_WORLD = new PlayerLocation(Status.OUTSIDE_IRIS_WORLD, null, null, null); + + boolean isBelowSurfaceBiome() { + return biomeAtPositionKey != null && !biomeAtPositionKey.equals(surfaceBiomeKey); + } } interface Listener {