Saving chunks still is a problem though

This commit is contained in:
RePixelatedMC 2024-09-29 19:00:52 +02:00
parent 5d5c5ba9f4
commit 7c6df58c15
4 changed files with 121 additions and 89 deletions

View File

@ -171,6 +171,11 @@ public class CommandDeveloper implements DecreeExecutor {
Iris.info("Done fixing biomes!"); Iris.info("Done fixing biomes!");
} }
@Decree(description = "check", aliases = {"ck"} )
public void check() {
sender().sendMessage("Data Pack Biome: " + INMS.get().getTrueBiomeBaseKey(player().getLocation()) + " (ID: " + INMS.get().getTrueBiomeBaseId(INMS.get().getTrueBiomeBase(player().getLocation())) + ")");
}
@Decree(description = "Upgrade to another Minecraft version") @Decree(description = "Upgrade to another Minecraft version")
public void upgrade( public void upgrade(
@Param(description = "The version to upgrade to", defaultValue = "latest") DataVersion version) { @Param(description = "The version to upgrade to", defaultValue = "latest") DataVersion version) {

View File

@ -24,6 +24,7 @@ import com.volmit.iris.core.nms.datapack.DataVersion;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.math.Vector3d; import com.volmit.iris.util.math.Vector3d;
import com.volmit.iris.util.nbt.mca.palette.MCABiomeContainer; import com.volmit.iris.util.nbt.mca.palette.MCABiomeContainer;
@ -98,6 +99,10 @@ public interface INMSBinding {
int countCustomBiomes(); int countCustomBiomes();
default void setBiomes(int cx, int cz, World world, Hunk<Object> biomes) {
Iris.error("Unsupported version!");
}
void forceBiomeInto(int x, int y, int z, Object somethingVeryDirty, ChunkGenerator.BiomeGrid chunk); void forceBiomeInto(int x, int y, int z, Object somethingVeryDirty, ChunkGenerator.BiomeGrid chunk);
default boolean supportsDataPacks() { default boolean supportsDataPacks() {

View File

@ -4,62 +4,50 @@ import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisBiomeCustom; import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.math.RollingSequence; import com.volmit.iris.util.math.RollingSequence;
import com.volmit.iris.util.misc.E;
import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.Chunk;
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.util.concurrent.*;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
public class IrisBiomeFixer { public class IrisBiomeFixer {
/**
* Do a pregen style approach iterate across a certain region and set everything to the correct biome again.
* Have 2 modes ( all, surface-only ) surface-only gets the underground caves from a different world
*/
private World world; private World world;
private Engine engine; private Engine engine;
private int radius;
private ChronoLatch latch; private ChronoLatch latch;
private RollingSequence chunksPerSecond; private RollingSequence chunksPerSecond;
private RollingSequence chunksPerMinute;
private AtomicLong startTime; private AtomicLong startTime;
private AtomicLong lastLogTime; private AtomicLong lastLogTime;
private AtomicInteger generated = new AtomicInteger(0); private AtomicInteger generated = new AtomicInteger(0);
private AtomicInteger lastGenerated = new AtomicInteger(0); private AtomicInteger generatedLast = new AtomicInteger(0);
private AtomicInteger generatedLastMinute = new AtomicInteger(0);
private AtomicInteger totalChunks = new AtomicInteger(0); private AtomicInteger totalChunks = new AtomicInteger(0);
private ChronoLatch progressLatch = new ChronoLatch(5000); // Update every 5 seconds private ChronoLatch progressLatch = new ChronoLatch(5000); // Update every 5 seconds
private ChronoLatch minuteLatch = new ChronoLatch(60000, false);
// File to store unregistered biome IDs
private File unregisteredBiomesFile; private File unregisteredBiomesFile;
// Reference to your plugin instance (Assuming you have one)
private Plugin plugin; private Plugin plugin;
private ScheduledExecutorService progressUpdater;
public IrisBiomeFixer(World world) { public IrisBiomeFixer(World world) {
if (!IrisToolbelt.isIrisWorld(world)) { if (!IrisToolbelt.isIrisWorld(world)) {
Iris.info("This is not an Iris world!"); Iris.info("This is not an Iris world!");
return; return;
} }
this.chunksPerSecond = new RollingSequence(32); this.chunksPerSecond = new RollingSequence(10);
this.chunksPerMinute = new RollingSequence(10);
this.startTime = new AtomicLong(M.ms()); this.startTime = new AtomicLong(M.ms());
this.lastLogTime = new AtomicLong(M.ms()); this.lastLogTime = new AtomicLong(M.ms());
this.world = world; this.world = world;
@ -69,6 +57,9 @@ public class IrisBiomeFixer {
// Initialize the file for storing unregistered biome IDs // Initialize the file for storing unregistered biome IDs
this.unregisteredBiomesFile = new File(world.getWorldFolder(), "unregistered_biomes.txt"); this.unregisteredBiomesFile = new File(world.getWorldFolder(), "unregistered_biomes.txt");
// Initialize the progress updater executor
this.progressUpdater = Executors.newSingleThreadScheduledExecutor();
} }
public void fixBiomes() { public void fixBiomes() {
@ -94,6 +85,9 @@ public class IrisBiomeFixer {
totalChunks.addAndGet(1024); totalChunks.addAndGet(1024);
} }
// Start the progress updater
progressUpdater.scheduleAtFixedRate(this::updateProgress, 1, 1, TimeUnit.SECONDS);
for (File regionFile : regionFiles) { for (File regionFile : regionFiles) {
String filename = regionFile.getName(); // e.g., "r.0.0.mca" String filename = regionFile.getName(); // e.g., "r.0.0.mca"
String[] parts = filename.split("\\."); String[] parts = filename.split("\\.");
@ -114,81 +108,105 @@ public class IrisBiomeFixer {
continue; continue;
} }
J.s(() -> {
world.loadChunk(chunkX, chunkZ);
});
Chunk chunk = world.getChunkAt(chunkX, chunkZ);
int minY = world.getMinHeight(); int minY = world.getMinHeight();
int maxY = world.getMaxHeight(); int maxY = world.getMaxHeight();
int height = maxY - minY; // Correct height calculation
for (int x = 0; x < 16; x++) { Hunk<Object> biomes = Hunk.newHunk(16, height, 16);
for (int y = minY; y < maxY; y++) {
for (int z = 0; z < 16; z++) {
Block block = chunk.getBlock(x, y, z);
IrisBiome irisBiome = engine.getBiome(x, y, z);
IrisBiomeCustom custom;
try {
custom = irisBiome.getCustomBiome(rng, x, y, z);
} catch (Exception e) {
custom = null;
}
if (custom != null) { for (int x = 0; x < 16; x += 4) {
try { for (int z = 0; z < 16; z += 4) {
int id = INMS.get().getBiomeBaseIdForKey(engine.getDimension().getLoadKey() + ":" + custom.getId()); for (int y = minY; y < maxY; y += 4) {
Biome biome = (Biome) INMS.get().getBiomeBaseFromId(id); // Calculate the biome once per 4x4x4 block
world.setBiome(block.getX(), block.getY(), block.getZ(), biome); int realX = chunkX * 16 + x;
} catch (Exception e) { int realZ = chunkZ * 16 + z;
Iris.warn("Fallback! IrisBiome ID: " + custom.getId() + " is invalid!"); int realY = y;
world.setBiome(block.getX(), block.getY(), block.getZ(), irisBiome.getDerivative());
} IrisBiome biome = engine.getBiome(realX, realY, realZ);
Object biomeHolder = null;
if (biome.isCustom()) {
biomeHolder = INMS.get().getCustomBiomeBaseHolderFor(
engine.getDimension().getLoadKey() + ":" + biome.getCustomBiome(rng, realX, realY, realZ).getId());
} else { } else {
// Use derivative biome if custom biome is null // Handle non-custom biome if necessary
world.setBiome(block.getX(), block.getY(), block.getZ(), irisBiome.getDerivative()); // biomeHolder = INMS.get().getCustomBiomeBaseHolderFor(biome.getDerivative().getKey().getKey());
}
// Now fill the 4x4x4 block in the hunk
for (int subX = x; subX < x + 4 && subX < 16; subX++) {
for (int subZ = z; subZ < z + 4 && subZ < 16; subZ++) {
for (int subY = y; subY < y + 4 && subY < maxY; subY++) {
int relativeY = subY - minY; // Offset Y-coordinate
biomes.set(subX, relativeY, subZ, biomeHolder);
} }
} }
} }
} }
}
}
INMS.get().setBiomes(cx, cz, engine.getWorld().realWorld(), biomes);
generated.incrementAndGet(); generated.incrementAndGet();
// Progress Logging
if (progressLatch.flip()) {
long currentTime = M.ms();
long elapsedTime = currentTime - lastLogTime.get();
int currentGenerated = generated.get();
int last = lastGenerated.getAndSet(currentGenerated);
int chunksProcessed = currentGenerated - last;
double seconds = elapsedTime / 1000.0;
int cps = seconds > 0 ? (int) (chunksProcessed / seconds) : 0;
chunksPerSecond.put(cps);
long eta = computeETA(cps);
double percentage = ((double) currentGenerated / totalChunks.get()) * 100;
Iris.info(String.format("Biome Fixer Progress: %d/%d chunks (%.2f%%) - %d chunks/s ETA: %s",
currentGenerated, totalChunks.get(), percentage, cps, formatETA(eta)));
lastLogTime.set(currentTime);
}
world.unloadChunk(chunkX, chunkZ);
} }
} }
} }
// Shut down the progress updater
progressUpdater.shutdown();
try {
// Wait for the progress updater to finish
if (!progressUpdater.awaitTermination(1, TimeUnit.MINUTES)) {
Iris.warn("Progress updater did not terminate in time.");
progressUpdater.shutdownNow();
}
} catch (InterruptedException e) {
Iris.warn("Progress updater interrupted during shutdown.");
progressUpdater.shutdownNow();
Thread.currentThread().interrupt();
}
// Final Progress Update // Final Progress Update
Iris.info(String.format("Biome Fixing Completed: %d/%d chunks processed.", generated.get(), totalChunks.get())); Iris.info("Biome Fixing Completed: " + generated.get() + "/" + totalChunks.get() + " chunks processed.");
} }
private long computeETA(int cps) { private void updateProgress() {
if (chunksPerSecond.size() < chunksPerSecond.getMax()) { long currentTime = M.ms();
if (cps == 0) return Long.MAX_VALUE; int currentGenerated = generated.get();
int last = generatedLast.getAndSet(currentGenerated);
int chunksProcessed = currentGenerated - last;
chunksPerSecond.put(chunksProcessed);
// Update chunks per minute
if (minuteLatch.flip()) {
int lastMinuteGenerated = generatedLastMinute.getAndSet(currentGenerated);
int minuteProcessed = currentGenerated - lastMinuteGenerated;
chunksPerMinute.put(minuteProcessed);
}
long eta = computeETA();
double percentage = ((double) currentGenerated / totalChunks.get()) * 100;
if (progressLatch.flip()) {
Iris.info("Biome Fixer Progress: " + currentGenerated + "/" + totalChunks.get() +
" chunks (" + percentage + "%%) - " +
chunksPerSecond.getAverage() + " chunks/s ETA: " + formatETA(eta));
}
}
private long computeETA() {
if (generated.get() > totalChunks.get() / 8) {
// Use smooth function
double elapsedTime = (double) (M.ms() - startTime.get());
double rate = generated.get() / elapsedTime; // chunks per millisecond
int remaining = totalChunks.get() - generated.get(); int remaining = totalChunks.get() - generated.get();
return (long) ((double) remaining / cps) * 1000; return (long) (remaining / rate);
} else { } else {
// Use quick function
double averageCps = chunksPerSecond.getAverage(); double averageCps = chunksPerSecond.getAverage();
if (averageCps == 0) return Long.MAX_VALUE; if (averageCps == 0) return Long.MAX_VALUE;
int remaining = totalChunks.get() - generated.get(); int remaining = totalChunks.get() - generated.get();
@ -205,6 +223,6 @@ public class IrisBiomeFixer {
seconds %= 60; seconds %= 60;
long hours = minutes / 60; long hours = minutes / 60;
minutes %= 60; minutes %= 60;
return String.format("%02dh:%02dm:%02ds", hours, minutes, seconds); return hours + "h:" + minutes + "m:" + seconds + "s";
} }
} }

View File

@ -1,10 +1,6 @@
package com.volmit.iris.core.nms.v1_20_R3; package com.volmit.iris.core.nms.v1_20_R3;
import java.awt.Color; import java.awt.Color;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
@ -33,10 +29,8 @@ import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockState; import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockState;
import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockStates; import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockStates;
import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftDolphin;
import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_20_R3.util.CraftNamespacedKey; import org.bukkit.craftbukkit.v1_20_R3.util.CraftNamespacedKey;
import org.bukkit.entity.Dolphin;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
@ -56,7 +50,6 @@ import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.math.Vector3d; import com.volmit.iris.util.math.Vector3d;
import com.volmit.iris.util.matter.MatterBiomeInject; import com.volmit.iris.util.matter.MatterBiomeInject;
import com.volmit.iris.util.nbt.io.NBTUtil;
import com.volmit.iris.util.nbt.mca.NBTWorld; import com.volmit.iris.util.nbt.mca.NBTWorld;
import com.volmit.iris.util.nbt.mca.palette.*; import com.volmit.iris.util.nbt.mca.palette.*;
import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.nbt.tag.CompoundTag;
@ -71,14 +64,12 @@ import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import sun.misc.Unsafe;
public class NMSBinding implements INMSBinding { public class NMSBinding implements INMSBinding {
private final KMap<Biome, Object> baseBiomeCache = new KMap<>(); private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
@ -286,7 +277,11 @@ public class NMSBinding implements INMSBinding {
@Override @Override
public int getTrueBiomeBaseId(Object biomeBase) { public int getTrueBiomeBaseId(Object biomeBase) {
return getCustomBiomeRegistry().getId(((Holder<net.minecraft.world.level.biome.Biome>) biomeBase).value()); if (biomeBase instanceof net.minecraft.world.level.biome.Biome) {
net.minecraft.world.level.biome.Biome biome = (net.minecraft.world.level.biome.Biome) biomeBase;
return getCustomBiomeRegistry().getId(biome);
}
throw new IllegalArgumentException("Invalid biomeBase type: " + biomeBase.getClass().getName());
} }
@Override @Override
@ -315,7 +310,15 @@ public class NMSBinding implements INMSBinding {
@Override @Override
public String getKeyForBiomeBase(Object biomeBase) { public String getKeyForBiomeBase(Object biomeBase) {
return getCustomBiomeRegistry().getKey((net.minecraft.world.level.biome.Biome) biomeBase).getPath(); // something, not something:something if (biomeBase instanceof net.minecraft.core.Holder<?>) {
net.minecraft.core.Holder<?> holder = (net.minecraft.core.Holder<?>) biomeBase;
if (holder.value() instanceof net.minecraft.world.level.biome.Biome) {
net.minecraft.world.level.biome.Biome biome = (net.minecraft.world.level.biome.Biome) holder.value();
return getCustomBiomeRegistry().getKey(biome).getPath();
}
}
throw new IllegalArgumentException("Invalid biomeBase type: " + biomeBase.getClass().getName());
} }
@Override @Override
@ -438,6 +441,7 @@ public class NMSBinding implements INMSBinding {
return true; return true;
} }
@Override
public void setBiomes(int cx, int cz, World world, Hunk<Object> biomes) { public void setBiomes(int cx, int cz, World world, Hunk<Object> biomes) {
LevelChunk c = ((CraftWorld) world).getHandle().getChunk(cx, cz); LevelChunk c = ((CraftWorld) world).getHandle().getChunk(cx, cz);
biomes.iterateSync((x, y, z, b) -> c.setBiome(x, y, z, (Holder<net.minecraft.world.level.biome.Biome>) b)); biomes.iterateSync((x, y, z, b) -> c.setBiome(x, y, z, (Holder<net.minecraft.world.level.biome.Biome>) b));