Start creating API classes, some general refactoring/reorganizing, and wrapper changes

This commit is contained in:
James Seibel
2021-11-12 23:25:12 -06:00
parent 1ca7ac6671
commit 342261d78a
60 changed files with 972 additions and 727 deletions
@@ -33,8 +33,7 @@ import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
/**
* Initialize and setup the Mod.
* <br>
* Initialize and setup the Mod. <br>
* 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);
}
@@ -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);
}
}
@@ -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
@@ -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;
@@ -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));
}
/**
@@ -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;
@@ -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<Direction, long[]> 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!");
}
}
@@ -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<Direction, long[]> 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!");
}
}
@@ -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;
@@ -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.
@@ -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
@@ -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,
@@ -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;
@@ -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 <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.enums;
/**
* ServerWorld, ClientWorld, Unknown
*
* @author James Seibel
* @version 11-12-2021
*/
public enum WorldType
{
ServerWorld,
ClientWorld,
Unknown
}
@@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.enums;
package com.seibel.lod.enums.config;
/**
* heightmap <br>
@@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.enums;
package com.seibel.lod.enums.config;
/**
* Near_First <br>
@@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.enums;
package com.seibel.lod.enums.config;
/**
* NONE <br>
@@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.enums;
package com.seibel.lod.enums.config;
/**
* Near_First <br>
@@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.enums;
package com.seibel.lod.enums.config;
/**
* Buffer_Storage, Sub_Data, Buffer_Mapping
@@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.enums;
package com.seibel.lod.enums.config;
/**
* Lowest <br>
@@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.enums;
package com.seibel.lod.enums.config;
import java.util.ArrayList;
import java.util.Collections;
@@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.enums;
package com.seibel.lod.enums.config;
/**
* Low <br>
@@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
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;
@@ -1,4 +1,4 @@
package com.seibel.lod.enums;
package com.seibel.lod.enums.config;
/**
* NONE, GAME_SHADING
@@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.enums;
package com.seibel.lod.enums.config;
/**
* None, Dynamic, Always
@@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.enums;
package com.seibel.lod.enums.config;
/**
* heightmap <br>
@@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.enums;
package com.seibel.lod.enums.rendering;
/**
* off, detail, detail wireframe
@@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.enums;
package com.seibel.lod.enums.rendering;
/**
* NEAR, FAR, or NEAR_AND_FAR.
@@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.enums;
package com.seibel.lod.enums.rendering;
/**
* USE_OPTIFINE_FOG_SETTING, <br>
@@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.enums;
package com.seibel.lod.enums.rendering;
/**
* fast, fancy, or off
@@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.enums;
package com.seibel.lod.enums.rendering;
/**
* Minecraft, Lod_Builder, None
@@ -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 <https://www.gnu.org/licenses/>.
*/
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;
// }
// }
}
@@ -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 <https://www.gnu.org/licenses/>.
*/
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;
}
}
}
@@ -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;
}
@@ -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.");
}
@@ -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 <https://www.gnu.org/licenses/>.
*/
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()
{
}
}
@@ -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 <https://www.gnu.org/licenses/>.
*/
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();
}
}
@@ -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 <https://www.gnu.org/licenses/>.
*/
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();
}
}
@@ -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);
}
}
}
@@ -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;
}
@@ -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
{
@@ -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;
@@ -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();
@@ -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 <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.objects.rending;
import java.nio.FloatBuffer;
@@ -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
@@ -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 <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.objects.rending;
import com.seibel.lod.util.LodUtil;
@@ -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;
}
}
@@ -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());
}
}
@@ -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())
{
@@ -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();
@@ -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;
/**
*
@@ -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;
/**
+16 -20
View File
@@ -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<ServerWorld> worlds = server.getAllLevels();
ServerWorld returnWorld = null;
Iterable<WorldWrapper> 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;
}
}
@@ -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;
@@ -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 <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.wrappers;
import java.nio.FloatBuffer;
@@ -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<ServerWorld> 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<WorldWrapper> getAllServerWorlds()
{
ArrayList<WorldWrapper> worlds = new ArrayList<WorldWrapper>();
Iterable<ServerWorld> serverWorlds = mc.getSingleplayerServer().getAllLevels();
for (ServerWorld world : serverWorlds)
{
worlds.add(WorldWrapper.getWorldWrapper(world));
}
return worlds;
}
/**
* Crashes Minecraft, displaying the given errorMessage <br> <br>
* In the following format: <br>
*
* The game crashed whilst <strong>errorMessage</strong> <br>
* Error: <strong>java.lang.ExceptionClass: exceptionErrorMessage</strong> <br>
* Error: <strong>ExceptionClass: exceptionErrorMessage</strong> <br>
* Exit Code: -1 <br>
*/
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);
}
}
@@ -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 <https://www.gnu.org/licenses/>.
*/
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());
}
}
@@ -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<DimensionType, DimensionTypeWrapper> 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();
}
}
@@ -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<IWorld, LevelWrapper> 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;
}
}
@@ -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<IWorld, WorldWrapper> 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;
}
}