move beacon render enabling to LodQuadTree
Fixes beacons not always showing/hiding correctly
This commit is contained in:
+148
-23
@@ -38,6 +38,8 @@ import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
|
||||
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
|
||||
import com.seibel.distanthorizons.core.render.renderer.BeaconRenderHandler;
|
||||
import com.seibel.distanthorizons.core.render.renderer.IDebugRenderable;
|
||||
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.ThreadUtil;
|
||||
import com.seibel.distanthorizons.core.util.WorldGenUtil;
|
||||
@@ -55,10 +57,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import javax.annotation.WillNotClose;
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
@@ -97,8 +96,19 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
|
||||
private final AtomicBoolean queueThreadRunningRef = new AtomicBoolean(false);
|
||||
|
||||
|
||||
/**
|
||||
* contains the list of beacons currently being rendered in this section
|
||||
* if this list is modified the {@link LodQuadTree#beaconRenderHandler} should be updated to match.
|
||||
*/
|
||||
private final ArrayList<BeaconRenderHandler.BeaconBeamWithWidth> beaconList = new ArrayList<>();
|
||||
@Nullable
|
||||
public final BeaconRenderHandler beaconRenderHandler;
|
||||
private final BeaconRenderHandler beaconRenderHandler;
|
||||
@Nullable
|
||||
private final BeaconBeamRepo beaconBeamRepo;
|
||||
/** used to prevent updating the beacons concurrently */
|
||||
@NotNull
|
||||
private CompletableFuture<Void> beaconUpdateFuture = CompletableFuture.completedFuture(null);
|
||||
|
||||
|
||||
/** the smallest numerical detail level number that can be rendered */
|
||||
private byte maxLeafRenderDetailLevel;
|
||||
@@ -149,6 +159,8 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
|
||||
IDhGenericRenderer genericObjectRenderer = this.level.getGenericRenderer();
|
||||
this.beaconRenderHandler = (genericObjectRenderer != null) ? new BeaconRenderHandler(genericObjectRenderer) : null;
|
||||
|
||||
this.beaconBeamRepo = this.level.getBeaconBeamRepo();
|
||||
|
||||
Config.Common.WorldGenerator.enableDistantGeneration.addListener(this);
|
||||
Config.Server.enableServerGeneration.addListener(this);
|
||||
|
||||
@@ -367,7 +379,6 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
|
||||
if (node == null || node.value == null) { continue; }
|
||||
|
||||
node.value.setRenderingEnabled(false);
|
||||
node.value.tryDisableBeacons();
|
||||
}
|
||||
|
||||
for (QuadNode<LodRenderSection> node : this.tickNodeHolder.getEnableDeleteChildrenNodes())
|
||||
@@ -389,7 +400,6 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
|
||||
if (childRenderSection != null)
|
||||
{
|
||||
childRenderSection.setRenderingEnabled(false);
|
||||
childRenderSection.tryDisableBeacons();
|
||||
childRenderSection.close();
|
||||
}
|
||||
});
|
||||
@@ -405,21 +415,7 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
|
||||
//=================//
|
||||
//region
|
||||
|
||||
// must be handled after beacon disabling
|
||||
// otherwise the beacons will be missing
|
||||
|
||||
for (QuadNode<LodRenderSection> node : this.tickNodeHolder.getEnabledNodes())
|
||||
{
|
||||
if (node == null || node.value == null) { continue; }
|
||||
|
||||
node.value.tryEnableBeacons();
|
||||
}
|
||||
for (QuadNode<LodRenderSection> node : this.tickNodeHolder.getEnableDeleteChildrenNodes())
|
||||
{
|
||||
if (node == null || node.value == null) { continue; }
|
||||
|
||||
node.value.tryEnableBeacons();
|
||||
}
|
||||
this.tryRefreshRenderingBeaconsAsync(playerPos);
|
||||
|
||||
//endregion
|
||||
|
||||
@@ -872,6 +868,133 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
|
||||
|
||||
|
||||
|
||||
//=================//
|
||||
// beacon handling //
|
||||
//=================//
|
||||
//region beacon handling
|
||||
|
||||
/** gets the active beacon list and stops/starts beacon rendering as necessary */
|
||||
private void tryRefreshRenderingBeaconsAsync(DhBlockPos2D playerPos)
|
||||
{
|
||||
// do nothing if beacon rendering or repos are unavailable
|
||||
if (this.beaconBeamRepo == null
|
||||
|| this.beaconRenderHandler == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor();
|
||||
if (executor == null)
|
||||
{
|
||||
// shouldn't normally happen, but just in case
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.beaconUpdateFuture.isDone())
|
||||
{
|
||||
return;
|
||||
}
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
this.beaconUpdateFuture = future;
|
||||
|
||||
try
|
||||
{
|
||||
executor.execute(() ->
|
||||
{
|
||||
this.refreshRenderingBeacons(playerPos);
|
||||
|
||||
try { Thread.sleep(2_000); } catch (InterruptedException ignore) { }
|
||||
future.complete(null);
|
||||
});
|
||||
}
|
||||
catch (RejectedExecutionException e)
|
||||
{
|
||||
// the thread pool was probably shut down because it's size is being changed, just wait a sec and it should be back
|
||||
future.completeExceptionally(e);
|
||||
}
|
||||
}
|
||||
private void refreshRenderingBeacons(DhBlockPos2D playerPos)
|
||||
{
|
||||
if (this.beaconBeamRepo == null
|
||||
|| this.beaconRenderHandler == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Synchronized to prevent two threads for accessing the array at once
|
||||
synchronized (this.beaconList)
|
||||
{
|
||||
// get beacons //
|
||||
|
||||
int blockDistanceRadius = (this.blockRenderDistanceDiameter / 2);
|
||||
int minBlockPosX = playerPos.x - blockDistanceRadius;
|
||||
int minBlockPosZ = playerPos.z - blockDistanceRadius;
|
||||
int maxBlockPosX = playerPos.x + blockDistanceRadius;
|
||||
int maxBlockPosZ = playerPos.z + blockDistanceRadius;
|
||||
|
||||
ArrayList<BeaconBeamDTO> dbBeacons = this.beaconBeamRepo.getAllBeamsInBlockPosRange(
|
||||
minBlockPosX, maxBlockPosX,
|
||||
minBlockPosZ, maxBlockPosZ
|
||||
);
|
||||
|
||||
|
||||
// convert DB beacons //
|
||||
|
||||
ArrayList<BeaconRenderHandler.BeaconBeamWithWidth> newBeaconList = new ArrayList<>(this.beaconList.size());
|
||||
for (BeaconBeamDTO beaconBeam : dbBeacons)
|
||||
{
|
||||
byte beaconDetailLevel = this.calcExpectedDetailLevel(playerPos, beaconBeam.blockPos.getX(), beaconBeam.blockPos.getZ());
|
||||
newBeaconList.add(new BeaconRenderHandler.BeaconBeamWithWidth(beaconBeam, beaconDetailLevel));
|
||||
}
|
||||
|
||||
|
||||
boolean replaceBeacons = false;
|
||||
if (this.beaconList.size() != newBeaconList.size())
|
||||
{
|
||||
// lists are different sizes
|
||||
replaceBeacons = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// sort the beacons so they can be compared
|
||||
this.beaconList.sort(BeaconRenderHandler.NegativeInfiniteBlockPosComparator.INSTANCE);
|
||||
newBeaconList.sort(BeaconRenderHandler.NegativeInfiniteBlockPosComparator.INSTANCE);
|
||||
|
||||
for (int i = 0; i < this.beaconList.size(); i++)
|
||||
{
|
||||
BeaconRenderHandler.BeaconBeamWithWidth oldBeam = this.beaconList.get(i);
|
||||
BeaconRenderHandler.BeaconBeamWithWidth newBeam = newBeaconList.get(i);
|
||||
if (!oldBeam.equals(newBeam))
|
||||
{
|
||||
replaceBeacons = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// only replace the beacons if something changed
|
||||
// this is done to prevent constantly re-uploading the render data
|
||||
if (replaceBeacons)
|
||||
{
|
||||
this.beaconList.clear();
|
||||
this.beaconList.addAll(newBeaconList);
|
||||
this.beaconRenderHandler.replaceRenderingBeacons(this.beaconList);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.error("Unexpected issue updating beacons, error: ["+e.getMessage()+"].", e);
|
||||
}
|
||||
}
|
||||
|
||||
//endregion beacon handling
|
||||
|
||||
|
||||
|
||||
//====================//
|
||||
// detail level logic //
|
||||
//====================//
|
||||
@@ -885,8 +1008,10 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
|
||||
* @return detail level of this section pos
|
||||
*/
|
||||
public byte calcExpectedDetailLevel(DhBlockPos2D playerPos, long sectionPos)
|
||||
{ return this.calcExpectedDetailLevel(playerPos, DhSectionPos.getCenterBlockPosX(sectionPos), DhSectionPos.getCenterBlockPosZ(sectionPos)); }
|
||||
public byte calcExpectedDetailLevel(DhBlockPos2D playerPos, int targetBlockPosX, int targetBlockPosZ)
|
||||
{
|
||||
double blockDistance = playerPos.dist(DhSectionPos.getCenterBlockPosX(sectionPos), DhSectionPos.getCenterBlockPosZ(sectionPos));
|
||||
double blockDistance = playerPos.dist(targetBlockPosX, targetBlockPosZ);
|
||||
return this.calcDetailLevelFromDistance(blockDistance);
|
||||
}
|
||||
|
||||
|
||||
-146
@@ -73,21 +73,6 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable
|
||||
private final FullDataSourceProviderV2 fullDataSourceProvider;
|
||||
private final LodQuadTree quadTree;
|
||||
|
||||
/**
|
||||
* 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 ArrayList<BeaconBeamDTO> activeBeaconList = new ArrayList<>();
|
||||
@Nullable
|
||||
public final BeaconRenderHandler beaconRenderHandler;
|
||||
@Nullable
|
||||
public final BeaconBeamRepo beaconBeamRepo;
|
||||
/**
|
||||
* locking is necessary to prevent some weird threading issues
|
||||
* causing beacons to appear/disappear at the wrong times.
|
||||
*/
|
||||
private final ReentrantLock beaconRenderHandlingLock = new ReentrantLock();
|
||||
|
||||
|
||||
private boolean renderingEnabled = false;
|
||||
private boolean beaconsRendering = false;
|
||||
@@ -134,9 +119,6 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable
|
||||
this.levelWrapper = level.getClientLevelWrapper();
|
||||
this.fullDataSourceProvider = fullDataSourceProvider;
|
||||
|
||||
this.beaconRenderHandler = this.quadTree.beaconRenderHandler;
|
||||
this.beaconBeamRepo = this.level.getBeaconBeamRepo();
|
||||
|
||||
DEBUG_RENDERER.register(this, Config.Client.Advanced.Debugging.DebugWireframe.showRenderSectionStatus);
|
||||
}
|
||||
|
||||
@@ -188,8 +170,6 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable
|
||||
{
|
||||
try
|
||||
{
|
||||
this.refreshActiveBeaconList();
|
||||
|
||||
LodQuadBuilder lodQuadBuilder = this.getAndBuildRenderData();
|
||||
if (lodQuadBuilder == null)
|
||||
{
|
||||
@@ -376,130 +356,6 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable
|
||||
|
||||
|
||||
|
||||
//=================//
|
||||
// beacon handling //
|
||||
//=================//
|
||||
//region beacon handling
|
||||
|
||||
/** gets the active beacon list and stops/starts beacon rendering as necessary */
|
||||
private void refreshActiveBeaconList()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.beaconRenderHandlingLock.lock();
|
||||
|
||||
// do nothing if beacon rendering or repos are unavailable
|
||||
if (this.beaconBeamRepo == null
|
||||
|| this.beaconRenderHandler == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Synchronized to prevent two threads for accessing the array at once
|
||||
synchronized (this.activeBeaconList)
|
||||
{
|
||||
ArrayList<BeaconBeamDTO> activeBeacons = this.beaconBeamRepo.getAllBeamsForPos(this.pos);
|
||||
|
||||
// swap old and new active beacon list
|
||||
this.activeBeaconList.clear();
|
||||
this.activeBeaconList.addAll(activeBeacons);
|
||||
|
||||
// if the beacons are currently rendering,
|
||||
// re-create them so we can see any potential changes
|
||||
if (this.beaconsRendering)
|
||||
{
|
||||
this.tryDisableBeacons();
|
||||
this.tryEnableBeacons();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.beaconRenderHandlingLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void tryDisableBeacons()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.beaconRenderHandlingLock.lock();
|
||||
|
||||
|
||||
// do nothing if beacon rendering is unavailable
|
||||
if (this.beaconRenderHandler == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.beaconsRendering)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.beaconsRendering = false;
|
||||
|
||||
|
||||
|
||||
if (Config.Client.Advanced.Debugging.DebugWireframe.showRenderSectionStatus.get())
|
||||
{
|
||||
// show that this position has just been disabled
|
||||
DEBUG_RENDERER.makeParticle(
|
||||
new AbstractDebugWireframeRenderer.BoxParticle(
|
||||
new AbstractDebugWireframeRenderer.Box(this.pos, 128f, 156f, 0.09f, Color.CYAN.darker()),
|
||||
0.2, 32f
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
synchronized (this.activeBeaconList)
|
||||
{
|
||||
this.beaconRenderHandler.stopRenderingBeaconsInRange(this.pos);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.beaconRenderHandlingLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void tryEnableBeacons()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.beaconRenderHandlingLock.lock();
|
||||
|
||||
|
||||
// do nothing if beacon rendering is unavailable
|
||||
if (this.beaconRenderHandler == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.beaconsRendering)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.beaconsRendering = true;
|
||||
|
||||
|
||||
synchronized (this.activeBeaconList)
|
||||
{
|
||||
byte absoluteDetailLevel = (byte)(DhSectionPos.getDetailLevel(this.pos) - DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL);
|
||||
this.beaconRenderHandler.startRenderingBeacons(this.activeBeaconList, absoluteDetailLevel);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.beaconRenderHandlingLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
//endregion beacon handling
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// base methods //
|
||||
//==============//
|
||||
@@ -562,8 +418,6 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable
|
||||
}
|
||||
|
||||
|
||||
this.tryDisableBeacons();
|
||||
|
||||
if (this.renderBufferContainer != null)
|
||||
{
|
||||
this.renderBufferContainer.close();
|
||||
|
||||
+126
-124
@@ -46,7 +46,6 @@ import java.util.*;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class BeaconRenderHandler
|
||||
{
|
||||
@@ -57,8 +56,6 @@ public class BeaconRenderHandler
|
||||
/** how often should we check if a beacon should be culled? */
|
||||
private static final int MAX_CULLING_FREQUENCY_IN_MS = 1_000;
|
||||
|
||||
private static final Comparator<BeaconBeamDTO> NEGATIVE_BLOCKPOS_COMPARATOR = new NegativeInfiniteBlockPosComparator();
|
||||
|
||||
|
||||
|
||||
private final ReentrantLock updateLock = new ReentrantLock();
|
||||
@@ -67,8 +64,6 @@ public class BeaconRenderHandler
|
||||
private final IDhApiRenderableBoxGroup activeBeaconBoxRenderGroup;
|
||||
/** contains all beacons that could be rendered (including those that are being culled) */
|
||||
private final ArrayList<DhApiRenderableBox> fullBeaconBoxList = new ArrayList<>();
|
||||
/** contains all beacons that could be rendered */
|
||||
private final HashSet<DhBlockPos> fullBeaconBlockPosSet = new HashSet<>();
|
||||
|
||||
private boolean cullingThreadRunning = false;
|
||||
private boolean updateRenderDataNextFrame = false;
|
||||
@@ -96,125 +91,11 @@ public class BeaconRenderHandler
|
||||
|
||||
|
||||
|
||||
//=================//
|
||||
// render handling //
|
||||
//=================//
|
||||
//===============//
|
||||
// before render //
|
||||
//===============//
|
||||
//region
|
||||
|
||||
public void startRenderingBeacons(ArrayList<BeaconBeamDTO> beaconList, byte detailLevel)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.updateLock.lock();
|
||||
|
||||
|
||||
// how wide should each beacon be?
|
||||
int beaconBlockWidth = 1;
|
||||
if (Config.Client.Advanced.Graphics.GenericRendering.expandDistantBeacons.get())
|
||||
{
|
||||
beaconBlockWidth = DhSectionPos.getBlockWidth(detailLevel);
|
||||
}
|
||||
|
||||
|
||||
ArrayList<BeaconBeamDTO> sortedBeaconList = new ArrayList<>(beaconList);
|
||||
|
||||
// merge distant beams if requested
|
||||
if (Config.Client.Advanced.Graphics.GenericRendering.expandDistantBeacons.get())
|
||||
{
|
||||
// sort beacons from neg inf -> pos inf
|
||||
// so we can consistently merge adjacent beacons
|
||||
sortedBeaconList.sort(NEGATIVE_BLOCKPOS_COMPARATOR);
|
||||
|
||||
// go through each beacon...
|
||||
for (int outerIndex = 0; outerIndex < sortedBeaconList.size(); outerIndex++)
|
||||
{
|
||||
BeaconBeamDTO outerBeacon = sortedBeaconList.get(outerIndex);
|
||||
DhBlockPos outerBlockPos = outerBeacon.blockPos;
|
||||
|
||||
// ...and remove any beacons that are within the block width to prevent overlaps
|
||||
for (int mergeIndex = outerIndex + 1; mergeIndex < sortedBeaconList.size(); mergeIndex++)
|
||||
{
|
||||
BeaconBeamDTO beaconToMerge = sortedBeaconList.get(mergeIndex);
|
||||
DhBlockPos mergeBlockPos = beaconToMerge.blockPos;
|
||||
|
||||
int xDiff = mergeBlockPos.getX() - outerBlockPos.getX();
|
||||
int zDiff = mergeBlockPos.getZ() - outerBlockPos.getZ();
|
||||
|
||||
// merge (remove) this beacon if
|
||||
// it's close to the outer beacon
|
||||
if (xDiff < beaconBlockWidth
|
||||
&& zDiff < beaconBlockWidth)
|
||||
{
|
||||
sortedBeaconList.remove(mergeIndex);
|
||||
mergeIndex--; // minus 1 so we don't go past the end of the array when incrementing in the for loop up top
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//LOGGER.info("startRenderingBeacons ["+sortedBeaconList+"]");
|
||||
|
||||
// add each beacon to the renderer
|
||||
for (int i = 0; i < sortedBeaconList.size(); i++)
|
||||
{
|
||||
BeaconBeamDTO beacon = sortedBeaconList.get(i);
|
||||
if (!this.fullBeaconBlockPosSet.add(beacon.blockPos))
|
||||
{
|
||||
// skip already present beacons
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
int maxBeaconBeamHeight = Config.Client.Advanced.Graphics.GenericRendering.beaconRenderHeight.get();
|
||||
DhApiRenderableBox beaconBox = new DhApiRenderableBox(
|
||||
new DhApiVec3d(beacon.blockPos.getX(), beacon.blockPos.getY() + 1, beacon.blockPos.getZ()),
|
||||
new DhApiVec3d(beacon.blockPos.getX() + beaconBlockWidth, maxBeaconBeamHeight, beacon.blockPos.getZ() + beaconBlockWidth),
|
||||
beacon.color,
|
||||
EDhApiBlockMaterial.ILLUMINATED
|
||||
);
|
||||
|
||||
this.activeBeaconBoxRenderGroup.add(beaconBox);
|
||||
this.fullBeaconBoxList.add(beaconBox);
|
||||
this.activeBeaconBoxRenderGroup.triggerBoxChange();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.updateLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void stopRenderingBeaconsInRange(long pos)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.updateLock.lock();
|
||||
|
||||
Predicate<DhApiRenderableBox> removeBoxPredicate = (DhApiRenderableBox box) ->
|
||||
{
|
||||
DhBlockPos blockPos = new DhBlockPos((int)box.minPos.x, (int)box.minPos.y, (int)box.minPos.z);
|
||||
boolean contains = DhSectionPos.contains(pos, blockPos);
|
||||
//if (contains)
|
||||
//{
|
||||
// LOGGER.info("stopRenderingBeaconsInRange ["+DhSectionPos.toString(pos)+"] ["+blockPos+"]");
|
||||
//}
|
||||
return contains;
|
||||
};
|
||||
this.activeBeaconBoxRenderGroup.removeIf(removeBoxPredicate);
|
||||
this.fullBeaconBoxList.removeIf(removeBoxPredicate);
|
||||
|
||||
this.fullBeaconBlockPosSet.removeIf((DhBlockPos blockPos) -> DhSectionPos.contains(pos, blockPos));
|
||||
|
||||
this.activeBeaconBoxRenderGroup.triggerBoxChange();
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.updateLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void beforeRender(DhApiRenderParam renderEventParam)
|
||||
{
|
||||
if (Config.Client.Advanced.Graphics.Culling.disableBeaconDistanceCulling.get())
|
||||
@@ -304,15 +185,136 @@ public class BeaconRenderHandler
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// registration //
|
||||
//==============//
|
||||
//region
|
||||
|
||||
public void replaceRenderingBeacons(ArrayList<BeaconBeamWithWidth> beaconList)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.updateLock.lock();
|
||||
|
||||
ArrayList<BeaconBeamWithWidth> sortedBeaconList = new ArrayList<>(beaconList);
|
||||
|
||||
// merge distant beams if requested
|
||||
if (Config.Client.Advanced.Graphics.GenericRendering.expandDistantBeacons.get())
|
||||
{
|
||||
// sort beacons from neg inf -> pos inf
|
||||
// so we can consistently merge adjacent beacons
|
||||
sortedBeaconList.sort(NegativeInfiniteBlockPosComparator.INSTANCE);
|
||||
|
||||
// go through each beacon...
|
||||
for (int outerIndex = 0; outerIndex < sortedBeaconList.size(); outerIndex++)
|
||||
{
|
||||
BeaconBeamWithWidth outerBeacon = sortedBeaconList.get(outerIndex);
|
||||
DhBlockPos outerBlockPos = outerBeacon.blockPos;
|
||||
|
||||
// ...and remove any beacons that are within the block width to prevent overlaps
|
||||
for (int mergeIndex = outerIndex + 1; mergeIndex < sortedBeaconList.size(); mergeIndex++)
|
||||
{
|
||||
BeaconBeamWithWidth beaconToMerge = sortedBeaconList.get(mergeIndex);
|
||||
DhBlockPos mergeBlockPos = beaconToMerge.blockPos;
|
||||
|
||||
int xDiff = mergeBlockPos.getX() - outerBlockPos.getX();
|
||||
int zDiff = mergeBlockPos.getZ() - outerBlockPos.getZ();
|
||||
|
||||
// merge (remove) this beacon if
|
||||
// it's close to the outer beacon
|
||||
if (xDiff < beaconToMerge.beaconBlockWidth
|
||||
&& zDiff < beaconToMerge.beaconBlockWidth)
|
||||
{
|
||||
sortedBeaconList.remove(mergeIndex);
|
||||
mergeIndex--; // minus 1 so we don't go past the end of the array when incrementing in the for loop up top
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.activeBeaconBoxRenderGroup.clear();
|
||||
this.fullBeaconBoxList.clear();
|
||||
|
||||
// add each beacon to the renderer
|
||||
for (int i = 0; i < sortedBeaconList.size(); i++)
|
||||
{
|
||||
BeaconBeamWithWidth beacon = sortedBeaconList.get(i);
|
||||
int maxBeaconBeamHeight = Config.Client.Advanced.Graphics.GenericRendering.beaconRenderHeight.get();
|
||||
DhApiRenderableBox beaconBox = new DhApiRenderableBox(
|
||||
new DhApiVec3d(beacon.blockPos.getX(), beacon.blockPos.getY() + 1, beacon.blockPos.getZ()),
|
||||
new DhApiVec3d(beacon.blockPos.getX() + beacon.beaconBlockWidth, maxBeaconBeamHeight, beacon.blockPos.getZ() + beacon.beaconBlockWidth),
|
||||
beacon.color,
|
||||
EDhApiBlockMaterial.ILLUMINATED
|
||||
);
|
||||
|
||||
this.activeBeaconBoxRenderGroup.add(beaconBox);
|
||||
this.fullBeaconBoxList.add(beaconBox);
|
||||
}
|
||||
|
||||
this.activeBeaconBoxRenderGroup.triggerBoxChange();
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.updateLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper classes //
|
||||
//================//
|
||||
//region
|
||||
|
||||
private static class NegativeInfiniteBlockPosComparator implements Comparator<BeaconBeamDTO>
|
||||
public static class BeaconBeamWithWidth extends BeaconBeamDTO
|
||||
{
|
||||
public final int beaconBlockWidth;
|
||||
|
||||
public BeaconBeamWithWidth(BeaconBeamDTO beaconBeamDTO, byte lodDetailLevel)
|
||||
{
|
||||
super(beaconBeamDTO.blockPos, beaconBeamDTO.color);
|
||||
|
||||
|
||||
// how wide should each beacon be?
|
||||
if (Config.Client.Advanced.Graphics.GenericRendering.expandDistantBeacons.get())
|
||||
{
|
||||
this.beaconBlockWidth = DhSectionPos.getBlockWidth(lodDetailLevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.beaconBlockWidth = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(BeaconBeamDTO beacon1, BeaconBeamDTO beacon2)
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj == null
|
||||
|| obj.getClass() != this.getClass())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BeaconBeamWithWidth that = (BeaconBeamWithWidth) obj;
|
||||
if (that.beaconBlockWidth != this.beaconBlockWidth)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return super.equals(that);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class NegativeInfiniteBlockPosComparator implements Comparator<BeaconBeamWithWidth>
|
||||
{
|
||||
public static final NegativeInfiniteBlockPosComparator INSTANCE = new NegativeInfiniteBlockPosComparator();
|
||||
|
||||
@Override
|
||||
public int compare(BeaconBeamWithWidth beacon1, BeaconBeamWithWidth beacon2)
|
||||
{
|
||||
DhBlockPos blockPos1 = beacon1.blockPos;
|
||||
DhBlockPos blockPos2 = beacon2.blockPos;
|
||||
|
||||
@@ -72,6 +72,20 @@ public class BeaconBeamDTO implements IBaseDTO<DhBlockPos>, INetworkObject
|
||||
@Override
|
||||
public DhBlockPos getKey() { return this.blockPos; }
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj == null
|
||||
|| obj.getClass() != this.getClass())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BeaconBeamDTO that = (BeaconBeamDTO)obj;
|
||||
return this.blockPos.equals(that.blockPos)
|
||||
&& this.color.equals(that.color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{ /* no closing needed */ }
|
||||
|
||||
Reference in New Issue
Block a user