SectionOcclusionGraph.java
net.minecraft.client.renderer.SectionOcclusionGraph
信息
- 全限定名:net.minecraft.client.renderer.SectionOcclusionGraph
- 类型:public class
- 包:net.minecraft.client.renderer
- 源码路径:src/main/java/net/minecraft/client/renderer/SectionOcclusionGraph.java
- 起始行号:L44
- 职责:
TODO
字段/常量
-
LOGGER- 类型:
Logger - 修饰符:
private static final - 源码定位:
L45 - 说明:
TODO
- 类型:
-
DIRECTIONS- 类型:
Direction[] - 修饰符:
private static final - 源码定位:
L46 - 说明:
TODO
- 类型:
-
MINIMUM_ADVANCED_CULLING_DISTANCE- 类型:
int - 修饰符:
private static final - 源码定位:
L47 - 说明:
TODO
- 类型:
-
MINIMUM_ADVANCED_CULLING_SECTION_DISTANCE- 类型:
int - 修饰符:
private static final - 源码定位:
L48 - 说明:
TODO
- 类型:
-
CEILED_SECTION_DIAGONAL- 类型:
double - 修饰符:
private static final - 源码定位:
L49 - 说明:
TODO
- 类型:
-
needsFullUpdate- 类型:
boolean - 修饰符:
private - 源码定位:
L50 - 说明:
TODO
- 类型:
-
fullUpdateTask- 类型:
Future<?> - 修饰符:
private - 源码定位:
L51 - 说明:
TODO
- 类型:
-
viewArea- 类型:
ViewArea - 修饰符:
private - 源码定位:
L52 - 说明:
TODO
- 类型:
-
currentGraph- 类型:
AtomicReference<SectionOcclusionGraph.GraphState> - 修饰符:
private final - 源码定位:
L53 - 说明:
TODO
- 类型:
-
nextGraphEvents- 类型:
AtomicReference<SectionOcclusionGraph.GraphEvents> - 修饰符:
private final - 源码定位:
L54 - 说明:
TODO
- 类型:
-
needsFrustumUpdate- 类型:
AtomicBoolean - 修饰符:
private final - 源码定位:
L55 - 说明:
TODO
- 类型:
内部类/嵌套类型
-
net.minecraft.client.renderer.SectionOcclusionGraph.GraphEvents- 类型:
record - 修饰符:
private - 源码定位:
L386 - 说明:
TODO
- 类型:
-
net.minecraft.client.renderer.SectionOcclusionGraph.GraphState- 类型:
record - 修饰符:
private - 源码定位:
L393 - 说明:
TODO
- 类型:
-
net.minecraft.client.renderer.SectionOcclusionGraph.GraphStorage- 类型:
class - 修饰符:
private static - 源码定位:
L400 - 说明:
TODO
- 类型:
-
net.minecraft.client.renderer.SectionOcclusionGraph.Node- 类型:
class - 修饰符:
public static - 源码定位:
L414 - 说明:
TODO
- 类型:
-
net.minecraft.client.renderer.SectionOcclusionGraph.SectionToNodeMap- 类型:
class - 修饰符:
private static - 源码定位:
L464 - 说明:
TODO
- 类型:
构造器
- 无
方法
下面的方法块按源码顺序生成。
public void waitAndReset(ViewArea viewArea) @ L57
- 方法名:waitAndReset
- 源码定位:L57
- 返回类型:void
- 修饰符:public
参数:
- viewArea: ViewArea
说明:
TODO
public void invalidate() @ L76
- 方法名:invalidate
- 源码定位:L76
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
public void addSectionsInFrustum(Frustum frustum, List<SectionRenderDispatcher.RenderSection> visibleSections, List<SectionRenderDispatcher.RenderSection> nearbyVisibleSection) @ L80
- 方法名:addSectionsInFrustum
- 源码定位:L80
- 返回类型:void
- 修饰符:public
参数:
- frustum: Frustum
- visibleSections: List<SectionRenderDispatcher.RenderSection>
- nearbyVisibleSection: List<SectionRenderDispatcher.RenderSection>
说明:
TODO
public boolean consumeFrustumUpdate() @ L94
- 方法名:consumeFrustumUpdate
- 源码定位:L94
- 返回类型:boolean
- 修饰符:public
参数:
- 无
说明:
TODO
public void onChunkReadyToRender(ChunkPos pos) @ L98
- 方法名:onChunkReadyToRender
- 源码定位:L98
- 返回类型:void
- 修饰符:public
参数:
- pos: ChunkPos
说明:
TODO
public void schedulePropagationFrom(SectionRenderDispatcher.RenderSection section) @ L110
- 方法名:schedulePropagationFrom
- 源码定位:L110
- 返回类型:void
- 修饰符:public
参数:
- section: SectionRenderDispatcher.RenderSection
说明:
TODO
public void update(boolean smartCull, Camera camera, Frustum frustum, List<SectionRenderDispatcher.RenderSection> visibleSections, LongOpenHashSet loadedEmptySections) @ L122
- 方法名:update
- 源码定位:L122
- 返回类型:void
- 修饰符:public
参数:
- smartCull: boolean
- camera: Camera
- frustum: Frustum
- visibleSections: List<SectionRenderDispatcher.RenderSection>
- loadedEmptySections: LongOpenHashSet
说明:
TODO
private void scheduleFullUpdate(boolean smartCull, Camera camera, Vec3 cameraPos, LongOpenHashSet loadedEmptySections) @ L133
- 方法名:scheduleFullUpdate
- 源码定位:L133
- 返回类型:void
- 修饰符:private
参数:
- smartCull: boolean
- camera: Camera
- cameraPos: Vec3
- loadedEmptySections: LongOpenHashSet
说明:
TODO
private void runPartialUpdate(boolean smartCull, Frustum frustum, List<SectionRenderDispatcher.RenderSection> visibleSections, Vec3 cameraPos, LongOpenHashSet loadedEmptySections) @ L149
- 方法名:runPartialUpdate
- 源码定位:L149
- 返回类型:void
- 修饰符:private
参数:
- smartCull: boolean
- frustum: Frustum
- visibleSections: List<SectionRenderDispatcher.RenderSection>
- cameraPos: Vec3
- loadedEmptySections: LongOpenHashSet
说明:
TODO
private void queueSectionsWithNewNeighbors(SectionOcclusionGraph.GraphState state) @ L175
- 方法名:queueSectionsWithNewNeighbors
- 源码定位:L175
- 返回类型:void
- 修饰符:private
参数:
- state: SectionOcclusionGraph.GraphState
说明:
TODO
private void addNeighbors(SectionOcclusionGraph.GraphEvents events, ChunkPos pos) @ L190
- 方法名:addNeighbors
- 源码定位:L190
- 返回类型:void
- 修饰符:private
参数:
- events: SectionOcclusionGraph.GraphEvents
- pos: ChunkPos
说明:
TODO
private void initializeQueueForFullUpdate(Camera camera, Queue<SectionOcclusionGraph.Node> queue) @ L201
- 方法名:initializeQueueForFullUpdate
- 源码定位:L201
- 返回类型:void
- 修饰符:private
参数:
- camera: Camera
- queue: Queue<SectionOcclusionGraph.Node>
说明:
TODO
private void runUpdates(SectionOcclusionGraph.GraphStorage storage, Vec3 cameraPos, Queue<SectionOcclusionGraph.Node> queue, boolean smartCull, Consumer<SectionRenderDispatcher.RenderSection> onSectionAdded, LongOpenHashSet emptySections) @ L247
- 方法名:runUpdates
- 源码定位:L247
- 返回类型:void
- 修饰符:private
参数:
- storage: SectionOcclusionGraph.GraphStorage
- cameraPos: Vec3
- queue: Queue<SectionOcclusionGraph.Node>
- smartCull: boolean
- onSectionAdded: Consumer<SectionRenderDispatcher.RenderSection>
- emptySections: LongOpenHashSet
说明:
TODO
private boolean isInViewDistance(long cameraSectionNode, long sectionNode) @ L353
- 方法名:isInViewDistance
- 源码定位:L353
- 返回类型:boolean
- 修饰符:private
参数:
- cameraSectionNode: long
- sectionNode: long
说明:
TODO
private SectionRenderDispatcher.RenderSection getRelativeFrom(long cameraSectionNode, SectionRenderDispatcher.RenderSection renderSection, Direction direction) @ L363
- 方法名:getRelativeFrom
- 源码定位:L363
- 返回类型:SectionRenderDispatcher.RenderSection
- 修饰符:private
参数:
- cameraSectionNode: long
- renderSection: SectionRenderDispatcher.RenderSection
- direction: Direction
说明:
TODO
public SectionOcclusionGraph.Node getNode(SectionRenderDispatcher.RenderSection section) @ L376
- 方法名:getNode
- 源码定位:L376
- 返回类型:SectionOcclusionGraph.Node
- 修饰符:public
参数:
- section: SectionRenderDispatcher.RenderSection
说明:
TODO
public Octree getOctree() @ L381
- 方法名:getOctree
- 源码定位:L381
- 返回类型:Octree
- 修饰符:public
参数:
- 无
说明:
TODO
代码
@OnlyIn(Dist.CLIENT)
public class SectionOcclusionGraph {
private static final Logger LOGGER = LogUtils.getLogger();
private static final Direction[] DIRECTIONS = Direction.values();
private static final int MINIMUM_ADVANCED_CULLING_DISTANCE = 60;
private static final int MINIMUM_ADVANCED_CULLING_SECTION_DISTANCE = SectionPos.blockToSectionCoord(60);
private static final double CEILED_SECTION_DIAGONAL = Math.ceil(Math.sqrt(3.0) * 16.0);
private boolean needsFullUpdate = true;
private @Nullable Future<?> fullUpdateTask;
private @Nullable ViewArea viewArea;
private final AtomicReference<SectionOcclusionGraph.@Nullable GraphState> currentGraph = new AtomicReference<>();
private final AtomicReference<SectionOcclusionGraph.@Nullable GraphEvents> nextGraphEvents = new AtomicReference<>();
private final AtomicBoolean needsFrustumUpdate = new AtomicBoolean(false);
public void waitAndReset(@Nullable ViewArea viewArea) {
if (this.fullUpdateTask != null) {
try {
this.fullUpdateTask.get();
this.fullUpdateTask = null;
} catch (Exception var3) {
LOGGER.warn("Full update failed", (Throwable)var3);
}
}
this.viewArea = viewArea;
if (viewArea != null) {
this.currentGraph.set(new SectionOcclusionGraph.GraphState(viewArea));
this.invalidate();
} else {
this.currentGraph.set(null);
}
}
public void invalidate() {
this.needsFullUpdate = true;
}
public void addSectionsInFrustum(
Frustum frustum, List<SectionRenderDispatcher.RenderSection> visibleSections, List<SectionRenderDispatcher.RenderSection> nearbyVisibleSection
) {
this.currentGraph.get().storage().sectionTree.visitNodes((node, fullyVisible, depth, isClose) -> {
SectionRenderDispatcher.RenderSection renderSection = node.getSection();
if (renderSection != null) {
visibleSections.add(renderSection);
if (isClose) {
nearbyVisibleSection.add(renderSection);
}
}
}, frustum, 32);
}
public boolean consumeFrustumUpdate() {
return this.needsFrustumUpdate.compareAndSet(true, false);
}
public void onChunkReadyToRender(ChunkPos pos) {
SectionOcclusionGraph.GraphEvents nextEvents = this.nextGraphEvents.get();
if (nextEvents != null) {
this.addNeighbors(nextEvents, pos);
}
SectionOcclusionGraph.GraphEvents events = this.currentGraph.get().events;
if (events != nextEvents) {
this.addNeighbors(events, pos);
}
}
public void schedulePropagationFrom(SectionRenderDispatcher.RenderSection section) {
SectionOcclusionGraph.GraphEvents nextEvents = this.nextGraphEvents.get();
if (nextEvents != null) {
nextEvents.sectionsToPropagateFrom.add(section);
}
SectionOcclusionGraph.GraphEvents events = this.currentGraph.get().events;
if (events != nextEvents) {
events.sectionsToPropagateFrom.add(section);
}
}
public void update(
boolean smartCull, Camera camera, Frustum frustum, List<SectionRenderDispatcher.RenderSection> visibleSections, LongOpenHashSet loadedEmptySections
) {
Vec3 cameraPos = camera.position();
if (this.needsFullUpdate && (this.fullUpdateTask == null || this.fullUpdateTask.isDone())) {
this.scheduleFullUpdate(smartCull, camera, cameraPos, loadedEmptySections);
}
this.runPartialUpdate(smartCull, frustum, visibleSections, cameraPos, loadedEmptySections);
}
private void scheduleFullUpdate(boolean smartCull, Camera camera, Vec3 cameraPos, LongOpenHashSet loadedEmptySections) {
this.needsFullUpdate = false;
LongOpenHashSet emptySections = loadedEmptySections.clone();
this.fullUpdateTask = CompletableFuture.runAsync(() -> {
SectionOcclusionGraph.GraphState newState = new SectionOcclusionGraph.GraphState(this.viewArea);
this.nextGraphEvents.set(newState.events);
Queue<SectionOcclusionGraph.Node> queue = Queues.newArrayDeque();
this.initializeQueueForFullUpdate(camera, queue);
queue.forEach(node -> newState.storage.sectionToNodeMap.put(node.section, node));
this.runUpdates(newState.storage, cameraPos, queue, smartCull, node -> {}, emptySections);
this.currentGraph.set(newState);
this.nextGraphEvents.set(null);
this.needsFrustumUpdate.set(true);
}, Util.backgroundExecutor());
}
private void runPartialUpdate(
boolean smartCull, Frustum frustum, List<SectionRenderDispatcher.RenderSection> visibleSections, Vec3 cameraPos, LongOpenHashSet loadedEmptySections
) {
SectionOcclusionGraph.GraphState state = this.currentGraph.get();
this.queueSectionsWithNewNeighbors(state);
if (!state.events.sectionsToPropagateFrom.isEmpty()) {
Queue<SectionOcclusionGraph.Node> queue = Queues.newArrayDeque();
while (!state.events.sectionsToPropagateFrom.isEmpty()) {
SectionRenderDispatcher.RenderSection renderSection = state.events.sectionsToPropagateFrom.poll();
SectionOcclusionGraph.Node node = state.storage.sectionToNodeMap.get(renderSection);
if (node != null && node.section == renderSection) {
queue.add(node);
}
}
Frustum offsetFrustum = LevelRenderer.offsetFrustum(frustum);
Consumer<SectionRenderDispatcher.RenderSection> onSectionAdded = section -> {
if (offsetFrustum.isVisible(section.getBoundingBox())) {
this.needsFrustumUpdate.set(true);
}
};
this.runUpdates(state.storage, cameraPos, queue, smartCull, onSectionAdded, loadedEmptySections);
}
}
private void queueSectionsWithNewNeighbors(SectionOcclusionGraph.GraphState state) {
LongIterator iterator = state.events.chunksWhichReceivedNeighbors.iterator();
while (iterator.hasNext()) {
long chunkWithNewNeighbor = iterator.nextLong();
List<SectionRenderDispatcher.RenderSection> renderSections = state.storage.chunksWaitingForNeighbors.get(chunkWithNewNeighbor);
if (renderSections != null && renderSections.get(0).hasAllNeighbors()) {
state.events.sectionsToPropagateFrom.addAll(renderSections);
state.storage.chunksWaitingForNeighbors.remove(chunkWithNewNeighbor);
}
}
state.events.chunksWhichReceivedNeighbors.clear();
}
private void addNeighbors(SectionOcclusionGraph.GraphEvents events, ChunkPos pos) {
events.chunksWhichReceivedNeighbors.add(ChunkPos.pack(pos.x() - 1, pos.z()));
events.chunksWhichReceivedNeighbors.add(ChunkPos.pack(pos.x(), pos.z() - 1));
events.chunksWhichReceivedNeighbors.add(ChunkPos.pack(pos.x() + 1, pos.z()));
events.chunksWhichReceivedNeighbors.add(ChunkPos.pack(pos.x(), pos.z() + 1));
events.chunksWhichReceivedNeighbors.add(ChunkPos.pack(pos.x() - 1, pos.z() - 1));
events.chunksWhichReceivedNeighbors.add(ChunkPos.pack(pos.x() - 1, pos.z() + 1));
events.chunksWhichReceivedNeighbors.add(ChunkPos.pack(pos.x() + 1, pos.z() - 1));
events.chunksWhichReceivedNeighbors.add(ChunkPos.pack(pos.x() + 1, pos.z() + 1));
}
private void initializeQueueForFullUpdate(Camera camera, Queue<SectionOcclusionGraph.Node> queue) {
BlockPos cameraPosition = camera.blockPosition();
long cameraSectionNode = SectionPos.asLong(cameraPosition);
int cameraSectionY = SectionPos.y(cameraSectionNode);
SectionRenderDispatcher.RenderSection cameraSection = this.viewArea.getRenderSection(cameraSectionNode);
if (cameraSection == null) {
LevelHeightAccessor heightAccessor = this.viewArea.getLevelHeightAccessor();
boolean isBelowTheWorld = cameraSectionY < heightAccessor.getMinSectionY();
int sectionY = isBelowTheWorld ? heightAccessor.getMinSectionY() : heightAccessor.getMaxSectionY();
int viewDistance = this.viewArea.getViewDistance();
List<SectionOcclusionGraph.Node> toAdd = Lists.newArrayList();
int cameraSectionX = SectionPos.x(cameraSectionNode);
int cameraSectionZ = SectionPos.z(cameraSectionNode);
for (int sectionX = -viewDistance; sectionX <= viewDistance; sectionX++) {
for (int sectionZ = -viewDistance; sectionZ <= viewDistance; sectionZ++) {
SectionRenderDispatcher.RenderSection renderSectionAt = this.viewArea
.getRenderSection(SectionPos.asLong(sectionX + cameraSectionX, sectionY, sectionZ + cameraSectionZ));
if (renderSectionAt != null && this.isInViewDistance(cameraSectionNode, renderSectionAt.getSectionNode())) {
Direction sourceDirection = isBelowTheWorld ? Direction.UP : Direction.DOWN;
SectionOcclusionGraph.Node node = new SectionOcclusionGraph.Node(renderSectionAt, sourceDirection, 0);
node.setDirections(node.directions, sourceDirection);
if (sectionX > 0) {
node.setDirections(node.directions, Direction.EAST);
} else if (sectionX < 0) {
node.setDirections(node.directions, Direction.WEST);
}
if (sectionZ > 0) {
node.setDirections(node.directions, Direction.SOUTH);
} else if (sectionZ < 0) {
node.setDirections(node.directions, Direction.NORTH);
}
toAdd.add(node);
}
}
}
toAdd.sort(Comparator.comparingDouble(c -> cameraPosition.distSqr(SectionPos.of(c.section.getSectionNode()).center())));
queue.addAll(toAdd);
} else {
queue.add(new SectionOcclusionGraph.Node(cameraSection, null, 0));
}
}
private void runUpdates(
SectionOcclusionGraph.GraphStorage storage,
Vec3 cameraPos,
Queue<SectionOcclusionGraph.Node> queue,
boolean smartCull,
Consumer<SectionRenderDispatcher.RenderSection> onSectionAdded,
LongOpenHashSet emptySections
) {
SectionPos cameraSectionPos = SectionPos.of(cameraPos);
long cameraSectionNode = cameraSectionPos.asLong();
BlockPos cameraSectionCenter = cameraSectionPos.center();
while (!queue.isEmpty()) {
SectionOcclusionGraph.Node node = queue.poll();
SectionRenderDispatcher.RenderSection currentSection = node.section;
if (!emptySections.contains(node.section.getSectionNode())) {
if (storage.sectionTree.add(node.section)) {
onSectionAdded.accept(node.section);
}
} else {
node.section.sectionMesh.compareAndSet(CompiledSectionMesh.UNCOMPILED, CompiledSectionMesh.EMPTY);
}
long sectionNode = currentSection.getSectionNode();
boolean distantFromCamera = Math.abs(SectionPos.x(sectionNode) - cameraSectionPos.x()) > MINIMUM_ADVANCED_CULLING_SECTION_DISTANCE
|| Math.abs(SectionPos.y(sectionNode) - cameraSectionPos.y()) > MINIMUM_ADVANCED_CULLING_SECTION_DISTANCE
|| Math.abs(SectionPos.z(sectionNode) - cameraSectionPos.z()) > MINIMUM_ADVANCED_CULLING_SECTION_DISTANCE;
for (Direction direction : DIRECTIONS) {
SectionRenderDispatcher.RenderSection renderSectionAt = this.getRelativeFrom(cameraSectionNode, currentSection, direction);
if (renderSectionAt != null && (!smartCull || !node.hasDirection(direction.getOpposite()))) {
if (smartCull && node.hasSourceDirections()) {
SectionMesh sectionMesh = currentSection.getSectionMesh();
boolean visible = false;
for (int i = 0; i < DIRECTIONS.length; i++) {
if (node.hasSourceDirection(i) && sectionMesh.facesCanSeeEachother(DIRECTIONS[i].getOpposite(), direction)) {
visible = true;
break;
}
}
if (!visible) {
continue;
}
}
if (smartCull && distantFromCamera) {
int renderSectionOriginX = SectionPos.sectionToBlockCoord(SectionPos.x(sectionNode));
int renderSectionOriginY = SectionPos.sectionToBlockCoord(SectionPos.y(sectionNode));
int renderSectionOriginZ = SectionPos.sectionToBlockCoord(SectionPos.z(sectionNode));
boolean maxX = direction.getAxis() == Direction.Axis.X
? cameraSectionCenter.getX() > renderSectionOriginX
: cameraSectionCenter.getX() < renderSectionOriginX;
boolean maxY = direction.getAxis() == Direction.Axis.Y
? cameraSectionCenter.getY() > renderSectionOriginY
: cameraSectionCenter.getY() < renderSectionOriginY;
boolean maxZ = direction.getAxis() == Direction.Axis.Z
? cameraSectionCenter.getZ() > renderSectionOriginZ
: cameraSectionCenter.getZ() < renderSectionOriginZ;
Vector3d checkPos = new Vector3d(
renderSectionOriginX + (maxX ? 16 : 0), renderSectionOriginY + (maxY ? 16 : 0), renderSectionOriginZ + (maxZ ? 16 : 0)
);
Vector3d step = new Vector3d(cameraPos.x, cameraPos.y, cameraPos.z).sub(checkPos).normalize().mul(CEILED_SECTION_DIAGONAL);
boolean visible = true;
while (checkPos.distanceSquared(cameraPos.x, cameraPos.y, cameraPos.z) > 3600.0) {
checkPos.add(step);
LevelHeightAccessor heightAccessor = this.viewArea.getLevelHeightAccessor();
if (checkPos.y > heightAccessor.getMaxY() || checkPos.y < heightAccessor.getMinY()) {
break;
}
SectionRenderDispatcher.RenderSection checkSection = this.viewArea
.getRenderSectionAt(BlockPos.containing(checkPos.x, checkPos.y, checkPos.z));
if (checkSection == null || storage.sectionToNodeMap.get(checkSection) == null) {
visible = false;
break;
}
}
if (!visible) {
continue;
}
}
SectionOcclusionGraph.Node existingNode = storage.sectionToNodeMap.get(renderSectionAt);
if (existingNode != null) {
existingNode.addSourceDirection(direction);
} else {
SectionOcclusionGraph.Node newNode = new SectionOcclusionGraph.Node(renderSectionAt, direction, node.step + 1);
newNode.setDirections(node.directions, direction);
if (renderSectionAt.hasAllNeighbors()) {
queue.add(newNode);
storage.sectionToNodeMap.put(renderSectionAt, newNode);
} else if (this.isInViewDistance(cameraSectionNode, renderSectionAt.getSectionNode())) {
storage.sectionToNodeMap.put(renderSectionAt, newNode);
long chunkNode = SectionPos.sectionToChunk(renderSectionAt.getSectionNode());
storage.chunksWaitingForNeighbors.computeIfAbsent(chunkNode, l -> new ArrayList<>()).add(renderSectionAt);
}
}
}
}
}
}
private boolean isInViewDistance(long cameraSectionNode, long sectionNode) {
return ChunkTrackingView.isInViewDistance(
SectionPos.x(cameraSectionNode),
SectionPos.z(cameraSectionNode),
this.viewArea.getViewDistance(),
SectionPos.x(sectionNode),
SectionPos.z(sectionNode)
);
}
private SectionRenderDispatcher.@Nullable RenderSection getRelativeFrom(
long cameraSectionNode, SectionRenderDispatcher.RenderSection renderSection, Direction direction
) {
long relative = renderSection.getNeighborSectionNode(direction);
if (!this.isInViewDistance(cameraSectionNode, relative)) {
return null;
} else {
return Mth.abs(SectionPos.y(cameraSectionNode) - SectionPos.y(relative)) > this.viewArea.getViewDistance()
? null
: this.viewArea.getRenderSection(relative);
}
}
@VisibleForDebug
public SectionOcclusionGraph.@Nullable Node getNode(SectionRenderDispatcher.RenderSection section) {
return this.currentGraph.get().storage.sectionToNodeMap.get(section);
}
public Octree getOctree() {
return this.currentGraph.get().storage.sectionTree;
}
@OnlyIn(Dist.CLIENT)
private record GraphEvents(LongSet chunksWhichReceivedNeighbors, BlockingQueue<SectionRenderDispatcher.RenderSection> sectionsToPropagateFrom) {
private GraphEvents() {
this(new LongOpenHashSet(), new LinkedBlockingQueue<>());
}
}
@OnlyIn(Dist.CLIENT)
private record GraphState(SectionOcclusionGraph.GraphStorage storage, SectionOcclusionGraph.GraphEvents events) {
private GraphState(ViewArea viewArea) {
this(new SectionOcclusionGraph.GraphStorage(viewArea), new SectionOcclusionGraph.GraphEvents());
}
}
@OnlyIn(Dist.CLIENT)
private static class GraphStorage {
public final SectionOcclusionGraph.SectionToNodeMap sectionToNodeMap;
public final Octree sectionTree;
public final Long2ObjectMap<List<SectionRenderDispatcher.RenderSection>> chunksWaitingForNeighbors;
public GraphStorage(ViewArea viewArea) {
this.sectionToNodeMap = new SectionOcclusionGraph.SectionToNodeMap(viewArea.sections.length);
this.sectionTree = new Octree(viewArea.getCameraSectionPos(), viewArea.getViewDistance(), viewArea.sectionGridSizeY, viewArea.level.getMinY());
this.chunksWaitingForNeighbors = new Long2ObjectOpenHashMap<>();
}
}
@OnlyIn(Dist.CLIENT)
@VisibleForDebug
public static class Node {
@VisibleForDebug
protected final SectionRenderDispatcher.RenderSection section;
private byte sourceDirections;
private byte directions;
@VisibleForDebug
public final int step;
private Node(SectionRenderDispatcher.RenderSection section, @Nullable Direction sourceDirection, int step) {
this.section = section;
if (sourceDirection != null) {
this.addSourceDirection(sourceDirection);
}
this.step = step;
}
private void setDirections(byte oldDirections, Direction direction) {
this.directions = (byte)(this.directions | oldDirections | 1 << direction.ordinal());
}
private boolean hasDirection(Direction direction) {
return (this.directions & 1 << direction.ordinal()) > 0;
}
private void addSourceDirection(Direction direction) {
this.sourceDirections = (byte)(this.sourceDirections | this.sourceDirections | 1 << direction.ordinal());
}
@VisibleForDebug
public boolean hasSourceDirection(int directionOrdinal) {
return (this.sourceDirections & 1 << directionOrdinal) > 0;
}
private boolean hasSourceDirections() {
return this.sourceDirections != 0;
}
@Override
public int hashCode() {
return Long.hashCode(this.section.getSectionNode());
}
@Override
public boolean equals(Object obj) {
return !(obj instanceof SectionOcclusionGraph.Node other) ? false : this.section.getSectionNode() == other.section.getSectionNode();
}
}
@OnlyIn(Dist.CLIENT)
private static class SectionToNodeMap {
private final SectionOcclusionGraph.Node[] nodes;
private SectionToNodeMap(int sectionCount) {
this.nodes = new SectionOcclusionGraph.Node[sectionCount];
}
public void put(SectionRenderDispatcher.RenderSection renderSection, SectionOcclusionGraph.Node node) {
this.nodes[renderSection.index] = node;
}
public SectionOcclusionGraph.@Nullable Node get(SectionRenderDispatcher.RenderSection renderSection) {
int index = renderSection.index;
return index >= 0 && index < this.nodes.length ? this.nodes[index] : null;
}
}
}引用的其他类
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
LevelRenderer.offsetFrustum()
- 引用位置:
-
- 引用位置:
构造调用/返回值 - 关联成员:
Octree()
- 引用位置:
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
参数/返回值
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
BlockPos.containing()
- 引用位置:
-
- 引用位置:
参数/字段/方法调用 - 关联成员:
Direction.values()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
SectionPos.asLong(), SectionPos.blockToSectionCoord(), SectionPos.of(), SectionPos.sectionToBlockCoord(), SectionPos.sectionToChunk(), SectionPos.x(), SectionPos.y(), SectionPos.z()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
ChunkTrackingView.isInViewDistance()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Mth.abs()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Util.backgroundExecutor()
- 引用位置:
-
- 引用位置:
参数/方法调用 - 关联成员:
ChunkPos.pack()
- 引用位置:
-
- 引用位置:
参数
- 引用位置: