Skip to content

Commit

Permalink
Replace chunk tracker (#661)
Browse files Browse the repository at this point in the history
* Replace chunk tracker

---------

Co-authored-by: Jason Mitchell <mitchej@gmail.com>
  • Loading branch information
embeddedt and mitchej123 authored Oct 16, 2024
1 parent 9e1fa7b commit 8c5f4d2
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 38 deletions.
3 changes: 1 addition & 2 deletions src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,7 @@ public enum Mixins {

SODIUM(new Builder("Sodium").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT)
.setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableSodium).addMixinClasses(
"sodium.MixinChunkProviderClient"
,"sodium.MixinBlock"
"sodium.MixinBlock"
,"sodium.MixinBlockFluidBase"
,"sodium.AccessorBiomeColorEvent"
,"sodium.MixinBiomeGenBase"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import me.jellysquid.mods.sodium.client.render.chunk.backends.oneshot.ChunkRenderBackendOneshot;
import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData;
import me.jellysquid.mods.sodium.client.render.chunk.format.DefaultModelVertexFormats;
import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkTracker;
import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkTrackerHolder;
import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass;
import me.jellysquid.mods.sodium.client.render.pipeline.context.ChunkRenderCacheShared;
import me.jellysquid.mods.sodium.client.util.math.FrustumExtended;
Expand Down Expand Up @@ -59,7 +61,7 @@
/**
* Provides an extension to vanilla's {@link WorldRenderer}.
*/
public class SodiumWorldRenderer implements ChunkStatusListener {
public class SodiumWorldRenderer {
private static SodiumWorldRenderer instance;

private final Minecraft client;
Expand Down Expand Up @@ -155,7 +157,6 @@ private void unloadWorld() {
this.chunkRenderBackend = null;
}

this.loadedChunkPositions.clear();
this.globalTileEntities.clear();

this.world = null;
Expand Down Expand Up @@ -194,6 +195,8 @@ public boolean isTerrainRenderComplete() {
public void updateChunks(Camera camera, Frustrum frustum, boolean hasForcedFrustum, int frame, boolean spectator) {
this.frustum = frustum;

this.processChunkEvents();

this.useEntityCulling = SodiumClientMod.options().advanced.useEntityCulling;

if (this.client.gameSettings.renderDistanceChunks != this.renderDistance) {
Expand Down Expand Up @@ -265,6 +268,11 @@ public void updateChunks(Camera camera, Frustrum frustum, boolean hasForcedFrust
}
}

private void processChunkEvents() {
var tracker = ChunkTrackerHolder.get(this.world);
tracker.forEachEvent(this.chunkRenderManager::onChunkAdded, this.chunkRenderManager::onChunkRemoved);
}

/**
* Performs a render pass for the given {@link RenderLayer} and draws all visible chunks for it.
*/
Expand Down Expand Up @@ -324,7 +332,9 @@ private void initRenderer() {
this.chunkRenderBackend.createShaders(device);

this.chunkRenderManager = new ChunkRenderManager<>(this, this.chunkRenderBackend, this.world, this.renderDistance);
this.chunkRenderManager.restoreChunks(this.loadedChunkPositions);

var tracker = ChunkTrackerHolder.get(this.world);
ChunkTracker.forEachChunk(tracker.getReadyChunks(), this.chunkRenderManager::onChunkAdded);
}

private static ChunkRenderBackend<?> createChunkRenderBackend(RenderDevice device, SodiumGameOptions options, ChunkVertexType vertexFormat) {
Expand Down Expand Up @@ -379,18 +389,6 @@ public void renderTileEntities(EntityLivingBase entity, ICamera camera, float pa
}
}

@Override
public void onChunkAdded(int x, int z) {
this.loadedChunkPositions.add(ChunkPos.toLong(x, z));
this.chunkRenderManager.onChunkAdded(x, z);
}

@Override
public void onChunkRemoved(int x, int z) {
this.loadedChunkPositions.remove(ChunkPos.toLong(x, z));
this.chunkRenderManager.onChunkRemoved(x, z);
}

public void onChunkRenderUpdated(int x, int y, int z, ChunkRenderData meshBefore, ChunkRenderData meshAfter) {
ListUtil.updateList(this.globalTileEntities, meshBefore.getGlobalTileEntities(), meshAfter.getGlobalTileEntities());

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package me.jellysquid.mods.sodium.client.render.chunk.map;

public class ChunkStatus {
public static final int FLAG_HAS_BLOCK_DATA = 1;
public static final int FLAG_HAS_LIGHT_DATA = 2;
public static final int FLAG_ALL = FLAG_HAS_BLOCK_DATA | FLAG_HAS_LIGHT_DATA;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package me.jellysquid.mods.sodium.client.render.chunk.map;

import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongCollection;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import it.unimi.dsi.fastutil.longs.LongSet;
import it.unimi.dsi.fastutil.longs.LongSets;
import net.minecraft.world.ChunkCoordIntPair;

public class ChunkTracker implements ClientChunkEventListener {
private final Long2IntOpenHashMap chunkStatus = new Long2IntOpenHashMap();
private final LongOpenHashSet chunkReady = new LongOpenHashSet();

private final LongSet unloadQueue = new LongOpenHashSet();
private final LongSet loadQueue = new LongOpenHashSet();

public ChunkTracker() {

}

@Override
public void updateMapCenter(int chunkX, int chunkZ) {

}

@Override
public void updateLoadDistance(int loadDistance) {

}

@Override
public void onChunkStatusAdded(int x, int z, int flags) {
var key = ChunkCoordIntPair.chunkXZ2Int(x, z);

var prev = this.chunkStatus.get(key);
var cur = prev | flags;

if (prev == cur) {
return;
}

this.chunkStatus.put(key, cur);

this.updateNeighbors(x, z);
}

@Override
public void onChunkStatusRemoved(int x, int z, int flags) {
var key = ChunkCoordIntPair.chunkXZ2Int(x, z);

var prev = this.chunkStatus.get(key);
int cur = prev & ~flags;

if (prev == cur) {
return;
}

if (cur == this.chunkStatus.defaultReturnValue()) {
this.chunkStatus.remove(key);
} else {
this.chunkStatus.put(key, cur);
}

this.updateNeighbors(x, z);
}

private void updateNeighbors(int x, int z) {
for (int ox = -1; ox <= 1; ox++) {
for (int oz = -1; oz <= 1; oz++) {
this.updateMerged(ox + x, oz + z);
}
}
}

private void updateMerged(int x, int z) {
long key = ChunkCoordIntPair.chunkXZ2Int(x, z);

int flags = this.chunkStatus.get(key);

for (int ox = -1; ox <= 1; ox++) {
for (int oz = -1; oz <= 1; oz++) {
flags &= this.chunkStatus.get(ChunkCoordIntPair.chunkXZ2Int(ox + x, oz + z));
}
}

if (flags == ChunkStatus.FLAG_ALL) {
if (this.chunkReady.add(key) && !this.unloadQueue.remove(key)) {
this.loadQueue.add(key);
}
} else {
if (this.chunkReady.remove(key) && !this.loadQueue.remove(key)) {
this.unloadQueue.add(key);
}
}
}

public LongCollection getReadyChunks() {
return LongSets.unmodifiable(this.chunkReady);
}

public void forEachEvent(ChunkEventHandler loadEventHandler, ChunkEventHandler unloadEventHandler) {
forEachChunk(this.unloadQueue, unloadEventHandler);
this.unloadQueue.clear();

forEachChunk(this.loadQueue, loadEventHandler);
this.loadQueue.clear();
}

public static void forEachChunk(LongCollection queue, ChunkEventHandler handler) {
var iterator = queue.iterator();

while (iterator.hasNext()) {
var pos = iterator.nextLong();

var x = (int)(pos & 4294967295L);
var z = (int)((pos >> 32L) & 4294967295L);

handler.apply(x, z);
}
}

public interface ChunkEventHandler {
void apply(int x, int z);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package me.jellysquid.mods.sodium.client.render.chunk.map;

import net.minecraft.client.multiplayer.WorldClient;

public interface ChunkTrackerHolder {
static ChunkTracker get(WorldClient world) {
return ((ChunkTrackerHolder) world).sodium$getTracker();
}

ChunkTracker sodium$getTracker();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package me.jellysquid.mods.sodium.client.render.chunk.map;

public interface ClientChunkEventListener {
void updateMapCenter(int chunkX, int chunkZ);

void updateLoadDistance(int loadDistance);

void onChunkStatusAdded(int x, int z, int flags);
void onChunkStatusRemoved(int x, int z, int flags);
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
package com.gtnewhorizons.angelica.mixins.early.sodium;

import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer;
import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkStatus;
import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkTracker;
import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkTrackerHolder;
import net.minecraft.client.multiplayer.WorldClient;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin(WorldClient.class)
public class MixinWorldClient {
public class MixinWorldClient implements ChunkTrackerHolder {
private final ChunkTracker angelica$tracker = new ChunkTracker();

@Inject(method = "doPreChunk", at = @At("TAIL"))
private void sodium$loadChunk(int x, int z, boolean load, CallbackInfo ci) {
if(load)
SodiumWorldRenderer.getInstance().onChunkAdded(x, z);
if(load) {
this.angelica$tracker.onChunkStatusAdded(x, z, ChunkStatus.FLAG_ALL);
} else {
this.angelica$tracker.onChunkStatusRemoved(x, z, ChunkStatus.FLAG_ALL);
}
}

@Override
public ChunkTracker sodium$getTracker() {
return this.angelica$tracker;
}
}

0 comments on commit 8c5f4d2

Please sign in to comment.