More work

This commit is contained in:
mcrcortex
2025-03-13 11:26:13 +10:00
parent c6fd3b19f9
commit 7b11670d55
12 changed files with 115 additions and 53 deletions

View File

@@ -3,6 +3,7 @@ package me.cortex.voxy.client;
import me.cortex.voxy.client.core.VoxelCore;
import me.cortex.voxy.client.saver.ContextSelectionSystem;
import me.cortex.voxy.client.terrain.WorldImportCommand;
import me.cortex.voxy.commonImpl.VoxyCommon;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientWorldEvents;
@@ -14,5 +15,6 @@ public class VoxyClient implements ClientModInitializer {
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> {
dispatcher.register(WorldImportCommand.register());
});
VoxyCommon.setInstanceFactory(VoxyClientInstance::new);
}
}

View File

@@ -0,0 +1,37 @@
package me.cortex.voxy.client;
import me.cortex.voxy.client.core.WorldImportWrapper;
import me.cortex.voxy.client.saver.ContextSelectionSystem;
import me.cortex.voxy.common.world.WorldEngine;
import me.cortex.voxy.commonImpl.IVoxyWorldGetter;
import me.cortex.voxy.commonImpl.IVoxyWorldSetter;
import me.cortex.voxy.commonImpl.VoxyInstance;
import net.minecraft.client.world.ClientWorld;
public class VoxyClientInstance extends VoxyInstance {
private static final ContextSelectionSystem SELECTOR = new ContextSelectionSystem();
public WorldImportWrapper importWrapper;
public VoxyClientInstance() {
super(12);
}
@Override
public void stopWorld(WorldEngine world) {
if (this.importWrapper != null) {
this.importWrapper.stopImporter();
this.importWrapper = null;
}
super.stopWorld(world);
}
public WorldEngine getOrMakeRenderWorld(ClientWorld world) {
var vworld = ((IVoxyWorldGetter)world).getWorldEngine();
if (vworld == null) {
vworld = this.createWorld(SELECTOR.getBestSelectionOrCreate(world).createSectionStorageBackend());
((IVoxyWorldSetter)world).setWorldEngine(vworld);
this.importWrapper = new WorldImportWrapper(this.threadPool, vworld);
}
return vworld;
}
}

View File

@@ -1,11 +0,0 @@
package me.cortex.voxy.client.mixin.joml;
import org.joml.FrustumIntersection;
import org.joml.Vector4f;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(value = FrustumIntersection.class, remap = false)
public interface AccessFrustumIntersection {
@Accessor Vector4f[] getPlanes();
}

View File

@@ -0,0 +1,23 @@
package me.cortex.voxy.client.mixin.minecraft;
import me.cortex.voxy.client.LoadException;
import me.cortex.voxy.client.config.VoxyConfig;
import me.cortex.voxy.commonImpl.VoxyCommon;
import net.minecraft.client.network.ClientCommonNetworkHandler;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ClientPlayNetworkHandler.class)
public class MixinClientPlayNetworkHandler {
@Inject(method = "onGameJoin", at = @At(value = "NEW", target = "(Lnet/minecraft/client/network/ClientPlayNetworkHandler;Lnet/minecraft/client/world/ClientWorld$Properties;Lnet/minecraft/registry/RegistryKey;Lnet/minecraft/registry/entry/RegistryEntry;IILnet/minecraft/client/render/WorldRenderer;ZJI)Lnet/minecraft/client/world/ClientWorld;", shift = At.Shift.BEFORE))
private void voxy$init(GameJoinS2CPacket packet, CallbackInfo ci) {
if (VoxyConfig.CONFIG.enabled) {
VoxyCommon.createInstance();
}
}
}

View File

@@ -23,10 +23,11 @@ public class MixinMinecraftClient {
VoxyCommon.shutdownInstance();
}
/*
@Inject(method = "joinWorld", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;setWorld(Lnet/minecraft/client/world/ClientWorld;)V", shift = At.Shift.BEFORE))
private void voxy$injectInitialization(ClientWorld world, DownloadingTerrainScreen.WorldEntryReason worldEntryReason, CallbackInfo ci) {
if (VoxyConfig.CONFIG.enabled) {
VoxyCommon.createInstance();
}
}
}*/
}

View File

@@ -1,11 +1,12 @@
package me.cortex.voxy.client.mixin.minecraft;
import me.cortex.voxy.client.VoxyClient;
import me.cortex.voxy.client.VoxyClientInstance;
import me.cortex.voxy.client.config.VoxyConfig;
import me.cortex.voxy.client.core.IGetVoxyRenderSystem;
import me.cortex.voxy.client.core.rendering.VoxyRenderSystem;
import me.cortex.voxy.common.Logger;
import me.cortex.voxy.common.world.WorldEngine;
import me.cortex.voxy.commonImpl.IVoxyWorldGetter;
import me.cortex.voxy.commonImpl.VoxyCommon;
import me.cortex.voxy.commonImpl.VoxyInstance;
import net.minecraft.client.render.*;
@@ -46,11 +47,25 @@ public abstract class MixinWorldRenderer implements IGetVoxyRenderSystem {
}
}
@Inject(method = "setWorld", at = @At("TAIL"))
@Unique private ClientWorld refCopy;
@Inject(method = "setWorld", at = @At("HEAD"))
private void initVoxelCore(ClientWorld world, CallbackInfo ci) {
this.refCopy = this.world;
}
@Inject(method = "setWorld", at = @At("TAIL"))
private void voxy$setWorld(ClientWorld world, CallbackInfo ci) {
if (world == null) {
this.shutdownRenderer();
}
//Release the client world
if (this.refCopy != null) {
var engine = ((IVoxyWorldGetter)this.refCopy).getWorldEngine();
if (engine != null) {
VoxyCommon.getInstance().stopWorld(engine);
}
}
}
@Inject(method = "close", at = @At("HEAD"))
@@ -73,12 +88,12 @@ public abstract class MixinWorldRenderer implements IGetVoxyRenderSystem {
Logger.info("Not creating renderer due to disabled");
return;
}
var instance = VoxyCommon.getInstance();
var instance = (VoxyClientInstance)VoxyCommon.getInstance();
if (instance == null) {
Logger.error("Not creating renderer due to null instance");
return;
}
WorldEngine world = instance.getOrMakeWorld(this.world);
WorldEngine world = instance.getOrMakeRenderWorld(this.world);
if (world == null) {
Logger.error("Null world selected");
return;

View File

@@ -5,6 +5,7 @@ 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.VoxyClientInstance;
import me.cortex.voxy.commonImpl.VoxyCommon;
import me.cortex.voxy.commonImpl.VoxyInstance;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
@@ -47,7 +48,7 @@ public class WorldImportCommand {
}
private static boolean fileBasedImporter(File directory) {
var instance = VoxyCommon.getInstance();
var instance = (VoxyClientInstance)VoxyCommon.getInstance();
if (instance == null) {
return false;
}
@@ -133,7 +134,7 @@ public class WorldImportCommand {
innerDir = ctx.getArgument("innerPath", String.class);
} catch (Exception e) {}
var instance = VoxyCommon.getInstance();
var instance = (VoxyClientInstance)VoxyCommon.getInstance();
if (instance == null) {
return 1;
}
@@ -143,7 +144,7 @@ public class WorldImportCommand {
}
private static int cancelImport(CommandContext<FabricClientCommandSource> fabricClientCommandSourceCommandContext) {
var instance = VoxyCommon.getInstance();
var instance = (VoxyClientInstance)VoxyCommon.getInstance();
if (instance == null) {
return 1;
}

View File

@@ -164,4 +164,8 @@ public class ServiceSlice extends TrackedObject {
this.threadPool.steal(this);
return true;
}
public boolean isAlive() {
return this.alive;
}
}

View File

@@ -26,7 +26,7 @@ public class VoxyCommon implements ModInitializer {
}
//This is hardcoded like this because people do not understand what they are doing
private static final boolean GlobalVerificationDisableOverride = false;//System.getProperty("voxy.verificationDisableOverride", "false").equals("true");
private static final boolean GlobalVerificationDisableOverride = true;//System.getProperty("voxy.verificationDisableOverride", "false").equals("true");
public static boolean isVerificationFlagOn(String name) {
return (!GlobalVerificationDisableOverride) && System.getProperty("voxy."+name, "true").equals("true");
}
@@ -41,7 +41,14 @@ public class VoxyCommon implements ModInitializer {
public interface IInstanceFactory {VoxyInstance create();}
private static VoxyInstance INSTANCE;
private static IInstanceFactory FACTORY;
private static IInstanceFactory FACTORY = null;
public static void setInstanceFactory(IInstanceFactory factory) {
if (FACTORY != null) {
throw new IllegalStateException("Cannot set instance factory more than once");
}
FACTORY = factory;
}
public static VoxyInstance getInstance() {
return INSTANCE;

View File

@@ -23,6 +23,7 @@ public class VoxyInstance {
protected final Set<WorldEngine> activeWorlds = new HashSet<>();
public VoxyInstance(int threadCount) {
Logger.info("Initializing voxy instance");
this.threadPool = new ServiceThreadPool(threadCount);
this.savingService = new SectionSavingService(this.threadPool);
this.ingestService = new VoxelIngestService(this.threadPool);
@@ -36,9 +37,22 @@ public class VoxyInstance {
public void shutdown() {
Logger.info("Shutdown voxy instance");
try {this.ingestService.shutdown();} catch (Exception e) {Logger.error(e);}
try {this.savingService.shutdown();} catch (Exception e) {Logger.error(e);}
if (!this.activeWorlds.isEmpty()) {
Logger.error("Not all worlds shutdown, force closing " + this.activeWorlds.size() + " worlds");
for (var world : new HashSet<>(this.activeWorlds)) {//Create a clone
this.stopWorld(world);
}
}
try {this.threadPool.shutdown();} catch (Exception e) {Logger.error(e);}
if (!this.activeWorlds.isEmpty()) {
throw new IllegalStateException("Not all worlds shutdown");
}
}
public ServiceThreadPool getThreadPool() {
@@ -94,29 +108,9 @@ public class VoxyInstance {
throw new IllegalStateException("World cannot be in world set and not alive");
}
if (this.importWrapper != null) {
this.importWrapper.stopImporter();
this.importWrapper = null;
}
this.flush();
world.free();
this.activeWorlds.remove(world);
}
private static final ContextSelectionSystem SELECTOR = new ContextSelectionSystem();
public WorldImportWrapper importWrapper;
public WorldEngine getOrMakeWorld(ClientWorld world) {
var vworld = ((IVoxyWorldGetter)world).getWorldEngine();
if (vworld == null) {
vworld = this.createWorld(SELECTOR.getBestSelectionOrCreate(world).createSectionStorageBackend());
((IVoxyWorldSetter)world).setWorldEngine(vworld);
this.importWrapper = new WorldImportWrapper(this.threadPool, vworld);
}
return vworld;
}
}

View File

@@ -16,17 +16,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public class MixinWorld implements IVoxyWorldGetter, IVoxyWorldSetter {
@Unique private WorldEngine voxyWorld;
@Inject(method = "close", at = @At("HEAD"))
private void closeVoxyWorld(CallbackInfo ci) {
if (this.voxyWorld != null) {
//TODO: FIXME: DONT DO THIS, this is a hack to ensure everything is saved
var instance = VoxyCommon.getInstance();
try {instance.stopWorld(this.voxyWorld); this.voxyWorld = null;} catch (Exception e) {
Logger.error("Failed to shutdown voxy world engine.", e);
}
}
}
@Override
public WorldEngine getWorldEngine() {
return this.voxyWorld;

View File

@@ -3,8 +3,8 @@
"package": "me.cortex.voxy.client.mixin",
"compatibilityLevel": "JAVA_17",
"client": [
"joml.AccessFrustumIntersection",
"minecraft.MixinClientCommonNetworkHandler",
"minecraft.MixinClientPlayNetworkHandler",
"minecraft.MixinDebugHud",
"minecraft.MixinMinecraftClient",
"minecraft.MixinThreadExecutor",