Skip to content

Commit

Permalink
Handle corrupt light data gracefully
Browse files Browse the repository at this point in the history
First, if the light data is not marked as correct, we should not be
parsing it in the first place. This will eliminate errors from
parsing possibly different versioned light data.

Secondly, if parsing the light data throws an exception (from
the SWMRNibbleArray constructor), then we can simply mark
the returned chunk as having incorrect light data - rather than
propagating the exception and causing the chunk to be re-generated.
  • Loading branch information
Spottedleaf committed Nov 2, 2024
1 parent 0cbc9aa commit 54fc964
Showing 1 changed file with 38 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import net.minecraft.world.level.chunk.storage.RegionStorageInfo;
import net.minecraft.world.level.chunk.storage.SerializableChunkData;
import net.minecraft.world.level.lighting.LevelLightEngine;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
Expand All @@ -46,6 +47,10 @@ abstract class SerializableChunkDataMixin {
@Final
private List<SerializableChunkData.SectionData> sectionData;

@Shadow
@Final
private static Logger LOGGER;

/**
* @reason Replace light correctness check with our own
* Our light check is versioned in case we change the light format OR fix a bug
Expand Down Expand Up @@ -116,33 +121,45 @@ private void loadStarlightLightData(final ServerLevel world, final PoiManager po
final SWMRNibbleArray[] blockNibbles = StarLightEngine.getFilledEmptyLight(world);
final SWMRNibbleArray[] skyNibbles = StarLightEngine.getFilledEmptyLight(world);

for (final SerializableChunkData.SectionData sectionData : this.sectionData) {
final int y = sectionData.y();
final DataLayer blockLight = sectionData.blockLight();
final DataLayer skyLight = sectionData.skyLight();

final int blockState = ((StarlightSectionData)(Object)sectionData).starlight$getBlockLightState();
final int skyState = ((StarlightSectionData)(Object)sectionData).starlight$getSkyLightState();
if (!this.lightCorrect) {
((StarlightChunk)ret).starlight$setBlockNibbles(blockNibbles);
((StarlightChunk)ret).starlight$setSkyNibbles(skyNibbles);
return;
}

if (blockState >= 0) {
if (blockLight != null) {
blockNibbles[y - minSection] = new SWMRNibbleArray(MixinWorkarounds.clone(blockLight.getData()), blockState); // clone for data safety
} else {
blockNibbles[y - minSection] = new SWMRNibbleArray(null, blockState);
try {
for (final SerializableChunkData.SectionData sectionData : this.sectionData) {
final int y = sectionData.y();
final DataLayer blockLight = sectionData.blockLight();
final DataLayer skyLight = sectionData.skyLight();

final int blockState = ((StarlightSectionData)(Object)sectionData).starlight$getBlockLightState();
final int skyState = ((StarlightSectionData)(Object)sectionData).starlight$getSkyLightState();

if (blockState >= 0) {
if (blockLight != null) {
blockNibbles[y - minSection] = new SWMRNibbleArray(MixinWorkarounds.clone(blockLight.getData()), blockState); // clone for data safety
} else {
blockNibbles[y - minSection] = new SWMRNibbleArray(null, blockState);
}
}
}

if (skyState >= 0 && hasSkyLight) {
if (skyLight != null) {
skyNibbles[y - minSection] = new SWMRNibbleArray(MixinWorkarounds.clone(skyLight.getData()), skyState); // clone for data safety
} else {
skyNibbles[y - minSection] = new SWMRNibbleArray(null, skyState);
if (skyState >= 0 && hasSkyLight) {
if (skyLight != null) {
skyNibbles[y - minSection] = new SWMRNibbleArray(MixinWorkarounds.clone(skyLight.getData()), skyState); // clone for data safety
} else {
skyNibbles[y - minSection] = new SWMRNibbleArray(null, skyState);
}
}
}
}

((StarlightChunk)ret).starlight$setBlockNibbles(blockNibbles);
((StarlightChunk)ret).starlight$setSkyNibbles(skyNibbles);
((StarlightChunk)ret).starlight$setBlockNibbles(blockNibbles);
((StarlightChunk)ret).starlight$setSkyNibbles(skyNibbles);
} catch (final Throwable thr) {
ret.setLightCorrect(false);

LOGGER.error("Failed to parse light data for chunk " + ret.getPos() + " in world '" + WorldUtil.getWorldName(world) + "'", thr);
}
}

/**
Expand Down

0 comments on commit 54fc964

Please sign in to comment.