diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 1f8e028c..0b1508d3 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -18,6 +18,7 @@ dependencies { modCompileOnly(libs.fabric.waystones) modCompileOnly(libs.worldtools) implementation(libs.oldbiomes) + implementation(libs.sqlite) } tasks { diff --git a/common/src/main/java/xaeroplus/feature/render/highlights/ChunkHighlightDatabase.java b/common/src/main/java/xaeroplus/feature/render/highlights/ChunkHighlightDatabase.java index e0f08847..c16008ba 100644 --- a/common/src/main/java/xaeroplus/feature/render/highlights/ChunkHighlightDatabase.java +++ b/common/src/main/java/xaeroplus/feature/render/highlights/ChunkHighlightDatabase.java @@ -3,6 +3,7 @@ import com.google.common.collect.Lists; import net.minecraft.resources.ResourceKey; import net.minecraft.world.level.Level; +import org.rfresh.sqlite.JDBC; import xaero.map.WorldMap; import xaeroplus.XaeroPlus; import xaeroplus.feature.render.highlights.db.DatabaseMigrator; @@ -28,6 +29,10 @@ public class ChunkHighlightDatabase implements Closeable { public ChunkHighlightDatabase(String worldId, String databaseName) { this.databaseName = databaseName; try { + // workaround for other mods that might have forced the JDBC drivers to be init + // before we are on the classpath + var jdbcClass = JDBC.class; + final Path dbPath = WorldMap.saveFolder.toPath().resolve(worldId).resolve(databaseName + ".db"); boolean shouldRunMigrations = dbPath.toFile().exists(); connection = DriverManager.getConnection("jdbc:rfresh_sqlite:" + dbPath); diff --git a/common/src/main/java/xaeroplus/module/impl/PaletteNewChunks.java b/common/src/main/java/xaeroplus/module/impl/PaletteNewChunks.java index c59c8009..21ac7eab 100644 --- a/common/src/main/java/xaeroplus/module/impl/PaletteNewChunks.java +++ b/common/src/main/java/xaeroplus/module/impl/PaletteNewChunks.java @@ -16,7 +16,6 @@ import xaeroplus.Globals; import xaeroplus.XaeroPlus; import xaeroplus.event.ChunkDataEvent; -import xaeroplus.feature.render.highlights.ChunkHighlightLocalCache; import xaeroplus.feature.render.highlights.SavableHighlightCacheInstance; import xaeroplus.module.Module; import xaeroplus.settings.Settings; @@ -48,23 +47,22 @@ public void onChunkData(ChunkDataEvent event) { try { if (newChunksCache.get().isHighlighted(x, z, dim)) return; if (newChunksInverseCache.get().isHighlighted(x, z, dim)) return; - if (checkNewChunk(dim, chunk)) newChunksCache.get().addHighlight(x, z); + if (isNewChunk(dim, chunk)) newChunksCache.get().addHighlight(x, z); else newChunksInverseCache.get().addHighlight(x, z); } catch (final Exception e) { XaeroPlus.LOGGER.error("Error checking palette NewChunk at [{} {}]", x, z, e); } } - private boolean checkNewChunk(final ResourceKey dim, final LevelChunk chunk) { + private boolean isNewChunk(final ResourceKey dim, final LevelChunk chunk) { if (dim == OVERWORLD) { - return checkNewChunkBiomePalette(chunk, true) - // it's possible for the overworld to have a plains biome - // so we need to check the blockstate palette as well - || checkNewChunkBlockStatePalette(chunk); + return plainsBiomePresent(chunk) + ? checkNewChunkBlockStatePalette(chunk) + : checkNewChunkBiomePalette(chunk); } else if (dim == NETHER) { - return checkNewChunkBiomePalette(chunk, false); + return checkNewChunkBiomePalette(chunk); } else if (dim == END) { - return checkNewChunkBiomePalette(chunk, false); + return checkNewChunkBiomePalette(chunk); } return false; } @@ -104,7 +102,7 @@ private boolean checkNewChunkBlockStatePalette(LevelChunk chunk) { Palette firstPalette = firstSection.getStates().data.palette(); if (isNotLinearOrHashMapPalette(firstPalette)) return false; if (firstPalette instanceof LinearPalette) { - return firstPalette.valueFor(0).getBlock() == Blocks.AIR; + return firstPalette.valueFor(0).is(Blocks.AIR); } else { // HashMapPalette // we could iterate through more sections but this is good enough in most cases // checking every blockstate is relatively expensive @@ -129,36 +127,37 @@ private boolean checkNewChunkBlockStatePalette(LevelChunk chunk) { * For example, this solves the issue of player activity modifying the chunk, and therefore possibly causing palette ID's * without matching data present, at the same time as we load them. */ - private boolean checkNewChunkBiomePalette(LevelChunk chunk, boolean checkPlainsPresent) { + private boolean checkNewChunkBiomePalette(LevelChunk chunk) { var sections = chunk.getSections(); if (sections.length == 0) return false; var firstSection = sections[0]; var biomes = firstSection.getBiomes(); if (biomes instanceof PalettedContainer> biomesPaletteContainer) { var firstPalette = biomesPaletteContainer.data.palette(); - // Alternatively we could check the first palette entry for plains in the nether/end - // but checking data entries allows this to also work in the overworld - // and plains is not set to the first entry in certain cases in the nether - var plainsInPalette = firstPalette.maybeHas(holder -> holder.unwrapKey().get().equals(Biomes.PLAINS)); - // only needed in overworld - return checkPlainsPresent - ? plainsInPalette && plainsNotPresentInData(biomesPaletteContainer) - : plainsInPalette; + // assumes that plains is not a real biome present in this chunk + return firstPalette.maybeHas(PaletteNewChunks::isPlainsBiome); } return false; } - private boolean plainsNotPresentInData(PalettedContainer> biomesPaletteContainer) { - var palette = biomesPaletteContainer.data.palette(); - var storage = biomesPaletteContainer.data.storage(); - presentStateIdsBuf.clear(); // reusing to reduce gc pressure - storage.getAll(presentStateIdsBuf::add); - for (int id : presentStateIdsBuf) { - if (palette.valueFor(id).unwrapKey().get().equals(Biomes.PLAINS)) { - return false; + private boolean plainsBiomePresent(LevelChunk chunk) { + var sections = chunk.getSections(); + if (sections.length == 0) return false; + var firstSection = sections[0]; + var biomes = firstSection.getBiomes(); + if (biomes instanceof PalettedContainer> biomesPaletteContainer) { + var palette = biomesPaletteContainer.data.palette(); + if (!palette.maybeHas(PaletteNewChunks::isPlainsBiome)) return false; + var storage = biomesPaletteContainer.data.storage(); + presentStateIdsBuf.clear(); // reusing to reduce gc pressure + storage.getAll(presentStateIdsBuf::add); + for (int id : presentStateIdsBuf) { + if (isPlainsBiome(palette.valueFor(id))) { + return true; + } } } - return true; + return false; } private boolean isNotLinearOrHashMapPalette(Palette palette) { @@ -173,6 +172,10 @@ private synchronized boolean checkForExtraPaletteEntries(PalettedContainer.Data< return palette.getSize() > presentStateIdsBuf.size(); } + private static boolean isPlainsBiome(Holder holder) { + return holder.is(Biomes.PLAINS); + } + @Override public void onEnable() { Globals.drawManager.registerChunkHighlightProvider( @@ -187,12 +190,6 @@ public void onEnable() { public void onDisable() { newChunksCache.onDisable(); newChunksInverseCache.onDisable(); - if (newChunksCache.get() instanceof ChunkHighlightLocalCache localCache) { - localCache.reset(); - } - if (newChunksInverseCache.get() instanceof ChunkHighlightLocalCache localCache) { - localCache.reset(); - } Globals.drawManager.unregisterChunkHighlightProvider(this.getClass()); }