From 5738a5b7cd047641a7bbaac422501029cc32319a Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 3 Apr 2021 12:05:16 -0500 Subject: [PATCH] Close #8 (allow client use on servers) --- .../com/backsun/lod/builders/LodBuilder.java | 9 +- .../lod/builders/LodChunkGenWorker.java | 2 +- .../lod/handlers/LodDimensionFileHandler.java | 14 +-- .../com/backsun/lod/objects/LodDimension.java | 47 +++++++++- .../com/backsun/lod/objects/LodWorld.java | 17 +++- .../com/backsun/lod/proxy/ClientProxy.java | 32 ++++--- .../java/com/backsun/lod/util/LodUtils.java | 93 +++++++++++++++++-- 7 files changed, 165 insertions(+), 49 deletions(-) diff --git a/src/main/java/com/backsun/lod/builders/LodBuilder.java b/src/main/java/com/backsun/lod/builders/LodBuilder.java index d30fb8c14..2011e6967 100644 --- a/src/main/java/com/backsun/lod/builders/LodBuilder.java +++ b/src/main/java/com/backsun/lod/builders/LodBuilder.java @@ -15,6 +15,7 @@ import net.minecraft.block.Blocks; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.color.BlockColors; import net.minecraft.world.DimensionType; +import net.minecraft.world.IWorld; import net.minecraft.world.chunk.ChunkSection; import net.minecraft.world.chunk.IChunk; import net.minecraft.world.gen.Heightmap; @@ -55,13 +56,13 @@ public class LodBuilder - public void generateLodChunkAsync(IChunk chunk, LodWorld lodWorld, DimensionType dim) + public void generateLodChunkAsync(IChunk chunk, LodWorld lodWorld, IWorld world) { if (lodWorld == null || !lodWorld.getIsWorldLoaded()) return; // is this chunk from the same world as the lodWorld? - if (!lodWorld.getWorldName().equals(LodUtils.getCurrentWorldID())) + if (!lodWorld.getWorldName().equals(LodUtils.getWorldID(world))) // we are not in the same world anymore // don't add this LOD return; @@ -77,13 +78,15 @@ public class LodBuilder { try { + DimensionType dim = world.getDimensionType(); + LodChunk lod = generateLodFromChunk(chunk); LodDimension lodDim; if (lodWorld.getLodDimension(dim) == null) { - lodDim = new LodDimension(dim, regionWidth); + lodDim = new LodDimension(dim, lodWorld, regionWidth); lodWorld.addLodDimension(lodDim); } else diff --git a/src/main/java/com/backsun/lod/builders/LodChunkGenWorker.java b/src/main/java/com/backsun/lod/builders/LodChunkGenWorker.java index 3ea87b9f7..48f89ffed 100644 --- a/src/main/java/com/backsun/lod/builders/LodChunkGenWorker.java +++ b/src/main/java/com/backsun/lod/builders/LodChunkGenWorker.java @@ -62,7 +62,7 @@ public class LodChunkGenWorker implements IWorker //System.out.println(endTime - startTime + "\t" + lodBuilder.hasBlockData(chunk)); - lodBuilder.generateLodChunkAsync(chunk, ClientProxy.getLodWorld(), serverWorld.getDimensionType()); + lodBuilder.generateLodChunkAsync(chunk, ClientProxy.getLodWorld(), serverWorld); // this is called so that the new LOD chunk is drawn // after it is generated lodRenderer.regenerateLODsNextFrame(); diff --git a/src/main/java/com/backsun/lod/handlers/LodDimensionFileHandler.java b/src/main/java/com/backsun/lod/handlers/LodDimensionFileHandler.java index ed8132a5d..d1e8a831d 100644 --- a/src/main/java/com/backsun/lod/handlers/LodDimensionFileHandler.java +++ b/src/main/java/com/backsun/lod/handlers/LodDimensionFileHandler.java @@ -12,8 +12,6 @@ import com.backsun.lod.objects.LodChunk; import com.backsun.lod.objects.LodDimension; import com.backsun.lod.objects.LodRegion; -import net.minecraft.client.Minecraft; - /** * This object handles creating LodRegions * from files and saving LodRegion objects @@ -63,11 +61,6 @@ public class LodDimensionFileHandler */ public LodRegion loadRegionFromFile(int regionX, int regionZ) { - // we don't currently support reading or writing - // files when connected to a server - if (!Minecraft.getInstance().isIntegratedServerRunning()) - return null; - if (!readyToReadAndWrite()) return null; @@ -138,11 +131,6 @@ public class LodDimensionFileHandler */ public synchronized void saveDirtyRegionsToFileAsync() { - // we don't currently support reading or writing - // files when connected to a server - if (!Minecraft.getInstance().isIntegratedServerRunning()) - return; - if (!readyToReadAndWrite()) // we aren't ready to read and write yet return; @@ -231,7 +219,7 @@ public class LodDimensionFileHandler // ".\Super Flat\DIM-1\data" // or // ".\Super Flat\data" - return dimensionDataSaveFolder.getCanonicalPath() + "\\lod\\" + + return dimensionDataSaveFolder.getCanonicalPath() + "\\" + FILE_NAME_PREFIX + "." + regionX + "." + regionZ + FILE_EXTENSION; } catch(IOException e) diff --git a/src/main/java/com/backsun/lod/objects/LodDimension.java b/src/main/java/com/backsun/lod/objects/LodDimension.java index 4a5023401..fe88bbe4b 100644 --- a/src/main/java/com/backsun/lod/objects/LodDimension.java +++ b/src/main/java/com/backsun/lod/objects/LodDimension.java @@ -1,11 +1,16 @@ package com.backsun.lod.objects; +import java.io.File; +import java.io.IOException; + import com.backsun.lod.handlers.LodDimensionFileHandler; import com.backsun.lod.util.LodUtils; +import net.minecraft.client.Minecraft; import net.minecraft.util.math.ChunkPos; import net.minecraft.world.DimensionType; import net.minecraft.world.server.ServerChunkProvider; +import net.minecraft.world.server.ServerWorld; /** * This object holds all loaded LOD regions @@ -30,13 +35,42 @@ public class LodDimension private LodDimensionFileHandler fileHandler; - public LodDimension(DimensionType newDimension, int newMaxWidth) + public LodDimension(DimensionType newDimension, LodWorld lodWorld, int newMaxWidth) { dimension = newDimension; width = newMaxWidth; - ServerChunkProvider provider = LodUtils.getServerWorldFromDimension(newDimension).getChunkProvider(); - fileHandler = new LodDimensionFileHandler(provider.getSavedData().folder, this); + try + { + Minecraft mc = Minecraft.getInstance(); + + File saveDir; + if(mc.isIntegratedServerRunning()) + { + // local world + + ServerWorld serverWorld = LodUtils.getServerWorldFromDimension(newDimension); + // provider needs a separate variable to prevent + // the compiler from complaining + ServerChunkProvider provider = serverWorld.getChunkProvider(); + saveDir = new File(provider.getSavedData().folder.getCanonicalFile() + "\\lod"); + } + else + { + // connected to server + + saveDir = new File(mc.gameDir.getCanonicalFile() + + "\\lod server data\\" + LodUtils.getDimensionIDFromWorld(mc.world)); + } + + fileHandler = new LodDimensionFileHandler(saveDir, this); + } + catch(IOException e) + { + // the file handler wasn't able to be created + // we won't be able to read or write any files + } + regions = new LodRegion[width][width]; isRegionDirty = new boolean[width][width]; @@ -229,7 +263,7 @@ public class LodDimension region.addLod(lod); // don't save empty place holders to disk - if (!lod.isPlaceholder()) + if (!lod.isPlaceholder() && fileHandler != null) { // mark the region as dirty so it will be saved to disk int xIndex = (pos.x - centerX) + halfWidth; @@ -265,7 +299,10 @@ public class LodDimension */ public LodRegion getRegionFromFile(int regionX, int regionZ) { - return fileHandler.loadRegionFromFile(regionX, regionZ); + if (fileHandler != null) + return fileHandler.loadRegionFromFile(regionX, regionZ); + else + return null; } diff --git a/src/main/java/com/backsun/lod/objects/LodWorld.java b/src/main/java/com/backsun/lod/objects/LodWorld.java index e203dbc00..106165c54 100644 --- a/src/main/java/com/backsun/lod/objects/LodWorld.java +++ b/src/main/java/com/backsun/lod/objects/LodWorld.java @@ -19,9 +19,11 @@ public class LodWorld /** If true then the LOD world is setup and ready to use */ private boolean isWorldLoaded = false; + public static final String NO_WORLD_LOADED = "No world loaded"; + public LodWorld() { - worldName = "No world loaded"; + worldName = NO_WORLD_LOADED; } /** @@ -31,6 +33,17 @@ public class LodWorld */ public void selectWorld(String newWorldName) { + if(newWorldName.isEmpty()) + { + deselectWorld(); + return; + } + + if (worldName.equals(newWorldName)) + // don't recreate everything if we + // didn't actually change worlds + return; + worldName = newWorldName; lodDimensions = new Hashtable(); isWorldLoaded = true; @@ -43,7 +56,7 @@ public class LodWorld */ public void deselectWorld() { - worldName = "No world loaded"; + worldName = NO_WORLD_LOADED; lodDimensions = null; isWorldLoaded = false; } diff --git a/src/main/java/com/backsun/lod/proxy/ClientProxy.java b/src/main/java/com/backsun/lod/proxy/ClientProxy.java index 1f8fd0f9b..73dfd518e 100644 --- a/src/main/java/com/backsun/lod/proxy/ClientProxy.java +++ b/src/main/java/com/backsun/lod/proxy/ClientProxy.java @@ -14,9 +14,6 @@ import net.minecraftforge.event.world.ChunkEvent; import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; -//TODO Find a way to replace getIntegratedServer so this mod could be used on non-local worlds. -// Minecraft.getMinecraft().getIntegratedServer() - /** * This handles all events sent to the client, * and is the starting point for most of this program. @@ -51,9 +48,12 @@ public class ClientProxy */ public void renderLods(float partialTicks) { + if (mc == null || mc.player == null || !lodWorld.getIsWorldLoaded()) + return; + // update each regions' width to match the new render distance int newWidth = Math.max(4, (mc.gameSettings.renderDistanceChunks * LodChunk.WIDTH * 2) / LodRegion.SIZE); - if (lodWorld != null && lodBuilder.regionWidth != newWidth) + if (lodBuilder.regionWidth != newWidth) { lodWorld.resizeDimensionRegionWidth(newWidth); lodBuilder.regionWidth = newWidth; @@ -63,10 +63,6 @@ public class ClientProxy return; } - - if (mc == null || mc.player == null || !lodWorld.getIsWorldLoaded()) - return; - LodDimension lodDim = lodWorld.getLodDimension(mc.player.world.getDimensionType()); if (lodDim == null) return; @@ -99,27 +95,33 @@ public class ClientProxy @SubscribeEvent public void chunkLoadEvent(ChunkEvent.Load event) { - lodBuilder.generateLodChunkAsync(event.getChunk(), lodWorld, event.getWorld().getDimensionType()); + lodBuilder.generateLodChunkAsync(event.getChunk(), lodWorld, event.getWorld()); } @SubscribeEvent public void worldLoadEvent(WorldEvent.Load event) { - // update the LodWorld to use the new world the player - // is loaded - lodWorld.selectWorld(LodUtils.getCurrentWorldID()); + // the player just loaded a new world/dimension + lodWorld.selectWorld(LodUtils.getWorldID(event.getWorld())); + // make sure the correct LODs are being rendered + // (if this isn't done the previous world's LODs may be drawn) + renderer.regenerateLODsNextFrame(); } @SubscribeEvent public void worldUnloadEvent(WorldEvent.Unload event) { - lodWorld.deselectWorld(); + // the player just loaded a new world/dimension + + if(mc.getConnection().getWorld() == null) + // the player has disconnected from a server + lodWorld.deselectWorld(); } @SubscribeEvent - public void worldChangeEvent(BlockEvent event) + public void blockChangeEvent(BlockEvent event) { if (event.getClass() == BlockEvent.BreakEvent.class || event.getClass() == BlockEvent.EntityPlaceEvent.class || @@ -128,7 +130,7 @@ public class ClientProxy event.getClass() == BlockEvent.PortalSpawnEvent.class) { // recreate the LOD where the blocks were changed - lodBuilder.generateLodChunkAsync(event.getWorld().getChunk(event.getPos()), lodWorld, event.getWorld().getDimensionType()); + lodBuilder.generateLodChunkAsync(event.getWorld().getChunk(event.getPos()), lodWorld, event.getWorld()); } } diff --git a/src/main/java/com/backsun/lod/util/LodUtils.java b/src/main/java/com/backsun/lod/util/LodUtils.java index 2488b6cf8..43bc07cbe 100644 --- a/src/main/java/com/backsun/lod/util/LodUtils.java +++ b/src/main/java/com/backsun/lod/util/LodUtils.java @@ -8,6 +8,7 @@ import net.minecraft.client.multiplayer.ServerData; import net.minecraft.server.integrated.IntegratedServer; import net.minecraft.util.math.ChunkPos; import net.minecraft.world.DimensionType; +import net.minecraft.world.IWorld; import net.minecraft.world.chunk.ChunkSection; import net.minecraft.world.chunk.IChunk; import net.minecraft.world.server.ServerChunkProvider; @@ -109,32 +110,104 @@ public class LodUtils return false; } + + + + public static String getCurrentDimensionID() + { + + Minecraft mc = Minecraft.getInstance(); + if(mc.isIntegratedServerRunning()) + { + // this will return the world save location + // and the dimension folder + + if(mc.world == null) + return ""; + + ServerWorld serverWorld = LodUtils.getServerWorldFromDimension(mc.world.getDimensionType()); + if(serverWorld == null) + return ""; + + ServerChunkProvider provider = serverWorld.getChunkProvider(); + if(provider == null) + return ""; + + return provider.getSavedData().folder.toString(); + } + else + { + ServerData server = mc.getCurrentServerData(); + return server.serverName + ", IP " + + server.serverIP + ", GameVersion " + + server.gameVersion.getString() + "\\" + + "dim_" + mc.world.getDimensionType().getEffects().getPath() + "\\"; + } + } + + /** * If on single player this will return the name of the user's - * world, if in multiplayer it will return the server name - * and game version. + * world and the dimensional save folder, if in multiplayer + * it will return the server name, game version, and dimension.
+ *
+ * This can be used to determine where to save files for a given + * dimension. */ - public static String getCurrentWorldID() + public static String getDimensionIDFromWorld(IWorld world) { Minecraft mc = Minecraft.getInstance(); if(mc.isIntegratedServerRunning()) { - ServerWorld serverWorld = LodUtils.getFirstValidServerWorld(); - if (serverWorld == null) - throw new NullPointerException("getCurrentWorldID tried to get the ServerWorld but it was null"); + // this will return the world save location + // and the dimension folder + + ServerWorld serverWorld = LodUtils.getServerWorldFromDimension(world.getDimensionType()); + if(serverWorld == null) + throw new NullPointerException("getDimensionIDFromWorld wasn't able to get the ServerWorld for the dimension " + world.getDimensionType().getEffects().getPath()); ServerChunkProvider provider = serverWorld.getChunkProvider(); - if(provider != null) - return provider.getSavedData().folder.toString(); + if(provider == null) + throw new NullPointerException("getDimensionIDFromWorld wasn't able to get the ServerChunkProvider for the dimension " + world.getDimensionType().getEffects().getPath()); - return ""; + return provider.getSavedData().folder.toString(); } else { ServerData server = mc.getCurrentServerData(); - return server.serverName + ", IP " + server.serverIP + ", GameVersion " + server.gameVersion.getString(); + return server.serverName + ", IP " + + server.serverIP + ", GameVersion " + + server.gameVersion.getString() + "\\" + + "dim_" + world.getDimensionType().getEffects().getPath() + "\\"; + } + } + + /** + * If on single player this will return the name of the user's + * world, if in multiplayer it will return the server name + * and game version. + */ + public static String getWorldID(IWorld world) + { + if(mc.isIntegratedServerRunning()) + { + // chop off the dimension ID as it is not needed/wanted + String dimId = getDimensionIDFromWorld(world); + + // get the world name + int saveIndex = dimId.indexOf("saves") + 1 + "saves".length(); + int slashIndex = dimId.indexOf('\\', saveIndex); + dimId = dimId.substring(saveIndex, slashIndex); + return dimId; + } + else + { + ServerData server = mc.getCurrentServerData(); + return server.serverName + ", IP " + + server.serverIP + ", GameVersion " + + server.gameVersion.getString(); } }