Skip to content

Commit

Permalink
Bypass lighting engine for fake chunks
Browse files Browse the repository at this point in the history
The vanilla lighting engine has horrible bulk chunk load/unload performance, but
we do not even need it because we do not need to update any light in any of the
fake chunks, so this commit completely bypasses it for fake chunks.
Thereby massively reducing main thread load on fake chunk load/unload.

Also fixes any lighting issues present in the current implementation (cause we
no longer do any lighting updates!).
  • Loading branch information
Johni0702 committed Mar 14, 2021
1 parent 143dbf9 commit c059a62
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 61 deletions.
39 changes: 15 additions & 24 deletions src/main/java/de/johni0702/minecraft/bobby/FakeChunkManager.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package de.johni0702.minecraft.bobby;

import de.johni0702.minecraft.bobby.ext.ChunkLightProviderExt;
import de.johni0702.minecraft.bobby.mixin.BiomeAccessAccessor;
import de.johni0702.minecraft.bobby.mixin.LightingProviderAccessor;
import de.johni0702.minecraft.bobby.mixin.sodium.SodiumChunkManagerAccessor;
import io.netty.util.concurrent.DefaultThreadFactory;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
Expand Down Expand Up @@ -40,10 +42,8 @@
import net.minecraft.world.SaveProperties;
import net.minecraft.world.World;
import net.minecraft.world.biome.source.BiomeSource;
import net.minecraft.world.chunk.ChunkSection;
import net.minecraft.world.chunk.ChunkStatus;
import net.minecraft.world.chunk.WorldChunk;
import net.minecraft.world.chunk.light.LightingProvider;
import net.minecraft.world.level.storage.LevelStorage;
import org.jetbrains.annotations.Nullable;

Expand Down Expand Up @@ -242,20 +242,8 @@ public void load(int x, int z, CompoundTag tag, FakeChunkStorage storage) {
}

protected void load(int x, int z, WorldChunk chunk) {
ChunkPos chunkPos = new ChunkPos(x, z);

fakeChunks.put(ChunkPos.toLong(x, z), chunk);

LightingProvider lightingProvider = clientChunkManager.getLightingProvider();
lightingProvider.setColumnEnabled(chunkPos, true);
lightingProvider.setRetainData(chunkPos, false);

int y = 0;
for (ChunkSection section : chunk.getSectionArray()) {
lightingProvider.setSectionStatus(ChunkSectionPos.from(x, y, z), ChunkSection.isEmpty(section));
y++;
}

world.resetChunkColor(x, z);

for (int i = 0; i < 16; i++) {
Expand All @@ -266,18 +254,21 @@ protected void load(int x, int z, WorldChunk chunk) {
public void unload(int x, int z, boolean willBeReplaced) {
cancelLoad(x, z);
WorldChunk chunk = fakeChunks.remove(ChunkPos.toLong(x, z));
if (chunk != null && !willBeReplaced) {
LightingProvider lightingProvider = clientChunkManager.getLightingProvider();

for (int y = 0; y < 16; y++) {
world.scheduleBlockRenders(x, y, z);
lightingProvider.setSectionStatus(ChunkSectionPos.from(x, y, z), true);
if (chunk != null) {
LightingProviderAccessor lightingProvider = (LightingProviderAccessor) clientChunkManager.getLightingProvider();
ChunkLightProviderExt blockLightProvider = (ChunkLightProviderExt) lightingProvider.getBlockLightProvider();
ChunkLightProviderExt skyLightProvider = (ChunkLightProviderExt) lightingProvider.getSkyLightProvider();
for (int y = 0; y < chunk.getSectionArray().length; y++) {
if (blockLightProvider != null) {
blockLightProvider.bobby_removeSectionData(ChunkSectionPos.asLong(x, y, z));
}
if (skyLightProvider != null) {
skyLightProvider.bobby_removeSectionData(ChunkSectionPos.asLong(x, y, z));
}
}

lightingProvider.setColumnEnabled(new ChunkPos(x, z), false);
}
if (chunk != null) {
world.unloadBlockEntities(chunk);
world.blockEntities.removeAll(chunk.getBlockEntities().values());
world.tickingBlockEntities.removeAll(chunk.getBlockEntities().values());
}
}

Expand Down
19 changes: 11 additions & 8 deletions src/main/java/de/johni0702/minecraft/bobby/FakeChunkStorage.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package de.johni0702.minecraft.bobby;

import de.johni0702.minecraft.bobby.ext.ChunkLightProviderExt;
import de.johni0702.minecraft.bobby.mixin.LightingProviderAccessor;
import net.minecraft.SharedConstants;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.world.DummyClientTickScheduler;
Expand Down Expand Up @@ -218,21 +220,22 @@ public CompoundTag serialize(Chunk chunk, LightingProvider lightingProvider) {
return () -> {
boolean hasSkyLight = world.getDimension().hasSkyLight();
ChunkManager chunkManager = world.getChunkManager();
LightingProvider lightingProvider = chunkManager.getLightingProvider();
lightingProvider.setRetainData(pos, true);
LightingProviderAccessor lightingProvider = (LightingProviderAccessor) chunkManager.getLightingProvider();
ChunkLightProviderExt blockLightProvider = (ChunkLightProviderExt) lightingProvider.getBlockLightProvider();
ChunkLightProviderExt skyLightProvider = (ChunkLightProviderExt) lightingProvider.getSkyLightProvider();

for (int i = 0; i < sectionsTag.size(); i++) {
CompoundTag sectionTag = sectionsTag.getCompound(i);
int y = sectionTag.getByte("Y");

if (sectionTag.contains("BlockLight", 7)) {
lightingProvider.enqueueSectionData(LightType.BLOCK, ChunkSectionPos.from(pos, y),
new ChunkNibbleArray(sectionTag.getByteArray("BlockLight")), true);
if (sectionTag.contains("BlockLight", 7) && blockLightProvider != null) {
blockLightProvider.bobby_addSectionData(ChunkSectionPos.from(pos, y).asLong(),
new ChunkNibbleArray(sectionTag.getByteArray("BlockLight")));
}

if (hasSkyLight && sectionTag.contains("SkyLight", 7)) {
lightingProvider.enqueueSectionData(LightType.SKY, ChunkSectionPos.from(pos, y),
new ChunkNibbleArray(sectionTag.getByteArray("SkyLight")), true);
if (hasSkyLight && sectionTag.contains("SkyLight", 7) && skyLightProvider != null) {
skyLightProvider.bobby_addSectionData(ChunkSectionPos.from(pos, y).asLong(),
new ChunkNibbleArray(sectionTag.getByteArray("SkyLight")));
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package de.johni0702.minecraft.bobby.ext;

import net.minecraft.world.chunk.ChunkNibbleArray;

public interface ChunkLightProviderExt {
void bobby_addSectionData(long pos, ChunkNibbleArray data);
void bobby_removeSectionData(long pos);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package de.johni0702.minecraft.bobby.mixin;

import de.johni0702.minecraft.bobby.ext.ChunkLightProviderExt;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkSectionPos;
import net.minecraft.world.chunk.ChunkNibbleArray;
import net.minecraft.world.chunk.light.ChunkLightProvider;
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.CallbackInfoReturnable;

@Mixin(ChunkLightProvider.class)
public abstract class ChunkLightProviderMixin implements ChunkLightProviderExt {
private final Long2ObjectMap<ChunkNibbleArray> bobbySectionData = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>());

@Override
public void bobby_addSectionData(long pos, ChunkNibbleArray data) {
this.bobbySectionData.put(pos, data);
}

@Override
public void bobby_removeSectionData(long pos) {
this.bobbySectionData.remove(pos);
}

@Inject(method = "getLightSection", at = @At("HEAD"), cancellable = true)
private void bobby_getLightSection(ChunkSectionPos pos, CallbackInfoReturnable<ChunkNibbleArray> ci) {
ChunkNibbleArray data = this.bobbySectionData.get(pos.asLong());
if (data != null) {
ci.setReturnValue(data);
}
}

@Inject(method = "getLightLevel", at = @At("HEAD"), cancellable = true)
private void bobby_getLightSection(BlockPos blockPos, CallbackInfoReturnable<Integer> ci) {
ChunkNibbleArray data = this.bobbySectionData.get(ChunkSectionPos.from(blockPos).asLong());
if (data != null) {
ci.setReturnValue(data.get(
ChunkSectionPos.getLocalCoord(blockPos.getX()),
ChunkSectionPos.getLocalCoord(blockPos.getY()),
ChunkSectionPos.getLocalCoord(blockPos.getZ())
));
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package de.johni0702.minecraft.bobby.mixin;

import net.minecraft.world.chunk.light.ChunkLightProvider;
import net.minecraft.world.chunk.light.LightingProvider;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;

@Mixin(LightingProvider.class)
public interface LightingProviderAccessor {
@Accessor
@Nullable
ChunkLightProvider<?, ?> getBlockLightProvider();
@Accessor
@Nullable
ChunkLightProvider<?, ?> getSkyLightProvider();
}
7 changes: 3 additions & 4 deletions src/main/resources/bobby.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@
"package": "de.johni0702.minecraft.bobby.mixin",
"compatibilityLevel": "JAVA_8",
"plugin": "de.johni0702.minecraft.bobby.MixinConfigPlugin",
"mixins": [
"BiomeAccessAccessor"
],
"client": [
"BiomeAccessAccessor",
"ChunkLightProviderMixin",
"ClientChunkManagerMixin",
"ClientPlayNetworkHandlerMixin",
"IntegratedServerMixin",
"LightingProviderAccessor",
"MinecraftClientMixin",
"sodium.SodiumChunkManagerAccessor",
"sodium.SodiumChunkManagerMixin",
Expand Down

0 comments on commit c059a62

Please sign in to comment.