From 55cb4595bdadcf425b79510fcd35989aaa5e3ee3 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Tue, 2 Jul 2024 07:50:21 -0500 Subject: [PATCH] Fix beacons un-loading incorrectly in some situations Specifically neighboring chunks updating and in some cases flying away too fast --- .../core/api/internal/SharedApi.java | 4 +- .../core/level/AbstractDhLevel.java | 108 +++++++++++++++++- .../distanthorizons/core/level/IDhLevel.java | 5 +- .../distanthorizons/core/pos/DhChunkPos.java | 26 +++++ .../core/render/LodQuadTree.java | 6 + .../core/render/LodRenderSection.java | 10 ++ .../core/sql/repo/BeaconBeamRepo.java | 2 +- .../chunk/IChunkWrapper.java | 6 +- 8 files changed, 152 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java index 6b1ccc4d3..192e60d5e 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java @@ -26,10 +26,8 @@ import com.seibel.distanthorizons.core.generation.DhLightingEngine; import com.seibel.distanthorizons.core.level.IDhLevel; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.f3.F3Screen; -import com.seibel.distanthorizons.core.pos.DhBlockPos; import com.seibel.distanthorizons.core.pos.DhBlockPos2D; import com.seibel.distanthorizons.core.pos.DhChunkPos; -import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.render.renderer.DebugRenderer; import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO; import com.seibel.distanthorizons.core.util.TimerUtil; @@ -350,7 +348,7 @@ public class SharedApi // get this chunk's active beacons List beaconBeamList = chunkWrapper.getAllActiveBeacons(); - dhLevel.ensureBeaconBeamsAtPos(DhSectionPos.encode(chunkWrapper.getChunkPos()), beaconBeamList); + dhLevel.setBeaconBeamsForChunk(chunkWrapper.getChunkPos(), beaconBeamList); dhLevel.updateChunkAsync(chunkWrapper); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/AbstractDhLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/AbstractDhLevel.java index d6badae9b..be6bbe0a8 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/AbstractDhLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/AbstractDhLevel.java @@ -48,6 +48,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; public abstract class AbstractDhLevel implements IDhLevel { @@ -199,11 +200,13 @@ public abstract class AbstractDhLevel implements IDhLevel } - HashMap beamRenderGroupByPos = new HashMap<>(); + HashMap beamRenderGroupByBlockPos = new HashMap<>(); + HashMap beamRefCountByPos = new HashMap<>(); @Override - public void ensureBeaconBeamsAtPos(long pos, List newBeamList) + public void setBeaconBeamsForChunk(DhChunkPos chunkPos, List newBeamList) { + long pos = DhSectionPos.encode(chunkPos); if (this.beaconBeamRepo != null) { HashSet allPosSet = new HashSet<>(); @@ -231,6 +234,12 @@ public abstract class AbstractDhLevel implements IDhLevel for (DhBlockPos beaconPos : allPosSet) { + if (!chunkPos.contains(beaconPos)) + { + // don't update beacons outside the updated chunk + continue; + } + BeaconBeamDTO existingBeam = existingBeamByPos.get(beaconPos); BeaconBeamDTO newBeam = newBeamByPos.get(beaconPos); @@ -245,19 +254,31 @@ public abstract class AbstractDhLevel implements IDhLevel IDhApiRenderableBoxGroup beaconBox = GenericObjectRenderer.INSTANCE.createForSingleBox(new DhApiRenderableBox( new DhApiVec3f(newBeam.pos.x, newBeam.pos.y+1, newBeam.pos.z), - new DhApiVec3f(newBeam.pos.x+1, 2_000, newBeam.pos.z+1), + new DhApiVec3f(newBeam.pos.x+1, 6_000, newBeam.pos.z+1), newBeam.color )); beaconBox.setBlockLight(LodUtil.MAX_MC_LIGHT); beaconBox.setSkyLight(LodUtil.MAX_MC_LIGHT); - this.beamRenderGroupByPos.put(newBeam.pos, beaconBox); + + this.beamRenderGroupByBlockPos.put(newBeam.pos, beaconBox); + this.beamRefCountByPos.compute(newBeam.pos, (beamPos, refCount) -> + { + if (refCount == null) + { + refCount = new AtomicInteger(0); + } + refCount.getAndIncrement(); + return refCount; + }); + GenericObjectRenderer.INSTANCE.add(beaconBox); } else if (existingBeam != null && newBeam == null) { // beam no longer exists at position, remove - this.beaconBeamRepo.deleteWithKey(beaconPos); - IDhApiRenderableBoxGroup beaconBox = this.beamRenderGroupByPos.remove(existingBeam.pos); + this.beaconBeamRepo.deleteWithKey(beaconPos); // TODO broken when updating adjacent chunks + this.beamRefCountByPos.remove(existingBeam.pos); + IDhApiRenderableBoxGroup beaconBox = this.beamRenderGroupByBlockPos.remove(existingBeam.pos); if (beaconBox != null) { GenericObjectRenderer.INSTANCE.remove(beaconBox.getId()); @@ -269,6 +290,81 @@ public abstract class AbstractDhLevel implements IDhLevel } } + @Override + public void loadBeaconBeamsInPos(long pos) + { + if (this.beaconBeamRepo != null) + { + // get beams in pos + List existingBeamList = this.beaconBeamRepo.getAllBeamsForSectionPos(pos); + for (int i = 0; i < existingBeamList.size(); i++) + { + BeaconBeamDTO beam = existingBeamList.get(i); + + IDhApiRenderableBoxGroup beaconBox = GenericObjectRenderer.INSTANCE.createForSingleBox(new DhApiRenderableBox( + new DhApiVec3f(beam.pos.x, beam.pos.y+1, beam.pos.z), + new DhApiVec3f(beam.pos.x+1, 6_000, beam.pos.z+1), + beam.color + )); + beaconBox.setBlockLight(LodUtil.MAX_MC_LIGHT); + beaconBox.setSkyLight(LodUtil.MAX_MC_LIGHT); + + this.beamRefCountByPos.compute(beam.pos, (beamPos, refCount) -> + { + if (refCount == null) + { + refCount = new AtomicInteger(0); + } + + if (refCount.getAndIncrement() == 0) + { + this.beamRenderGroupByBlockPos.put(beam.pos, beaconBox); + GenericObjectRenderer.INSTANCE.add(beaconBox); + } + + return refCount; + }); + } + } + } + + @Override + public void unloadBeaconBeamsInPos(long pos) + { + if (this.beaconBeamRepo != null) + { + // get beams in pos + List existingBeamList = this.beaconBeamRepo.getAllBeamsForSectionPos(pos); + for (int i = 0; i < existingBeamList.size(); i++) + { + BeaconBeamDTO beam = existingBeamList.get(i); + + // beam no longer exists at position, remove + this.beamRefCountByPos.compute(beam.pos, (beamPos, refCount) -> + { + if (refCount == null) + { + return null; + } + + if (refCount.decrementAndGet() == 0) + { + IDhApiRenderableBoxGroup beaconBox = this.beamRenderGroupByBlockPos.remove(beam.pos); + if (beaconBox != null) + { + GenericObjectRenderer.INSTANCE.remove(beaconBox.getId()); + } + return null; + } + else + { + return refCount; + } + }); + } + } + } + //================// diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/IDhLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/IDhLevel.java index 5a52cd29a..accaaa11c 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/IDhLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/IDhLevel.java @@ -22,7 +22,6 @@ package com.seibel.distanthorizons.core.level; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2; import com.seibel.distanthorizons.core.file.fullDatafile.FullDataSourceProviderV2; import com.seibel.distanthorizons.core.file.structure.AbstractSaveStructure; -import com.seibel.distanthorizons.core.pos.DhBlockPos; import com.seibel.distanthorizons.core.pos.DhChunkPos; import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; @@ -46,8 +45,10 @@ public interface IDhLevel extends AutoCloseable void setChunkHash(DhChunkPos pos, int chunkHash); void updateChunkAsync(IChunkWrapper chunk); + void loadBeaconBeamsInPos(long pos); List getAllBeamsForSectionPos(long pos); - void ensureBeaconBeamsAtPos(long pos, List beamList); + void setBeaconBeamsForChunk(DhChunkPos chunkPos, List beamList); + void unloadBeaconBeamsInPos(long pos); FullDataSourceProviderV2 getFullDataProvider(); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhChunkPos.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhChunkPos.java index e9cd29ba0..1bfd83218 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhChunkPos.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhChunkPos.java @@ -19,6 +19,8 @@ package com.seibel.distanthorizons.core.pos; +import com.seibel.distanthorizons.core.util.LodUtil; + public class DhChunkPos { public final int x; // Low 32 bits @@ -29,6 +31,10 @@ public class DhChunkPos + //==============// + // constructors // + //==============// + public DhChunkPos(int x, int z) { this.x = x; @@ -51,6 +57,10 @@ public class DhChunkPos + //=========// + // methods // + //=========// + public DhBlockPos center() { return new DhBlockPos(8 + this.x << 4, 0, 8 + this.z << 4); } public DhBlockPos corner() { return new DhBlockPos(this.x << 4, 0, this.z << 4); } @@ -64,8 +74,24 @@ public class DhChunkPos public DhBlockPos2D getMinBlockPos() { return new DhBlockPos2D(this.x << 4, this.z << 4); } + public boolean contains(DhBlockPos pos) + { + int minBlockX = this.getMinBlockX(); + int minBlockZ = this.getMinBlockZ(); + int maxBlockX = minBlockX + LodUtil.CHUNK_WIDTH; + int maxBlockZ = minBlockZ + LodUtil.CHUNK_WIDTH; + + return minBlockX <= pos.x && pos.x <= maxBlockX + && minBlockZ <= pos.z && pos.z <= maxBlockZ; + } + public long getLong() { return toLong(this.x, this.z); } + + //================// + // base overrides // + //================// + @Override public boolean equals(Object obj) { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java b/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java index 49c349a42..ffadc3c9d 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java @@ -31,6 +31,7 @@ import com.seibel.distanthorizons.core.pos.DhBlockPos2D; import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.render.renderer.DebugRenderer; import com.seibel.distanthorizons.core.render.renderer.IDebugRenderable; +import com.seibel.distanthorizons.core.sql.repo.BeaconBeamRepo; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.ThreadUtil; import com.seibel.distanthorizons.core.util.objects.quadTree.QuadNode; @@ -329,6 +330,10 @@ public class LodQuadTree extends QuadTree implements IDebugRen } // all child positions are loaded, disable this section and enable its children. + if (renderSection.renderingEnabled) + { + this.level.unloadBeaconBeamsInPos(renderSection.pos); + } renderSection.renderingEnabled = false; // walk back down the tree and enable the child sections //TODO there are probably more efficient ways of doing this, but this will work for now @@ -383,6 +388,7 @@ public class LodQuadTree extends QuadTree implements IDebugRen if (!renderSection.renderingEnabled) { renderSection.renderingEnabled = true; + this.level.loadBeaconBeamsInPos(renderSection.pos); // delete/disable children, all of them will be a lower detail level than requested quadNode.deleteAllChildren((childRenderSection) -> diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java b/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java index fbfd9a2ed..372e64f7c 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java @@ -19,6 +19,9 @@ package com.seibel.distanthorizons.core.render; +import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup; +import com.seibel.distanthorizons.api.objects.math.DhApiVec3f; +import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2; import com.seibel.distanthorizons.core.dataObjects.render.ColumnRenderSource; @@ -28,11 +31,16 @@ import com.seibel.distanthorizons.core.enums.EDhDirection; import com.seibel.distanthorizons.core.file.fullDatafile.FullDataSourceProviderV2; import com.seibel.distanthorizons.core.level.IDhClientLevel; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.pos.DhBlockPos; import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.render.glObject.GLProxy; +import com.seibel.distanthorizons.core.render.renderer.GenericObjectRenderer; import com.seibel.distanthorizons.core.render.renderer.IDebugRenderable; import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.ColumnRenderBuffer; import com.seibel.distanthorizons.core.render.renderer.DebugRenderer; +import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO; +import com.seibel.distanthorizons.core.sql.repo.BeaconBeamRepo; +import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil; import it.unimi.dsi.fastutil.longs.LongArrayList; import org.apache.logging.log4j.Logger; @@ -41,6 +49,7 @@ import org.jetbrains.annotations.Nullable; import javax.annotation.WillNotClose; import java.awt.*; import java.util.*; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ThreadPoolExecutor; @@ -416,6 +425,7 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable } + this.level.unloadBeaconBeamsInPos(this.pos); if (this.renderBuffer != null) { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/sql/repo/BeaconBeamRepo.java b/core/src/main/java/com/seibel/distanthorizons/core/sql/repo/BeaconBeamRepo.java index 6433ff3e9..5882c3729 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/sql/repo/BeaconBeamRepo.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/sql/repo/BeaconBeamRepo.java @@ -121,7 +121,7 @@ public class BeaconBeamRepo extends AbstractDhRepo "UPDATE "+this.getTableName()+" \n" + "SET \n" + " ColorR = ?, ColorG = ?, ColorB = ?, \n" + - " ,LastModifiedUnixDateTime = ? \n" + + " LastModifiedUnixDateTime = ? \n" + "WHERE BlockPosX = ? AND BlockPosY = ? AND BlockPosZ = ?"; PreparedStatement statement = this.createPreparedStatement(sql); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/chunk/IChunkWrapper.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/chunk/IChunkWrapper.java index 52e12c9e8..09d8538ba 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/chunk/IChunkWrapper.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/chunk/IChunkWrapper.java @@ -254,11 +254,11 @@ public interface IChunkWrapper extends IBindable ArrayList blockPosList = this.getBlockLightPosList(); for (int i = 0; i < blockPosList.size(); i++) { - DhBlockPos pos = blockPosList.get(i).convertToChunkRelativePos(); - IBlockStateWrapper block = this.getBlockState(pos); + DhBlockPos pos = blockPosList.get(i); + IBlockStateWrapper block = this.getBlockState(pos.convertToChunkRelativePos()); if (block.getSerialString().toLowerCase().contains("minecraft:beacon")) { - BeaconBeamDTO beam = new BeaconBeamDTO(pos, Color.WHITE); // TODO + BeaconBeamDTO beam = new BeaconBeamDTO(blockPosList.get(i), Color.WHITE); beaconPosList.add(beam); } }