From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Spottedleaf Date: Mon, 10 May 2021 15:46:57 -0700 Subject: [PATCH] Fix incorrect status dataconverter for pre 1.13 chunks Vanilla was setting non-populated OR non-lit chunks to empty, but really this is just completely wrong. It should be set to "carved" at minmum, because pre 1.13 chunks went through 3 distinct stages of generation: carving, population, and lighting - in this order. There is no "empty" status, because a chunk was simply carved or it didn't exist. So mapping any chunk data to empty is simply invalid. If the chunk is terrain populated, then obviously it must be at minmum "decorated." If the chunk is lit and populated, then it is marked "mobs_spawned" (which is what Vanilla is doing, and this is the last stage before moving to full so it looks correct). So now here is a table representing the new status conversion: Chunk is lit Chunk is populated Vanilla F F empty T F empty F T empty T T mobs_spawned Chunk is lit Chunk is populated Paper F F carved T F carved F T decorated T T mobs_spawned This should fix some problems converting old data, as the changes here are going to prevent the chunk from being regenerated incorrectly. SPOTTEDLEAF!!!!!!!!!!! diff --git a/src/main/java/net/minecraft/util/datafix/fixes/ChunkToProtochunkFix.java b/src/main/java/net/minecraft/util/datafix/fixes/ChunkToProtochunkFix.java index 16f6aa39385e2d278d4883a32c11ddd119d0d85d..3d262dcf6db0e395d2fa457f7197f24013037ac1 100644 --- a/src/main/java/net/minecraft/util/datafix/fixes/ChunkToProtochunkFix.java +++ b/src/main/java/net/minecraft/util/datafix/fixes/ChunkToProtochunkFix.java @@ -43,13 +43,21 @@ public class ChunkToProtochunkFix extends DataFix { return dynamic.asStreamOpt().result(); }); Dynamic dynamic = (Dynamic) typed1.get(DSL.remainderFinder()); - boolean flag = dynamic.get("TerrainPopulated").asBoolean(false) && (!dynamic.get("LightPopulated").asNumber().result().isPresent() || dynamic.get("LightPopulated").asBoolean(false)); - - dynamic = dynamic.set("Status", dynamic.createString(flag ? "mobs_spawned" : "empty")); + // Paper start - fix incorrect status conversion + // Vanilla is setting chunks to incorrect status here, they should be using at minimum carved. + // for populated chunks, it should be at minimum decorated + // and for lit and populated, mobs_spawned is correct (technically mobs_spawned should be for populated, + // but if it's not lit then it can't be set above lit) + final boolean terrainPopulated = dynamic.get("TerrainPopulated").asBoolean(false); + final boolean lightPopulated = dynamic.get("LightPopulated").asBoolean(false) || dynamic.get("LightPopulated").asNumber().result().isPresent(); + final String newStatus = !terrainPopulated ? "carved" : (lightPopulated ? "mobs_spawned" : "decorated"); + + dynamic = dynamic.set("Status", dynamic.createString(newStatus)); dynamic = dynamic.set("hasLegacyStructureData", dynamic.createBoolean(true)); - Dynamic dynamic1; + // Paper end - fix incorrect status conversion + Dynamic dynamic1; // Paper - decompile fix - if (flag) { + if (true) { // Paper - fix incorrect status conversion Optional optional1 = dynamic.get("Biomes").asByteBufferOpt().result(); if (optional1.isPresent()) { @@ -70,7 +78,7 @@ public class ChunkToProtochunkFix extends DataFix { }).collect(Collectors.toList()); if (optional.isPresent()) { - ((Stream) optional.get()).forEach((dynamic2) -> { + optional.get().forEach((dynamic2) -> { // Paper - decompile fix int j = dynamic2.get("x").asInt(0); int k = dynamic2.get("y").asInt(0); int l = dynamic2.get("z").asInt(0); @@ -78,11 +86,11 @@ public class ChunkToProtochunkFix extends DataFix { ((ShortList) list.get(k >> 4)).add(short0); }); + Dynamic finalDynamic = dynamic; // Paper - decompile fix dynamic = dynamic.set("ToBeTicked", dynamic.createList(list.stream().map((shortlist) -> { - Stream stream = shortlist.stream(); + Stream stream = shortlist.stream(); // Paper - decompile fix - dynamic.getClass(); - return dynamic.createList(stream.map(dynamic::createShort)); + return finalDynamic.createList(stream.map(finalDynamic::createShort)); }))); }