From 375cc3b17f375ee27051a3f7a317cef2db988d8b Mon Sep 17 00:00:00 2001 From: Algent Date: Tue, 8 Sep 2026 15:11:28 +0200 Subject: [PATCH 1/4] fix: gate vein repair on verified pattern A fallback pattern can be wrong when world data is missing. Rewriting cached and team coordinates against it can permanently relocate veins and discard rescans. Refs GTNewHorizons/GT5-Unofficial#7919 --- .../visualprospecting/database/DimensionCache.java | 9 ++++++++- .../visualprospecting/teams/TeamProspectionData.java | 8 +++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/sinthoras/visualprospecting/database/DimensionCache.java b/src/main/java/com/sinthoras/visualprospecting/database/DimensionCache.java index e6c889e..92cc88a 100644 --- a/src/main/java/com/sinthoras/visualprospecting/database/DimensionCache.java +++ b/src/main/java/com/sinthoras/visualprospecting/database/DimensionCache.java @@ -19,6 +19,7 @@ import com.sinthoras.visualprospecting.database.veintypes.VeinType; import com.sinthoras.visualprospecting.database.veintypes.VeinTypeCaching; +import gregtech.common.GTWorldgenerator; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; /** @@ -127,6 +128,12 @@ private void loadOres(NBTTagCompound ores) { int size = chunkXArray.length; oreChunks.ensureCapacity(oreChunks.size() + size); + final boolean patternVerified = GTWorldgenerator.isOregenPatternVerified(); + if (!patternVerified) { + preventSaving = true; + VP.LOG.warn("Dimension {}: ore vein pattern is not confirmed, data will not be modified.", dimensionId); + } + int unknownVeinTypes = 0; int repairedCoordinates = 0; int discardedRescans = 0; @@ -150,7 +157,7 @@ private void loadOres(NBTTagCompound ores) { veinType, depletedArray[i] == 1, source); - if (position.chunkX != chunkXArray[i] || position.chunkZ != chunkZArray[i]) { + if (patternVerified && (position.chunkX != chunkXArray[i] || position.chunkZ != chunkZArray[i])) { repairedCoordinates++; if (source == VeinSource.RESCAN) { discardedRescans++; diff --git a/src/main/java/com/sinthoras/visualprospecting/teams/TeamProspectionData.java b/src/main/java/com/sinthoras/visualprospecting/teams/TeamProspectionData.java index b948a87..cab029f 100644 --- a/src/main/java/com/sinthoras/visualprospecting/teams/TeamProspectionData.java +++ b/src/main/java/com/sinthoras/visualprospecting/teams/TeamProspectionData.java @@ -22,6 +22,7 @@ import com.sinthoras.visualprospecting.Utils; import com.sinthoras.visualprospecting.VP; +import gregtech.common.GTWorldgenerator; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; @@ -77,7 +78,12 @@ private void ensureExpanded() { } pendingBlob = null; } - repairedVeinCoordinates = normalizeVeinCoordinates(discoveredVeins) | normalizeVeinCoordinates(depletedVeins); + if (GTWorldgenerator.isOregenPatternVerified()) { + repairedVeinCoordinates = normalizeVeinCoordinates(discoveredVeins) + | normalizeVeinCoordinates(depletedVeins); + } else { + VP.LOG.warn("Ore vein pattern is not confirmed, leaving team prospection coordinates untouched."); + } expanded = true; } From bf8189b42cae10f7213bd64669d78ea181c23cf1 Mon Sep 17 00:00:00 2001 From: Algent Date: Tue, 8 Sep 2026 16:07:28 +0200 Subject: [PATCH 2/4] fix: prefer NBT cache over legacy data Stale binary directories must not replace an existing NBT cache. Apply the unverified-pattern save block to v1 and v2 migrations too. --- .../database/DimensionCache.java | 21 ++++++++++++------- .../database/WorldCache.java | 8 +++---- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/sinthoras/visualprospecting/database/DimensionCache.java b/src/main/java/com/sinthoras/visualprospecting/database/DimensionCache.java index 92cc88a..7244001 100644 --- a/src/main/java/com/sinthoras/visualprospecting/database/DimensionCache.java +++ b/src/main/java/com/sinthoras/visualprospecting/database/DimensionCache.java @@ -90,12 +90,14 @@ public void loadFromNbt(NBTTagCompound compound) { return; } + NBTTagCompound ores = compound.getCompoundTag("ores"); if (version == CURRENT_FORMAT_VERSION) { - loadOres(compound.getCompoundTag("ores")); + loadOres(ores); loadFluids(compound.getCompoundTag("fluids")); } else { // version key absent => v2 or older - LegacyDimensionCacheLoader.loadV2Ores(this, compound.getCompoundTag("ores")); + if (!ores.hasNoTags()) canRepairVeinCoordinates(); + LegacyDimensionCacheLoader.loadV2Ores(this, ores); LegacyDimensionCacheLoader.loadV2Fluids(this, compound.getCompoundTag("fluids")); } } @@ -128,11 +130,7 @@ private void loadOres(NBTTagCompound ores) { int size = chunkXArray.length; oreChunks.ensureCapacity(oreChunks.size() + size); - final boolean patternVerified = GTWorldgenerator.isOregenPatternVerified(); - if (!patternVerified) { - preventSaving = true; - VP.LOG.warn("Dimension {}: ore vein pattern is not confirmed, data will not be modified.", dimensionId); - } + final boolean patternVerified = canRepairVeinCoordinates(); int unknownVeinTypes = 0; int repairedCoordinates = 0; @@ -197,6 +195,15 @@ private void loadOres(NBTTagCompound ores) { } } + private boolean canRepairVeinCoordinates() { + boolean patternVerified = GTWorldgenerator.isOregenPatternVerified(); + if (!patternVerified) { + preventSaving = true; + VP.LOG.warn("Dimension {}: ore vein pattern is not confirmed, data will not be modified.", dimensionId); + } + return patternVerified; + } + private void loadFluids(NBTTagCompound fluids) { if (!fluids.hasKey("palette")) return; diff --git a/src/main/java/com/sinthoras/visualprospecting/database/WorldCache.java b/src/main/java/com/sinthoras/visualprospecting/database/WorldCache.java index c193420..a134371 100644 --- a/src/main/java/com/sinthoras/visualprospecting/database/WorldCache.java +++ b/src/main/java/com/sinthoras/visualprospecting/database/WorldCache.java @@ -29,18 +29,18 @@ public boolean loadVeinCache(String worldId) { isLoaded = true; worldCache = new File(getStorageDirectory(), worldId); - if (loadLegacyVeinCache(worldCache)) return true; - final File[] dimensionFiles = worldCache.listFiles(); - if (dimensionFiles == null || dimensionFiles.length == 0) return false; + if (dimensionFiles == null) return loadLegacyVeinCache(worldCache); boolean loadedAny = false; + boolean hasNbtCache = false; boolean requiresOreRescan = false; for (File dimensionFile : dimensionFiles) { final String fileName = dimensionFile.getName(); if (!dimensionFile.isFile() || !fileName.endsWith(".dat")) { continue; } + hasNbtCache = true; final NBTTagCompound dimCompound = Utils.readNBT(dimensionFile); if (dimCompound == null) continue; @@ -52,7 +52,7 @@ public boolean loadVeinCache(String worldId) { loadedAny = true; } - return loadedAny && !requiresOreRescan; + return hasNbtCache ? loadedAny && !requiresOreRescan : loadLegacyVeinCache(worldCache); } private boolean loadLegacyVeinCache(File worldCacheDirectory) { From c553972342180fa1003465192b7677bfbe6d0b4f Mon Sep 17 00:00:00 2001 From: Algent Date: Fri, 11 Sep 2026 11:11:10 +0200 Subject: [PATCH 3/4] fix: skip ores with unverified pattern & explain unverified cache recovery --- .../database/DimensionCache.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/sinthoras/visualprospecting/database/DimensionCache.java b/src/main/java/com/sinthoras/visualprospecting/database/DimensionCache.java index 7244001..6a953fb 100644 --- a/src/main/java/com/sinthoras/visualprospecting/database/DimensionCache.java +++ b/src/main/java/com/sinthoras/visualprospecting/database/DimensionCache.java @@ -96,8 +96,9 @@ public void loadFromNbt(NBTTagCompound compound) { loadFluids(compound.getCompoundTag("fluids")); } else { // version key absent => v2 or older - if (!ores.hasNoTags()) canRepairVeinCoordinates(); - LegacyDimensionCacheLoader.loadV2Ores(this, ores); + if (ores.hasNoTags() || canRepairVeinCoordinates()) { + LegacyDimensionCacheLoader.loadV2Ores(this, ores); + } LegacyDimensionCacheLoader.loadV2Fluids(this, compound.getCompoundTag("fluids")); } } @@ -130,7 +131,7 @@ private void loadOres(NBTTagCompound ores) { int size = chunkXArray.length; oreChunks.ensureCapacity(oreChunks.size() + size); - final boolean patternVerified = canRepairVeinCoordinates(); + if (!canRepairVeinCoordinates()) return; int unknownVeinTypes = 0; int repairedCoordinates = 0; @@ -155,7 +156,7 @@ private void loadOres(NBTTagCompound ores) { veinType, depletedArray[i] == 1, source); - if (patternVerified && (position.chunkX != chunkXArray[i] || position.chunkZ != chunkZArray[i])) { + if (position.chunkX != chunkXArray[i] || position.chunkZ != chunkZArray[i]) { repairedCoordinates++; if (source == VeinSource.RESCAN) { discardedRescans++; @@ -199,7 +200,11 @@ private boolean canRepairVeinCoordinates() { boolean patternVerified = GTWorldgenerator.isOregenPatternVerified(); if (!patternVerified) { preventSaving = true; - VP.LOG.warn("Dimension {}: ore vein pattern is not confirmed, data will not be modified.", dimensionId); + VP.LOG.warn( + "Dimension {}: ore vein pattern is not confirmed. This cache is read-only for the session; " + + "changes will not be saved. After confirming the pattern with " + + "/gt oregenpattern set confirm, restart the world/server and reconnect clients.", + dimensionId); } return patternVerified; } From 11fe9cdcf3e9b6a8316eeaca84b04f914b2e93cd Mon Sep 17 00:00:00 2001 From: Algent Date: Sun, 13 Sep 2026 13:05:55 +0200 Subject: [PATCH 4/4] fix: defer unsafe v0 ore migration --- .../sinthoras/visualprospecting/database/WorldCache.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/com/sinthoras/visualprospecting/database/WorldCache.java b/src/main/java/com/sinthoras/visualprospecting/database/WorldCache.java index a134371..7000517 100644 --- a/src/main/java/com/sinthoras/visualprospecting/database/WorldCache.java +++ b/src/main/java/com/sinthoras/visualprospecting/database/WorldCache.java @@ -12,7 +12,9 @@ import com.sinthoras.visualprospecting.Tags; import com.sinthoras.visualprospecting.Utils; +import com.sinthoras.visualprospecting.VP; +import gregtech.common.GTWorldgenerator; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @@ -66,6 +68,13 @@ private boolean loadLegacyVeinCache(File worldCacheDirectory) { final Map oreVeinDimensionBuffers = Utils.getLegacyDimFiles(oreVeinCacheDirectory); final Map undergroundFluidDimensionBuffers = Utils .getLegacyDimFiles(undergroundFluidCacheDirectory); + if (!oreVeinDimensionBuffers.isEmpty() && !GTWorldgenerator.isOregenPatternVerified()) { + VP.LOG.warn( + "Ore vein pattern is not confirmed, deferring legacy cache migration. After confirming the pattern " + + "with /gt oregenpattern set confirm, restart the world/server."); + return true; + } + final Set dimensionsIds = new HashSet<>(); dimensionsIds.addAll(oreVeinDimensionBuffers.keySet()); dimensionsIds.addAll(undergroundFluidDimensionBuffers.keySet());