diff --git a/src/main/java/com/seibel/lod/LodMain.java b/src/main/java/com/seibel/lod/LodForgeMain.java similarity index 90% rename from src/main/java/com/seibel/lod/LodMain.java rename to src/main/java/com/seibel/lod/LodForgeMain.java index 19e88b0bc..f288b0a26 100644 --- a/src/main/java/com/seibel/lod/LodMain.java +++ b/src/main/java/com/seibel/lod/LodForgeMain.java @@ -33,8 +33,7 @@ import net.minecraftforge.fml.event.server.FMLServerStartingEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; /** - * Initialize and setup the Mod. - *
+ * Initialize and setup the Mod.
* If you are looking for the real start of the mod * check out the ClientProxy. * @@ -42,12 +41,9 @@ import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; * @version 7-3-2021 */ @Mod(ModInfo.ID) -public class LodMain +public class LodForgeMain { - public static LodMain instance; - - public static ClientProxy client_proxy; - + public static ClientProxy clientProxy; private void init(final FMLCommonSetupEvent event) { @@ -55,7 +51,7 @@ public class LodMain } - public LodMain() + public LodForgeMain() { // Register the methods FMLJavaModLoadingContext.get().getModEventBus().addListener(this::init); @@ -67,8 +63,8 @@ public class LodMain private void onClientStart(final FMLClientSetupEvent event) { - client_proxy = new ClientProxy(); - MinecraftForge.EVENT_BUS.register(client_proxy); + clientProxy = new ClientProxy(); + MinecraftForge.EVENT_BUS.register(clientProxy); } diff --git a/src/main/java/com/seibel/lod/api/ClientApi.java b/src/main/java/com/seibel/lod/api/ClientApi.java deleted file mode 100644 index 67b760e7e..000000000 --- a/src/main/java/com/seibel/lod/api/ClientApi.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.seibel.lod.api; - -import com.seibel.lod.LodMain; -import com.seibel.lod.objects.rending.Mat4f; - -/** - * TODO - * - * @author James Seibel - * @version 11-11-2021 - */ -public class ClientApi -{ - - public ClientApi() - { - - } - - - - - public static void renderLods(Mat4f mcModelViewMatrix, float partialTicks) - { - LodMain.client_proxy.renderLods(mcModelViewMatrix, partialTicks); - } - - - - -} diff --git a/src/main/java/com/seibel/lod/builders/bufferBuilding/LodBufferBuilder.java b/src/main/java/com/seibel/lod/builders/bufferBuilding/LodBufferBuilder.java index 9b9eb909c..c61215697 100644 --- a/src/main/java/com/seibel/lod/builders/bufferBuilding/LodBufferBuilder.java +++ b/src/main/java/com/seibel/lod/builders/bufferBuilding/LodBufferBuilder.java @@ -39,14 +39,14 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.mojang.blaze3d.systems.RenderSystem; import com.seibel.lod.builders.bufferBuilding.lodTemplates.Box; import com.seibel.lod.config.LodConfig; -import com.seibel.lod.enums.GlProxyContext; -import com.seibel.lod.enums.GpuUploadMethod; -import com.seibel.lod.enums.VanillaOverdraw; +import com.seibel.lod.enums.config.GpuUploadMethod; +import com.seibel.lod.enums.config.VanillaOverdraw; +import com.seibel.lod.enums.rendering.GlProxyContext; +import com.seibel.lod.lodApi.ClientApi; import com.seibel.lod.objects.PosToRenderContainer; import com.seibel.lod.objects.lod.LodDimension; import com.seibel.lod.objects.lod.LodRegion; import com.seibel.lod.objects.lod.RegionPos; -import com.seibel.lod.proxy.ClientProxy; import com.seibel.lod.proxy.GlProxy; import com.seibel.lod.render.LodRenderer; import com.seibel.lod.util.DataPointUtil; @@ -229,7 +229,7 @@ public class LodBufferBuilder // create the nodeToRenderThreads // //================================// - skyLightPlayer = MinecraftWrapper.INSTANCE.getWrappedClientLevel().getSkyLight(playerBlockPos); + skyLightPlayer = MinecraftWrapper.INSTANCE.getWrappedClientWorld().getSkyLight(playerBlockPos); for (int xRegion = 0; xRegion < lodDim.getWidth(); xRegion++) { @@ -426,7 +426,7 @@ public class LodBufferBuilder // the future will be false if its thread failed if (!future.get()) { - ClientProxy.LOGGER.warn("LodBufferBuilder ran into trouble and had to start over."); + ClientApi.LOGGER.warn("LodBufferBuilder ran into trouble and had to start over."); break; } } @@ -445,7 +445,7 @@ public class LodBufferBuilder } catch (Exception e) { - ClientProxy.LOGGER.warn("\"LodNodeBufferBuilder.generateLodBuffersAsync\" ran into trouble: "); + ClientApi.LOGGER.warn("\"LodNodeBufferBuilder.generateLodBuffersAsync\" ran into trouble: "); e.printStackTrace(); } finally @@ -461,7 +461,7 @@ public class LodBufferBuilder } catch (Exception e) { - ClientProxy.LOGGER.warn("\"LodNodeBufferBuilder.generateLodBuffersAsync\" was unable to upload the buffers to the GPU: " + e.getMessage()); + ClientApi.LOGGER.warn("\"LodNodeBufferBuilder.generateLodBuffersAsync\" was unable to upload the buffers to the GPU: " + e.getMessage()); e.printStackTrace(); } @@ -792,7 +792,7 @@ public class LodBufferBuilder catch (Exception e) { // this doesn't appear to be necessary anymore, but just in case. - ClientProxy.LOGGER.error(LodBufferBuilder.class.getSimpleName() + " - UploadBuffers failed: " + e.getMessage()); + ClientApi.LOGGER.error(LodBufferBuilder.class.getSimpleName() + " - UploadBuffers failed: " + e.getMessage()); e.printStackTrace(); } finally @@ -911,7 +911,7 @@ public class LodBufferBuilder } catch (Exception e) { - ClientProxy.LOGGER.error("vboUpload failed: " + e.getClass().getSimpleName()); + ClientApi.LOGGER.error("vboUpload failed: " + e.getClass().getSimpleName()); e.printStackTrace(); } finally diff --git a/src/main/java/com/seibel/lod/builders/bufferBuilding/lodTemplates/AbstractLodTemplate.java b/src/main/java/com/seibel/lod/builders/bufferBuilding/lodTemplates/AbstractLodTemplate.java index 0cf1eab1d..312255c68 100644 --- a/src/main/java/com/seibel/lod/builders/bufferBuilding/lodTemplates/AbstractLodTemplate.java +++ b/src/main/java/com/seibel/lod/builders/bufferBuilding/lodTemplates/AbstractLodTemplate.java @@ -21,7 +21,7 @@ package com.seibel.lod.builders.bufferBuilding.lodTemplates; import java.util.Map; -import com.seibel.lod.enums.DebugMode; +import com.seibel.lod.enums.rendering.DebugMode; import com.seibel.lod.util.ColorUtil; import com.seibel.lod.wrappers.Block.BlockPosWrapper; diff --git a/src/main/java/com/seibel/lod/builders/bufferBuilding/lodTemplates/Box.java b/src/main/java/com/seibel/lod/builders/bufferBuilding/lodTemplates/Box.java index acea09391..60cb7c9ba 100644 --- a/src/main/java/com/seibel/lod/builders/bufferBuilding/lodTemplates/Box.java +++ b/src/main/java/com/seibel/lod/builders/bufferBuilding/lodTemplates/Box.java @@ -24,7 +24,7 @@ import java.util.HashMap; import java.util.Map; import com.seibel.lod.config.LodConfig; -import com.seibel.lod.enums.DebugMode; +import com.seibel.lod.enums.rendering.DebugMode; import com.seibel.lod.util.ColorUtil; import com.seibel.lod.util.DataPointUtil; import com.seibel.lod.util.LodUtil; @@ -249,7 +249,7 @@ public class Box for (Direction direction : DIRECTIONS) { if (!adjShadeDisabled[DIRECTION_INDEX.get(direction)]) - colorMap[DIRECTION_INDEX.get(direction)] = ColorUtil.applyShade(color, MinecraftWrapper.INSTANCE.getClientLevel().getShade(direction, true)); + colorMap[DIRECTION_INDEX.get(direction)] = ColorUtil.applyShade(color, MinecraftWrapper.INSTANCE.getClientWorld().getShade(direction, true)); else colorMap[DIRECTION_INDEX.get(direction)] = color; } @@ -264,7 +264,7 @@ public class Box if (LodConfig.CLIENT.advancedModOptions.debugging.debugMode.get() != DebugMode.SHOW_DETAIL) return colorMap[DIRECTION_INDEX.get(direction)]; else - return ColorUtil.applyShade(color, MinecraftWrapper.INSTANCE.getClientLevel().getShade(direction, true)); + return ColorUtil.applyShade(color, MinecraftWrapper.INSTANCE.getClientWorld().getShade(direction, true)); } /** diff --git a/src/main/java/com/seibel/lod/builders/bufferBuilding/lodTemplates/CubicLodTemplate.java b/src/main/java/com/seibel/lod/builders/bufferBuilding/lodTemplates/CubicLodTemplate.java index 8faae6538..071430703 100644 --- a/src/main/java/com/seibel/lod/builders/bufferBuilding/lodTemplates/CubicLodTemplate.java +++ b/src/main/java/com/seibel/lod/builders/bufferBuilding/lodTemplates/CubicLodTemplate.java @@ -21,7 +21,7 @@ package com.seibel.lod.builders.bufferBuilding.lodTemplates; import java.util.Map; -import com.seibel.lod.enums.DebugMode; +import com.seibel.lod.enums.rendering.DebugMode; import com.seibel.lod.util.ColorUtil; import com.seibel.lod.util.DataPointUtil; import com.seibel.lod.util.LodUtil; diff --git a/src/main/java/com/seibel/lod/builders/bufferBuilding/lodTemplates/DynamicLodTemplate.java b/src/main/java/com/seibel/lod/builders/bufferBuilding/lodTemplates/DynamicLodTemplate.java index e3f92f067..cc0e6270d 100644 --- a/src/main/java/com/seibel/lod/builders/bufferBuilding/lodTemplates/DynamicLodTemplate.java +++ b/src/main/java/com/seibel/lod/builders/bufferBuilding/lodTemplates/DynamicLodTemplate.java @@ -21,9 +21,8 @@ package com.seibel.lod.builders.bufferBuilding.lodTemplates; import java.util.Map; -import com.seibel.lod.enums.DebugMode; -import com.seibel.lod.proxy.ClientProxy; - +import com.seibel.lod.enums.rendering.DebugMode; +import com.seibel.lod.lodApi.ClientApi; import com.seibel.lod.wrappers.Block.BlockPosWrapper; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.util.Direction; @@ -42,7 +41,7 @@ public class DynamicLodTemplate extends AbstractLodTemplate public void addLodToBuffer(BufferBuilder buffer, BlockPosWrapper bufferCenterBlockPos, long data, Map adjData, byte detailLevel, int posX, int posZ, Box box, DebugMode debugging, boolean[] adjShadeDisabled) { - ClientProxy.LOGGER.error(DynamicLodTemplate.class.getSimpleName() + " is not implemented!"); + ClientApi.LOGGER.error(DynamicLodTemplate.class.getSimpleName() + " is not implemented!"); } } diff --git a/src/main/java/com/seibel/lod/builders/bufferBuilding/lodTemplates/TriangularLodTemplate.java b/src/main/java/com/seibel/lod/builders/bufferBuilding/lodTemplates/TriangularLodTemplate.java index 2bd3491e1..5291f92fa 100644 --- a/src/main/java/com/seibel/lod/builders/bufferBuilding/lodTemplates/TriangularLodTemplate.java +++ b/src/main/java/com/seibel/lod/builders/bufferBuilding/lodTemplates/TriangularLodTemplate.java @@ -21,9 +21,8 @@ package com.seibel.lod.builders.bufferBuilding.lodTemplates; import java.util.Map; -import com.seibel.lod.enums.DebugMode; -import com.seibel.lod.proxy.ClientProxy; - +import com.seibel.lod.enums.rendering.DebugMode; +import com.seibel.lod.lodApi.ClientApi; import com.seibel.lod.wrappers.Block.BlockPosWrapper; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.util.Direction; @@ -40,7 +39,7 @@ public class TriangularLodTemplate extends AbstractLodTemplate public void addLodToBuffer(BufferBuilder buffer, BlockPosWrapper bufferCenterBlockPos, long data, Map adjData, byte detailLevel, int posX, int posZ, Box box, DebugMode debugging, boolean[] adjShadeDisabled) { - ClientProxy.LOGGER.error(DynamicLodTemplate.class.getSimpleName() + " is not implemented!"); + ClientApi.LOGGER.error(DynamicLodTemplate.class.getSimpleName() + " is not implemented!"); } } diff --git a/src/main/java/com/seibel/lod/builders/lodBuilding/LodBuilder.java b/src/main/java/com/seibel/lod/builders/lodBuilding/LodBuilder.java index 082d77e0b..e1689170d 100644 --- a/src/main/java/com/seibel/lod/builders/lodBuilding/LodBuilder.java +++ b/src/main/java/com/seibel/lod/builders/lodBuilding/LodBuilder.java @@ -23,8 +23,8 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import com.seibel.lod.config.LodConfig; -import com.seibel.lod.enums.DistanceGenerationMode; -import com.seibel.lod.enums.HorizontalResolution; +import com.seibel.lod.enums.config.DistanceGenerationMode; +import com.seibel.lod.enums.config.HorizontalResolution; import com.seibel.lod.objects.lod.LodDimension; import com.seibel.lod.objects.lod.LodRegion; import com.seibel.lod.objects.lod.LodWorld; @@ -42,10 +42,8 @@ import com.seibel.lod.wrappers.Block.BlockShapeWrapper; import com.seibel.lod.wrappers.Chunk.ChunkPosWrapper; import com.seibel.lod.wrappers.Chunk.ChunkWrapper; import com.seibel.lod.wrappers.World.BiomeWrapper; -import com.seibel.lod.wrappers.World.LevelWrapper; - -import net.minecraft.world.DimensionType; -import net.minecraft.world.IWorld; +import com.seibel.lod.wrappers.World.DimensionTypeWrapper; +import com.seibel.lod.wrappers.World.WorldWrapper; /** * This object is in charge of creating Lod related objects. @@ -86,12 +84,12 @@ public class LodBuilder } - public void generateLodNodeAsync(ChunkWrapper chunk, LodWorld lodWorld, IWorld world) + public void generateLodNodeAsync(ChunkWrapper chunk, LodWorld lodWorld, DimensionTypeWrapper dim) { - generateLodNodeAsync(chunk, lodWorld, world, DistanceGenerationMode.SERVER); + generateLodNodeAsync(chunk, lodWorld, dim, DistanceGenerationMode.SERVER); } - public void generateLodNodeAsync(ChunkWrapper chunk, LodWorld lodWorld, IWorld world, DistanceGenerationMode generationMode) + public void generateLodNodeAsync(ChunkWrapper chunk, LodWorld lodWorld, DimensionTypeWrapper dim, DistanceGenerationMode generationMode) { if (lodWorld == null || lodWorld.getIsWorldNotLoaded()) return; @@ -108,7 +106,7 @@ public class LodBuilder { // we need a loaded client world in order to // get the textures for blocks - if (mc.getClientLevel() == null) + if (mc.getClientWorld() == null) return; // don't try to generate LODs if the user isn't in the world anymore @@ -116,8 +114,6 @@ public class LodBuilder if (mc.getSinglePlayerServer() == null && mc.getCurrentServer() == null) return; - DimensionType dim = world.dimensionType(); - // make sure the dimension exists LodDimension lodDim; if (lodWorld.getLodDimension(dim) == null) @@ -170,7 +166,7 @@ public class LodBuilder return; // this happens if a LOD is generated after the user leaves the world. - if (MinecraftWrapper.INSTANCE.getWrappedClientLevel() == null) + if (MinecraftWrapper.INSTANCE.getWrappedClientWorld() == null) return; // determine how many LODs to generate horizontally @@ -230,8 +226,8 @@ public class LodBuilder int xAbs; int yAbs; int zAbs; - boolean hasCeiling = mc.getClientLevel().dimensionType().hasCeiling(); - boolean hasSkyLight = mc.getClientLevel().dimensionType().hasSkyLight(); + boolean hasCeiling = mc.getClientWorld().dimensionType().hasCeiling(); + boolean hasSkyLight = mc.getClientWorld().dimensionType().hasSkyLight(); boolean isDefault; BlockPosWrapper blockPos = new BlockPosWrapper(); int index; @@ -386,7 +382,7 @@ public class LodBuilder // 1 means the lighting is a guess int isDefault = 0; - LevelWrapper world = MinecraftWrapper.INSTANCE.getWrappedServerLevel(); + WorldWrapper world = MinecraftWrapper.INSTANCE.getWrappedServerWorld(); int blockBrightness = chunk.getEmittedBrightness(blockPos); // get the air block above or below this block @@ -414,7 +410,7 @@ public class LodBuilder { // we are on predicted terrain, and we don't know what the light here is, // lets just take a guess - if (blockPos.getY() >= mc.getClientLevel().getSeaLevel() - 5) + if (blockPos.getY() >= mc.getClientWorld().getSeaLevel() - 5) { skyLight = 12; isDefault = 1; @@ -425,7 +421,7 @@ public class LodBuilder } else { - world = MinecraftWrapper.INSTANCE.getWrappedClientLevel(); + world = MinecraftWrapper.INSTANCE.getWrappedServerWorld(); if (world.isEmpty()) return 0; // client world sky light (almost never accurate) @@ -447,7 +443,7 @@ public class LodBuilder { // we don't know what the light here is, // lets just take a guess - if (blockPos.getY() >= mc.getClientLevel().getSeaLevel() - 5) + if (blockPos.getY() >= mc.getClientWorld().getSeaLevel() - 5) { skyLight = 12; isDefault = 1; diff --git a/src/main/java/com/seibel/lod/builders/lodBuilding/LodBuilderConfig.java b/src/main/java/com/seibel/lod/builders/lodBuilding/LodBuilderConfig.java index 89569f486..5b2034d8e 100644 --- a/src/main/java/com/seibel/lod/builders/lodBuilding/LodBuilderConfig.java +++ b/src/main/java/com/seibel/lod/builders/lodBuilding/LodBuilderConfig.java @@ -19,7 +19,7 @@ package com.seibel.lod.builders.lodBuilding; -import com.seibel.lod.enums.DistanceGenerationMode; +import com.seibel.lod.enums.config.DistanceGenerationMode; /** * This is used to easily configure how LodChunks are generated. diff --git a/src/main/java/com/seibel/lod/builders/worldGeneration/LodGenWorker.java b/src/main/java/com/seibel/lod/builders/worldGeneration/LodGenWorker.java index 5d61498b1..271a47e62 100644 --- a/src/main/java/com/seibel/lod/builders/worldGeneration/LodGenWorker.java +++ b/src/main/java/com/seibel/lod/builders/worldGeneration/LodGenWorker.java @@ -32,13 +32,13 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.seibel.lod.builders.lodBuilding.LodBuilder; import com.seibel.lod.builders.lodBuilding.LodBuilderConfig; import com.seibel.lod.config.LodConfig; -import com.seibel.lod.enums.DistanceGenerationMode; +import com.seibel.lod.enums.config.DistanceGenerationMode; import com.seibel.lod.objects.lod.LodDimension; -import com.seibel.lod.proxy.ClientProxy; import com.seibel.lod.util.LodUtil; - import com.seibel.lod.wrappers.Chunk.ChunkPosWrapper; import com.seibel.lod.wrappers.Chunk.ChunkWrapper; +import com.seibel.lod.wrappers.World.WorldWrapper; + import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.util.palette.UpgradeData; @@ -92,7 +92,7 @@ public class LodGenWorker implements IWorker public LodGenWorker(ChunkPosWrapper newPos, DistanceGenerationMode newGenerationMode, LodBuilder newLodBuilder, - LodDimension newLodDimension, ServerWorld newServerWorld) + LodDimension newLodDimension, WorldWrapper serverWorld) { // just a few sanity checks if (newPos == null) @@ -104,14 +104,14 @@ public class LodGenWorker implements IWorker if (newLodDimension == null) throw new IllegalArgumentException("LodChunkGenThread requires a non-null LodDimension"); - if (newServerWorld == null) + if (serverWorld == null) throw new IllegalArgumentException("LodChunkGenThread requires a non-null ServerWorld"); thread = new LodChunkGenThread(newPos, newGenerationMode, newLodBuilder, - newLodDimension, newServerWorld); + newLodDimension, serverWorld.getServerWorld()); // TODO wrapper needed } @Override diff --git a/src/main/java/com/seibel/lod/builders/worldGeneration/LodWorldGenerator.java b/src/main/java/com/seibel/lod/builders/worldGeneration/LodWorldGenerator.java index f863881c2..014fb64ee 100644 --- a/src/main/java/com/seibel/lod/builders/worldGeneration/LodWorldGenerator.java +++ b/src/main/java/com/seibel/lod/builders/worldGeneration/LodWorldGenerator.java @@ -27,7 +27,7 @@ import java.util.concurrent.atomic.AtomicInteger; import com.seibel.lod.builders.lodBuilding.LodBuilder; import com.seibel.lod.config.LodConfig; -import com.seibel.lod.enums.DistanceGenerationMode; +import com.seibel.lod.enums.config.DistanceGenerationMode; import com.seibel.lod.objects.PosToGenerateContainer; import com.seibel.lod.objects.lod.LodDimension; import com.seibel.lod.render.LodRenderer; @@ -35,10 +35,10 @@ import com.seibel.lod.util.DetailDistanceUtil; import com.seibel.lod.util.LevelPosUtil; import com.seibel.lod.util.LodThreadFactory; import com.seibel.lod.util.LodUtil; -import com.seibel.lod.wrappers.Chunk.ChunkPosWrapper; import com.seibel.lod.wrappers.MinecraftWrapper; +import com.seibel.lod.wrappers.Chunk.ChunkPosWrapper; +import com.seibel.lod.wrappers.World.WorldWrapper; -import net.minecraft.world.server.ServerWorld; import net.minecraftforge.common.WorldWorkerManager; /** @@ -115,7 +115,7 @@ public class LodWorldGenerator // fill in positionsWaitingToBeGenerated // //=======================================// - ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(lodDim.dimension); + WorldWrapper serverWorld = LodUtil.getServerWorldFromDimension(lodDim.dimension); PosToGenerateContainer posToGenerate = lodDim.getPosToGenerate( maxChunkGenRequests, diff --git a/src/main/java/com/seibel/lod/config/LodConfig.java b/src/main/java/com/seibel/lod/config/LodConfig.java index 004b1fab2..25fd29ebb 100644 --- a/src/main/java/com/seibel/lod/config/LodConfig.java +++ b/src/main/java/com/seibel/lod/config/LodConfig.java @@ -28,20 +28,20 @@ import org.apache.logging.log4j.LogManager; import com.electronwill.nightconfig.core.file.CommentedFileConfig; import com.electronwill.nightconfig.core.io.WritingMode; import com.seibel.lod.ModInfo; -import com.seibel.lod.enums.BlockToAvoid; -import com.seibel.lod.enums.BufferRebuildTimes; -import com.seibel.lod.enums.DebugMode; -import com.seibel.lod.enums.DistanceGenerationMode; -import com.seibel.lod.enums.FogDistance; -import com.seibel.lod.enums.FogDrawOverride; -import com.seibel.lod.enums.GenerationPriority; -import com.seibel.lod.enums.GpuUploadMethod; -import com.seibel.lod.enums.HorizontalQuality; -import com.seibel.lod.enums.HorizontalResolution; -import com.seibel.lod.enums.HorizontalScale; -import com.seibel.lod.enums.LodTemplate; -import com.seibel.lod.enums.VanillaOverdraw; -import com.seibel.lod.enums.VerticalQuality; +import com.seibel.lod.enums.config.BlockToAvoid; +import com.seibel.lod.enums.config.BufferRebuildTimes; +import com.seibel.lod.enums.config.DistanceGenerationMode; +import com.seibel.lod.enums.config.GenerationPriority; +import com.seibel.lod.enums.config.GpuUploadMethod; +import com.seibel.lod.enums.config.HorizontalQuality; +import com.seibel.lod.enums.config.HorizontalResolution; +import com.seibel.lod.enums.config.HorizontalScale; +import com.seibel.lod.enums.config.LodTemplate; +import com.seibel.lod.enums.config.VanillaOverdraw; +import com.seibel.lod.enums.config.VerticalQuality; +import com.seibel.lod.enums.rendering.DebugMode; +import com.seibel.lod.enums.rendering.FogDistance; +import com.seibel.lod.enums.rendering.FogDrawOverride; import com.seibel.lod.util.LodUtil; import net.minecraftforge.common.ForgeConfigSpec; diff --git a/src/main/java/com/seibel/lod/enums/WorldType.java b/src/main/java/com/seibel/lod/enums/WorldType.java new file mode 100644 index 000000000..b8a74d999 --- /dev/null +++ b/src/main/java/com/seibel/lod/enums/WorldType.java @@ -0,0 +1,33 @@ +/* + * This file is part of the Distant Horizon mod (formerly the LOD Mod), + * licensed under the GNU GPL v3 License. + * + * Copyright (C) 2020 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.seibel.lod.enums; + +/** + * ServerWorld, ClientWorld, Unknown + * + * @author James Seibel + * @version 11-12-2021 + */ +public enum WorldType +{ + ServerWorld, + ClientWorld, + Unknown +} diff --git a/src/main/java/com/seibel/lod/enums/BlockToAvoid.java b/src/main/java/com/seibel/lod/enums/config/BlockToAvoid.java similarity index 96% rename from src/main/java/com/seibel/lod/enums/BlockToAvoid.java rename to src/main/java/com/seibel/lod/enums/config/BlockToAvoid.java index a09b5d68f..a768b2d85 100644 --- a/src/main/java/com/seibel/lod/enums/BlockToAvoid.java +++ b/src/main/java/com/seibel/lod/enums/config/BlockToAvoid.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.seibel.lod.enums; +package com.seibel.lod.enums.config; /** * heightmap
diff --git a/src/main/java/com/seibel/lod/enums/BufferRebuildTimes.java b/src/main/java/com/seibel/lod/enums/config/BufferRebuildTimes.java similarity index 97% rename from src/main/java/com/seibel/lod/enums/BufferRebuildTimes.java rename to src/main/java/com/seibel/lod/enums/config/BufferRebuildTimes.java index 0ae515b1f..3f7c3bafa 100644 --- a/src/main/java/com/seibel/lod/enums/BufferRebuildTimes.java +++ b/src/main/java/com/seibel/lod/enums/config/BufferRebuildTimes.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.seibel.lod.enums; +package com.seibel.lod.enums.config; /** * Near_First
diff --git a/src/main/java/com/seibel/lod/enums/DistanceGenerationMode.java b/src/main/java/com/seibel/lod/enums/config/DistanceGenerationMode.java similarity index 98% rename from src/main/java/com/seibel/lod/enums/DistanceGenerationMode.java rename to src/main/java/com/seibel/lod/enums/config/DistanceGenerationMode.java index 3060ec4a4..c71973fde 100644 --- a/src/main/java/com/seibel/lod/enums/DistanceGenerationMode.java +++ b/src/main/java/com/seibel/lod/enums/config/DistanceGenerationMode.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.seibel.lod.enums; +package com.seibel.lod.enums.config; /** * NONE
diff --git a/src/main/java/com/seibel/lod/enums/GenerationPriority.java b/src/main/java/com/seibel/lod/enums/config/GenerationPriority.java similarity index 96% rename from src/main/java/com/seibel/lod/enums/GenerationPriority.java rename to src/main/java/com/seibel/lod/enums/config/GenerationPriority.java index 63c6b9d7f..58721d6c4 100644 --- a/src/main/java/com/seibel/lod/enums/GenerationPriority.java +++ b/src/main/java/com/seibel/lod/enums/config/GenerationPriority.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.seibel.lod.enums; +package com.seibel.lod.enums.config; /** * Near_First
diff --git a/src/main/java/com/seibel/lod/enums/GpuUploadMethod.java b/src/main/java/com/seibel/lod/enums/config/GpuUploadMethod.java similarity index 97% rename from src/main/java/com/seibel/lod/enums/GpuUploadMethod.java rename to src/main/java/com/seibel/lod/enums/config/GpuUploadMethod.java index b88be18be..997ffbc22 100644 --- a/src/main/java/com/seibel/lod/enums/GpuUploadMethod.java +++ b/src/main/java/com/seibel/lod/enums/config/GpuUploadMethod.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.seibel.lod.enums; +package com.seibel.lod.enums.config; /** * Buffer_Storage, Sub_Data, Buffer_Mapping diff --git a/src/main/java/com/seibel/lod/enums/HorizontalQuality.java b/src/main/java/com/seibel/lod/enums/config/HorizontalQuality.java similarity index 97% rename from src/main/java/com/seibel/lod/enums/HorizontalQuality.java rename to src/main/java/com/seibel/lod/enums/config/HorizontalQuality.java index 09472c320..6af03fcd8 100644 --- a/src/main/java/com/seibel/lod/enums/HorizontalQuality.java +++ b/src/main/java/com/seibel/lod/enums/config/HorizontalQuality.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.seibel.lod.enums; +package com.seibel.lod.enums.config; /** * Lowest
diff --git a/src/main/java/com/seibel/lod/enums/HorizontalResolution.java b/src/main/java/com/seibel/lod/enums/config/HorizontalResolution.java similarity index 99% rename from src/main/java/com/seibel/lod/enums/HorizontalResolution.java rename to src/main/java/com/seibel/lod/enums/config/HorizontalResolution.java index e8cdbbfa9..bdd481dc4 100644 --- a/src/main/java/com/seibel/lod/enums/HorizontalResolution.java +++ b/src/main/java/com/seibel/lod/enums/config/HorizontalResolution.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.seibel.lod.enums; +package com.seibel.lod.enums.config; import java.util.ArrayList; import java.util.Collections; diff --git a/src/main/java/com/seibel/lod/enums/HorizontalScale.java b/src/main/java/com/seibel/lod/enums/config/HorizontalScale.java similarity index 97% rename from src/main/java/com/seibel/lod/enums/HorizontalScale.java rename to src/main/java/com/seibel/lod/enums/config/HorizontalScale.java index cf941d1e6..779f70043 100644 --- a/src/main/java/com/seibel/lod/enums/HorizontalScale.java +++ b/src/main/java/com/seibel/lod/enums/config/HorizontalScale.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.seibel.lod.enums; +package com.seibel.lod.enums.config; /** * Low
diff --git a/src/main/java/com/seibel/lod/enums/LodTemplate.java b/src/main/java/com/seibel/lod/enums/config/LodTemplate.java similarity index 97% rename from src/main/java/com/seibel/lod/enums/LodTemplate.java rename to src/main/java/com/seibel/lod/enums/config/LodTemplate.java index 965838571..9d7fa8651 100644 --- a/src/main/java/com/seibel/lod/enums/LodTemplate.java +++ b/src/main/java/com/seibel/lod/enums/config/LodTemplate.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.seibel.lod.enums; +package com.seibel.lod.enums.config; import com.seibel.lod.builders.bufferBuilding.lodTemplates.AbstractLodTemplate; import com.seibel.lod.builders.bufferBuilding.lodTemplates.CubicLodTemplate; diff --git a/src/main/java/com/seibel/lod/enums/ShadingMode.java b/src/main/java/com/seibel/lod/enums/config/ShadingMode.java similarity index 89% rename from src/main/java/com/seibel/lod/enums/ShadingMode.java rename to src/main/java/com/seibel/lod/enums/config/ShadingMode.java index 89d7d0405..5e1eb7657 100644 --- a/src/main/java/com/seibel/lod/enums/ShadingMode.java +++ b/src/main/java/com/seibel/lod/enums/config/ShadingMode.java @@ -1,4 +1,4 @@ -package com.seibel.lod.enums; +package com.seibel.lod.enums.config; /** * NONE, GAME_SHADING diff --git a/src/main/java/com/seibel/lod/enums/VanillaOverdraw.java b/src/main/java/com/seibel/lod/enums/config/VanillaOverdraw.java similarity index 97% rename from src/main/java/com/seibel/lod/enums/VanillaOverdraw.java rename to src/main/java/com/seibel/lod/enums/config/VanillaOverdraw.java index aa980a6ff..51d7c04da 100644 --- a/src/main/java/com/seibel/lod/enums/VanillaOverdraw.java +++ b/src/main/java/com/seibel/lod/enums/config/VanillaOverdraw.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.seibel.lod.enums; +package com.seibel.lod.enums.config; /** * None, Dynamic, Always diff --git a/src/main/java/com/seibel/lod/enums/VerticalQuality.java b/src/main/java/com/seibel/lod/enums/config/VerticalQuality.java similarity index 97% rename from src/main/java/com/seibel/lod/enums/VerticalQuality.java rename to src/main/java/com/seibel/lod/enums/config/VerticalQuality.java index b66cff165..1f8a26f9b 100644 --- a/src/main/java/com/seibel/lod/enums/VerticalQuality.java +++ b/src/main/java/com/seibel/lod/enums/config/VerticalQuality.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.seibel.lod.enums; +package com.seibel.lod.enums.config; /** * heightmap
diff --git a/src/main/java/com/seibel/lod/enums/DebugMode.java b/src/main/java/com/seibel/lod/enums/rendering/DebugMode.java similarity index 97% rename from src/main/java/com/seibel/lod/enums/DebugMode.java rename to src/main/java/com/seibel/lod/enums/rendering/DebugMode.java index 1b68f2a6f..2ecf20a93 100644 --- a/src/main/java/com/seibel/lod/enums/DebugMode.java +++ b/src/main/java/com/seibel/lod/enums/rendering/DebugMode.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.seibel.lod.enums; +package com.seibel.lod.enums.rendering; /** * off, detail, detail wireframe diff --git a/src/main/java/com/seibel/lod/enums/FogDistance.java b/src/main/java/com/seibel/lod/enums/rendering/FogDistance.java similarity index 96% rename from src/main/java/com/seibel/lod/enums/FogDistance.java rename to src/main/java/com/seibel/lod/enums/rendering/FogDistance.java index b589a57c5..d7e0bdaf5 100644 --- a/src/main/java/com/seibel/lod/enums/FogDistance.java +++ b/src/main/java/com/seibel/lod/enums/rendering/FogDistance.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.seibel.lod.enums; +package com.seibel.lod.enums.rendering; /** * NEAR, FAR, or NEAR_AND_FAR. diff --git a/src/main/java/com/seibel/lod/enums/FogDrawOverride.java b/src/main/java/com/seibel/lod/enums/rendering/FogDrawOverride.java similarity index 96% rename from src/main/java/com/seibel/lod/enums/FogDrawOverride.java rename to src/main/java/com/seibel/lod/enums/rendering/FogDrawOverride.java index 57ec7a3af..fe330a280 100644 --- a/src/main/java/com/seibel/lod/enums/FogDrawOverride.java +++ b/src/main/java/com/seibel/lod/enums/rendering/FogDrawOverride.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.seibel.lod.enums; +package com.seibel.lod.enums.rendering; /** * USE_OPTIFINE_FOG_SETTING,
diff --git a/src/main/java/com/seibel/lod/enums/FogQuality.java b/src/main/java/com/seibel/lod/enums/rendering/FogQuality.java similarity index 95% rename from src/main/java/com/seibel/lod/enums/FogQuality.java rename to src/main/java/com/seibel/lod/enums/rendering/FogQuality.java index d192a33f4..460c82bdf 100644 --- a/src/main/java/com/seibel/lod/enums/FogQuality.java +++ b/src/main/java/com/seibel/lod/enums/rendering/FogQuality.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.seibel.lod.enums; +package com.seibel.lod.enums.rendering; /** * fast, fancy, or off diff --git a/src/main/java/com/seibel/lod/enums/GlProxyContext.java b/src/main/java/com/seibel/lod/enums/rendering/GlProxyContext.java similarity index 96% rename from src/main/java/com/seibel/lod/enums/GlProxyContext.java rename to src/main/java/com/seibel/lod/enums/rendering/GlProxyContext.java index 512b46c7b..cd7965705 100644 --- a/src/main/java/com/seibel/lod/enums/GlProxyContext.java +++ b/src/main/java/com/seibel/lod/enums/rendering/GlProxyContext.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.seibel.lod.enums; +package com.seibel.lod.enums.rendering; /** * Minecraft, Lod_Builder, None diff --git a/src/main/java/com/seibel/lod/handlers/ChunkFileLoader.java b/src/main/java/com/seibel/lod/handlers/ChunkFileLoader.java new file mode 100644 index 000000000..6a20605a7 --- /dev/null +++ b/src/main/java/com/seibel/lod/handlers/ChunkFileLoader.java @@ -0,0 +1,65 @@ +/* + * This file is part of the Distant Horizon mod (formerly the LOD Mod), + * licensed under the GNU GPL v3 License. + * + * Copyright (C) 2020 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.seibel.lod.handlers; + +/** + * + * @author Cola + * @author Leonardo Amato + * @version 11-12-2021 + */ +public class ChunkFileLoader +{ + // TODO +// public static IChunk getChunkFromFile(ChunkPos pos) +// { +// LevelWrapper clientLevel = MinecraftWrapper.INSTANCE.getWrappedClientLevel(); +// if (clientLevel == null) +// return null; +// WorldWrapper serverWorld = LodUtil.getServerWorldFromDimension(clientLevel.getDimensionType()); +// try +// { +// File file = new File(serverWorld.getSaveFolder().getParent() + File.separatorChar + "region", "r." + (pos.x >> 5) + "." + (pos.z >> 5) + ".mca"); +// if(!file.exists()) +// return null; +// IChunk loadedChunk = ChunkSerializer.read( +// serverWorld, +// serverWorld.getStructureManager(), +// serverWorld.getPoiManager(), +// pos, +// serverWorld.getChunkSource().chunkMap.read(pos) +// ); +// boolean emptyChunk = true; +// for(int i = 0; i < 16; i++){ +// for(int j = 0; j < 16; j++){ +// emptyChunk &= loadedChunk.isYSpaceEmpty(i,j); +// } +// } +// if(emptyChunk) +// return null; +// else +// return loadedChunk; +// } +// catch (Exception e) +// { +// return null; +// } +// } +} diff --git a/src/main/java/com/seibel/lod/handlers/ChunkLoader.java b/src/main/java/com/seibel/lod/handlers/ChunkLoader.java deleted file mode 100644 index 392e34a7a..000000000 --- a/src/main/java/com/seibel/lod/handlers/ChunkLoader.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * This file is part of the Distant Horizon mod (formerly the LOD Mod), - * licensed under the GNU GPL v3 License. - * - * Copyright (C) 2020 James Seibel - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.seibel.lod.handlers; - -import java.io.File; - -import com.seibel.lod.util.LodUtil; -import com.seibel.lod.wrappers.MinecraftWrapper; - -import com.seibel.lod.wrappers.World.LevelWrapper; -import net.minecraft.util.math.ChunkPos; -import net.minecraft.world.chunk.IChunk; -import net.minecraft.world.chunk.storage.ChunkSerializer; -import net.minecraft.world.server.ServerWorld; - -/** - * - * @author ?? - * @version ?? - */ -public class ChunkLoader -{ - public static IChunk getChunkFromFile(ChunkPos pos){ - - LevelWrapper clientLevel = MinecraftWrapper.INSTANCE.getWrappedClientLevel(); - if (clientLevel == null) - return null; - ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(clientLevel.getWorld().dimensionType()); - try - { - File file = new File(serverWorld.getChunkSource().getDataStorage().dataFolder.getParent() + File.separatorChar + "region", "r." + (pos.x >> 5) + "." + (pos.z >> 5) + ".mca"); - if(!file.exists()) - return null; - IChunk loadedChunk = ChunkSerializer.read( - serverWorld, - serverWorld.getStructureManager(), - serverWorld.getPoiManager(), - pos, - serverWorld.getChunkSource().chunkMap.read(pos) - ); - boolean emptyChunk = true; - for(int i = 0; i < 16; i++){ - for(int j = 0; j < 16; j++){ - emptyChunk &= loadedChunk.isYSpaceEmpty(i,j); - } - } - if(emptyChunk) - return null; - else - return loadedChunk; - } - catch (Exception e) - { - return null; - } - } -} diff --git a/src/main/java/com/seibel/lod/handlers/LodDimensionFileHandler.java b/src/main/java/com/seibel/lod/handlers/LodDimensionFileHandler.java index 4718c7389..2e2bdf990 100644 --- a/src/main/java/com/seibel/lod/handlers/LodDimensionFileHandler.java +++ b/src/main/java/com/seibel/lod/handlers/LodDimensionFileHandler.java @@ -29,13 +29,13 @@ import java.util.concurrent.Executors; import org.apache.commons.compress.compressors.xz.XZCompressorInputStream; import org.apache.commons.compress.compressors.xz.XZCompressorOutputStream; -import com.seibel.lod.enums.DistanceGenerationMode; -import com.seibel.lod.enums.VerticalQuality; +import com.seibel.lod.enums.config.DistanceGenerationMode; +import com.seibel.lod.enums.config.VerticalQuality; +import com.seibel.lod.lodApi.ClientApi; import com.seibel.lod.objects.lod.LodDimension; import com.seibel.lod.objects.lod.LodRegion; import com.seibel.lod.objects.lod.RegionPos; import com.seibel.lod.objects.lod.VerticalLevelContainer; -import com.seibel.lod.proxy.ClientProxy; import com.seibel.lod.util.LodThreadFactory; import com.seibel.lod.util.LodUtil; import com.seibel.lod.util.ThreadMapUtil; @@ -175,7 +175,7 @@ public class LodDimensionFileHandler // close the reader and delete the file. inputStream.close(); file.delete(); - ClientProxy.LOGGER.info("Outdated LOD region file for region: (" + regionX + "," + regionZ + ")" + ClientApi.LOGGER.info("Outdated LOD region file for region: (" + regionX + "," + regionZ + ")" + " version found: " + fileVersion + ", version requested: " + LOD_SAVE_FILE_VERSION + ". File was been deleted."); @@ -188,7 +188,7 @@ public class LodDimensionFileHandler // close the reader and ignore the file, we don't // want to accidentally delete anything the user may want. inputStream.close(); - ClientProxy.LOGGER.info("Newer LOD region file for region: (" + regionX + "," + regionZ + ")" + ClientApi.LOGGER.info("Newer LOD region file for region: (" + regionX + "," + regionZ + ")" + " version found: " + fileVersion + ", version requested: " + LOD_SAVE_FILE_VERSION + " this region will not be written to in order to protect the newer file."); @@ -209,7 +209,7 @@ public class LodDimensionFileHandler } catch (IOException ioEx) { - ClientProxy.LOGGER.error("LOD file read error. Unable to read to [" + fileName + "] error [" + ioEx.getMessage() + "]: "); + ClientApi.LOGGER.error("LOD file read error. Unable to read to [" + fileName + "] error [" + ioEx.getMessage() + "]: "); ioEx.printStackTrace(); } } @@ -218,7 +218,7 @@ public class LodDimensionFileHandler { // the buffered reader encountered a // problem reading the file - ClientProxy.LOGGER.error("LOD file read error. Unable to read to [" + fileName + "] error [" + e.getMessage() + "]: "); + ClientApi.LOGGER.error("LOD file read error. Unable to read to [" + fileName + "] error [" + e.getMessage() + "]: "); e.printStackTrace(); } }// for each detail level @@ -280,7 +280,7 @@ public class LodDimensionFileHandler // for some reason if (fileName == null) { - ClientProxy.LOGGER.warn("Unable to save region [" + region.regionPosX + ", " + region.regionPosZ + "] to file, file is inaccessible."); + ClientApi.LOGGER.warn("Unable to save region [" + region.regionPosX + ", " + region.regionPosZ + "] to file, file is inaccessible."); return; } File oldFile = new File(fileName); @@ -331,7 +331,7 @@ public class LodDimensionFileHandler // existing file is complete while new one is only partially generate // this can happen is for some reason loading failed // this doesn't fix the bug, but at least protects old data - ClientProxy.LOGGER.error("LOD file write error. Attempted to overwrite complete region with incomplete one [" + fileName + "]"); + ClientApi.LOGGER.error("LOD file write error. Attempted to overwrite complete region with incomplete one [" + fileName + "]"); return; } // if we got this far then we are good @@ -358,7 +358,7 @@ public class LodDimensionFileHandler } catch (Exception e) { - ClientProxy.LOGGER.error("LOD file write error. Unable to write to [" + fileName + "] error [" + e.getMessage() + "]: "); + ClientApi.LOGGER.error("LOD file write error. Unable to write to [" + fileName + "] error [" + e.getMessage() + "]: "); e.printStackTrace(); } } @@ -382,7 +382,7 @@ public class LodDimensionFileHandler } catch (IOException ioEx) { - ClientProxy.LOGGER.error("LOD file read error. Unable to read to [" + fileName + "] error [" + ioEx.getMessage() + "]: "); + ClientApi.LOGGER.error("LOD file read error. Unable to read to [" + fileName + "] error [" + ioEx.getMessage() + "]: "); ioEx.printStackTrace(); } return new byte[0]; @@ -414,7 +414,7 @@ public class LodDimensionFileHandler } catch (IOException | SecurityException e) { - ClientProxy.LOGGER.warn("Unable to get the filename for the region [" + regionX + ", " + regionZ + "], error: [" + e.getMessage() + "], stacktrace: "); + ClientApi.LOGGER.warn("Unable to get the filename for the region [" + regionX + ", " + regionZ + "], error: [" + e.getMessage() + "], stacktrace: "); e.printStackTrace(); return null; } diff --git a/src/main/java/com/seibel/lod/handlers/ReflectionHandler.java b/src/main/java/com/seibel/lod/handlers/ReflectionHandler.java index 9ed3373c5..7203603c8 100644 --- a/src/main/java/com/seibel/lod/handlers/ReflectionHandler.java +++ b/src/main/java/com/seibel/lod/handlers/ReflectionHandler.java @@ -19,8 +19,8 @@ package com.seibel.lod.handlers; -import com.seibel.lod.enums.FogQuality; -import com.seibel.lod.proxy.ClientProxy; +import com.seibel.lod.enums.rendering.FogQuality; +import com.seibel.lod.lodApi.ClientApi; import com.seibel.lod.wrappers.MinecraftWrapper; import net.minecraft.util.math.vector.Matrix4f; @@ -70,7 +70,7 @@ public class ReflectionHandler // we didn't find the field, // either optifine isn't installed, or // optifine changed the name of the variable - ClientProxy.LOGGER.info(ReflectionHandler.class.getSimpleName() + ": unable to find the Optifine fog field. If Optifine isn't installed this can be ignored."); + ClientApi.LOGGER.info(ReflectionHandler.class.getSimpleName() + ": unable to find the Optifine fog field. If Optifine isn't installed this can be ignored."); } diff --git a/src/main/java/com/seibel/lod/lodApi/ApiShared.java b/src/main/java/com/seibel/lod/lodApi/ApiShared.java new file mode 100644 index 000000000..ee23a7593 --- /dev/null +++ b/src/main/java/com/seibel/lod/lodApi/ApiShared.java @@ -0,0 +1,53 @@ +/* + * This file is part of the Distant Horizon mod (formerly the LOD Mod), + * licensed under the GNU GPL v3 License. + * + * Copyright (C) 2020 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.seibel.lod.lodApi; + +import com.seibel.lod.builders.bufferBuilding.LodBufferBuilder; +import com.seibel.lod.builders.lodBuilding.LodBuilder; +import com.seibel.lod.objects.lod.LodWorld; + +/** + * This stores objects and variables that + * are shared between the different LodApi classes. + * + * @author James Seibel + * @version 11-12-2021 + */ +public class ApiShared +{ + public ApiShared INSTANCE = new ApiShared(); + + public static final LodBufferBuilder lodBufferBuilder = new LodBufferBuilder(); + public static final LodWorld lodWorld = new LodWorld(); + public static final LodBuilder lodBuilder = new LodBuilder(); + + /** Used to determine if the LODs should be regenerated */ + public static int previousChunkRenderDistance = 0; + /** Used to determine if the LODs should be regenerated */ + public static int previousLodRenderDistance = 0; + + + + private ApiShared() + { + + } + +} diff --git a/src/main/java/com/seibel/lod/lodApi/ClientApi.java b/src/main/java/com/seibel/lod/lodApi/ClientApi.java new file mode 100644 index 000000000..15a1e51d1 --- /dev/null +++ b/src/main/java/com/seibel/lod/lodApi/ClientApi.java @@ -0,0 +1,202 @@ +/* + * This file is part of the Distant Horizon mod (formerly the LOD Mod), + * licensed under the GNU GPL v3 License. + * + * Copyright (C) 2020 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.seibel.lod.lodApi; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.seibel.lod.builders.worldGeneration.LodGenWorker; +import com.seibel.lod.config.LodConfig; +import com.seibel.lod.objects.lod.LodDimension; +import com.seibel.lod.objects.rending.Mat4f; +import com.seibel.lod.proxy.GlProxy; +import com.seibel.lod.render.LodRenderer; +import com.seibel.lod.util.DetailDistanceUtil; +import com.seibel.lod.util.ThreadMapUtil; +import com.seibel.lod.wrappers.MinecraftWrapper; + +import net.minecraft.profiler.IProfiler; +import net.minecraft.util.text.StringTextComponent; + +/** + * This holds the methods that should be called + * by the host mod loader (Fabric, Forge, etc.). + * Specifically for the client. + * + * @author James Seibel + * @version 11-12-2021 + */ +public class ClientApi +{ + public static final ClientApi INSTANCE = new ClientApi(); + public static final Logger LOGGER = LogManager.getLogger("LOD"); + + public static LodRenderer renderer = new LodRenderer(ApiShared.lodBufferBuilder); + + + private final MinecraftWrapper mc = MinecraftWrapper.INSTANCE; + private final EventApi eventApi = EventApi.INSTANCE; + + /** + * there is some setup that should only happen once, + * once this is true that setup has completed + */ + private boolean firstTimeSetupComplete = false; + private boolean configOverrideReminderPrinted = false; + + + + private ClientApi() + { + + } + + + + + public void renderLods(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks) + { + // comment out when creating a release + // applyConfigOverrides(); + + // clear any out of date objects + mc.clearFrameObjectCache(); + + try + { + // only run the first time setup once + if (!firstTimeSetupComplete) + firstFrameSetup(); + + + if (mc.getPlayer() == null || ApiShared.lodWorld.getIsWorldNotLoaded()) + return; + + LodDimension lodDim = ApiShared.lodWorld.getLodDimension(mc.getCurrentDimension()); + if (lodDim == null) + return; + + DetailDistanceUtil.updateSettings(); + eventApi.viewDistanceChangedEvent(); + eventApi.playerMoveEvent(lodDim); + + lodDim.cutRegionNodesAsync((int) mc.getPlayer().getX(), (int) mc.getPlayer().getZ()); + lodDim.expandOrLoadRegionsAsync((int) mc.getPlayer().getX(), (int) mc.getPlayer().getZ()); + + + // Note to self: + // if "unspecified" shows up in the pie chart, it is + // possibly because the amount of time between sections + // is too small for the profiler to measure + IProfiler profiler = mc.getProfiler(); + profiler.pop(); // get out of "terrain" + profiler.push("LOD"); + + + ClientApi.renderer.drawLODs(lodDim, mcModelViewMatrix, mcProjectionMatrix, partialTicks, mc.getProfiler()); + + profiler.pop(); // end LOD + profiler.push("terrain"); // go back into "terrain" + + + // these can't be set until after the buffers are built (in renderer.drawLODs) + // otherwise the buffers may be set to the wrong size, or not changed at all + ApiShared.previousChunkRenderDistance = mc.getRenderDistance(); + ApiShared.previousLodRenderDistance = LodConfig.CLIENT.graphics.qualityOption.lodChunkRenderDistance.get(); + } + catch (Exception e) + { + ClientApi.LOGGER.error("client proxy: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** used in a development environment to change settings on the fly */ + private void applyConfigOverrides() + { + // remind the developer(s) that the config override is active + if (!configOverrideReminderPrinted) + { + // TODO add a send message method to the MC wrapper +// mc.getPlayer().sendMessage(new StringTextComponent("LOD experimental build 1.5.1"), mc.getPlayer().getUUID()); +// mc.getPlayer().sendMessage(new StringTextComponent("Here be dragons!"), mc.getPlayer().getUUID()); + + mc.getPlayer().sendMessage(new StringTextComponent("Debug settings enabled!"), mc.getPlayer().getUUID()); + configOverrideReminderPrinted = true; + } + +// LodConfig.CLIENT.graphics.drawResolution.set(HorizontalResolution.BLOCK); +// LodConfig.CLIENT.worldGenerator.generationResolution.set(HorizontalResolution.BLOCK); + // requires a world restart? +// LodConfig.CLIENT.worldGenerator.lodQualityMode.set(VerticalQuality.VOXEL); + +// LodConfig.CLIENT.graphics.fogQualityOption.fogDistance.set(FogDistance.FAR); +// LodConfig.CLIENT.graphics.fogQualityOption.fogDrawOverride.set(FogDrawOverride.FANCY); +// LodConfig.CLIENT.graphics.fogQualityOption.disableVanillaFog.set(true); +// LodConfig.CLIENT.graphics.shadingMode.set(ShadingMode.DARKEN_SIDES); + +// LodConfig.CLIENT.graphics.advancedGraphicsOption.vanillaOverdraw.set(VanillaOverdraw.DYNAMIC); + +// LodConfig.CLIENT.graphics.advancedGraphicsOption.gpuUploadMethod.set(GpuUploadMethod.BUFFER_STORAGE); + +// LodConfig.CLIENT.worldGenerator.distanceGenerationMode.set(DistanceGenerationMode.SURFACE); +// LodConfig.CLIENT.graphics.qualityOption.lodChunkRenderDistance.set(128); +// LodConfig.CLIENT.worldGenerator.lodDistanceCalculatorType.set(DistanceCalculatorType.LINEAR); +// LodConfig.CLIENT.worldGenerator.allowUnstableFeatureGeneration.set(false); + +// LodConfig.CLIENT.buffers.rebuildTimes.set(BufferRebuildTimes.FREQUENT); + + LodConfig.CLIENT.advancedModOptions.debugging.enableDebugKeybindings.set(true); +// LodConfig.CLIENT.debugging.debugMode.set(DebugMode.SHOW_DETAIL); + } + + + + + //=================// + // Lod maintenance // + //=================// + + /** This event is called once during the first frame Minecraft renders in the world. */ + public void firstFrameSetup() + { + // make sure the GlProxy is created before the LodBufferBuilder needs it + GlProxy.getInstance(); + + firstTimeSetupComplete = true; + } + + /** this method reset some static data every time we change world */ + private void resetMod() + { + // TODO when should this be used? + ThreadMapUtil.clearMaps(); + LodGenWorker.restartExecutorService(); + } + + + + + + + + + +} diff --git a/src/main/java/com/seibel/lod/lodApi/EventApi.java b/src/main/java/com/seibel/lod/lodApi/EventApi.java new file mode 100644 index 000000000..af821c0b8 --- /dev/null +++ b/src/main/java/com/seibel/lod/lodApi/EventApi.java @@ -0,0 +1,224 @@ +/* + * This file is part of the Distant Horizon mod (formerly the LOD Mod), + * licensed under the GNU GPL v3 License. + * + * Copyright (C) 2020 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.seibel.lod.lodApi; + +import org.lwjgl.glfw.GLFW; + +import com.seibel.lod.builders.worldGeneration.LodWorldGenerator; +import com.seibel.lod.config.LodConfig; +import com.seibel.lod.enums.config.DistanceGenerationMode; +import com.seibel.lod.objects.lod.LodDimension; +import com.seibel.lod.objects.lod.RegionPos; +import com.seibel.lod.render.LodRenderer; +import com.seibel.lod.util.DataPointUtil; +import com.seibel.lod.util.DetailDistanceUtil; +import com.seibel.lod.util.LodUtil; +import com.seibel.lod.util.ThreadMapUtil; +import com.seibel.lod.wrappers.MinecraftWrapper; +import com.seibel.lod.wrappers.Chunk.ChunkWrapper; +import com.seibel.lod.wrappers.World.DimensionTypeWrapper; +import com.seibel.lod.wrappers.World.WorldWrapper; + +/** + * This holds the methods that should be called + * by the host mod loader (Fabric, Forge, etc.). + * Specifically server and client events. + * + * @author James Seibel + * @version 11-12-2021 + */ +public class EventApi +{ + public static final EventApi INSTANCE = new EventApi(); + + private final MinecraftWrapper mc = MinecraftWrapper.INSTANCE; + + /** + * can be set if we want to recalculate variables related + * to the LOD view distance + */ + private boolean recalculateWidths = false; + + + private EventApi() + { + + } + + + + + //=============// + // tick events // + //=============// + + public void serverTickEvent() + { + if (mc.getPlayer() == null || ApiShared.lodWorld.getIsWorldNotLoaded()) + return; + + LodDimension lodDim = ApiShared.lodWorld.getLodDimension(DimensionTypeWrapper.getDimensionTypeWrapper(mc.getPlayer().level.dimensionType())); + if (lodDim == null) + return; + + LodWorldGenerator.INSTANCE.queueGenerationRequests(lodDim, ClientApi.renderer, ApiShared.lodBuilder); + } + + + + + //==============// + // world events // + //==============// + + public void chunkLoadEvent(ChunkWrapper chunk, DimensionTypeWrapper dimType) + { + ApiShared.lodBuilder.generateLodNodeAsync(chunk, ApiShared.lodWorld, dimType, DistanceGenerationMode.SERVER); + } + + public void worldSaveEvent() + { + ApiShared.lodWorld.saveAllDimensions(); + } + + /** This is also called when a new dimension loads */ + public void worldLoadEvent(WorldWrapper world) + { + DataPointUtil.worldHeight = world.getHeight(); + //LodNodeGenWorker.restartExecutorService(); + //ThreadMapUtil.clearMaps(); + + // the player just loaded a new world/dimension + ApiShared.lodWorld.selectWorld(LodUtil.getWorldID(world)); + + // make sure the correct LODs are being rendered + // (if this isn't done the previous world's LODs may be drawn) + ClientApi.renderer.regenerateLODsNextFrame(); + } + + public void worldUnloadEvent() + { + // the player just unloaded a world/dimension + ThreadMapUtil.clearMaps(); + + + if (mc.getConnection().getLevel() == null) + { + // the player just left the server + + // TODO should "resetMod()" be called here? -James + + // if this isn't done unfinished tasks may be left in the queue + // preventing new LodChunks form being generated + //LodNodeGenWorker.restartExecutorService(); // TODO why was this commented out? -James + //ThreadMapUtil.clearMaps(); + + LodWorldGenerator.INSTANCE.numberOfChunksWaitingToGenerate.set(0); + ApiShared.lodWorld.deselectWorld(); + + + // prevent issues related to the buffer builder + // breaking when changing worlds. + ClientApi.renderer.destroyBuffers(); + recalculateWidths = true; + ClientApi.renderer = new LodRenderer(ApiShared.lodBufferBuilder); + + + // make sure the nulled objects are freed. + // (this prevents an out of memory error when + // changing worlds) + System.gc(); + } + } + + public void blockChangeEvent(ChunkWrapper chunk, DimensionTypeWrapper dimType) + { + // recreate the LOD where the blocks were changed + ApiShared.lodBuilder.generateLodNodeAsync(chunk, ApiShared.lodWorld, dimType); + } + + + + + //=============// + // Misc Events // + //=============// + + public void onKeyInput(int key, int keyAction) + { + if (LodConfig.CLIENT.advancedModOptions.debugging.enableDebugKeybindings.get() + && key == GLFW.GLFW_KEY_F4 && keyAction == GLFW.GLFW_PRESS) + { + LodConfig.CLIENT.advancedModOptions.debugging.debugMode.set(LodConfig.CLIENT.advancedModOptions.debugging.debugMode.get().getNext()); + } + + if (LodConfig.CLIENT.advancedModOptions.debugging.enableDebugKeybindings.get() + && key == GLFW.GLFW_KEY_F6 && keyAction == GLFW.GLFW_PRESS) + { + LodConfig.CLIENT.advancedModOptions.debugging.drawLods.set(!LodConfig.CLIENT.advancedModOptions.debugging.drawLods.get()); + } + } + + /** Re-centers the given LodDimension if it needs to be. */ + public void playerMoveEvent(LodDimension lodDim) + { + // make sure the dimension is centered + RegionPos playerRegionPos = new RegionPos(mc.getPlayerBlockPos()); + RegionPos worldRegionOffset = new RegionPos(playerRegionPos.x - lodDim.getCenterRegionPosX(), playerRegionPos.z - lodDim.getCenterRegionPosZ()); + if (worldRegionOffset.x != 0 || worldRegionOffset.z != 0) + { + ApiShared.lodWorld.saveAllDimensions(); + lodDim.move(worldRegionOffset); + //LOGGER.info("offset: " + worldRegionOffset.x + "," + worldRegionOffset.z + "\t center: " + lodDim.getCenterX() + "," + lodDim.getCenterZ()); + } + } + + /** Re-sizes all LodDimensions if they need to be. */ + public void viewDistanceChangedEvent() + { + // calculate how wide the dimension(s) should be in regions + int chunksWide; + if (mc.getClientWorld().dimensionType().hasCeiling()) + chunksWide = Math.min(LodConfig.CLIENT.graphics.qualityOption.lodChunkRenderDistance.get(), LodUtil.CEILED_DIMENSION_MAX_RENDER_DISTANCE) * 2 + 1; + else + chunksWide = LodConfig.CLIENT.graphics.qualityOption.lodChunkRenderDistance.get() * 2 + 1; + + int newWidth = (int) Math.ceil(chunksWide / (float) LodUtil.REGION_WIDTH_IN_CHUNKS); + // make sure we have an odd number of regions + newWidth += (newWidth & 1) == 0 ? 1 : 2; + + // do the dimensions need to change in size? + if (ApiShared.lodBuilder.defaultDimensionWidthInRegions != newWidth || recalculateWidths) + { + ApiShared.lodWorld.saveAllDimensions(); + + // update the dimensions to fit the new width + ApiShared.lodWorld.resizeDimensionRegionWidth(newWidth); + ApiShared.lodBuilder.defaultDimensionWidthInRegions = newWidth; + ClientApi.renderer.setupBuffers(ApiShared.lodWorld.getLodDimension(DimensionTypeWrapper.getDimensionTypeWrapper(mc.getClientWorld().dimensionType()))); + + recalculateWidths = false; + //LOGGER.info("new dimension width in regions: " + newWidth + "\t potential: " + newWidth ); + } + DetailDistanceUtil.updateSettings(); + } + + +} diff --git a/src/main/java/com/seibel/lod/mixin/MixinWorldRenderer.java b/src/main/java/com/seibel/lod/mixin/MixinWorldRenderer.java index 2ce84ff89..6c3867fad 100644 --- a/src/main/java/com/seibel/lod/mixin/MixinWorldRenderer.java +++ b/src/main/java/com/seibel/lod/mixin/MixinWorldRenderer.java @@ -19,13 +19,14 @@ package com.seibel.lod.mixin; +import org.lwjgl.opengl.GL15; 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; import com.mojang.blaze3d.matrix.MatrixStack; -import com.seibel.lod.api.ClientApi; +import com.seibel.lod.lodApi.ClientApi; import com.seibel.lod.objects.rending.Mat4f; import com.seibel.lod.wrappers.McObjectConverter; @@ -62,8 +63,18 @@ public class MixinWorldRenderer // only render before solid blocks if (renderType.equals(RenderType.solid())) { + // get MC's current projection matrix + float[] mcProjMatrixRaw = new float[16]; + GL15.glGetFloatv(GL15.GL_PROJECTION_MATRIX, mcProjMatrixRaw); + Mat4f mcProjectionMatrix = new Mat4f(mcProjMatrixRaw); + // OpenGl outputs their matrices in col,row form instead of row,col + // (or maybe vice versa I have no idea :P) + mcProjectionMatrix.transpose(); + + Mat4f mcModelViewMatrix = McObjectConverter.Convert(matrixStackIn.last().pose()); - ClientApi.renderLods(mcModelViewMatrix, previousPartialTicks); + + ClientApi.INSTANCE.renderLods(mcModelViewMatrix, mcProjectionMatrix, previousPartialTicks); } } } diff --git a/src/main/java/com/seibel/lod/objects/PosToRenderContainer.java b/src/main/java/com/seibel/lod/objects/PosToRenderContainer.java index ce01fb601..606edc44d 100644 --- a/src/main/java/com/seibel/lod/objects/PosToRenderContainer.java +++ b/src/main/java/com/seibel/lod/objects/PosToRenderContainer.java @@ -21,7 +21,7 @@ package com.seibel.lod.objects; import java.util.Arrays; -import com.seibel.lod.proxy.ClientProxy; +import com.seibel.lod.lodApi.ClientApi; import com.seibel.lod.util.LevelPosUtil; import com.seibel.lod.util.LodUtil; @@ -60,7 +60,7 @@ public class PosToRenderContainer { // This is might be due to dimensions having a different width // when first loading in - ClientProxy.LOGGER.error("Unable to addPosToRender. numberOfPosToRender [" + numberOfPosToRender + "] detailLevel [" + detailLevel + "] Pos [" + posX + "," + posZ + "]"); + ClientApi.LOGGER.error("Unable to addPosToRender. numberOfPosToRender [" + numberOfPosToRender + "] detailLevel [" + detailLevel + "] Pos [" + posX + "," + posZ + "]"); numberOfPosToRender++; // incrementing so we can see how many pos over the limit we would go return; } diff --git a/src/main/java/com/seibel/lod/objects/lod/LodDimension.java b/src/main/java/com/seibel/lod/objects/lod/LodDimension.java index b160d909f..b7f11b708 100644 --- a/src/main/java/com/seibel/lod/objects/lod/LodDimension.java +++ b/src/main/java/com/seibel/lod/objects/lod/LodDimension.java @@ -25,9 +25,9 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import com.seibel.lod.config.LodConfig; -import com.seibel.lod.enums.DistanceGenerationMode; -import com.seibel.lod.enums.GenerationPriority; -import com.seibel.lod.enums.VerticalQuality; +import com.seibel.lod.enums.config.DistanceGenerationMode; +import com.seibel.lod.enums.config.GenerationPriority; +import com.seibel.lod.enums.config.VerticalQuality; import com.seibel.lod.handlers.LodDimensionFileHandler; import com.seibel.lod.objects.PosToGenerateContainer; import com.seibel.lod.objects.PosToRenderContainer; @@ -37,11 +37,10 @@ import com.seibel.lod.util.LevelPosUtil; import com.seibel.lod.util.LodThreadFactory; import com.seibel.lod.util.LodUtil; import com.seibel.lod.wrappers.MinecraftWrapper; +import com.seibel.lod.wrappers.World.DimensionTypeWrapper; +import com.seibel.lod.wrappers.World.WorldWrapper; import net.minecraft.util.math.ChunkPos; -import net.minecraft.world.DimensionType; -import net.minecraft.world.server.ServerChunkProvider; -import net.minecraft.world.server.ServerWorld; /** @@ -54,11 +53,11 @@ import net.minecraft.world.server.ServerWorld; * * @author Leonardo Amato * @author James Seibel - * @version 10-10-2021 + * @version 11-12-2021 */ public class LodDimension { - public final DimensionType dimension; + public final DimensionTypeWrapper dimension; /** measured in regions */ private volatile int width; @@ -97,7 +96,7 @@ public class LodDimension * Creates the dimension centered at (0,0) * @param newWidth in regions */ - public LodDimension(DimensionType newDimension, LodWorld lodWorld, int newWidth) + public LodDimension(DimensionTypeWrapper newDimension, LodWorld lodWorld, int newWidth) { lastCutChunk = null; lastExpandedChunk = null; @@ -110,17 +109,14 @@ public class LodDimension { try { + // determine the save folder File saveDir; if (mc.hasSinglePlayerServer()) { // local world - ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(newDimension); - - // provider needs a separate variable to prevent - // the compiler from complaining - ServerChunkProvider provider = serverWorld.getChunkSource(); - saveDir = new File(provider.dataStorage.dataFolder.getCanonicalFile().getPath() + File.separatorChar + "lod"); + WorldWrapper serverWorld = LodUtil.getServerWorldFromDimension(newDimension); + saveDir = new File(serverWorld.getSaveFolder().getCanonicalFile().getPath() + File.separatorChar + "lod"); } else { diff --git a/src/main/java/com/seibel/lod/objects/lod/LodRegion.java b/src/main/java/com/seibel/lod/objects/lod/LodRegion.java index aee58b7a0..4cffd60bd 100644 --- a/src/main/java/com/seibel/lod/objects/lod/LodRegion.java +++ b/src/main/java/com/seibel/lod/objects/lod/LodRegion.java @@ -19,8 +19,8 @@ package com.seibel.lod.objects.lod; -import com.seibel.lod.enums.DistanceGenerationMode; -import com.seibel.lod.enums.VerticalQuality; +import com.seibel.lod.enums.config.DistanceGenerationMode; +import com.seibel.lod.enums.config.VerticalQuality; import com.seibel.lod.objects.PosToGenerateContainer; import com.seibel.lod.objects.PosToRenderContainer; import com.seibel.lod.util.DataPointUtil; diff --git a/src/main/java/com/seibel/lod/objects/lod/LodWorld.java b/src/main/java/com/seibel/lod/objects/lod/LodWorld.java index b9e5f79d8..bbeab344e 100644 --- a/src/main/java/com/seibel/lod/objects/lod/LodWorld.java +++ b/src/main/java/com/seibel/lod/objects/lod/LodWorld.java @@ -22,10 +22,8 @@ package com.seibel.lod.objects.lod; import java.util.Hashtable; import java.util.Map; -import com.seibel.lod.proxy.ClientProxy; - +import com.seibel.lod.lodApi.ClientApi; import com.seibel.lod.wrappers.World.DimensionTypeWrapper; -import net.minecraft.world.DimensionType; /** * This stores all LODs for a given world. @@ -108,18 +106,18 @@ public class LodWorld if (lodDimensions == null) return; - lodDimensions.put(DimensionTypeWrapper.getDimensionTypeWrapper(newDimension.dimension), newDimension); + lodDimensions.put(newDimension.dimension, newDimension); } /** * Returns null if no LodDimension exists for the given dimension */ - public LodDimension getLodDimension(DimensionType dimension) + public LodDimension getLodDimension(DimensionTypeWrapper dimType) { if (lodDimensions == null) return null; - return lodDimensions.get(DimensionTypeWrapper.getDimensionTypeWrapper(dimension)); + return lodDimensions.get(dimType); } /** @@ -147,7 +145,7 @@ public class LodWorld // TODO we should only print this if lods were actually saved to file // but that requires a LodDimension.hasDirtyRegions() method or something similar - ClientProxy.LOGGER.info("Saving LODs"); + ClientApi.LOGGER.info("Saving LODs"); for (DimensionTypeWrapper key : lodDimensions.keySet()) lodDimensions.get(key).saveDirtyRegionsToFileAsync(); diff --git a/src/main/java/com/seibel/lod/objects/rending/Mat4f.java b/src/main/java/com/seibel/lod/objects/rending/Mat4f.java index 4a1a39594..da374d932 100644 --- a/src/main/java/com/seibel/lod/objects/rending/Mat4f.java +++ b/src/main/java/com/seibel/lod/objects/rending/Mat4f.java @@ -1,3 +1,22 @@ +/* + * This file is part of the Distant Horizon mod (formerly the LOD Mod), + * licensed under the GNU GPL v3 License. + * + * Copyright (C) 2020 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package com.seibel.lod.objects.rending; import java.nio.FloatBuffer; diff --git a/src/main/java/com/seibel/lod/objects/rending/NearFarFogSettings.java b/src/main/java/com/seibel/lod/objects/rending/NearFarFogSettings.java index 3acddc6ed..f73942635 100644 --- a/src/main/java/com/seibel/lod/objects/rending/NearFarFogSettings.java +++ b/src/main/java/com/seibel/lod/objects/rending/NearFarFogSettings.java @@ -19,8 +19,8 @@ package com.seibel.lod.objects.rending; -import com.seibel.lod.enums.FogDistance; -import com.seibel.lod.enums.FogQuality; +import com.seibel.lod.enums.rendering.FogDistance; +import com.seibel.lod.enums.rendering.FogQuality; /** * This object is just a replacement for an array diff --git a/src/main/java/com/seibel/lod/objects/rending/Vec3f.java b/src/main/java/com/seibel/lod/objects/rending/Vec3f.java index 98f14d461..9da51aa5d 100644 --- a/src/main/java/com/seibel/lod/objects/rending/Vec3f.java +++ b/src/main/java/com/seibel/lod/objects/rending/Vec3f.java @@ -1,3 +1,22 @@ +/* + * This file is part of the Distant Horizon mod (formerly the LOD Mod), + * licensed under the GNU GPL v3 License. + * + * Copyright (C) 2020 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package com.seibel.lod.objects.rending; import com.seibel.lod.util.LodUtil; diff --git a/src/main/java/com/seibel/lod/proxy/ClientProxy.java b/src/main/java/com/seibel/lod/proxy/ClientProxy.java index 0ffec18cf..ddb8a0bac 100644 --- a/src/main/java/com/seibel/lod/proxy/ClientProxy.java +++ b/src/main/java/com/seibel/lod/proxy/ClientProxy.java @@ -19,31 +19,11 @@ package com.seibel.lod.proxy; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.lwjgl.glfw.GLFW; -import org.lwjgl.opengl.GL15; - -import com.seibel.lod.builders.bufferBuilding.LodBufferBuilder; -import com.seibel.lod.builders.lodBuilding.LodBuilder; -import com.seibel.lod.builders.worldGeneration.LodGenWorker; -import com.seibel.lod.builders.worldGeneration.LodWorldGenerator; -import com.seibel.lod.config.LodConfig; -import com.seibel.lod.enums.DistanceGenerationMode; -import com.seibel.lod.objects.lod.LodDimension; -import com.seibel.lod.objects.lod.LodWorld; -import com.seibel.lod.objects.lod.RegionPos; -import com.seibel.lod.objects.rending.Mat4f; -import com.seibel.lod.render.LodRenderer; -import com.seibel.lod.util.DataPointUtil; -import com.seibel.lod.util.DetailDistanceUtil; -import com.seibel.lod.util.LodUtil; -import com.seibel.lod.util.ThreadMapUtil; -import com.seibel.lod.wrappers.MinecraftWrapper; +import com.seibel.lod.lodApi.EventApi; import com.seibel.lod.wrappers.Chunk.ChunkWrapper; +import com.seibel.lod.wrappers.World.DimensionTypeWrapper; +import com.seibel.lod.wrappers.World.WorldWrapper; -import net.minecraft.profiler.IProfiler; -import net.minecraft.util.text.StringTextComponent; import net.minecraftforge.client.event.InputEvent; import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.world.BlockEvent; @@ -54,359 +34,71 @@ import net.minecraftforge.eventbus.api.SubscribeEvent; /** * This handles all events sent to the client, * and is the starting point for most of the mod. + * * @author James_Seibel - * @version 11-8-2021 + * @version 11-12-2021 */ public class ClientProxy { - public static final Logger LOGGER = LogManager.getLogger("LOD"); - - /** - * there is some setup that should only happen once, - * once this is true that setup has completed - */ - private boolean firstTimeSetupComplete = false; - - private static final LodWorld lodWorld = new LodWorld(); - private static final LodBuilder lodBuilder = new LodBuilder(); - private static final LodBufferBuilder lodBufferBuilder = new LodBufferBuilder(); - private static LodRenderer renderer = new LodRenderer(lodBufferBuilder); - private static final LodWorldGenerator lodWorldGenerator = LodWorldGenerator.INSTANCE; - - private boolean configOverrideReminderPrinted = false; - - private final MinecraftWrapper mc = MinecraftWrapper.INSTANCE; + private final EventApi eventApi = EventApi.INSTANCE; - /** This is used to determine if the LODs should be regenerated */ - public static int previousChunkRenderDistance = 0; - /** This is used to determine if the LODs should be regenerated */ - public static int previousLodRenderDistance = 0; - - /** - * can be set if we want to recalculate variables related - * to the LOD view distance - */ - private boolean recalculateWidths = false; - - public ClientProxy() - { - - } - - - //==============// - // render event // - //==============// - - /** Do any setup that is required to draw LODs and then tell the LodRenderer to draw. */ - public void renderLods(Mat4f mcModelViewMatrix, float partialTicks) - { - // comment out when creating a release - // applyConfigOverrides(); - - // clear any out of date objects - mc.clearFrameObjectCache(); - - try - { - // only run the first time setup once - if (!firstTimeSetupComplete) - firstFrameSetup(); - - - if (mc.getPlayer() == null || lodWorld.getIsWorldNotLoaded()) - return; - - LodDimension lodDim = lodWorld.getLodDimension(mc.getCurrentDimension()); - if (lodDim == null) - return; - - DetailDistanceUtil.updateSettings(); - viewDistanceChangedEvent(); - playerMoveEvent(lodDim); - - lodDim.cutRegionNodesAsync((int) mc.getPlayer().getX(), (int) mc.getPlayer().getZ()); - lodDim.expandOrLoadRegionsAsync((int) mc.getPlayer().getX(), (int) mc.getPlayer().getZ()); - - - // get the default projection matrix, so we can - // reset it after drawing the LODs - float[] mcProjMatrixRaw = new float[16]; - GL15.glGetFloatv(GL15.GL_PROJECTION_MATRIX, mcProjMatrixRaw); - Mat4f mcProjectionMatrix = new Mat4f(mcProjMatrixRaw); - // OpenGl outputs their matrices in col,row form instead of row,col - // (or maybe vice versa I have no idea :P) - mcProjectionMatrix.transpose(); - - // Note to self: - // if "unspecified" shows up in the pie chart, it is - // possibly because the amount of time between sections - // is too small for the profiler to measure - IProfiler profiler = mc.getProfiler(); - profiler.pop(); // get out of "terrain" - profiler.push("LOD"); - - - renderer.drawLODs(lodDim, mcModelViewMatrix, mcProjectionMatrix, partialTicks, mc.getProfiler()); - - profiler.pop(); // end LOD - profiler.push("terrain"); // go back into "terrain" - - - // these can't be set until after the buffers are built (in renderer.drawLODs) - // otherwise the buffers may be set to the wrong size, or not changed at all - previousChunkRenderDistance = mc.getRenderDistance(); - previousLodRenderDistance = LodConfig.CLIENT.graphics.qualityOption.lodChunkRenderDistance.get(); - } - catch (Exception e) - { - LOGGER.error("client proxy: " + e.getMessage()); - e.printStackTrace(); - } - } - - /** used in a development environment to change settings on the fly */ - private void applyConfigOverrides() - { - // remind the developer(s) that the config override is active - if (!configOverrideReminderPrinted) - { - // TODO add a send message method to the MC wrapper -// mc.getPlayer().sendMessage(new StringTextComponent("LOD experimental build 1.5.1"), mc.getPlayer().getUUID()); -// mc.getPlayer().sendMessage(new StringTextComponent("Here be dragons!"), mc.getPlayer().getUUID()); - - mc.getPlayer().sendMessage(new StringTextComponent("Debug settings enabled!"), mc.getPlayer().getUUID()); - configOverrideReminderPrinted = true; - } - -// LodConfig.CLIENT.graphics.drawResolution.set(HorizontalResolution.BLOCK); -// LodConfig.CLIENT.worldGenerator.generationResolution.set(HorizontalResolution.BLOCK); - // requires a world restart? -// LodConfig.CLIENT.worldGenerator.lodQualityMode.set(VerticalQuality.VOXEL); - -// LodConfig.CLIENT.graphics.fogQualityOption.fogDistance.set(FogDistance.FAR); -// LodConfig.CLIENT.graphics.fogQualityOption.fogDrawOverride.set(FogDrawOverride.FANCY); -// LodConfig.CLIENT.graphics.fogQualityOption.disableVanillaFog.set(true); -// LodConfig.CLIENT.graphics.shadingMode.set(ShadingMode.DARKEN_SIDES); - -// LodConfig.CLIENT.graphics.advancedGraphicsOption.vanillaOverdraw.set(VanillaOverdraw.DYNAMIC); - -// LodConfig.CLIENT.graphics.advancedGraphicsOption.gpuUploadMethod.set(GpuUploadMethod.BUFFER_STORAGE); - -// LodConfig.CLIENT.worldGenerator.distanceGenerationMode.set(DistanceGenerationMode.SURFACE); -// LodConfig.CLIENT.graphics.qualityOption.lodChunkRenderDistance.set(128); -// LodConfig.CLIENT.worldGenerator.lodDistanceCalculatorType.set(DistanceCalculatorType.LINEAR); -// LodConfig.CLIENT.worldGenerator.allowUnstableFeatureGeneration.set(false); - -// LodConfig.CLIENT.buffers.rebuildTimes.set(BufferRebuildTimes.FREQUENT); - - LodConfig.CLIENT.advancedModOptions.debugging.enableDebugKeybindings.set(true); -// LodConfig.CLIENT.debugging.debugMode.set(DebugMode.SHOW_DETAIL); - } - - - //==============// - // forge events // - //==============// @SubscribeEvent public void serverTickEvent(TickEvent.ServerTickEvent event) { - if (mc.getPlayer() == null || lodWorld.getIsWorldNotLoaded()) - return; - - LodDimension lodDim = lodWorld.getLodDimension(mc.getPlayer().level.dimensionType()); - if (lodDim == null) - return; - - lodWorldGenerator.queueGenerationRequests(lodDim, renderer, lodBuilder); + eventApi.serverTickEvent(); } @SubscribeEvent public void chunkLoadEvent(ChunkEvent.Load event) { - lodBuilder.generateLodNodeAsync(new ChunkWrapper(event.getChunk()), lodWorld, event.getWorld(), DistanceGenerationMode.SERVER); + eventApi.chunkLoadEvent(new ChunkWrapper(event.getChunk()), DimensionTypeWrapper.getDimensionTypeWrapper(event.getWorld().dimensionType())); } @SubscribeEvent public void worldSaveEvent(WorldEvent.Save event) { - lodWorld.saveAllDimensions(); + eventApi.worldSaveEvent(); } /** This is also called when a new dimension loads */ @SubscribeEvent public void worldLoadEvent(WorldEvent.Load event) { - DataPointUtil.worldHeight = event.getWorld().getHeight(); - //LodNodeGenWorker.restartExecutorService(); - //ThreadMapUtil.clearMaps(); - - // the player just loaded a new world/dimension - lodWorld.selectWorld(LodUtil.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(); + eventApi.worldLoadEvent(WorldWrapper.getWorldWrapper(event.getWorld())); } @SubscribeEvent public void worldUnloadEvent(WorldEvent.Unload event) { - // the player just unloaded a world/dimension - ThreadMapUtil.clearMaps(); - - - if (mc.getConnection().getLevel() == null) - { - // the player just left the server - - // TODO should "resetMod()" be called here? -James - - // if this isn't done unfinished tasks may be left in the queue - // preventing new LodChunks form being generated - //LodNodeGenWorker.restartExecutorService(); // TODO why was this commented out? -James - //ThreadMapUtil.clearMaps(); - - LodWorldGenerator.INSTANCE.numberOfChunksWaitingToGenerate.set(0); - lodWorld.deselectWorld(); - - - // prevent issues related to the buffer builder - // breaking when changing worlds. - renderer.destroyBuffers(); - recalculateWidths = true; - renderer = new LodRenderer(lodBufferBuilder); - - - // make sure the nulled objects are freed. - // (this prevents an out of memory error when - // changing worlds) - System.gc(); - } + eventApi.worldUnloadEvent(); } @SubscribeEvent public void blockChangeEvent(BlockEvent event) { + // we only care about certain block events if (event.getClass() == BlockEvent.BreakEvent.class || event.getClass() == BlockEvent.EntityPlaceEvent.class || event.getClass() == BlockEvent.EntityMultiPlaceEvent.class || event.getClass() == BlockEvent.FluidPlaceBlockEvent.class || event.getClass() == BlockEvent.PortalSpawnEvent.class) { + ChunkWrapper chunk = new ChunkWrapper(event.getWorld().getChunk(event.getPos())); + DimensionTypeWrapper dimType = DimensionTypeWrapper.getDimensionTypeWrapper(event.getWorld().dimensionType()); + // recreate the LOD where the blocks were changed - lodBuilder.generateLodNodeAsync(new ChunkWrapper(event.getWorld().getChunk(event.getPos())), lodWorld, event.getWorld()); + eventApi.blockChangeEvent(chunk, dimType); } } @SubscribeEvent public void onKeyInput(InputEvent.KeyInputEvent event) { - if (LodConfig.CLIENT.advancedModOptions.debugging.enableDebugKeybindings.get() - && event.getKey() == GLFW.GLFW_KEY_F4 && event.getAction() == GLFW.GLFW_PRESS) - { - LodConfig.CLIENT.advancedModOptions.debugging.debugMode.set(LodConfig.CLIENT.advancedModOptions.debugging.debugMode.get().getNext()); - } - - if (LodConfig.CLIENT.advancedModOptions.debugging.enableDebugKeybindings.get() - && event.getKey() == GLFW.GLFW_KEY_F6 && event.getAction() == GLFW.GLFW_PRESS) - { - LodConfig.CLIENT.advancedModOptions.debugging.drawLods.set(!LodConfig.CLIENT.advancedModOptions.debugging.drawLods.get()); - } + eventApi.onKeyInput(event.getKey(), event.getAction()); } - - //============// - // LOD events // - //============// - - /** Re-centers the given LodDimension if it needs to be. */ - private void playerMoveEvent(LodDimension lodDim) - { - // make sure the dimension is centered - RegionPos playerRegionPos = new RegionPos(mc.getPlayerBlockPos()); - RegionPos worldRegionOffset = new RegionPos(playerRegionPos.x - lodDim.getCenterRegionPosX(), playerRegionPos.z - lodDim.getCenterRegionPosZ()); - if (worldRegionOffset.x != 0 || worldRegionOffset.z != 0) - { - lodWorld.saveAllDimensions(); - lodDim.move(worldRegionOffset); - //LOGGER.info("offset: " + worldRegionOffset.x + "," + worldRegionOffset.z + "\t center: " + lodDim.getCenterX() + "," + lodDim.getCenterZ()); - } - } - - - /** Re-sizes all LodDimensions if they need to be. */ - private void viewDistanceChangedEvent() - { - // calculate how wide the dimension(s) should be in regions - int chunksWide; - if (mc.getClientLevel().dimensionType().hasCeiling()) - chunksWide = Math.min(LodConfig.CLIENT.graphics.qualityOption.lodChunkRenderDistance.get(), LodUtil.CEILED_DIMENSION_MAX_RENDER_DISTANCE) * 2 + 1; - else - chunksWide = LodConfig.CLIENT.graphics.qualityOption.lodChunkRenderDistance.get() * 2 + 1; - - int newWidth = (int) Math.ceil(chunksWide / (float) LodUtil.REGION_WIDTH_IN_CHUNKS); - // make sure we have an odd number of regions - newWidth += (newWidth & 1) == 0 ? 1 : 2; - - // do the dimensions need to change in size? - if (lodBuilder.defaultDimensionWidthInRegions != newWidth || recalculateWidths) - { - lodWorld.saveAllDimensions(); - - // update the dimensions to fit the new width - lodWorld.resizeDimensionRegionWidth(newWidth); - lodBuilder.defaultDimensionWidthInRegions = newWidth; - renderer.setupBuffers(lodWorld.getLodDimension(mc.getClientLevel().dimensionType())); - - recalculateWidths = false; - //LOGGER.info("new dimension width in regions: " + newWidth + "\t potential: " + newWidth ); - } - DetailDistanceUtil.updateSettings(); - } - - - /** This event is called once during the first frame Minecraft renders in the world. */ - public void firstFrameSetup() - { - // make sure the GlProxy is created before the LodBufferBuilder needs it - GlProxy.getInstance(); - - firstTimeSetupComplete = true; - } - - /** this method reset some static data every time we change world */ - private void resetMod() - { - // TODO when should this be used? - ThreadMapUtil.clearMaps(); - LodGenWorker.restartExecutorService(); - - } - - - - - //================// - // public getters // - //================// - - public static LodWorld getLodWorld() - { - return lodWorld; - } - - public static LodBuilder getLodBuilder() - { - return lodBuilder; - } - - public static LodRenderer getRenderer() - { - return renderer; - } } diff --git a/src/main/java/com/seibel/lod/proxy/GlProxy.java b/src/main/java/com/seibel/lod/proxy/GlProxy.java index 90df6f79d..75a3824b9 100644 --- a/src/main/java/com/seibel/lod/proxy/GlProxy.java +++ b/src/main/java/com/seibel/lod/proxy/GlProxy.java @@ -28,7 +28,8 @@ import org.lwjgl.opengl.GLCapabilities; import com.mojang.blaze3d.systems.RenderSystem; import com.seibel.lod.ModInfo; -import com.seibel.lod.enums.GlProxyContext; +import com.seibel.lod.enums.rendering.GlProxyContext; +import com.seibel.lod.lodApi.ClientApi; import com.seibel.lod.render.shader.LodShader; import com.seibel.lod.render.shader.LodShaderProgram; import com.seibel.lod.wrappers.MinecraftWrapper; @@ -85,7 +86,7 @@ public class GlProxy private GlProxy() { - ClientProxy.LOGGER.error("Creating " + GlProxy.class.getSimpleName() + "... If this is the last message you see in the log there must have been a OpenGL error."); + ClientApi.LOGGER.error("Creating " + GlProxy.class.getSimpleName() + "... If this is the last message you see in the log there must have been a OpenGL error."); // getting Minecraft's context has to be done on the render thread, // where the GL context is @@ -128,7 +129,7 @@ public class GlProxy // get any GPU related capabilities // //==================================// - ClientProxy.LOGGER.info("Lod Render OpenGL version [" + GL11.glGetString(GL11.GL_VERSION) + "]."); + ClientApi.LOGGER.info("Lod Render OpenGL version [" + GL11.glGetString(GL11.GL_VERSION) + "]."); // crash the game if the GPU doesn't support OpenGL 2.0 if (!minecraftGlCapabilities.OpenGL20) @@ -152,11 +153,11 @@ public class GlProxy if (!bufferStorageSupported) { String fallBackVersion = mapBufferRangeSupported ? "3.0" : "1.5"; - ClientProxy.LOGGER.error("This GPU doesn't support Buffer Storage (OpenGL 4.5), falling back to OpenGL " + fallBackVersion + ". This may cause stuttering and reduced performance."); + ClientApi.LOGGER.error("This GPU doesn't support Buffer Storage (OpenGL 4.5), falling back to OpenGL " + fallBackVersion + ". This may cause stuttering and reduced performance."); } if (!fancyFogAvailable) - ClientProxy.LOGGER.info("This GPU does not support GL_NV_fog_distance. This means that the fancy fog option will not be available."); + ClientApi.LOGGER.info("This GPU does not support GL_NV_fog_distance. This means that the fancy fog option will not be available."); @@ -189,7 +190,7 @@ public class GlProxy // GlProxy creation success - ClientProxy.LOGGER.error(GlProxy.class.getSimpleName() + " creation successful. OpenGL smiles upon you this day."); + ClientApi.LOGGER.error(GlProxy.class.getSimpleName() + " creation successful. OpenGL smiles upon you this day."); } /** Creates all required shaders */ @@ -231,7 +232,7 @@ public class GlProxy } catch (Exception e) { - ClientProxy.LOGGER.error("Unable to compile shaders. Error: " + e.getMessage()); + ClientApi.LOGGER.error("Unable to compile shaders. Error: " + e.getMessage()); } } diff --git a/src/main/java/com/seibel/lod/render/LodRenderer.java b/src/main/java/com/seibel/lod/render/LodRenderer.java index 67c04255d..0a5bed061 100644 --- a/src/main/java/com/seibel/lod/render/LodRenderer.java +++ b/src/main/java/com/seibel/lod/render/LodRenderer.java @@ -29,17 +29,17 @@ import org.lwjgl.opengl.NVFogDistance; import com.seibel.lod.builders.bufferBuilding.LodBufferBuilder; import com.seibel.lod.builders.bufferBuilding.LodBufferBuilder.VertexBuffersAndOffset; import com.seibel.lod.config.LodConfig; -import com.seibel.lod.enums.DebugMode; -import com.seibel.lod.enums.FogDistance; -import com.seibel.lod.enums.FogDrawOverride; -import com.seibel.lod.enums.FogQuality; -import com.seibel.lod.enums.GpuUploadMethod; +import com.seibel.lod.enums.config.GpuUploadMethod; +import com.seibel.lod.enums.rendering.DebugMode; +import com.seibel.lod.enums.rendering.FogDistance; +import com.seibel.lod.enums.rendering.FogDrawOverride; +import com.seibel.lod.enums.rendering.FogQuality; import com.seibel.lod.handlers.ReflectionHandler; +import com.seibel.lod.lodApi.ApiShared; import com.seibel.lod.objects.lod.LodDimension; import com.seibel.lod.objects.lod.RegionPos; import com.seibel.lod.objects.rending.Mat4f; import com.seibel.lod.objects.rending.NearFarFogSettings; -import com.seibel.lod.proxy.ClientProxy; import com.seibel.lod.proxy.GlProxy; import com.seibel.lod.render.shader.LodShaderProgram; import com.seibel.lod.util.DetailDistanceUtil; @@ -251,7 +251,7 @@ public class LodRenderer Mat4f modelViewMatrix = offsetTheModelViewMatrix(mcModelViewMatrix, partialTicks); vanillaBlockRenderedDistance = mc.getRenderDistance() * LodUtil.CHUNK_WIDTH; // required for setupFog and setupProjectionMatrix - if (mc.getClientLevel().dimensionType().hasCeiling()) + if (mc.getClientWorld().dimensionType().hasCeiling()) farPlaneBlockDistance = Math.min(LodConfig.CLIENT.graphics.qualityOption.lodChunkRenderDistance.get(), LodUtil.CEILED_DIMENSION_MAX_RENDER_DISTANCE) * LodUtil.CHUNK_WIDTH; else farPlaneBlockDistance = LodConfig.CLIENT.graphics.qualityOption.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH; @@ -802,7 +802,7 @@ public class LodRenderer //=============// // check if the view distance changed - if (ClientProxy.previousLodRenderDistance != LodConfig.CLIENT.graphics.qualityOption.lodChunkRenderDistance.get() + if (ApiShared.previousLodRenderDistance != LodConfig.CLIENT.graphics.qualityOption.lodChunkRenderDistance.get() || chunkRenderDistance != prevRenderDistance || prevFogDistance != LodConfig.CLIENT.graphics.fogQualityOption.fogDistance.get()) { diff --git a/src/main/java/com/seibel/lod/render/shader/LodShader.java b/src/main/java/com/seibel/lod/render/shader/LodShader.java index d806b70ef..5191ae760 100644 --- a/src/main/java/com/seibel/lod/render/shader/LodShader.java +++ b/src/main/java/com/seibel/lod/render/shader/LodShader.java @@ -27,7 +27,7 @@ import java.io.InputStreamReader; import org.lwjgl.opengl.GL20; -import com.seibel.lod.proxy.ClientProxy; +import com.seibel.lod.lodApi.ClientApi; /** * This object holds a OpenGL reference to a shader @@ -76,7 +76,7 @@ public class LodShader } catch (IOException e) { - ClientProxy.LOGGER.error("Unable to load shader from file [" + path + "]. Error: " + e.getMessage()); + ClientApi.LOGGER.error("Unable to load shader from file [" + path + "]. Error: " + e.getMessage()); } CharSequence shaderFileSource = stringBuilder.toString(); diff --git a/src/main/java/com/seibel/lod/util/DataPointUtil.java b/src/main/java/com/seibel/lod/util/DataPointUtil.java index 5bc568e90..91abb8a7e 100644 --- a/src/main/java/com/seibel/lod/util/DataPointUtil.java +++ b/src/main/java/com/seibel/lod/util/DataPointUtil.java @@ -21,7 +21,7 @@ package com.seibel.lod.util; import static com.seibel.lod.builders.bufferBuilding.LodBufferBuilder.skyLightPlayer; -import com.seibel.lod.enums.DistanceGenerationMode; +import com.seibel.lod.enums.config.DistanceGenerationMode; /** * diff --git a/src/main/java/com/seibel/lod/util/DetailDistanceUtil.java b/src/main/java/com/seibel/lod/util/DetailDistanceUtil.java index 61f38942e..6908fd864 100644 --- a/src/main/java/com/seibel/lod/util/DetailDistanceUtil.java +++ b/src/main/java/com/seibel/lod/util/DetailDistanceUtil.java @@ -20,9 +20,9 @@ package com.seibel.lod.util; import com.seibel.lod.config.LodConfig; -import com.seibel.lod.enums.DistanceGenerationMode; -import com.seibel.lod.enums.HorizontalQuality; -import com.seibel.lod.enums.HorizontalResolution; +import com.seibel.lod.enums.config.DistanceGenerationMode; +import com.seibel.lod.enums.config.HorizontalQuality; +import com.seibel.lod.enums.config.HorizontalResolution; import com.seibel.lod.wrappers.MinecraftWrapper; /** diff --git a/src/main/java/com/seibel/lod/util/LodUtil.java b/src/main/java/com/seibel/lod/util/LodUtil.java index 931c3437a..871370c2e 100644 --- a/src/main/java/com/seibel/lod/util/LodUtil.java +++ b/src/main/java/com/seibel/lod/util/LodUtil.java @@ -25,13 +25,16 @@ import java.util.HashSet; import com.seibel.lod.builders.bufferBuilding.lodTemplates.Box; import com.seibel.lod.config.LodConfig; -import com.seibel.lod.enums.HorizontalResolution; -import com.seibel.lod.enums.VanillaOverdraw; +import com.seibel.lod.enums.config.HorizontalResolution; +import com.seibel.lod.enums.config.VanillaOverdraw; import com.seibel.lod.objects.lod.LodDimension; import com.seibel.lod.objects.lod.RegionPos; import com.seibel.lod.wrappers.MinecraftWrapper; import com.seibel.lod.wrappers.Block.BlockPosWrapper; import com.seibel.lod.wrappers.Chunk.ChunkPosWrapper; +import com.seibel.lod.wrappers.World.DimensionTypeWrapper; +import com.seibel.lod.wrappers.World.WorldWrapper; +import com.seibel.lod.wrappers.World.WorldWrapper; import net.minecraft.client.multiplayer.ServerData; import net.minecraft.client.renderer.WorldRenderer; @@ -42,12 +45,9 @@ import net.minecraft.server.integrated.IntegratedServer; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; 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.gen.Heightmap; -import net.minecraft.world.server.ServerChunkProvider; import net.minecraft.world.server.ServerWorld; /** @@ -179,18 +179,18 @@ public class LodUtil * Gets the ServerWorld for the relevant dimension. * @return null if there is no ServerWorld for the given dimension */ - public static ServerWorld getServerWorldFromDimension(DimensionType dimension) + public static WorldWrapper getServerWorldFromDimension(DimensionTypeWrapper newDimension) { IntegratedServer server = mc.getSinglePlayerServer(); if (server == null) return null; - Iterable worlds = server.getAllLevels(); - ServerWorld returnWorld = null; + Iterable worlds = mc.getAllServerWorlds(); + WorldWrapper returnWorld = null; - for (ServerWorld world : worlds) + for (WorldWrapper world : worlds) { - if (world.dimensionType() == dimension) + if (world.getDimensionType() == newDimension) { returnWorld = world; break; @@ -238,7 +238,7 @@ public class LodUtil * world, if in multiplayer it will return the server name, IP, * and game version. */ - public static String getWorldID(IWorld world) + public static String getWorldID(WorldWrapper world) { if (mc.hasSinglePlayerServer()) { @@ -266,26 +266,22 @@ public class LodUtil * This can be used to determine where to save files for a given * dimension. */ - public static String getDimensionIDFromWorld(IWorld world) + public static String getDimensionIDFromWorld(WorldWrapper world) { if (mc.hasSinglePlayerServer()) { // this will return the world save location // and the dimension folder - ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(world.dimensionType()); + WorldWrapper serverWorld = LodUtil.getServerWorldFromDimension(world.getDimensionType()); if (serverWorld == null) - throw new NullPointerException("getDimensionIDFromWorld wasn't able to get the ServerWorld for the dimension " + world.dimensionType().effectsLocation().getPath()); + throw new NullPointerException("getDimensionIDFromWorld wasn't able to get the WorldWrapper for the dimension " + world.getDimensionType().getDimensionName()); - ServerChunkProvider provider = serverWorld.getChunkSource(); - if (provider == null) - throw new NullPointerException("getDimensionIDFromWorld wasn't able to get the ServerChunkProvider for the dimension " + world.dimensionType().effectsLocation().getPath()); - - return provider.dataStorage.dataFolder.toString(); + return serverWorld.getSaveFolder().toString(); } else { - return getServerId() + File.separatorChar + "dim_" + world.dimensionType().effectsLocation().getPath() + File.separatorChar; + return getServerId() + File.separatorChar + "dim_" + world.getDimensionType().getDimensionName() + File.separatorChar; } } diff --git a/src/main/java/com/seibel/lod/wrappers/Block/BlockColorWrapper.java b/src/main/java/com/seibel/lod/wrappers/Block/BlockColorWrapper.java index a45a6da4e..f64e45a57 100644 --- a/src/main/java/com/seibel/lod/wrappers/Block/BlockColorWrapper.java +++ b/src/main/java/com/seibel/lod/wrappers/Block/BlockColorWrapper.java @@ -134,7 +134,7 @@ public class BlockColorWrapper else { isColored = true; - texture = mc.getModelManager().getBlockModelShaper().getTexture(block.defaultBlockState(), mc.getClientLevel(), blockPosWrapper.getBlockPos()); + texture = mc.getModelManager().getBlockModelShaper().getTexture(block.defaultBlockState(), mc.getClientWorld(), blockPosWrapper.getBlockPos()); } int count = 0; diff --git a/src/main/java/com/seibel/lod/wrappers/McObjectConverter.java b/src/main/java/com/seibel/lod/wrappers/McObjectConverter.java index e05a486f0..9336dd98d 100644 --- a/src/main/java/com/seibel/lod/wrappers/McObjectConverter.java +++ b/src/main/java/com/seibel/lod/wrappers/McObjectConverter.java @@ -1,3 +1,22 @@ +/* + * This file is part of the Distant Horizon mod (formerly the LOD Mod), + * licensed under the GNU GPL v3 License. + * + * Copyright (C) 2020 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package com.seibel.lod.wrappers; import java.nio.FloatBuffer; diff --git a/src/main/java/com/seibel/lod/wrappers/MinecraftWrapper.java b/src/main/java/com/seibel/lod/wrappers/MinecraftWrapper.java index 70bfb4d23..f7b9c94d7 100644 --- a/src/main/java/com/seibel/lod/wrappers/MinecraftWrapper.java +++ b/src/main/java/com/seibel/lod/wrappers/MinecraftWrapper.java @@ -21,14 +21,16 @@ package com.seibel.lod.wrappers; import java.awt.Color; import java.io.File; +import java.util.ArrayList; import com.seibel.lod.ModInfo; -import com.seibel.lod.proxy.ClientProxy; +import com.seibel.lod.lodApi.ClientApi; import com.seibel.lod.util.LodUtil; - import com.seibel.lod.wrappers.Block.BlockPosWrapper; import com.seibel.lod.wrappers.Chunk.ChunkPosWrapper; -import com.seibel.lod.wrappers.World.LevelWrapper; +import com.seibel.lod.wrappers.World.DimensionTypeWrapper; +import com.seibel.lod.wrappers.World.WorldWrapper; + import net.minecraft.client.GameSettings; import net.minecraft.client.MainWindow; import net.minecraft.client.Minecraft; @@ -109,14 +111,14 @@ public class MinecraftWrapper return mc.hasSingleplayerServer(); } - public DimensionType getCurrentDimension() + public DimensionTypeWrapper getCurrentDimension() { - return mc.player.level.dimensionType(); + return DimensionTypeWrapper.getDimensionTypeWrapper(mc.player.level.dimensionType()); } public String getCurrentDimensionId() { - return LodUtil.getDimensionIDFromWorld(mc.level); + return LodUtil.getDimensionIDFromWorld(WorldWrapper.getWorldWrapper(mc.level)); } /** @@ -178,12 +180,12 @@ public class MinecraftWrapper BlockPos playerPos = getPlayer().blockPosition(); return new BlockPosWrapper(playerPos.getX(), playerPos.getY(), playerPos.getZ()); } - + public ChunkPosWrapper getPlayerChunkPos() { return new ChunkPosWrapper(getPlayer().xChunk, getPlayer().zChunk); } - + public GameSettings getOptions() { return mc.options; @@ -194,39 +196,43 @@ public class MinecraftWrapper return mc.getModelManager(); } - public ClientWorld getClientLevel() + public ClientWorld getClientWorld() { return mc.level; } - public LevelWrapper getWrappedClientLevel() + /** + * Attempts to get the ServerWorld for the dimension + * the user is currently in. + * @returns null if no ServerWorld is available + */ + public WorldWrapper getWrappedServerWorld() { - return LevelWrapper.getLevelWrapper(mc.level); - } - - public LevelWrapper getWrappedServerLevel() - { - if (mc.level == null) return null; + DimensionType dimension = mc.level.dimensionType(); IntegratedServer server = mc.getSingleplayerServer(); + if (server == null) return null; + ServerWorld serverWorld = null; Iterable worlds = server.getAllLevels(); - ServerWorld returnWorld = null; - for (ServerWorld world : worlds) { if (world.dimensionType() == dimension) { - returnWorld = world; + serverWorld = world; break; } } - - return LevelWrapper.getLevelWrapper(returnWorld); + return WorldWrapper.getWorldWrapper(serverWorld); + } + + public WorldWrapper getWrappedClientWorld() + { + return WorldWrapper.getWorldWrapper(mc.level); } /** Measured in chunks */ @@ -285,19 +291,36 @@ public class MinecraftWrapper return mc.levelRenderer; } + /** Returns all worlds available to the server */ + public ArrayList getAllServerWorlds() + { + ArrayList worlds = new ArrayList(); + + Iterable serverWorlds = mc.getSingleplayerServer().getAllLevels(); + for (ServerWorld world : serverWorlds) + { + worlds.add(WorldWrapper.getWorldWrapper(world)); + } + + return worlds; + } + + /** * Crashes Minecraft, displaying the given errorMessage

* In the following format:
* * The game crashed whilst errorMessage
- * Error: java.lang.ExceptionClass: exceptionErrorMessage
+ * Error: ExceptionClass: exceptionErrorMessage
* Exit Code: -1
*/ public void crashMinecraft(String errorMessage, Throwable exception) { - ClientProxy.LOGGER.error(ModInfo.READABLE_NAME + " had the following error: [" + errorMessage + "]. Crashing Minecraft..."); + ClientApi.LOGGER.error(ModInfo.READABLE_NAME + " had the following error: [" + errorMessage + "]. Crashing Minecraft..."); CrashReport report = new CrashReport(errorMessage, exception); Minecraft.crash(report); } + + } diff --git a/src/main/java/com/seibel/lod/wrappers/World/BiomeColorWrapper.java b/src/main/java/com/seibel/lod/wrappers/World/BiomeColorWrapper.java index 15762db9c..98ce7f595 100644 --- a/src/main/java/com/seibel/lod/wrappers/World/BiomeColorWrapper.java +++ b/src/main/java/com/seibel/lod/wrappers/World/BiomeColorWrapper.java @@ -1,24 +1,49 @@ +/* + * This file is part of the Distant Horizon mod (formerly the LOD Mod), + * licensed under the GNU GPL v3 License. + * + * Copyright (C) 2020 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package com.seibel.lod.wrappers.World; import com.seibel.lod.wrappers.Block.BlockPosWrapper; + import net.minecraft.world.biome.BiomeColors; +/** + * + * @author Cola? + * @version 11-12-2021 + */ public class BiomeColorWrapper { - public static int getGrassColor(LevelWrapper levelWrapper, BlockPosWrapper blockPosWrapper) + public static int getGrassColor(WorldWrapper world, BlockPosWrapper blockPos) { - return BiomeColors.getAverageGrassColor(levelWrapper.getWorld(), blockPosWrapper.getBlockPos()); + return BiomeColors.getAverageGrassColor(world.getWorld(), blockPos.getBlockPos()); } - public static int getWaterColor(LevelWrapper levelWrapper, BlockPosWrapper blockPosWrapper) + public static int getWaterColor(WorldWrapper world, BlockPosWrapper blockPos) { - return BiomeColors.getAverageWaterColor(levelWrapper.getWorld(), blockPosWrapper.getBlockPos()); + return BiomeColors.getAverageWaterColor(world.getWorld(), blockPos.getBlockPos()); } - public static int getFoliageColor(LevelWrapper levelWrapper, BlockPosWrapper blockPosWrapper) + public static int getFoliageColor(WorldWrapper world, BlockPosWrapper blockPos) { - return BiomeColors.getAverageFoliageColor(levelWrapper.getWorld(), blockPosWrapper.getBlockPos()); + return BiomeColors.getAverageFoliageColor(world.getWorld(), blockPos.getBlockPos()); } } diff --git a/src/main/java/com/seibel/lod/wrappers/World/DimensionTypeWrapper.java b/src/main/java/com/seibel/lod/wrappers/World/DimensionTypeWrapper.java index 32ee894b1..c595ef60f 100644 --- a/src/main/java/com/seibel/lod/wrappers/World/DimensionTypeWrapper.java +++ b/src/main/java/com/seibel/lod/wrappers/World/DimensionTypeWrapper.java @@ -1,10 +1,10 @@ package com.seibel.lod.wrappers.World; -import net.minecraft.world.DimensionType; - import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import net.minecraft.world.DimensionType; + public class DimensionTypeWrapper { private static final ConcurrentMap dimensionTypeWrapperMap = new ConcurrentHashMap<>(); @@ -34,4 +34,19 @@ public class DimensionTypeWrapper { dimensionTypeWrapperMap.clear(); } + + public String getDimensionName() + { + return dimensionType.effectsLocation().getPath(); + } + + public boolean hasCeiling() + { + return dimensionType.hasCeiling(); + } + + public boolean hasSkyLight() + { + return dimensionType.hasSkyLight(); + } } diff --git a/src/main/java/com/seibel/lod/wrappers/World/LevelWrapper.java b/src/main/java/com/seibel/lod/wrappers/World/LevelWrapper.java deleted file mode 100644 index 17c35c352..000000000 --- a/src/main/java/com/seibel/lod/wrappers/World/LevelWrapper.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.seibel.lod.wrappers.World; - -import com.seibel.lod.wrappers.Block.BlockPosWrapper; -import net.minecraft.world.IWorld; -import net.minecraft.world.LightType; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -public class LevelWrapper -{ - private static final ConcurrentMap worldWrapperMap = new ConcurrentHashMap<>(); - private final IWorld world; - - public LevelWrapper(IWorld world) - { - this.world = world; - } - - - public static LevelWrapper getLevelWrapper(IWorld world) - { - //first we check if the biome has already been wrapped - if(worldWrapperMap.containsKey(world) && worldWrapperMap.get(world) != null) - return worldWrapperMap.get(world); - - - //if it hasn't been created yet, we create it and save it in the map - LevelWrapper levelWrapper = new LevelWrapper(world); - worldWrapperMap.put(world, levelWrapper); - - //we return the newly created wrapper - return levelWrapper; - } - - public static void clearMap() - { - worldWrapperMap.clear(); - } - - public DimensionTypeWrapper getDimensionType() - { - return DimensionTypeWrapper.getDimensionTypeWrapper(world.dimensionType()); - } - - public int getBlockLight(BlockPosWrapper blockPos) - { - return world.getBrightness(LightType.BLOCK, blockPos.getBlockPos()); - } - - public int getSkyLight(BlockPosWrapper blockPos) - { - return world.getBrightness(LightType.SKY, blockPos.getBlockPos()); - } - - public BiomeWrapper getBiome(BlockPosWrapper blockPos) - { - return BiomeWrapper.getBiomeWrapper(world.getBiome(blockPos.getBlockPos())); - } - - public IWorld getWorld() - { - return world; - } - - public boolean hasCeiling() - { - return world.dimensionType().hasCeiling(); - } - - public boolean hasSkyLight() - { - return world.dimensionType().hasSkyLight(); - } - - public boolean isEmpty() - { - return world == null; - } -} diff --git a/src/main/java/com/seibel/lod/wrappers/World/WorldWrapper.java b/src/main/java/com/seibel/lod/wrappers/World/WorldWrapper.java index c03f08344..4e9e8e6a5 100644 --- a/src/main/java/com/seibel/lod/wrappers/World/WorldWrapper.java +++ b/src/main/java/com/seibel/lod/wrappers/World/WorldWrapper.java @@ -1,22 +1,44 @@ package com.seibel.lod.wrappers.World; -import com.seibel.lod.wrappers.Block.BlockPosWrapper; -import net.minecraft.world.IWorld; - +import java.io.File; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import com.seibel.lod.enums.WorldType; +import com.seibel.lod.wrappers.Block.BlockPosWrapper; + +import net.minecraft.client.world.ClientWorld; +import net.minecraft.world.IWorld; +import net.minecraft.world.server.ServerChunkProvider; +import net.minecraft.world.server.ServerWorld; + +/** + * + * @author James Seibel + * @author ?? + * @version 11-12-2021 + */ public class WorldWrapper { private static final ConcurrentMap worldWrapperMap = new ConcurrentHashMap<>(); private final IWorld world; + public final WorldType worldType; - public WorldWrapper(IWorld world) + + public WorldWrapper(IWorld newWorld) { - this.world = world; + world = newWorld; + + if (world.getClass() == ServerWorld.class) + worldType = WorldType.ServerWorld; + else if (world.getClass() == ClientWorld.class) + worldType = WorldType.ClientWorld; + else + worldType = WorldType.Unknown; } + public static WorldWrapper getWorldWrapper(IWorld world) { //first we check if the biome has already been wrapped @@ -76,4 +98,31 @@ public class WorldWrapper { return world == null; } + + public int getHeight() + { + return world.getHeight(); + } + + /** @throws UnsupportedOperationException if the WorldWrapper isn't for a ServerWorld */ + public File getSaveFolder() throws UnsupportedOperationException + { + if (worldType != WorldType.ServerWorld) + throw new UnsupportedOperationException("getSaveFolder can only be called for ServerWorlds."); + + ServerChunkProvider chunkSource = ((ServerWorld) world).getChunkSource(); + return chunkSource.dataStorage.dataFolder; + } + + + /** @throws UnsupportedOperationException if the WorldWrapper isn't for a ServerWorld */ + public ServerWorld getServerWorld() throws UnsupportedOperationException + { + if (worldType != WorldType.ServerWorld) + throw new UnsupportedOperationException("getSaveFolder can only be called for ServerWorlds."); + + return (ServerWorld) world; + } + + }