Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 26d4220967 | |||
| 5ca754d2ac | |||
| f13744e858 | |||
| 64ac218003 | |||
| 385bd326cf | |||
| 6ea864ef6b | |||
| 4e96728c25 | |||
| 1c44ef7f0c | |||
| 227d0d09ba | |||
| d7ba3fa724 | |||
| 7e46adf469 | |||
| f43e2fa441 | |||
| f9819d3d46 | |||
| 19b23bea5f | |||
| d1c0f7ebb4 | |||
| 5a4ddafbbb | |||
| 7c40d96f2e | |||
| b535be16c0 | |||
| 22f5608f9a | |||
| a498422843 | |||
| bfd6efb4a4 | |||
| c8c9df3a34 | |||
| 3349e5b898 | |||
| ed7511ff6a | |||
| 8516e8f9ab | |||
| 47a4d1535f | |||
| 33a55dc7cd | |||
| 1b4f9e8942 | |||
| 2537c4a259 | |||
| b74b6e8068 | |||
| 25979d6a76 | |||
| 3f287388d5 | |||
| 72d2ba6aae | |||
| 611ed4e24a | |||
| eac7a38e73 | |||
| afd7da7763 | |||
| ff7abb6a18 | |||
| ca3f5da5de | |||
| 69012ab7e6 | |||
| e5e502b4f8 | |||
| 42dc0903de | |||
| 4b20637e47 | |||
| 3257ae8480 | |||
| a6ddc561a0 | |||
| 7c82c9eb7b | |||
| 3c62e18502 | |||
| eea5198fb6 | |||
| 6bfcf36687 | |||
| 91dffa3c3e | |||
| e0c143881f |
+1
-1
@@ -10,7 +10,7 @@ insert_final_newline = false
|
|||||||
max_line_length = 1000
|
max_line_length = 1000
|
||||||
tab_width = 4
|
tab_width = 4
|
||||||
trim_trailing_whitespace = false
|
trim_trailing_whitespace = false
|
||||||
ij_continuation_indent_size = 8
|
ij_continuation_indent_size = 4
|
||||||
ij_formatter_off_tag = @formatter:off
|
ij_formatter_off_tag = @formatter:off
|
||||||
ij_formatter_on_tag = @formatter:on
|
ij_formatter_on_tag = @formatter:on
|
||||||
ij_formatter_tags_enabled = true
|
ij_formatter_tags_enabled = true
|
||||||
|
|||||||
+11
-1
@@ -63,7 +63,17 @@ public enum EDhApiDataCompressionMode
|
|||||||
* Write Speed: 15.13 MS / DTO <br>
|
* Write Speed: 15.13 MS / DTO <br>
|
||||||
* Compression ratio: 0.2606 <br>
|
* Compression ratio: 0.2606 <br>
|
||||||
*/
|
*/
|
||||||
Z_STD(2),
|
Z_STD(4),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to {@link EDhApiDataCompressionMode#Z_STD}
|
||||||
|
* except slower.
|
||||||
|
* <br>
|
||||||
|
* This option is only provided for legacy support when processing old databases.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
@DisallowSelectingViaConfigGui
|
||||||
|
Z_STD_STREAM(2),
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+1
-1
@@ -104,7 +104,7 @@ public interface IDhApiGraphicsConfig extends IDhApiConfigGroup
|
|||||||
* 2 = blending of 5x5 <br>
|
* 2 = blending of 5x5 <br>
|
||||||
* ... <br>
|
* ... <br>
|
||||||
*/
|
*/
|
||||||
// IDhApiConfigValue<Integer> getBiomeBlending();
|
IDhApiConfigValue<Integer> getBiomeBlending();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+1
@@ -41,6 +41,7 @@ public interface IDhApiEventInjector extends IDependencyInjector<IDhApiEvent>
|
|||||||
* @throws IllegalArgumentException if the implementation object doesn't implement the interface
|
* @throws IllegalArgumentException if the implementation object doesn't implement the interface
|
||||||
*/
|
*/
|
||||||
// Note to self: Don't try adding a generic type to IDhApiEvent, the constructor won't accept it
|
// Note to self: Don't try adding a generic type to IDhApiEvent, the constructor won't accept it
|
||||||
|
// TODO why are we removing the class instead of an instance?
|
||||||
boolean unbind(Class<? extends IDhApiEvent> dependencyInterface, Class<? extends IDhApiEvent> dependencyClassToRemove) throws IllegalArgumentException;
|
boolean unbind(Class<? extends IDhApiEvent> dependencyInterface, Class<? extends IDhApiEvent> dependencyClassToRemove) throws IllegalArgumentException;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -54,27 +54,12 @@ public class DhApiChunk
|
|||||||
// constructors //
|
// constructors //
|
||||||
//==============//
|
//==============//
|
||||||
|
|
||||||
/**
|
/** @since API 3.0.0 */
|
||||||
* Deprecated due to the topYBlockPos and bottomYBlockPos variables being put in the wrong order.
|
|
||||||
* They should have been in bottom -> top order.
|
|
||||||
*
|
|
||||||
* @see DhApiChunk#create(int, int, int, int)
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public DhApiChunk(int chunkPosX, int chunkPosZ, int topYBlockPos, int bottomYBlockPos)
|
|
||||||
{ this(chunkPosX, chunkPosZ, bottomYBlockPos, topYBlockPos, false); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @since API 3.0.0
|
|
||||||
*/
|
|
||||||
public static DhApiChunk create(int chunkPosX, int chunkPosZ, int bottomYBlockPos, int topYBlockPos)
|
public static DhApiChunk create(int chunkPosX, int chunkPosZ, int bottomYBlockPos, int topYBlockPos)
|
||||||
{ return new DhApiChunk(chunkPosX, chunkPosZ, bottomYBlockPos, topYBlockPos, false); }
|
{ return new DhApiChunk(chunkPosX, chunkPosZ, bottomYBlockPos, topYBlockPos); }
|
||||||
|
|
||||||
/**
|
/** Only visible to internal DH methods */
|
||||||
* Only visible to internal DH methods
|
private DhApiChunk(int chunkPosX, int chunkPosZ, int bottomYBlockPos, int topYBlockPos)
|
||||||
* @param ignoredParameter is only present to differentiate the two constructors and isn't actually used
|
|
||||||
*/
|
|
||||||
private DhApiChunk(int chunkPosX, int chunkPosZ, int bottomYBlockPos, int topYBlockPos, boolean ignoredParameter)
|
|
||||||
{
|
{
|
||||||
this.chunkPosX = chunkPosX;
|
this.chunkPosX = chunkPosX;
|
||||||
this.chunkPosZ = chunkPosZ;
|
this.chunkPosZ = chunkPosZ;
|
||||||
|
|||||||
+29
-31
@@ -29,7 +29,7 @@ import java.util.ArrayList;
|
|||||||
* Holds a single datapoint of terrain data.
|
* Holds a single datapoint of terrain data.
|
||||||
*
|
*
|
||||||
* @author James Seibel
|
* @author James Seibel
|
||||||
* @version 2024-7-20
|
* @version 2025-11-15
|
||||||
* @since API 1.0.0
|
* @since API 1.0.0
|
||||||
*/
|
*/
|
||||||
public class DhApiTerrainDataPoint
|
public class DhApiTerrainDataPoint
|
||||||
@@ -47,6 +47,10 @@ public class DhApiTerrainDataPoint
|
|||||||
|
|
||||||
public final int blockLightLevel;
|
public final int blockLightLevel;
|
||||||
public final int skyLightLevel;
|
public final int skyLightLevel;
|
||||||
|
/**
|
||||||
|
* An unsigned block position of the bottom vertex for this LOD relative to the level's minimum height.
|
||||||
|
* Should be greater than or equal to 0.
|
||||||
|
*/
|
||||||
public final int bottomYBlockPos;
|
public final int bottomYBlockPos;
|
||||||
public final int topYBlockPos;
|
public final int topYBlockPos;
|
||||||
|
|
||||||
@@ -59,28 +63,7 @@ public class DhApiTerrainDataPoint
|
|||||||
// constructors //
|
// constructors //
|
||||||
//==============//
|
//==============//
|
||||||
|
|
||||||
/**
|
/** @since API 3.0.0 */
|
||||||
* Deprecated due to the topYBlockPos and bottomYBlockPos variables being put in the wrong order.
|
|
||||||
* They should have been in bottom -> top order.
|
|
||||||
*
|
|
||||||
* @see DhApiTerrainDataPoint#create(byte, int, int, int, int, IDhApiBlockStateWrapper, IDhApiBiomeWrapper)
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public DhApiTerrainDataPoint(
|
|
||||||
byte detailLevel,
|
|
||||||
int blockLightLevel, int skyLightLevel,
|
|
||||||
int topYBlockPos, int bottomYBlockPos,
|
|
||||||
IDhApiBlockStateWrapper blockStateWrapper, IDhApiBiomeWrapper biomeWrapper)
|
|
||||||
{
|
|
||||||
this(detailLevel, blockLightLevel, skyLightLevel,
|
|
||||||
bottomYBlockPos, topYBlockPos,
|
|
||||||
blockStateWrapper, biomeWrapper,
|
|
||||||
false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @since API 3.0.0
|
|
||||||
*/
|
|
||||||
public static DhApiTerrainDataPoint create(
|
public static DhApiTerrainDataPoint create(
|
||||||
byte detailLevel,
|
byte detailLevel,
|
||||||
int blockLightLevel, int skyLightLevel,
|
int blockLightLevel, int skyLightLevel,
|
||||||
@@ -91,20 +74,15 @@ public class DhApiTerrainDataPoint
|
|||||||
return new DhApiTerrainDataPoint(
|
return new DhApiTerrainDataPoint(
|
||||||
detailLevel, blockLightLevel, skyLightLevel,
|
detailLevel, blockLightLevel, skyLightLevel,
|
||||||
bottomYBlockPos, topYBlockPos,
|
bottomYBlockPos, topYBlockPos,
|
||||||
blockStateWrapper, biomeWrapper,
|
blockStateWrapper, biomeWrapper);
|
||||||
false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Only visible to internal DH methods */
|
||||||
* Only visible to internal DH methods
|
|
||||||
* @param ignoredParameter is only present to differentiate the two constructors and isn't actually used
|
|
||||||
*/
|
|
||||||
private DhApiTerrainDataPoint(
|
private DhApiTerrainDataPoint(
|
||||||
byte detailLevel,
|
byte detailLevel,
|
||||||
int blockLightLevel, int skyLightLevel,
|
int blockLightLevel, int skyLightLevel,
|
||||||
int bottomYBlockPos, int topYBlockPos,
|
int bottomYBlockPos, int topYBlockPos,
|
||||||
IDhApiBlockStateWrapper blockStateWrapper, IDhApiBiomeWrapper biomeWrapper,
|
IDhApiBlockStateWrapper blockStateWrapper, IDhApiBiomeWrapper biomeWrapper
|
||||||
boolean ignoredParameter
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.detailLevel = detailLevel;
|
this.detailLevel = detailLevel;
|
||||||
@@ -118,4 +96,24 @@ public class DhApiTerrainDataPoint
|
|||||||
this.biomeWrapper = biomeWrapper;
|
this.biomeWrapper = biomeWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return "[Block:" + this.blockStateWrapper.getSerialString() +
|
||||||
|
",Biome:" + this.biomeWrapper.getName() +
|
||||||
|
",TopY:" + this.topYBlockPos +
|
||||||
|
",BottomY:" + this.bottomYBlockPos +
|
||||||
|
",BlockLight:" + this.blockLightLevel +
|
||||||
|
",SkyLight:" + this.skyLightLevel +
|
||||||
|
"]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public final class ModInfo
|
|||||||
public static final String DEDICATED_SERVER_INITIAL_PATH = "dedicated_server_initial";
|
public static final String DEDICATED_SERVER_INITIAL_PATH = "dedicated_server_initial";
|
||||||
|
|
||||||
/** Incremented every time any packets are added, changed or removed, with a few exceptions. */
|
/** Incremented every time any packets are added, changed or removed, with a few exceptions. */
|
||||||
public static final int PROTOCOL_VERSION = 12;
|
public static final int PROTOCOL_VERSION = 13;
|
||||||
public static final String WRAPPER_PACKET_PATH = "message";
|
public static final String WRAPPER_PACKET_PATH = "message";
|
||||||
|
|
||||||
/** The internal mod name */
|
/** The internal mod name */
|
||||||
|
|||||||
+3
-4
@@ -97,10 +97,9 @@ public class DhApiGraphicsConfig implements IDhApiGraphicsConfig
|
|||||||
public IDhApiConfigValue<Boolean> tintWithAvoidedBlocks()
|
public IDhApiConfigValue<Boolean> tintWithAvoidedBlocks()
|
||||||
{ return new DhApiConfigValue<Boolean, Boolean>(Config.Client.Advanced.Graphics.Quality.tintWithAvoidedBlocks); }
|
{ return new DhApiConfigValue<Boolean, Boolean>(Config.Client.Advanced.Graphics.Quality.tintWithAvoidedBlocks); }
|
||||||
|
|
||||||
// TODO re-implement
|
@Override
|
||||||
// @Override
|
public IDhApiConfigValue<Integer> getBiomeBlending()
|
||||||
// public IDhApiConfigValue<Integer> getBiomeBlending()
|
{ return new DhApiConfigValue<Integer, Integer>(Config.Client.Advanced.Graphics.Quality.lodBiomeBlending); }
|
||||||
// { return new DhApiConfigValue<Integer, Integer>(Quality.lodBiomeBlending); }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+18
-9
@@ -277,7 +277,7 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
|||||||
if (!getSpecificYCoordinate)
|
if (!getSpecificYCoordinate)
|
||||||
{
|
{
|
||||||
// if we aren't look for a specific datapoint, add each datapoint to the return array
|
// if we aren't look for a specific datapoint, add each datapoint to the return array
|
||||||
returnArray[i] = DhApiTerrainDataPointUtil.createApiDatapoint(levelWrapper, mapping, requestedDetailLevel, dataPoint);
|
returnArray[i] = DhApiTerrainDataPointUtil.createApiDatapoint(levelWrapper.getMinHeight(), mapping, requestedDetailLevel, dataPoint);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -294,7 +294,7 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
|||||||
if (bottomY <= requestedY && requestedY < topY) // blockPositions start from the bottom of the block, thus "<=" for bottomY, just "<" for topY
|
if (bottomY <= requestedY && requestedY < topY) // blockPositions start from the bottom of the block, thus "<=" for bottomY, just "<" for topY
|
||||||
{
|
{
|
||||||
// this datapoint contains the requested block position, return it
|
// this datapoint contains the requested block position, return it
|
||||||
DhApiTerrainDataPoint apiTerrainData = DhApiTerrainDataPointUtil.createApiDatapoint(levelWrapper, mapping, requestedDetailLevel, dataPoint);
|
DhApiTerrainDataPoint apiTerrainData = DhApiTerrainDataPointUtil.createApiDatapoint(levelWrapper.getMinHeight(), mapping, requestedDetailLevel, dataPoint);
|
||||||
return DhApiResult.createSuccess(new DhApiTerrainDataPoint[]{apiTerrainData});
|
return DhApiResult.createSuccess(new DhApiTerrainDataPoint[]{apiTerrainData});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -345,7 +345,10 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
|||||||
@Nullable
|
@Nullable
|
||||||
IDhApiTerrainDataCache dataCache)
|
IDhApiTerrainDataCache dataCache)
|
||||||
{
|
{
|
||||||
return this.raycastLodData(levelWrapper, new Vec3d(rayOriginX, rayOriginY, rayOriginZ), new Vec3f(rayDirectionX, rayDirectionY, rayDirectionZ), maxRayBlockLength, dataCache);
|
return this.raycastLodData(levelWrapper,
|
||||||
|
new Vec3d(rayOriginX, rayOriginY, rayOriginZ),
|
||||||
|
new Vec3f(rayDirectionX, rayDirectionY, rayDirectionZ),
|
||||||
|
maxRayBlockLength, dataCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -363,8 +366,8 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
|||||||
{
|
{
|
||||||
rayDirection.normalize();
|
rayDirection.normalize();
|
||||||
|
|
||||||
int minBlockHeight = levelWrapper.getMinHeight();
|
int minLevelBlockHeight = levelWrapper.getMinHeight();
|
||||||
int maxBlockHeight = levelWrapper.getMaxHeight();
|
int maxLevelBlockHeight = levelWrapper.getMaxHeight();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -380,7 +383,8 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
|||||||
DhApiRaycastResult closetFoundDataPoint = null;
|
DhApiRaycastResult closetFoundDataPoint = null;
|
||||||
|
|
||||||
|
|
||||||
while (blockPos.y >= minBlockHeight && blockPos.y < maxBlockHeight
|
while (blockPos.y >= minLevelBlockHeight
|
||||||
|
&& blockPos.y < maxLevelBlockHeight
|
||||||
&& currentLength <= maxRayBlockLength)
|
&& currentLength <= maxRayBlockLength)
|
||||||
{
|
{
|
||||||
// get the LOD columns around this position
|
// get the LOD columns around this position
|
||||||
@@ -403,7 +407,8 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
|||||||
{
|
{
|
||||||
// does this LOD contain the given Y position?
|
// does this LOD contain the given Y position?
|
||||||
Vec3i dataPointPos = new Vec3i(columnPos.x, dataPoint.bottomYBlockPos, columnPos.z);
|
Vec3i dataPointPos = new Vec3i(columnPos.x, dataPoint.bottomYBlockPos, columnPos.z);
|
||||||
if (exactPos.y >= dataPoint.bottomYBlockPos && exactPos.y <= dataPoint.topYBlockPos)
|
if (exactPos.y >= dataPoint.bottomYBlockPos
|
||||||
|
&& exactPos.y <= dataPoint.topYBlockPos)
|
||||||
{
|
{
|
||||||
if (closetFoundDataPoint == null)
|
if (closetFoundDataPoint == null)
|
||||||
{
|
{
|
||||||
@@ -572,12 +577,16 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// draw raycast position
|
// draw raycast position
|
||||||
if (rayCast.success && rayCast.payload != null)
|
if (rayCast.success
|
||||||
|
&& rayCast.payload != null)
|
||||||
{
|
{
|
||||||
DebugRenderer.makeParticle(
|
DebugRenderer.makeParticle(
|
||||||
new DebugRenderer.BoxParticle(
|
new DebugRenderer.BoxParticle(
|
||||||
new DebugRenderer.Box(
|
new DebugRenderer.Box(
|
||||||
DhSectionPos.encode((byte) 0, rayCast.payload.pos.x, rayCast.payload.pos.z), rayCast.payload.dataPoint.bottomYBlockPos, rayCast.payload.dataPoint.topYBlockPos, -0.1f, Color.RED),
|
DhSectionPos.encode((byte) 0, rayCast.payload.pos.x, rayCast.payload.pos.z),
|
||||||
|
rayCast.payload.dataPoint.bottomYBlockPos,
|
||||||
|
rayCast.payload.dataPoint.topYBlockPos,
|
||||||
|
-0.1f, Color.RED),
|
||||||
1.0, 0f
|
1.0, 0f
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import com.seibel.distanthorizons.api.DhApi;
|
|||||||
import com.seibel.distanthorizons.api.enums.config.EDhApiMcRenderingFadeMode;
|
import com.seibel.distanthorizons.api.enums.config.EDhApiMcRenderingFadeMode;
|
||||||
import com.seibel.distanthorizons.api.enums.rendering.EDhApiRenderPass;
|
import com.seibel.distanthorizons.api.enums.rendering.EDhApiRenderPass;
|
||||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.*;
|
import com.seibel.distanthorizons.api.methods.events.abstractEvents.*;
|
||||||
|
import com.seibel.distanthorizons.core.api.external.methods.data.DhApiTerrainDataRepo;
|
||||||
import com.seibel.distanthorizons.core.api.internal.rendering.DhRenderState;
|
import com.seibel.distanthorizons.core.api.internal.rendering.DhRenderState;
|
||||||
import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure;
|
import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
@@ -338,12 +339,6 @@ public class ClientApi
|
|||||||
if (clientWorld != null)
|
if (clientWorld != null)
|
||||||
{
|
{
|
||||||
clientWorld.clientTick();
|
clientWorld.clientTick();
|
||||||
|
|
||||||
// Ignore local world gen, as it's managed by server ticking
|
|
||||||
if (!(clientWorld instanceof DhClientServerWorld))
|
|
||||||
{
|
|
||||||
SharedApi.worldGenTick(clientWorld::worldGenTick);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -570,8 +565,13 @@ public class ClientApi
|
|||||||
{
|
{
|
||||||
// only fade when DH is rendering
|
// only fade when DH is rendering
|
||||||
if (Config.Client.Advanced.Debugging.rendererMode.get() == EDhApiRendererMode.DEFAULT
|
if (Config.Client.Advanced.Debugging.rendererMode.get() == EDhApiRendererMode.DEFAULT
|
||||||
// only fade when requested
|
&&
|
||||||
&& Config.Client.Advanced.Graphics.Quality.vanillaFadeMode.get() == EDhApiMcRenderingFadeMode.DOUBLE_PASS
|
(
|
||||||
|
// only fade when requested
|
||||||
|
Config.Client.Advanced.Graphics.Quality.vanillaFadeMode.get() == EDhApiMcRenderingFadeMode.DOUBLE_PASS
|
||||||
|
// or if LOD-only mode is enabled (fading is used to remove the MC render pass)
|
||||||
|
|| Config.Client.Advanced.Debugging.lodOnlyMode.get()
|
||||||
|
)
|
||||||
// don't fade when Iris shaders are active, otherwise the rendering can get weird
|
// don't fade when Iris shaders are active, otherwise the rendering can get weird
|
||||||
&& !DhApiRenderProxy.INSTANCE.getDeferTransparentRendering())
|
&& !DhApiRenderProxy.INSTANCE.getDeferTransparentRendering())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -53,30 +53,6 @@ public class ServerApi
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=============//
|
|
||||||
// tick events //
|
|
||||||
//=============//
|
|
||||||
|
|
||||||
public void serverTickEvent()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
IDhServerWorld serverWorld = SharedApi.tryGetDhServerWorld();
|
|
||||||
if (serverWorld != null)
|
|
||||||
{
|
|
||||||
serverWorld.serverTick();
|
|
||||||
SharedApi.worldGenTick(serverWorld::worldGenTick);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
// try catch is necessary to prevent crashing the internal server when an exception is thrown
|
|
||||||
LOGGER.error("ServerTickEvent error: " + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===============//
|
//===============//
|
||||||
// server events //
|
// server events //
|
||||||
//===============//
|
//===============//
|
||||||
|
|||||||
@@ -141,16 +141,6 @@ public class SharedApi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void worldGenTick(Runnable worldGenRunnable)
|
|
||||||
{
|
|
||||||
lastWorldGenTickDelta--;
|
|
||||||
if (lastWorldGenTickDelta <= 0)
|
|
||||||
{
|
|
||||||
worldGenRunnable.run();
|
|
||||||
lastWorldGenTickDelta = 20;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static AbstractDhWorld getAbstractDhWorld() { return currentWorld; }
|
public static AbstractDhWorld getAbstractDhWorld() { return currentWorld; }
|
||||||
|
|
||||||
|
|||||||
+21
-1
@@ -8,6 +8,10 @@ import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
|||||||
import com.seibel.distanthorizons.core.world.EWorldEnvironment;
|
import com.seibel.distanthorizons.core.world.EWorldEnvironment;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class ChunkUpdateQueueManager
|
public class ChunkUpdateQueueManager
|
||||||
{
|
{
|
||||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
@@ -15,6 +19,7 @@ public class ChunkUpdateQueueManager
|
|||||||
|
|
||||||
public final ChunkPosQueue updateQueue;
|
public final ChunkPosQueue updateQueue;
|
||||||
public final ChunkPosQueue preUpdateQueue;
|
public final ChunkPosQueue preUpdateQueue;
|
||||||
|
public final Set<DhChunkPos> ignoredChunkPosSet = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||||
|
|
||||||
public int maxSize = 500;
|
public int maxSize = 500;
|
||||||
|
|
||||||
@@ -38,12 +43,18 @@ public class ChunkUpdateQueueManager
|
|||||||
// list/set methods //
|
// list/set methods //
|
||||||
//==================//
|
//==================//
|
||||||
|
|
||||||
public boolean contains(DhChunkPos pos) { return this.updateQueue.contains(pos) || this.preUpdateQueue.contains(pos); }
|
public boolean contains(DhChunkPos pos)
|
||||||
|
{
|
||||||
|
return this.updateQueue.contains(pos)
|
||||||
|
|| this.ignoredChunkPosSet.contains(pos)
|
||||||
|
|| this.preUpdateQueue.contains(pos);
|
||||||
|
}
|
||||||
|
|
||||||
public void clear()
|
public void clear()
|
||||||
{
|
{
|
||||||
this.updateQueue.clear();
|
this.updateQueue.clear();
|
||||||
this.preUpdateQueue.clear();
|
this.preUpdateQueue.clear();
|
||||||
|
this.ignoredChunkPosSet.clear();
|
||||||
}
|
}
|
||||||
public int getQueuedCount() { return this.updateQueue.getQueuedCount() + this.preUpdateQueue.getQueuedCount(); }
|
public int getQueuedCount() { return this.updateQueue.getQueuedCount() + this.preUpdateQueue.getQueuedCount(); }
|
||||||
public boolean isEmpty()
|
public boolean isEmpty()
|
||||||
@@ -131,6 +142,15 @@ public class ChunkUpdateQueueManager
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// ignores //
|
||||||
|
//=========//
|
||||||
|
|
||||||
|
public void addPosToIgnore(DhChunkPos chunkPos) { this.ignoredChunkPosSet.add(chunkPos); }
|
||||||
|
public void removePosToIgnore(DhChunkPos chunkPos) { this.ignoredChunkPosSet.remove(chunkPos); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==================//
|
//==================//
|
||||||
// position methods //
|
// position methods //
|
||||||
//==================//
|
//==================//
|
||||||
|
|||||||
@@ -103,10 +103,7 @@ public class Config
|
|||||||
|
|
||||||
public static ConfigUiLinkedEntry quickEnableWorldGenerator = new ConfigUiLinkedEntry(Common.WorldGenerator.enableDistantGeneration);
|
public static ConfigUiLinkedEntry quickEnableWorldGenerator = new ConfigUiLinkedEntry(Common.WorldGenerator.enableDistantGeneration);
|
||||||
|
|
||||||
public static ConfigEntry<Boolean> quickShowWorldGenProgress = new ConfigEntry.Builder<Boolean>()
|
public static ConfigUiLinkedEntry quickShowWorldGenProgress = new ConfigUiLinkedEntry(Common.WorldGenerator.showGenerationProgress);
|
||||||
.set(false) // TODO should be set by the underlying world gen progress button, not a static default
|
|
||||||
.setAppearance(EConfigEntryAppearance.ONLY_IN_GUI)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
public static ConfigUiLinkedEntry quickLodCloudRendering = new ConfigUiLinkedEntry(Advanced.Graphics.GenericRendering.enableCloudRendering);
|
public static ConfigUiLinkedEntry quickLodCloudRendering = new ConfigUiLinkedEntry(Advanced.Graphics.GenericRendering.enableCloudRendering);
|
||||||
|
|
||||||
@@ -1391,36 +1388,8 @@ public class Config
|
|||||||
|
|
||||||
public static ConfigEntry<EDhApiDataCompressionMode> dataCompression = new ConfigEntry.Builder<EDhApiDataCompressionMode>()
|
public static ConfigEntry<EDhApiDataCompressionMode> dataCompression = new ConfigEntry.Builder<EDhApiDataCompressionMode>()
|
||||||
.set(EDhApiDataCompressionMode.Z_STD)
|
.set(EDhApiDataCompressionMode.Z_STD)
|
||||||
.comment(""
|
// only visible via the API since there is no reason to use any compressor except ZStandard as of 2025-11-24
|
||||||
+ "What algorithm should be used to compress new LOD data? \n"
|
.setAppearance(EConfigEntryAppearance.ONLY_IN_API)
|
||||||
+ "This setting will only affect new or updated LOD data, \n"
|
|
||||||
+ "any data already generated when this setting is changed will be\n"
|
|
||||||
+ "unaffected until it needs to be re-written to the database.\n"
|
|
||||||
+ "\n"
|
|
||||||
+ EDhApiDataCompressionMode.UNCOMPRESSED + " \n"
|
|
||||||
+ "Should only be used for testing, is worse in every way vs ["+EDhApiDataCompressionMode.LZ4+"].\n"
|
|
||||||
+ "Expected Compression Ratio: 1.0\n"
|
|
||||||
+ "Estimated average DTO read speed: 6.09 milliseconds\n"
|
|
||||||
+ "Estimated average DTO write speed: 6.01 milliseconds\n"
|
|
||||||
+ "\n"
|
|
||||||
+ EDhApiDataCompressionMode.LZ4 + " \n"
|
|
||||||
+ "A good option if you're CPU limited and have plenty of hard drive space.\n"
|
|
||||||
+ "Expected Compression Ratio: 0.4513\n"
|
|
||||||
+ "Estimated average DTO read speed: 3.25 ms\n"
|
|
||||||
+ "Estimated average DTO write speed: 5.99 ms\n"
|
|
||||||
+ "\n"
|
|
||||||
+ EDhApiDataCompressionMode.Z_STD + " \n"
|
|
||||||
+ "A good option if you're CPU limited and have plenty of hard drive space.\n"
|
|
||||||
+ "Expected Compression Ratio: 0.2606\n"
|
|
||||||
+ "Estimated average DTO read speed: 9.31 ms\n"
|
|
||||||
+ "Estimated average DTO write speed: 15.13 ms\n"
|
|
||||||
+ "\n"
|
|
||||||
+ EDhApiDataCompressionMode.LZMA2 + " \n"
|
|
||||||
+ "Slow but very good compression.\n"
|
|
||||||
+ "Expected Compression Ratio: 0.2\n"
|
|
||||||
+ "Estimated average DTO read speed: 13.29 ms\n"
|
|
||||||
+ "Estimated average DTO write speed: 70.95 ms\n"
|
|
||||||
+ "")
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
public static ConfigEntry<EDhApiWorldCompressionMode> worldCompression = new ConfigEntry.Builder<EDhApiWorldCompressionMode>()
|
public static ConfigEntry<EDhApiWorldCompressionMode> worldCompression = new ConfigEntry.Builder<EDhApiWorldCompressionMode>()
|
||||||
@@ -1443,49 +1412,6 @@ public class Config
|
|||||||
+ "")
|
+ "")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
public static ConfigEntry<Boolean> recalculateChunkHeightmaps = new ConfigEntry.Builder<Boolean>()
|
|
||||||
.set(false)
|
|
||||||
.comment(""
|
|
||||||
+ "True: Recalculate chunk height maps before chunks can be used by DH.\n"
|
|
||||||
+ " This can fix problems with worlds created by World Painter or \n"
|
|
||||||
+ " other external tools where the heightmap format may be incorrect. \n"
|
|
||||||
+ "False: Assume any height maps handled by Minecraft are correct. \n"
|
|
||||||
+ "\n"
|
|
||||||
+ "Fastest: False\n"
|
|
||||||
+ "Most Compatible: True\n"
|
|
||||||
+ "")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
public static ConfigEntry<Boolean> pullLightingForPregeneratedChunks = new ConfigEntry.Builder<Boolean>()
|
|
||||||
.set(false)
|
|
||||||
.comment(""
|
|
||||||
+ "If true LOD generation for pre-existing chunks will attempt to pull the lighting data \n"
|
|
||||||
+ "saved in Minecraft's Region files. \n"
|
|
||||||
+ "If false DH will pull in chunks without lighting and re-light them. \n"
|
|
||||||
+ " \n"
|
|
||||||
+ "Setting this to true will result in faster LOD generation \n"
|
|
||||||
+ "for already generated worlds, but is broken by most lighting mods. \n"
|
|
||||||
+ " \n"
|
|
||||||
+ "Set this to false if LODs are black. \n"
|
|
||||||
+ "")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
public static ConfigEntry<Boolean> assumePreExistingChunksAreFinished = new ConfigEntry.Builder<Boolean>()
|
|
||||||
.set(false)
|
|
||||||
.comment(""
|
|
||||||
+ "When DH pulls in pre-existing chunks it will attempt to \n"
|
|
||||||
+ "run any missing world generation steps; for example: \n"
|
|
||||||
+ "if a chunk has the status SURFACE, DH will skip BIOMES \n"
|
|
||||||
+ "and SURFACE, but will run FEATURES. \n"
|
|
||||||
+ " \n"
|
|
||||||
+ "However if for some reason the chunks are malformed \n"
|
|
||||||
+ "or there's some other issue that causes the status \n"
|
|
||||||
+ "to be incorrect that can either cause world gen \n"
|
|
||||||
+ "lock-ups and/or crashes. \n"
|
|
||||||
+ "If either of those happen try setting this to True. \n"
|
|
||||||
+ "")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
public static ConfigCategory experimental = new ConfigCategory.Builder().set(Experimental.class).build();
|
public static ConfigCategory experimental = new ConfigCategory.Builder().set(Experimental.class).build();
|
||||||
|
|
||||||
|
|
||||||
@@ -1527,6 +1453,7 @@ public class Config
|
|||||||
+ "How many threads should be used by Distant Horizons? \n"
|
+ "How many threads should be used by Distant Horizons? \n"
|
||||||
+ "")
|
+ "")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
public static final ConfigEntry<Double> threadRunTimeRatio = new ConfigEntry.Builder<Double>()
|
public static final ConfigEntry<Double> threadRunTimeRatio = new ConfigEntry.Builder<Double>()
|
||||||
.setChatCommandName("threading.threadRunTimeRatio")
|
.setChatCommandName("threading.threadRunTimeRatio")
|
||||||
.setMinDefaultMax(0.01, ThreadPresetConfigEventHandler.getDefaultRunTimeRatio(), 1.0)
|
.setMinDefaultMax(0.01, ThreadPresetConfigEventHandler.getDefaultRunTimeRatio(), 1.0)
|
||||||
@@ -1540,6 +1467,19 @@ public class Config
|
|||||||
"")
|
"")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
public static final ConfigEntry<Integer> threadPriority = new ConfigEntry.Builder<Integer>()
|
||||||
|
.setAppearance(EConfigEntryAppearance.ONLY_IN_FILE) // only in file since this requires a MC reboot to change
|
||||||
|
.setMinDefaultMax(Thread.MIN_PRIORITY, // 1
|
||||||
|
Thread.NORM_PRIORITY, // 5 (1 higher than C2ME's default priority of 4 which can help reduce issues with Chunky)
|
||||||
|
Thread.MAX_PRIORITY) // 10
|
||||||
|
.comment(""
|
||||||
|
+ "What Java thread priority should DH's primary thread pools run with? \n"
|
||||||
|
+ "\n"
|
||||||
|
+ "You probably don't need to change this unless you are also \n"
|
||||||
|
+ "running C2ME and are seeing thread starvation in either C2ME or DH. \n"
|
||||||
|
+ "")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1576,14 +1516,6 @@ public class Config
|
|||||||
+ "This can be useful for debugging.")
|
+ "This can be useful for debugging.")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
public static ConfigEntry<EDhApiLoggerLevel> logWorldGenPerformanceToFile = new ConfigEntry.Builder<EDhApiLoggerLevel>()
|
|
||||||
.setChatCommandName("logging.logWorldGenPerformance")
|
|
||||||
.set(EDhApiLoggerLevel.INFO)
|
|
||||||
.comment(""
|
|
||||||
+ "If enabled, the mod will log performance about the world generation process. \n"
|
|
||||||
+ "This can be useful for debugging.")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
public static ConfigEntry<EDhApiLoggerLevel> logWorldGenChunkLoadEventToFile = new ConfigEntry.Builder<EDhApiLoggerLevel>()
|
public static ConfigEntry<EDhApiLoggerLevel> logWorldGenChunkLoadEventToFile = new ConfigEntry.Builder<EDhApiLoggerLevel>()
|
||||||
.setChatCommandName("logging.logWorldGenLoadEvent")
|
.setChatCommandName("logging.logWorldGenLoadEvent")
|
||||||
.set(EDhApiLoggerLevel.INFO)
|
.set(EDhApiLoggerLevel.INFO)
|
||||||
@@ -1669,6 +1601,14 @@ public class Config
|
|||||||
+ "")
|
+ "")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
public static ConfigEntry<Boolean> showSlowWorldGenSettingWarnings = new ConfigEntry.Builder<Boolean>()
|
||||||
|
.set(true)
|
||||||
|
.comment(""
|
||||||
|
+ "If enabled, a chat message will be displayed when DH has too many chunks \n"
|
||||||
|
+ "queued for updating. \n"
|
||||||
|
+ "")
|
||||||
|
.build();
|
||||||
|
|
||||||
public static ConfigEntry<Boolean> showModCompatibilityWarningsOnStartup = new ConfigEntry.Builder<Boolean>()
|
public static ConfigEntry<Boolean> showModCompatibilityWarningsOnStartup = new ConfigEntry.Builder<Boolean>()
|
||||||
.set(true)
|
.set(true)
|
||||||
.comment(""
|
.comment(""
|
||||||
@@ -1892,7 +1832,6 @@ public class Config
|
|||||||
ThreadPresetConfigEventHandler.INSTANCE.setUiOnlyConfigValues();
|
ThreadPresetConfigEventHandler.INSTANCE.setUiOnlyConfigValues();
|
||||||
RenderQualityPresetConfigEventHandler.INSTANCE.setUiOnlyConfigValues();
|
RenderQualityPresetConfigEventHandler.INSTANCE.setUiOnlyConfigValues();
|
||||||
QuickRenderToggleConfigEventHandler.INSTANCE.setUiOnlyConfigValues();
|
QuickRenderToggleConfigEventHandler.INSTANCE.setUiOnlyConfigValues();
|
||||||
QuickShowWorldGenProgressConfigEventHandler.INSTANCE.setUiOnlyConfigValues();
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|||||||
-66
@@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the Distant Horizons mod
|
|
||||||
* licensed under the GNU LGPL 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 Lesser 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 Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.seibel.distanthorizons.core.config.eventHandlers.presets;
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.api.enums.rendering.EDhApiRendererMode;
|
|
||||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorProgressDisplayLocation;
|
|
||||||
import com.seibel.distanthorizons.core.config.Config;
|
|
||||||
import com.seibel.distanthorizons.core.config.listeners.ConfigChangeListener;
|
|
||||||
|
|
||||||
public class QuickShowWorldGenProgressConfigEventHandler
|
|
||||||
{
|
|
||||||
public static QuickShowWorldGenProgressConfigEventHandler INSTANCE = new QuickShowWorldGenProgressConfigEventHandler();
|
|
||||||
|
|
||||||
private final ConfigChangeListener<Boolean> quickChangeListener;
|
|
||||||
private final ConfigChangeListener<EDhApiDistantGeneratorProgressDisplayLocation> fullChangeListener;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** private since we only ever need one handler at a time */
|
|
||||||
private QuickShowWorldGenProgressConfigEventHandler()
|
|
||||||
{
|
|
||||||
this.quickChangeListener = new ConfigChangeListener<>(Config.Client.quickShowWorldGenProgress,
|
|
||||||
(val) ->
|
|
||||||
{
|
|
||||||
boolean quickShowProgress = Config.Client.quickShowWorldGenProgress.get();
|
|
||||||
Config.Common.WorldGenerator.showGenerationProgress.set(
|
|
||||||
quickShowProgress
|
|
||||||
? EDhApiDistantGeneratorProgressDisplayLocation.OVERLAY
|
|
||||||
: EDhApiDistantGeneratorProgressDisplayLocation.DISABLED);
|
|
||||||
});
|
|
||||||
this.fullChangeListener = new ConfigChangeListener<>(Config.Common.WorldGenerator.showGenerationProgress,
|
|
||||||
(val) ->
|
|
||||||
{
|
|
||||||
boolean showProgress = Config.Common.WorldGenerator.showGenerationProgress.get() != EDhApiDistantGeneratorProgressDisplayLocation.DISABLED;
|
|
||||||
Config.Client.quickShowWorldGenProgress.setWithoutFiringEvents(showProgress);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the UI only config based on what is set in the file. <br>
|
|
||||||
* This should only be called once.
|
|
||||||
*/
|
|
||||||
public void setUiOnlyConfigValues()
|
|
||||||
{
|
|
||||||
boolean showProgress = Config.Common.WorldGenerator.showGenerationProgress.get() != EDhApiDistantGeneratorProgressDisplayLocation.DISABLED;
|
|
||||||
Config.Client.quickShowWorldGenProgress.set(showProgress);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
+1
-1
@@ -268,7 +268,7 @@ public class FullDataPointIdMap
|
|||||||
// necessary to prevent issues with deserializing objects after the level has been closed
|
// necessary to prevent issues with deserializing objects after the level has been closed
|
||||||
if (Thread.interrupted())
|
if (Thread.interrupted())
|
||||||
{
|
{
|
||||||
throw new InterruptedException(FullDataPointIdMap.class.getSimpleName() + " task interrupted.");
|
throw new InterruptedException("[" + FullDataPointIdMap.class.getSimpleName() + "] deserializing interrupted.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+274
-238
@@ -44,6 +44,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
|||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
import it.unimi.dsi.fastutil.bytes.ByteArrayList;
|
import it.unimi.dsi.fastutil.bytes.ByteArrayList;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -92,8 +93,6 @@ public class FullDataSourceV2
|
|||||||
public long lastModifiedUnixDateTime;
|
public long lastModifiedUnixDateTime;
|
||||||
public long createdUnixDateTime;
|
public long createdUnixDateTime;
|
||||||
|
|
||||||
public int levelMinY;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* stores how far each column has been generated should start with {@link EDhApiWorldGenerationStep#EMPTY}
|
* stores how far each column has been generated should start with {@link EDhApiWorldGenerationStep#EMPTY}
|
||||||
*
|
*
|
||||||
@@ -299,9 +298,9 @@ public class FullDataSourceV2
|
|||||||
* returns {@link FullDataPointUtil#EMPTY_DATA_POINT} if the given {@link DhBlockPos}
|
* returns {@link FullDataPointUtil#EMPTY_DATA_POINT} if the given {@link DhBlockPos}
|
||||||
* is outside this data source's boundaries.
|
* is outside this data source's boundaries.
|
||||||
*/
|
*/
|
||||||
public long getDataPointAtBlockPos(DhBlockPos blockPos)
|
public long getDataPointAtBlockPos(int blockPosX, int blockPosY, int blockPosZ, int levelMinY)
|
||||||
{
|
{
|
||||||
DhLodPos requestedPos = new DhLodPos(LodUtil.BLOCK_DETAIL_LEVEL, blockPos.getX(), blockPos.getZ());
|
DhLodPos requestedPos = new DhLodPos(LodUtil.BLOCK_DETAIL_LEVEL, blockPosX, blockPosZ);
|
||||||
|
|
||||||
// stop if the requested blockPos is outside this datasource
|
// stop if the requested blockPos is outside this datasource
|
||||||
{
|
{
|
||||||
@@ -331,6 +330,7 @@ public class FullDataSourceV2
|
|||||||
|
|
||||||
|
|
||||||
// search for a datapoint that contains the given block y position
|
// search for a datapoint that contains the given block y position
|
||||||
|
int relBlockPosY = blockPosY - levelMinY;
|
||||||
long dataPoint;
|
long dataPoint;
|
||||||
for (int i = 0; i < dataColumn.size(); i++)
|
for (int i = 0; i < dataColumn.size(); i++)
|
||||||
{
|
{
|
||||||
@@ -345,14 +345,13 @@ public class FullDataSourceV2
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
int requestedY = blockPos.getY();
|
int bottomY = FullDataPointUtil.getBottomY(dataPoint);
|
||||||
int bottomY = FullDataPointUtil.getBottomY(dataPoint) + this.levelMinY;
|
|
||||||
int height = FullDataPointUtil.getHeight(dataPoint);
|
int height = FullDataPointUtil.getHeight(dataPoint);
|
||||||
int topY = bottomY + height;
|
int topY = bottomY + height;
|
||||||
|
|
||||||
// does this datapoint contain the requested Y position?
|
// does this datapoint contain the requested Y position?
|
||||||
if (bottomY <= requestedY
|
if (bottomY <= relBlockPosY
|
||||||
&& requestedY < topY) // blockPositions start from the bottom of the block, thus "<=" for bottomY, just "<" for topY
|
&& relBlockPosY < topY) // blockPositions start from the bottom of the block, thus "<=" for bottomY, just "<" for topY
|
||||||
{
|
{
|
||||||
return dataPoint;
|
return dataPoint;
|
||||||
}
|
}
|
||||||
@@ -367,7 +366,7 @@ public class FullDataSourceV2
|
|||||||
// updating //
|
// updating //
|
||||||
//==========//
|
//==========//
|
||||||
|
|
||||||
public boolean updateFromChunk(@NotNull FullDataSourceV2 inputDataSource)
|
public boolean updateFromDataSource(@NotNull FullDataSourceV2 inputDataSource)
|
||||||
{
|
{
|
||||||
// don't try updating if the input is empty
|
// don't try updating if the input is empty
|
||||||
if (inputDataSource.mapping.isEmpty())
|
if (inputDataSource.mapping.isEmpty())
|
||||||
@@ -470,7 +469,7 @@ public class FullDataSourceV2
|
|||||||
return dataChanged;
|
return dataChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean updateFromSameDetailLevel(FullDataSourceV2 inputDataSource, int[] remappedIds)
|
private boolean updateFromSameDetailLevel(FullDataSourceV2 inputDataSource, int[] remappedIds)
|
||||||
{
|
{
|
||||||
// both data sources should have the same detail level
|
// both data sources should have the same detail level
|
||||||
if (DhSectionPos.getDetailLevel(inputDataSource.pos) != DhSectionPos.getDetailLevel(this.pos))
|
if (DhSectionPos.getDetailLevel(inputDataSource.pos) != DhSectionPos.getDetailLevel(this.pos))
|
||||||
@@ -486,96 +485,103 @@ public class FullDataSourceV2
|
|||||||
for (int z = 0; z < WIDTH; z++)
|
for (int z = 0; z < WIDTH; z++)
|
||||||
{
|
{
|
||||||
int index = relativePosToIndex(x, z);
|
int index = relativePosToIndex(x, z);
|
||||||
|
|
||||||
LongArrayList inputDataArray = inputDataSource.dataPoints[index];
|
LongArrayList inputDataArray = inputDataSource.dataPoints[index];
|
||||||
if (inputDataArray != null)
|
if (inputDataArray == null)
|
||||||
{
|
{
|
||||||
byte thisGenState = this.columnGenerationSteps.getByte(index);
|
continue;
|
||||||
byte inputGenState = inputDataSource.columnGenerationSteps.getByte(index);
|
}
|
||||||
|
|
||||||
|
|
||||||
// determine if this column should be updated
|
|
||||||
boolean genStateAllowsUpdating = false;
|
byte thisGenState = this.columnGenerationSteps.getByte(index);
|
||||||
// if the input is downsampled, we only want to replace empty or downsampled values
|
byte inputGenState = inputDataSource.columnGenerationSteps.getByte(index);
|
||||||
if (inputGenState == EDhApiWorldGenerationStep.DOWN_SAMPLED.value
|
|
||||||
&&
|
|
||||||
(
|
// determine if this column should be updated
|
||||||
thisGenState == EDhApiWorldGenerationStep.EMPTY.value
|
boolean genStateAllowsUpdating = false;
|
||||||
|| thisGenState == EDhApiWorldGenerationStep.DOWN_SAMPLED.value
|
// if the input is downsampled, we only want to replace empty or downsampled values
|
||||||
))
|
if (inputGenState == EDhApiWorldGenerationStep.DOWN_SAMPLED.value
|
||||||
|
&&
|
||||||
|
(
|
||||||
|
thisGenState == EDhApiWorldGenerationStep.EMPTY.value
|
||||||
|
|| thisGenState == EDhApiWorldGenerationStep.DOWN_SAMPLED.value
|
||||||
|
))
|
||||||
|
{
|
||||||
|
genStateAllowsUpdating = true;
|
||||||
|
}
|
||||||
|
// if the input is any other non-empty value,
|
||||||
|
// replace anything that is less-complete
|
||||||
|
else if (inputGenState != EDhApiWorldGenerationStep.EMPTY.value
|
||||||
|
&& thisGenState <= inputGenState)
|
||||||
|
{
|
||||||
|
// don't apply less-complete generation data
|
||||||
|
genStateAllowsUpdating = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!genStateAllowsUpdating)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// check if the data changed
|
||||||
|
if (this.dataPoints[index] == null)
|
||||||
|
{
|
||||||
|
// no data was present previously
|
||||||
|
this.dataPoints[index] = new LongArrayList(inputDataArray);
|
||||||
|
dataChanged = true;
|
||||||
|
}
|
||||||
|
else if (this.dataPoints[index].size() != inputDataArray.size())
|
||||||
|
{
|
||||||
|
// data is present, but the size is different
|
||||||
|
dataChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int oldDataHash = 0;
|
||||||
|
if (!dataChanged)
|
||||||
|
{
|
||||||
|
// some old data existed with the same length,
|
||||||
|
// we'll have to compare the caches
|
||||||
|
oldDataHash = this.dataPoints[index].hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// copy over the new data
|
||||||
|
this.dataPoints[index].clear();
|
||||||
|
this.dataPoints[index].addAll(inputDataArray);
|
||||||
|
this.remapDataColumn(index, remappedIds);
|
||||||
|
|
||||||
|
if (RUN_DATA_ORDER_VALIDATION)
|
||||||
|
{
|
||||||
|
throwIfDataColumnInWrongOrder(inputDataSource.pos, this.dataPoints[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (!dataChanged)
|
||||||
|
{
|
||||||
|
// check if the identical length data column hashes are the same
|
||||||
|
// hashes need to be compared after the ID's have been remapped otherwise the ID's won't match even if the data is the same
|
||||||
|
if (oldDataHash != this.dataPoints[index].hashCode())
|
||||||
{
|
{
|
||||||
genStateAllowsUpdating = true;
|
// the hashes are different, something was changed
|
||||||
}
|
dataChanged = true;
|
||||||
// if the input is any other non-empty value,
|
|
||||||
// replace anything that is less-complete
|
|
||||||
else if (inputGenState != EDhApiWorldGenerationStep.EMPTY.value
|
|
||||||
&& thisGenState <= inputGenState)
|
|
||||||
{
|
|
||||||
// don't apply less-complete generation data
|
|
||||||
genStateAllowsUpdating = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (genStateAllowsUpdating)
|
|
||||||
{
|
|
||||||
// check if the data changed
|
|
||||||
if (this.dataPoints[index] == null)
|
|
||||||
{
|
|
||||||
// no data was present previously
|
|
||||||
this.dataPoints[index] = new LongArrayList(inputDataArray);
|
|
||||||
dataChanged = true;
|
|
||||||
}
|
|
||||||
else if (this.dataPoints[index].size() != inputDataArray.size())
|
|
||||||
{
|
|
||||||
// data is present, but the size is different
|
|
||||||
dataChanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int oldDataHash = 0;
|
|
||||||
if (!dataChanged)
|
|
||||||
{
|
|
||||||
// some old data existed with the same length,
|
|
||||||
// we'll have to compare the caches
|
|
||||||
oldDataHash = this.dataPoints[index].hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// copy over the new data
|
|
||||||
this.dataPoints[index].clear();
|
|
||||||
this.dataPoints[index].addAll(inputDataArray);
|
|
||||||
this.remapDataColumn(index, remappedIds);
|
|
||||||
|
|
||||||
if (RUN_DATA_ORDER_VALIDATION)
|
|
||||||
{
|
|
||||||
throwIfDataColumnInWrongOrder(inputDataSource.pos, this.dataPoints[index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (!dataChanged)
|
|
||||||
{
|
|
||||||
// check if the identical length data column hashes are the same
|
|
||||||
// hashes need to be compared after the ID's have been remapped otherwise the ID's won't match even if the data is the same
|
|
||||||
if (oldDataHash != this.dataPoints[index].hashCode())
|
|
||||||
{
|
|
||||||
// the hashes are different, something was changed
|
|
||||||
dataChanged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
this.columnGenerationSteps.set(index, inputGenState);
|
|
||||||
// always overwrite the compression mode since we're replacing this column
|
|
||||||
this.columnWorldCompressionMode.set(index, inputDataSource.columnWorldCompressionMode.getByte(index));
|
|
||||||
this.isEmpty = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.columnGenerationSteps.set(index, inputGenState);
|
||||||
|
// always overwrite the compression mode since we're replacing this column
|
||||||
|
this.columnWorldCompressionMode.set(index, inputDataSource.columnWorldCompressionMode.getByte(index));
|
||||||
|
this.isEmpty = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dataChanged;
|
return dataChanged;
|
||||||
}
|
}
|
||||||
public boolean updateFromOneBelowDetailLevel(FullDataSourceV2 inputDataSource, int[] remappedIds)
|
|
||||||
|
private boolean updateFromOneBelowDetailLevel(FullDataSourceV2 inputDataSource, int[] remappedIds)
|
||||||
{
|
{
|
||||||
if (DhSectionPos.getDetailLevel(inputDataSource.pos) + 1 != DhSectionPos.getDetailLevel(this.pos))
|
if (DhSectionPos.getDetailLevel(inputDataSource.pos) + 1 != DhSectionPos.getDetailLevel(this.pos))
|
||||||
{
|
{
|
||||||
@@ -711,176 +717,221 @@ public class FullDataSourceV2
|
|||||||
{
|
{
|
||||||
LongArrayList newColumnList = new LongArrayList();
|
LongArrayList newColumnList = new LongArrayList();
|
||||||
|
|
||||||
// special numbers:
|
|
||||||
// -2 = the column's height hasn't been determined yet
|
//=========================//
|
||||||
// -1 = we've reached the end of the column
|
// get the 4 input columns //
|
||||||
int[] currentDatapointIndex = new int[] { -2, -2, -2, -2 };
|
//=========================//
|
||||||
|
|
||||||
|
LongArrayList[] inputColumns = new LongArrayList[4];
|
||||||
|
int colIndex = 0;
|
||||||
|
for (int inputX = x; inputX < x + 2; inputX++)
|
||||||
|
{
|
||||||
|
for (int inputZ = z; inputZ < z + 2; inputZ++, colIndex++)
|
||||||
|
{
|
||||||
|
inputColumns[colIndex] = inputDataSource.dataPoints[relativePosToIndex(inputX, inputZ)];
|
||||||
|
if (inputColumns[colIndex] != null
|
||||||
|
&& RUN_DATA_ORDER_VALIDATION)
|
||||||
|
{
|
||||||
|
throwIfDataColumnInWrongOrder(inputDataSource.pos, inputColumns[colIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========================================//
|
||||||
|
// find all y levels where changes happen //
|
||||||
|
//========================================//
|
||||||
|
|
||||||
|
IntArrayList yTransitions = new IntArrayList();
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
if (inputColumns[i] == null
|
||||||
|
|| inputColumns[i].isEmpty())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < inputColumns[i].size(); j++)
|
||||||
|
{
|
||||||
|
long datapoint = inputColumns[i].getLong(j);
|
||||||
|
int minY = FullDataPointUtil.getBottomY(datapoint);
|
||||||
|
int maxY = minY + FullDataPointUtil.getHeight(datapoint);
|
||||||
|
|
||||||
|
if (!yTransitions.contains(minY))
|
||||||
|
{
|
||||||
|
yTransitions.add(minY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!yTransitions.contains(maxY))
|
||||||
|
{
|
||||||
|
yTransitions.add(maxY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// can happen if the columns are empty
|
||||||
|
if (yTransitions.isEmpty())
|
||||||
|
{
|
||||||
|
return newColumnList;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort the transitions from bottom to top // TODO
|
||||||
|
yTransitions.sort(null);
|
||||||
|
|
||||||
|
// create index trackers for each column,
|
||||||
|
// starting with the top-most datapoint
|
||||||
|
int[] currentIndices = new int[4];
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
if (inputColumns[i] != null
|
||||||
|
&& !inputColumns[i].isEmpty())
|
||||||
|
{
|
||||||
|
currentIndices[i] = inputColumns[i].size() - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentIndices[i] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=======================//
|
||||||
|
// process each Y change //
|
||||||
|
//=======================//
|
||||||
|
|
||||||
int lastId = 0;
|
int lastId = 0;
|
||||||
byte lastBlockLight = 0;
|
byte lastBlockLight = 0;
|
||||||
byte lastSkyLight = 0;
|
byte lastSkyLight = 0;
|
||||||
int height = 0;
|
int currentMinY = yTransitions.getInt(0);
|
||||||
int minY = 0;
|
int accumulatedHeight = 0;
|
||||||
|
|
||||||
|
|
||||||
// these arrays will be reused quite often, so re-using them helps reduce some GC pressure
|
|
||||||
long[] datapointsForYSlice = new long[4];
|
|
||||||
int[] mergeIds = new int[4];
|
int[] mergeIds = new int[4];
|
||||||
int[] mergeBlockLights = new int[4];
|
int[] mergeBlockLights = new int[4];
|
||||||
int[] mergeSkyLights = new int[4];
|
int[] mergeSkyLights = new int[4];
|
||||||
|
|
||||||
|
for (int yIndex = 0; yIndex < yTransitions.size() - 1; yIndex++)
|
||||||
for (int blockY = 0; blockY < RenderDataPointUtil.MAX_WORLD_Y_SIZE; blockY++, height++)
|
|
||||||
{
|
{
|
||||||
// if each column has reached the end of their data, nothing more needs to be done
|
int sliceMinY = yTransitions.getInt(yIndex);
|
||||||
if (currentDatapointIndex[0] == -1
|
int sliceMaxY = yTransitions.getInt(yIndex + 1);
|
||||||
&& currentDatapointIndex[1] == -1
|
int sliceHeight = sliceMaxY - sliceMinY;
|
||||||
&& currentDatapointIndex[2] == -1
|
|
||||||
&& currentDatapointIndex[3] == -1
|
|
||||||
)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// scary double loop but,
|
|
||||||
// this will only ever loop 4 times,
|
|
||||||
// once for each of the 4 input columns
|
|
||||||
Arrays.fill(datapointsForYSlice, 0L);
|
|
||||||
int colIndex = 0;
|
|
||||||
for (int inputX = x; inputX < x + 2; inputX++)
|
|
||||||
{
|
|
||||||
for (int inputZ = z; inputZ < z + 2; inputZ++, colIndex++)
|
|
||||||
{
|
|
||||||
// TODO throw an assertion if the column isn't in top-down order or just fix it...
|
|
||||||
LongArrayList inputDataArray = inputDataSource.dataPoints[relativePosToIndex(inputX, inputZ)];
|
|
||||||
if (inputDataArray == null || inputDataArray.size() == 0)
|
|
||||||
{
|
|
||||||
currentDatapointIndex[colIndex] = -1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// determine the last index (the lowest data point) for each column
|
|
||||||
if (currentDatapointIndex[colIndex] == -2)
|
|
||||||
{
|
|
||||||
currentDatapointIndex[colIndex] = inputDataArray.size() - 1;
|
|
||||||
|
|
||||||
if (RUN_DATA_ORDER_VALIDATION)
|
|
||||||
{
|
|
||||||
throwIfDataColumnInWrongOrder(inputDataSource.pos, inputDataArray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int dataPointIndex = currentDatapointIndex[colIndex];
|
|
||||||
if (dataPointIndex == -1)
|
|
||||||
{
|
|
||||||
// went over the end
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
long datapoint = inputDataArray.getLong(dataPointIndex);
|
|
||||||
|
|
||||||
int datapointMinY = FullDataPointUtil.getBottomY(datapoint);
|
|
||||||
int numbOfBlocksTall = FullDataPointUtil.getHeight(datapoint);
|
|
||||||
int datapointMaxY = (datapointMinY + numbOfBlocksTall);
|
|
||||||
|
|
||||||
|
|
||||||
// check if y position is inside this datapoint
|
|
||||||
if (blockY < datapointMinY)
|
|
||||||
{
|
|
||||||
// this y-slice is below this datapoint, nothing can be added
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (blockY >= datapointMaxY)
|
|
||||||
{
|
|
||||||
// this y-slice is above the current datapoint,
|
|
||||||
// try the next data point
|
|
||||||
|
|
||||||
int newDatapointIndex = currentDatapointIndex[colIndex] - 1;
|
|
||||||
if (newDatapointIndex < 0)
|
|
||||||
{
|
|
||||||
// went to far, no additional data present
|
|
||||||
newDatapointIndex = -1;
|
|
||||||
}
|
|
||||||
currentDatapointIndex[colIndex] = newDatapointIndex;
|
|
||||||
|
|
||||||
|
|
||||||
// try again with the next data point
|
|
||||||
inputZ--;
|
|
||||||
colIndex--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
datapointsForYSlice[colIndex] = datapoint;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
// Sample at the midpoint of this slice
|
||||||
|
int sampleY = sliceMinY + (sliceHeight / 2);
|
||||||
|
|
||||||
|
// Get data from each column at this Y level
|
||||||
Arrays.fill(mergeIds, 0);
|
Arrays.fill(mergeIds, 0);
|
||||||
Arrays.fill(mergeBlockLights, 0);
|
Arrays.fill(mergeBlockLights, 0);
|
||||||
Arrays.fill(mergeSkyLights, 0);
|
Arrays.fill(mergeSkyLights, 0);
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
mergeIds[i] = FullDataPointUtil.getId(datapointsForYSlice[i]);
|
// skip columns that are empty or where we have already reached the bottom
|
||||||
mergeBlockLights[i] = FullDataPointUtil.getBlockLight(datapointsForYSlice[i]);
|
if (currentIndices[i] == -1)
|
||||||
mergeSkyLights[i] = FullDataPointUtil.getSkyLight(datapointsForYSlice[i]);
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LongArrayList column = inputColumns[i];
|
||||||
|
if (column == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// move the index down if we've passed the current datapoint
|
||||||
|
while (currentIndices[i] >= 0)
|
||||||
|
{
|
||||||
|
long datapoint = column.getLong(currentIndices[i]);
|
||||||
|
int inputMinY = FullDataPointUtil.getBottomY(datapoint);
|
||||||
|
int inputMaxY = inputMinY + FullDataPointUtil.getHeight(datapoint);
|
||||||
|
|
||||||
|
if (sampleY >= inputMaxY)
|
||||||
|
{
|
||||||
|
// Sample point is above this datapoint, move to next (lower) one
|
||||||
|
currentIndices[i]--;
|
||||||
|
}
|
||||||
|
else if (sampleY >= inputMinY
|
||||||
|
&& sampleY < inputMaxY)
|
||||||
|
{
|
||||||
|
// Sample point is within this datapoint
|
||||||
|
mergeIds[i] = FullDataPointUtil.getId(datapoint);
|
||||||
|
mergeBlockLights[i] = FullDataPointUtil.getBlockLight(datapoint);
|
||||||
|
mergeSkyLights[i] = FullDataPointUtil.getSkyLight(datapoint);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Sample point is below this datapoint
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// determine the most common values for this slice
|
|
||||||
int id = determineMostValueInColumnSlice(mergeIds, inputDataSource.mapping);
|
// Determine merged values for this slice
|
||||||
|
int id = determineMostCommonValueInColumnSlice(mergeIds, inputDataSource.mapping);
|
||||||
byte blockLight = (byte) determineAverageValueInColumnSlice(mergeBlockLights);
|
byte blockLight = (byte) determineAverageValueInColumnSlice(mergeBlockLights);
|
||||||
byte skyLight = (byte) determineAverageValueInColumnSlice(mergeSkyLights);
|
byte skyLight = (byte) determineAverageValueInColumnSlice(mergeSkyLights);
|
||||||
|
|
||||||
// if this slice is different then the last one, create a new one
|
// Check if we need to start a new datapoint
|
||||||
if (id != lastId
|
if (accumulatedHeight == 0)
|
||||||
// block and sky light might not be necessary
|
|
||||||
|| blockLight != lastBlockLight
|
|
||||||
|| skyLight != lastSkyLight)
|
|
||||||
{
|
{
|
||||||
if (height != 0)
|
// first datapoint
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
long datapoint = FullDataPointUtil.encode(lastId, height, minY, lastBlockLight, lastSkyLight);
|
|
||||||
newColumnList.add(datapoint);
|
|
||||||
}
|
|
||||||
catch (DataCorruptedException e)
|
|
||||||
{
|
|
||||||
// shouldn't happen, (especially if validation is disabled) but just in case
|
|
||||||
LOGGER.warn("Skipping corrupt datapoint for pos ["+DhSectionPos.toString(inputDataSource.pos)+"] at relative position ["+x+","+z+"] with data: ID["+lastId+"], Height["+height+"], minY["+minY+"], lastBlockLight["+lastBlockLight+"], lastSkyLight["+lastSkyLight+"].");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lastId = id;
|
lastId = id;
|
||||||
lastBlockLight = blockLight;
|
lastBlockLight = blockLight;
|
||||||
lastSkyLight = skyLight;
|
lastSkyLight = skyLight;
|
||||||
height = 0;
|
currentMinY = sliceMinY;
|
||||||
minY = blockY;
|
accumulatedHeight = sliceHeight;
|
||||||
|
}
|
||||||
|
else if (id != lastId
|
||||||
|
|| blockLight != lastBlockLight
|
||||||
|
|| skyLight != lastSkyLight)
|
||||||
|
{
|
||||||
|
// the data changed, create a new datapoint
|
||||||
|
try
|
||||||
|
{
|
||||||
|
long datapoint = FullDataPointUtil.encode(lastId, accumulatedHeight, currentMinY, lastBlockLight, lastSkyLight);
|
||||||
|
newColumnList.add(datapoint);
|
||||||
|
}
|
||||||
|
catch (DataCorruptedException e)
|
||||||
|
{
|
||||||
|
LOGGER.warn("Skipping corrupt datapoint for pos ["+DhSectionPos.toString(inputDataSource.pos)+"] at relative position ["+x+","+z+"] with data: ID["+lastId+"], Height["+accumulatedHeight+"], minY["+currentMinY+"], lastBlockLight["+lastBlockLight+"], lastSkyLight["+lastSkyLight+"].");
|
||||||
|
}
|
||||||
|
|
||||||
|
// start the next datapoint
|
||||||
|
lastId = id;
|
||||||
|
lastBlockLight = blockLight;
|
||||||
|
lastSkyLight = skyLight;
|
||||||
|
currentMinY = sliceMinY;
|
||||||
|
accumulatedHeight = sliceHeight;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// this datapoint is the same as the last one,
|
||||||
|
// just extend it's height
|
||||||
|
accumulatedHeight += sliceHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the last slice if present
|
|
||||||
if (height != 0)
|
// add the final datapoint if needed
|
||||||
|
if (accumulatedHeight > 0)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
newColumnList.add(FullDataPointUtil.encode(lastId, height, minY, lastBlockLight, lastSkyLight));
|
newColumnList.add(FullDataPointUtil.encode(lastId, accumulatedHeight, currentMinY, lastBlockLight, lastSkyLight));
|
||||||
}
|
}
|
||||||
catch (DataCorruptedException e)
|
catch (DataCorruptedException e)
|
||||||
{
|
{
|
||||||
// shouldn't happen, (especially if validation is disabled) but just in case
|
LOGGER.warn("Skipping corrupt datapoint for pos ["+DhSectionPos.toString(inputDataSource.pos)+"] at relative position ["+x+","+z+"] with data: ID["+lastId+"], Height["+accumulatedHeight+"], minY["+currentMinY+"], lastBlockLight["+lastBlockLight+"], lastSkyLight["+lastSkyLight+"].");
|
||||||
LOGGER.warn("Skipping corrupt datapoint for pos ["+DhSectionPos.toString(inputDataSource.pos)+"] at relative position ["+x+","+z+"] with data: ID["+lastId+"], Height["+height+"], minY["+minY+"], lastBlockLight["+lastBlockLight+"], lastSkyLight["+lastSkyLight+"].");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// flip the array if necessary
|
// confirm the array is in the correct order
|
||||||
// TODO why is this sometimes necessary? What did I (James) screw up that causes the mergedInputDataArray
|
|
||||||
// to sometimes be in a different order? Is it potentially related to what detail level is coming in?
|
|
||||||
ensureDataColumnOrder(newColumnList);
|
ensureDataColumnOrder(newColumnList);
|
||||||
|
|
||||||
return newColumnList;
|
return newColumnList;
|
||||||
@@ -898,23 +949,8 @@ public class FullDataSourceV2
|
|||||||
dataColumn.set(i, FullDataPointUtil.remap(remappedIds, dataColumn.getLong(i)));
|
dataColumn.set(i, FullDataPointUtil.remap(remappedIds, dataColumn.getLong(i)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static boolean areDataColumnsDifferent(long[] oldDataArray, long[] newDataArray)
|
|
||||||
{
|
|
||||||
if (oldDataArray == null || oldDataArray.length != newDataArray.length)
|
|
||||||
{
|
|
||||||
// new data was added/removed
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// check if the new column data is different
|
|
||||||
int oldArrayHash = Arrays.hashCode(oldDataArray);
|
|
||||||
int newArrayHash = Arrays.hashCode(newDataArray);
|
|
||||||
return (newArrayHash != oldArrayHash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/** @param mapping can be included to ignore air ID's, otherwise all 4 values are treated equally */
|
/** @param mapping can be included to ignore air ID's, otherwise all 4 values are treated equally */
|
||||||
private static int determineMostValueInColumnSlice(int[] sliceArray, @Nullable FullDataPointIdMap mapping)
|
private static int determineMostCommonValueInColumnSlice(int[] sliceArray, @Nullable FullDataPointIdMap mapping)
|
||||||
{
|
{
|
||||||
if (RUN_UPDATE_DEV_VALIDATION)
|
if (RUN_UPDATE_DEV_VALIDATION)
|
||||||
{
|
{
|
||||||
@@ -958,7 +994,7 @@ public class FullDataSourceV2
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// return the most common occurance
|
// return the most common occurrence
|
||||||
int maxCount = Math.max(count0, Math.max(count1, Math.max(count2, count3)));
|
int maxCount = Math.max(count0, Math.max(count1, Math.max(count2, count3)));
|
||||||
if (maxCount == count0)
|
if (maxCount == count0)
|
||||||
// if the max count is 1 then we'll just go with the first column
|
// if the max count is 1 then we'll just go with the first column
|
||||||
@@ -1271,13 +1307,13 @@ public class FullDataSourceV2
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
LodDataBuilder.correctDataColumnOrder(columnDataPoints);
|
LodDataBuilder.putListInTopDownOrder(columnDataPoints);
|
||||||
if (this.runApiChunkValidation)
|
if (this.runApiChunkValidation)
|
||||||
{
|
{
|
||||||
LodDataBuilder.validateOrThrowApiDataColumn(columnDataPoints);
|
LodDataBuilder.validateOrThrowApiDataColumn(columnDataPoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
LongArrayList packedDataPoints = LodDataBuilder.convertApiDataPointListToPackedLongArray(columnDataPoints, this, 0);
|
LongArrayList packedDataPoints = LodDataBuilder.convertApiDataPointListToPackedLongArray(columnDataPoints, this, 0, true);
|
||||||
|
|
||||||
// TODO there should be an "unknown" compression and generation step, or be defined via the datapoints
|
// TODO there should be an "unknown" compression and generation step, or be defined via the datapoints
|
||||||
this.setSingleColumn(packedDataPoints, relX, relZ, EDhApiWorldGenerationStep.SURFACE, EDhApiWorldCompressionMode.MERGE_SAME_BLOCKS);
|
this.setSingleColumn(packedDataPoints, relX, relZ, EDhApiWorldGenerationStep.SURFACE, EDhApiWorldCompressionMode.MERGE_SAME_BLOCKS);
|
||||||
@@ -1300,7 +1336,7 @@ public class FullDataSourceV2
|
|||||||
{
|
{
|
||||||
long datapoint = dataColumn.getLong(i);
|
long datapoint = dataColumn.getLong(i);
|
||||||
|
|
||||||
DhApiTerrainDataPoint apiDataPoint = DhApiTerrainDataPointUtil.createApiDatapoint(this.levelMinY, this.mapping, DhSectionPos.getDetailLevel(this.pos), datapoint);
|
DhApiTerrainDataPoint apiDataPoint = DhApiTerrainDataPointUtil.createApiDatapoint(0, this.mapping, DhSectionPos.getDetailLevel(this.pos), datapoint);
|
||||||
apiList.add(apiDataPoint);
|
apiList.add(apiDataPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -157,8 +157,8 @@ public final class BufferQuad
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// make sure these quads share the same perpendicular axis
|
// make sure these quads share the same perpendicular axis
|
||||||
if ((mergeDirection == BufferMergeDirectionEnum.EastWest && this.y != quad.y) ||
|
if ((mergeDirection == BufferMergeDirectionEnum.EastWest && this.y != quad.y)
|
||||||
(mergeDirection == BufferMergeDirectionEnum.NorthSouthOrUpDown && this.x != quad.x))
|
|| (mergeDirection == BufferMergeDirectionEnum.NorthSouthOrUpDown && this.x != quad.x))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-21
@@ -24,7 +24,6 @@ import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
|||||||
import com.seibel.distanthorizons.core.enums.EDhDirection;
|
import com.seibel.distanthorizons.core.enums.EDhDirection;
|
||||||
import com.seibel.distanthorizons.core.level.IDhClientLevel;
|
import com.seibel.distanthorizons.core.level.IDhClientLevel;
|
||||||
import com.seibel.distanthorizons.core.pooling.PhantomArrayListCheckout;
|
import com.seibel.distanthorizons.core.pooling.PhantomArrayListCheckout;
|
||||||
import com.seibel.distanthorizons.core.pooling.PhantomArrayListPool;
|
|
||||||
import com.seibel.distanthorizons.core.util.ColorUtil;
|
import com.seibel.distanthorizons.core.util.ColorUtil;
|
||||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||||
import com.seibel.distanthorizons.core.util.RenderDataPointUtil;
|
import com.seibel.distanthorizons.core.util.RenderDataPointUtil;
|
||||||
@@ -46,7 +45,6 @@ public class ColumnBox
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=========//
|
//=========//
|
||||||
// builder //
|
// builder //
|
||||||
//=========//
|
//=========//
|
||||||
@@ -249,10 +247,10 @@ public class ColumnBox
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void makeAdjVerticalQuad(
|
private static void makeAdjVerticalQuad(
|
||||||
LodQuadBuilder builder, PhantomArrayListCheckout phantomArrayCheckout,
|
LodQuadBuilder builder, PhantomArrayListCheckout phantomArrayCheckout,
|
||||||
@NotNull ColumnArrayView adjColumnView, boolean adjacentIsSameDetailLevel, int caveCullingMaxY, EDhDirection direction,
|
@NotNull ColumnArrayView adjColumnView, boolean adjacentIsSameDetailLevel, int caveCullingMaxY, EDhDirection direction,
|
||||||
short x, short yMin, short z, short horizontalWidth, short ySize,
|
short x, short yMin, short z, short horizontalWidth, short ySize,
|
||||||
int color, byte irisBlockMaterialId, byte blockLight)
|
int color, byte irisBlockMaterialId, byte blockLight)
|
||||||
{
|
{
|
||||||
// pooled arrays
|
// pooled arrays
|
||||||
LongArrayList segments = phantomArrayCheckout.getLongArray(0, 0);
|
LongArrayList segments = phantomArrayCheckout.getLongArray(0, 0);
|
||||||
@@ -311,9 +309,10 @@ public class ColumnBox
|
|||||||
long adjBelowPoint = (adjIndex + 1 < adjCount) ? adjColumnView.get(adjIndex + 1) : RenderDataPointUtil.EMPTY_DATA;
|
long adjBelowPoint = (adjIndex + 1 < adjCount) ? adjColumnView.get(adjIndex + 1) : RenderDataPointUtil.EMPTY_DATA;
|
||||||
|
|
||||||
boolean adjOverVoid = !RenderDataPointUtil.doesDataPointExist(adjBelowPoint);
|
boolean adjOverVoid = !RenderDataPointUtil.doesDataPointExist(adjBelowPoint);
|
||||||
boolean adjTransparent = !adjOverVoid
|
boolean adjTransparent =
|
||||||
&& RenderDataPointUtil.getAlpha(adjPoint) < 255
|
!adjOverVoid
|
||||||
&& transparencyEnabled;
|
&& RenderDataPointUtil.getAlpha(adjPoint) < 255
|
||||||
|
&& transparencyEnabled;
|
||||||
|
|
||||||
byte adjSkyLight = RenderDataPointUtil.getLightSky(adjPoint);
|
byte adjSkyLight = RenderDataPointUtil.getLightSky(adjPoint);
|
||||||
byte lightToApply;
|
byte lightToApply;
|
||||||
@@ -323,14 +322,14 @@ public class ColumnBox
|
|||||||
// Adjacent is opaque
|
// Adjacent is opaque
|
||||||
boolean adjacentCoversThis =
|
boolean adjacentCoversThis =
|
||||||
!adjacentIsSameDetailLevel
|
!adjacentIsSameDetailLevel
|
||||||
&& RenderDataPointUtil.getYMax(adjPoint) >= caveCullingMaxY
|
&& RenderDataPointUtil.getYMax(adjPoint) >= caveCullingMaxY
|
||||||
&&
|
&&
|
||||||
(
|
(
|
||||||
(x == 0 && direction == EDhDirection.WEST)
|
(x == 0 && direction == EDhDirection.WEST)
|
||||||
|| (z == 0 && direction == EDhDirection.NORTH)
|
|| (z == 0 && direction == EDhDirection.NORTH)
|
||||||
|| (x == 256 && direction == EDhDirection.EAST)
|
|| (x == 256 && direction == EDhDirection.EAST)
|
||||||
|| (z == 256 && direction == EDhDirection.SOUTH)
|
|| (z == 256 && direction == EDhDirection.SOUTH)
|
||||||
);
|
);
|
||||||
|
|
||||||
lightToApply = adjacentCoversThis ? adjSkyLight : SKYLIGHT_COVERED;
|
lightToApply = adjacentCoversThis ? adjSkyLight : SKYLIGHT_COVERED;
|
||||||
}
|
}
|
||||||
@@ -363,10 +362,10 @@ public class ColumnBox
|
|||||||
{
|
{
|
||||||
long segment = segments.getLong(i);
|
long segment = segments.getLong(i);
|
||||||
tryAddVerticalFaceWithSkyLightToBuilder(
|
tryAddVerticalFaceWithSkyLightToBuilder(
|
||||||
builder, direction,
|
builder, direction,
|
||||||
x, z, horizontalWidth,
|
x, z, horizontalWidth,
|
||||||
color, irisBlockMaterialId, blockLight,
|
color, irisBlockMaterialId, blockLight,
|
||||||
YSegmentUtil.getSkyLight(segment), inputTransparent, YSegmentUtil.getEndY(segment), YSegmentUtil.getStartY(segment)
|
YSegmentUtil.getSkyLight(segment), inputTransparent, YSegmentUtil.getEndY(segment), YSegmentUtil.getStartY(segment)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -112,7 +112,8 @@ public class LodBufferContainer implements AutoCloseable
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// skip this event if requested
|
// skip this event if requested
|
||||||
if (Thread.interrupted() || this.uploadFuture.isCancelled())
|
if (Thread.interrupted()
|
||||||
|
|| this.uploadFuture.isCancelled())
|
||||||
{
|
{
|
||||||
throw new InterruptedException();
|
throw new InterruptedException();
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-1
@@ -148,8 +148,18 @@ public class LodQuadBuilder
|
|||||||
throw new IllegalArgumentException("addQuadAdj() is only for adj direction! Not UP or Down!");
|
throw new IllegalArgumentException("addQuadAdj() is only for adj direction! Not UP or Down!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ArrayList<BufferQuad> quadList;
|
||||||
|
if (this.doTransparency && ColorUtil.getAlpha(color) < 255)
|
||||||
|
{
|
||||||
|
quadList = this.transparentQuads[dir.ordinal()];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
quadList = this.opaqueQuads[dir.ordinal()];
|
||||||
|
}
|
||||||
|
|
||||||
BufferQuad quad = new BufferQuad(x, y, z, widthEastWest, widthNorthSouthOrUpDown, color, irisBlockMaterialId, skyLight, blockLight, dir);
|
BufferQuad quad = new BufferQuad(x, y, z, widthEastWest, widthNorthSouthOrUpDown, color, irisBlockMaterialId, skyLight, blockLight, dir);
|
||||||
ArrayList<BufferQuad> quadList = (this.doTransparency && ColorUtil.getAlpha(color) < 255) ? this.transparentQuads[dir.ordinal()] : this.opaqueQuads[dir.ordinal()];
|
|
||||||
if (!quadList.isEmpty()
|
if (!quadList.isEmpty()
|
||||||
&& (
|
&& (
|
||||||
quadList.get(quadList.size() - 1).tryMerge(quad, BufferMergeDirectionEnum.EastWest)
|
quadList.get(quadList.size() - 1).tryMerge(quad, BufferMergeDirectionEnum.EastWest)
|
||||||
|
|||||||
+35
-11
@@ -31,11 +31,9 @@ import com.seibel.distanthorizons.core.pooling.PhantomArrayListCheckout;
|
|||||||
import com.seibel.distanthorizons.core.pooling.PhantomArrayListPool;
|
import com.seibel.distanthorizons.core.pooling.PhantomArrayListPool;
|
||||||
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPosMutable;
|
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPosMutable;
|
||||||
import com.seibel.distanthorizons.core.render.LodQuadTree;
|
|
||||||
import com.seibel.distanthorizons.core.util.*;
|
import com.seibel.distanthorizons.core.util.*;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
import com.seibel.distanthorizons.coreapi.util.BitShiftUtil;
|
import com.seibel.distanthorizons.coreapi.util.BitShiftUtil;
|
||||||
@@ -54,11 +52,11 @@ public class FullDataToRenderDataTransformer
|
|||||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
private static final IWrapperFactory WRAPPER_FACTORY = SingletonInjector.INSTANCE.get(IWrapperFactory.class);
|
private static final IWrapperFactory WRAPPER_FACTORY = SingletonInjector.INSTANCE.get(IWrapperFactory.class);
|
||||||
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
|
||||||
|
|
||||||
private static final LongOpenHashSet brokenPos = new LongOpenHashSet();
|
private static final LongOpenHashSet BROKEN_POS_SET = new LongOpenHashSet();
|
||||||
|
private static final PhantomArrayListPool ARRAY_LIST_POOL = new PhantomArrayListPool("Data Transformer");
|
||||||
|
|
||||||
public static final PhantomArrayListPool ARRAY_LIST_POOL = new PhantomArrayListPool("Data Transformer");
|
private static HashSet<IBlockStateWrapper> snowLayerBlockStates = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -198,6 +196,16 @@ public class FullDataToRenderDataTransformer
|
|||||||
HashSet<IBlockStateWrapper> blockStatesToIgnore = WRAPPER_FACTORY.getRendererIgnoredBlocks(levelWrapper);
|
HashSet<IBlockStateWrapper> blockStatesToIgnore = WRAPPER_FACTORY.getRendererIgnoredBlocks(levelWrapper);
|
||||||
HashSet<IBlockStateWrapper> caveBlockStatesToIgnore = WRAPPER_FACTORY.getRendererIgnoredCaveBlocks(levelWrapper);
|
HashSet<IBlockStateWrapper> caveBlockStatesToIgnore = WRAPPER_FACTORY.getRendererIgnoredCaveBlocks(levelWrapper);
|
||||||
|
|
||||||
|
// build snow block cache if needed
|
||||||
|
if (snowLayerBlockStates == null)
|
||||||
|
{
|
||||||
|
snowLayerBlockStates = new HashSet<>();
|
||||||
|
// ignore snow layers 1-3, everything above should be considered a full block
|
||||||
|
snowLayerBlockStates.add(WRAPPER_FACTORY.deserializeBlockStateWrapperOrGetDefault("minecraft:snow_STATE_{layers:1}", levelWrapper));
|
||||||
|
snowLayerBlockStates.add(WRAPPER_FACTORY.deserializeBlockStateWrapperOrGetDefault("minecraft:snow_STATE_{layers:2}", levelWrapper));
|
||||||
|
snowLayerBlockStates.add(WRAPPER_FACTORY.deserializeBlockStateWrapperOrGetDefault("minecraft:snow_STATE_{layers:3}", levelWrapper));
|
||||||
|
}
|
||||||
|
|
||||||
int caveCullingMaxY = Config.Client.Advanced.Graphics.Culling.caveCullingHeight.get() - levelWrapper.getMinHeight();
|
int caveCullingMaxY = Config.Client.Advanced.Graphics.Culling.caveCullingHeight.get() - levelWrapper.getMinHeight();
|
||||||
boolean caveCullingEnabled =
|
boolean caveCullingEnabled =
|
||||||
Config.Client.Advanced.Graphics.Culling.enableCaveCulling.get()
|
Config.Client.Advanced.Graphics.Culling.enableCaveCulling.get()
|
||||||
@@ -252,9 +260,9 @@ public class FullDataToRenderDataTransformer
|
|||||||
}
|
}
|
||||||
catch (IndexOutOfBoundsException e)
|
catch (IndexOutOfBoundsException e)
|
||||||
{
|
{
|
||||||
if (!brokenPos.contains(fullDataMapping.getPos()))
|
if (!BROKEN_POS_SET.contains(fullDataMapping.getPos()))
|
||||||
{
|
{
|
||||||
brokenPos.add(fullDataMapping.getPos());
|
BROKEN_POS_SET.add(fullDataMapping.getPos());
|
||||||
String levelId = levelWrapper.getDhIdentifier();
|
String levelId = levelWrapper.getDhIdentifier();
|
||||||
LOGGER.warn("Unable to get data point with id ["+id+"] " +
|
LOGGER.warn("Unable to get data point with id ["+id+"] " +
|
||||||
"(Max possible ID: ["+fullDataMapping.getMaxValidId()+"]) " +
|
"(Max possible ID: ["+fullDataMapping.getMaxValidId()+"]) " +
|
||||||
@@ -324,10 +332,26 @@ public class FullDataToRenderDataTransformer
|
|||||||
// non-solid block check //
|
// non-solid block check //
|
||||||
//=======================//
|
//=======================//
|
||||||
|
|
||||||
if (ignoreNonCollidingBlocks
|
boolean ignoreNonSolidBlock =
|
||||||
&& !block.isSolid()
|
ignoreNonCollidingBlocks
|
||||||
&& !block.isLiquid()
|
&& !block.isSolid()
|
||||||
&& block.getOpacity() != LodUtil.BLOCK_FULLY_OPAQUE)
|
&& !block.isLiquid()
|
||||||
|
&& block.getOpacity() != LodUtil.BLOCK_FULLY_OPAQUE;
|
||||||
|
|
||||||
|
// merge snow into the block below it
|
||||||
|
if (snowLayerBlockStates.contains(block))
|
||||||
|
{
|
||||||
|
// sometimes a snow datapoint will be multiple blocks tall,
|
||||||
|
// in that case we just want to drop the top by 1
|
||||||
|
blockHeight -= 1;
|
||||||
|
if (blockHeight == 0)
|
||||||
|
{
|
||||||
|
// this snow block was entirely removed, just color the block below it
|
||||||
|
ignoreNonSolidBlock = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ignoreNonSolidBlock)
|
||||||
{
|
{
|
||||||
if (colorBelowWithAvoidedBlocks)
|
if (colorBelowWithAvoidedBlocks)
|
||||||
{
|
{
|
||||||
|
|||||||
+109
-30
@@ -74,7 +74,7 @@ public class LodDataBuilder
|
|||||||
long pos = DhSectionPos.encode(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, sectionPosX, sectionPosZ);
|
long pos = DhSectionPos.encode(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, sectionPosX, sectionPosZ);
|
||||||
|
|
||||||
FullDataSourceV2 dataSource = FullDataSourceV2.createEmpty(pos);
|
FullDataSourceV2 dataSource = FullDataSourceV2.createEmpty(pos);
|
||||||
dataSource.isEmpty = false;
|
dataSource.isEmpty = false; // this will be set to "true" if any blocks are found
|
||||||
// chunk updates always propagate up
|
// chunk updates always propagate up
|
||||||
dataSource.applyToParent = true;
|
dataSource.applyToParent = true;
|
||||||
|
|
||||||
@@ -244,6 +244,15 @@ public class LodDataBuilder
|
|||||||
blockLight = newBlockLight;
|
blockLight = newBlockLight;
|
||||||
skyLight = newSkyLight;
|
skyLight = newSkyLight;
|
||||||
lastY = y;
|
lastY = y;
|
||||||
|
|
||||||
|
|
||||||
|
// mark the data source as non-empty if we find any non-air blocks
|
||||||
|
if (dataSource.isEmpty
|
||||||
|
&& newBlockState != null
|
||||||
|
&& !newBlockState.isAir())
|
||||||
|
{
|
||||||
|
dataSource.isEmpty = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,7 +270,6 @@ public class LodDataBuilder
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
LodUtil.assertTrue(!dataSource.isEmpty);
|
|
||||||
return dataSource;
|
return dataSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,13 +297,29 @@ public class LodDataBuilder
|
|||||||
for (int relBlockX = 0; relBlockX < LodUtil.CHUNK_WIDTH; relBlockX++)
|
for (int relBlockX = 0; relBlockX < LodUtil.CHUNK_WIDTH; relBlockX++)
|
||||||
{
|
{
|
||||||
List<DhApiTerrainDataPoint> columnDataPoints = apiChunk.getDataPoints(relBlockX, relBlockZ);
|
List<DhApiTerrainDataPoint> columnDataPoints = apiChunk.getDataPoints(relBlockX, relBlockZ);
|
||||||
LodDataBuilder.correctDataColumnOrder(columnDataPoints);
|
|
||||||
|
// mark the data source as non-empty if we find any non-air blocks
|
||||||
|
if (dataSource.isEmpty)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < columnDataPoints.size(); i++)
|
||||||
|
{
|
||||||
|
DhApiTerrainDataPoint dataPoint = columnDataPoints.get(i);
|
||||||
|
if (dataPoint.blockStateWrapper != null
|
||||||
|
&& !dataPoint.blockStateWrapper.isAir())
|
||||||
|
{
|
||||||
|
dataSource.isEmpty = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LodDataBuilder.putListInTopDownOrder(columnDataPoints);
|
||||||
if (runAdditionalValidation)
|
if (runAdditionalValidation)
|
||||||
{
|
{
|
||||||
validateOrThrowApiDataColumn(columnDataPoints);
|
validateOrThrowApiDataColumn(columnDataPoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
LongArrayList packedDataPoints = convertApiDataPointListToPackedLongArray(columnDataPoints, dataSource, apiChunk.bottomYBlockPos);
|
LongArrayList packedDataPoints = convertApiDataPointListToPackedLongArray(columnDataPoints, dataSource, apiChunk.bottomYBlockPos, runAdditionalValidation);
|
||||||
|
|
||||||
// TODO add the ability for API users to define a different compression mode
|
// TODO add the ability for API users to define a different compression mode
|
||||||
// or add a "unkown" compression mode
|
// or add a "unkown" compression mode
|
||||||
@@ -303,7 +327,6 @@ public class LodDataBuilder
|
|||||||
packedDataPoints,
|
packedDataPoints,
|
||||||
relBlockX + relSourceBlockX, relBlockZ + relSourceBlockZ,
|
relBlockX + relSourceBlockX, relBlockZ + relSourceBlockZ,
|
||||||
EDhApiWorldGenerationStep.LIGHT, EDhApiWorldCompressionMode.MERGE_SAME_BLOCKS);
|
EDhApiWorldGenerationStep.LIGHT, EDhApiWorldCompressionMode.MERGE_SAME_BLOCKS);
|
||||||
dataSource.isEmpty = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dataSource;
|
return dataSource;
|
||||||
@@ -317,41 +340,97 @@ public class LodDataBuilder
|
|||||||
|
|
||||||
/** @see FullDataPointUtil */
|
/** @see FullDataPointUtil */
|
||||||
public static LongArrayList convertApiDataPointListToPackedLongArray(
|
public static LongArrayList convertApiDataPointListToPackedLongArray(
|
||||||
@Nullable List<DhApiTerrainDataPoint> columnDataPoints, FullDataSourceV2 dataSource,
|
@Nullable List<DhApiTerrainDataPoint> topDownColumnDataPoints, FullDataSourceV2 dataSource,
|
||||||
int bottomYBlockPos) throws DataCorruptedException
|
int bottomYBlockPos, boolean runAdditionalValidation) throws DataCorruptedException
|
||||||
{
|
{
|
||||||
// this null check does 2 nice things at the same time:
|
if (topDownColumnDataPoints == null
|
||||||
// if columnDataPoints is null,
|
|| topDownColumnDataPoints.size() == 0)
|
||||||
// then packedDataPoints will be of length 0
|
|
||||||
// AND the below loop won't run.
|
|
||||||
int size = (columnDataPoints != null) ? columnDataPoints.size() : 0;
|
|
||||||
|
|
||||||
// TODO make missing air LODs
|
|
||||||
// TODO merge duplicate datapoints
|
|
||||||
LongArrayList packedDataPoints = new LongArrayList(new long[size]);
|
|
||||||
for (int index = 0; index < size; index++)
|
|
||||||
{
|
{
|
||||||
DhApiTerrainDataPoint dataPoint = columnDataPoints.get(index);
|
return new LongArrayList(0);
|
||||||
|
}
|
||||||
|
|
||||||
int id = dataSource.mapping.addIfNotPresentAndGetId(
|
|
||||||
(IBiomeWrapper) (dataPoint.biomeWrapper),
|
|
||||||
(IBlockStateWrapper) (dataPoint.blockStateWrapper)
|
// array to store data
|
||||||
|
int size = topDownColumnDataPoints.size();
|
||||||
|
LongArrayList packedDataPoints = new LongArrayList(size);
|
||||||
|
packedDataPoints.clear();
|
||||||
|
|
||||||
|
|
||||||
|
if (runAdditionalValidation)
|
||||||
|
{
|
||||||
|
// check for missing data
|
||||||
|
int lastTopY = Integer.MAX_VALUE;
|
||||||
|
for (int i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
DhApiTerrainDataPoint apiDataPoint = topDownColumnDataPoints.get(i);
|
||||||
|
|
||||||
|
if (lastTopY != apiDataPoint.topYBlockPos
|
||||||
|
// the first index won't have a lastTopY value
|
||||||
|
&& i != 0)
|
||||||
|
{
|
||||||
|
throw new DataCorruptedException("LOD data has a gap between ["+lastTopY+"] and ["+apiDataPoint.bottomYBlockPos+"]. Empty areas should be filled with air datapoints so light propagates correctly.");
|
||||||
|
}
|
||||||
|
lastTopY = apiDataPoint.bottomYBlockPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// go through data from top down
|
||||||
|
long lastDataPoint = FullDataPointUtil.EMPTY_DATA_POINT;
|
||||||
|
for (int i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
DhApiTerrainDataPoint apiDataPoint = topDownColumnDataPoints.get(i);
|
||||||
|
|
||||||
|
int thisId = dataSource.mapping.addIfNotPresentAndGetId(
|
||||||
|
(IBiomeWrapper) (apiDataPoint.biomeWrapper),
|
||||||
|
(IBlockStateWrapper) (apiDataPoint.blockStateWrapper)
|
||||||
);
|
);
|
||||||
|
int thisHeight = (apiDataPoint.topYBlockPos - apiDataPoint.bottomYBlockPos);
|
||||||
|
|
||||||
packedDataPoints.set(index, FullDataPointUtil.encode(
|
int lastId = FullDataPointUtil.getId(lastDataPoint);
|
||||||
id,
|
byte lastBlockLight = (byte)FullDataPointUtil.getBlockLight(lastDataPoint);
|
||||||
dataPoint.topYBlockPos - dataPoint.bottomYBlockPos,
|
byte lastSkyLight = (byte)FullDataPointUtil.getSkyLight(lastDataPoint);
|
||||||
dataPoint.bottomYBlockPos - bottomYBlockPos,
|
|
||||||
(byte) (dataPoint.blockLightLevel),
|
|
||||||
(byte) (dataPoint.skyLightLevel)
|
// if the ID and light are the same, merge the height
|
||||||
));
|
if (thisId == lastId
|
||||||
|
&& apiDataPoint.blockLightLevel == lastBlockLight
|
||||||
|
&& apiDataPoint.skyLightLevel == lastSkyLight
|
||||||
|
// the first index should always be added to the list
|
||||||
|
&& i != 0 )
|
||||||
|
{
|
||||||
|
// add adjacent height
|
||||||
|
int lastHeight = FullDataPointUtil.getHeight(lastDataPoint);
|
||||||
|
int newHeight = (lastHeight + thisHeight);
|
||||||
|
lastDataPoint = FullDataPointUtil.setHeight(lastDataPoint, newHeight);
|
||||||
|
|
||||||
|
// subtract bottom Y
|
||||||
|
int lastBottomY = FullDataPointUtil.getBottomY(lastDataPoint);
|
||||||
|
int newBottomY = lastBottomY - thisHeight;
|
||||||
|
lastDataPoint = FullDataPointUtil.setBottomY(lastDataPoint, newBottomY);
|
||||||
|
|
||||||
|
packedDataPoints.set(packedDataPoints.size()-1, lastDataPoint);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// data changed, create a new datapoint
|
||||||
|
long dataPoint = FullDataPointUtil.encode(
|
||||||
|
thisId,
|
||||||
|
thisHeight,
|
||||||
|
apiDataPoint.bottomYBlockPos - bottomYBlockPos,
|
||||||
|
(byte) (apiDataPoint.blockLightLevel),
|
||||||
|
(byte) (apiDataPoint.skyLightLevel)
|
||||||
|
);
|
||||||
|
lastDataPoint = dataPoint;
|
||||||
|
packedDataPoints.add(dataPoint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return packedDataPoints;
|
return packedDataPoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** also corrects the order if it's backwards */
|
public static void putListInTopDownOrder(List<DhApiTerrainDataPoint> dataPoints)
|
||||||
public static void correctDataColumnOrder(List<DhApiTerrainDataPoint> dataPoints)
|
|
||||||
{
|
{
|
||||||
// order doesn't need to be checked if there is 0 or 1 items
|
// order doesn't need to be checked if there is 0 or 1 items
|
||||||
if (dataPoints.size() > 1)
|
if (dataPoints.size() > 1)
|
||||||
|
|||||||
+1
-1
@@ -104,7 +104,7 @@ public class DelayedFullDataSourceSaveCache implements AutoCloseable
|
|||||||
}
|
}
|
||||||
|
|
||||||
// write the new data into memory
|
// write the new data into memory
|
||||||
memoryDataSource.updateFromChunk(inputDataSource);
|
memoryDataSource.updateFromDataSource(inputDataSource);
|
||||||
// keep track of when the last time we saved something was
|
// keep track of when the last time we saved something was
|
||||||
pair.updateLastWrittenTimestamp();
|
pair.updateLastWrittenTimestamp();
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -47,6 +47,8 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
@@ -80,8 +82,8 @@ public class GeneratedFullDataSourceProvider extends FullDataSourceProviderV2 im
|
|||||||
// constructor //
|
// constructor //
|
||||||
//=============//
|
//=============//
|
||||||
|
|
||||||
public GeneratedFullDataSourceProvider(IDhLevel level, ISaveStructure saveStructure) { super(level, saveStructure); }
|
public GeneratedFullDataSourceProvider(IDhLevel level, ISaveStructure saveStructure) throws SQLException, IOException { super(level, saveStructure); }
|
||||||
public GeneratedFullDataSourceProvider(IDhLevel level, ISaveStructure saveStructure, @Nullable File saveDirOverride)
|
public GeneratedFullDataSourceProvider(IDhLevel level, ISaveStructure saveStructure, @Nullable File saveDirOverride) throws SQLException, IOException
|
||||||
{
|
{
|
||||||
super(level, saveStructure, saveDirOverride);
|
super(level, saveStructure, saveDirOverride);
|
||||||
|
|
||||||
|
|||||||
+6
-3
@@ -24,20 +24,22 @@ import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSour
|
|||||||
import com.seibel.distanthorizons.core.file.structure.ISaveStructure;
|
import com.seibel.distanthorizons.core.file.structure.ISaveStructure;
|
||||||
import com.seibel.distanthorizons.core.generation.RemoteWorldRetrievalQueue;
|
import com.seibel.distanthorizons.core.generation.RemoteWorldRetrievalQueue;
|
||||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||||
import com.seibel.distanthorizons.core.level.WorldGenModule;
|
import com.seibel.distanthorizons.core.level.LodRequestModule;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.multiplayer.client.SyncOnLoadRequestQueue;
|
import com.seibel.distanthorizons.core.multiplayer.client.SyncOnLoadRequestQueue;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Only handles {@link SyncOnLoadRequestQueue} requests (IE updating existing LODs based on a timestamp).
|
* Only handles {@link SyncOnLoadRequestQueue} requests (IE updating existing LODs based on a timestamp).
|
||||||
* Missing data is handled by {@link WorldGenModule} and {@link RemoteWorldRetrievalQueue}.
|
* Missing data is handled by {@link LodRequestModule} and {@link RemoteWorldRetrievalQueue}.
|
||||||
*/
|
*/
|
||||||
public class RemoteFullDataSourceProvider extends GeneratedFullDataSourceProvider
|
public class RemoteFullDataSourceProvider extends GeneratedFullDataSourceProvider
|
||||||
{
|
{
|
||||||
@@ -58,7 +60,8 @@ public class RemoteFullDataSourceProvider extends GeneratedFullDataSourceProvide
|
|||||||
|
|
||||||
public RemoteFullDataSourceProvider(
|
public RemoteFullDataSourceProvider(
|
||||||
IDhLevel level, ISaveStructure saveStructure, @Nullable File saveDirOverride,
|
IDhLevel level, ISaveStructure saveStructure, @Nullable File saveDirOverride,
|
||||||
@Nullable SyncOnLoadRequestQueue syncOnLoadRequestQueue)
|
@Nullable SyncOnLoadRequestQueue syncOnLoadRequestQueue
|
||||||
|
) throws SQLException, IOException
|
||||||
{
|
{
|
||||||
super(level, saveStructure, saveDirOverride);
|
super(level, saveStructure, saveDirOverride);
|
||||||
this.syncOnLoadRequestQueue = syncOnLoadRequestQueue;
|
this.syncOnLoadRequestQueue = syncOnLoadRequestQueue;
|
||||||
|
|||||||
+2
-17
@@ -43,7 +43,7 @@ public class FullDataSourceProviderV1<TDhLevel extends IDhLevel>
|
|||||||
// constructor //
|
// constructor //
|
||||||
//=============//
|
//=============//
|
||||||
|
|
||||||
public FullDataSourceProviderV1(TDhLevel level, File saveDir)
|
public FullDataSourceProviderV1(TDhLevel level, File saveDir) throws SQLException, IOException
|
||||||
{
|
{
|
||||||
this.level = level;
|
this.level = level;
|
||||||
this.saveDir = saveDir;
|
this.saveDir = saveDir;
|
||||||
@@ -52,7 +52,7 @@ public class FullDataSourceProviderV1<TDhLevel extends IDhLevel>
|
|||||||
LOGGER.warn("Unable to create full data folder, file saving may fail.");
|
LOGGER.warn("Unable to create full data folder, file saving may fail.");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.repo = this.createRepo();
|
this.repo = new FullDataSourceV1Repo(AbstractDhRepo.DEFAULT_DATABASE_TYPE, new File(this.saveDir.getPath() + File.separator + ISaveStructure.DATABASE_NAME));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -61,21 +61,6 @@ public class FullDataSourceProviderV1<TDhLevel extends IDhLevel>
|
|||||||
// abstract methods //
|
// abstract methods //
|
||||||
//==================//
|
//==================//
|
||||||
|
|
||||||
/** When this is called the parent folders should be created */
|
|
||||||
protected FullDataSourceV1Repo createRepo()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return new FullDataSourceV1Repo(AbstractDhRepo.DEFAULT_DATABASE_TYPE, new File(this.saveDir.getPath() + File.separator + ISaveStructure.DATABASE_NAME));
|
|
||||||
}
|
|
||||||
catch (SQLException e)
|
|
||||||
{
|
|
||||||
// should only happen if there is an issue with the database (it's locked or can't be created if missing)
|
|
||||||
// or the database update failed
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected FullDataSourceV1 createDataSourceFromDto(FullDataSourceV1DTO dto) throws InterruptedException, IOException, DataCorruptedException
|
protected FullDataSourceV1 createDataSourceFromDto(FullDataSourceV1DTO dto) throws InterruptedException, IOException, DataCorruptedException
|
||||||
{
|
{
|
||||||
FullDataSourceV1 dataSource = FullDataSourceV1.createEmpty(dto.pos);
|
FullDataSourceV1 dataSource = FullDataSourceV1.createEmpty(dto.pos);
|
||||||
|
|||||||
+4
-1
@@ -14,6 +14,8 @@ import com.seibel.distanthorizons.core.render.renderer.IDebugRenderable;
|
|||||||
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
|
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -62,7 +64,8 @@ public class DataMigratorV1 implements IDebugRenderable, AutoCloseable
|
|||||||
|
|
||||||
public DataMigratorV1(
|
public DataMigratorV1(
|
||||||
FullDataUpdaterV2 dataUpdater,
|
FullDataUpdaterV2 dataUpdater,
|
||||||
IDhLevel level, String levelId, File saveDir)
|
IDhLevel level, String levelId, File saveDir
|
||||||
|
) throws SQLException, IOException
|
||||||
{
|
{
|
||||||
this.dataUpdater = dataUpdater;
|
this.dataUpdater = dataUpdater;
|
||||||
this.saveDir = saveDir;
|
this.saveDir = saveDir;
|
||||||
|
|||||||
+26
-19
@@ -96,11 +96,11 @@ public class FullDataSourceProviderV2 implements IDebugRenderable, AutoCloseable
|
|||||||
// constructor //
|
// constructor //
|
||||||
//=============//
|
//=============//
|
||||||
|
|
||||||
public FullDataSourceProviderV2(IDhLevel level, ISaveStructure saveStructure) { this(level, saveStructure, null); }
|
public FullDataSourceProviderV2(IDhLevel level, ISaveStructure saveStructure) throws SQLException, IOException { this(level, saveStructure, null); }
|
||||||
public FullDataSourceProviderV2(IDhLevel level, ISaveStructure saveStructure, @Nullable File saveDirOverride)
|
public FullDataSourceProviderV2(IDhLevel level, ISaveStructure saveStructure, @Nullable File saveDirOverride) throws SQLException, IOException
|
||||||
{
|
{
|
||||||
this.saveDir = (saveDirOverride == null) ? saveStructure.getSaveFolder(level.getLevelWrapper()) : saveDirOverride;
|
this.saveDir = (saveDirOverride == null) ? saveStructure.getSaveFolder(level.getLevelWrapper()) : saveDirOverride;
|
||||||
this.repo = this.createRepo();
|
this.repo = new FullDataSourceV2Repo(AbstractDhRepo.DEFAULT_DATABASE_TYPE, new File(this.saveDir.getPath() + File.separator + ISaveStructure.DATABASE_NAME));
|
||||||
this.level = level;
|
this.level = level;
|
||||||
|
|
||||||
this.levelId = this.level.getLevelWrapper().getDhIdentifier();
|
this.levelId = this.level.getLevelWrapper().getDhIdentifier();
|
||||||
@@ -112,19 +112,6 @@ public class FullDataSourceProviderV2 implements IDebugRenderable, AutoCloseable
|
|||||||
DebugRenderer.register(this, Config.Client.Advanced.Debugging.DebugWireframe.showFullDataUpdateStatus);
|
DebugRenderer.register(this, Config.Client.Advanced.Debugging.DebugWireframe.showFullDataUpdateStatus);
|
||||||
|
|
||||||
}
|
}
|
||||||
private FullDataSourceV2Repo createRepo()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return new FullDataSourceV2Repo(AbstractDhRepo.DEFAULT_DATABASE_TYPE, new File(this.saveDir.getPath() + File.separator + ISaveStructure.DATABASE_NAME));
|
|
||||||
}
|
|
||||||
catch (SQLException e)
|
|
||||||
{
|
|
||||||
// should only happen if there is an issue with the database (it's locked or the folder path is missing)
|
|
||||||
// or the database update failed
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -134,14 +121,14 @@ public class FullDataSourceProviderV2 implements IDebugRenderable, AutoCloseable
|
|||||||
|
|
||||||
public void addDataSourceUpdateListener(IDataSourceUpdateListenerFunc<FullDataSourceV2> listener)
|
public void addDataSourceUpdateListener(IDataSourceUpdateListenerFunc<FullDataSourceV2> listener)
|
||||||
{
|
{
|
||||||
synchronized (this.dataUpdater)
|
synchronized (this.dataUpdater.dateSourceUpdateListeners)
|
||||||
{
|
{
|
||||||
this.dataUpdater.dateSourceUpdateListeners.add(listener);
|
this.dataUpdater.dateSourceUpdateListeners.add(listener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void removeDataSourceUpdateListener(IDataSourceUpdateListenerFunc<FullDataSourceV2> listener)
|
public void removeDataSourceUpdateListener(IDataSourceUpdateListenerFunc<FullDataSourceV2> listener)
|
||||||
{
|
{
|
||||||
synchronized (this.dataUpdater)
|
synchronized (this.dataUpdater.dateSourceUpdateListeners)
|
||||||
{
|
{
|
||||||
this.dataUpdater.dateSourceUpdateListeners.add(listener);
|
this.dataUpdater.dateSourceUpdateListeners.add(listener);
|
||||||
}
|
}
|
||||||
@@ -239,7 +226,27 @@ public class FullDataSourceProviderV2 implements IDebugRenderable, AutoCloseable
|
|||||||
catch (InterruptedException ignore) { }
|
catch (InterruptedException ignore) { }
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
LOGGER.warn("File read Error for pos ["+DhSectionPos.toString(pos)+"], error: "+e.getMessage(), e);
|
String message = e.getMessage();
|
||||||
|
if (CORRUPT_DATA_ERRORS_LOGGED.add(message))
|
||||||
|
{
|
||||||
|
LOGGER.warn("File read Error for pos [" + DhSectionPos.toString(pos) + "], this error message will only be logged once, error: [" + message + "].", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IllegalStateException e)
|
||||||
|
{
|
||||||
|
String message = e.getMessage();
|
||||||
|
if (CORRUPT_DATA_ERRORS_LOGGED.add(message))
|
||||||
|
{
|
||||||
|
LOGGER.warn("Incorrectly formatted data for: [" + DhSectionPos.toString(pos) + "], this error message will only be logged once, error: [" + message + "].", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
String message = e.getMessage();
|
||||||
|
if (CORRUPT_DATA_ERRORS_LOGGED.add(message))
|
||||||
|
{
|
||||||
|
LOGGER.warn("Unexpected error getting: [" + DhSectionPos.toString(pos) + "], this error message will only be logged once, error: [" + message + "].", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// an error occurred
|
// an error occurred
|
||||||
|
|||||||
+8
-9
@@ -82,6 +82,7 @@ public class FullDataUpdatePropagatorV2 implements IDebugRenderable, AutoCloseab
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//================//
|
//================//
|
||||||
// parent updates //
|
// parent updates //
|
||||||
//================//
|
//================//
|
||||||
@@ -184,7 +185,7 @@ public class FullDataUpdatePropagatorV2 implements IDebugRenderable, AutoCloseab
|
|||||||
parentLocked = true;
|
parentLocked = true;
|
||||||
this.dataUpdater.lockedPosSet.add(parentUpdatePos);
|
this.dataUpdater.lockedPosSet.add(parentUpdatePos);
|
||||||
|
|
||||||
try (FullDataSourceV2 parentDataSource = this.provider.get(parentUpdatePos))
|
try (FullDataSourceV2 parentDataSource = this.provider.get(parentUpdatePos)) // TODO can we cache anything in memory to speed up the propagation process? Compression/Disk IO is by far the slowest part of this process
|
||||||
{
|
{
|
||||||
// will return null if the file handler is shutting down
|
// will return null if the file handler is shutting down
|
||||||
if (parentDataSource != null)
|
if (parentDataSource != null)
|
||||||
@@ -203,7 +204,7 @@ public class FullDataUpdatePropagatorV2 implements IDebugRenderable, AutoCloseab
|
|||||||
// can return null when the file handler is being shut down
|
// can return null when the file handler is being shut down
|
||||||
if (childDataSource != null)
|
if (childDataSource != null)
|
||||||
{
|
{
|
||||||
parentDataSource.updateFromChunk(childDataSource);
|
parentDataSource.updateFromDataSource(childDataSource);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -213,6 +214,8 @@ public class FullDataUpdatePropagatorV2 implements IDebugRenderable, AutoCloseab
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
this.provider.repo.setApplyToParent(childPos, false);
|
||||||
|
|
||||||
childReadLock.unlock();
|
childReadLock.unlock();
|
||||||
this.dataUpdater.lockedPosSet.remove(childPos);
|
this.dataUpdater.lockedPosSet.remove(childPos);
|
||||||
}
|
}
|
||||||
@@ -225,10 +228,6 @@ public class FullDataUpdatePropagatorV2 implements IDebugRenderable, AutoCloseab
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.dataUpdater.updateDataSource(parentDataSource, false);
|
this.dataUpdater.updateDataSource(parentDataSource, false);
|
||||||
for (Long childPos : updatePosByParentPos.get(parentUpdatePos))
|
|
||||||
{
|
|
||||||
this.provider.repo.setApplyToParent(childPos, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -321,7 +320,7 @@ public class FullDataUpdatePropagatorV2 implements IDebugRenderable, AutoCloseab
|
|||||||
// will return null if the file handler is shutting down
|
// will return null if the file handler is shutting down
|
||||||
if (childDataSource != null)
|
if (childDataSource != null)
|
||||||
{
|
{
|
||||||
childDataSource.updateFromChunk(parentDataSource);
|
childDataSource.updateFromDataSource(parentDataSource);
|
||||||
|
|
||||||
// don't propagate child updates past the bottom of the tree
|
// don't propagate child updates past the bottom of the tree
|
||||||
if (DhSectionPos.getDetailLevel(childPos) != DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL)
|
if (DhSectionPos.getDetailLevel(childPos) != DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL)
|
||||||
@@ -339,12 +338,12 @@ public class FullDataUpdatePropagatorV2 implements IDebugRenderable, AutoCloseab
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
this.provider.repo.setApplyToChild(parentUpdatePos, false);
|
||||||
|
|
||||||
childWriteLock.unlock();
|
childWriteLock.unlock();
|
||||||
this.dataUpdater.lockedPosSet.remove(childPos);
|
this.dataUpdater.lockedPosSet.remove(childPos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.provider.repo.setApplyToChild(parentUpdatePos, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-4
@@ -137,7 +137,7 @@ public class FullDataUpdaterV2 implements IDebugRenderable, AutoCloseable
|
|||||||
{
|
{
|
||||||
if (recipientDataSource != null)
|
if (recipientDataSource != null)
|
||||||
{
|
{
|
||||||
boolean dataModified = recipientDataSource.updateFromChunk(inputData);
|
boolean dataModified = recipientDataSource.updateFromDataSource(inputData);
|
||||||
if (dataModified)
|
if (dataModified)
|
||||||
{
|
{
|
||||||
// save the updated data to the database
|
// save the updated data to the database
|
||||||
@@ -150,11 +150,14 @@ public class FullDataUpdaterV2 implements IDebugRenderable, AutoCloseable
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (IDataSourceUpdateListenerFunc<FullDataSourceV2> listener : this.dateSourceUpdateListeners)
|
synchronized (this.dateSourceUpdateListeners)
|
||||||
{
|
{
|
||||||
if (listener != null)
|
for (IDataSourceUpdateListenerFunc<FullDataSourceV2> listener : this.dateSourceUpdateListeners)
|
||||||
{
|
{
|
||||||
listener.OnDataSourceUpdated(recipientDataSource);
|
if (listener != null)
|
||||||
|
{
|
||||||
|
listener.OnDataSourceUpdated(recipientDataSource);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,12 +24,13 @@ import com.seibel.distanthorizons.api.interfaces.override.worldGenerator.IDhApiW
|
|||||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.util.ExceptionUtil;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.IBatchGeneratorEnvironmentWrapper;
|
||||||
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IOverrideInjector;
|
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IOverrideInjector;
|
||||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode;
|
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode;
|
||||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvironmentWrapper;
|
|
||||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
@@ -42,10 +43,10 @@ import java.util.function.Consumer;
|
|||||||
*/
|
*/
|
||||||
public class BatchGenerator implements IDhApiWorldGenerator
|
public class BatchGenerator implements IDhApiWorldGenerator
|
||||||
{
|
{
|
||||||
private static final IWrapperFactory FACTORY = SingletonInjector.INSTANCE.get(IWrapperFactory.class);
|
private static final IWrapperFactory WRAPPER_FACTORY = SingletonInjector.INSTANCE.get(IWrapperFactory.class);
|
||||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
public AbstractBatchGenerationEnvironmentWrapper generationEnvironment;
|
public IBatchGeneratorEnvironmentWrapper generationEnvironment;
|
||||||
public IDhLevel targetDhLevel;
|
public IDhLevel targetDhLevel;
|
||||||
|
|
||||||
|
|
||||||
@@ -57,7 +58,7 @@ public class BatchGenerator implements IDhApiWorldGenerator
|
|||||||
public BatchGenerator(IDhLevel targetDhLevel)
|
public BatchGenerator(IDhLevel targetDhLevel)
|
||||||
{
|
{
|
||||||
this.targetDhLevel = targetDhLevel;
|
this.targetDhLevel = targetDhLevel;
|
||||||
this.generationEnvironment = FACTORY.createBatchGenerator(targetDhLevel);
|
this.generationEnvironment = WRAPPER_FACTORY.createBatchGenerator(targetDhLevel);
|
||||||
LOGGER.info("Batch Chunk Generator initialized");
|
LOGGER.info("Batch Chunk Generator initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,26 +84,26 @@ public class BatchGenerator implements IDhApiWorldGenerator
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===================//
|
//===================//
|
||||||
// generator methods //
|
// generator methods //
|
||||||
//===================//
|
//===================//
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Void> generateChunks(
|
public CompletableFuture<Void> generateChunks(
|
||||||
int chunkPosMinX, int chunkPosMinZ, int generationRequestChunkWidthCount, byte targetDataDetail, EDhApiDistantGeneratorMode generatorMode,
|
int chunkPosMinX,
|
||||||
ExecutorService worldGeneratorThreadPool, Consumer<Object[]> resultConsumer)
|
int chunkPosMinZ,
|
||||||
|
int chunkWidthCount,
|
||||||
|
byte targetDataDetail,
|
||||||
|
EDhApiDistantGeneratorMode generatorMode,
|
||||||
|
ExecutorService worldGeneratorThreadPool,
|
||||||
|
Consumer<Object[]> resultConsumer)
|
||||||
{
|
{
|
||||||
EDhApiWorldGenerationStep targetStep = null;
|
EDhApiWorldGenerationStep targetStep;
|
||||||
switch (generatorMode)
|
switch (generatorMode)
|
||||||
{
|
{
|
||||||
case PRE_EXISTING_ONLY: // Only load in existing chunks. Note: this requires the biome generation step in order for biomes to be properly initialized.
|
case PRE_EXISTING_ONLY: // Only load in existing chunks.
|
||||||
//case BIOME_ONLY: // No blocks. Require fake height in LodBuilder
|
targetStep = EDhApiWorldGenerationStep.EMPTY; // special logic
|
||||||
targetStep = EDhApiWorldGenerationStep.BIOMES;
|
|
||||||
break;
|
break;
|
||||||
//case BIOME_ONLY_SIMULATE_HEIGHT:
|
|
||||||
// targetStep = EDhApiWorldGenerationStep.NOISE; // Stone only. Requires a fake surface
|
|
||||||
// break;
|
|
||||||
case SURFACE:
|
case SURFACE:
|
||||||
targetStep = EDhApiWorldGenerationStep.SURFACE;
|
targetStep = EDhApiWorldGenerationStep.SURFACE;
|
||||||
break;
|
break;
|
||||||
@@ -112,20 +113,27 @@ public class BatchGenerator implements IDhApiWorldGenerator
|
|||||||
case INTERNAL_SERVER:
|
case INTERNAL_SERVER:
|
||||||
targetStep = EDhApiWorldGenerationStep.LIGHT;
|
targetStep = EDhApiWorldGenerationStep.LIGHT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("no target step defined for generator mode: ["+generatorMode+"].");
|
||||||
}
|
}
|
||||||
|
|
||||||
// the consumer needs to be wrapped like this because the API can't use DH core objects (and IChunkWrapper can't be easily put into the API project)
|
// the consumer needs to be wrapped like this because the API can't use DH core objects (and IChunkWrapper can't be easily put into the API project)
|
||||||
Consumer<IChunkWrapper> consumerWrapper = (chunkWrapper) -> resultConsumer.accept(new Object[]{chunkWrapper});
|
Consumer<IChunkWrapper> consumerWrapper = (chunkWrapper) -> resultConsumer.accept(new Object[]{chunkWrapper});
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return this.generationEnvironment.generateChunks(
|
return this.generationEnvironment.queueGenEvent(
|
||||||
chunkPosMinX, chunkPosMinZ, generationRequestChunkWidthCount,
|
chunkPosMinX, chunkPosMinZ, chunkWidthCount,
|
||||||
generatorMode, targetStep,
|
generatorMode, targetStep,
|
||||||
worldGeneratorThreadPool, consumerWrapper);
|
worldGeneratorThreadPool, consumerWrapper);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
if (!LodUtil.isInterruptOrReject(e)) LOGGER.error("Error starting future for chunk generation", e);
|
if (!ExceptionUtil.isInterruptOrReject(e))
|
||||||
|
{
|
||||||
|
LOGGER.error("Error starting future for chunk generation, error: ["+e.getMessage()+"].", e);
|
||||||
|
}
|
||||||
|
|
||||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||||
future.completeExceptionally(e);
|
future.completeExceptionally(e);
|
||||||
return future;
|
return future;
|
||||||
@@ -144,9 +152,10 @@ public class BatchGenerator implements IDhApiWorldGenerator
|
|||||||
@Override
|
@Override
|
||||||
public void close()
|
public void close()
|
||||||
{
|
{
|
||||||
LOGGER.info(BatchGenerator.class.getSimpleName() + " shutting down...");
|
LOGGER.info("["+BatchGenerator.class.getSimpleName()+"] shutting down...");
|
||||||
this.generationEnvironment.stop();
|
this.generationEnvironment.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+49
-36
@@ -154,14 +154,15 @@ public class DhLightingEngine
|
|||||||
// and get any necessary info from them
|
// and get any necessary info from them
|
||||||
for (int chunkIndex = 0; chunkIndex < nearbyChunkList.size(); chunkIndex++) // using iterators in high traffic areas can cause GC issues due to allocating a bunch of iterators, use an indexed for-loop instead
|
for (int chunkIndex = 0; chunkIndex < nearbyChunkList.size(); chunkIndex++) // using iterators in high traffic areas can cause GC issues due to allocating a bunch of iterators, use an indexed for-loop instead
|
||||||
{
|
{
|
||||||
IChunkWrapper chunk = nearbyChunkList.get(chunkIndex);
|
IChunkWrapper neighborChunk = nearbyChunkList.get(chunkIndex);
|
||||||
if (chunk != null && requestedAdjacentPositions.contains(chunk.getChunkPos()))
|
if (neighborChunk != null
|
||||||
|
&& requestedAdjacentPositions.contains(neighborChunk.getChunkPos()))
|
||||||
{
|
{
|
||||||
// remove the newly found position
|
// remove the newly found position
|
||||||
requestedAdjacentPositions.remove(chunk.getChunkPos());
|
requestedAdjacentPositions.remove(neighborChunk.getChunkPos());
|
||||||
|
|
||||||
// add the adjacent chunk
|
// add the adjacent chunk
|
||||||
adjacentChunkHolder.add(chunk);
|
adjacentChunkHolder.add(neighborChunk);
|
||||||
|
|
||||||
// get and set the adjacent chunk's initial block lights
|
// get and set the adjacent chunk's initial block lights
|
||||||
final DhBlockPosMutable relLightBlockPos = PRIMARY_BLOCK_POS_REF.get();
|
final DhBlockPosMutable relLightBlockPos = PRIMARY_BLOCK_POS_REF.get();
|
||||||
@@ -174,19 +175,19 @@ public class DhLightingEngine
|
|||||||
|
|
||||||
if (updateBlockLight)
|
if (updateBlockLight)
|
||||||
{
|
{
|
||||||
ArrayList<DhBlockPos> blockLightPosList = chunk.getWorldBlockLightPosList();
|
ArrayList<DhBlockPos> blockLightPosList = neighborChunk.getWorldBlockLightPosList();
|
||||||
for (int blockLightIndex = 0; blockLightIndex < blockLightPosList.size(); blockLightIndex++) // using iterators in high traffic areas can cause GC issues due to allocating a bunch of iterators, use an indexed for-loop instead
|
for (int blockLightIndex = 0; blockLightIndex < blockLightPosList.size(); blockLightIndex++) // using iterators in high traffic areas can cause GC issues due to allocating a bunch of iterators, use an indexed for-loop instead
|
||||||
{
|
{
|
||||||
DhBlockPos blockLightPos = blockLightPosList.get(blockLightIndex);
|
DhBlockPos blockLightPos = blockLightPosList.get(blockLightIndex);
|
||||||
blockLightPos.mutateToChunkRelativePos(relLightBlockPos);
|
blockLightPos.mutateToChunkRelativePos(relLightBlockPos);
|
||||||
|
|
||||||
// get the light
|
// get the light
|
||||||
IBlockStateWrapper blockState = chunk.getBlockState(relLightBlockPos);
|
IBlockStateWrapper blockState = neighborChunk.getBlockState(relLightBlockPos);
|
||||||
int lightValue = blockState.getLightEmission();
|
int lightValue = blockState.getLightEmission();
|
||||||
blockLightWorldPosQueue.push(blockLightPos.getX(), blockLightPos.getY(), blockLightPos.getZ(), lightValue);
|
blockLightWorldPosQueue.push(blockLightPos.getX(), blockLightPos.getY(), blockLightPos.getZ(), lightValue);
|
||||||
|
|
||||||
// set the light
|
// set the light
|
||||||
chunk.setDhBlockLight(relLightBlockPos.getX(), relLightBlockPos.getY(), relLightBlockPos.getZ(), lightValue);
|
neighborChunk.setDhBlockLight(relLightBlockPos.getX(), relLightBlockPos.getY(), relLightBlockPos.getZ(), lightValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,23 +199,24 @@ public class DhLightingEngine
|
|||||||
|
|
||||||
// get and set the adjacent chunk's initial skylights,
|
// get and set the adjacent chunk's initial skylights,
|
||||||
// if the dimension has skylights
|
// if the dimension has skylights
|
||||||
if (updateSkyLight && maxSkyLight > 0)
|
if (updateSkyLight
|
||||||
|
&& maxSkyLight > 0)
|
||||||
{
|
{
|
||||||
IMutableBlockPosWrapper mcBlockPos = chunk.getMutableBlockPosWrapper();
|
IMutableBlockPosWrapper mcBlockPos = neighborChunk.getMutableBlockPosWrapper();
|
||||||
IBlockStateWrapper previousBlockState = null;
|
IBlockStateWrapper previousBlockState = null;
|
||||||
|
|
||||||
int maxY = chunk.getMaxNonEmptyHeight();
|
int maxY = neighborChunk.getMaxNonEmptyHeight();
|
||||||
int minY = chunk.getInclusiveMinBuildHeight();
|
int minY = neighborChunk.getInclusiveMinBuildHeight();
|
||||||
|
|
||||||
// get the adjacent chunk's sky lights
|
// get the adjacent chunk's sky lights
|
||||||
for (int relX = 0; relX < LodUtil.CHUNK_WIDTH; relX++) // relative block pos
|
for (int relX = 0; relX < LodUtil.CHUNK_WIDTH; relX++) // relative block pos
|
||||||
{
|
{
|
||||||
for (int relZ = 0; relZ < LodUtil.CHUNK_WIDTH; relZ++)
|
for (int relZ = 0; relZ < LodUtil.CHUNK_WIDTH; relZ++)
|
||||||
{
|
{
|
||||||
// set each pos' sky light all the way down until an opaque block is hit
|
// set each pos sky light all the way down until an opaque block is hit
|
||||||
for (int y = maxY; y >= minY; y--)
|
for (int y = maxY; y >= minY; y--)
|
||||||
{
|
{
|
||||||
IBlockStateWrapper block = previousBlockState = chunk.getBlockState(relX, y, relZ, mcBlockPos, previousBlockState);
|
IBlockStateWrapper block = previousBlockState = neighborChunk.getBlockState(relX, y, relZ, mcBlockPos, previousBlockState);
|
||||||
if (block != null && block.getOpacity() != LodUtil.BLOCK_FULLY_TRANSPARENT)
|
if (block != null && block.getOpacity() != LodUtil.BLOCK_FULLY_TRANSPARENT)
|
||||||
{
|
{
|
||||||
// keep moving down until we find a non-transparent block
|
// keep moving down until we find a non-transparent block
|
||||||
@@ -223,12 +225,12 @@ public class DhLightingEngine
|
|||||||
|
|
||||||
|
|
||||||
// add sky light to the queue
|
// add sky light to the queue
|
||||||
DhBlockPos skyLightPos = new DhBlockPos(chunk.getMinBlockX() + relX, y, chunk.getMinBlockZ() + relZ);
|
DhBlockPos skyLightPos = new DhBlockPos(neighborChunk.getMinBlockX() + relX, y, neighborChunk.getMinBlockZ() + relZ);
|
||||||
skyLightWorldPosQueue.push(skyLightPos.getX(), skyLightPos.getY(), skyLightPos.getZ(), maxSkyLight);
|
skyLightWorldPosQueue.push(skyLightPos.getX(), skyLightPos.getY(), skyLightPos.getZ(), maxSkyLight);
|
||||||
|
|
||||||
// set the chunk's sky light
|
// set the chunk's sky light
|
||||||
skyLightPos.mutateToChunkRelativePos(relLightBlockPos);
|
skyLightPos.mutateToChunkRelativePos(relLightBlockPos);
|
||||||
chunk.setDhSkyLight(relLightBlockPos.getX(), relLightBlockPos.getY(), relLightBlockPos.getZ(), maxSkyLight);
|
neighborChunk.setDhSkyLight(relLightBlockPos.getX(), relLightBlockPos.getY(), relLightBlockPos.getZ(), maxSkyLight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -247,13 +249,12 @@ public class DhLightingEngine
|
|||||||
if (updateBlockLight)
|
if (updateBlockLight)
|
||||||
{
|
{
|
||||||
// done to prevent a rare issue where the light values are incorrectly set to -1
|
// done to prevent a rare issue where the light values are incorrectly set to -1
|
||||||
// TODO why could that happen?
|
|
||||||
centerChunk.clearDhBlockLighting();
|
centerChunk.clearDhBlockLighting();
|
||||||
|
|
||||||
this.propagateChunkLightPosList(blockLightWorldPosQueue, adjacentChunkHolder,
|
this.propagateChunkLightPosList(blockLightWorldPosQueue, adjacentChunkHolder,
|
||||||
(neighbourChunk, relBlockPos) -> neighbourChunk.getDhBlockLight(relBlockPos.getX(), relBlockPos.getY(), relBlockPos.getZ()),
|
(neighbourChunk, relBlockPos) -> neighbourChunk.getDhBlockLight(relBlockPos.getX(), relBlockPos.getY(), relBlockPos.getZ()),
|
||||||
(neighbourChunk, relBlockPos, newLightValue) -> neighbourChunk.setDhBlockLight(relBlockPos.getX(), relBlockPos.getY(), relBlockPos.getZ(), newLightValue),
|
(neighbourChunk, relBlockPos, newLightValue) -> neighbourChunk.setDhBlockLight(relBlockPos.getX(), relBlockPos.getY(), relBlockPos.getZ(), newLightValue),
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// sky light
|
// sky light
|
||||||
@@ -262,9 +263,9 @@ public class DhLightingEngine
|
|||||||
centerChunk.clearDhSkyLighting();
|
centerChunk.clearDhSkyLighting();
|
||||||
|
|
||||||
this.propagateChunkLightPosList(skyLightWorldPosQueue, adjacentChunkHolder,
|
this.propagateChunkLightPosList(skyLightWorldPosQueue, adjacentChunkHolder,
|
||||||
(neighbourChunk, relBlockPos) -> neighbourChunk.getDhSkyLight(relBlockPos.getX(), relBlockPos.getY(), relBlockPos.getZ()),
|
(neighbourChunk, relBlockPos) -> neighbourChunk.getDhSkyLight(relBlockPos.getX(), relBlockPos.getY(), relBlockPos.getZ()),
|
||||||
(neighbourChunk, relBlockPos, newLightValue) -> neighbourChunk.setDhSkyLight(relBlockPos.getX(), relBlockPos.getY(), relBlockPos.getZ(), newLightValue),
|
(neighbourChunk, relBlockPos, newLightValue) -> neighbourChunk.setDhSkyLight(relBlockPos.getX(), relBlockPos.getY(), relBlockPos.getZ(), newLightValue),
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -300,9 +301,25 @@ public class DhLightingEngine
|
|||||||
final DhBlockPosMutable neighbourBlockPos = PRIMARY_BLOCK_POS_REF.get();
|
final DhBlockPosMutable neighbourBlockPos = PRIMARY_BLOCK_POS_REF.get();
|
||||||
final DhBlockPosMutable relNeighbourBlockPos = SECONDARY_BLOCK_POS_REF.get();
|
final DhBlockPosMutable relNeighbourBlockPos = SECONDARY_BLOCK_POS_REF.get();
|
||||||
|
|
||||||
|
// it doesn't matter what chunk we get the mutable block pos from
|
||||||
IMutableBlockPosWrapper mcBlockPos = null;
|
IMutableBlockPosWrapper mcBlockPos = null;
|
||||||
|
for (int i = 0; i < adjacentChunkHolder.chunkArray.length; i++)
|
||||||
|
{
|
||||||
|
IChunkWrapper chunkWrapper = adjacentChunkHolder.chunkArray[i];
|
||||||
|
if (chunkWrapper != null)
|
||||||
|
{
|
||||||
|
mcBlockPos = chunkWrapper.getMutableBlockPosWrapper();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mcBlockPos == null)
|
||||||
|
{
|
||||||
|
LodUtil.assertNotReach("How did we try to light a chunk with no chunks?");
|
||||||
|
}
|
||||||
|
|
||||||
IBlockStateWrapper previousBlockState = null;
|
IBlockStateWrapper previousBlockState = null;
|
||||||
|
|
||||||
|
|
||||||
// update each light position
|
// update each light position
|
||||||
while (!lightPosQueue.isEmpty())
|
while (!lightPosQueue.isEmpty())
|
||||||
{
|
{
|
||||||
@@ -346,15 +363,9 @@ public class DhLightingEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (mcBlockPos == null)
|
IBlockStateWrapper neighbourBlockState = neighbourChunk.getBlockState(relNeighbourBlockPos, mcBlockPos, previousBlockState);
|
||||||
{
|
previousBlockState = neighbourBlockState;
|
||||||
// it doesn't matter what chunk we get the position object from
|
|
||||||
// TODO move this getter logic out of ChunkWrapper
|
|
||||||
mcBlockPos = neighbourChunk.getMutableBlockPosWrapper();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
IBlockStateWrapper neighbourBlockState = previousBlockState = neighbourChunk.getBlockState(relNeighbourBlockPos, mcBlockPos, previousBlockState);
|
|
||||||
// Math.max(1, ...) is used so that the propagated light level always drops by at least 1, preventing infinite cycles.
|
// Math.max(1, ...) is used so that the propagated light level always drops by at least 1, preventing infinite cycles.
|
||||||
int targetLevel = lightValue - Math.max(1, neighbourBlockState.getOpacity());
|
int targetLevel = lightValue - Math.max(1, neighbourBlockState.getOpacity());
|
||||||
if (targetLevel > currentBlockLight)
|
if (targetLevel > currentBlockLight)
|
||||||
@@ -370,12 +381,14 @@ public class DhLightingEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// can be enable if troubleshooting lighting issues
|
// can be enabled if troubleshooting lighting issues
|
||||||
if (RENDER_BLOCK_LIGHT_WIREFRAME && propagatingBlockLights)
|
if (RENDER_BLOCK_LIGHT_WIREFRAME
|
||||||
|
&& propagatingBlockLights)
|
||||||
{
|
{
|
||||||
RenderDhLightValuesAsWireframe(adjacentChunkHolder, true);
|
RenderDhLightValuesAsWireframe(adjacentChunkHolder, true);
|
||||||
}
|
}
|
||||||
else if (RENDER_SKY_LIGHT_WIREFRAME && !propagatingBlockLights)
|
else if (RENDER_SKY_LIGHT_WIREFRAME
|
||||||
|
&& !propagatingBlockLights)
|
||||||
{
|
{
|
||||||
RenderDhLightValuesAsWireframe(adjacentChunkHolder, false);
|
RenderDhLightValuesAsWireframe(adjacentChunkHolder, false);
|
||||||
}
|
}
|
||||||
@@ -462,7 +475,7 @@ public class DhLightingEngine
|
|||||||
point = FullDataPointUtil.setSkyLight(point, skylight);
|
point = FullDataPointUtil.setSkyLight(point, skylight);
|
||||||
dataPoints.set(index, point);
|
dataPoints.set(index, point);
|
||||||
// now for the propagation.
|
// now for the propagation.
|
||||||
recursivelyLightAdjacentDataPoints(dataSource, airIDs, x, z, point);
|
this.recursivelyLightAdjacentDataPoints(dataSource, airIDs, x, z, point);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -596,7 +609,7 @@ public class DhLightingEngine
|
|||||||
else if (!airIDs.get(FullDataPointUtil.getId(adjacentDataPoint)))
|
else if (!airIDs.get(FullDataPointUtil.getId(adjacentDataPoint)))
|
||||||
{
|
{
|
||||||
// assume for now that we cannot propagate into non-transparent data points.
|
// assume for now that we cannot propagate into non-transparent data points.
|
||||||
continue; // TODO how does this work with water? Do we care?
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -610,7 +623,7 @@ public class DhLightingEngine
|
|||||||
adjacentDataPoint = FullDataPointUtil.setSkyLight(adjacentDataPoint, lightLevel - 1);
|
adjacentDataPoint = FullDataPointUtil.setSkyLight(adjacentDataPoint, lightLevel - 1);
|
||||||
adjacentDataPoints.set(adjacentIndex, adjacentDataPoint);
|
adjacentDataPoints.set(adjacentIndex, adjacentDataPoint);
|
||||||
// if propagation succeeded, recursively propagate again starting at the adjacent data point.
|
// if propagation succeeded, recursively propagate again starting at the adjacent data point.
|
||||||
recursivelyLightAdjacentDataPoints(chunk, airIDs, adjacentX, adjacentZ, adjacentDataPoint);
|
this.recursivelyLightAdjacentDataPoints(chunk, airIDs, adjacentX, adjacentZ, adjacentDataPoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.google.common.cache.CacheBuilder;
|
|||||||
import com.google.common.cache.RemovalCause;
|
import com.google.common.cache.RemovalCause;
|
||||||
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
||||||
import com.seibel.distanthorizons.core.config.Config;
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
import com.seibel.distanthorizons.core.file.fullDatafile.GeneratedFullDataSourceProvider;
|
import com.seibel.distanthorizons.core.file.fullDatafile.GeneratedFullDataSourceProvider;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||||
@@ -12,6 +13,7 @@ import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D;
|
|||||||
import com.seibel.distanthorizons.core.util.FormatUtil;
|
import com.seibel.distanthorizons.core.util.FormatUtil;
|
||||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||||
import com.seibel.distanthorizons.core.util.objects.RollingAverage;
|
import com.seibel.distanthorizons.core.util.objects.RollingAverage;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -28,6 +30,8 @@ public class PregenManager
|
|||||||
{
|
{
|
||||||
protected static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
protected static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final IMinecraftSharedWrapper MC_SERVER = SingletonInjector.INSTANCE.get(IMinecraftSharedWrapper.class);
|
||||||
|
|
||||||
private final AtomicReference<PregenState> pregenFuture = new AtomicReference<>();
|
private final AtomicReference<PregenState> pregenFuture = new AtomicReference<>();
|
||||||
|
|
||||||
|
|
||||||
@@ -51,8 +55,11 @@ public class PregenManager
|
|||||||
pregenState.completeExceptionally(new IllegalStateException("Pregen is already running."));
|
pregenState.completeExceptionally(new IllegalStateException("Pregen is already running."));
|
||||||
return pregenState;
|
return pregenState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MC_SERVER.setPreventAutoPause(true);
|
||||||
pregenState.whenComplete((result, throwable) -> {
|
pregenState.whenComplete((result, throwable) -> {
|
||||||
this.pregenFuture.set(null);
|
this.pregenFuture.set(null);
|
||||||
|
MC_SERVER.setPreventAutoPause(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
pregenState.fillPendingQueue();
|
pregenState.fillPendingQueue();
|
||||||
@@ -104,7 +111,7 @@ public class PregenManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
long timeSincePreviousTaskFinish = System.currentTimeMillis() - this.lastTaskFinishTime.getAndSet(System.currentTimeMillis());
|
long timeSincePreviousTaskFinish = System.currentTimeMillis() - this.lastTaskFinishTime.getAndSet(System.currentTimeMillis());
|
||||||
this.averageTaskCompletionIntervalMs.addValue(timeSincePreviousTaskFinish);
|
this.averageTaskCompletionIntervalMs.add(timeSincePreviousTaskFinish);
|
||||||
|
|
||||||
PregenState.this.fillPendingQueue();
|
PregenState.this.fillPendingQueue();
|
||||||
})
|
})
|
||||||
|
|||||||
+1
-1
@@ -69,7 +69,7 @@ public class RemoteWorldRetrievalQueue extends AbstractFullDataNetworkRequestQue
|
|||||||
int chunkWidth = DhSectionPos.getChunkWidth(sectionPos);
|
int chunkWidth = DhSectionPos.getChunkWidth(sectionPos);
|
||||||
int chunkCount = chunkWidth * chunkWidth;
|
int chunkCount = chunkWidth * chunkWidth;
|
||||||
double timePerChunk = (double)totalGenTimeInMs / (double)chunkCount;
|
double timePerChunk = (double)totalGenTimeInMs / (double)chunkCount;
|
||||||
this.rollingAverageChunkGenTimeInMs.addValue(timePerChunk);
|
this.rollingAverageChunkGenTimeInMs.add(timePerChunk);
|
||||||
|
|
||||||
switch (requestResult)
|
switch (requestResult)
|
||||||
{
|
{
|
||||||
|
|||||||
+25
-23
@@ -40,6 +40,7 @@ import com.seibel.distanthorizons.core.config.Config;
|
|||||||
import com.seibel.distanthorizons.core.dataObjects.transformers.LodDataBuilder;
|
import com.seibel.distanthorizons.core.dataObjects.transformers.LodDataBuilder;
|
||||||
import com.seibel.distanthorizons.core.render.renderer.DebugRenderer;
|
import com.seibel.distanthorizons.core.render.renderer.DebugRenderer;
|
||||||
import com.seibel.distanthorizons.core.render.renderer.IDebugRenderable;
|
import com.seibel.distanthorizons.core.render.renderer.IDebugRenderable;
|
||||||
|
import com.seibel.distanthorizons.core.util.ExceptionUtil;
|
||||||
import com.seibel.distanthorizons.core.util.LodUtil.AssertFailureException;
|
import com.seibel.distanthorizons.core.util.LodUtil.AssertFailureException;
|
||||||
import com.seibel.distanthorizons.core.util.ThreadUtil;
|
import com.seibel.distanthorizons.core.util.ThreadUtil;
|
||||||
import com.seibel.distanthorizons.core.util.objects.DataCorruptedException;
|
import com.seibel.distanthorizons.core.util.objects.DataCorruptedException;
|
||||||
@@ -65,15 +66,6 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb
|
|||||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
private static final IWrapperFactory WRAPPER_FACTORY = SingletonInjector.INSTANCE.get(IWrapperFactory.class);
|
private static final IWrapperFactory WRAPPER_FACTORY = SingletonInjector.INSTANCE.get(IWrapperFactory.class);
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines how many tasks can be queued per thread. <br><br>
|
|
||||||
*
|
|
||||||
* TODO the multiplier here should change dynamically based on how fast the generator is vs the queuing thread,
|
|
||||||
* if this is too high it may cause issues when moving,
|
|
||||||
* but if it is too low the generator threads won't have enough tasks to work on
|
|
||||||
*/
|
|
||||||
private static final int MAX_QUEUED_TASKS_PER_THREAD = 3;
|
|
||||||
|
|
||||||
|
|
||||||
private final IDhApiWorldGenerator generator;
|
private final IDhApiWorldGenerator generator;
|
||||||
private final IDhServerLevel level;
|
private final IDhServerLevel level;
|
||||||
@@ -240,9 +232,9 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// queue more tasks if any of the threads are available
|
||||||
int worldGenThreadCount = Math.max(Config.Common.MultiThreading.numberOfThreads.get(), 1);
|
int worldGenThreadCount = Math.max(Config.Common.MultiThreading.numberOfThreads.get(), 1);
|
||||||
int maxWorldGenTaskCount = worldGenThreadCount * MAX_QUEUED_TASKS_PER_THREAD;
|
return this.inProgressGenTasksByLodPos.size() > worldGenThreadCount;
|
||||||
return executor.getQueueSize() > maxWorldGenTaskCount;
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @param targetPos the position to center the generation around
|
* @param targetPos the position to center the generation around
|
||||||
@@ -345,7 +337,7 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb
|
|||||||
long totalGenTimeInMs = System.currentTimeMillis() - generationStartMsTime;
|
long totalGenTimeInMs = System.currentTimeMillis() - generationStartMsTime;
|
||||||
int chunkCount = generationRequestChunkWidthCount * generationRequestChunkWidthCount;
|
int chunkCount = generationRequestChunkWidthCount * generationRequestChunkWidthCount;
|
||||||
double timePerChunk = (double)totalGenTimeInMs / (double)chunkCount;
|
double timePerChunk = (double)totalGenTimeInMs / (double)chunkCount;
|
||||||
this.rollingAverageChunkGenTimeInMs.addValue(timePerChunk);
|
this.rollingAverageChunkGenTimeInMs.add(timePerChunk);
|
||||||
});
|
});
|
||||||
|
|
||||||
newTaskGroup.genFuture = generationFuture;
|
newTaskGroup.genFuture = generationFuture;
|
||||||
@@ -358,7 +350,7 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb
|
|||||||
if (exception != null)
|
if (exception != null)
|
||||||
{
|
{
|
||||||
// don't log the shutdown exceptions
|
// don't log the shutdown exceptions
|
||||||
if (!LodUtil.isInterruptOrReject(exception))
|
if (!ExceptionUtil.isInterruptOrReject(exception))
|
||||||
{
|
{
|
||||||
LOGGER.error("Error generating data for pos: " + DhSectionPos.toString(taskPos), exception);
|
LOGGER.error("Error generating data for pos: " + DhSectionPos.toString(taskPos), exception);
|
||||||
}
|
}
|
||||||
@@ -412,11 +404,16 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb
|
|||||||
{
|
{
|
||||||
IChunkWrapper chunkWrapper = WRAPPER_FACTORY.createChunkWrapper(generatedObjectArray);
|
IChunkWrapper chunkWrapper = WRAPPER_FACTORY.createChunkWrapper(generatedObjectArray);
|
||||||
|
|
||||||
// TODO light data should be pulled (if possible) from the ChunkAccess object itself via ChunkFileReader.readLight
|
// only light the chunk here if necessary,
|
||||||
// but this should work for now
|
// lighting before this point is preferred but for potenial legacy API uses this
|
||||||
ArrayList<IChunkWrapper> nearbyChunkList = new ArrayList<IChunkWrapper>();
|
// check should be done
|
||||||
nearbyChunkList.add(chunkWrapper);
|
if (!chunkWrapper.isDhBlockLightingCorrect())
|
||||||
DhLightingEngine.INSTANCE.bakeChunkBlockLighting(chunkWrapper, nearbyChunkList, this.level.getLevelWrapper().hasSkyLight() ? LodUtil.MAX_MC_LIGHT : LodUtil.MIN_MC_LIGHT);
|
{
|
||||||
|
ArrayList<IChunkWrapper> nearbyChunkList = new ArrayList<>();
|
||||||
|
nearbyChunkList.add(chunkWrapper);
|
||||||
|
byte maxSkyLight = this.level.getLevelWrapper().hasSkyLight() ? LodUtil.MAX_MC_LIGHT : LodUtil.MIN_MC_LIGHT;
|
||||||
|
DhLightingEngine.INSTANCE.bakeChunkBlockLighting(chunkWrapper, nearbyChunkList, maxSkyLight);
|
||||||
|
}
|
||||||
|
|
||||||
try (FullDataSourceV2 dataSource = LodDataBuilder.createFromChunk(this.level.getLevelWrapper(), chunkWrapper))
|
try (FullDataSourceV2 dataSource = LodDataBuilder.createFromChunk(this.level.getLevelWrapper(), chunkWrapper))
|
||||||
{
|
{
|
||||||
@@ -596,9 +593,10 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb
|
|||||||
exception = exception.getCause();
|
exception = exception.getCause();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!UncheckedInterruptedException.isInterrupt(exception) && !(exception instanceof CancellationException))
|
if (!UncheckedInterruptedException.isInterrupt(exception)
|
||||||
|
&& !(exception instanceof CancellationException))
|
||||||
{
|
{
|
||||||
LOGGER.error("Error when terminating data generation for section " + runningTaskGroup.group.pos, exception);
|
LOGGER.error("Error when terminating data generation for pos: ["+DhSectionPos.toString(runningTaskGroup.group.pos)+"], error: ["+exception.getMessage()+"].", exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -623,13 +621,17 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb
|
|||||||
|
|
||||||
LOGGER.info("Shutting down world generator thread pool...");
|
LOGGER.info("Shutting down world generator thread pool...");
|
||||||
|
|
||||||
AbstractExecutorService executor = ThreadPoolUtil.getWorldGenExecutor();
|
PriorityTaskPicker.Executor executor = ThreadPoolUtil.getWorldGenExecutor();
|
||||||
if (executor != null)
|
if (executor != null)
|
||||||
{
|
{
|
||||||
List<Runnable> tasks = executor.shutdownNow();
|
int queueSize = executor.getQueueSize();
|
||||||
LOGGER.info("World generator thread pool shutdown with [" + tasks.size() + "] incomplete tasks.");
|
executor.clearQueue();
|
||||||
|
LOGGER.info("World generator thread pool shutdown with [" + queueSize + "] incomplete tasks.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.inProgressGenTasksByLodPos.values().forEach((inProgressWorldGenTaskGroup) -> inProgressWorldGenTaskGroup.genFuture.cancel(true));
|
||||||
|
this.waitingTasks.values().forEach((worldGenTask) -> worldGenTask.future.cancel(true));
|
||||||
|
|
||||||
|
|
||||||
this.generator.close();
|
this.generator.close();
|
||||||
DebugRenderer.unregister(this, Config.Client.Advanced.Debugging.DebugWireframe.showWorldGenQueue);
|
DebugRenderer.unregister(this, Config.Client.Advanced.Debugging.DebugWireframe.showWorldGenQueue);
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ public class JarMain
|
|||||||
{
|
{
|
||||||
repo = new FullDataSourceV2Repo(FullDataSourceV2Repo.DEFAULT_DATABASE_TYPE, dbFile);
|
repo = new FullDataSourceV2Repo(FullDataSourceV2Repo.DEFAULT_DATABASE_TYPE, dbFile);
|
||||||
}
|
}
|
||||||
catch (SQLException e)
|
catch (SQLException | IOException e)
|
||||||
{
|
{
|
||||||
LOGGER.error("Failed to initialize connection with database: ["+exportFile.getAbsolutePath()+"], error: ["+e.getMessage()+"].", e);
|
LOGGER.error("Failed to initialize connection with database: ["+exportFile.getAbsolutePath()+"], error: ["+e.getMessage()+"].", e);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ public class GitlabGetter
|
|||||||
/** Commit sha; Commit info */
|
/** Commit sha; Commit info */
|
||||||
private static final Map<String, Config> commitInfo = new HashMap<>();
|
private static final Map<String, Config> commitInfo = new HashMap<>();
|
||||||
/** Pipeline ID; Pipeline info */
|
/** Pipeline ID; Pipeline info */
|
||||||
private static final Map<Integer, ArrayList<Config>> pipelineInfo = new HashMap<>();
|
private static final Map<Number, ArrayList<Config>> pipelineInfo = new HashMap<>();
|
||||||
|
|
||||||
/** Uses our projectID to init this */
|
/** Uses our projectID to init this */
|
||||||
public GitlabGetter()
|
public GitlabGetter()
|
||||||
@@ -88,7 +88,7 @@ public class GitlabGetter
|
|||||||
return commitInfo.get(commit);
|
return commitInfo.get(commit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArrayList<Config> getPipelineInfo(int pipeline)
|
public ArrayList<Config> getPipelineInfo(Number pipeline)
|
||||||
{
|
{
|
||||||
if (!pipelineInfo.containsKey(pipeline))
|
if (!pipelineInfo.containsKey(pipeline))
|
||||||
{
|
{
|
||||||
@@ -111,9 +111,10 @@ public class GitlabGetter
|
|||||||
/**
|
/**
|
||||||
* Gets all the Minecraft download links to a pipeline ID
|
* Gets all the Minecraft download links to a pipeline ID
|
||||||
*
|
*
|
||||||
|
* @param pipelineID Uses {@link Number} instead of a specific value due to the possibility of receiving Integer or Long
|
||||||
* @return Minecraft version; Download URL
|
* @return Minecraft version; Download URL
|
||||||
*/
|
*/
|
||||||
public Map<String, URL> getDownloads(int pipelineID)
|
public Map<String, URL> getDownloads(Number pipelineID)
|
||||||
{
|
{
|
||||||
Map<String, URL> downloads = new HashMap<>();
|
Map<String, URL> downloads = new HashMap<>();
|
||||||
ArrayList<Config> currentPipelineInfo = this.getPipelineInfo(pipelineID);
|
ArrayList<Config> currentPipelineInfo = this.getPipelineInfo(pipelineID);
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -106,9 +107,9 @@ public abstract class AbstractDhLevel implements IDhLevel
|
|||||||
{
|
{
|
||||||
newChunkHashRepo = new ChunkHashRepo(AbstractDhRepo.DEFAULT_DATABASE_TYPE, databaseFile);
|
newChunkHashRepo = new ChunkHashRepo(AbstractDhRepo.DEFAULT_DATABASE_TYPE, databaseFile);
|
||||||
}
|
}
|
||||||
catch (SQLException e)
|
catch (SQLException | IOException e)
|
||||||
{
|
{
|
||||||
LOGGER.error("Unable to create [ChunkHashRepo], error: ["+e.getMessage()+"].", e);
|
LOGGER.fatal("Unable to create ["+ChunkHashRepo.class.getSimpleName()+"], error: ["+e.getMessage()+"].", e);
|
||||||
}
|
}
|
||||||
this.chunkHashRepo = newChunkHashRepo;
|
this.chunkHashRepo = newChunkHashRepo;
|
||||||
|
|
||||||
@@ -119,9 +120,9 @@ public abstract class AbstractDhLevel implements IDhLevel
|
|||||||
{
|
{
|
||||||
newBeaconBeamRepo = new BeaconBeamRepo(AbstractDhRepo.DEFAULT_DATABASE_TYPE, databaseFile);
|
newBeaconBeamRepo = new BeaconBeamRepo(AbstractDhRepo.DEFAULT_DATABASE_TYPE, databaseFile);
|
||||||
}
|
}
|
||||||
catch (SQLException e)
|
catch (SQLException | IOException e)
|
||||||
{
|
{
|
||||||
LOGGER.error("Unable to create [BeaconBeamRepo], error: ["+e.getMessage()+"].", e);
|
LOGGER.error("Unable to create ["+BeaconBeamRepo.class.getSimpleName()+"], error: ["+e.getMessage()+"].", e);
|
||||||
}
|
}
|
||||||
this.beaconBeamRepo = newBeaconBeamRepo;
|
this.beaconBeamRepo = newBeaconBeamRepo;
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-16
@@ -29,6 +29,8 @@ import com.seibel.distanthorizons.core.logging.DhLogger;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
@@ -48,23 +50,27 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I
|
|||||||
*/
|
*/
|
||||||
protected final ConcurrentLinkedQueue<IServerPlayerWrapper> worldGenPlayerCenteringQueue = new ConcurrentLinkedQueue<>();
|
protected final ConcurrentLinkedQueue<IServerPlayerWrapper> worldGenPlayerCenteringQueue = new ConcurrentLinkedQueue<>();
|
||||||
|
|
||||||
private final FullDataSourceRequestHandler requestHandler = new FullDataSourceRequestHandler(this);
|
private final FullDataSourceRequestHandler requestHandler;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=============//
|
//=============//
|
||||||
// constructor //
|
// constructor //
|
||||||
//=============//
|
//=============//
|
||||||
|
|
||||||
public AbstractDhServerLevel(ISaveStructure saveStructure, IServerLevelWrapper serverLevelWrapper, ServerPlayerStateManager serverPlayerStateManager)
|
public AbstractDhServerLevel(
|
||||||
{
|
ISaveStructure saveStructure,
|
||||||
this(saveStructure, serverLevelWrapper, serverPlayerStateManager, true);
|
IServerLevelWrapper serverLevelWrapper,
|
||||||
}
|
ServerPlayerStateManager serverPlayerStateManager
|
||||||
|
) throws SQLException, IOException
|
||||||
|
{ this(saveStructure, serverLevelWrapper, serverPlayerStateManager, true); }
|
||||||
|
|
||||||
public AbstractDhServerLevel(
|
public AbstractDhServerLevel(
|
||||||
ISaveStructure saveStructure,
|
ISaveStructure saveStructure,
|
||||||
IServerLevelWrapper serverLevelWrapper,
|
IServerLevelWrapper serverLevelWrapper,
|
||||||
ServerPlayerStateManager serverPlayerStateManager,
|
ServerPlayerStateManager serverPlayerStateManager,
|
||||||
boolean runRepoReliantSetup
|
boolean runRepoReliantSetup
|
||||||
)
|
) throws SQLException, IOException
|
||||||
{
|
{
|
||||||
if (saveStructure.getSaveFolder(serverLevelWrapper).mkdirs())
|
if (saveStructure.getSaveFolder(serverLevelWrapper).mkdirs())
|
||||||
{
|
{
|
||||||
@@ -81,6 +87,7 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I
|
|||||||
LOGGER.info("Started "+this.getClass().getSimpleName()+" for ["+serverLevelWrapper+"] at ["+saveStructure+"].");
|
LOGGER.info("Started "+this.getClass().getSimpleName()+" for ["+serverLevelWrapper+"] at ["+saveStructure+"].");
|
||||||
|
|
||||||
this.serverPlayerStateManager = serverPlayerStateManager;
|
this.serverPlayerStateManager = serverPlayerStateManager;
|
||||||
|
this.requestHandler = new FullDataSourceRequestHandler(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -89,12 +96,6 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I
|
|||||||
// ticks //
|
// ticks //
|
||||||
//=======//
|
//=======//
|
||||||
|
|
||||||
@Override
|
|
||||||
public void serverTick()
|
|
||||||
{
|
|
||||||
this.requestHandler.tick();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldDoWorldGen()
|
public boolean shouldDoWorldGen()
|
||||||
{ return Config.Common.WorldGenerator.enableDistantGeneration.get() && !this.worldGenPlayerCenteringQueue.isEmpty(); }
|
{ return Config.Common.WorldGenerator.enableDistantGeneration.get() && !this.worldGenPlayerCenteringQueue.isEmpty(); }
|
||||||
@@ -118,9 +119,6 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I
|
|||||||
return new DhBlockPos2D((int) position.x, (int) position.z);
|
return new DhBlockPos2D((int) position.x, (int) position.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void worldGenTick() { this.serverside.worldGenModule.worldGenTick(); }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==================//
|
//==================//
|
||||||
@@ -297,7 +295,7 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I
|
|||||||
public void addDebugMenuStringsToList(List<String> messageList)
|
public void addDebugMenuStringsToList(List<String> messageList)
|
||||||
{
|
{
|
||||||
this.serverside.fullDataFileHandler.addDebugMenuStringsToList(messageList);
|
this.serverside.fullDataFileHandler.addDebugMenuStringsToList(messageList);
|
||||||
this.serverside.worldGenModule.addDebugMenuStringsToList(messageList);
|
this.serverside.lodRequestModule.addDebugMenuStringsToList(messageList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -330,7 +328,10 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I
|
|||||||
{
|
{
|
||||||
super.close();
|
super.close();
|
||||||
this.serverside.close();
|
this.serverside.close();
|
||||||
|
this.requestHandler.close();
|
||||||
LOGGER.info("Closed DHLevel for [" + this.getLevelWrapper() + "].");
|
LOGGER.info("Closed DHLevel for [" + this.getLevelWrapper() + "].");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import javax.annotation.CheckForNull;
|
import javax.annotation.CheckForNull;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
@@ -83,7 +85,7 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
|
|||||||
.asMap()
|
.asMap()
|
||||||
);
|
);
|
||||||
|
|
||||||
public final WorldGenModule worldGenModule;
|
public final LodRequestModule lodRequestModule;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private final SyncOnLoadRequestQueue syncOnLoadRequestQueue;
|
private final SyncOnLoadRequestQueue syncOnLoadRequestQueue;
|
||||||
@@ -94,9 +96,18 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
|
|||||||
// constructor //
|
// constructor //
|
||||||
//=============//
|
//=============//
|
||||||
|
|
||||||
public DhClientLevel(ISaveStructure saveStructure, IClientLevelWrapper clientLevelWrapper, @Nullable ClientNetworkState networkState)
|
public DhClientLevel(
|
||||||
|
ISaveStructure saveStructure,
|
||||||
|
IClientLevelWrapper clientLevelWrapper,
|
||||||
|
@Nullable ClientNetworkState networkState
|
||||||
|
) throws SQLException, IOException
|
||||||
{ this(saveStructure, clientLevelWrapper, null, networkState); }
|
{ this(saveStructure, clientLevelWrapper, null, networkState); }
|
||||||
public DhClientLevel(ISaveStructure saveStructure, IClientLevelWrapper clientLevelWrapper, @Nullable File fullDataSaveDirOverride, @Nullable ClientNetworkState networkState)
|
public DhClientLevel(
|
||||||
|
ISaveStructure saveStructure,
|
||||||
|
IClientLevelWrapper clientLevelWrapper,
|
||||||
|
@Nullable File fullDataSaveDirOverride,
|
||||||
|
@Nullable ClientNetworkState networkState
|
||||||
|
) throws SQLException, IOException
|
||||||
{
|
{
|
||||||
File saveFolder = saveStructure.getSaveFolder(clientLevelWrapper);
|
File saveFolder = saveStructure.getSaveFolder(clientLevelWrapper);
|
||||||
File pre23Folder = saveStructure.getPre23SaveFolder(clientLevelWrapper);
|
File pre23Folder = saveStructure.getPre23SaveFolder(clientLevelWrapper);
|
||||||
@@ -131,7 +142,7 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.remoteDataSourceProvider = new RemoteFullDataSourceProvider(this, saveStructure, fullDataSaveDirOverride, this.syncOnLoadRequestQueue);
|
this.remoteDataSourceProvider = new RemoteFullDataSourceProvider(this, saveStructure, fullDataSaveDirOverride, this.syncOnLoadRequestQueue);
|
||||||
this.worldGenModule = new WorldGenModule(this, this.remoteDataSourceProvider, () -> new WorldGenState(this, networkState));
|
this.lodRequestModule = new LodRequestModule(this,this, this.remoteDataSourceProvider, () -> new LodRequestState(this, networkState));
|
||||||
|
|
||||||
this.clientside = new ClientLevelModule(this);
|
this.clientside = new ClientLevelModule(this);
|
||||||
|
|
||||||
@@ -239,11 +250,6 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
|
|||||||
@Nullable
|
@Nullable
|
||||||
public DhBlockPos2D getTargetPosForGeneration() { return new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()); }
|
public DhBlockPos2D getTargetPosForGeneration() { return new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()); }
|
||||||
|
|
||||||
@Override
|
|
||||||
public void worldGenTick() { this.worldGenModule.worldGenTick(); }
|
|
||||||
|
|
||||||
public void startRenderer() { this.clientside.startRenderer(); }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===========//
|
//===========//
|
||||||
@@ -325,7 +331,7 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
|
|||||||
|
|
||||||
|
|
||||||
// world gen
|
// world gen
|
||||||
this.worldGenModule.addDebugMenuStringsToList(messageList);
|
this.lodRequestModule.addDebugMenuStringsToList(messageList);
|
||||||
if (this.syncOnLoadRequestQueue != null)
|
if (this.syncOnLoadRequestQueue != null)
|
||||||
{
|
{
|
||||||
assert this.networkState != null;
|
assert this.networkState != null;
|
||||||
@@ -348,9 +354,9 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
|
|||||||
@Override
|
@Override
|
||||||
public void close()
|
public void close()
|
||||||
{
|
{
|
||||||
if (this.worldGenModule != null)
|
if (this.lodRequestModule != null)
|
||||||
{
|
{
|
||||||
this.worldGenModule.close();
|
this.lodRequestModule.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.networkEventSource != null)
|
if (this.networkEventSource != null)
|
||||||
@@ -371,11 +377,11 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
|
|||||||
// helper classes //
|
// helper classes //
|
||||||
//================//
|
//================//
|
||||||
|
|
||||||
private static class WorldGenState extends WorldGenModule.AbstractWorldGenState
|
private static class LodRequestState extends LodRequestModule.AbstractLodRequestState
|
||||||
{
|
{
|
||||||
WorldGenState(DhClientLevel level, ClientNetworkState networkState)
|
LodRequestState(DhClientLevel level, ClientNetworkState networkState)
|
||||||
{
|
{
|
||||||
this.worldGenerationQueue = new RemoteWorldRetrievalQueue(networkState, level);
|
this.retrievalQueue = new RemoteWorldRetrievalQueue(networkState, level);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapp
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/** The level used for a singleplayer world */
|
/** The level used for a singleplayer world */
|
||||||
@@ -48,7 +50,11 @@ public class DhClientServerLevel extends AbstractDhServerLevel implements IDhCli
|
|||||||
// constructor //
|
// constructor //
|
||||||
//=============//
|
//=============//
|
||||||
|
|
||||||
public DhClientServerLevel(ISaveStructure saveStructure, IServerLevelWrapper serverLevelWrapper, ServerPlayerStateManager serverPlayerStateManager)
|
public DhClientServerLevel(
|
||||||
|
ISaveStructure saveStructure,
|
||||||
|
IServerLevelWrapper serverLevelWrapper,
|
||||||
|
ServerPlayerStateManager serverPlayerStateManager
|
||||||
|
) throws SQLException, IOException
|
||||||
{
|
{
|
||||||
super(saveStructure, serverLevelWrapper, serverPlayerStateManager, false);
|
super(saveStructure, serverLevelWrapper, serverPlayerStateManager, false);
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ import com.seibel.distanthorizons.core.render.renderer.generic.GenericObjectRend
|
|||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class DhServerLevel extends AbstractDhServerLevel
|
public class DhServerLevel extends AbstractDhServerLevel
|
||||||
@@ -35,10 +37,12 @@ public class DhServerLevel extends AbstractDhServerLevel
|
|||||||
// constructor //
|
// constructor //
|
||||||
//=============//
|
//=============//
|
||||||
|
|
||||||
public DhServerLevel(ISaveStructure saveStructure, IServerLevelWrapper serverLevelWrapper, ServerPlayerStateManager serverPlayerStateManager)
|
public DhServerLevel(
|
||||||
{
|
ISaveStructure saveStructure,
|
||||||
super(saveStructure, serverLevelWrapper, serverPlayerStateManager);
|
IServerLevelWrapper serverLevelWrapper,
|
||||||
}
|
ServerPlayerStateManager serverPlayerStateManager
|
||||||
|
) throws SQLException, IOException
|
||||||
|
{ super(saveStructure, serverLevelWrapper, serverPlayerStateManager); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -56,9 +56,6 @@ import java.util.concurrent.CompletableFuture;
|
|||||||
*/
|
*/
|
||||||
public interface IDhLevel extends AutoCloseable, GeneratedFullDataSourceProvider.IOnWorldGenCompleteListener
|
public interface IDhLevel extends AutoCloseable, GeneratedFullDataSourceProvider.IOnWorldGenCompleteListener
|
||||||
{
|
{
|
||||||
@Deprecated
|
|
||||||
void worldGenTick();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* May return either a client or server level wrapper. <br>
|
* May return either a client or server level wrapper. <br>
|
||||||
* Should not return null
|
* Should not return null
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapp
|
|||||||
|
|
||||||
public interface IDhServerLevel extends IDhLevel
|
public interface IDhServerLevel extends IDhLevel
|
||||||
{
|
{
|
||||||
void serverTick();
|
|
||||||
|
|
||||||
IServerLevelWrapper getServerLevelWrapper();
|
IServerLevelWrapper getServerLevelWrapper();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+106
-77
@@ -45,18 +45,18 @@ import java.util.function.Supplier;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles both single-player/server-side world gen and client side LOD requests.
|
* Handles both single-player/server-side world gen and client side LOD requests.
|
||||||
* TODO rename
|
|
||||||
*/
|
*/
|
||||||
public class WorldGenModule implements Closeable
|
public class LodRequestModule implements Closeable
|
||||||
{
|
{
|
||||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
private final GeneratedFullDataSourceProvider.IOnWorldGenCompleteListener onWorldGenCompleteListener;
|
private final GeneratedFullDataSourceProvider.IOnWorldGenCompleteListener onWorldGenCompleteListener;
|
||||||
|
private final ThreadPoolExecutor tickerThread;
|
||||||
|
|
||||||
private final GeneratedFullDataSourceProvider dataSourceProvider;
|
private final GeneratedFullDataSourceProvider dataSourceProvider;
|
||||||
private final Supplier<? extends AbstractWorldGenState> worldGenStateSupplier;
|
private final Supplier<? extends AbstractLodRequestState> worldGenStateSupplier;
|
||||||
|
|
||||||
private final AtomicReference<AbstractWorldGenState> worldGenStateRef = new AtomicReference<>();
|
private final AtomicReference<AbstractLodRequestState> lodRequestStateRef = new AtomicReference<>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -64,59 +64,41 @@ public class WorldGenModule implements Closeable
|
|||||||
// constructor //
|
// constructor //
|
||||||
//=============//
|
//=============//
|
||||||
|
|
||||||
public WorldGenModule(
|
public LodRequestModule(
|
||||||
|
IDhLevel level,
|
||||||
GeneratedFullDataSourceProvider.IOnWorldGenCompleteListener onWorldGenCompleteListener,
|
GeneratedFullDataSourceProvider.IOnWorldGenCompleteListener onWorldGenCompleteListener,
|
||||||
GeneratedFullDataSourceProvider dataSourceProvider,
|
GeneratedFullDataSourceProvider dataSourceProvider,
|
||||||
Supplier<? extends AbstractWorldGenState> worldGenStateSupplier
|
Supplier<? extends AbstractLodRequestState> worldGenStateSupplier
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.onWorldGenCompleteListener = onWorldGenCompleteListener;
|
this.onWorldGenCompleteListener = onWorldGenCompleteListener;
|
||||||
this.dataSourceProvider = dataSourceProvider;
|
this.dataSourceProvider = dataSourceProvider;
|
||||||
this.worldGenStateSupplier = worldGenStateSupplier;
|
this.worldGenStateSupplier = worldGenStateSupplier;
|
||||||
|
|
||||||
|
String levelId = level.getLevelWrapper().getDhIdentifier();
|
||||||
|
this.tickerThread = ThreadUtil.makeSingleDaemonThreadPool("Request Module Ticker ["+levelId+"]");
|
||||||
|
this.tickerThread.execute(this::tickLoop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===================//
|
//=========//
|
||||||
// world gen control //
|
// ticking //
|
||||||
//===================//
|
//=========//
|
||||||
|
|
||||||
public void startWorldGen(GeneratedFullDataSourceProvider dataFileHandler, AbstractWorldGenState newWgs)
|
private void tickLoop()
|
||||||
{
|
{
|
||||||
// create the new world generator
|
try
|
||||||
if (!this.worldGenStateRef.compareAndSet(null, newWgs))
|
|
||||||
{
|
{
|
||||||
LOGGER.warn("Failed to start world gen due to concurrency");
|
while (!Thread.interrupted())
|
||||||
newWgs.closeAsync(false);
|
|
||||||
}
|
|
||||||
dataFileHandler.addWorldGenCompleteListener(this.onWorldGenCompleteListener);
|
|
||||||
dataFileHandler.setWorldGenerationQueue(newWgs.worldGenerationQueue);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stopWorldGen(GeneratedFullDataSourceProvider dataFileHandler)
|
|
||||||
{
|
|
||||||
AbstractWorldGenState worldGenState = this.worldGenStateRef.get();
|
|
||||||
if (worldGenState == null)
|
|
||||||
{
|
|
||||||
LOGGER.warn("Attempted to stop world gen when it was not running");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// shut down the world generator
|
|
||||||
while (!this.worldGenStateRef.compareAndSet(worldGenState, null))
|
|
||||||
{
|
|
||||||
worldGenState = this.worldGenStateRef.get();
|
|
||||||
if (worldGenState == null)
|
|
||||||
{
|
{
|
||||||
return;
|
Thread.sleep(20);
|
||||||
|
this.tick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dataFileHandler.clearRetrievalQueue();
|
catch (InterruptedException ignore) { }
|
||||||
worldGenState.closeAsync(true).join(); //TODO: Make it async.
|
|
||||||
dataFileHandler.removeWorldGenCompleteListener(this.onWorldGenCompleteListener);
|
|
||||||
}
|
}
|
||||||
|
private void tick()
|
||||||
public void worldGenTick()
|
|
||||||
{
|
{
|
||||||
boolean shouldDoWorldGen = this.onWorldGenCompleteListener.shouldDoWorldGen();
|
boolean shouldDoWorldGen = this.onWorldGenCompleteListener.shouldDoWorldGen();
|
||||||
// if the world is read only don't generate anything
|
// if the world is read only don't generate anything
|
||||||
@@ -136,13 +118,13 @@ public class WorldGenModule implements Closeable
|
|||||||
|
|
||||||
if (this.isWorldGenRunning())
|
if (this.isWorldGenRunning())
|
||||||
{
|
{
|
||||||
AbstractWorldGenState worldGenState = this.worldGenStateRef.get();
|
AbstractLodRequestState lodRequestState = this.lodRequestStateRef.get();
|
||||||
if (worldGenState != null)
|
if (lodRequestState != null)
|
||||||
{
|
{
|
||||||
DhBlockPos2D targetPosForGeneration = this.onWorldGenCompleteListener.getTargetPosForGeneration();
|
DhBlockPos2D targetPosForGeneration = this.onWorldGenCompleteListener.getTargetPosForGeneration();
|
||||||
if (targetPosForGeneration != null)
|
if (targetPosForGeneration != null)
|
||||||
{
|
{
|
||||||
worldGenState.startGenerationQueueAndSetTargetPos(targetPosForGeneration);
|
lodRequestState.startRequestQueueAndSetTargetPos(targetPosForGeneration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,6 +132,48 @@ public class WorldGenModule implements Closeable
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===================//
|
||||||
|
// world gen control //
|
||||||
|
//===================//
|
||||||
|
|
||||||
|
public void startWorldGen(GeneratedFullDataSourceProvider dataFileHandler, AbstractLodRequestState newWgs)
|
||||||
|
{
|
||||||
|
// create the new world generator
|
||||||
|
if (!this.lodRequestStateRef.compareAndSet(null, newWgs))
|
||||||
|
{
|
||||||
|
LOGGER.warn("Failed to start world gen due to concurrency");
|
||||||
|
newWgs.closeAsync(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
dataFileHandler.addWorldGenCompleteListener(this.onWorldGenCompleteListener);
|
||||||
|
dataFileHandler.setWorldGenerationQueue(newWgs.retrievalQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopWorldGen(GeneratedFullDataSourceProvider dataFileHandler)
|
||||||
|
{
|
||||||
|
AbstractLodRequestState worldGenState = this.lodRequestStateRef.get();
|
||||||
|
if (worldGenState == null)
|
||||||
|
{
|
||||||
|
LOGGER.warn("Attempted to stop world gen when it was not running");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// shut down the world generator
|
||||||
|
while (!this.lodRequestStateRef.compareAndSet(worldGenState, null))
|
||||||
|
{
|
||||||
|
worldGenState = this.lodRequestStateRef.get();
|
||||||
|
if (worldGenState == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dataFileHandler.clearRetrievalQueue();
|
||||||
|
worldGenState.closeAsync(true).join(); //TODO: Make it async.
|
||||||
|
dataFileHandler.removeWorldGenCompleteListener(this.onWorldGenCompleteListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=======================//
|
//=======================//
|
||||||
// base method overrides //
|
// base method overrides //
|
||||||
//=======================//
|
//=======================//
|
||||||
@@ -157,13 +181,15 @@ public class WorldGenModule implements Closeable
|
|||||||
@Override
|
@Override
|
||||||
public void close()
|
public void close()
|
||||||
{
|
{
|
||||||
|
this.tickerThread.shutdownNow();
|
||||||
|
|
||||||
// shutdown the world-gen
|
// shutdown the world-gen
|
||||||
AbstractWorldGenState worldGenState = this.worldGenStateRef.get();
|
AbstractLodRequestState worldGenState = this.lodRequestStateRef.get();
|
||||||
if (worldGenState != null)
|
if (worldGenState != null)
|
||||||
{
|
{
|
||||||
while (!this.worldGenStateRef.compareAndSet(worldGenState, null))
|
while (!this.lodRequestStateRef.compareAndSet(worldGenState, null))
|
||||||
{
|
{
|
||||||
worldGenState = this.worldGenStateRef.get();
|
worldGenState = this.lodRequestStateRef.get();
|
||||||
if (worldGenState == null)
|
if (worldGenState == null)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
@@ -183,12 +209,12 @@ public class WorldGenModule implements Closeable
|
|||||||
// getters //
|
// getters //
|
||||||
//=========//
|
//=========//
|
||||||
|
|
||||||
public boolean isWorldGenRunning() { return this.worldGenStateRef.get() != null; }
|
public boolean isWorldGenRunning() { return this.lodRequestStateRef.get() != null; }
|
||||||
|
|
||||||
/** mutates a list so it can be added to an existing {@link IDhLevel}'s debug list */
|
/** mutates a list so it can be added to an existing {@link IDhLevel}'s debug list */
|
||||||
public void addDebugMenuStringsToList(List<String> messageList)
|
public void addDebugMenuStringsToList(List<String> messageList)
|
||||||
{
|
{
|
||||||
AbstractWorldGenState worldGenState = this.worldGenStateRef.get();
|
AbstractLodRequestState worldGenState = this.lodRequestStateRef.get();
|
||||||
if (worldGenState == null)
|
if (worldGenState == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -196,9 +222,9 @@ public class WorldGenModule implements Closeable
|
|||||||
|
|
||||||
|
|
||||||
// estimated tasks
|
// estimated tasks
|
||||||
String waitingCountStr = F3Screen.NUMBER_FORMAT.format(worldGenState.worldGenerationQueue.getWaitingTaskCount());
|
String waitingCountStr = F3Screen.NUMBER_FORMAT.format(worldGenState.retrievalQueue.getWaitingTaskCount());
|
||||||
String inProgressCountStr = F3Screen.NUMBER_FORMAT.format(worldGenState.worldGenerationQueue.getInProgressTaskCount());
|
String inProgressCountStr = F3Screen.NUMBER_FORMAT.format(worldGenState.retrievalQueue.getInProgressTaskCount());
|
||||||
String totalCountEstimateStr = F3Screen.NUMBER_FORMAT.format(worldGenState.worldGenerationQueue.getRetrievalEstimatedRemainingChunkCount());
|
String totalCountEstimateStr = F3Screen.NUMBER_FORMAT.format(worldGenState.retrievalQueue.getRetrievalEstimatedRemainingChunkCount());
|
||||||
String message = "World Gen/Import Tasks: "+waitingCountStr+"/"+totalCountEstimateStr+" (in progress "+inProgressCountStr+")";
|
String message = "World Gen/Import Tasks: "+waitingCountStr+"/"+totalCountEstimateStr+" (in progress "+inProgressCountStr+")";
|
||||||
|
|
||||||
// estimated chunks/sec
|
// estimated chunks/sec
|
||||||
@@ -210,7 +236,7 @@ public class WorldGenModule implements Closeable
|
|||||||
|
|
||||||
messageList.add(message);
|
messageList.add(message);
|
||||||
|
|
||||||
worldGenState.worldGenerationQueue.addDebugMenuStringsToList(messageList);
|
worldGenState.retrievalQueue.addDebugMenuStringsToList(messageList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -220,40 +246,22 @@ public class WorldGenModule implements Closeable
|
|||||||
//================//
|
//================//
|
||||||
|
|
||||||
/** Handles the {@link IFullDataSourceRetrievalQueue} and any other necessary world gen information. */
|
/** Handles the {@link IFullDataSourceRetrievalQueue} and any other necessary world gen information. */
|
||||||
public static abstract class AbstractWorldGenState
|
public static abstract class AbstractLodRequestState
|
||||||
{
|
{
|
||||||
/** static so we only send the disable message once per session */
|
/** static so we only send the disable message once per session */
|
||||||
private static long firstProgressMessageSentMs = 0;
|
private static long firstProgressMessageSentMs = 0;
|
||||||
|
|
||||||
public IFullDataSourceRetrievalQueue worldGenerationQueue;
|
public IFullDataSourceRetrievalQueue retrievalQueue;
|
||||||
|
|
||||||
private static final ThreadPoolExecutor PROGRESS_UPDATER_THREAD = ThreadUtil.makeSingleDaemonThreadPool("World Gen Progress Updater");
|
private static final ThreadPoolExecutor PROGRESS_UPDATER_THREAD = ThreadUtil.makeSingleDaemonThreadPool("World Gen Progress Updater");
|
||||||
private boolean progressUpdateThreadRunning = false;
|
private boolean progressUpdateThreadRunning = false;
|
||||||
|
|
||||||
|
|
||||||
CompletableFuture<Void> closeAsync(boolean doInterrupt)
|
|
||||||
{
|
|
||||||
// this should stop the updater thread
|
|
||||||
this.progressUpdateThreadRunning = false;
|
|
||||||
|
|
||||||
return this.worldGenerationQueue.startClosingAsync(true, doInterrupt)
|
/** @param targetPosForRequest the position that world generation should be centered around */
|
||||||
.exceptionally(e ->
|
public void startRequestQueueAndSetTargetPos(DhBlockPos2D targetPosForRequest)
|
||||||
{
|
|
||||||
LOGGER.error("Error during first stage of generation queue shutdown, Error: ["+e.getMessage()+"].", e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
).thenRun(this.worldGenerationQueue::close)
|
|
||||||
.exceptionally(e ->
|
|
||||||
{
|
|
||||||
LOGGER.error("Error during second stage of generation queue shutdown, Error: ["+e.getMessage()+"].", e);
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param targetPosForGeneration the position that world generation should be centered around */
|
|
||||||
public void startGenerationQueueAndSetTargetPos(DhBlockPos2D targetPosForGeneration)
|
|
||||||
{
|
{
|
||||||
this.worldGenerationQueue.startAndSetTargetPos(targetPosForGeneration);
|
this.retrievalQueue.startAndSetTargetPos(targetPosForRequest);
|
||||||
this.startProgressUpdateThread();
|
this.startProgressUpdateThread();
|
||||||
}
|
}
|
||||||
private void startProgressUpdateThread()
|
private void startProgressUpdateThread()
|
||||||
@@ -286,8 +294,8 @@ public class WorldGenModule implements Closeable
|
|||||||
private void sendRetrievalProgress()
|
private void sendRetrievalProgress()
|
||||||
{
|
{
|
||||||
// format the remaining chunks
|
// format the remaining chunks
|
||||||
int remainingChunkCount = this.worldGenerationQueue.getRetrievalEstimatedRemainingChunkCount();
|
int remainingChunkCount = this.retrievalQueue.getRetrievalEstimatedRemainingChunkCount();
|
||||||
remainingChunkCount += this.worldGenerationQueue.getQueuedChunkCount();
|
remainingChunkCount += this.retrievalQueue.getQueuedChunkCount();
|
||||||
String remainingChunkCountStr = F3Screen.NUMBER_FORMAT.format(remainingChunkCount);
|
String remainingChunkCountStr = F3Screen.NUMBER_FORMAT.format(remainingChunkCount);
|
||||||
|
|
||||||
String message = "DH is generating chunks. " + remainingChunkCountStr + " left.";
|
String message = "DH is generating chunks. " + remainingChunkCountStr + " left.";
|
||||||
@@ -350,7 +358,7 @@ public class WorldGenModule implements Closeable
|
|||||||
/** @return -1 if this method isn't supported or available */
|
/** @return -1 if this method isn't supported or available */
|
||||||
public double getEstimatedChunksPerSecond()
|
public double getEstimatedChunksPerSecond()
|
||||||
{
|
{
|
||||||
RollingAverage avg = this.worldGenerationQueue.getRollingAverageChunkGenTimeInMs();
|
RollingAverage avg = this.retrievalQueue.getRollingAverageChunkGenTimeInMs();
|
||||||
if (avg == null)
|
if (avg == null)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
@@ -373,6 +381,27 @@ public class WorldGenModule implements Closeable
|
|||||||
return chunksPerSecond;
|
return chunksPerSecond;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CompletableFuture<Void> closeAsync(boolean doInterrupt)
|
||||||
|
{
|
||||||
|
// this should stop the updater thread
|
||||||
|
this.progressUpdateThreadRunning = false;
|
||||||
|
|
||||||
|
return this.retrievalQueue.startClosingAsync(true, doInterrupt)
|
||||||
|
.exceptionally(e ->
|
||||||
|
{
|
||||||
|
LOGGER.error("Error during first stage of generation queue shutdown, Error: ["+e.getMessage()+"].", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
).thenRun(this.retrievalQueue::close)
|
||||||
|
.exceptionally(e ->
|
||||||
|
{
|
||||||
|
LOGGER.error("Error during second stage of generation queue shutdown, Error: ["+e.getMessage()+"].", e);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -28,6 +28,9 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
|||||||
import com.seibel.distanthorizons.coreapi.DependencyInjection.WorldGeneratorInjector;
|
import com.seibel.distanthorizons.coreapi.DependencyInjection.WorldGeneratorInjector;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
public class ServerLevelModule implements AutoCloseable
|
public class ServerLevelModule implements AutoCloseable
|
||||||
{
|
{
|
||||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
@@ -36,7 +39,7 @@ public class ServerLevelModule implements AutoCloseable
|
|||||||
public final ISaveStructure saveStructure;
|
public final ISaveStructure saveStructure;
|
||||||
public final GeneratedFullDataSourceProvider fullDataFileHandler;
|
public final GeneratedFullDataSourceProvider fullDataFileHandler;
|
||||||
|
|
||||||
public final WorldGenModule worldGenModule;
|
public final LodRequestModule lodRequestModule;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -44,12 +47,12 @@ public class ServerLevelModule implements AutoCloseable
|
|||||||
// constructor //
|
// constructor //
|
||||||
//=============//
|
//=============//
|
||||||
|
|
||||||
public ServerLevelModule(IDhServerLevel parentServerLevel, ISaveStructure saveStructure)
|
public ServerLevelModule(IDhServerLevel parentServerLevel, ISaveStructure saveStructure) throws SQLException, IOException
|
||||||
{
|
{
|
||||||
this.parentServerLevel = parentServerLevel;
|
this.parentServerLevel = parentServerLevel;
|
||||||
this.saveStructure = saveStructure;
|
this.saveStructure = saveStructure;
|
||||||
this.fullDataFileHandler = new GeneratedFullDataSourceProvider(parentServerLevel, saveStructure);
|
this.fullDataFileHandler = new GeneratedFullDataSourceProvider(parentServerLevel, saveStructure);
|
||||||
this.worldGenModule = new WorldGenModule(this.parentServerLevel, this.fullDataFileHandler, () -> new ServerLevelModule.WorldGenState(this.parentServerLevel));
|
this.lodRequestModule = new LodRequestModule(this.parentServerLevel, this.parentServerLevel, this.fullDataFileHandler, () -> new LodRequestState(this.parentServerLevel));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -62,7 +65,7 @@ public class ServerLevelModule implements AutoCloseable
|
|||||||
public void close()
|
public void close()
|
||||||
{
|
{
|
||||||
// shutdown the world-gen
|
// shutdown the world-gen
|
||||||
this.worldGenModule.close();
|
this.lodRequestModule.close();
|
||||||
this.fullDataFileHandler.close();
|
this.fullDataFileHandler.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,9 +75,9 @@ public class ServerLevelModule implements AutoCloseable
|
|||||||
// helper classes //
|
// helper classes //
|
||||||
//================//
|
//================//
|
||||||
|
|
||||||
public static class WorldGenState extends WorldGenModule.AbstractWorldGenState
|
public static class LodRequestState extends LodRequestModule.AbstractLodRequestState
|
||||||
{
|
{
|
||||||
WorldGenState(IDhServerLevel level)
|
LodRequestState(IDhServerLevel level)
|
||||||
{
|
{
|
||||||
IDhApiWorldGenerator worldGenerator = WorldGeneratorInjector.INSTANCE.get(level.getLevelWrapper());
|
IDhApiWorldGenerator worldGenerator = WorldGeneratorInjector.INSTANCE.get(level.getLevelWrapper());
|
||||||
if (worldGenerator == null)
|
if (worldGenerator == null)
|
||||||
@@ -85,7 +88,7 @@ public class ServerLevelModule implements AutoCloseable
|
|||||||
// since core world generator's should have the lowest override priority
|
// since core world generator's should have the lowest override priority
|
||||||
WorldGeneratorInjector.INSTANCE.bind(level.getLevelWrapper(), worldGenerator);
|
WorldGeneratorInjector.INSTANCE.bind(level.getLevelWrapper(), worldGenerator);
|
||||||
}
|
}
|
||||||
this.worldGenerationQueue = new WorldGenerationQueue(worldGenerator, level);
|
this.retrievalQueue = new WorldGenerationQueue(worldGenerator, level);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+90
-47
@@ -14,6 +14,7 @@ import com.seibel.distanthorizons.core.network.messages.fullData.FullDataSourceR
|
|||||||
import com.seibel.distanthorizons.core.network.messages.fullData.FullDataSourceResponseMessage;
|
import com.seibel.distanthorizons.core.network.messages.fullData.FullDataSourceResponseMessage;
|
||||||
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||||
import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO;
|
import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO;
|
||||||
|
import com.seibel.distanthorizons.core.util.ThreadUtil;
|
||||||
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
|
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -21,7 +22,7 @@ import java.util.Map;
|
|||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
public class FullDataSourceRequestHandler
|
public class FullDataSourceRequestHandler implements AutoCloseable
|
||||||
{
|
{
|
||||||
private static final DhLogger LOGGER = new DhLoggerBuilder()
|
private static final DhLogger LOGGER = new DhLoggerBuilder()
|
||||||
.fileLevelConfig(Config.Common.Logging.logNetworkEventToFile)
|
.fileLevelConfig(Config.Common.Logging.logNetworkEventToFile)
|
||||||
@@ -29,6 +30,8 @@ public class FullDataSourceRequestHandler
|
|||||||
|
|
||||||
|
|
||||||
private final AbstractDhServerLevel serverLevel;
|
private final AbstractDhServerLevel serverLevel;
|
||||||
|
private final ThreadPoolExecutor tickerThread;
|
||||||
|
|
||||||
private String getLevelIdentifier() { return this.serverLevel.getLevelWrapper().getDhIdentifier(); }
|
private String getLevelIdentifier() { return this.serverLevel.getLevelWrapper().getDhIdentifier(); }
|
||||||
private GeneratedFullDataSourceProvider fullDataSourceProvider() { return this.serverLevel.serverside.fullDataFileHandler; }
|
private GeneratedFullDataSourceProvider fullDataSourceProvider() { return this.serverLevel.serverside.fullDataFileHandler; }
|
||||||
private List<BeaconBeamDTO> getAllBeamsForPos(long pos) { return this.serverLevel.beaconBeamRepo.getAllBeamsForPos(pos); }
|
private List<BeaconBeamDTO> getAllBeamsForPos(long pos) { return this.serverLevel.beaconBeamRepo.getAllBeamsForPos(pos); }
|
||||||
@@ -37,12 +40,22 @@ public class FullDataSourceRequestHandler
|
|||||||
private final ConcurrentMap<Long, DataSourceRequestGroup> requestGroupsByFutureId = new ConcurrentHashMap<>();
|
private final ConcurrentMap<Long, DataSourceRequestGroup> requestGroupsByFutureId = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
public FullDataSourceRequestHandler(AbstractDhServerLevel serverLevel)
|
public FullDataSourceRequestHandler(AbstractDhServerLevel serverLevel)
|
||||||
{
|
{
|
||||||
this.serverLevel = serverLevel;
|
this.serverLevel = serverLevel;
|
||||||
|
|
||||||
|
String levelId = this.serverLevel.getServerLevelWrapper().getDhIdentifier();
|
||||||
|
this.tickerThread = ThreadUtil.makeSingleDaemonThreadPool("DataSource Request Ticker ["+levelId+"]");
|
||||||
|
this.tickerThread.execute(this::tickLoop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==================//
|
//==================//
|
||||||
// network handling //
|
// network handling //
|
||||||
//==================//
|
//==================//
|
||||||
@@ -214,52 +227,6 @@ public class FullDataSourceRequestHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void tick()
|
|
||||||
{
|
|
||||||
// Send finished data source requests
|
|
||||||
for (Map.Entry<Long, DataSourceRequestGroup> entry : this.requestGroupsByPos.entrySet())
|
|
||||||
{
|
|
||||||
DataSourceRequestGroup requestGroup = entry.getValue();
|
|
||||||
|
|
||||||
if (requestGroup.fullDataSource == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGGER.debug("[" + this.getLevelIdentifier() + "] Fulfilled request group [" + DhSectionPos.toString(entry.getKey()) + "]");
|
|
||||||
|
|
||||||
// Make this group unavailable for adding into
|
|
||||||
this.requestGroupsByPos.remove(entry.getKey());
|
|
||||||
if (!requestGroup.tryClose())
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
AbstractExecutorService executor = ThreadPoolUtil.getNetworkCompressionExecutor();
|
|
||||||
if (executor == null)
|
|
||||||
{
|
|
||||||
LOGGER.warn("Unable to send FullDataSourceResponseMessage - getNetworkCompressionExecutor() is null");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
CompletableFuture.runAsync(() ->
|
|
||||||
{
|
|
||||||
FullDataPayload payload = new FullDataPayload(requestGroup.fullDataSource, this.getAllBeamsForPos(entry.getKey()));
|
|
||||||
requestGroup.fullDataSource.close();
|
|
||||||
|
|
||||||
for (DataSourceRequestGroup.RequestData requestData : requestGroup.requestMessages.values())
|
|
||||||
{
|
|
||||||
this.requestGroupsByFutureId.remove(requestData.futureId());
|
|
||||||
|
|
||||||
requestData.serverPlayerState.fullDataPayloadSender.sendInChunks(payload, () -> {
|
|
||||||
requestData.message.sendResponse(new FullDataSourceResponseMessage(payload));
|
|
||||||
requestData.rateLimiterSet.generationRequestRateLimiter.release();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, executor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void tryFulfillDataSourceRequestGroup(DataSourceRequestGroup requestGroup, long pos)
|
private void tryFulfillDataSourceRequestGroup(DataSourceRequestGroup requestGroup, long pos)
|
||||||
{
|
{
|
||||||
this.fullDataSourceProvider().getAsync(pos).thenAccept(fullDataSource ->
|
this.fullDataSourceProvider().getAsync(pos).thenAccept(fullDataSource ->
|
||||||
@@ -313,4 +280,80 @@ public class FullDataSourceRequestHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// ticking //
|
||||||
|
//=========//
|
||||||
|
|
||||||
|
private void tickLoop()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (!Thread.interrupted())
|
||||||
|
{
|
||||||
|
Thread.sleep(20);
|
||||||
|
this.tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (InterruptedException ignore) { }
|
||||||
|
}
|
||||||
|
private void tick()
|
||||||
|
{
|
||||||
|
// Send finished data source requests
|
||||||
|
for (Map.Entry<Long, DataSourceRequestGroup> entry : this.requestGroupsByPos.entrySet())
|
||||||
|
{
|
||||||
|
DataSourceRequestGroup requestGroup = entry.getValue();
|
||||||
|
if (requestGroup.fullDataSource == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.debug("[" + this.getLevelIdentifier() + "] Fulfilled request group [" + DhSectionPos.toString(entry.getKey()) + "]");
|
||||||
|
|
||||||
|
// Make this group unavailable for adding into
|
||||||
|
this.requestGroupsByPos.remove(entry.getKey());
|
||||||
|
if (!requestGroup.tryClose())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractExecutorService executor = ThreadPoolUtil.getNetworkCompressionExecutor();
|
||||||
|
if (executor == null)
|
||||||
|
{
|
||||||
|
LOGGER.warn("Unable to send FullDataSourceResponseMessage - getNetworkCompressionExecutor() is null");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
CompletableFuture.runAsync(() ->
|
||||||
|
{
|
||||||
|
FullDataPayload payload = new FullDataPayload(requestGroup.fullDataSource, this.getAllBeamsForPos(entry.getKey()));
|
||||||
|
requestGroup.fullDataSource.close();
|
||||||
|
|
||||||
|
for (DataSourceRequestGroup.RequestData requestData : requestGroup.requestMessages.values())
|
||||||
|
{
|
||||||
|
this.requestGroupsByFutureId.remove(requestData.futureId());
|
||||||
|
|
||||||
|
requestData.serverPlayerState.fullDataPayloadSender.sendInChunks(payload, () -> {
|
||||||
|
requestData.message.sendResponse(new FullDataSourceResponseMessage(payload));
|
||||||
|
requestData.rateLimiterSet.generationRequestRateLimiter.release();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, executor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
this.tickerThread.shutdownNow();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -182,7 +182,8 @@ public class PhantomArrayListPool
|
|||||||
"Potential causes: \n" +
|
"Potential causes: \n" +
|
||||||
"1. your allocated memory isn't high enough \n" +
|
"1. your allocated memory isn't high enough \n" +
|
||||||
"2. your DH CPU preset is too high \n" +
|
"2. your DH CPU preset is too high \n" +
|
||||||
"3. your DH quality preset is too high";
|
"3. your DH quality preset is too high \n" +
|
||||||
|
"4. you have other memory hungry mod(s)";
|
||||||
|
|
||||||
LOGGER.warn(message);
|
LOGGER.warn(message);
|
||||||
if (Config.Common.Logging.Warning.showPoolInsufficientMemoryWarning.get())
|
if (Config.Common.Logging.Warning.showPoolInsufficientMemoryWarning.get())
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ import java.util.function.LongConsumer;
|
|||||||
* <strong>Too big</strong>, and the LOD dropoff will be very noticeable.<br>
|
* <strong>Too big</strong>, and the LOD dropoff will be very noticeable.<br>
|
||||||
* With those thoughts in mind we decided on a smallest section size of 64 data points square (IE 4x4 chunks).
|
* With those thoughts in mind we decided on a smallest section size of 64 data points square (IE 4x4 chunks).
|
||||||
*
|
*
|
||||||
|
* TODO absolute vs section detail levels
|
||||||
|
*
|
||||||
* @author Leetom
|
* @author Leetom
|
||||||
*/
|
*/
|
||||||
public class DhSectionPos
|
public class DhSectionPos
|
||||||
|
|||||||
+1
-1
@@ -379,7 +379,7 @@ public class GLBuffer implements AutoCloseable
|
|||||||
{
|
{
|
||||||
int id = PHANTOM_TO_BUFFER_ID.get(phantomRef);
|
int id = PHANTOM_TO_BUFFER_ID.get(phantomRef);
|
||||||
destroyBufferIdAsync(id);
|
destroyBufferIdAsync(id);
|
||||||
LOGGER.warn("Buffer Phantom collected, ID: ["+id+"]");
|
//LOGGER.warn("Buffer Phantom collected, ID: ["+id+"]");
|
||||||
}
|
}
|
||||||
|
|
||||||
phantomRef = PHANTOM_REFERENCE_QUEUE.poll();
|
phantomRef = PHANTOM_REFERENCE_QUEUE.poll();
|
||||||
|
|||||||
@@ -110,8 +110,6 @@ public class DhFadeRenderer
|
|||||||
|
|
||||||
public void render(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks, IProfilerWrapper profiler)
|
public void render(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks, IProfilerWrapper profiler)
|
||||||
{
|
{
|
||||||
GLState mcState = new GLState();
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
profiler.push("Fade Generate");
|
profiler.push("Fade Generate");
|
||||||
@@ -149,10 +147,6 @@ public class DhFadeRenderer
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
// make sure we always revert to MC's state to prevent GL state corruption
|
|
||||||
// this is especially important on MC 1.16.5 or when other rendering mods are present
|
|
||||||
mcState.restore();
|
|
||||||
|
|
||||||
profiler.pop();
|
profiler.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -243,7 +243,10 @@ public class LodRenderer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// far plane clip fading
|
// far plane clip fading
|
||||||
if (Config.Client.Advanced.Graphics.Quality.dhFadeFarClipPlane.get())
|
if (Config.Client.Advanced.Graphics.Quality.dhFadeFarClipPlane.get()
|
||||||
|
// the fade shader messes with the GL state in a way Iris doesn't like,
|
||||||
|
// so skip it if a shader is active
|
||||||
|
&& (IRIS_ACCESSOR == null || !IRIS_ACCESSOR.isShaderPackInUse()))
|
||||||
{
|
{
|
||||||
profiler.popPush("Fade Far Clip Fade");
|
profiler.popPush("Fade Far Clip Fade");
|
||||||
DhFadeRenderer.INSTANCE.render(
|
DhFadeRenderer.INSTANCE.render(
|
||||||
|
|||||||
+11
-1
@@ -121,6 +121,16 @@ public class VanillaFadeRenderer
|
|||||||
|
|
||||||
public void render(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks, IClientLevelWrapper level)
|
public void render(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks, IClientLevelWrapper level)
|
||||||
{
|
{
|
||||||
|
int depthTextureId = LodRenderer.INSTANCE.getActiveDepthTextureId();
|
||||||
|
if (depthTextureId == -1)
|
||||||
|
{
|
||||||
|
// the renderer hasn't been set up yet
|
||||||
|
// trying to render fading may cause GL errors
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
IProfilerWrapper profiler = MC_CLIENT.getProfiler();
|
IProfilerWrapper profiler = MC_CLIENT.getProfiler();
|
||||||
profiler.pop(); // get out of "terrain"
|
profiler.pop(); // get out of "terrain"
|
||||||
profiler.push("DH-Vanilla Fade");
|
profiler.push("DH-Vanilla Fade");
|
||||||
@@ -158,7 +168,7 @@ public class VanillaFadeRenderer
|
|||||||
|
|
||||||
FadeApplyShader.INSTANCE.fadeTexture = this.fadeTexture;
|
FadeApplyShader.INSTANCE.fadeTexture = this.fadeTexture;
|
||||||
FadeApplyShader.INSTANCE.readFramebuffer = DhFadeShader.INSTANCE.frameBuffer;
|
FadeApplyShader.INSTANCE.readFramebuffer = DhFadeShader.INSTANCE.frameBuffer;
|
||||||
FadeApplyShader.INSTANCE.drawFramebuffer = LodRenderer.INSTANCE.getActiveFramebufferId();
|
FadeApplyShader.INSTANCE.drawFramebuffer = MC_RENDER.getTargetFramebuffer();
|
||||||
FadeApplyShader.INSTANCE.render(partialTicks);
|
FadeApplyShader.INSTANCE.render(partialTicks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,8 +69,7 @@ public class FullDataSourceV1DTO implements IBaseDTO<Long>
|
|||||||
/** @return a stream for the data contained in this DTO. */
|
/** @return a stream for the data contained in this DTO. */
|
||||||
public DhDataInputStream getInputStream() throws IOException
|
public DhDataInputStream getInputStream() throws IOException
|
||||||
{
|
{
|
||||||
InputStream inputStream = new ByteArrayInputStream(this.dataArray);
|
DhDataInputStream compressedStream = DhDataInputStream.create(this.dataArray, EDhApiDataCompressionMode.LZ4); // LZ4 was used by DH before 2.1.0 and as such must be used until the render data format is changed to record the compressor
|
||||||
DhDataInputStream compressedStream = new DhDataInputStream(inputStream, EDhApiDataCompressionMode.LZ4); // LZ4 was used by DH before 2.1.0 and as such must be used until the render data format is changed to record the compressor
|
|
||||||
return compressedStream;
|
return compressedStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+39
-55
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
package com.seibel.distanthorizons.core.sql.dto;
|
package com.seibel.distanthorizons.core.sql.dto;
|
||||||
|
|
||||||
|
import com.github.luben.zstd.Zstd;
|
||||||
import com.google.common.base.MoreObjects;
|
import com.google.common.base.MoreObjects;
|
||||||
import com.seibel.distanthorizons.api.enums.config.EDhApiDataCompressionMode;
|
import com.seibel.distanthorizons.api.enums.config.EDhApiDataCompressionMode;
|
||||||
import com.seibel.distanthorizons.api.enums.config.EDhApiWorldCompressionMode;
|
import com.seibel.distanthorizons.api.enums.config.EDhApiWorldCompressionMode;
|
||||||
@@ -65,8 +66,6 @@ public class FullDataSourceV2DTO
|
|||||||
|
|
||||||
public long pos;
|
public long pos;
|
||||||
|
|
||||||
public int levelMinY;
|
|
||||||
|
|
||||||
/** only for the data array */
|
/** only for the data array */
|
||||||
public int dataChecksum;
|
public int dataChecksum;
|
||||||
|
|
||||||
@@ -132,7 +131,6 @@ public class FullDataSourceV2DTO
|
|||||||
dto.createdUnixDateTime = dataSource.createdUnixDateTime;
|
dto.createdUnixDateTime = dataSource.createdUnixDateTime;
|
||||||
dto.applyToParent = dataSource.applyToParent;
|
dto.applyToParent = dataSource.applyToParent;
|
||||||
dto.applyToChildren = dataSource.applyToChildren;
|
dto.applyToChildren = dataSource.applyToChildren;
|
||||||
dto.levelMinY = dataSource.levelMinY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return dto;
|
return dto;
|
||||||
@@ -296,8 +294,6 @@ public class FullDataSourceV2DTO
|
|||||||
dataSource.lastModifiedUnixDateTime = this.lastModifiedUnixDateTime;
|
dataSource.lastModifiedUnixDateTime = this.lastModifiedUnixDateTime;
|
||||||
dataSource.createdUnixDateTime = this.createdUnixDateTime;
|
dataSource.createdUnixDateTime = this.createdUnixDateTime;
|
||||||
|
|
||||||
dataSource.levelMinY = this.levelMinY;
|
|
||||||
|
|
||||||
dataSource.isEmpty = false;
|
dataSource.isEmpty = false;
|
||||||
|
|
||||||
if (this.applyToParent != null)
|
if (this.applyToParent != null)
|
||||||
@@ -322,12 +318,7 @@ public class FullDataSourceV2DTO
|
|||||||
LongArrayList[] inputDataArray, ByteArrayList outputByteArray,
|
LongArrayList[] inputDataArray, ByteArrayList outputByteArray,
|
||||||
EDhApiDataCompressionMode compressionModeEnum) throws IOException
|
EDhApiDataCompressionMode compressionModeEnum) throws IOException
|
||||||
{
|
{
|
||||||
// write the outputs to a stream to prep for writing to the database
|
try (DhDataOutputStream compressedOut = DhDataOutputStream.create(compressionModeEnum, outputByteArray))
|
||||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
// normally a DhStream should be the topmost stream to prevent closing the stream accidentally,
|
|
||||||
// but since this stream will be closed immediately after writing anyway, it won't be an issue
|
|
||||||
try (DhDataOutputStream compressedOut = new DhDataOutputStream(byteArrayOutputStream, compressionModeEnum))
|
|
||||||
{
|
{
|
||||||
// write the data
|
// write the data
|
||||||
int dataArrayLength = FullDataSourceV2.WIDTH * FullDataSourceV2.WIDTH;
|
int dataArrayLength = FullDataSourceV2.WIDTH * FullDataSourceV2.WIDTH;
|
||||||
@@ -347,20 +338,13 @@ public class FullDataSourceV2DTO
|
|||||||
compressedOut.writeLong(dataColumn.getLong(y));
|
compressedOut.writeLong(dataColumn.getLong(y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// generate the checksum
|
|
||||||
compressedOut.flush();
|
|
||||||
byteArrayOutputStream.close();
|
|
||||||
outputByteArray.addElements(0, byteArrayOutputStream.toByteArray());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static void readBlobToDataSourceDataArrayV1(
|
private static void readBlobToDataSourceDataArrayV1(
|
||||||
ByteArrayList inputCompressedDataByteArray, LongArrayList[] outputDataLongArray,
|
ByteArrayList inputCompressedDataByteArray, LongArrayList[] outputDataLongArray,
|
||||||
EDhApiDataCompressionMode compressionModeEnum) throws IOException, DataCorruptedException
|
EDhApiDataCompressionMode compressionModeEnum) throws IOException, DataCorruptedException
|
||||||
{
|
{
|
||||||
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(inputCompressedDataByteArray.elements());
|
try (DhDataInputStream compressedIn = DhDataInputStream.create(inputCompressedDataByteArray, compressionModeEnum))
|
||||||
try (DhDataInputStream compressedIn = new DhDataInputStream(byteArrayInputStream, compressionModeEnum))
|
|
||||||
{
|
{
|
||||||
// read the data
|
// read the data
|
||||||
int dataArrayLength = FullDataSourceV2.WIDTH * FullDataSourceV2.WIDTH;
|
int dataArrayLength = FullDataSourceV2.WIDTH * FullDataSourceV2.WIDTH;
|
||||||
@@ -412,8 +396,7 @@ public class FullDataSourceV2DTO
|
|||||||
maxZ = FullDataSourceV2.WIDTH-1;
|
maxZ = FullDataSourceV2.WIDTH-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
try (DhDataOutputStream compressedOut = DhDataOutputStream.create(compressionModeEnum, outputByteArray))
|
||||||
try (DhDataOutputStream compressedOut = new DhDataOutputStream(byteArrayOutputStream, compressionModeEnum))
|
|
||||||
{
|
{
|
||||||
// this method would be simpler if we allocated a bunch of temporary arrays,
|
// this method would be simpler if we allocated a bunch of temporary arrays,
|
||||||
// but we're trying to avoid garbage.
|
// but we're trying to avoid garbage.
|
||||||
@@ -530,10 +513,6 @@ public class FullDataSourceV2DTO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
compressedOut.flush();
|
|
||||||
byteArrayOutputStream.close();
|
|
||||||
outputByteArray.addElements(0, byteArrayOutputStream.toByteArray());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static void readBlobToDataSourceDataArrayV2(
|
private static void readBlobToDataSourceDataArrayV2(
|
||||||
@@ -560,8 +539,8 @@ public class FullDataSourceV2DTO
|
|||||||
maxZ = FullDataSourceV2.WIDTH-1;
|
maxZ = FullDataSourceV2.WIDTH-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(inputCompressedDataByteArray.elements());
|
|
||||||
try (DhDataInputStream compressedIn = new DhDataInputStream(byteArrayInputStream, compressionModeEnum))
|
try (DhDataInputStream compressedIn = DhDataInputStream.create(inputCompressedDataByteArray, compressionModeEnum))
|
||||||
{
|
{
|
||||||
// 1. column counts, preallocate
|
// 1. column counts, preallocate
|
||||||
for (int x = minX; x < maxX; x++)
|
for (int x = minX; x < maxX; x++)
|
||||||
@@ -687,24 +666,17 @@ public class FullDataSourceV2DTO
|
|||||||
|
|
||||||
private static void writeGenerationStepsToBlob(ByteArrayList inputColumnGenStepByteArray, ByteArrayList outputByteArray, EDhApiDataCompressionMode compressionModeEnum) throws IOException
|
private static void writeGenerationStepsToBlob(ByteArrayList inputColumnGenStepByteArray, ByteArrayList outputByteArray, EDhApiDataCompressionMode compressionModeEnum) throws IOException
|
||||||
{
|
{
|
||||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
try (DhDataOutputStream compressedOut = DhDataOutputStream.create(compressionModeEnum, outputByteArray))
|
||||||
try (DhDataOutputStream compressedOut = new DhDataOutputStream(byteArrayOutputStream, compressionModeEnum))
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < inputColumnGenStepByteArray.size(); i++)
|
for (int i = 0; i < inputColumnGenStepByteArray.size(); i++)
|
||||||
{
|
{
|
||||||
compressedOut.writeByte(inputColumnGenStepByteArray.getByte(i));
|
compressedOut.writeByte(inputColumnGenStepByteArray.getByte(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
compressedOut.flush();
|
|
||||||
byteArrayOutputStream.close();
|
|
||||||
outputByteArray.addElements(0, byteArrayOutputStream.toByteArray());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static void readBlobToGenerationSteps(ByteArrayList inputCompressedDataByteArray, ByteArrayList outputByteArray, EDhApiDataCompressionMode compressionModeEnum) throws IOException, DataCorruptedException
|
private static void readBlobToGenerationSteps(ByteArrayList inputCompressedDataByteArray, ByteArrayList outputByteArray, EDhApiDataCompressionMode compressionModeEnum) throws IOException, DataCorruptedException
|
||||||
{
|
{
|
||||||
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(inputCompressedDataByteArray.elements());
|
try(DhDataInputStream compressedIn = DhDataInputStream.create(inputCompressedDataByteArray, compressionModeEnum))
|
||||||
|
|
||||||
try(DhDataInputStream compressedIn = new DhDataInputStream(byteArrayInputStream, compressionModeEnum))
|
|
||||||
{
|
{
|
||||||
compressedIn.readFully(outputByteArray.elements(), 0, FullDataSourceV2.WIDTH * FullDataSourceV2.WIDTH);
|
compressedIn.readFully(outputByteArray.elements(), 0, FullDataSourceV2.WIDTH * FullDataSourceV2.WIDTH);
|
||||||
}
|
}
|
||||||
@@ -717,24 +689,17 @@ public class FullDataSourceV2DTO
|
|||||||
|
|
||||||
private static void writeWorldCompressionModeToBlob(ByteArrayList inputWorldCompressionModeByteArray, ByteArrayList outputByteArray, EDhApiDataCompressionMode compressionModeEnum) throws IOException
|
private static void writeWorldCompressionModeToBlob(ByteArrayList inputWorldCompressionModeByteArray, ByteArrayList outputByteArray, EDhApiDataCompressionMode compressionModeEnum) throws IOException
|
||||||
{
|
{
|
||||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
try (DhDataOutputStream compressedOut = DhDataOutputStream.create(compressionModeEnum, outputByteArray))
|
||||||
try (DhDataOutputStream compressedOut = new DhDataOutputStream(byteArrayOutputStream, compressionModeEnum))
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < inputWorldCompressionModeByteArray.size(); i++)
|
for (int i = 0; i < inputWorldCompressionModeByteArray.size(); i++)
|
||||||
{
|
{
|
||||||
compressedOut.write(inputWorldCompressionModeByteArray.getByte(i));
|
compressedOut.write(inputWorldCompressionModeByteArray.getByte(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
compressedOut.flush();
|
|
||||||
byteArrayOutputStream.close();
|
|
||||||
outputByteArray.addElements(0, byteArrayOutputStream.toByteArray());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static void readBlobToWorldCompressionMode(ByteArrayList inputCompressedDataByteArray, ByteArrayList outputByteArray, EDhApiDataCompressionMode compressionModeEnum) throws IOException, DataCorruptedException
|
private static void readBlobToWorldCompressionMode(ByteArrayList inputCompressedDataByteArray, ByteArrayList outputByteArray, EDhApiDataCompressionMode compressionModeEnum) throws IOException, DataCorruptedException
|
||||||
{
|
{
|
||||||
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(inputCompressedDataByteArray.elements());
|
try(DhDataInputStream compressedIn = DhDataInputStream.create(inputCompressedDataByteArray, compressionModeEnum))
|
||||||
|
|
||||||
try(DhDataInputStream compressedIn = new DhDataInputStream(byteArrayInputStream, compressionModeEnum))
|
|
||||||
{
|
{
|
||||||
compressedIn.readFully(outputByteArray.elements(), 0, FullDataSourceV2.WIDTH * FullDataSourceV2.WIDTH);
|
compressedIn.readFully(outputByteArray.elements(), 0, FullDataSourceV2.WIDTH * FullDataSourceV2.WIDTH);
|
||||||
}
|
}
|
||||||
@@ -747,20 +712,14 @@ public class FullDataSourceV2DTO
|
|||||||
|
|
||||||
private static void writeDataMappingToBlob(FullDataPointIdMap mapping, ByteArrayList outputByteArray, EDhApiDataCompressionMode compressionModeEnum) throws IOException
|
private static void writeDataMappingToBlob(FullDataPointIdMap mapping, ByteArrayList outputByteArray, EDhApiDataCompressionMode compressionModeEnum) throws IOException
|
||||||
{
|
{
|
||||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
try(DhDataOutputStream compressedOut = DhDataOutputStream.create(compressionModeEnum, outputByteArray))
|
||||||
try(DhDataOutputStream compressedOut = new DhDataOutputStream(byteArrayOutputStream, compressionModeEnum))
|
|
||||||
{
|
{
|
||||||
mapping.serialize(compressedOut);
|
mapping.serialize(compressedOut);
|
||||||
|
|
||||||
compressedOut.flush();
|
|
||||||
byteArrayOutputStream.close();
|
|
||||||
outputByteArray.addElements(0, byteArrayOutputStream.toByteArray());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static FullDataPointIdMap readBlobToDataMapping(ByteArrayList compressedMappingByteArray, long pos, @NotNull ILevelWrapper levelWrapper, EDhApiDataCompressionMode compressionModeEnum) throws IOException, InterruptedException, DataCorruptedException
|
private static FullDataPointIdMap readBlobToDataMapping(ByteArrayList inputCompressedDataByteArray, long pos, @NotNull ILevelWrapper levelWrapper, EDhApiDataCompressionMode compressionModeEnum) throws IOException, InterruptedException, DataCorruptedException
|
||||||
{
|
{
|
||||||
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(compressedMappingByteArray.elements());
|
try (DhDataInputStream compressedIn = DhDataInputStream.create(inputCompressedDataByteArray, compressionModeEnum))
|
||||||
try (DhDataInputStream compressedIn = new DhDataInputStream(byteArrayInputStream, compressionModeEnum))
|
|
||||||
{
|
{
|
||||||
FullDataPointIdMap mapping = FullDataPointIdMap.deserialize(compressedIn, pos, levelWrapper);
|
FullDataPointIdMap mapping = FullDataPointIdMap.deserialize(compressedIn, pos, levelWrapper);
|
||||||
return mapping;
|
return mapping;
|
||||||
@@ -779,14 +738,27 @@ public class FullDataSourceV2DTO
|
|||||||
out.writeLong(this.pos);
|
out.writeLong(this.pos);
|
||||||
out.writeInt(this.dataChecksum);
|
out.writeInt(this.dataChecksum);
|
||||||
|
|
||||||
|
// data
|
||||||
out.writeInt(this.compressedDataByteArray.size());
|
out.writeInt(this.compressedDataByteArray.size());
|
||||||
out.writeBytes(this.compressedDataByteArray.elements(), 0, this.compressedDataByteArray.size());
|
out.writeBytes(this.compressedDataByteArray.elements(), 0, this.compressedDataByteArray.size());
|
||||||
|
|
||||||
|
// adj data
|
||||||
|
out.writeInt(this.compressedNorthAdjDataByteArray.size());
|
||||||
|
out.writeBytes(this.compressedNorthAdjDataByteArray.elements(), 0, this.compressedNorthAdjDataByteArray.size());
|
||||||
|
out.writeInt(this.compressedSouthAdjDataByteArray.size());
|
||||||
|
out.writeBytes(this.compressedSouthAdjDataByteArray.elements(), 0, this.compressedSouthAdjDataByteArray.size());
|
||||||
|
out.writeInt(this.compressedEastAdjDataByteArray.size());
|
||||||
|
out.writeBytes(this.compressedEastAdjDataByteArray.elements(), 0, this.compressedEastAdjDataByteArray.size());
|
||||||
|
out.writeInt(this.compressedWestAdjDataByteArray.size());
|
||||||
|
out.writeBytes(this.compressedWestAdjDataByteArray.elements(), 0, this.compressedWestAdjDataByteArray.size());
|
||||||
|
|
||||||
|
// world gen
|
||||||
out.writeInt(this.compressedColumnGenStepByteArray.size());
|
out.writeInt(this.compressedColumnGenStepByteArray.size());
|
||||||
out.writeBytes(this.compressedColumnGenStepByteArray.elements(), 0, this.compressedColumnGenStepByteArray.size());
|
out.writeBytes(this.compressedColumnGenStepByteArray.elements(), 0, this.compressedColumnGenStepByteArray.size());
|
||||||
out.writeInt(this.compressedWorldCompressionModeByteArray.size());
|
out.writeInt(this.compressedWorldCompressionModeByteArray.size());
|
||||||
out.writeBytes(this.compressedWorldCompressionModeByteArray.elements(), 0, this.compressedWorldCompressionModeByteArray.size());
|
out.writeBytes(this.compressedWorldCompressionModeByteArray.elements(), 0, this.compressedWorldCompressionModeByteArray.size());
|
||||||
|
|
||||||
|
// compression type
|
||||||
out.writeInt(this.compressedMappingByteArray.size());
|
out.writeInt(this.compressedMappingByteArray.size());
|
||||||
out.writeBytes(this.compressedMappingByteArray.elements(), 0, this.compressedMappingByteArray.size());
|
out.writeBytes(this.compressedMappingByteArray.elements(), 0, this.compressedMappingByteArray.size());
|
||||||
|
|
||||||
@@ -806,14 +778,27 @@ public class FullDataSourceV2DTO
|
|||||||
this.pos = in.readLong();
|
this.pos = in.readLong();
|
||||||
this.dataChecksum = in.readInt();
|
this.dataChecksum = in.readInt();
|
||||||
|
|
||||||
|
// data
|
||||||
this.compressedDataByteArray.size(in.readInt());
|
this.compressedDataByteArray.size(in.readInt());
|
||||||
in.readBytes(this.compressedDataByteArray.elements(), 0, this.compressedDataByteArray.size());
|
in.readBytes(this.compressedDataByteArray.elements(), 0, this.compressedDataByteArray.size());
|
||||||
|
|
||||||
|
// adj data
|
||||||
|
this.compressedNorthAdjDataByteArray.size(in.readInt());
|
||||||
|
in.readBytes(this.compressedNorthAdjDataByteArray.elements(), 0, this.compressedNorthAdjDataByteArray.size());
|
||||||
|
this.compressedSouthAdjDataByteArray.size(in.readInt());
|
||||||
|
in.readBytes(this.compressedSouthAdjDataByteArray.elements(), 0, this.compressedSouthAdjDataByteArray.size());
|
||||||
|
this.compressedEastAdjDataByteArray.size(in.readInt());
|
||||||
|
in.readBytes(this.compressedEastAdjDataByteArray.elements(), 0, this.compressedEastAdjDataByteArray.size());
|
||||||
|
this.compressedWestAdjDataByteArray.size(in.readInt());
|
||||||
|
in.readBytes(this.compressedWestAdjDataByteArray.elements(), 0, this.compressedWestAdjDataByteArray.size());
|
||||||
|
|
||||||
|
// world gen
|
||||||
this.compressedColumnGenStepByteArray.size(in.readInt());
|
this.compressedColumnGenStepByteArray.size(in.readInt());
|
||||||
in.readBytes(this.compressedColumnGenStepByteArray.elements(), 0, this.compressedColumnGenStepByteArray.size());
|
in.readBytes(this.compressedColumnGenStepByteArray.elements(), 0, this.compressedColumnGenStepByteArray.size());
|
||||||
this.compressedWorldCompressionModeByteArray.size(in.readInt());
|
this.compressedWorldCompressionModeByteArray.size(in.readInt());
|
||||||
in.readBytes(this.compressedWorldCompressionModeByteArray.elements(), 0, this.compressedWorldCompressionModeByteArray.size());
|
in.readBytes(this.compressedWorldCompressionModeByteArray.elements(), 0, this.compressedWorldCompressionModeByteArray.size());
|
||||||
|
|
||||||
|
// compression type
|
||||||
this.compressedMappingByteArray.size(in.readInt());
|
this.compressedMappingByteArray.size(in.readInt());
|
||||||
in.readBytes(this.compressedMappingByteArray.elements(), 0, this.compressedMappingByteArray.size());
|
in.readBytes(this.compressedMappingByteArray.elements(), 0, this.compressedMappingByteArray.size());
|
||||||
|
|
||||||
@@ -842,7 +827,6 @@ public class FullDataSourceV2DTO
|
|||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
return MoreObjects.toStringHelper(this)
|
return MoreObjects.toStringHelper(this)
|
||||||
.add("levelMinY", this.levelMinY)
|
|
||||||
.add("pos", DhSectionPos.toString(this.pos))
|
.add("pos", DhSectionPos.toString(this.pos))
|
||||||
.add("dataChecksum", this.dataChecksum)
|
.add("dataChecksum", this.dataChecksum)
|
||||||
.add("compressedDataByteArray length", this.compressedDataByteArray.size())
|
.add("compressedDataByteArray length", this.compressedDataByteArray.size())
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ public abstract class AbstractDhRepo<TKey, TDTO extends IBaseDTO<TKey>> implemen
|
|||||||
//=============//
|
//=============//
|
||||||
|
|
||||||
/** @throws SQLException if the repo is unable to access the database or has trouble updating said database. */
|
/** @throws SQLException if the repo is unable to access the database or has trouble updating said database. */
|
||||||
public AbstractDhRepo(String databaseType, File databaseFile, Class<? extends TDTO> dtoClass) throws SQLException
|
public AbstractDhRepo(String databaseType, File databaseFile, Class<? extends TDTO> dtoClass) throws SQLException, IOException
|
||||||
{
|
{
|
||||||
this.databaseType = databaseType;
|
this.databaseType = databaseType;
|
||||||
this.databaseFile = databaseFile;
|
this.databaseFile = databaseFile;
|
||||||
@@ -107,7 +107,7 @@ public abstract class AbstractDhRepo<TKey, TDTO extends IBaseDTO<TKey>> implemen
|
|||||||
{
|
{
|
||||||
if (!parentFolder.mkdirs())
|
if (!parentFolder.mkdirs())
|
||||||
{
|
{
|
||||||
throw new RuntimeException("Unable to create the necessary parent folders for the database file at location ["+databaseFile.getPath()+"].");
|
throw new IOException("Unable to create the necessary parent folders for the database file at location ["+databaseFile.getPath()+"].");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,18 +119,18 @@ public abstract class AbstractDhRepo<TKey, TDTO extends IBaseDTO<TKey>> implemen
|
|||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
throw new RuntimeException("Unable to create database file at location ["+databaseFile.getPath()+"] due to error: ["+e.getMessage()+"]", e);
|
throw new IOException("Unable to create database file at location ["+databaseFile.getPath()+"] due to error: ["+e.getMessage()+"]", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!databaseFile.canRead())
|
if (!databaseFile.canRead())
|
||||||
{
|
{
|
||||||
throw new RuntimeException("Unable to read database file at location ["+databaseFile.getPath()+"], please make sure the folder and file has the correct permissions.");
|
throw new IOException("Unable to read database file at location ["+databaseFile.getPath()+"], please make sure the folder and file has the correct permissions.");
|
||||||
}
|
}
|
||||||
if (!databaseFile.canWrite())
|
if (!databaseFile.canWrite())
|
||||||
{
|
{
|
||||||
throw new RuntimeException("Unable to write database file at location ["+databaseFile.getPath()+"], please make sure the folder and file aren't set to read-only.");
|
throw new IOException("Unable to write database file at location ["+databaseFile.getPath()+"], please make sure the folder and file aren't set to read-only.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
@@ -47,7 +48,7 @@ public class BeaconBeamRepo extends AbstractDhRepo<DhBlockPos, BeaconBeamDTO>
|
|||||||
// constructor //
|
// constructor //
|
||||||
//=============//
|
//=============//
|
||||||
|
|
||||||
public BeaconBeamRepo(String databaseType, File databaseFile) throws SQLException
|
public BeaconBeamRepo(String databaseType, File databaseFile) throws SQLException, IOException
|
||||||
{
|
{
|
||||||
super(databaseType, databaseFile, BeaconBeamDTO.class);
|
super(databaseType, databaseFile, BeaconBeamDTO.class);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import com.seibel.distanthorizons.core.logging.DhLogger;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
@@ -40,7 +41,7 @@ public class ChunkHashRepo extends AbstractDhRepo<DhChunkPos, ChunkHashDTO>
|
|||||||
// constructor //
|
// constructor //
|
||||||
//=============//
|
//=============//
|
||||||
|
|
||||||
public ChunkHashRepo(String databaseType, File databaseFile) throws SQLException
|
public ChunkHashRepo(String databaseType, File databaseFile) throws SQLException, IOException
|
||||||
{
|
{
|
||||||
super(databaseType, databaseFile, ChunkHashDTO.class);
|
super(databaseType, databaseFile, ChunkHashDTO.class);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -28,6 +28,7 @@ import it.unimi.dsi.fastutil.longs.LongArrayList;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
@@ -45,7 +46,7 @@ public class FullDataSourceV1Repo extends AbstractDhRepo<Long, FullDataSourceV1D
|
|||||||
// constructor //
|
// constructor //
|
||||||
//=============//
|
//=============//
|
||||||
|
|
||||||
public FullDataSourceV1Repo(String databaseType, File databaseFile) throws SQLException
|
public FullDataSourceV1Repo(String databaseType, File databaseFile) throws SQLException, IOException
|
||||||
{
|
{
|
||||||
super(databaseType, databaseFile, FullDataSourceV1DTO.class);
|
super(databaseType, databaseFile, FullDataSourceV1DTO.class);
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-21
@@ -51,7 +51,7 @@ public class FullDataSourceV2Repo extends AbstractDhRepo<Long, FullDataSourceV2D
|
|||||||
// constructor //
|
// constructor //
|
||||||
//=============//
|
//=============//
|
||||||
|
|
||||||
public FullDataSourceV2Repo(String databaseType, File databaseFile) throws SQLException
|
public FullDataSourceV2Repo(String databaseType, File databaseFile) throws SQLException, IOException
|
||||||
{
|
{
|
||||||
super(databaseType, databaseFile, FullDataSourceV2DTO.class);
|
super(databaseType, databaseFile, FullDataSourceV2DTO.class);
|
||||||
}
|
}
|
||||||
@@ -98,7 +98,6 @@ public class FullDataSourceV2Repo extends AbstractDhRepo<Long, FullDataSourceV2D
|
|||||||
int posZ = resultSet.getInt("PosZ");
|
int posZ = resultSet.getInt("PosZ");
|
||||||
long pos = DhSectionPos.encode(sectionDetailLevel, posX, posZ);
|
long pos = DhSectionPos.encode(sectionDetailLevel, posX, posZ);
|
||||||
|
|
||||||
int minY = resultSet.getInt("MinY");
|
|
||||||
int dataChecksum = resultSet.getInt("DataChecksum");
|
int dataChecksum = resultSet.getInt("DataChecksum");
|
||||||
|
|
||||||
|
|
||||||
@@ -145,19 +144,17 @@ public class FullDataSourceV2Repo extends AbstractDhRepo<Long, FullDataSourceV2D
|
|||||||
dto.createdUnixDateTime = createdUnixDateTime;
|
dto.createdUnixDateTime = createdUnixDateTime;
|
||||||
dto.applyToParent = applyToParent;
|
dto.applyToParent = applyToParent;
|
||||||
dto.applyToChildren = applyToChildren;
|
dto.applyToChildren = applyToChildren;
|
||||||
dto.levelMinY = minY;
|
|
||||||
}
|
}
|
||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public FullDataSourceV2DTO convertResultSetToAdjDto(long pos, EDhDirection direction, ResultSet resultSet) throws ClassCastException, IOException, SQLException
|
public FullDataSourceV2DTO convertResultSetToAdjDto(long pos, ResultSet resultSet) throws ClassCastException, IOException, SQLException
|
||||||
{
|
{
|
||||||
//======================//
|
//======================//
|
||||||
// get statement values //
|
// get statement values //
|
||||||
//======================//
|
//======================//
|
||||||
|
|
||||||
int minY = resultSet.getInt("MinY");
|
|
||||||
int dataChecksum = resultSet.getInt("DataChecksum");
|
int dataChecksum = resultSet.getInt("DataChecksum");
|
||||||
|
|
||||||
|
|
||||||
@@ -178,17 +175,11 @@ public class FullDataSourceV2Repo extends AbstractDhRepo<Long, FullDataSourceV2D
|
|||||||
//===================//
|
//===================//
|
||||||
|
|
||||||
FullDataSourceV2DTO dto = FullDataSourceV2DTO.CreateEmptyDataSourceForDecoding();
|
FullDataSourceV2DTO dto = FullDataSourceV2DTO.CreateEmptyDataSourceForDecoding();
|
||||||
// dto.compressedNorthAdjDataByteArray = putAllBytes(resultSet.getBinaryStream("NorthAdjData"), dto.compressedNorthAdjDataByteArray);
|
|
||||||
// set pooled arrays
|
// set pooled arrays
|
||||||
dto.compressedDataByteArray = putAllBytes(resultSet.getBinaryStream("AdjData"), dto.compressedDataByteArray);
|
dto.compressedDataByteArray = putAllBytes(resultSet.getBinaryStream("AdjData"), dto.compressedDataByteArray);
|
||||||
dto.compressedColumnGenStepByteArray = putAllBytes(resultSet.getBinaryStream("ColumnGenerationStep"), dto.compressedColumnGenStepByteArray);
|
dto.compressedColumnGenStepByteArray = putAllBytes(resultSet.getBinaryStream("ColumnGenerationStep"), dto.compressedColumnGenStepByteArray);
|
||||||
dto.compressedWorldCompressionModeByteArray = putAllBytes(resultSet.getBinaryStream("ColumnWorldCompressionMode"), dto.compressedWorldCompressionModeByteArray);
|
dto.compressedWorldCompressionModeByteArray = putAllBytes(resultSet.getBinaryStream("ColumnWorldCompressionMode"), dto.compressedWorldCompressionModeByteArray);
|
||||||
dto.compressedMappingByteArray = putAllBytes(resultSet.getBinaryStream("Mapping"), dto.compressedMappingByteArray);
|
dto.compressedMappingByteArray = putAllBytes(resultSet.getBinaryStream("Mapping"), dto.compressedMappingByteArray);
|
||||||
// adjacent full data
|
|
||||||
//dto.compressedNorthAdjDataByteArray = putAllBytes(resultSet.getBinaryStream("NorthAdjData"), dto.compressedNorthAdjDataByteArray);
|
|
||||||
//dto.compressedSouthAdjDataByteArray = putAllBytes(resultSet.getBinaryStream("SouthAdjData"), dto.compressedSouthAdjDataByteArray);
|
|
||||||
//dto.compressedEastAdjDataByteArray = putAllBytes(resultSet.getBinaryStream("EastAdjData"), dto.compressedEastAdjDataByteArray);
|
|
||||||
//dto.compressedWestAdjDataByteArray = putAllBytes(resultSet.getBinaryStream("WestAdjData"), dto.compressedWestAdjDataByteArray);
|
|
||||||
|
|
||||||
// set individual variables
|
// set individual variables
|
||||||
{
|
{
|
||||||
@@ -200,7 +191,6 @@ public class FullDataSourceV2Repo extends AbstractDhRepo<Long, FullDataSourceV2D
|
|||||||
dto.createdUnixDateTime = createdUnixDateTime;
|
dto.createdUnixDateTime = createdUnixDateTime;
|
||||||
dto.applyToParent = applyToParent;
|
dto.applyToParent = applyToParent;
|
||||||
dto.applyToChildren = applyToChildren;
|
dto.applyToChildren = applyToChildren;
|
||||||
dto.levelMinY = minY;
|
|
||||||
}
|
}
|
||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
@@ -237,7 +227,10 @@ public class FullDataSourceV2Repo extends AbstractDhRepo<Long, FullDataSourceV2D
|
|||||||
statement.setInt(i++, DhSectionPos.getX(dto.pos));
|
statement.setInt(i++, DhSectionPos.getX(dto.pos));
|
||||||
statement.setInt(i++, DhSectionPos.getZ(dto.pos));
|
statement.setInt(i++, DhSectionPos.getZ(dto.pos));
|
||||||
|
|
||||||
statement.setInt(i++, dto.levelMinY);
|
statement.setInt(i++, 0); // deprecated MinY column
|
||||||
|
// MinY is deprecated due to a bug introduced sometime before 2.3.6 where was always set to "0"
|
||||||
|
// and due to being unused wasn't noticed until 2.3.7-dev (2025-11-15)
|
||||||
|
|
||||||
statement.setInt(i++, dto.dataChecksum);
|
statement.setInt(i++, dto.dataChecksum);
|
||||||
|
|
||||||
statement.setBinaryStream(i++, new ByteArrayInputStream(dto.compressedDataByteArray.elements()), dto.compressedDataByteArray.size());
|
statement.setBinaryStream(i++, new ByteArrayInputStream(dto.compressedDataByteArray.elements()), dto.compressedDataByteArray.size());
|
||||||
@@ -272,8 +265,7 @@ public class FullDataSourceV2Repo extends AbstractDhRepo<Long, FullDataSourceV2D
|
|||||||
String updateSqlTemplate = (
|
String updateSqlTemplate = (
|
||||||
"UPDATE "+this.getTableName()+" \n" +
|
"UPDATE "+this.getTableName()+" \n" +
|
||||||
"SET \n" +
|
"SET \n" +
|
||||||
" MinY = ? \n" +
|
" DataChecksum = ? \n" +
|
||||||
" ,DataChecksum = ? \n" +
|
|
||||||
|
|
||||||
" ,Data = ? \n" +
|
" ,Data = ? \n" +
|
||||||
" ,ColumnGenerationStep = ? \n" +
|
" ,ColumnGenerationStep = ? \n" +
|
||||||
@@ -303,7 +295,6 @@ public class FullDataSourceV2Repo extends AbstractDhRepo<Long, FullDataSourceV2D
|
|||||||
|
|
||||||
|
|
||||||
int i = 1;
|
int i = 1;
|
||||||
statement.setInt(i++, dto.levelMinY);
|
|
||||||
statement.setInt(i++, dto.dataChecksum);
|
statement.setInt(i++, dto.dataChecksum);
|
||||||
|
|
||||||
statement.setBinaryStream(i++, new ByteArrayInputStream(dto.compressedDataByteArray.elements()), dto.compressedDataByteArray.size());
|
statement.setBinaryStream(i++, new ByteArrayInputStream(dto.compressedDataByteArray.elements()), dto.compressedDataByteArray.size());
|
||||||
@@ -346,7 +337,7 @@ public class FullDataSourceV2Repo extends AbstractDhRepo<Long, FullDataSourceV2D
|
|||||||
|
|
||||||
private final String getAdjForDirectionSqlTemplate =
|
private final String getAdjForDirectionSqlTemplate =
|
||||||
"SELECT \n" +
|
"SELECT \n" +
|
||||||
" MinY, DataChecksum, \n" +
|
" DataChecksum, \n" +
|
||||||
" ColumnGenerationStep, ColumnWorldCompressionMode, Mapping, \n" +
|
" ColumnGenerationStep, ColumnWorldCompressionMode, Mapping, \n" +
|
||||||
" DataFormatVersion, CompressionMode, ApplyToParent, ApplyToChildren, \n" +
|
" DataFormatVersion, CompressionMode, ApplyToParent, ApplyToChildren, \n" +
|
||||||
" LastModifiedUnixDateTime, CreatedUnixDateTime, \n" +
|
" LastModifiedUnixDateTime, CreatedUnixDateTime, \n" +
|
||||||
@@ -400,9 +391,9 @@ public class FullDataSourceV2Repo extends AbstractDhRepo<Long, FullDataSourceV2D
|
|||||||
try(ResultSet resultSet = this.query(statement))
|
try(ResultSet resultSet = this.query(statement))
|
||||||
{
|
{
|
||||||
if (resultSet != null
|
if (resultSet != null
|
||||||
&& resultSet.next())
|
&& resultSet.next())
|
||||||
{
|
{
|
||||||
return this.convertResultSetToAdjDto(pos, direction, resultSet);
|
return this.convertResultSetToAdjDto(pos, resultSet);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -581,9 +572,14 @@ public class FullDataSourceV2Repo extends AbstractDhRepo<Long, FullDataSourceV2D
|
|||||||
EDhApiDataCompressionMode compressionModeEnum = EDhApiDataCompressionMode.getFromValue(compressionModeEnumValue);
|
EDhApiDataCompressionMode compressionModeEnum = EDhApiDataCompressionMode.getFromValue(compressionModeEnumValue);
|
||||||
|
|
||||||
// decompress the data
|
// decompress the data
|
||||||
try(DhDataInputStream compressedIn = new DhDataInputStream(result.getBinaryStream("ColumnGenerationStep"), compressionModeEnum))
|
try
|
||||||
{
|
{
|
||||||
putAllBytes(compressedIn, outputByteArray);
|
ByteArrayList byteArrayList = new ByteArrayList();
|
||||||
|
putAllBytes(result.getBinaryStream("ColumnGenerationStep"), byteArrayList);
|
||||||
|
try(DhDataInputStream compressedIn = DhDataInputStream.create(byteArrayList, compressionModeEnum))
|
||||||
|
{
|
||||||
|
putAllBytes(compressedIn, outputByteArray);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,8 +13,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
|||||||
public class DhApiTerrainDataPointUtil
|
public class DhApiTerrainDataPointUtil
|
||||||
{
|
{
|
||||||
|
|
||||||
public static DhApiTerrainDataPoint createApiDatapoint(IDhApiLevelWrapper levelWrapper, FullDataPointIdMap mapping, byte detailLevel, long dataPoint)
|
|
||||||
{ return createApiDatapoint(levelWrapper.getMinHeight(), mapping, detailLevel, dataPoint); }
|
|
||||||
public static DhApiTerrainDataPoint createApiDatapoint(int minLevelHeight, FullDataPointIdMap mapping, byte detailLevel, long dataPoint)
|
public static DhApiTerrainDataPoint createApiDatapoint(int minLevelHeight, FullDataPointIdMap mapping, byte detailLevel, long dataPoint)
|
||||||
{
|
{
|
||||||
IBlockStateWrapper blockState = mapping.getBlockStateWrapper(FullDataPointUtil.getId(dataPoint));
|
IBlockStateWrapper blockState = mapping.getBlockStateWrapper(FullDataPointUtil.getId(dataPoint));
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package com.seibel.distanthorizons.core.util;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException;
|
||||||
|
|
||||||
|
import java.nio.channels.ClosedByInterruptException;
|
||||||
|
import java.util.concurrent.CancellationException;
|
||||||
|
import java.util.concurrent.CompletionException;
|
||||||
|
import java.util.concurrent.RejectedExecutionException;
|
||||||
|
|
||||||
|
public class ExceptionUtil
|
||||||
|
{
|
||||||
|
public static boolean isShutdownException(Throwable throwable)
|
||||||
|
{
|
||||||
|
Throwable unwrappedCompletion = throwable;
|
||||||
|
while (unwrappedCompletion instanceof CompletionException)
|
||||||
|
{
|
||||||
|
unwrappedCompletion = unwrappedCompletion.getCause();
|
||||||
|
}
|
||||||
|
|
||||||
|
return isThrowableShutdown(throwable)
|
||||||
|
|| isThrowableShutdown(unwrappedCompletion);
|
||||||
|
}
|
||||||
|
private static boolean isThrowableShutdown(Throwable throwable)
|
||||||
|
{
|
||||||
|
return throwable instanceof InterruptedException
|
||||||
|
|| throwable instanceof UncheckedInterruptedException
|
||||||
|
|| throwable instanceof RejectedExecutionException
|
||||||
|
|| throwable instanceof ClosedByInterruptException;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean isInterruptOrReject(Throwable t)
|
||||||
|
{
|
||||||
|
Throwable unwrapped = ensureUnwrap(t);
|
||||||
|
return UncheckedInterruptedException.isInterrupt(unwrapped) ||
|
||||||
|
unwrapped instanceof RejectedExecutionException ||
|
||||||
|
unwrapped instanceof CancellationException;
|
||||||
|
}
|
||||||
|
public static Throwable ensureUnwrap(Throwable t)
|
||||||
|
{
|
||||||
|
return t instanceof CompletionException ? ensureUnwrap(t.getCause()) : t;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -21,21 +21,11 @@ package com.seibel.distanthorizons.core.util;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CancellationException;
|
|
||||||
import java.util.concurrent.CompletionException;
|
|
||||||
import java.util.concurrent.RejectedExecutionException;
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.api.enums.config.EDhApiVanillaOverdraw;
|
|
||||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.render.vertexFormat.DefaultLodVertexFormats;
|
import com.seibel.distanthorizons.core.render.vertexFormat.DefaultLodVertexFormats;
|
||||||
import com.seibel.distanthorizons.core.render.vertexFormat.LodVertexFormat;
|
import com.seibel.distanthorizons.core.render.vertexFormat.LodVertexFormat;
|
||||||
import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException;
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IDimensionTypeWrapper;
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
|
||||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -191,17 +181,6 @@ public class LodUtil
|
|||||||
throw new AssertFailureException("Assert Not Reach failed:\n " + message);
|
throw new AssertFailureException("Assert Not Reach failed:\n " + message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Throwable ensureUnwrap(Throwable t)
|
|
||||||
{
|
|
||||||
return t instanceof CompletionException ? ensureUnwrap(t.getCause()) : t;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isInterruptOrReject(Throwable t)
|
|
||||||
{
|
|
||||||
Throwable unwrapped = LodUtil.ensureUnwrap(t);
|
|
||||||
return UncheckedInterruptedException.isInterrupt(unwrapped) ||
|
|
||||||
unwrapped instanceof RejectedExecutionException ||
|
|
||||||
unwrapped instanceof CancellationException;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,111 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the Distant Horizons mod
|
|
||||||
* licensed under the GNU LGPL 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 Lesser 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 Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.seibel.distanthorizons.core.util.objects;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
public class EventTimer
|
|
||||||
{
|
|
||||||
public static class Event
|
|
||||||
{
|
|
||||||
public long timeNs = -1;
|
|
||||||
public String name;
|
|
||||||
Event(String name)
|
|
||||||
{
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
long lastEventNs = -1;
|
|
||||||
|
|
||||||
public ArrayList<Event> events = new ArrayList<>();
|
|
||||||
|
|
||||||
public EventTimer(String firstEventName)
|
|
||||||
{
|
|
||||||
lastEventNs = System.nanoTime();
|
|
||||||
events.add(new Event(firstEventName));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void nextEvent(String name)
|
|
||||||
{
|
|
||||||
long timeNs = System.nanoTime();
|
|
||||||
if (lastEventNs != -1 && !events.isEmpty() && events.get(events.size() - 1).timeNs == -1)
|
|
||||||
{
|
|
||||||
events.get(events.size() - 1).timeNs = timeNs - lastEventNs;
|
|
||||||
}
|
|
||||||
lastEventNs = timeNs;
|
|
||||||
events.add(new Event(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void complete()
|
|
||||||
{
|
|
||||||
long timeNs = System.nanoTime();
|
|
||||||
if (lastEventNs != -1 && !events.isEmpty() && events.get(events.size() - 1).timeNs == -1)
|
|
||||||
{
|
|
||||||
events.get(events.size() - 1).timeNs = timeNs - lastEventNs;
|
|
||||||
}
|
|
||||||
lastEventNs = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getEventTimeNs(String name)
|
|
||||||
{
|
|
||||||
for (Event e : events)
|
|
||||||
{
|
|
||||||
if (e.name.equals(name))
|
|
||||||
{
|
|
||||||
return e.timeNs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTotalTimeNs()
|
|
||||||
{
|
|
||||||
long total = 0;
|
|
||||||
for (Event e : events)
|
|
||||||
{
|
|
||||||
if (e.timeNs != -1)
|
|
||||||
{
|
|
||||||
total += e.timeNs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (Event e : events)
|
|
||||||
{
|
|
||||||
if (e.timeNs != -1)
|
|
||||||
{
|
|
||||||
sb.append(e.name).append(": ").append(Duration.ofNanos(e.timeNs)).append('\n');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sb.append(e.name).append(": ").append("N/A").append('\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -41,7 +41,7 @@ public class RollingAverage
|
|||||||
// input //
|
// input //
|
||||||
//=======//
|
//=======//
|
||||||
|
|
||||||
public void addValue(double value)
|
public void add(double value)
|
||||||
{
|
{
|
||||||
this.arrayLock.lock();
|
this.arrayLock.lock();
|
||||||
try
|
try
|
||||||
|
|||||||
+2
-2
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
package com.seibel.distanthorizons.core.util.objects;
|
package com.seibel.distanthorizons.core.util.objects;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
import com.seibel.distanthorizons.core.util.ExceptionUtil;
|
||||||
|
|
||||||
import java.util.concurrent.CompletionException;
|
import java.util.concurrent.CompletionException;
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ public class UncheckedInterruptedException extends RuntimeException
|
|||||||
}
|
}
|
||||||
public static boolean isInterrupt(Throwable t)
|
public static boolean isInterrupt(Throwable t)
|
||||||
{
|
{
|
||||||
Throwable unwrapped = LodUtil.ensureUnwrap(t);
|
Throwable unwrapped = ExceptionUtil.ensureUnwrap(t);
|
||||||
return unwrapped instanceof InterruptedException || unwrapped instanceof UncheckedInterruptedException;
|
return unwrapped instanceof InterruptedException || unwrapped instanceof UncheckedInterruptedException;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+40
-10
@@ -20,9 +20,11 @@
|
|||||||
package com.seibel.distanthorizons.core.util.objects.dataStreams;
|
package com.seibel.distanthorizons.core.util.objects.dataStreams;
|
||||||
|
|
||||||
import com.github.luben.zstd.RecyclingBufferPool;
|
import com.github.luben.zstd.RecyclingBufferPool;
|
||||||
|
import com.github.luben.zstd.Zstd;
|
||||||
import com.github.luben.zstd.ZstdInputStream;
|
import com.github.luben.zstd.ZstdInputStream;
|
||||||
import com.seibel.distanthorizons.api.enums.config.EDhApiDataCompressionMode;
|
import com.seibel.distanthorizons.api.enums.config.EDhApiDataCompressionMode;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import it.unimi.dsi.fastutil.bytes.ByteArrayList;
|
||||||
import net.jpountz.lz4.LZ4FrameInputStream;
|
import net.jpountz.lz4.LZ4FrameInputStream;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
@@ -48,11 +50,34 @@ public class DhDataInputStream extends DataInputStream
|
|||||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
|
||||||
public DhDataInputStream(InputStream stream, EDhApiDataCompressionMode compressionMode) throws IOException
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
public static DhDataInputStream create(ByteArrayList byteArrayList, EDhApiDataCompressionMode compressionMode) throws IOException
|
||||||
|
{ return create(byteArrayList.toByteArray(), compressionMode); }
|
||||||
|
public static DhDataInputStream create(byte[] byteArray, EDhApiDataCompressionMode compressionMode) throws IOException
|
||||||
{
|
{
|
||||||
super(warpStream(new BufferedInputStream(stream), compressionMode));
|
// Z_Std handling compression outside the stream provides a significant performance boost
|
||||||
|
ByteArrayInputStream byteArrayInputStream;
|
||||||
|
if (compressionMode == EDhApiDataCompressionMode.Z_STD)
|
||||||
|
{
|
||||||
|
byteArrayInputStream = new ByteArrayInputStream(Zstd.decompress(byteArray));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
byteArrayInputStream = new ByteArrayInputStream(byteArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DhDataInputStream(byteArrayInputStream, compressionMode);
|
||||||
}
|
}
|
||||||
private static InputStream warpStream(InputStream stream, EDhApiDataCompressionMode compressionMode) throws IOException
|
private DhDataInputStream(ByteArrayInputStream stream, EDhApiDataCompressionMode compressionMode) throws IOException
|
||||||
|
{
|
||||||
|
super(warpStream(stream, compressionMode));
|
||||||
|
}
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
private static InputStream warpStream(ByteArrayInputStream stream, EDhApiDataCompressionMode compressionMode) throws IOException
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -63,15 +88,19 @@ public class DhDataInputStream extends DataInputStream
|
|||||||
case LZ4:
|
case LZ4:
|
||||||
return new LZ4FrameInputStream(stream);
|
return new LZ4FrameInputStream(stream);
|
||||||
case Z_STD:
|
case Z_STD:
|
||||||
return new ZstdInputStream(stream, RecyclingBufferPool.INSTANCE);
|
// ZStd compression should be handled before this point
|
||||||
|
// just return the stream
|
||||||
|
return stream;
|
||||||
case LZMA2:
|
case LZMA2:
|
||||||
// using an array cache significantly reduces GC pressure
|
// using an array cache significantly reduces GC pressure
|
||||||
ResettableArrayCache arrayCache = LZMA_RESETTABLE_ARRAY_CACHE_GETTER.get();
|
ResettableArrayCache arrayCache = LZMA_RESETTABLE_ARRAY_CACHE_GETTER.get();
|
||||||
arrayCache.reset();
|
arrayCache.reset();
|
||||||
|
|
||||||
// Note: all LZMA/XZ compressors can be decompressed using this same InputStream
|
// Note: all LZMA/XZ compressors can be decompressed using this same InputStream
|
||||||
return new XZInputStream(stream, arrayCache);
|
return new XZInputStream(stream, arrayCache);
|
||||||
|
|
||||||
|
case Z_STD_STREAM: // deprecated, only used for legacy support
|
||||||
|
return new ZstdInputStream(stream, RecyclingBufferPool.INSTANCE);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("No compressor defined for [" + compressionMode + "]");
|
throw new IllegalArgumentException("No compressor defined for [" + compressionMode + "]");
|
||||||
}
|
}
|
||||||
@@ -85,6 +114,11 @@ public class DhDataInputStream extends DataInputStream
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read() throws IOException
|
public int read() throws IOException
|
||||||
{
|
{
|
||||||
@@ -114,10 +148,6 @@ public class DhDataInputStream extends DataInputStream
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO at one point closing the streams caused errors, is that due to a bug with LZMA streams or some bug in DH's code that was since fixed?
|
|
||||||
// if streams aren't closed that cause cause higher-than-expected native memory use if the GC decides
|
|
||||||
// it doesn't want to clear the stream objects
|
|
||||||
//@Override
|
|
||||||
//public void close() throws IOException { /* Do nothing. */ }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+55
-11
@@ -19,9 +19,11 @@
|
|||||||
|
|
||||||
package com.seibel.distanthorizons.core.util.objects.dataStreams;
|
package com.seibel.distanthorizons.core.util.objects.dataStreams;
|
||||||
|
|
||||||
|
import com.github.luben.zstd.Zstd;
|
||||||
import com.github.luben.zstd.ZstdOutputStream;
|
import com.github.luben.zstd.ZstdOutputStream;
|
||||||
import com.seibel.distanthorizons.api.enums.config.EDhApiDataCompressionMode;
|
import com.seibel.distanthorizons.api.enums.config.EDhApiDataCompressionMode;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import it.unimi.dsi.fastutil.bytes.ByteArrayList;
|
||||||
import net.jpountz.lz4.LZ4Factory;
|
import net.jpountz.lz4.LZ4Factory;
|
||||||
import net.jpountz.lz4.LZ4FrameOutputStream;
|
import net.jpountz.lz4.LZ4FrameOutputStream;
|
||||||
import net.jpountz.xxhash.XXHashFactory;
|
import net.jpountz.xxhash.XXHashFactory;
|
||||||
@@ -41,13 +43,31 @@ public class DhDataOutputStream extends DataOutputStream
|
|||||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
private static final ThreadLocal<ResettableArrayCache> LZMA_RESETTABLE_ARRAY_CACHE_GETTER = ThreadLocal.withInitial(() -> new ResettableArrayCache(new LzmaArrayCache()));
|
private static final ThreadLocal<ResettableArrayCache> LZMA_RESETTABLE_ARRAY_CACHE_GETTER = ThreadLocal.withInitial(() -> new ResettableArrayCache(new LzmaArrayCache()));
|
||||||
|
|
||||||
|
private final ByteArrayList outputByteArray;
|
||||||
|
private final ByteArrayOutputStream wrappedByteStream;
|
||||||
|
private final EDhApiDataCompressionMode compressionMode;
|
||||||
|
|
||||||
|
|
||||||
public DhDataOutputStream(OutputStream stream, EDhApiDataCompressionMode compressionMode) throws IOException
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param outputByteArray where the contents of this stream will be written to when done
|
||||||
|
*/
|
||||||
|
public static DhDataOutputStream create(EDhApiDataCompressionMode compressionMode, ByteArrayList outputByteArray) throws IOException
|
||||||
|
{ return new DhDataOutputStream(new ByteArrayOutputStream(), compressionMode, outputByteArray); }
|
||||||
|
private DhDataOutputStream(ByteArrayOutputStream wrappedByteStream, EDhApiDataCompressionMode compressionMode, ByteArrayList outputByteArray) throws IOException
|
||||||
{
|
{
|
||||||
super(warpStream(new BufferedOutputStream(stream), compressionMode));
|
super(warpStream(wrappedByteStream, compressionMode));
|
||||||
|
|
||||||
|
this.wrappedByteStream = wrappedByteStream;
|
||||||
|
this.outputByteArray = outputByteArray;
|
||||||
|
this.compressionMode = compressionMode;
|
||||||
}
|
}
|
||||||
private static OutputStream warpStream(OutputStream stream, EDhApiDataCompressionMode compressionMode) throws IOException
|
@SuppressWarnings("deprecation")
|
||||||
|
private static OutputStream warpStream(ByteArrayOutputStream stream, EDhApiDataCompressionMode compressionMode) throws IOException
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -55,9 +75,6 @@ public class DhDataOutputStream extends DataOutputStream
|
|||||||
{
|
{
|
||||||
case UNCOMPRESSED:
|
case UNCOMPRESSED:
|
||||||
return stream;
|
return stream;
|
||||||
|
|
||||||
case Z_STD:
|
|
||||||
return new ZstdOutputStream(stream, 3, true, true);
|
|
||||||
case LZ4:
|
case LZ4:
|
||||||
return new LZ4FrameOutputStream(stream,
|
return new LZ4FrameOutputStream(stream,
|
||||||
LZ4FrameOutputStream.BLOCKSIZE.SIZE_64KB, -1L,
|
LZ4FrameOutputStream.BLOCKSIZE.SIZE_64KB, -1L,
|
||||||
@@ -68,6 +85,10 @@ public class DhDataOutputStream extends DataOutputStream
|
|||||||
//LZ4Factory.nativeInstance().fastCompressor(),
|
//LZ4Factory.nativeInstance().fastCompressor(),
|
||||||
//XXHashFactory.nativeInstance().hash32(),
|
//XXHashFactory.nativeInstance().hash32(),
|
||||||
LZ4FrameOutputStream.FLG.Bits.BLOCK_INDEPENDENCE);
|
LZ4FrameOutputStream.FLG.Bits.BLOCK_INDEPENDENCE);
|
||||||
|
case Z_STD:
|
||||||
|
// ZStd compression should be handled after the stream is closed
|
||||||
|
// just return the stream
|
||||||
|
return stream;
|
||||||
case LZMA2:
|
case LZMA2:
|
||||||
// using an array cache significantly reduces GC pressure
|
// using an array cache significantly reduces GC pressure
|
||||||
ResettableArrayCache arrayCache = LZMA_RESETTABLE_ARRAY_CACHE_GETTER.get();
|
ResettableArrayCache arrayCache = LZMA_RESETTABLE_ARRAY_CACHE_GETTER.get();
|
||||||
@@ -77,6 +98,10 @@ public class DhDataOutputStream extends DataOutputStream
|
|||||||
return new XZOutputStream(stream, new LZMA2Options(3),
|
return new XZOutputStream(stream, new LZMA2Options(3),
|
||||||
XZ.CHECK_CRC64, arrayCache);
|
XZ.CHECK_CRC64, arrayCache);
|
||||||
|
|
||||||
|
case Z_STD_STREAM: // deprecated, only used for legacy support
|
||||||
|
//return new ZstdOutputStream(stream, 3, true, true);
|
||||||
|
throw new UnsupportedOperationException("Z_STD_STREAM is deprecated and shouldn't be used for encoding. The faster block encoding format should be used instead.");
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("No compressor defined for ["+compressionMode+"]");
|
throw new IllegalArgumentException("No compressor defined for ["+compressionMode+"]");
|
||||||
}
|
}
|
||||||
@@ -90,10 +115,29 @@ public class DhDataOutputStream extends DataOutputStream
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO at one point closing the streams caused errors, is that due to a bug with LZMA streams or some bug in DH's code that was since fixed?
|
|
||||||
// if streams aren't closed that cause cause higher-than-expected native memory use if the GC decides
|
//================//
|
||||||
// it doesn't want to clear the stream objects
|
// base overrides //
|
||||||
//@Override
|
//================//
|
||||||
//public void close() throws IOException { /* Do nothing. */ }
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException
|
||||||
|
{
|
||||||
|
super.close();
|
||||||
|
|
||||||
|
|
||||||
|
this.outputByteArray.clear();
|
||||||
|
if (this.compressionMode == EDhApiDataCompressionMode.Z_STD)
|
||||||
|
{
|
||||||
|
this.outputByteArray.addElements(0, Zstd.compress(this.wrappedByteStream.toByteArray(), 3));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.outputByteArray.addElements(0, this.wrappedByteStream.toByteArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-2
@@ -190,7 +190,7 @@ public class PriorityTaskPicker
|
|||||||
{
|
{
|
||||||
return new RateLimitedThreadPoolExecutor(
|
return new RateLimitedThreadPoolExecutor(
|
||||||
Config.Common.MultiThreading.numberOfThreads.get(),
|
Config.Common.MultiThreading.numberOfThreads.get(),
|
||||||
new DhThreadFactory(this.name, Thread.MIN_PRIORITY, false),
|
new DhThreadFactory(this.name, Config.Common.MultiThreading.threadPriority.get(), false),
|
||||||
new ArrayBlockingQueue<>(Runtime.getRuntime().availableProcessors())
|
new ArrayBlockingQueue<>(Runtime.getRuntime().availableProcessors())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -224,6 +224,13 @@ public class PriorityTaskPicker
|
|||||||
@Override
|
@Override
|
||||||
public void execute(@NotNull Runnable command)
|
public void execute(@NotNull Runnable command)
|
||||||
{
|
{
|
||||||
|
// needed so we don't try queuing tasks that will never be completed
|
||||||
|
if (this.threadPoolExecutor.isShutdown())
|
||||||
|
{
|
||||||
|
throw new RejectedExecutionException("Thread pool ["+this.name+"] shutdown.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
this.taskQueue.add(new TrackedRunnable(this.parentTaskPicker, this, command));
|
this.taskQueue.add(new TrackedRunnable(this.parentTaskPicker, this, command));
|
||||||
|
|
||||||
// Attempt to start the task immediately
|
// Attempt to start the task immediately
|
||||||
@@ -249,6 +256,8 @@ public class PriorityTaskPicker
|
|||||||
/** Will return NaN if nothing has been submitted yet */
|
/** Will return NaN if nothing has been submitted yet */
|
||||||
public double getAverageRunTimeInMs() { return this.runTimeInMsRollingAverage.getAverage(); }
|
public double getAverageRunTimeInMs() { return this.runTimeInMsRollingAverage.getAverage(); }
|
||||||
|
|
||||||
|
public void clearQueue() { this.taskQueue.clear(); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==========//
|
//==========//
|
||||||
@@ -311,7 +320,7 @@ public class PriorityTaskPicker
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
long timeElapsed = System.nanoTime() - startTime;
|
long timeElapsed = System.nanoTime() - startTime;
|
||||||
this.executor.runTimeInMsRollingAverage.addValue(TimeUnit.NANOSECONDS.toMillis(timeElapsed));
|
this.executor.runTimeInMsRollingAverage.add(TimeUnit.NANOSECONDS.toMillis(timeElapsed));
|
||||||
|
|
||||||
// Update variables related to task status
|
// Update variables related to task status
|
||||||
this.parentTaskPicker.occupiedThreadsRef.getAndDecrement();
|
this.parentTaskPicker.occupiedThreadsRef.getAndDecrement();
|
||||||
|
|||||||
+7
-13
@@ -54,7 +54,13 @@ public abstract class AbstractDhServerWorld<TDhServerLevel extends AbstractDhSer
|
|||||||
public void addPlayer(IServerPlayerWrapper serverPlayer)
|
public void addPlayer(IServerPlayerWrapper serverPlayer)
|
||||||
{
|
{
|
||||||
ServerPlayerState playerState = this.serverPlayerStateManager.registerJoinedPlayer(serverPlayer);
|
ServerPlayerState playerState = this.serverPlayerStateManager.registerJoinedPlayer(serverPlayer);
|
||||||
((TDhServerLevel) this.getOrLoadServerLevel(serverPlayer.getLevel())).addPlayer(serverPlayer);
|
AbstractDhServerLevel serverLevel = (AbstractDhServerLevel) this.getOrLoadServerLevel(serverPlayer.getLevel());
|
||||||
|
if (serverLevel == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
serverLevel.addPlayer(serverPlayer);
|
||||||
|
|
||||||
Iterator<TDhServerLevel> it = this.dhLevelByLevelWrapper.values().stream().distinct().iterator();
|
Iterator<TDhServerLevel> it = this.dhLevelByLevelWrapper.values().stream().distinct().iterator();
|
||||||
while (it.hasNext())
|
while (it.hasNext())
|
||||||
@@ -117,18 +123,6 @@ public abstract class AbstractDhServerWorld<TDhServerLevel extends AbstractDhSer
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==============//
|
|
||||||
// tick methods //
|
|
||||||
//==============//
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void serverTick() { this.dhLevelByLevelWrapper.values().forEach(TDhServerLevel::serverTick); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void worldGenTick() { this.dhLevelByLevelWrapper.values().forEach(TDhServerLevel::worldGenTick); }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//================//
|
//================//
|
||||||
// base overrides //
|
// base overrides //
|
||||||
//================//
|
//================//
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
package com.seibel.distanthorizons.core.world;
|
package com.seibel.distanthorizons.core.world;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||||
import com.seibel.distanthorizons.core.level.DhClientServerLevel;
|
import com.seibel.distanthorizons.core.level.DhClientServerLevel;
|
||||||
import com.seibel.distanthorizons.core.util.ThreadUtil;
|
import com.seibel.distanthorizons.core.util.ThreadUtil;
|
||||||
import com.seibel.distanthorizons.core.util.objects.EventLoop;
|
import com.seibel.distanthorizons.core.util.objects.EventLoop;
|
||||||
@@ -67,9 +68,22 @@ public class DhClientServerWorld extends AbstractDhServerWorld<DhClientServerLev
|
|||||||
{
|
{
|
||||||
return this.dhLevelByLevelWrapper.computeIfAbsent(wrapper, (levelWrapper) ->
|
return this.dhLevelByLevelWrapper.computeIfAbsent(wrapper, (levelWrapper) ->
|
||||||
{
|
{
|
||||||
DhClientServerLevel level = new DhClientServerLevel(this.saveStructure, (IServerLevelWrapper) levelWrapper, this.getServerPlayerStateManager());
|
try
|
||||||
this.dhLevels.add(level);
|
{
|
||||||
return level;
|
DhClientServerLevel level = new DhClientServerLevel(this.saveStructure, (IServerLevelWrapper) levelWrapper, this.getServerPlayerStateManager());
|
||||||
|
this.dhLevels.add(level);
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LOGGER.fatal("Failed to load client-server level, error: ["+e.getMessage()+"].", e);
|
||||||
|
|
||||||
|
ClientApi.INSTANCE.showChatMessageNextFrame(// red text
|
||||||
|
"\u00A7c" + "Distant Horizons: ClientServer level loading failed." + "\u00A7r \n" +
|
||||||
|
"Unable to load level ["+levelWrapper.getDhIdentifier()+"], LODs may not appear. See log for more information.");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
package com.seibel.distanthorizons.core.world;
|
package com.seibel.distanthorizons.core.world;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||||
import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure;
|
import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure;
|
||||||
import com.seibel.distanthorizons.core.level.DhClientLevel;
|
import com.seibel.distanthorizons.core.level.DhClientLevel;
|
||||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||||
@@ -75,7 +76,23 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
|||||||
}
|
}
|
||||||
|
|
||||||
return this.levels.computeIfAbsent((IClientLevelWrapper) wrapper,
|
return this.levels.computeIfAbsent((IClientLevelWrapper) wrapper,
|
||||||
(clientLevelWrapper) -> new DhClientLevel(this.saveStructure, clientLevelWrapper, this.networkState));
|
(clientLevelWrapper) ->
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return new DhClientLevel(this.saveStructure, clientLevelWrapper, this.networkState);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LOGGER.fatal("Failed to load client level, error: ["+e.getMessage()+"].", e);
|
||||||
|
|
||||||
|
ClientApi.INSTANCE.showChatMessageNextFrame(// red text
|
||||||
|
"\u00A7c" + "Distant Horizons: Client level loading failed." + "\u00A7r \n" +
|
||||||
|
"Unable to load level ["+clientLevelWrapper.getDhIdentifier()+"], LODs may not appear. See log for more information.");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -115,9 +132,6 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
|||||||
@Override
|
@Override
|
||||||
public void clientTick() { this.eventLoop.tick(); }
|
public void clientTick() { this.eventLoop.tick(); }
|
||||||
|
|
||||||
@Override
|
|
||||||
public void worldGenTick() { this.levels.values().forEach(DhClientLevel::worldGenTick); }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addDebugMenuStringsToList(List<String> messageList)
|
public void addDebugMenuStringsToList(List<String> messageList)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
package com.seibel.distanthorizons.core.world;
|
package com.seibel.distanthorizons.core.world;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||||
import com.seibel.distanthorizons.core.level.DhServerLevel;
|
import com.seibel.distanthorizons.core.level.DhServerLevel;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||||
@@ -51,7 +52,23 @@ public class DhServerWorld extends AbstractDhServerWorld<DhServerLevel>
|
|||||||
}
|
}
|
||||||
|
|
||||||
return this.dhLevelByLevelWrapper.computeIfAbsent(wrapper,
|
return this.dhLevelByLevelWrapper.computeIfAbsent(wrapper,
|
||||||
(serverLevelWrapper) -> new DhServerLevel(this.saveStructure, (IServerLevelWrapper) serverLevelWrapper, this.getServerPlayerStateManager()));
|
(serverLevelWrapper) ->
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return new DhServerLevel(this.saveStructure, (IServerLevelWrapper) serverLevelWrapper, this.getServerPlayerStateManager());
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LOGGER.fatal("Failed to load server level, error: ["+e.getMessage()+"].", e);
|
||||||
|
|
||||||
|
ClientApi.INSTANCE.showChatMessageNextFrame(// red text
|
||||||
|
"\u00A7c" + "Distant Horizons: Server level loading failed." + "\u00A7r \n" +
|
||||||
|
"Unable to load level ["+serverLevelWrapper.getDhIdentifier()+"], LODs may not appear. See log for more information.");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import com.seibel.distanthorizons.core.multiplayer.server.ServerPlayerStateManag
|
|||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
/** Used both for dedicated server and singleplayer worlds */
|
/** Used both for dedicated server and singleplayer worlds */
|
||||||
public interface IDhServerWorld extends IDhWorld
|
public interface IDhServerWorld extends IDhWorld
|
||||||
@@ -32,8 +33,8 @@ public interface IDhServerWorld extends IDhWorld
|
|||||||
void addPlayer(IServerPlayerWrapper serverPlayer);
|
void addPlayer(IServerPlayerWrapper serverPlayer);
|
||||||
void removePlayer(IServerPlayerWrapper serverPlayer);
|
void removePlayer(IServerPlayerWrapper serverPlayer);
|
||||||
void changePlayerLevel(IServerPlayerWrapper player, IServerLevelWrapper originLevel, IServerLevelWrapper destinationLevel);
|
void changePlayerLevel(IServerPlayerWrapper player, IServerLevelWrapper originLevel, IServerLevelWrapper destinationLevel);
|
||||||
void serverTick();
|
|
||||||
|
|
||||||
|
@Nullable
|
||||||
default IDhServerLevel getOrLoadServerLevel(ILevelWrapper levelWrapper) { return (IDhServerLevel) this.getOrLoadLevel(levelWrapper); }
|
default IDhServerLevel getOrLoadServerLevel(ILevelWrapper levelWrapper) { return (IDhServerLevel) this.getOrLoadLevel(levelWrapper); }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import java.util.concurrent.CompletableFuture;
|
|||||||
public interface IDhWorld extends Closeable
|
public interface IDhWorld extends Closeable
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@Nullable
|
||||||
IDhLevel getOrLoadLevel(@NotNull ILevelWrapper levelWrapper);
|
IDhLevel getOrLoadLevel(@NotNull ILevelWrapper levelWrapper);
|
||||||
@Nullable
|
@Nullable
|
||||||
IDhLevel getLevel(@NotNull ILevelWrapper wrapper);
|
IDhLevel getLevel(@NotNull ILevelWrapper wrapper);
|
||||||
@@ -39,6 +40,4 @@ public interface IDhWorld extends Closeable
|
|||||||
|
|
||||||
void unloadLevel(@NotNull ILevelWrapper levelWrapper);
|
void unloadLevel(@NotNull ILevelWrapper levelWrapper);
|
||||||
|
|
||||||
void worldGenTick();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -25,7 +25,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrappe
|
|||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvironmentWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.IBatchGeneratorEnvironmentWrapper;
|
||||||
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindable;
|
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindable;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -39,7 +39,7 @@ import java.util.HashSet;
|
|||||||
*/
|
*/
|
||||||
public interface IWrapperFactory extends IDhApiWrapperFactory, IBindable
|
public interface IWrapperFactory extends IDhApiWrapperFactory, IBindable
|
||||||
{
|
{
|
||||||
AbstractBatchGenerationEnvironmentWrapper createBatchGenerator(IDhLevel targetLevel);
|
IBatchGeneratorEnvironmentWrapper createBatchGenerator(IDhLevel targetLevel);
|
||||||
|
|
||||||
IBiomeWrapper deserializeBiomeWrapper(String str, ILevelWrapper levelWrapper) throws IOException;
|
IBiomeWrapper deserializeBiomeWrapper(String str, ILevelWrapper levelWrapper) throws IOException;
|
||||||
IBiomeWrapper getPlainsBiomeWrapper(ILevelWrapper levelWrapper); // TODO it would be nice to remove the level wrapper if possible to put this in line with getAirBlockStateWrapper() but it isn't necessary
|
IBiomeWrapper getPlainsBiomeWrapper(ILevelWrapper levelWrapper); // TODO it would be nice to remove the level wrapper if possible to put this in line with getAirBlockStateWrapper() but it isn't necessary
|
||||||
|
|||||||
+6
@@ -158,6 +158,12 @@ public class ChunkLightStorage
|
|||||||
lightSection.set(x, y, z, lightLevel);
|
lightSection.set(x, y, z, lightLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty()
|
||||||
|
{
|
||||||
|
return this.lightSections == null
|
||||||
|
|| this.lightSections.length == 0;
|
||||||
|
}
|
||||||
|
|
||||||
public void clear()
|
public void clear()
|
||||||
{
|
{
|
||||||
if (this.lightSections != null)
|
if (this.lightSections != null)
|
||||||
|
|||||||
+2
@@ -32,4 +32,6 @@ public interface IMinecraftSharedWrapper extends IBindable
|
|||||||
|
|
||||||
int getPlayerCount();
|
int getPlayerCount();
|
||||||
|
|
||||||
|
void setPreventAutoPause(boolean preventAutoPause);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-27
@@ -17,34 +17,9 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.seibel.distanthorizons.core.enums.worldGeneration;
|
package com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor;
|
||||||
|
|
||||||
/**
|
public interface IC2meAccessor extends IModAccessor
|
||||||
* MULTI_THREADED, <br>
|
|
||||||
* SINGLE_THREADED, <br>
|
|
||||||
* SERVER_THREAD, <br>
|
|
||||||
*
|
|
||||||
* @author James Seibel
|
|
||||||
* @version 7-25-2022
|
|
||||||
*/
|
|
||||||
public enum EWorldGenThreadMode
|
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* This world generator can be run on an unlimited number
|
|
||||||
* of concurrent threads.
|
|
||||||
*/
|
|
||||||
MULTI_THREADED,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This world generator can only be run on one thread at
|
|
||||||
* a time, however that thread can run concurrently
|
|
||||||
* to Minecraft's server thread.
|
|
||||||
*/
|
|
||||||
SINGLE_THREADED,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This world generator can only be run on Minecraft's
|
|
||||||
* server thread.
|
|
||||||
*/
|
|
||||||
SERVER_THREAD,
|
|
||||||
}
|
}
|
||||||
+7
-11
@@ -21,25 +21,21 @@ package com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration;
|
|||||||
|
|
||||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode;
|
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode;
|
||||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep;
|
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep;
|
||||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public abstract class AbstractBatchGenerationEnvironmentWrapper
|
public interface IBatchGeneratorEnvironmentWrapper extends AutoCloseable
|
||||||
{
|
{
|
||||||
public AbstractBatchGenerationEnvironmentWrapper(IDhLevel level) { }
|
void updateAllFutures();
|
||||||
|
|
||||||
public abstract void updateAllFutures();
|
CompletableFuture<Void> queueGenEvent(
|
||||||
|
int minX, int minZ, int genSize,
|
||||||
public abstract int getEventCount();
|
EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep targetStep,
|
||||||
|
|
||||||
public abstract void stop();
|
|
||||||
|
|
||||||
public abstract CompletableFuture<Void> generateChunks(
|
|
||||||
int minX, int minZ, int genSize, EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep targetStep,
|
|
||||||
ExecutorService worldGeneratorThreadPool, Consumer<IChunkWrapper> resultConsumer);
|
ExecutorService worldGeneratorThreadPool, Consumer<IChunkWrapper> resultConsumer);
|
||||||
|
|
||||||
|
void close();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -678,6 +678,10 @@
|
|||||||
"How many threads DH will use.",
|
"How many threads DH will use.",
|
||||||
"distanthorizons.config.common.multiThreading.threadRunTimeRatio":
|
"distanthorizons.config.common.multiThreading.threadRunTimeRatio":
|
||||||
"Runtime % for threads",
|
"Runtime % for threads",
|
||||||
|
"distanthorizons.config.common.multiThreading.threadPriority":
|
||||||
|
"Thread Priority",
|
||||||
|
"distanthorizons.config.common.multiThreading.threadPriority.@tooltip":
|
||||||
|
"What Java thread priority should DH's primary thread pools run with?\n\nYou probably don't need to change this unless you are also \nrunning C2ME and are seeing thread starvation in either C2ME or DH.",
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -720,6 +724,8 @@
|
|||||||
"Show Replay Warning",
|
"Show Replay Warning",
|
||||||
"distanthorizons.config.common.logging.warning.showUpdateQueueOverloadedChatWarning":
|
"distanthorizons.config.common.logging.warning.showUpdateQueueOverloadedChatWarning":
|
||||||
"Show Update Queue Overloaded Warning",
|
"Show Update Queue Overloaded Warning",
|
||||||
|
"distanthorizons.config.common.logging.warning.showSlowWorldGenSettingWarnings":
|
||||||
|
"Show Slow World Gen Warnings",
|
||||||
"distanthorizons.config.common.logging.warning.showModCompatibilityWarningsOnStartup":
|
"distanthorizons.config.common.logging.warning.showModCompatibilityWarningsOnStartup":
|
||||||
"Show Mod Compatibility Warnings",
|
"Show Mod Compatibility Warnings",
|
||||||
|
|
||||||
@@ -975,7 +981,9 @@
|
|||||||
"distanthorizons.config.enum.EDhApiDataCompressionMode.LZ4":
|
"distanthorizons.config.enum.EDhApiDataCompressionMode.LZ4":
|
||||||
"Fastest/Big - LZ4",
|
"Fastest/Big - LZ4",
|
||||||
"distanthorizons.config.enum.EDhApiDataCompressionMode.Z_STD":
|
"distanthorizons.config.enum.EDhApiDataCompressionMode.Z_STD":
|
||||||
"Fast/Small - Z_STD",
|
"Fastest/Small - Z_STD - Block",
|
||||||
|
"distanthorizons.config.enum.EDhApiDataCompressionMode.Z_STD_STREAM":
|
||||||
|
"Fast/Small - Z_STD - Stream",
|
||||||
"distanthorizons.config.enum.EDhApiDataCompressionMode.LZMA2":
|
"distanthorizons.config.enum.EDhApiDataCompressionMode.LZMA2":
|
||||||
"Slow/Smallest - LZMA2",
|
"Slow/Smallest - LZMA2",
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import com.seibel.distanthorizons.core.sql.repo.AbstractDhRepo;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
@@ -33,7 +34,7 @@ import java.util.Map;
|
|||||||
public class TestCompoundKeyRepo extends AbstractDhRepo<DhChunkPos, TestCompoundKeyDto>
|
public class TestCompoundKeyRepo extends AbstractDhRepo<DhChunkPos, TestCompoundKeyDto>
|
||||||
{
|
{
|
||||||
|
|
||||||
public TestCompoundKeyRepo(String databaseType, File databaseFile) throws SQLException
|
public TestCompoundKeyRepo(String databaseType, File databaseFile) throws SQLException, IOException
|
||||||
{
|
{
|
||||||
super(databaseType, databaseFile, TestCompoundKeyDto.class);
|
super(databaseType, databaseFile, TestCompoundKeyDto.class);
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import com.seibel.distanthorizons.core.sql.repo.AbstractDhRepo;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
@@ -32,7 +33,7 @@ import java.util.Map;
|
|||||||
public class TestPrimaryKeyRepo extends AbstractDhRepo<Integer, TestSingleKeyDto>
|
public class TestPrimaryKeyRepo extends AbstractDhRepo<Integer, TestSingleKeyDto>
|
||||||
{
|
{
|
||||||
|
|
||||||
public TestPrimaryKeyRepo(String databaseType, File databaseFile) throws SQLException
|
public TestPrimaryKeyRepo(String databaseType, File databaseFile) throws SQLException, IOException
|
||||||
{
|
{
|
||||||
super(databaseType, databaseFile, TestSingleKeyDto.class);
|
super(databaseType, databaseFile, TestSingleKeyDto.class);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package testItems.wrappers;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||||
|
|
||||||
|
public class TestBiomeWrapper implements IBiomeWrapper
|
||||||
|
{
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
|
||||||
|
public TestBiomeWrapper(String name)
|
||||||
|
{ this.name = name; }
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName()
|
||||||
|
{ return this.name; }
|
||||||
|
@Override
|
||||||
|
public String getSerialString()
|
||||||
|
{ return this.name; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getWrappedMcObject()
|
||||||
|
{ return this; }
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{ return this.name.hashCode(); }
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj)
|
||||||
|
{
|
||||||
|
if (!(obj instanceof TestBiomeWrapper))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.name.equals(((TestBiomeWrapper)obj).name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package testItems.wrappers;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
public class TestBlockStateWrapper implements IBlockStateWrapper
|
||||||
|
{
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
|
||||||
|
public TestBlockStateWrapper(String name)
|
||||||
|
{ this.name = name; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAir()
|
||||||
|
{ return false; }
|
||||||
|
@Override
|
||||||
|
public boolean isSolid()
|
||||||
|
{ return true; }
|
||||||
|
@Override
|
||||||
|
public boolean isLiquid()
|
||||||
|
{ return false; }
|
||||||
|
@Override
|
||||||
|
public String getSerialString()
|
||||||
|
{ return this.name; }
|
||||||
|
@Override
|
||||||
|
public int getOpacity()
|
||||||
|
{ return 15; }
|
||||||
|
@Override
|
||||||
|
public int getLightEmission()
|
||||||
|
{ return 0; }
|
||||||
|
@Override
|
||||||
|
public byte getMaterialId()
|
||||||
|
{ return 0; }
|
||||||
|
@Override
|
||||||
|
public boolean isBeaconBlock()
|
||||||
|
{ return false; }
|
||||||
|
@Override
|
||||||
|
public boolean isBeaconTintBlock()
|
||||||
|
{ return false; }
|
||||||
|
@Override
|
||||||
|
public boolean allowsBeaconBeamPassage()
|
||||||
|
{ return false; }
|
||||||
|
@Override
|
||||||
|
public boolean isBeaconBaseBlock()
|
||||||
|
{ return false; }
|
||||||
|
@Override
|
||||||
|
public Color getMapColor()
|
||||||
|
{ return Color.MAGENTA; }
|
||||||
|
@Override
|
||||||
|
public Color getBeaconTintColor()
|
||||||
|
{ return Color.MAGENTA; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getWrappedMcObject()
|
||||||
|
{ return this; }
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{ return this.name.hashCode(); }
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj)
|
||||||
|
{
|
||||||
|
if (!(obj instanceof TestBlockStateWrapper))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.name.equals(((TestBlockStateWrapper)obj).name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+2
-2
@@ -30,7 +30,6 @@ import com.seibel.distanthorizons.core.sql.repo.FullDataSourceV2Repo;
|
|||||||
import com.seibel.distanthorizons.core.util.FullDataPointUtil;
|
import com.seibel.distanthorizons.core.util.FullDataPointUtil;
|
||||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||||
import com.seibel.distanthorizons.core.util.ThreadUtil;
|
import com.seibel.distanthorizons.core.util.ThreadUtil;
|
||||||
import com.seibel.distanthorizons.core.util.objects.DataCorruptedException;
|
|
||||||
import it.unimi.dsi.fastutil.bytes.ByteArrayList;
|
import it.unimi.dsi.fastutil.bytes.ByteArrayList;
|
||||||
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
@@ -50,7 +49,7 @@ import java.util.concurrent.atomic.LongAdder;
|
|||||||
* Can also be used to test if there are memory leaks in SQLite
|
* Can also be used to test if there are memory leaks in SQLite
|
||||||
* and if the {@link FullDataSourceV2DTO}/{@link FullDataSourceV2}'s are using pooled objects correctly
|
* and if the {@link FullDataSourceV2DTO}/{@link FullDataSourceV2}'s are using pooled objects correctly
|
||||||
*/
|
*/
|
||||||
public class DhFullDataSourceRepoTests
|
public class DataSourceRepoTests
|
||||||
{
|
{
|
||||||
public static String DATABASE_TYPE = "jdbc:sqlite";
|
public static String DATABASE_TYPE = "jdbc:sqlite";
|
||||||
public static String DB_FILE_NAME = "test.sqlite";
|
public static String DB_FILE_NAME = "test.sqlite";
|
||||||
@@ -395,4 +394,5 @@ public class DhFullDataSourceRepoTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,236 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL 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 Lesser 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 Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tests;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.enums.config.EDhApiWorldCompressionMode;
|
||||||
|
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep;
|
||||||
|
import com.seibel.distanthorizons.core.dataObjects.fullData.FullDataPointIdMap;
|
||||||
|
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
|
||||||
|
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||||
|
import com.seibel.distanthorizons.core.util.FullDataPointUtil;
|
||||||
|
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||||
|
import com.seibel.distanthorizons.core.util.objects.DataCorruptedException;
|
||||||
|
import it.unimi.dsi.fastutil.bytes.ByteArrayList;
|
||||||
|
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import testItems.wrappers.TestBiomeWrapper;
|
||||||
|
import testItems.wrappers.TestBlockStateWrapper;
|
||||||
|
|
||||||
|
import java.text.NumberFormat;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DataSourceUpdateSpeedTest
|
||||||
|
{
|
||||||
|
//@Test
|
||||||
|
public void test() throws DataCorruptedException
|
||||||
|
{
|
||||||
|
Random seededRandom = new Random(3);
|
||||||
|
|
||||||
|
|
||||||
|
//===================//
|
||||||
|
// parent datasource //
|
||||||
|
//===================//
|
||||||
|
|
||||||
|
long parentPos = DhSectionPos.encode((byte)7, 0, 0);
|
||||||
|
|
||||||
|
FullDataSourceV2 parentDataSource;
|
||||||
|
{
|
||||||
|
FullDataPointIdMap dataMapping = new FullDataPointIdMap(parentPos);
|
||||||
|
LongArrayList[] fullDataArray = new LongArrayList[FullDataSourceV2.WIDTH * FullDataSourceV2.WIDTH];
|
||||||
|
|
||||||
|
for (int arrayIndex = 0; arrayIndex < FullDataSourceV2.WIDTH * FullDataSourceV2.WIDTH; arrayIndex++)
|
||||||
|
{
|
||||||
|
fullDataArray[arrayIndex] = new LongArrayList(1);
|
||||||
|
|
||||||
|
// random column heights so we can differentiate
|
||||||
|
// columns from each other
|
||||||
|
int columnCount = Math.abs(seededRandom.nextInt() % 31) + 1;
|
||||||
|
int lastMaxY = 4000;
|
||||||
|
for (int colIndex = columnCount; colIndex >= 0; colIndex--)
|
||||||
|
{
|
||||||
|
int height = (Math.abs(seededRandom.nextInt()) % 20) + 1;
|
||||||
|
lastMaxY -= height;
|
||||||
|
|
||||||
|
long datapoint = FullDataPointUtil.encode(
|
||||||
|
colIndex, // id
|
||||||
|
height, // height
|
||||||
|
lastMaxY, // relative min Y
|
||||||
|
LodUtil.MIN_MC_LIGHT, // block light
|
||||||
|
LodUtil.MIN_MC_LIGHT // sky light
|
||||||
|
);
|
||||||
|
fullDataArray[arrayIndex].add(datapoint);
|
||||||
|
|
||||||
|
dataMapping.addIfNotPresentAndGetId(
|
||||||
|
new TestBiomeWrapper(colIndex+""),
|
||||||
|
new TestBlockStateWrapper(colIndex+""));
|
||||||
|
}
|
||||||
|
|
||||||
|
FullDataSourceV2.throwIfDataColumnInWrongOrder(parentPos, fullDataArray[arrayIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] columnGenStep = new byte[FullDataSourceV2.WIDTH * FullDataSourceV2.WIDTH];
|
||||||
|
Arrays.fill(columnGenStep, EDhApiWorldGenerationStep.FEATURES.value);
|
||||||
|
|
||||||
|
byte[] columnWorldCompressionMode = new byte[FullDataSourceV2.WIDTH * FullDataSourceV2.WIDTH];
|
||||||
|
Arrays.fill(columnWorldCompressionMode, EDhApiWorldCompressionMode.VISUALLY_EQUAL.value);
|
||||||
|
|
||||||
|
parentDataSource = FullDataSourceV2.createWithData(parentPos, dataMapping, fullDataArray, columnGenStep, columnWorldCompressionMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==================//
|
||||||
|
// child datasource //
|
||||||
|
//==================//
|
||||||
|
|
||||||
|
long childPos = DhSectionPos.encode((byte)6, 0, 0);
|
||||||
|
|
||||||
|
FullDataSourceV2 childDataSource;
|
||||||
|
{
|
||||||
|
FullDataPointIdMap dataMapping = new FullDataPointIdMap(childPos);
|
||||||
|
LongArrayList[] fullDataArray = new LongArrayList[FullDataSourceV2.WIDTH * FullDataSourceV2.WIDTH];
|
||||||
|
|
||||||
|
for (int arrayIndex = 0; arrayIndex < FullDataSourceV2.WIDTH * FullDataSourceV2.WIDTH; arrayIndex++)
|
||||||
|
{
|
||||||
|
fullDataArray[arrayIndex] = new LongArrayList(1);
|
||||||
|
|
||||||
|
// random column heights so we can differentiate
|
||||||
|
// columns from each other
|
||||||
|
int columnCount = Math.abs(seededRandom.nextInt() % 31) + 1;
|
||||||
|
int lastMaxY = 4000;
|
||||||
|
for (int colIndex = columnCount; colIndex >= 0; colIndex--)
|
||||||
|
{
|
||||||
|
int height = (Math.abs(seededRandom.nextInt()) % 20) + 1;
|
||||||
|
lastMaxY -= height;
|
||||||
|
|
||||||
|
long datapoint = FullDataPointUtil.encode(
|
||||||
|
colIndex, // id
|
||||||
|
height, // height
|
||||||
|
lastMaxY, // relative min Y
|
||||||
|
LodUtil.MAX_MC_LIGHT, // block light
|
||||||
|
LodUtil.MAX_MC_LIGHT // sky light
|
||||||
|
);
|
||||||
|
fullDataArray[arrayIndex].add(datapoint);
|
||||||
|
|
||||||
|
dataMapping.addIfNotPresentAndGetId(
|
||||||
|
new TestBiomeWrapper(colIndex+""),
|
||||||
|
new TestBlockStateWrapper(colIndex+""));
|
||||||
|
}
|
||||||
|
|
||||||
|
FullDataSourceV2.throwIfDataColumnInWrongOrder(childPos, fullDataArray[arrayIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] columnGenStep = new byte[FullDataSourceV2.WIDTH * FullDataSourceV2.WIDTH];
|
||||||
|
Arrays.fill(columnGenStep, EDhApiWorldGenerationStep.FEATURES.value);
|
||||||
|
|
||||||
|
byte[] columnWorldCompressionMode = new byte[FullDataSourceV2.WIDTH * FullDataSourceV2.WIDTH];
|
||||||
|
Arrays.fill(columnWorldCompressionMode, EDhApiWorldCompressionMode.VISUALLY_EQUAL.value);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
childDataSource = FullDataSourceV2.createWithData(childPos, dataMapping, fullDataArray, columnGenStep, columnWorldCompressionMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========================//
|
||||||
|
// (optional) loop forever //
|
||||||
|
//=========================//
|
||||||
|
|
||||||
|
// this can be set to "true"
|
||||||
|
// so we can profile the DTO creation process and
|
||||||
|
// see if there are any object leaks and how the GC
|
||||||
|
// handles it
|
||||||
|
if (true)
|
||||||
|
{
|
||||||
|
System.out.println("Starting long update test for time testing...");
|
||||||
|
|
||||||
|
long lastLogMsTime = 0;
|
||||||
|
|
||||||
|
long totalNano = 0;
|
||||||
|
|
||||||
|
NumberFormat numberFormat = NumberFormat.getNumberInstance();
|
||||||
|
|
||||||
|
// run for a long time
|
||||||
|
for (int i = 1; i < 100_000_000; i++)
|
||||||
|
{
|
||||||
|
long startNano = System.nanoTime();
|
||||||
|
|
||||||
|
boolean updated = parentDataSource.updateFromDataSource(childDataSource);
|
||||||
|
//Assert.assertTrue(updated);
|
||||||
|
|
||||||
|
long updateTimeNano = System.nanoTime() - startNano;
|
||||||
|
totalNano += updateTimeNano;
|
||||||
|
|
||||||
|
long nowMs = System.currentTimeMillis();
|
||||||
|
if (nowMs - lastLogMsTime > 5_000)
|
||||||
|
{
|
||||||
|
lastLogMsTime = nowMs;
|
||||||
|
|
||||||
|
double avgMs = ((totalNano / 1_000_000.0)/i);
|
||||||
|
double totalMs = totalNano / 1_000_000.0;
|
||||||
|
System.out.println("count: "+numberFormat.format(i)+"\tavg ms: "+numberFormat.format(avgMs)+"\ttotal ms: "+numberFormat.format(totalMs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// helper methods //
|
||||||
|
//================//
|
||||||
|
|
||||||
|
private static void assertArraysAreEqual(ByteArrayList expectedArray, ByteArrayList actualArray)
|
||||||
|
{
|
||||||
|
Assert.assertEquals("size mismatch", expectedArray.size(), actualArray.size());
|
||||||
|
|
||||||
|
for (int i = 0; i < expectedArray.size(); i++)
|
||||||
|
{
|
||||||
|
byte expectedNumb = expectedArray.getByte(i);
|
||||||
|
byte actualNumb = actualArray.getByte(i);
|
||||||
|
|
||||||
|
Assert.assertEquals("value mismatch at index ["+i+"]", expectedNumb, actualNumb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertArraysAreEqual(LongArrayList expectedArray, LongArrayList actualArray)
|
||||||
|
{ assertArraysAreEqual(null, expectedArray, actualArray); }
|
||||||
|
private static void assertArraysAreEqual(String message, LongArrayList expectedArray, LongArrayList actualArray)
|
||||||
|
{
|
||||||
|
Assert.assertEquals(message + "size mismatch", expectedArray.size(), actualArray.size());
|
||||||
|
|
||||||
|
for (int i = 0; i < expectedArray.size(); i++)
|
||||||
|
{
|
||||||
|
long expectedNumb = expectedArray.getLong(i);
|
||||||
|
long actualNumb = actualArray.getLong(i);
|
||||||
|
|
||||||
|
Assert.assertEquals(message + "value mismatch at index ["+i+"]", expectedNumb, actualNumb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -34,6 +34,7 @@ import testItems.sql.TestPrimaryKeyRepo;
|
|||||||
import testItems.sql.TestSingleKeyDto;
|
import testItems.sql.TestSingleKeyDto;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
@@ -137,7 +138,7 @@ public class DhRepoSqliteTest
|
|||||||
Assert.assertFalse("DTO exists failed", primaryKeyRepo.existsWithKey(insertDto.getKey()));
|
Assert.assertFalse("DTO exists failed", primaryKeyRepo.existsWithKey(insertDto.getKey()));
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (SQLException e)
|
catch (SQLException | IOException e)
|
||||||
{
|
{
|
||||||
Assert.fail(e.getMessage());
|
Assert.fail(e.getMessage());
|
||||||
}
|
}
|
||||||
@@ -200,7 +201,7 @@ public class DhRepoSqliteTest
|
|||||||
Assert.assertFalse("DTO exists failed", compoundKeyRepo.existsWithKey(insertDto.getKey()));
|
Assert.assertFalse("DTO exists failed", compoundKeyRepo.existsWithKey(insertDto.getKey()));
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (SQLException e)
|
catch (SQLException | IOException e)
|
||||||
{
|
{
|
||||||
Assert.fail(e.getMessage());
|
Assert.fail(e.getMessage());
|
||||||
}
|
}
|
||||||
@@ -330,7 +331,7 @@ public class DhRepoSqliteTest
|
|||||||
Assert.assertNotEquals(0, primaryKeyRepo.openClosables.size());
|
Assert.assertNotEquals(0, primaryKeyRepo.openClosables.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (SQLException e)
|
catch (SQLException | IOException e)
|
||||||
{
|
{
|
||||||
Assert.fail(e.getMessage());
|
Assert.fail(e.getMessage());
|
||||||
}
|
}
|
||||||
@@ -367,7 +368,7 @@ public class DhRepoSqliteTest
|
|||||||
long endMs = System.currentTimeMillis();
|
long endMs = System.currentTimeMillis();
|
||||||
System.out.println("Bulk update took ["+(endMs - startMs)+"] ms");
|
System.out.println("Bulk update took ["+(endMs - startMs)+"] ms");
|
||||||
}
|
}
|
||||||
catch (SQLException e)
|
catch (SQLException | IOException e)
|
||||||
{
|
{
|
||||||
Assert.fail(e.getMessage());
|
Assert.fail(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import com.seibel.distanthorizons.core.sql.dto.FullDataSourceV2DTO;
|
|||||||
import com.seibel.distanthorizons.core.sql.dto.util.VarintUtil;
|
import com.seibel.distanthorizons.core.sql.dto.util.VarintUtil;
|
||||||
import com.seibel.distanthorizons.core.util.objects.dataStreams.DhDataInputStream;
|
import com.seibel.distanthorizons.core.util.objects.dataStreams.DhDataInputStream;
|
||||||
import com.seibel.distanthorizons.core.util.objects.dataStreams.DhDataOutputStream;
|
import com.seibel.distanthorizons.core.util.objects.dataStreams.DhDataOutputStream;
|
||||||
|
import it.unimi.dsi.fastutil.bytes.ByteArrayList;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -43,12 +44,12 @@ public class VarintTest
|
|||||||
// zig zag encoding is needed for varint handling, so test it first
|
// zig zag encoding is needed for varint handling, so test it first
|
||||||
for (int i = -256; i < 256; i++)
|
for (int i = -256; i < 256; i++)
|
||||||
{
|
{
|
||||||
//testZigZagEncoding(i);
|
testZigZagEncoding(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = -256; i < 256; i++)
|
for (int i = -256; i < 256; i++)
|
||||||
{
|
{
|
||||||
//testSingleVarint(i);
|
testSingleVarint(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,8 +63,8 @@ public class VarintTest
|
|||||||
private static void testSingleVarint(int value)
|
private static void testSingleVarint(int value)
|
||||||
{
|
{
|
||||||
// write to stream
|
// write to stream
|
||||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
ByteArrayList byteArrayList = new ByteArrayList();
|
||||||
try (DhDataOutputStream outputStream = new DhDataOutputStream(byteArrayOutputStream, EDhApiDataCompressionMode.UNCOMPRESSED))
|
try (DhDataOutputStream outputStream = DhDataOutputStream.create(EDhApiDataCompressionMode.UNCOMPRESSED, byteArrayList))
|
||||||
{
|
{
|
||||||
int encodedValue = VarintUtil.zigzagEncode(value);
|
int encodedValue = VarintUtil.zigzagEncode(value);
|
||||||
VarintUtil.writeVarint(outputStream, encodedValue); // varint requires zig-zag encoding to function
|
VarintUtil.writeVarint(outputStream, encodedValue); // varint requires zig-zag encoding to function
|
||||||
@@ -76,9 +77,7 @@ public class VarintTest
|
|||||||
|
|
||||||
|
|
||||||
// read stream
|
// read stream
|
||||||
byte[] byteArray = byteArrayOutputStream.toByteArray();
|
try (DhDataInputStream inputStream = DhDataInputStream.create(byteArrayList, EDhApiDataCompressionMode.UNCOMPRESSED))
|
||||||
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArray);
|
|
||||||
try (DhDataInputStream inputStream = new DhDataInputStream(byteArrayInputStream, EDhApiDataCompressionMode.UNCOMPRESSED))
|
|
||||||
{
|
{
|
||||||
int encodedValue = VarintUtil.readVarint(inputStream);
|
int encodedValue = VarintUtil.readVarint(inputStream);
|
||||||
int decodedValue = VarintUtil.zigzagDecode(encodedValue);
|
int decodedValue = VarintUtil.zigzagDecode(encodedValue);
|
||||||
|
|||||||
Reference in New Issue
Block a user