Fix bunches of bugs. Quad tree ticks! Gen call is fired! Chunk gen works! Next to fix: File updates

This commit is contained in:
TomTheFurry
2022-07-26 17:06:50 +08:00
parent 50c5d044f1
commit a4546c63e3
13 changed files with 168 additions and 78 deletions
@@ -2,12 +2,15 @@ package com.seibel.lod.core.a7.datatype.transform;
import com.seibel.lod.core.a7.datatype.full.ChunkSizedData;
import com.seibel.lod.core.a7.datatype.full.FullFormat;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonInjector;
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
import it.unimi.dsi.fastutil.longs.LongArrayList;
public class LodDataBuilder {
private static final IBlockStateWrapper AIR = SingletonInjector.INSTANCE.get(IWrapperFactory.class).getAirBlockStateWrapper();
public static ChunkSizedData createChunkData(IChunkWrapper chunk) {
if (!canGenerateLodFromChunk(chunk)) return null;
@@ -18,7 +21,7 @@ public class LodDataBuilder {
LongArrayList longs = new LongArrayList(chunk.getHeight()/4);
int lastY = chunk.getMaxBuildHeight();
IBiomeWrapper biome = chunk.getBiome(x, lastY, z);
IBlockStateWrapper blockState = IBlockStateWrapper.AIR;
IBlockStateWrapper blockState = AIR;
int mappedId = chunkData.getMapping().setAndGetId(biome, blockState);
byte light = (byte) (chunk.getBlockLight(x,lastY,z) << 4 + chunk.getSkyLight(x,lastY,z));
int y=chunk.getMaxY(x, z);
@@ -42,7 +45,8 @@ public class LodDataBuilder {
}
}
longs.add(FullFormat.encode(mappedId, lastY-y+1, y+1, light));
chunkData.setSingleColumn(longs.toArray((long[]) null), x, z);
chunkData.setSingleColumn(longs.toArray(new long[0]), x, z);
}
}
@@ -16,6 +16,7 @@ import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.function.BiConsumer;
public class GenerationQueue implements PlaceHolderQueue {
@@ -29,7 +30,7 @@ public class GenerationQueue implements PlaceHolderQueue {
}
public void track(PlaceHolderRenderSource source) {
logger.info("Tracking source {} at {}", source, source.getSectionPos());
//logger.info("Tracking source {} at {}", source, source.getSectionPos());
trackers.put(source.getSectionPos(), new WeakReference<>(source));
}
@@ -108,25 +109,31 @@ public class GenerationQueue implements PlaceHolderQueue {
assert count > 0;
assert granularity >= 4; // Thanks compiler. Guess having a 'always true' warning means I did it right.
logger.info("Generating section {} of size {} with granularity {} at {}", pos, count, granularity, chunkPosMin);
//FIXME: Handle size != 1 case
CompletableFuture<ArrayGridList<ChunkSizedData>> dataFuture = generator.generate(chunkPosMin, granularity);
dataFuture.whenComplete((data, ex) -> {
if (ex != null) {
logger.error("Error generating data for section " + pos + ": " + ex);
if (ex instanceof CompletionException) {
ex = ex.getCause();
}
logger.error("Error generating data for section {}", pos, ex);
return;
}
assert data != null;
if (data.gridSize != count) {
logger.error("Generated data grid size (" + data.gridSize
+ ") does not match expected size (" + count + ") for section " + pos);
return;
}
if (data.gridSize < (1 << (granularity-4)))
throw new IllegalStateException("Generator returned chunks of size "
+ data.gridSize + " but requested granularity was " + granularity
+ " (equals to chunks of : " + (1 << (granularity-4)) + ") @ " + chunkPosMin);
final byte sectionDetail = (byte) (dataDetail + FullDataSource.SECTION_SIZE_OFFSET);
data.forEachPos((x,z) -> {
ChunkSizedData chunkData = data.get(x,z);
DhLodPos chunkDataPos = new DhLodPos((byte) (dataDetail + 4), x, z).convertUpwardsTo(sectionDetail);
DhSectionPos sectionPos = new DhSectionPos(chunkDataPos.detail, chunkDataPos.x, chunkDataPos.z);
logger.info("Writing chunk {} with data detail {} to section {}",
new DHChunkPos(x+chunkPosMin.x,z+chunkPosMin.z),
dataDetail, sectionPos);
write(sectionPos, chunkData);
});
});
@@ -16,7 +16,7 @@ public class DhLodPos {
}
public String toString() {
return "DhLodPos(" + detail + ", " + x + ", " + z + ")";
return "[" + detail + "*" + x + "," + z + "]";
}
public DhLodUnit getX() {
@@ -35,7 +35,7 @@ public class DhSectionPos {
return new DhLodUnit(sectionDetail, 1 << offset);
}
public DhLodPos getCenter() {
return getCenter((byte) (sectionDetail-1));
return getCenter((byte)0);
}
public DhLodPos getCorner() {
return getCorner((byte) (sectionDetail-1));
@@ -49,7 +49,7 @@ public class DhSectionPos {
if (sectionDetail <= 0) throw new IllegalStateException("section detail must be greater than 0");
return new DhSectionPos((byte) (sectionDetail - 1),
sectionX * 2 + (child0to3 & 1),
sectionZ * 2 + (child0to3 & 2) / 2);
sectionZ * 2 + ((child0to3 & 2) >> 1));
}
public void forEachChild(Consumer<DhSectionPos> callback){
@@ -59,7 +59,7 @@ public class DhSectionPos {
}
public DhSectionPos getParent(){
return new DhSectionPos((byte) (sectionDetail + 1), sectionX / 2, sectionZ / 2);
return new DhSectionPos((byte) (sectionDetail + 1), sectionX >> 1, sectionZ >> 1);
}
public DhSectionPos getAdjacent(ELodDirection dir) {
@@ -79,10 +79,9 @@ public class DhSectionPos {
@Override
public String toString() {
return "DhSectionPos{" +
"sectionDetail=" + sectionDetail +
", sectionX=" + sectionX +
", sectionZ=" + sectionZ +
return "{" + sectionDetail +
"*" + sectionX +
"," + sectionZ +
'}';
}
@@ -1,5 +1,6 @@
package com.seibel.lod.core.a7.render;
import com.seibel.lod.core.a7.datatype.LodRenderSource;
import com.seibel.lod.core.a7.datatype.column.ColumnRenderSource;
import com.seibel.lod.core.a7.level.IClientLevel;
import com.seibel.lod.core.a7.pos.DhBlockPos2D;
@@ -30,6 +31,7 @@ public class LodQuadTree {
* by implementing different abstract methods
*/
private static final byte LAYER_BEGINNING_OFFSET = ColumnRenderSource.SECTION_SIZE_OFFSET;
private static final boolean SUPER_VERBOSE_LOGGING = false;
public final byte getLayerDataDetailOffset(byte sectionDetail) {
return ColumnRenderSource.SECTION_SIZE_OFFSET;
}
@@ -59,6 +61,7 @@ public class LodQuadTree {
* @param initialPlayerZ player z coordinate
*/
public LodQuadTree(IClientLevel level, int viewDistance, int initialPlayerX, int initialPlayerZ, IRenderSourceProvider provider) {
DetailDistanceUtil.updateSettings(); //TODO: Move this to somewhere else
this.level = level;
renderSourceProvider = provider;
this.viewDistance = viewDistance;
@@ -71,13 +74,22 @@ public class LodQuadTree {
}
{ // Construct the ringLists
LOGGER.info("Creating ringLists with player center at {}", new Pos2D(initialPlayerX, initialPlayerZ));
for (byte i = LAYER_BEGINNING_OFFSET; i < numbersOfSectionLevels; i++) {
byte targetDataDetail = getLayerDataDetail(i);
int maxDist = getFurthestDistance(targetDataDetail);
int halfSize = LodUtil.ceilDiv(maxDist, (1 << i)) + 1;
LOGGER.info("Creating ringList {} with size {}", i, halfSize*2+1);
int halfSize = LodUtil.ceilDiv(maxDist, (1 << i)) + 2; // +2 to make sure the section is fully contained in the ringList
{
DhSectionPos checkerPos = new DhSectionPos(i, halfSize, halfSize);
byte checkedDetail = calculateExpectedDetailLevel(new DhBlockPos2D(initialPlayerX, initialPlayerZ),checkerPos);
LodUtil.assertTrue(checkedDetail > targetDataDetail,
"in {}, getFuthestDistance return {} which would be contained in range {}, but calculateExpectedDetailLevel at {} is {} <= {}",
i, maxDist, halfSize - 2, checkerPos, checkedDetail, targetDataDetail);
}
LOGGER.info("ringlist centered in {} with halfSize {} (maxDist {}, dataDetail {})", new Pos2D(initialPlayerX >> i, initialPlayerZ >> i), halfSize, maxDist, targetDataDetail);
ringLists[i - LAYER_BEGINNING_OFFSET] = new MovableGridRingList<>(halfSize,
initialPlayerX >> i, initialPlayerZ >> i);
LOGGER.info("Creating ringList {}: {}", i, ringLists[i - LAYER_BEGINNING_OFFSET].toString());
}
}
}
@@ -159,7 +171,8 @@ public class LodQuadTree {
* @return the furthest distance to the center, in blocks
*/
public int getFurthestDistance(byte detailLevel) {
return (int)Math.ceil(DetailDistanceUtil.getDrawDistanceFromDetail(detailLevel));
return (int)Math.ceil(DetailDistanceUtil.getDrawDistanceFromDetail(detailLevel + 1));
// +1 because that's the border to the next detail level, and we want to include up to it.
}
/**
@@ -181,7 +194,28 @@ public class LodQuadTree {
public LodRenderSection getChildSection(DhSectionPos pos, int child0to3) {
return getSection(pos.getChild(child0to3));
}
private LodRenderSection _set(MovableGridRingList<LodRenderSection> list, int x, int z, LodRenderSection t) {
LodUtil.assertTrue(t != null, "setting null at [{},{}] in {}", x, z, list.toString());
LodUtil.assertTrue(t.pos.sectionX == x && t.pos.sectionZ == z, "pos {} != [{},{}] in {}", t.pos, x, z, list.toString());
LodRenderSection s = list.setChained(x,z,t);
LodUtil.assertTrue(s != null, "returned null at [{},{}]: {}", x, z, list.toString());
LodUtil.assertTrue(s == t,"{} != {} in {}",s,t, list.toString());
return s;
}
private LodRenderSection _getNotNull(MovableGridRingList<LodRenderSection> list, int x, int z) {
LodUtil.assertTrue(list.inRange(x,z), "[{},{}] not in range of {}", x, z, list.toString());
LodRenderSection s = list.get(x,z);
LodUtil.assertTrue(s != null, "getting null at [{},{}] in {}", x, z, list.toString());
LodUtil.assertTrue(s.pos.sectionX == x && s.pos.sectionZ == z, "obj {} != [{},{}] in {}", s, x, z, list.toString());
return s;
}
private LodRenderSection _get(MovableGridRingList<LodRenderSection> list, int x, int z) {
LodRenderSection s = list.get(x,z);
LodUtil.assertTrue(s == null || (s.pos.sectionX == x && s.pos.sectionZ == z), "obj {} != [{},{}] in {}", s, x, z, list.toString());
return s;
}
/**
* This function update the quadTree based on the playerPos and the current game configs (static and global)
* @param playerPos the reference position for the player
@@ -207,7 +241,7 @@ public class LodQuadTree {
// - set childCount to 0
// If section != null && child != 0: //TODO: Should I move this createChild steps to Second tick pass?
// - // Section will be in the unloaded state.
// - create parent if it doesn't exist, with childCount = 1
// - create parent if not at final level and if it doesn't exist, with childCount = 1
// - for each child:
// - if null, create new with childCount = 0 (force load due to neighboring issues)
// - else if childCount == -1, set childCount = 0 (rescue it)
@@ -241,71 +275,77 @@ public class LodQuadTree {
ringList.forEachPosOrdered((section, pos) -> {
if (f_sectLevel == LAYER_BEGINNING_OFFSET && section != null) {
section.childCount = 0;
//LOGGER.info("sect {} in first layer with non-null. Reset childCount", section.pos);
}
if (section != null && section.childCount != 0) {
// Section will be in the unloaded state.
LodUtil.assertTrue(parentRingList != null);
LodRenderSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1);
if (parent == null) {
parent = parentRingList.setChained(pos.x >> 1, pos.y >> 1,
new LodRenderSection(section.pos.getParent()));
LodUtil.assertTrue(parent != null, "tried to set section at " + (pos.x >> 1) + "," + (pos.y >> 1) +", list is " + parentRingList);
parent.childCount++;
if (SUPER_VERBOSE_LOGGING) LOGGER.info("sect {} has child", section.pos);
if (parentRingList != null) {
LodRenderSection parent = _get(parentRingList, pos.x >> 1, pos.y >> 1);
if (parent == null) {
if (SUPER_VERBOSE_LOGGING) LOGGER.info("sect {} missing parent. Creating at {}", section.pos, section.pos.getParent());
parent = _set(parentRingList, pos.x >> 1, pos.y >> 1, new LodRenderSection(section.pos.getParent()));
parent.childCount++;
if (SUPER_VERBOSE_LOGGING) LOGGER.info("parent sect {} now has {} childs.", section.pos.getParent(), parent.childCount);
}
LodUtil.assertTrue(parent.childCount <= 4 && parent.childCount > 0);
}
LodUtil.assertTrue(parent.childCount <= 4 && parent.childCount > 0);
for (byte i = 0; i < 4; i++) {
DhSectionPos childPos = section.pos.getChild(i);
LodUtil.assertTrue(childRingList != null);
LodRenderSection child = childRingList.get(childPos.sectionX, childPos.sectionZ);
LodRenderSection child = _get(childRingList, childPos.sectionX, childPos.sectionZ);
if (child == null) {
child = childRingList.setChained(childPos.sectionX, childPos.sectionZ,
new LodRenderSection(childPos));
LodUtil.assertTrue(child != null, "tried to set section at " + childPos.sectionX + "," + childPos.sectionZ + ", list is " + childRingList);
if (SUPER_VERBOSE_LOGGING) LOGGER.info("sect {} missing child at {}. Creating.", section.pos, childPos);
child = _set(childRingList, childPos.sectionX, childPos.sectionZ, new LodRenderSection(childPos));
child.childCount = 0;
} else if (child.childCount == -1) {
if (SUPER_VERBOSE_LOGGING) LOGGER.info("sect {} rescued child at {}.", section.pos, childPos);
child.childCount = 0;
}
}
section.childCount = 4;
} else {
DhSectionPos sectPos = section != null ? section.pos : new DhSectionPos(f_sectLevel, pos.x, pos.y);
final DhSectionPos sectPos = section != null ? section.pos : new DhSectionPos(f_sectLevel, pos.x, pos.y);
LodUtil.assertTrue(sectPos.sectionDetail == f_sectLevel
&& sectPos.sectionX == pos.x && sectPos.sectionZ == pos.y,
"sectPos: " + sectPos + ", pos: " + pos + ", sectLevel: " + f_sectLevel);
"sectPos {} != {} @ {}", sectPos, pos, f_sectLevel);
byte targetLevel = calculateExpectedDetailLevel(playerPos, sectPos);
if (SUPER_VERBOSE_LOGGING) LOGGER.info("0 child sect {}(null?{}) - target:{}/{} (parent:{})", sectPos, section == null,
targetLevel, getLayerDataDetail(f_sectLevel),
f_sectLevel == numbersOfSectionLevels-1 ? "N/A" : getLayerDataDetail((byte) (f_sectLevel+1)));
if (f_sectLevel == numbersOfSectionLevels -1) {
// Section is in the top level.
if (targetLevel > getLayerDataDetail(f_sectLevel) && section != null) {
if (SUPER_VERBOSE_LOGGING) LOGGER.info("sect {} in top & target>current. Mark as free.", sectPos);
section.childCount = -1;
}
if (targetLevel <= getLayerDataDetail(f_sectLevel) && section == null) {
section = ringList.setChained(pos.x, pos.y,
new LodRenderSection(sectPos));
LodUtil.assertTrue(section != null, "tried to set section at " + pos.x + "," + pos.y +", list is " + ringList);
if (SUPER_VERBOSE_LOGGING) LOGGER.info("null sect {} in top & target<=current. Creating.", sectPos);
section = _set(ringList, pos.x, pos.y, new LodRenderSection(sectPos));
}
} else {
// Section is not the top level. So we also need to consider the parent.
if (targetLevel >= getLayerDataDetail((byte) (f_sectLevel+1)) && section != null) {
if (SUPER_VERBOSE_LOGGING) LOGGER.info("sect {} target>=nextLevel. Mark as free.", sectPos);
LodUtil.assertTrue(parentRingList != null);
LodRenderSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1);
LodUtil.assertTrue(parent != null, "fail to get parent setion at " + (pos.x >> 1) + "," + (pos.y >> 1) +", list is " + parentRingList);
LodRenderSection parent = _getNotNull(parentRingList, pos.x >> 1, pos.y >> 1);
LodUtil.assertTrue(parent.childCount <= 4 && parent.childCount > 0);
parent.childCount--;
if (SUPER_VERBOSE_LOGGING) LOGGER.info("parent sect {} now has {} child.", sectPos, parent.childCount);
section.childCount = -1;
}
if (targetLevel < getLayerDataDetail((byte) (f_sectLevel+1)) && section == null) {
section = ringList.setChained(pos.x, pos.y,
new LodRenderSection(sectPos));
LodUtil.assertTrue(section != null, "tried to set section at " + pos.x + "," + pos.y +", list is " + ringList);
if (SUPER_VERBOSE_LOGGING) LOGGER.info("null sect {} target<nextLevel. Creating.", sectPos);
section = _set(ringList, pos.x, pos.y, new LodRenderSection(sectPos));
LodUtil.assertTrue(parentRingList != null);
LodRenderSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1);
LodRenderSection parent = _get(parentRingList, pos.x >> 1, pos.y >> 1);
if (parent == null) {
parent = parentRingList.setChained(pos.x >> 1, pos.y >> 1,
new LodRenderSection(sectPos.getParent()));
LodUtil.assertTrue(parent != null, "tried to set section at " + (pos.x >> 1) + "," + (pos.y >> 1) +", list is " + parentRingList);
if (SUPER_VERBOSE_LOGGING) LOGGER.info("sect {} missing parent. Creating at {}", sectPos, sectPos.getParent());
parent = _set(parentRingList, pos.x >> 1, pos.y >> 1, new LodRenderSection(sectPos.getParent()));
}
parent.childCount++;
if (SUPER_VERBOSE_LOGGING) LOGGER.info("parent sect {} now has {} childs.", sectPos.getParent(), parent.childCount);
}
}
}
@@ -362,21 +402,6 @@ public class LodQuadTree {
section.childCount = 4;
}
// Assertion steps
LodUtil.assertTrue(section.childCount == 4 || section.childCount == 0 || section.childCount == -1);
if (section.childCount == 4) LodUtil.assertTrue(
getChildSection(section.pos, 0) != null &&
getChildSection(section.pos, 1) != null &&
getChildSection(section.pos, 2) != null &&
getChildSection(section.pos, 3) != null);
if (section.childCount == 0) LodUtil.assertTrue(
getChildSection(section.pos, 0) == null &&
getChildSection(section.pos, 1) == null &&
getChildSection(section.pos, 2) == null &&
getChildSection(section.pos, 3) == null);
if (section.childCount == -1) LodUtil.assertTrue(
getParentSection(section.pos).childCount == 0);
// Call load on new sections, and tick on existing ones, and dispose old sections
if (section.childCount == -1) {
ringList.set(pos.x, pos.y, null);
@@ -387,10 +412,26 @@ public class LodQuadTree {
} else if (section.isOutdated()) {
section.reload(renderSourceProvider);
}
if (section.childCount == 4) section.enableRender(level, this);
if (section.childCount == 0) section.disableRender();
if (section.childCount == 4) section.disableRender();
if (section.childCount == 0) section.enableRender(level, this);
section.tick(this);
}
// Assertion steps
LodUtil.assertTrue(section.childCount == 4 || section.childCount == 0 || section.childCount == -1);
if (section.pos.sectionDetail == LAYER_BEGINNING_OFFSET) LodUtil.assertTrue(section.childCount == 0);
if (section.childCount == 4) LodUtil.assertTrue(
getChildSection(section.pos, 0) != null &&
getChildSection(section.pos, 1) != null &&
getChildSection(section.pos, 2) != null &&
getChildSection(section.pos, 3) != null);
if (section.childCount == 0 && section.pos.sectionDetail > LAYER_BEGINNING_OFFSET) LodUtil.assertTrue(
getChildSection(section.pos, 0) == null &&
getChildSection(section.pos, 1) == null &&
getChildSection(section.pos, 2) == null &&
getChildSection(section.pos, 3) == null);
if (section.childCount == -1 && section.pos.sectionDetail < numbersOfSectionLevels-1) LodUtil.assertTrue(
getParentSection(section.pos).childCount == 0);
});
}
}
@@ -81,6 +81,11 @@ public class LodRenderSection {
return lodRenderSource != null;
}
//FIXME: Used by RenderBufferHandler
public int FIXME_BYPASS_DONT_USE_getChildCount() {
return childCount;
}
public boolean isLoading() {
return loadFuture != null;
}
@@ -17,7 +17,7 @@ public class RenderBufferHandler {
class RenderBufferNode implements AutoCloseable {
public final DhSectionPos pos;
public volatile RenderBufferNode[] children = null;
public AtomicReference<RenderBuffer> renderBufferSlot = null;
public final AtomicReference<RenderBuffer> renderBufferSlot = new AtomicReference<>();
public RenderBufferNode(DhSectionPos pos) {
this.pos = pos;
@@ -63,7 +63,8 @@ public class RenderBufferHandler {
// Update children's render buffer state
// TODO: Improve this! (Checking section.isLoaded() as if its not loaded, it can only be because
// it has children. (But this logic is... really hard to read!)
boolean shouldHaveChildren = !section.isLoaded();
// FIXME: Above comment is COMPLETELY WRONG! I am an idiot!
boolean shouldHaveChildren = section.FIXME_BYPASS_DONT_USE_getChildCount() > 0;
if (shouldHaveChildren) {
if (children == null) {
RenderBufferNode[] childs = new RenderBufferNode[4];
@@ -37,11 +37,13 @@ public class RenderMetaFile extends MetaFile {
// Not sure if it will cause issues or not.
public void updateChunkIfNeeded(ChunkSizedData chunkData) {
CompletableFuture<LodRenderSource> source = _readCached(data.get());
if (source == null) return;
if (source.isDone()) source.join().update(chunkData);
}
public CompletableFuture<Void> flushAndSave(ExecutorService renderCacheThread) {
CompletableFuture<LodRenderSource> source = _readCached(data.get());
if (source == null) return CompletableFuture.completedFuture(null);
return source.thenAccept((a)->{});
//TODO: Should we save the data or let user re-calculate it on new load?
}
@@ -1,16 +1,20 @@
package com.seibel.lod.core.util;
import com.seibel.lod.core.ModInfo;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import org.apache.logging.log4j.Logger;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ExecutorService;
public class EventLoop { //FIXME This should have close. We are leaking stuff.
private final boolean PAUSE_ON_ERROR = ModInfo.IS_DEV_BUILD;
private final Logger logger = DhLoggerBuilder.getLogger();
private final ExecutorService executorService;
private final Runnable runnable;
private CompletableFuture<Void> future;
private boolean isRunning = true;
public EventLoop(ExecutorService executorService, Runnable runnable) {
this.executorService = executorService;
this.runnable = runnable;
@@ -19,11 +23,15 @@ public class EventLoop { //FIXME This should have close. We are leaking stuff.
if (future != null && future.isDone()) {
try {
future.join();
} catch (CompletionException ce) {
logger.error("Uncaught exception in event loop", ce.getCause());
if (PAUSE_ON_ERROR) isRunning = false;
} catch (Exception e) {
logger.error("Uncaught exception in event loop", e);
logger.error("Exception in event loop", e);
if (PAUSE_ON_ERROR) isRunning = false;
} finally {future = null;}
}
if (future == null) {
if (future == null && isRunning) {
future = CompletableFuture.runAsync(runnable, executorService);
}
}
@@ -28,6 +28,7 @@ import com.seibel.lod.core.config.Config;
import com.seibel.lod.core.enums.config.EServerFolderNameMode;
import com.seibel.lod.core.enums.config.EVanillaOverdraw;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonInjector;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.objects.DHChunkPos;
import com.seibel.lod.core.objects.ParsedIp;
import com.seibel.lod.core.objects.Pos2D;
@@ -39,6 +40,9 @@ import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IDimensionTypeWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.Message;
/**
* This class holds methods and constants that may be used in multiple places.
@@ -50,6 +54,7 @@ public class LodUtil
{
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
/**
* Vanilla render distances less than or equal to this will not allow partial
@@ -419,7 +424,20 @@ public class LodUtil
public static void checkInterruptsUnchecked() {
if (Thread.interrupted()) throw new RuntimeException(new InterruptedException());
}
/**
* Format a given string with params using log4j's MessageFormat
*
* @apiNote <b>This 'format' SHOULD ONLY be used for logging and debugging purposes!
* Do not use it for deserialization or naming of objects.</b>
* @param str The string to format
* @param param The parameters to use in the string
* @return A message object. Call .toString() to get the string.
* @author leetom
*/
public static String formatLog(String str, Object... param) {
return LOGGER.getMessageFactory().newMessage(str, param).getFormattedMessage();
}
/**
* Returns a shortened version of the given string that is no longer than maxLength. <br>
@@ -441,14 +459,20 @@ public class LodUtil
if (!condition) throw new RuntimeException("Assertion failed");
}
public static void assertTrue(boolean condition, String message) {
if (!condition) throw new RuntimeException("Assertion failed: " + message);
if (!condition) throw new RuntimeException("Assertion failed:\n " + message);
}
public static void assertNotReach(String message) {
throw new RuntimeException("Assert Not Reach failed: " + message);
public static void assertTrue(boolean condition, String message, Object... args) {
if (!condition) throw new RuntimeException("Assertion failed:\n " + formatLog(message, args));
}
public static void assertNotReach() {
throw new RuntimeException("Assert Not Reach failed");
}
public static void assertNotReach(String message) {
throw new RuntimeException("Assert Not Reach failed:\n " + message);
}
public static void assertNotReach(String message, Object... args) {
throw new RuntimeException("Assert Not Reach failed:\n " + formatLog(message, args));
}
public static ExecutorService makeSingleThreadPool(String name, int relativePriority) {
return Executors.newSingleThreadExecutor(new LodThreadFactory(name, Thread.NORM_PRIORITY+relativePriority));
}
@@ -33,7 +33,7 @@ import java.util.function.Consumer;
public class MovableGridRingList<T> extends ArrayList<T> implements List<T> {
private AtomicReference<Pos2D> pos = new AtomicReference<Pos2D>();
private final AtomicReference<Pos2D> pos = new AtomicReference<>();
private final int halfSize;
private final int size;
@@ -329,7 +329,7 @@ public class MovableGridRingList<T> extends ArrayList<T> implements List<T> {
@Override
public String toString() {
Pos2D p = pos.get();
return "MovabeGridRingList[" + p.x+halfSize + "," + p.y+halfSize + "] " + size + "*" + size + "[" + size() + "]";
return "MovabeGridRingList[" + (p.x+halfSize) + "," + (p.y+halfSize) + "] " + size + "*" + size + "[" + size() + "]";
}
public String toDetailString() {
@@ -36,4 +36,5 @@ public interface IWrapperFactory extends IBindable
AbstractBatchGenerationEnvionmentWrapper createBatchGenerator(ILevel targetLevel);
IBiomeWrapper deserializeBiomeWrapper(String str);
IBlockStateWrapper deserializeBlockStateWrapper(String str);
IBlockStateWrapper getAirBlockStateWrapper();
}
@@ -1,7 +1,5 @@
package com.seibel.lod.core.wrapperInterfaces.block;
public interface IBlockStateWrapper {
IBlockStateWrapper AIR = null;
String serialize();
}