Skip to content

Commit

Permalink
Update to Sodium 0.5
Browse files Browse the repository at this point in the history
  • Loading branch information
Johni0702 committed Aug 13, 2023
1 parent 4483298 commit 8509a82
Show file tree
Hide file tree
Showing 11 changed files with 34 additions and 154 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
### 5.0.1-SNAPSHOT
- Update to Sodium 0.5

### 5.0.0
- Update to Minecraft 1.20.1
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ org.gradle.jvmargs=-Xmx2G
confabricateVersion = 2.1.0
clothConfigVersion = 11.0.99
modMenuVersion = 7.0.1
sodiumVersion = mc1.20-0.4.10
sodiumVersion = mc1.20.1-0.5.0
starlightVersion = 1.1.2+1.20
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ public boolean unload(int x, int z, boolean willBeReplaced) {
}
}

clientChunkManagerExt.bobby_onFakeChunkRemoved(x, z);
clientChunkManagerExt.bobby_onFakeChunkRemoved(x, z, willBeReplaced);

return true;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,9 @@
package de.johni0702.minecraft.bobby.ext;

import de.johni0702.minecraft.bobby.FakeChunkManager;
import de.johni0702.minecraft.bobby.sodium.ChunkStatusListener;

public interface ClientChunkManagerExt {
FakeChunkManager bobby_getFakeChunkManager();
void bobby_onFakeChunkAdded(int x, int z);
void bobby_onFakeChunkRemoved(int x, int z);

/**
* Mark Sodium's {@link ChunkStatusListener} as paused.
* This effectively delays all unload notifications until un-paused and most importantly removes redundant (as in
* unload followed by a load) ones. Otherwise Sodium will unload the geometry and the chunk will be missing until
* it is rebuilt.
*
* Has no effect on the vanilla renderer because it polls chunks every frame and gets no intermediate state.
*
* This method is idempotent.
*/
void bobby_pauseChunkStatusListener();

/**
* Resumes Sodium's {@link ChunkStatusListener}, forwarding all updates which are still applicable.
*/
void bobby_resumeChunkStatusListener();
void bobby_onFakeChunkRemoved(int x, int z, boolean willBeReplaced);
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,23 +82,11 @@ private void bobbyUnloadFakeChunk(int x, int z, PacketByteBuf buf, NbtCompound n
return;
}

bobby_pauseChunkStatusListener();

// This needs to be called unconditionally because even if there is no chunk loaded at the moment,
// we might already have one queued which we need to cancel as otherwise it will overwrite the real one later.
bobbyChunkManager.unload(x, z, true);
}

@Inject(method = "loadChunkFromPacket", at = @At("RETURN"))
private void bobbyPostLoadRealChunk(int x, int z, PacketByteBuf buf, NbtCompound nbt, Consumer<ChunkData.BlockEntityVisitor> consumer, CallbackInfoReturnable<WorldChunk> cir) {
// Sodium moved this into the ClientPlayNetworkHandler, but I'd rather not move all our stuff there.
// It looks like it's supposed to be idempotent (and ran even when the chunk fails to parse), so we'll just call
// it here as well and thereby cancel out the above unload.
bobby_onFakeChunkAdded(x, z);

bobby_resumeChunkStatusListener();
}

@Unique
private void saveRealChunk(long chunkPos) {
int chunkX = ChunkPos.getPackedX(chunkPos);
Expand All @@ -113,8 +101,6 @@ private void saveRealChunk(long chunkPos) {

if (bobbyChunkManager.shouldBeLoaded(chunkX, chunkZ)) {
bobbyChunkReplacements.add(Pair.of(chunkPos, copy));

bobby_pauseChunkStatusListener();
}
}

Expand All @@ -127,8 +113,6 @@ private void substituteFakeChunksForUnloadedRealOnes() {
bobbyChunkManager.load(chunkX, chunkZ, entry.getValue().get());
}
bobbyChunkReplacements.clear();

bobby_resumeChunkStatusListener();
}

@Inject(method = "unload", at = @At("HEAD"))
Expand Down Expand Up @@ -182,17 +166,7 @@ public void bobby_onFakeChunkAdded(int x, int z) {
}

@Override
public void bobby_onFakeChunkRemoved(int x, int z) {
// Vanilla polls for chunks each frame, this is only of interest for Sodium (see SodiumChunkManagerMixin)
}

@Override
public void bobby_pauseChunkStatusListener() {
// Vanilla polls for chunks each frame, this is only of interest for Sodium (see SodiumChunkManagerMixin)
}

@Override
public void bobby_resumeChunkStatusListener() {
public void bobby_onFakeChunkRemoved(int x, int z, boolean willBeReplaced) {
// Vanilla polls for chunks each frame, this is only of interest for Sodium (see SodiumChunkManagerMixin)
}
}
Original file line number Diff line number Diff line change
@@ -1,55 +1,33 @@
package de.johni0702.minecraft.bobby.mixin.sodium;

import de.johni0702.minecraft.bobby.ext.ClientChunkManagerExt;
import de.johni0702.minecraft.bobby.sodium.BufferedChunkStatusListener;
import de.johni0702.minecraft.bobby.sodium.ChunkStatusListener;
import de.johni0702.minecraft.bobby.sodium.SodiumChunkStatusListenerImpl;
import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkStatus;
import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkTrackerHolder;
import net.minecraft.client.world.ClientChunkManager;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.util.math.ChunkSectionPos;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;

@Mixin(value = ClientChunkManager.class, priority = 1010) // higher than our normal one
public abstract class SodiumChunkManagerMixin implements ClientChunkManagerExt {
@Unique
private ChunkStatusListener listener = new SodiumChunkStatusListenerImpl();
private final ClientWorld world;

@Unique
private BufferedChunkStatusListener bufferedListener;

@Override
public void bobby_onFakeChunkAdded(int x, int z) {
if (this.listener != null) {
this.listener.onChunkAdded(x, z);
}
}

@Override
public void bobby_onFakeChunkRemoved(int x, int z) {
if (this.listener != null) {
this.listener.onChunkRemoved(x, z);
}
protected SodiumChunkManagerMixin(ClientWorld world) {
this.world = world;
}

@Override
public void bobby_pauseChunkStatusListener() {
if (this.listener == this.bufferedListener) {
return;
}

if (this.bufferedListener == null || this.bufferedListener.delegate != this.listener) {
this.bufferedListener = new BufferedChunkStatusListener(this.listener);
}

this.listener = this.bufferedListener;
public void bobby_onFakeChunkAdded(int x, int z) {
// Fake chunks always have light data included, so we use ALL rather than just HAS_BLOCK_DATA
ChunkTrackerHolder.get(world).onChunkStatusAdded(x, z, ChunkStatus.FLAG_ALL);
}

@Override
public void bobby_resumeChunkStatusListener() {
if (this.listener != this.bufferedListener) {
return;
}

this.bufferedListener.flush();
this.listener = this.bufferedListener.delegate;
public void bobby_onFakeChunkRemoved(int x, int z, boolean willBeReplaced) {
// If we know the chunk will be replaced by a real one, then we can pretend like light data is already
// available, otherwise Sodium will unload the chunk for a few frames until MC's delayed light update gets
// around to actually inserting the real light.
boolean stillHasLight = willBeReplaced || world.getLightingProvider().isLightingEnabled(ChunkSectionPos.from(x, 0, z));
ChunkTrackerHolder.get(world).onChunkStatusRemoved(x, z, stillHasLight ? ChunkStatus.FLAG_HAS_BLOCK_DATA : ChunkStatus.FLAG_ALL);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,22 @@
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin(value = ClientPlayNetworkHandler.class, priority = 900) // lower than Sodium so we get to return before it runs
public abstract class SodiumClientPlayNetworkHandlerMixin implements ClientChunkManagerExt {
@Mixin(value = ClientPlayNetworkHandler.class, priority = 1100) // higher than Sodium so we get to run after it runs
public abstract class SodiumClientPlayNetworkHandlerMixin {
@Shadow
private ClientWorld world;

@Inject(method = "onUnloadChunk", at = @At("RETURN"), cancellable = true)
private void returnEarlyIfReplacedByFakeChunk(UnloadChunkS2CPacket packet, CallbackInfo ci) {
WorldChunk chunk = this.world.getChunk(packet.getX(), packet.getZ());
@Inject(method = "onUnloadChunk", at = @At("RETURN"))
private void keepChunkRenderedIfReplacedByFakeChunk(UnloadChunkS2CPacket packet, CallbackInfo ci) {
int x = packet.getX();
int z = packet.getZ();
WorldChunk chunk = this.world.getChunk(x, z);
// Sodium removes the block and light flags from the unloaded chunk at the end of this method.
// We however load our fake chunk at the end of the unload method in ClientChunkManager, so Sodium naturally
// would get the last word and un-render the chunk. To prevent that, when we have replaced it with a fake chunk,
// we simply re-add the flags.
if (chunk instanceof FakeChunk) {
ci.cancel(); // bypass Sodium's unload hook
((ClientChunkManagerExt) world.getChunkManager()).bobby_onFakeChunkAdded(x, z);
}
}
}

This file was deleted.

This file was deleted.

This file was deleted.

2 changes: 1 addition & 1 deletion src/main/resources/fabric.mod.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"modmenu": "^${modMenuVersion}"
},
"breaks": {
"sodium": "<0.3.0"
"sodium": "<0.5.1"
},

"custom": {
Expand Down

0 comments on commit 8509a82

Please sign in to comment.