diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/beacon/BeaconBeamDataHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/beacon/BeaconBeamDataHandler.java deleted file mode 100644 index 52e86fc83..000000000 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/beacon/BeaconBeamDataHandler.java +++ /dev/null @@ -1,177 +0,0 @@ -package com.seibel.distanthorizons.core.file.beacon; - -import com.seibel.distanthorizons.core.pos.DhChunkPos; -import com.seibel.distanthorizons.core.pos.DhSectionPos; -import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos; -import com.seibel.distanthorizons.core.render.renderer.generic.BeaconRenderHandler; -import com.seibel.distanthorizons.core.render.renderer.generic.GenericObjectRenderer; -import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO; -import com.seibel.distanthorizons.core.sql.repo.BeaconBeamRepo; -import com.seibel.distanthorizons.core.util.KeyedLockContainer; -import com.seibel.distanthorizons.core.util.LodUtil; -import org.jetbrains.annotations.NotNull; - -import javax.annotation.Nullable; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.concurrent.locks.ReentrantLock; - -public class BeaconBeamDataHandler -{ - private final BeaconBeamRepo beaconBeamRepo; - - @Nullable - private BeaconRenderHandler beaconRenderHandler; - - private final KeyedLockContainer updateLockContainer = new KeyedLockContainer<>(); - - - - //=============// - // constructor // - //=============// - - public BeaconBeamDataHandler(@NotNull BeaconBeamRepo beaconBeamRepo, @Nullable GenericObjectRenderer renderer) - { - this.beaconBeamRepo = beaconBeamRepo; - - if (renderer != null) - { - this.beaconRenderHandler = new BeaconRenderHandler(renderer); - } - } - - - - //==========// - // updating // - //==========// - - public void setBeaconBeamsForChunk(DhChunkPos chunkPos, List activeBeamList) - { - long sectionPos = DhSectionPos.encode(LodUtil.CHUNK_DETAIL_LEVEL, chunkPos.getX(), chunkPos.getZ()); - this.setBeaconBeamsForPos(sectionPos, activeBeamList); - } - - public void setBeaconBeamsForPos(long sectionPos, List activeBeamList) - { - // locked to prevent two threads from updating the same section at the same time - ReentrantLock lock = this.updateLockContainer.getLockForPos(sectionPos); - try - { - lock.lock(); - - HashSet allPosSet = new HashSet<>(); - - // sort new beams - HashMap activeBeamByPos = new HashMap<>(activeBeamList.size()); - for (BeaconBeamDTO beam : activeBeamList) - { - activeBeamByPos.put(beam.blockPos, beam); - allPosSet.add(beam.blockPos); - } - - // get existing beams - List existingBeamList = this.beaconBeamRepo.getAllBeamsForPos(sectionPos); - HashMap existingBeamByPos = new HashMap<>(existingBeamList.size()); - for (BeaconBeamDTO beam : existingBeamList) - { - existingBeamByPos.put(beam.blockPos, beam); - allPosSet.add(beam.blockPos); - } - - - - for (DhBlockPos beaconPos : allPosSet) - { - if (!DhSectionPos.contains(sectionPos, beaconPos)) - { - // don't update beacons outside the updated chunk - continue; - } - - BeaconBeamDTO existingBeam = existingBeamByPos.get(beaconPos); - BeaconBeamDTO activeBeam = activeBeamByPos.get(beaconPos); - - - if (activeBeam != null) - { - if (existingBeam == null) - { - // new beam found, add to DB - this.beaconBeamRepo.save(activeBeam); - if (this.beaconRenderHandler != null) - { - this.beaconRenderHandler.startRenderingBeacon(activeBeam); - } - } - else - { - // beam still exists in chunk - if (!existingBeam.color.equals(activeBeam.color)) - { - // beam colors were changed - this.beaconBeamRepo.save(activeBeam); - if (this.beaconRenderHandler != null) - { - this.beaconRenderHandler.updateBeaconColor(activeBeam); - } - } - } - } - else if (existingBeam != null) - { - // beam no longer exists at position, remove from DB - this.beaconBeamRepo.deleteWithKey(beaconPos); - if (this.beaconRenderHandler != null) - { - this.beaconRenderHandler.stopRenderingBeaconAtPos(beaconPos); - } - } - - } - } - finally - { - lock.unlock(); - } - } - - - - //===================// - // loading/unloading // - //===================// - - public void loadBeaconBeamsInPos(long pos) - { - if (this.beaconRenderHandler == null) - { - return; - } - - // get all beams in pos - List existingBeamList = this.beaconBeamRepo.getAllBeamsForPos(pos); - for (BeaconBeamDTO newBeam : existingBeamList) - { - this.beaconRenderHandler.startRenderingBeacon(newBeam); - } - } - - public void unloadBeaconBeamsInPos(long pos) - { - if (this.beaconRenderHandler == null) - { - return; - } - - // get all beams in pos - List existingBeamList = this.beaconBeamRepo.getAllBeamsForPos(pos); - for (BeaconBeamDTO beam : existingBeamList) - { - this.beaconRenderHandler.stopRenderingBeaconAtPos(beam.blockPos); - } - } - -} 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 430ad2c91..647c20bde 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 @@ -21,12 +21,12 @@ package com.seibel.distanthorizons.core.level; import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiChunkModifiedEvent; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2; -import com.seibel.distanthorizons.core.file.beacon.BeaconBeamDataHandler; import com.seibel.distanthorizons.core.file.fullDatafile.DelayedFullDataSourceSaveCache; import com.seibel.distanthorizons.core.generation.DhLightingEngine; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.DhChunkPos; import com.seibel.distanthorizons.core.pos.DhSectionPos; +import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos; import com.seibel.distanthorizons.core.render.renderer.generic.CloudRenderHandler; import com.seibel.distanthorizons.core.render.renderer.generic.GenericObjectRenderer; import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO; @@ -34,6 +34,7 @@ import com.seibel.distanthorizons.core.sql.dto.ChunkHashDTO; import com.seibel.distanthorizons.core.sql.repo.AbstractDhRepo; import com.seibel.distanthorizons.core.sql.repo.BeaconBeamRepo; import com.seibel.distanthorizons.core.sql.repo.ChunkHashRepo; +import com.seibel.distanthorizons.core.util.KeyedLockContainer; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; @@ -43,10 +44,12 @@ import org.jetbrains.annotations.Nullable; import java.io.File; import java.sql.SQLException; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; public abstract class AbstractDhLevel implements IDhLevel { @@ -59,6 +62,8 @@ public abstract class AbstractDhLevel implements IDhLevel @Nullable public BeaconBeamRepo beaconBeamRepo; + protected final KeyedLockContainer beaconUpdateLockContainer = new KeyedLockContainer<>(); + protected final DelayedFullDataSourceSaveCache delayedFullDataSourceSaveCache = new DelayedFullDataSourceSaveCache(this::onDataSourceSaveAsync, 3_000); /** contains the {@link DhChunkPos} for each {@link DhSectionPos} that are queued to save */ protected final ConcurrentHashMap> updatedChunkPosSetBySectionPos = new ConcurrentHashMap<>(); @@ -67,7 +72,6 @@ public abstract class AbstractDhLevel implements IDhLevel /** Will be null if clouds shouldn't be rendered for this level. */ @Nullable protected CloudRenderHandler cloudRenderHandler; - protected BeaconBeamDataHandler beaconBeamDataHandler; @@ -126,13 +130,6 @@ public abstract class AbstractDhLevel implements IDhLevel } } } - - - // shouldn't happen, but just in case - if (this.beaconBeamRepo != null) - { - this.beaconBeamDataHandler = new BeaconBeamDataHandler(this.beaconBeamRepo, genericRenderer); - } } @@ -228,31 +225,139 @@ public abstract class AbstractDhLevel implements IDhLevel //=================// @Override - public void updateBeaconBeamsForChunk(IChunkWrapper chunkToUpdate, ArrayList nearbyChunkList) + public void updateBeaconBeamsForSectionPos(long sectionPos, List activeBeamList) { - if (this.beaconBeamDataHandler != null) + int minBlockX = DhSectionPos.getMinCornerBlockX(sectionPos); + int minBlockZ = DhSectionPos.getMinCornerBlockZ(sectionPos); + // TODO special logic had to be done for DhChunkPos.getMaxBlock, + // does that need to be done here? + // The DhChunkPos issue caused beacons to appear/disappear incorrectly on negative chunk borders + int maxBlockX = minBlockX + DhSectionPos.getBlockWidth(sectionPos); + int maxBlockZ = minBlockZ + DhSectionPos.getBlockWidth(sectionPos); + + this.updateBeaconBeamsBetweenBlockPos( + sectionPos, + minBlockX, minBlockZ, + maxBlockX, maxBlockZ, + activeBeamList + ); + } + + @Override + public void updateBeaconBeamsForChunkPos(DhChunkPos chunkPos, List activeBeamList) + { + long sectionPos = DhSectionPos.encodeContaining(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, chunkPos); + + int minBlockX = chunkPos.getMinBlockX(); + int minBlockZ = chunkPos.getMinBlockZ(); + int maxBlockX = chunkPos.getMaxBlockX(); + int maxBlockZ = chunkPos.getMaxBlockZ(); + + //LOGGER.info("beacons ["+activeBeamList.size()+"] at ["+chunkPos+"] x["+minBlockX+"]-["+maxBlockX+"] z["+minBlockZ+"]-["+maxBlockZ+"]."); + + this.updateBeaconBeamsBetweenBlockPos( + sectionPos, + minBlockX, maxBlockX, + minBlockZ, maxBlockZ, + activeBeamList + ); + } + + private void updateBeaconBeamsBetweenBlockPos( + long sectionPosForLock, + int minBlockX, int maxBlockX, + int minBlockZ, int maxBlockZ, + List activeBeamList + ) // TODO min/max block pos instead + { + if (this.beaconBeamRepo == null) { - List activeBeamList = chunkToUpdate.getAllActiveBeacons(nearbyChunkList); - this.beaconBeamDataHandler.setBeaconBeamsForChunk(chunkToUpdate.getChunkPos(), activeBeamList); + return; + } + + + // locked to prevent two threads from updating the same section at the same time + ReentrantLock lock = this.beaconUpdateLockContainer.getLockForPos(sectionPosForLock); + try + { + lock.lock(); + + HashSet allPosSet = new HashSet<>(); + + // sort new beams + HashMap activeBeamByPos = new HashMap<>(activeBeamList.size()); + for (BeaconBeamDTO beam : activeBeamList) + { + activeBeamByPos.put(beam.blockPos, beam); + allPosSet.add(beam.blockPos); + } + + // get existing beams + List existingBeamList = this.beaconBeamRepo.getAllBeamsInBlockPosRange( + minBlockX, maxBlockX, + minBlockZ, maxBlockZ); + HashMap existingBeamByPos = new HashMap<>(existingBeamList.size()); + for (BeaconBeamDTO beam : existingBeamList) + { + existingBeamByPos.put(beam.blockPos, beam); + allPosSet.add(beam.blockPos); + } + + + + + for (DhBlockPos beaconPos : allPosSet) + { + if (minBlockX <= beaconPos.getX() && beaconPos.getX() <= maxBlockX + && minBlockZ <= beaconPos.getZ() && beaconPos.getZ() <= maxBlockZ) + { + //// don't modify beacons outside the updated range + //continue; + } + else + { + continue; + } + + + BeaconBeamDTO existingBeam = existingBeamByPos.get(beaconPos); + BeaconBeamDTO activeBeam = activeBeamByPos.get(beaconPos); + if (activeBeam != null) + { + //LOGGER.info("add beacon ["+activeBeam.blockPos+"] x["+minBlockX+"]-["+maxBlockX+"] z["+minBlockZ+"]-["+maxBlockZ+"]."); + + if (existingBeam == null) + { + // new beam found, add to DB + this.beaconBeamRepo.save(activeBeam); + } + else + { + // beam still exists in chunk + if (!existingBeam.color.equals(activeBeam.color)) + { + // beam colors were changed + this.beaconBeamRepo.save(activeBeam); + } + } + } + else if (existingBeam != null) + { + // beam no longer exists at position, remove from DB + this.beaconBeamRepo.deleteWithKey(beaconPos); + //LOGGER.info("remove beacon ["+beaconPos+"] x["+minBlockX+"]-["+maxBlockX+"] z["+minBlockZ+"]-["+maxBlockZ+"]."); + } + } + } + finally + { + lock.unlock(); } } @Override - public void loadBeaconBeamsInPos(long pos) - { - if (this.beaconBeamDataHandler != null) - { - this.beaconBeamDataHandler.loadBeaconBeamsInPos(pos); - } - } - @Override - public void unloadBeaconBeamsInPos(long pos) - { - if (this.beaconBeamDataHandler != null) - { - this.beaconBeamDataHandler.unloadBeaconBeamsInPos(pos); - } - } + @Nullable + public BeaconBeamRepo getBeaconBeamRepo() { return this.beaconBeamRepo; } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java index a96ae0008..92e3fdcaf 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java @@ -24,7 +24,6 @@ import com.seibel.distanthorizons.core.config.AppliedConfigState; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; -import com.seibel.distanthorizons.core.file.beacon.BeaconBeamDataHandler; import com.seibel.distanthorizons.core.file.fullDatafile.FullDataSourceProviderV2; import com.seibel.distanthorizons.core.file.fullDatafile.RemoteFullDataSourceProvider; import com.seibel.distanthorizons.core.file.structure.ISaveStructure; @@ -144,7 +143,7 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel return; } - this.beaconBeamDataHandler.setBeaconBeamsForPos(dataSourceDto.pos, message.payload.beaconBeams); + this.updateBeaconBeamsForSectionPos(dataSourceDto.pos, message.payload.beaconBeams); this.updateDataSourcesAsync(dataSourceDto.createDataSource(this.levelWrapper)); } catch (Exception e) @@ -283,7 +282,6 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel ClientLevelModule.ClientRenderState renderState = this.clientside.ClientRenderStateRef.get(); return (renderState != null) ? renderState.renderBufferHandler : null; } - public BeaconBeamDataHandler getBeaconBeamDataHandler() { return this.beaconBeamDataHandler; } 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 03b20718b..5ec90af5a 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 @@ -26,6 +26,8 @@ import com.seibel.distanthorizons.core.file.structure.ISaveStructure; import com.seibel.distanthorizons.core.pos.DhChunkPos; import com.seibel.distanthorizons.core.render.RenderBufferHandler; import com.seibel.distanthorizons.core.render.renderer.generic.GenericObjectRenderer; +import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO; +import com.seibel.distanthorizons.core.sql.repo.BeaconBeamRepo; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import org.jetbrains.annotations.Nullable; @@ -50,9 +52,16 @@ public interface IDhLevel extends AutoCloseable, GeneratedFullDataSourceProvider int getChunkHash(DhChunkPos pos); void updateChunkAsync(IChunkWrapper chunk, int newChunkHash); - void loadBeaconBeamsInPos(long pos); - void updateBeaconBeamsForChunk(IChunkWrapper chunkToUpdate, ArrayList nearbyChunkList); - void unloadBeaconBeamsInPos(long pos); + default void updateBeaconBeamsForChunk(IChunkWrapper chunkToUpdate, ArrayList nearbyChunkList) + { + List activeBeamList = chunkToUpdate.getAllActiveBeacons(nearbyChunkList); + this.updateBeaconBeamsForChunkPos(chunkToUpdate.getChunkPos(), activeBeamList); + } + void updateBeaconBeamsForChunkPos(DhChunkPos chunkPos, List activeBeamList); + void updateBeaconBeamsForSectionPos(long sectionPos, List activeBeamList); + + @Nullable + BeaconBeamRepo getBeaconBeamRepo(); FullDataSourceProviderV2 getFullDataProvider(); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/AbstractFullDataNetworkRequestQueue.java b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/AbstractFullDataNetworkRequestQueue.java index d1396607d..9bcd36a08 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/AbstractFullDataNetworkRequestQueue.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/AbstractFullDataNetworkRequestQueue.java @@ -239,7 +239,7 @@ public abstract class AbstractFullDataNetworkRequestQueue implements IDebugRende { try { - this.level.getBeaconBeamDataHandler().setBeaconBeamsForPos(dataSourceDto.pos, response.payload.beaconBeams); + this.level.updateBeaconBeamsForSectionPos(dataSourceDto.pos, response.payload.beaconBeams); try (FullDataSourceV2 fullDataSource = dataSourceDto.createDataSource(this.level.getLevelWrapper())) { entry.dataSourceConsumer.accept(fullDataSource); 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 9ebe039b9..590513c56 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 @@ -83,6 +83,19 @@ public class DhChunkPos public int getMinBlockX() { return this.x << 4; } public int getMinBlockZ() { return this.z << 4; } + public int getMaxBlockX() + { + int minBlockPos = this.getMinBlockX() + LodUtil.CHUNK_WIDTH; + minBlockPos += (minBlockPos < 0) ? -1 : 0; + return minBlockPos; + } + public int getMaxBlockZ() + { + int minBlockPos = this.getMinBlockZ() + LodUtil.CHUNK_WIDTH; + minBlockPos += (minBlockPos < 0) ? -1 : 0; + return minBlockPos; + } + public DhBlockPos2D getMinBlockPos() { return new DhBlockPos2D(this.x << 4, this.z << 4); } public boolean contains(DhBlockPos pos) @@ -92,8 +105,8 @@ public class DhChunkPos int maxBlockX = minBlockX + LodUtil.CHUNK_WIDTH; int maxBlockZ = minBlockZ + LodUtil.CHUNK_WIDTH; - return minBlockX <= pos.getX() && pos.getX() < maxBlockX - && minBlockZ <= pos.getZ() && pos.getZ() < maxBlockZ; + return minBlockX >= pos.getX() && pos.getX() < maxBlockX + && minBlockZ >= pos.getZ() && pos.getZ() < maxBlockZ; } public double distance(DhChunkPos other) 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 db52b8b8b..7e7060b28 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 @@ -34,6 +34,8 @@ import com.seibel.distanthorizons.core.pos.blockPos.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.render.renderer.generic.BeaconRenderHandler; +import com.seibel.distanthorizons.core.render.renderer.generic.GenericObjectRenderer; import com.seibel.distanthorizons.core.util.KeyedLockContainer; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.ThreadUtil; @@ -43,6 +45,7 @@ import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil; import com.seibel.distanthorizons.coreapi.util.MathUtil; import it.unimi.dsi.fastutil.longs.LongIterator; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.Nullable; import javax.annotation.WillNotClose; import java.awt.*; @@ -138,6 +141,9 @@ public class LodQuadTree extends QuadTree implements IDebugRen }) .build(); + @Nullable + public final BeaconRenderHandler beaconRenderHandler; + /** the smallest numerical detail level number that can be rendered */ private byte maxRenderDetailLevel; @@ -167,6 +173,10 @@ public class LodQuadTree extends QuadTree implements IDebugRen this.level = level; this.fullDataSourceProvider = fullDataSourceProvider; this.blockRenderDistanceDiameter = viewDiameterInBlocks; + + GenericObjectRenderer genericObjectRenderer = this.level.getGenericRenderer(); + this.beaconRenderHandler = (genericObjectRenderer != null) ? new BeaconRenderHandler(genericObjectRenderer) : null; + } @@ -340,9 +350,11 @@ public class LodQuadTree extends QuadTree implements IDebugRen } else { - // onRenderingDisabled() needs to be fired before the children are enabled so beacons render correctly + // children are all loaded, unload this and parents + if (renderSection.getRenderingEnabled()) { + // needs to be fired before the children are enabled so beacons render correctly renderSection.onRenderingDisabled(); @@ -463,7 +475,7 @@ public class LodQuadTree extends QuadTree implements IDebugRen } }); - // onRenderingEnabled() needs to be fired after the children are disabled so beacons render correctly + // needs to be fired after the children are disabled so beacons render correctly renderSection.onRenderingEnabled(); } 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 e64710fd7..1d543a32e 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 @@ -38,6 +38,9 @@ import com.seibel.distanthorizons.core.render.glObject.GLProxy; 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.render.renderer.generic.BeaconRenderHandler; +import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO; +import com.seibel.distanthorizons.core.sql.repo.BeaconBeamRepo; import com.seibel.distanthorizons.core.util.KeyedLockContainer; import com.seibel.distanthorizons.core.util.threading.PriorityTaskPicker; import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil; @@ -49,6 +52,7 @@ import org.jetbrains.annotations.Nullable; import javax.annotation.WillNotClose; import java.awt.*; import java.util.*; +import java.util.List; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; @@ -83,6 +87,15 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable private final KeyedLockContainer renderLoadLockContainer; private final Cache cachedRenderSourceByPos; + /** + * contains the list of beacons currently being rendered in this section + * if this list is modified the {@link LodRenderSection#beaconRenderHandler} should be updated to match. + */ + private final List activeBeaconList = new ArrayList<>(); + @Nullable + public final BeaconRenderHandler beaconRenderHandler; + @Nullable + public final BeaconBeamRepo beaconBeamRepo; private boolean renderingEnabled = false; @@ -139,6 +152,9 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable this.level = level; this.fullDataSourceProvider = fullDataSourceProvider; + this.beaconRenderHandler = this.quadTree.beaconRenderHandler; + this.beaconBeamRepo = this.level.getBeaconBeamRepo(); + DebugRenderer.register(this, Config.Client.Advanced.Debugging.DebugWireframe.showRenderSectionStatus); } @@ -193,6 +209,7 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable this.getAndBuildRenderDataRunnable = () -> { + this.getAndRefreshRenderingBeacons(); this.getAndUploadRenderDataToGpu(); // the future is passed in separate to prevent any possible race condition null pointers @@ -350,25 +367,24 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable public void setRenderingEnabled(boolean enabled) { this.renderingEnabled = enabled;} /** @see LodRenderSection#setRenderingEnabled */ - public void onRenderingEnabled() { this.level.loadBeaconBeamsInPos(this.pos); } + public void onRenderingEnabled() { this.startRenderingBeacons(); } /** @see LodRenderSection#setRenderingEnabled */ public void onRenderingDisabled() { - this.level.unloadBeaconBeamsInPos(this.pos); + this.stopRenderingBeacons(); if (Config.Client.Advanced.Debugging.DebugWireframe.showRenderSectionStatus.get()) { // show that this position has just been disabled DebugRenderer.makeParticle( - new DebugRenderer.BoxParticle( - new DebugRenderer.Box(this.pos, 128f, 156f, 0.09f, Color.CYAN.darker()), - 0.2, 32f - ) + new DebugRenderer.BoxParticle( + new DebugRenderer.Box(this.pos, 128f, 156f, 0.09f, Color.CYAN.darker()), + 0.2, 32f + ) ); } } - public boolean gpuUploadInProgress() { return this.getAndBuildRenderDataFuture != null; } @@ -465,6 +481,85 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable + //=================// + // beacon handling // + //=================// + + /** gets the active beacon list and stops/starts beacon rendering as necessary */ + private void getAndRefreshRenderingBeacons() + { + // do nothing if beacon rendering or repos are unavailable + if (this.beaconBeamRepo == null + || this.beaconRenderHandler == null) + { + return; + } + + + // Synchronized to prevent two threads for starting/stopping rendering at once + // Shouldn't be necessary, but just in case. + synchronized (this.activeBeaconList) + { + List activeBeacons = this.beaconBeamRepo.getAllBeamsForPos(this.pos); + + + // stop rendering current beacons + for (BeaconBeamDTO beam : this.activeBeaconList) + { + this.beaconRenderHandler.stopRenderingBeaconAtPos(beam.blockPos); + } + + // swap old and new active beacon list + this.activeBeaconList.clear(); + this.activeBeaconList.addAll(activeBeacons); + + // start rendering new beacon list + for (BeaconBeamDTO beam : this.activeBeaconList) + { + this.beaconRenderHandler.startRenderingBeacon(beam); + } + } + } + + private void stopRenderingBeacons() + { + // do nothing if beacon rendering is unavailable + if (this.beaconRenderHandler == null) + { + return; + } + + + synchronized (this.activeBeaconList) + { + for (BeaconBeamDTO beam : this.activeBeaconList) + { + this.beaconRenderHandler.stopRenderingBeaconAtPos(beam.blockPos); + } + } + } + + private void startRenderingBeacons() + { + // do nothing if beacon rendering is unavailable + if (this.beaconRenderHandler == null) + { + return; + } + + + synchronized (this.activeBeaconList) + { + for (BeaconBeamDTO beam : this.activeBeaconList) + { + this.beaconRenderHandler.startRenderingBeacon(beam); + } + } + } + + + + //==============// // base methods // //==============// @@ -514,7 +609,7 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable } - this.level.unloadBeaconBeamsInPos(this.pos); + this.stopRenderingBeacons(); if (this.renderBuffer != null) { @@ -551,6 +646,7 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable // while this should generally be a fast operation // this is run on a separate thread to prevent lag on the render thread executor.execute(() -> this.fullDataSourceProvider.removeRetrievalRequestIf((genPos) -> DhSectionPos.contains(this.pos, genPos))); + } 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 a9612c6c1..71a9a1cec 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 @@ -174,8 +174,8 @@ public class BeaconBeamRepo extends AbstractDhRepo int maxBlockZ = minBlockZ + LodUtil.CHUNK_WIDTH; return this.getAllBeamsInBlockPosRange( - minBlockX, minBlockZ, - maxBlockX, maxBlockZ + minBlockX, maxBlockX, + minBlockZ, maxBlockZ ); } @@ -187,8 +187,8 @@ public class BeaconBeamRepo extends AbstractDhRepo int maxBlockZ = minBlockZ + DhSectionPos.getBlockWidth(pos); return this.getAllBeamsInBlockPosRange( - minBlockX, minBlockZ, - maxBlockX, maxBlockZ + minBlockX, maxBlockX, + minBlockZ, maxBlockZ ); } @@ -199,8 +199,8 @@ public class BeaconBeamRepo extends AbstractDhRepo "? <= BlockPosX AND BlockPosX <= ? AND " + "? <= BlockPosZ AND BlockPosZ <= ?"; public List getAllBeamsInBlockPosRange( - int minBlockX, int minBlockZ, - int maxBlockX, int maxBlockZ + int minBlockX, int maxBlockX, + int minBlockZ, int maxBlockZ ) { ArrayList beamList = new ArrayList<>(); @@ -214,8 +214,8 @@ public class BeaconBeamRepo extends AbstractDhRepo int i = 1; statement.setInt(i++, minBlockX); - statement.setInt(i++, minBlockZ); statement.setInt(i++, maxBlockX); + statement.setInt(i++, minBlockZ); statement.setInt(i++, maxBlockZ);