Added progress bar to world importer, world name suggestions for when import a world (not bobby), fixed the entire thing segfaulting if voxy core shuts down while importing

This commit is contained in:
mcrcortex
2024-03-14 20:08:32 +10:00
parent af9c45bb51
commit 1d05b222ae
3 changed files with 76 additions and 26 deletions

View File

@@ -16,7 +16,10 @@ import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.Camera;
import net.minecraft.client.render.Frustum;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.boss.BossBar;
import net.minecraft.entity.boss.ServerBossBar;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.text.Text;
import net.minecraft.world.World;
import net.minecraft.world.chunk.WorldChunk;
import org.joml.Matrix4f;
@@ -54,7 +57,7 @@ public class VoxelCore {
//private final Thread shutdownThread = new Thread(this::shutdown);
private WorldImporter importer;
public VoxelCore(ContextSelectionSystem.Selection worldSelection) {
this.world = worldSelection.createEngine();
var cfg = worldSelection.getConfig();
@@ -216,6 +219,10 @@ public class VoxelCore {
//}
//this.world.getMapper().forceResaveStates();
if (this.importer != null) {
System.out.println("Shutting down importer");
try {this.importer.shutdown();this.importer = null;} catch (Exception e) {System.err.println(e);}
}
System.out.println("Shutting down voxel core");
try {this.renderGen.shutdown();} catch (Exception e) {System.err.println(e);}
System.out.println("Render gen shut down");
@@ -227,12 +234,24 @@ public class VoxelCore {
System.out.println("Voxel core shut down");
}
public WorldImporter createWorldImporter(World mcWorld, File worldPath) {
public boolean createWorldImporter(World mcWorld, File worldPath) {
if (this.importer != null) {
return false;
}
var importer = new WorldImporter(this.world, mcWorld);
importer.importWorldAsyncStart(worldPath, 4, null, ()->{
System.err.println("DONE IMPORT");
});
return importer;
var bossBar = new ServerBossBar(Text.of("Voxy world importer"), BossBar.Color.GREEN, BossBar.Style.PROGRESS);
bossBar.addPlayer(MinecraftClient.getInstance().getServer().getPlayerManager().getPlayer(MinecraftClient.getInstance().player.getUuid()));
importer.importWorldAsyncStart(worldPath, 4, (a,b)->
MinecraftClient.getInstance().executeSync(()-> {
bossBar.setPercent(((float) a)/((float) b));
bossBar.setName(Text.of("Voxy import: "+ a+"/"+b + " region files"));
}),
()-> {
MinecraftClient.getInstance().executeSync(bossBar::clearPlayers);
this.importer = null;
});
this.importer = importer;
return true;
}
public WorldEngine getWorldEngine() {

View File

@@ -36,19 +36,19 @@ import java.util.function.Function;
import java.util.function.Predicate;
public class WorldImporter {
public record ImportUpdate(){}
public interface UpdateCallback {
void update(int finished, int outof);
}
private final WorldEngine world;
private final World mcWorld;
private final ReadableContainer<RegistryEntry<Biome>> defaultBiomeProvider;
private final Codec<ReadableContainer<RegistryEntry<Biome>>> biomeCodec;
private final AtomicInteger totalRegions = new AtomicInteger();
private final AtomicInteger regionsProcessed = new AtomicInteger();
private final AtomicInteger percentMarker = new AtomicInteger();
private volatile boolean isRunning;
public WorldImporter(WorldEngine worldEngine, World mcWorld) {
this.world = worldEngine;
this.mcWorld = mcWorld;
var biomeRegistry = mcWorld.getRegistryManager().get(RegistryKeys.BIOME);
var defaultBiome = biomeRegistry.entryOf(BiomeKeys.PLAINS);
@@ -97,9 +97,16 @@ public class WorldImporter {
this.biomeCodec = PalettedContainer.createReadableContainerCodec(biomeRegistry.getIndexedEntries(), biomeRegistry.createEntryCodec(), PalettedContainer.PaletteProvider.BIOME, biomeRegistry.entryOf(BiomeKeys.PLAINS));
}
public void shutdown() {
this.isRunning = false;
try {this.worker.join();} catch (InterruptedException e) {throw new RuntimeException(e);}
}
private Thread worker;
public void importWorldAsyncStart(File directory, int threads, Function<ImportUpdate, Boolean> updateCallback, Runnable onCompletion) {
public void importWorldAsyncStart(File directory, int threads, UpdateCallback updateCallback, Runnable onCompletion) {
this.worker = new Thread(() -> {
this.isRunning = true;
var workers = new ForkJoinPool(threads);
var files = directory.listFiles();
for (var file : files) {
@@ -117,16 +124,12 @@ public class WorldImporter {
this.totalRegions.addAndGet(1);
workers.submit(() -> {
try {
if (!isRunning) {
return;
}
this.importRegionFile(file.toPath(), rx, rz);
int regionsProcessedCount = this.regionsProcessed.addAndGet(1);
synchronized (this.world) {
int percentMark = this.percentMarker.get();
int percent = (regionsProcessedCount*100)/this.totalRegions.get();
if (percent > percentMark) {
System.out.println(regionsProcessedCount + "/" + this.totalRegions.get());
this.percentMarker.addAndGet(1);
}
}
updateCallback.update(regionsProcessedCount, this.totalRegions.get());
} catch (
Exception e) {
e.printStackTrace();

View File

@@ -3,13 +3,19 @@ package me.cortex.voxy.client.terrain;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import me.cortex.voxy.client.core.IGetVoxelCore;
import me.cortex.voxy.client.importers.WorldImporter;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.client.MinecraftClient;
import net.minecraft.command.CommandSource;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.concurrent.CompletableFuture;
public class WorldImportCommand {
@@ -17,33 +23,55 @@ public class WorldImportCommand {
return ClientCommandManager.literal("voxy").then(
ClientCommandManager.literal("import")
.then(ClientCommandManager.literal("world")
.then(ClientCommandManager.argument("world_name", StringArgumentType.string()).executes(WorldImportCommand::importWorld)))
.then(ClientCommandManager.argument("world_name", StringArgumentType.string())
.suggests(WorldImportCommand::importWorldSuggester)
.executes(WorldImportCommand::importWorld)))
.then(ClientCommandManager.literal("bobby")
.then(ClientCommandManager.argument("world_name", StringArgumentType.string()).executes(WorldImportCommand::importBobby)))
.then(ClientCommandManager.argument("world_name", StringArgumentType.string())
.executes(WorldImportCommand::importBobby)))
.then(ClientCommandManager.literal("raw")
.then(ClientCommandManager.argument("path", StringArgumentType.string()).executes(WorldImportCommand::importRaw))));
.then(ClientCommandManager.argument("path", StringArgumentType.string())
.executes(WorldImportCommand::importRaw))));
}
public static WorldImporter importerInstance;
private static int importRaw(CommandContext<FabricClientCommandSource> ctx) {
var instance = MinecraftClient.getInstance();
var file = new File(ctx.getArgument("path", String.class));
importerInstance = ((IGetVoxelCore)instance.worldRenderer).getVoxelCore().createWorldImporter(MinecraftClient.getInstance().player.clientWorld, file);
((IGetVoxelCore)instance.worldRenderer).getVoxelCore().createWorldImporter(MinecraftClient.getInstance().player.clientWorld, file);
return 0;
}
private static int importBobby(CommandContext<FabricClientCommandSource> ctx) {
var instance = MinecraftClient.getInstance();
var file = new File(".bobby").toPath().resolve(ctx.getArgument("world_name", String.class)).toFile();
importerInstance = ((IGetVoxelCore)instance.worldRenderer).getVoxelCore().createWorldImporter(MinecraftClient.getInstance().player.clientWorld, file);
((IGetVoxelCore)instance.worldRenderer).getVoxelCore().createWorldImporter(MinecraftClient.getInstance().player.clientWorld, file);
return 0;
}
private static CompletableFuture<Suggestions> importWorldSuggester(CommandContext<FabricClientCommandSource> ctx, SuggestionsBuilder sb) {
try {
var worlds = Files.list(MinecraftClient.getInstance().runDirectory.toPath().resolve("saves")).toList();
for (var world : worlds) {
if (!world.toFile().isDirectory()) {
continue;
}
var wn = world.getFileName().toString();
if (CommandSource.shouldSuggest(sb.getRemaining(), wn)) {
sb.suggest(wn);
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return sb.buildFuture();
}
private static int importWorld(CommandContext<FabricClientCommandSource> ctx) {
var instance = MinecraftClient.getInstance();
var file = new File("saves").toPath().resolve(ctx.getArgument("world_name", String.class)).resolve("region").toFile();
importerInstance = ((IGetVoxelCore)instance.worldRenderer).getVoxelCore().createWorldImporter(MinecraftClient.getInstance().player.clientWorld, file);
((IGetVoxelCore)instance.worldRenderer).getVoxelCore().createWorldImporter(MinecraftClient.getInstance().player.clientWorld, file);
return 0;
}