diff --git a/patches/unapplied/server/Add-TickThread.patch b/patches/server/Add-TickThread.patch similarity index 100% rename from patches/unapplied/server/Add-TickThread.patch rename to patches/server/Add-TickThread.patch diff --git a/patches/server/Adventure.patch b/patches/server/Adventure.patch index cf4a8298511..ec93ede3439 100644 --- a/patches/server/Adventure.patch +++ b/patches/server/Adventure.patch @@ -2578,6 +2578,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } // CraftBukkit end +@@ -0,0 +0,0 @@ public abstract class PlayerList { + + } + +- public String remove(ServerPlayer entityplayer) { // CraftBukkit - return string ++ public net.kyori.adventure.text.Component remove(ServerPlayer entityplayer) { // CraftBukkit - return string // Paper - return Component + ServerLevel worldserver = entityplayer.serverLevel(); + + entityplayer.awardStat(Stats.LEAVE_GAME); @@ -0,0 +0,0 @@ public abstract class PlayerList { entityplayer.closeContainer(); } @@ -2795,6 +2804,34 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 ((ServerPlayer) player).connection.send(this.getUpdatePacket()); // CraftBukkit } } +@@ -0,0 +0,0 @@ public class SignBlockEntity extends BlockEntity implements CommandSource { // C + + // CraftBukkit start + Player player1 = ((ServerPlayer) player).getBukkitEntity(); +- String[] lines = new String[4]; ++ // Paper start ++ List lines = new java.util.ArrayList<>(); + + for (int j = 0; j < messages.size(); ++j) { +- lines[j] = CraftChatMessage.fromComponent(text.getMessage(j, player.isTextFilteringEnabled())); ++ lines.add(io.papermc.paper.adventure.PaperAdventure.asAdventure(text.getMessage(j, player.isTextFilteringEnabled()))); + } + + SignChangeEvent event = new SignChangeEvent(CraftBlock.at(this.level, this.worldPosition), player1, lines); + player.level().getCraftServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { +- Component[] components = org.bukkit.craftbukkit.block.CraftSign.sanitizeLines(event.getLines()); +- for (int j = 0; j < components.length; j++) { +- text = text.setMessage(j, components[j]); ++ // Paper start ++ for (int j = 0; j < 4; j++) { ++ text = text.setMessage(j, io.papermc.paper.adventure.PaperAdventure.asVanilla(lines.get(j))); + } ++ // Paper end + } + // CraftBukkit end + } diff --git a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java diff --git a/patches/unapplied/server/Rewrite-dataconverter-system.patch b/patches/server/Rewrite-dataconverter-system.patch similarity index 98% rename from patches/unapplied/server/Rewrite-dataconverter-system.patch rename to patches/server/Rewrite-dataconverter-system.patch index 122f36c97f9..41dc3088152 100644 --- a/patches/unapplied/server/Rewrite-dataconverter-system.patch +++ b/patches/server/Rewrite-dataconverter-system.patch @@ -408,8 +408,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 3209, + 3214, + 3319, -+ 3322 -+ // All up to 1.19.4 ++ 3322, ++ 3438, ++ 3439, ++ 3440, ++ 3441, ++ 3447, ++ 3448, ++ 3450, ++ 3451, ++ 3459 ++ // All up to 1.20-rc1 + }; + Arrays.sort(converterVersions); + @@ -440,7 +449,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // final release of major version + registerBreakpoint(MCVersions.V1_18_2, Integer.MAX_VALUE); + -+ ++ // final release of major version ++ registerBreakpoint(MCVersions.V1_19_4, Integer.MAX_VALUE); + } + + static { @@ -1031,6 +1041,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public static final int V1_19_4_RC2 = 3335; + public static final int V1_19_4_RC3 = 3336; + public static final int V1_19_4 = 3337; ++ public static final int V23W12A = 3442; ++ public static final int V23W13A = 3443; ++ public static final int V23W14A = 3445; ++ public static final int V23W16A = 3449; ++ public static final int V23W17A = 3452; ++ public static final int V23W19A = 3453; ++ public static final int V1_20_PRE1 = 3454; ++ public static final int V1_20_PRE2 = 3455; ++ public static final int V1_20_PRE3 = 3456; ++ public static final int V1_20_PRE4 = 3457; ++ public static final int V1_20_PRE5 = 3458; ++ public static final int V1_20_PRE6 = 3460; ++ public static final int V1_20_PRE7 = 3461; ++ public static final int V1_20_RC1 = 3462; + +} diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/advancements/ConverterAbstractAdvancementsRename.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/advancements/ConverterAbstractAdvancementsRename.java @@ -2239,7 +2263,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + public static void register(final int version, final int subVersion, final Function renamer) { -+ MCTypeRegistry.ENTITY.addStructureConverter(new DataConverter<>(version) { ++ MCTypeRegistry.ENTITY.addStructureConverter(new DataConverter<>(version, subVersion) { + @Override + public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { + final String id = data.getString("id"); @@ -5307,6 +5331,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // assumes no two or more entries are renamed to a single value, otherwise result will be only one of them will win + // and there is no defined winner in such a case + public static void renameKeys(final MapType data, final Function renamer) { ++ if (data == null) { ++ return; ++ } ++ + List newKeys = null; + List newValues = null; + boolean needsRename = false; @@ -5348,6 +5376,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + // Clobbers anything in toKey if fromKey exists + public static void renameSingle(final MapType data, final String fromKey, final String toKey) { ++ if (data == null) { ++ return; ++ } ++ + final Object value = data.getGeneric(fromKey); + if (value != null) { + data.remove(fromKey); @@ -5355,6 +5387,24 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + } + ++ public static void renameString(final MapType data, final String key, final Function renamer) { ++ if (data == null) { ++ return; ++ } ++ ++ final String value = data.getString(key); ++ if (value == null) { ++ return; ++ } ++ ++ final String renamed = renamer.apply(value); ++ if (renamed == null) { ++ return; ++ } ++ ++ data.setString(key, renamed); ++ } ++ + private RenameHelper() {} + +} @@ -6638,6 +6688,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public static final MCValueType BIOME = new MCValueType("Biome"); + public static final MCDataType WORLD_GEN_SETTINGS = new MCDataType("WorldGenSettings"); + public static final MCValueType GAME_EVENT_NAME = new MCValueType("GameEventName"); ++ public static final MCValueType MULTI_NOISE_BIOME_SOURCE_PARAMETER_LIST = new MCValueType("MULTI_NOISE_BIOME_SOURCE_PARAMETER_LIST"); + + static { + try { @@ -6846,6 +6897,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + V3326.register(); + V3327.register(); + V3328.register(); ++ // V1.20 ++ V3438.register(); ++ V3439.register(); ++ V3440.register(); ++ V3441.register(); ++ V3447.register(); ++ V3448.register(); ++ V3450.register(); ++ V3451.register(); ++ V3459.register(); + } + + private MCTypeRegistry() {} @@ -6968,13 +7029,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + @Override + public MapType preHook(final MapType data, final long fromVersion, final long toVersion) { -+ final String id = data.getString(this.path); -+ if (id != null) { -+ final String replace = NamespaceUtil.correctNamespaceOrNull(id); -+ if (replace != null) { -+ data.setString(this.path, replace); -+ } -+ } ++ NamespaceUtil.enforceForPath(data, this.path); + return null; + } + @@ -15963,7 +16018,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + case "minecraft:multi_noise": { -+ // preset is absent, no type for namespaced string ++ WalkerUtils.convert(MCTypeRegistry.MULTI_NOISE_BIOME_SOURCE_PARAMETER_LIST, biomeSource, "preset", fromVersion, toVersion); + + // Vanilla's schema is _still_ wrong. It should be DSL.fields("biomes", DSL.list(DSL.fields("biome"))) + // But it just contains the list part. That obviously can never be the case, because @@ -15975,6 +16030,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + WalkerUtils.convert(MCTypeRegistry.BIOME, biomes.getMap(i), "biome", fromVersion, toVersion); + } + } ++ + break; + } + @@ -16088,6 +16144,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + offsetHeightmaps(level); ++ // Difference from DFU: Still convert the Lights data. Just because it's being removed in a later version doesn't mean ++ // that it should be removed here. ++ // Generally, converters act only on the current version to bring it to the next. This principle allows the converter ++ // for the next version to assume that it acts on its current version, not some in-between of the current version ++ // and some future version that did not exist at the time it was written. This allows converters to be written and tested ++ // only with knowledge of the current version and the next version. + addEmptyListPadding(level, "Lights"); + addEmptyListPadding(level, "LiquidsToBeTicked"); + addEmptyListPadding(level, "PostProcessing"); @@ -17454,69 +17516,25 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ +package ca.spottedleaf.dataconverter.minecraft.versions; + -+import ca.spottedleaf.dataconverter.converters.DataConverter; +import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.dataconverter.minecraft.converters.chunk.ConverterAddBlendingData; +import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; -+import ca.spottedleaf.dataconverter.types.MapType; -+import ca.spottedleaf.dataconverter.types.Types; -+import ca.spottedleaf.dataconverter.util.NamespaceUtil; -+import java.util.Arrays; -+import java.util.HashSet; -+import java.util.Set; + +public final class V3088 { + + // this class originally targeted 3079 but was changed to target a later version without changing the converter, zero clue why ++ // this class then targeted 3088 but was changed to target 3441 ++ // to maintain integrity of the data version, I chose to extract the converter to a separate class and use it in both versions ++ // the reason it is important to never change old converters once released is that it creates _two_ versions under the same id. ++ // Consider the case where a user force upgrades their world, but does not load the chunk. Then, consider the case where ++ // the user does not force upgrade their world. Then, Mojang comes along and makes a decision like this and now both ++ // players load the chunk - they went through a different conversion process, which ultimately creates two versions. ++ // Unfortunately this fix doesn't exactly resolve it, as anyone running Mojang's converters will now be different ++ // from DataConverter's. It's broadly a dumb situation all around that could be avoided if Mojang wasn't being careless here. + protected static final int VERSION = MCVersions.V22W14A; + -+ private static final Set STATUSES_TO_SKIP_BLENDING = new HashSet<>( -+ Arrays.asList( -+ "minecraft:empty", -+ "minecraft:structure_starts", -+ "minecraft:structure_references", -+ "minecraft:biomes" -+ ) -+ ); -+ + public static void register() { -+ MCTypeRegistry.CHUNK.addStructureConverter(new DataConverter<>(VERSION) { -+ -+ private static MapType createBlendingData(final int height, final int minY) { -+ final MapType ret = Types.NBT.createEmptyMap(); -+ -+ ret.setInt("min_section", minY >> 4); -+ ret.setInt("max_section", (minY + height) >> 4); -+ -+ return ret; -+ } -+ -+ @Override -+ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ data.remove("blending_data"); -+ final MapType context = data.getMap("__context"); -+ if (!"minecraft:overworld".equals(context == null ? null : context.getString("dimension"))) { -+ return null; -+ } -+ -+ final String status = NamespaceUtil.correctNamespace(data.getString("Status")); -+ if (status == null) { -+ return null; -+ } -+ -+ final MapType belowZeroRetrogen = data.getMap("below_zero_retrogen"); -+ -+ if (!STATUSES_TO_SKIP_BLENDING.contains(status)) { -+ data.setMap("blending_data", createBlendingData(384, -64)); -+ } else if (belowZeroRetrogen != null) { -+ final String realStatus = NamespaceUtil.correctNamespace(belowZeroRetrogen.getString("target_status", "empty")); -+ if (!STATUSES_TO_SKIP_BLENDING.contains(realStatus)) { -+ data.setMap("blending_data", createBlendingData(256, 0)); -+ } -+ } -+ -+ return null; -+ } -+ }); ++ MCTypeRegistry.CHUNK.addStructureConverter(new ConverterAddBlendingData(VERSION)); + } +} diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V3090.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V3090.java @@ -18556,6 +18574,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:bee_nest", "minecraft:beehive"); + ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:beehive", "minecraft:beehive"); + ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:sculk_sensor", "minecraft:sculk_sensor"); ++ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:decorated_pot", "minecraft:decorated_pot"); + + // These are missing from Vanilla (TODO check on update) + ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:enchanting_table", "minecraft:enchanting_table"); @@ -18579,10 +18598,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:crimson_hanging_sign", "minecraft:sign"); + ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:warped_hanging_sign", "minecraft:sign"); + ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:piglin_head", "minecraft:skull"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:suspicious_sand", "minecraft:suspicious_sand"); -+ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:decorated_pot", "minecraft:decorated_pot"); ++ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:suspicious_sand", "minecraft:brushable_block"); // note: this was renamed in the past, see special case in the itemstack walker + ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:cherry_sign", "minecraft:sign"); + ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:cherry_hanging_sign", "minecraft:sign"); ++ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:suspicious_gravel", "minecraft:brushable_block"); ++ ITEM_ID_TO_TILE_ENTITY_ID.put("minecraft:calibrated_sculk_sensor", "minecraft:calibrated_sculk_sensor"); + } + + // This class is responsible for also integrity checking the item id to tile id map here, we just use the item registry to figure it out @@ -18752,7 +18772,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + MapType blockEntityTag = tag.getMap("BlockEntityTag"); + if (blockEntityTag != null) { + final String itemId = data.getString("id"); -+ final String entityId = ITEM_ID_TO_TILE_ENTITY_ID.get(itemId); ++ final String entityId; ++ if ("minecraft:suspicious_sand".equals(itemId) && fromVersion < V3438.VERSION) { ++ // renamed after this version, and since the id is a mapping to just string we need to special case this ++ entityId = "minecraft:suspicious_sand"; ++ } else { ++ entityId = ITEM_ID_TO_TILE_ENTITY_ID.get(itemId); ++ } + final boolean removeId; + if (entityId == null) { + if (!"minecraft:air".equals(itemId)) { @@ -23077,12 +23103,27 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ +package ca.spottedleaf.dataconverter.util; + ++import ca.spottedleaf.dataconverter.types.MapType; +import net.minecraft.resources.ResourceLocation; + +public final class NamespaceUtil { + + private NamespaceUtil() {} + ++ public static void enforceForPath(final MapType data, final String path) { ++ if (data == null) { ++ return; ++ } ++ ++ final String id = data.getString(path); ++ if (id != null) { ++ final String replace = NamespaceUtil.correctNamespaceOrNull(id); ++ if (replace != null) { ++ data.setString(path, replace); ++ } ++ } ++ } ++ + public static String correctNamespace(final String value) { + if (value == null) { + return null; @@ -23099,12 +23140,648 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return correct.equals(value) ? null : correct; + } +} +diff --git a/src/main/java/ca/spottedleaf/minecraft/converters/chunk/ConverterAddBlendingData.java b/src/main/java/ca/spottedleaf/minecraft/converters/chunk/ConverterAddBlendingData.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/minecraft/converters/chunk/ConverterAddBlendingData.java +@@ -0,0 +0,0 @@ ++package ca.spottedleaf.minecraft.converters.chunk; ++ ++import ca.spottedleaf.dataconverter.converters.DataConverter; ++import ca.spottedleaf.dataconverter.types.MapType; ++import ca.spottedleaf.dataconverter.types.Types; ++import ca.spottedleaf.dataconverter.util.NamespaceUtil; ++import java.util.Arrays; ++import java.util.HashSet; ++import java.util.Set; ++ ++public final class ConverterAddBlendingData extends DataConverter, MapType> { ++ ++ private static final Set STATUSES_TO_SKIP_BLENDING = new HashSet<>( ++ Arrays.asList( ++ "minecraft:empty", ++ "minecraft:structure_starts", ++ "minecraft:structure_references", ++ "minecraft:biomes" ++ ) ++ ); ++ ++ public ConverterAddBlendingData(final int toVersion) { ++ super(toVersion); ++ } ++ ++ public ConverterAddBlendingData(final int toVersion, final int versionStep) { ++ super(toVersion, versionStep); ++ } ++ ++ private static MapType createBlendingData(final int height, final int minY) { ++ final MapType ret = Types.NBT.createEmptyMap(); ++ ++ ret.setInt("min_section", minY >> 4); ++ ret.setInt("max_section", (minY + height) >> 4); ++ ++ return ret; ++ } ++ ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ data.remove("blending_data"); ++ final MapType context = data.getMap("__context"); ++ if (!"minecraft:overworld".equals(context == null ? null : context.getString("dimension"))) { ++ return null; ++ } ++ ++ final String status = NamespaceUtil.correctNamespace(data.getString("Status")); ++ if (status == null) { ++ return null; ++ } ++ ++ final MapType belowZeroRetrogen = data.getMap("below_zero_retrogen"); ++ ++ if (!STATUSES_TO_SKIP_BLENDING.contains(status)) { ++ data.setMap("blending_data", createBlendingData(384, -64)); ++ } else if (belowZeroRetrogen != null) { ++ final String realStatus = NamespaceUtil.correctNamespace(belowZeroRetrogen.getString("target_status", "empty")); ++ if (!STATUSES_TO_SKIP_BLENDING.contains(realStatus)) { ++ data.setMap("blending_data", createBlendingData(256, 0)); ++ } ++ } ++ ++ return null; ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/minecraft/converters/chunk/ConverterRenameStatus.java b/src/main/java/ca/spottedleaf/minecraft/converters/chunk/ConverterRenameStatus.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/minecraft/converters/chunk/ConverterRenameStatus.java +@@ -0,0 +0,0 @@ ++package ca.spottedleaf.minecraft.converters.chunk; ++ ++import ca.spottedleaf.dataconverter.converters.DataConverter; ++import ca.spottedleaf.dataconverter.minecraft.converters.helpers.RenameHelper; ++import ca.spottedleaf.dataconverter.types.MapType; ++import ca.spottedleaf.dataconverter.util.NamespaceUtil; ++import java.util.function.Function; ++ ++public final class ConverterRenameStatus extends DataConverter, MapType> { ++ ++ private final Function renamer; ++ ++ public ConverterRenameStatus(final int toVersion, final Function renamer) { ++ this(toVersion, 0, renamer); ++ } ++ ++ public ConverterRenameStatus(final int toVersion, final int versionStep, final Function renamer) { ++ super(toVersion, versionStep); ++ this.renamer = renamer; ++ } ++ ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ // Note: DFU technically enforces namespace due to how they wrote their converter, so we will do the same. ++ NamespaceUtil.enforceForPath(data, "Status"); ++ RenameHelper.renameString(data, "Status", this.renamer); ++ ++ NamespaceUtil.enforceForPath(data.getMap("below_zero_retrogen"), "target_status"); ++ RenameHelper.renameString(data.getMap("below_zero_retrogen"), "target_status", this.renamer); ++ return null; ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/minecraft/converters/leveldat/ConverterRemoveFeatureFlag.java b/src/main/java/ca/spottedleaf/minecraft/converters/leveldat/ConverterRemoveFeatureFlag.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/minecraft/converters/leveldat/ConverterRemoveFeatureFlag.java +@@ -0,0 +0,0 @@ ++package ca.spottedleaf.minecraft.converters.leveldat; ++ ++import ca.spottedleaf.dataconverter.converters.DataConverter; ++import ca.spottedleaf.dataconverter.types.ListType; ++import ca.spottedleaf.dataconverter.types.MapType; ++import ca.spottedleaf.dataconverter.types.ObjectType; ++import java.util.Set; ++ ++public final class ConverterRemoveFeatureFlag extends DataConverter, MapType> { ++ ++ private final Set flags; ++ ++ public ConverterRemoveFeatureFlag(final int toVersion, final Set flags) { ++ this(toVersion, 0, flags); ++ } ++ ++ public ConverterRemoveFeatureFlag(final int toVersion, final int versionStep, final Set flags) { ++ super(toVersion, versionStep); ++ this.flags = flags; ++ } ++ ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ final ListType enabledFeatures = data.getList("enabled_features", ObjectType.STRING); ++ if (enabledFeatures == null) { ++ return null; ++ } ++ ++ ListType removedFeatures = null; ++ ++ for (int i = 0; i < enabledFeatures.size(); ++i) { ++ final String flag = enabledFeatures.getString(i); ++ if (!this.flags.contains(flag)) { ++ continue; ++ } ++ enabledFeatures.remove(i--); ++ ++ if (removedFeatures == null) { ++ removedFeatures = data.getOrCreateList("removed_features", ObjectType.STRING); ++ } ++ removedFeatures.addString(flag); ++ } ++ ++ return null; ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/minecraft/converters/tileentity/ConverterAbstractTileEntityRename.java b/src/main/java/ca/spottedleaf/minecraft/converters/tileentity/ConverterAbstractTileEntityRename.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/minecraft/converters/tileentity/ConverterAbstractTileEntityRename.java +@@ -0,0 +0,0 @@ ++package ca.spottedleaf.minecraft.converters.tileentity; ++ ++import ca.spottedleaf.dataconverter.converters.DataConverter; ++import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; ++import ca.spottedleaf.dataconverter.types.MapType; ++import java.util.function.Function; ++ ++public final class ConverterAbstractTileEntityRename { ++ ++ public static void register(final int version, final Function renamer) { ++ register(version, 0, renamer); ++ } ++ ++ public static void register(final int version, final int subVersion, final Function renamer) { ++ MCTypeRegistry.TILE_ENTITY.addStructureConverter(new DataConverter<>(version, subVersion) { ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ final String id = data.getString("id"); ++ if (id == null) { ++ return null; ++ } ++ ++ final String converted = renamer.apply(id); ++ ++ if (converted != null) { ++ data.setString("id", converted); ++ } ++ ++ return null; ++ } ++ }); ++ } ++ ++} +diff --git a/src/main/java/ca/spottedleaf/minecraft/versions/V3438.java b/src/main/java/ca/spottedleaf/minecraft/versions/V3438.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/minecraft/versions/V3438.java +@@ -0,0 +0,0 @@ ++package ca.spottedleaf.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.converters.DataConverter; ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.dataconverter.minecraft.converters.helpers.RenameHelper; ++import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; ++import ca.spottedleaf.minecraft.converters.tileentity.ConverterAbstractTileEntityRename; ++import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; ++import ca.spottedleaf.dataconverter.types.MapType; ++ ++import java.util.HashMap; ++import java.util.Map; ++ ++public final class V3438 { ++ ++ public static final int VERSION = MCVersions.V1_19_4 + 101; ++ ++ public static void register() { ++ // brushable block rename ++ MCTypeRegistry.TILE_ENTITY.copyWalkers(VERSION,"minecraft:suspicious_sand", "minecraft:brushable_block"); ++ ++ ConverterAbstractTileEntityRename.register(VERSION, new HashMap<>(Map.of( ++ "minecraft:suspicious_sand", "minecraft:brushable_block" ++ ))::get); ++ ++ ++ MCTypeRegistry.TILE_ENTITY.addConverterForId("minecraft:brushable_block", new DataConverter<>(VERSION) { ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ RenameHelper.renameSingle(data, "loot_table", "LootTable"); ++ RenameHelper.renameSingle(data, "loot_table_seed", "LootTableSeed"); ++ return null; ++ } ++ }); ++ ++ ConverterAbstractItemRename.register(VERSION, new HashMap<>( ++ Map.of( ++ "minecraft:pottery_shard_archer", "minecraft:archer_pottery_shard", ++ "minecraft:pottery_shard_prize", "minecraft:prize_pottery_shard", ++ "minecraft:pottery_shard_arms_up", "minecraft:arms_up_pottery_shard", ++ "minecraft:pottery_shard_skull", "minecraft:skull_pottery_shard" ++ ) ++ )::get); ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/minecraft/versions/V3439.java b/src/main/java/ca/spottedleaf/minecraft/versions/V3439.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/minecraft/versions/V3439.java +@@ -0,0 +0,0 @@ ++package ca.spottedleaf.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.converters.DataConverter; ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; ++import ca.spottedleaf.dataconverter.types.ListType; ++import ca.spottedleaf.dataconverter.types.MapType; ++import net.minecraft.network.chat.CommonComponents; ++import net.minecraft.network.chat.Component; ++ ++public final class V3439 { ++ ++ private static final int VERSION = MCVersions.V1_19_4 + 102; ++ ++ public static void register() { ++ final DataConverter, MapType> signTileUpdater = new DataConverter<>(VERSION) { ++ private static final String BLANK_TEXT_LINE = Component.Serializer.toJson(CommonComponents.EMPTY); ++ private static final String DEFAULT_COLOR = "black"; ++ ++ private static ListType migrateToList(final MapType root, final String prefix) { ++ if (root == null) { ++ return null; ++ } ++ ++ final ListType ret = root.getTypeUtil().createEmptyList(); ++ ++ ret.addString(root.getString(prefix.concat("1"), BLANK_TEXT_LINE)); ++ ret.addString(root.getString(prefix.concat("2"), BLANK_TEXT_LINE)); ++ ret.addString(root.getString(prefix.concat("3"), BLANK_TEXT_LINE)); ++ ret.addString(root.getString(prefix.concat("4"), BLANK_TEXT_LINE)); ++ ++ return ret; ++ } ++ ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ final MapType frontText = data.getTypeUtil().createEmptyMap(); ++ data.setMap("front_text", frontText); ++ ++ frontText.setList("messages", migrateToList(data, "Text")); ++ frontText.setList("filtered_messages", migrateToList(data, "FilteredText")); ++ frontText.setString("color", data.getString("Color", DEFAULT_COLOR)); ++ frontText.setBoolean("has_glowing_text", data.getBoolean("GlowingText", false)); ++ ++ final MapType backText = data.getTypeUtil().createEmptyMap(); ++ data.setMap("back_text", backText); ++ ++ final ListType blankMessages = data.getTypeUtil().createEmptyList(); ++ for (int i = 0; i < 4; ++i) { ++ blankMessages.addString(BLANK_TEXT_LINE); ++ } ++ ++ backText.setList("messages", blankMessages); ++ backText.setList("filtered_messages", blankMessages.copy()); // need to copy so that the value isn't mapped to twice, so that updates to one do not reflect in the other ++ backText.setString("color", DEFAULT_COLOR); ++ backText.setBoolean("has_glowing_text", false); ++ ++ return null; ++ } ++ }; ++ ++ MCTypeRegistry.TILE_ENTITY.addConverterForId("minecraft:sign", signTileUpdater); ++ MCTypeRegistry.TILE_ENTITY.addConverterForId("minecraft:hanging_sign", signTileUpdater); ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/minecraft/versions/V3440.java b/src/main/java/ca/spottedleaf/minecraft/versions/V3440.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/minecraft/versions/V3440.java +@@ -0,0 +0,0 @@ ++package ca.spottedleaf.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.dataconverter.minecraft.converters.helpers.ConverterAbstractStringValueTypeRename; ++import ca.spottedleaf.minecraft.converters.leveldat.ConverterRemoveFeatureFlag; ++import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; ++import ca.spottedleaf.dataconverter.util.NamespaceUtil; ++ ++import java.util.Arrays; ++import java.util.HashSet; ++ ++public final class V3440 { ++ ++ private static final int VERSION = MCVersions.V1_19_4 + 103; ++ ++ public static void register() { ++ // Note: MULTI_NOISE_BIOME_SOURCE_PARAMETER_LIST is namespaced string ++ ConverterAbstractStringValueTypeRename.register(VERSION, MCTypeRegistry.MULTI_NOISE_BIOME_SOURCE_PARAMETER_LIST, (final String in) -> { ++ return "minecraft:overworld_update_1_20".equals(NamespaceUtil.correctNamespace(in)) ? "minecraft:overworld" : null; ++ }); ++ MCTypeRegistry.LEVEL.addStructureConverter(new ConverterRemoveFeatureFlag(VERSION, new HashSet<>( ++ Arrays.asList( ++ "minecraft:update_1_20" ++ ) ++ ))); ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/minecraft/versions/V3441.java b/src/main/java/ca/spottedleaf/minecraft/versions/V3441.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/minecraft/versions/V3441.java +@@ -0,0 +0,0 @@ ++package ca.spottedleaf.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.minecraft.converters.chunk.ConverterAddBlendingData; ++import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; ++ ++public final class V3441 { ++ ++ private static final int VERSION = MCVersions.V1_19_4 + 104; ++ ++ public static void register() { ++ // See V3088 for why this converter is duplicated here and in V3088 ++ MCTypeRegistry.CHUNK.addStructureConverter(new ConverterAddBlendingData(VERSION)); ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/minecraft/versions/V3447.java b/src/main/java/ca/spottedleaf/minecraft/versions/V3447.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/minecraft/versions/V3447.java +@@ -0,0 +0,0 @@ ++package ca.spottedleaf.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.dataconverter.minecraft.converters.itemname.ConverterAbstractItemRename; ++import java.util.HashMap; ++import java.util.Map; ++ ++public final class V3447 { ++ ++ private static final int VERSION = MCVersions.V23W14A + 2; ++ ++ public static void register() { ++ final String[] targets = new String[] { ++ "minecraft:angler_pottery_shard", ++ "minecraft:archer_pottery_shard", ++ "minecraft:arms_up_pottery_shard", ++ "minecraft:blade_pottery_shard", ++ "minecraft:brewer_pottery_shard", ++ "minecraft:burn_pottery_shard", ++ "minecraft:danger_pottery_shard", ++ "minecraft:explorer_pottery_shard", ++ "minecraft:friend_pottery_shard", ++ "minecraft:heart_pottery_shard", ++ "minecraft:heartbreak_pottery_shard", ++ "minecraft:howl_pottery_shard", ++ "minecraft:miner_pottery_shard", ++ "minecraft:mourner_pottery_shard", ++ "minecraft:plenty_pottery_shard", ++ "minecraft:prize_pottery_shard", ++ "minecraft:sheaf_pottery_shard", ++ "minecraft:shelter_pottery_shard", ++ "minecraft:skull_pottery_shard", ++ "minecraft:snort_pottery_shard" ++ }; ++ // shard->sherd ++ final Map rename = new HashMap<>(targets.length); ++ ++ for (final String target : targets) { ++ final String replace = target.replace("_pottery_shard", "_pottery_sherd"); ++ if (rename.put(target, replace) != null) { ++ throw new IllegalArgumentException("Duplicate target " + target); ++ } ++ } ++ ++ ConverterAbstractItemRename.register(VERSION, rename::get); ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/minecraft/versions/V3448.java b/src/main/java/ca/spottedleaf/minecraft/versions/V3448.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/minecraft/versions/V3448.java +@@ -0,0 +0,0 @@ ++package ca.spottedleaf.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.converters.DataConverter; ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.dataconverter.minecraft.converters.helpers.RenameHelper; ++import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; ++import ca.spottedleaf.dataconverter.minecraft.walkers.generic.DataWalkerListPaths; ++import ca.spottedleaf.dataconverter.types.MapType; ++ ++public final class V3448 { ++ ++ private static final int VERSION = MCVersions.V23W14A + 3; ++ ++ public static void register() { ++ MCTypeRegistry.TILE_ENTITY.addWalker(VERSION, "minecraft:decorated_pot", new DataWalkerListPaths<>(MCTypeRegistry.ITEM_NAME, "sherds")); ++ MCTypeRegistry.TILE_ENTITY.addConverterForId("minecraft:decorated_pot", new DataConverter<>(VERSION) { ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ RenameHelper.renameSingle(data, "shards", "sherds"); ++ return null; ++ } ++ }); ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/minecraft/versions/V3450.java b/src/main/java/ca/spottedleaf/minecraft/versions/V3450.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/minecraft/versions/V3450.java +@@ -0,0 +0,0 @@ ++package ca.spottedleaf.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.minecraft.converters.chunk.ConverterRenameStatus; ++import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; ++import java.util.HashMap; ++import java.util.Map; ++ ++public final class V3450 { ++ ++ private static final int VERSION = MCVersions.V23W16A + 1; ++ ++ public static void register() { ++ MCTypeRegistry.CHUNK.addStructureConverter(new ConverterRenameStatus(VERSION, new HashMap<>( ++ Map.of( ++ "minecraft:liquid_carvers", "minecraft:carvers", ++ "minecraft:heightmaps", "minecraft:spawn" ++ ) ++ )::get)); ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/minecraft/versions/V3451.java b/src/main/java/ca/spottedleaf/minecraft/versions/V3451.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/minecraft/versions/V3451.java +@@ -0,0 +0,0 @@ ++package ca.spottedleaf.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.converters.DataConverter; ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; ++import ca.spottedleaf.dataconverter.types.ListType; ++import ca.spottedleaf.dataconverter.types.MapType; ++import ca.spottedleaf.dataconverter.types.ObjectType; ++ ++public final class V3451 { ++ ++ private static final int VERSION = MCVersions.V23W16A + 2; ++ ++ public static void register() { ++ MCTypeRegistry.CHUNK.addStructureConverter(new DataConverter<>(VERSION) { ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ data.remove("isLightOn"); ++ ++ final ListType sections = data.getList("sections", ObjectType.MAP); ++ if (sections == null) { ++ return null; ++ } ++ ++ for (int i = 0, len = sections.size(); i < len; ++i) { ++ final MapType section = sections.getMap(i); ++ ++ section.remove("BlockLight"); ++ section.remove("SkyLight"); ++ } ++ ++ return null; ++ } ++ }); ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/minecraft/versions/V3459.java b/src/main/java/ca/spottedleaf/minecraft/versions/V3459.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/minecraft/versions/V3459.java +@@ -0,0 +0,0 @@ ++package ca.spottedleaf.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.converters.DataConverter; ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; ++import ca.spottedleaf.dataconverter.types.MapType; ++ ++public final class V3459 { ++ ++ private static final int VERSION = MCVersions.V1_20_PRE5 + 1; ++ ++ public static void register() { ++ MCTypeRegistry.LEVEL.addStructureConverter(new DataConverter<>(VERSION) { ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ if (data.hasKey("DragonFight")) { ++ return null; ++ } ++ ++ final MapType dimensionData = data.getMap("DimensionData"); ++ if (dimensionData == null) { ++ return null; ++ } ++ ++ final MapType endData = dimensionData.getMap("1"); ++ if (endData != null) { ++ data.setMap("DragonFight", endData.getMap("DragonFight", endData.getTypeUtil().createEmptyMap())); ++ } ++ ++ return null; ++ } ++ }); ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/mixin/PrintTheFuckingErrorJesusChristMixin.java b/src/main/java/ca/spottedleaf/mixin/PrintTheFuckingErrorJesusChristMixin.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/mixin/PrintTheFuckingErrorJesusChristMixin.java +@@ -0,0 +0,0 @@ ++package ca.spottedleaf.mixin; ++ ++import com.mojang.datafixers.DataFixer; ++import com.mojang.datafixers.util.Either; ++import net.minecraft.ReportedException; ++import net.minecraft.server.level.ChunkHolder; ++import net.minecraft.server.level.ChunkMap; ++import net.minecraft.world.level.ChunkPos; ++import net.minecraft.world.level.chunk.ChunkAccess; ++import net.minecraft.world.level.chunk.storage.ChunkStorage; ++import org.slf4j.Logger; ++import org.spongepowered.asm.mixin.Final; ++import org.spongepowered.asm.mixin.Mixin; ++import org.spongepowered.asm.mixin.Overwrite; ++import org.spongepowered.asm.mixin.Shadow; ++import java.io.IOException; ++import java.nio.file.Path; ++ ++@Mixin(ChunkMap.class) ++public abstract class PrintTheFuckingErrorJesusChristMixin extends ChunkStorage implements ChunkHolder.PlayerProvider { ++ ++ @Shadow ++ protected abstract void markPositionReplaceable(ChunkPos chunkPos); ++ ++ @Shadow ++ @Final ++ private static Logger LOGGER; ++ ++ @Shadow ++ protected abstract ChunkAccess createEmptyChunk(ChunkPos chunkPos); ++ ++ public PrintTheFuckingErrorJesusChristMixin(Path path, DataFixer dataFixer, boolean bl) { ++ super(path, dataFixer, bl); ++ } ++ ++ /** ++ * @reason Print the fucking exception jesus christ how hard is it: ++ * 1. handle or ++ * 2. print or ++ * 3. rethrow ++ * @author Spottedleaf ++ */ ++ @Overwrite ++ private Either handleChunkLoadFailure(Throwable throwable, ChunkPos chunkPos) { ++ if (throwable instanceof ReportedException reportedException) { ++ Throwable throwable2 = reportedException.getCause(); ++ if (!(throwable2 instanceof IOException)) { ++ this.markPositionReplaceable(chunkPos); ++ throw reportedException; ++ } ++ ++ LOGGER.error("Couldn't load chunk {}", chunkPos, throwable2); ++ } else if (throwable instanceof IOException) { ++ LOGGER.error("Couldn't load chunk {}", chunkPos, throwable); ++ } ++ ++ LOGGER.error("Couldn't load chunk {} (Vanilla swallowed exception)", chunkPos, throwable); ++ ++ return Either.left(this.createEmptyChunk(chunkPos)); ++ } ++} diff --git a/src/main/java/net/minecraft/data/structures/StructureUpdater.java b/src/main/java/net/minecraft/data/structures/StructureUpdater.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/data/structures/StructureUpdater.java +++ b/src/main/java/net/minecraft/data/structures/StructureUpdater.java @@ -0,0 +0,0 @@ public class StructureUpdater implements SnbtToNbt.Filter { - LOGGER.warn("SNBT Too old, do not forget to update: {} < {}: {}", i, 3318, name); + LOGGER.warn("SNBT Too old, do not forget to update: {} < {}: {}", i, 3437, name); } - CompoundTag compoundTag = DataFixTypes.STRUCTURE.updateToCurrentVersion(DataFixers.getDataFixer(), nbt, i); diff --git a/patches/unapplied/server/Starlight.patch b/patches/server/Starlight.patch similarity index 98% rename from patches/unapplied/server/Starlight.patch rename to patches/server/Starlight.patch index 68e8f830e9a..2161dbe8bd2 100644 --- a/patches/unapplied/server/Starlight.patch +++ b/patches/server/Starlight.patch @@ -218,58 +218,49 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.performLightDecrease(lightAccess); + } + -+ protected Iterator getSources(final LightChunkGetter lightAccess, final ChunkAccess chunk) { -+ if (chunk instanceof ImposterProtoChunk || chunk instanceof LevelChunk) { -+ // implementation on Chunk is pretty awful, so write our own here. The big optimisation is -+ // skipping empty sections, and the far more optimised reading of types. -+ List sources = new ArrayList<>(); ++ protected List getSources(final LightChunkGetter lightAccess, final ChunkAccess chunk) { ++ final List sources = new ArrayList<>(); + -+ int offX = chunk.getPos().x << 4; -+ int offZ = chunk.getPos().z << 4; ++ final int offX = chunk.getPos().x << 4; ++ final int offZ = chunk.getPos().z << 4; + -+ final LevelChunkSection[] sections = chunk.getSections(); -+ for (int sectionY = this.minSection; sectionY <= this.maxSection; ++sectionY) { -+ final LevelChunkSection section = sections[sectionY - this.minSection]; -+ if (section == null || section.hasOnlyAir()) { -+ // no sources in empty sections -+ continue; -+ } -+ final PalettedContainer states = section.states; -+ final int offY = sectionY << 4; -+ -+ for (int index = 0; index < (16 * 16 * 16); ++index) { -+ final BlockState state = states.get(index); -+ if (state.getLightEmission() <= 0) { -+ continue; -+ } -+ -+ // index = x | (z << 4) | (y << 8) -+ sources.add(new BlockPos(offX | (index & 15), offY | (index >>> 8), offZ | ((index >>> 4) & 15))); -+ } ++ final LevelChunkSection[] sections = chunk.getSections(); ++ for (int sectionY = this.minSection; sectionY <= this.maxSection; ++sectionY) { ++ final LevelChunkSection section = sections[sectionY - this.minSection]; ++ if (section == null || section.hasOnlyAir()) { ++ // no sources in empty sections ++ continue; + } ++ if (!section.maybeHas((final BlockState state) -> { ++ return state.getLightEmission() > 0; ++ })) { ++ // no light sources in palette ++ continue; ++ } ++ final PalettedContainer states = section.states; ++ final int offY = sectionY << 4; + -+ return sources.iterator(); -+ } else { -+ // world gen and lighting run in parallel, and if lighting keeps up it can be lighting chunks that are -+ // being generated. In the nether, lava will add a lot of sources. This resulted in quite a few CME crashes. -+ // So all we do spinloop until we can collect a list of sources, and even if it is out of date we will pick up -+ // the missing sources from checkBlock. -+ for (;;) { -+ try { -+ return chunk.getLights().collect(Collectors.toList()).iterator(); -+ } catch (final Exception cme) { ++ for (int index = 0; index < (16 * 16 * 16); ++index) { ++ final BlockState state = states.get(index); ++ if (state.getLightEmission() <= 0) { + continue; + } ++ ++ // index = x | (z << 4) | (y << 8) ++ sources.add(new BlockPos(offX | (index & 15), offY | (index >>> 8), offZ | ((index >>> 4) & 15))); + } + } ++ ++ return sources; + } + + @Override + public void lightChunk(final LightChunkGetter lightAccess, final ChunkAccess chunk, final boolean needsEdgeChecks) { + // setup sources + final int emittedMask = this.emittedLightMask; -+ for (final Iterator positions = this.getSources(lightAccess, chunk); positions.hasNext();) { -+ final BlockPos pos = positions.next(); ++ final List positions = this.getSources(lightAccess, chunk); ++ for (int i = 0, len = positions.size(); i < len; ++i) { ++ final BlockPos pos = positions.get(i); + final BlockState blockState = this.getBlockState(pos.getX(), pos.getY(), pos.getZ()); + final int emittedLight = blockState.getLightEmission() & emittedMask; + @@ -1537,7 +1528,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.x = x; + this.y = y; + this.z = z; -+ this.nms = Direction.fromNormal(x, y, z); ++ this.nms = Direction.fromDelta(x, y, z); + this.everythingButThisDirection = (long)(ALL_DIRECTIONS_BITSET ^ (1 << this.ordinal())); + // positive is always even, negative is always odd. Flip the 1 bit to get the negative direction. + this.everythingButTheOppositeDirection = (long)(ALL_DIRECTIONS_BITSET ^ (1 << (this.ordinal() ^ 1))); @@ -3134,8 +3125,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + @Override -+ public void onBlockEmissionIncrease(final BlockPos blockPos, final int i) { -+ // skylight doesn't care ++ public void propagateLightSources(final ChunkPos chunkPos) { ++ throw new UnsupportedOperationException(); + } + + @Override @@ -3145,12 +3136,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + @Override -+ public int runUpdates(final int i, final boolean bl, final boolean bl2) { ++ public int runLightUpdates() { + throw new UnsupportedOperationException(); + } + + @Override -+ public void enableLightSources(final ChunkPos chunkPos, final boolean bl) { ++ public void setLightEnabled(final ChunkPos chunkPos, final boolean bl) { + throw new UnsupportedOperationException(); + } + @@ -3191,8 +3182,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + @Override -+ public void onBlockEmissionIncrease(final BlockPos blockPos, final int i) { -+ this.checkBlock(blockPos); ++ public void propagateLightSources(final ChunkPos chunkPos) { ++ throw new UnsupportedOperationException(); + } + + @Override @@ -3202,12 +3193,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + @Override -+ public int runUpdates(final int i, final boolean bl, final boolean bl2) { ++ public int runLightUpdates() { + throw new UnsupportedOperationException(); + } + + @Override -+ public void enableLightSources(final ChunkPos chunkPos, final boolean bl) { ++ public void setLightEnabled(final ChunkPos chunkPos, final boolean bl) { + throw new UnsupportedOperationException(); + } + @@ -3234,6 +3225,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + }; + } + ++ public boolean hasSkyLight() { ++ return this.hasSkyLight; ++ } ++ ++ public boolean hasBlockLight() { ++ return this.hasBlockLight; ++ } ++ + protected int getSkyLightValue(final BlockPos blockPos, final ChunkAccess chunk) { + if (!this.hasSkyLight) { + return 0; @@ -4103,7 +4102,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + private static final Logger LOGGER = LogUtils.getLogger(); + -+ private static final int STARLIGHT_LIGHT_VERSION = 8; ++ private static final int STARLIGHT_LIGHT_VERSION = 9; + + public static int getLightVersion() { + return STARLIGHT_LIGHT_VERSION; @@ -4522,10 +4521,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +// Paper end + public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCloseable { + public static final int DEFAULT_BATCH_SIZE = 1000; private static final Logger LOGGER = LogUtils.getLogger(); - private final ProcessorMailbox taskMailbox; @@ -0,0 +0,0 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl - private volatile int taskPerBatch = 5; + private final int taskPerBatch = 1000; private final AtomicBoolean scheduled = new AtomicBoolean(); + // Paper start - replace light engine impl @@ -4550,8 +4549,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start - replace light engine impl + protected final ChunkAccess getChunk(final int chunkX, final int chunkZ) { + return ((ServerLevel)this.theLightEngine.getWorld()).getChunkSource().getChunkAtImmediately(chunkX, chunkZ); - } - ++ } ++ + protected long relightCounter; + + public int relight(java.util.Set chunks_param, @@ -4674,18 +4673,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (sky == 15) return 15; + final int block = this.theLightEngine.getBlockReader().getLightValue(pos); + return Math.max(sky, block); -+ } + } + // Paper end - replace light engine imp -+ + @Override public void close() { - } @@ -0,0 +0,0 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl @Override public void checkBlock(BlockPos pos) { - BlockPos blockPos = pos.immutable(); -- this.addTask(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ()), ThreadedLevelLightEngine.TaskType.POST_UPDATE, Util.name(() -> { +- this.addTask(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ()), ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> { - super.checkBlock(blockPos); - }, () -> { - return "checkBlock " + blockPos; @@ -4722,15 +4720,23 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } @Override - public void enableLightSources(ChunkPos pos, boolean retainData) { + public void propagateLightSources(ChunkPos chunkPos) { + if (true) return; // Paper - replace light engine impl - this.addTask(pos.x, pos.z, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> { - super.enableLightSources(pos, retainData); + this.addTask(chunkPos.x, chunkPos.z, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> { + super.propagateLightSources(chunkPos); }, () -> { @@ -0,0 +0,0 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl @Override - public void queueSectionData(LightLayer lightType, SectionPos pos, @Nullable DataLayer nibbles, boolean nonEdge) { + public void setLightEnabled(ChunkPos pos, boolean retainData) { ++ if (true) return; // Paper - replace light engine impl + this.addTask(pos.x, pos.z, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> { + super.setLightEnabled(pos, retainData); + }, () -> { +@@ -0,0 +0,0 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl + + @Override + public void queueSectionData(LightLayer lightType, SectionPos pos, @Nullable DataLayer nibbles) { + if (true) return; // Paper - replace light engine impl this.addTask(pos.x(), pos.z(), () -> { return 0; @@ -4746,6 +4752,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl } + public CompletableFuture initializeLight(ChunkAccess chunk, boolean bl) { ++ if (true) return CompletableFuture.completedFuture(chunk); // Paper - replace light engine impl + ChunkPos chunkPos = chunk.getPos(); + this.addTask(chunkPos.x, chunkPos.z, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> { + LevelChunkSection[] levelChunkSections = chunk.getSections(); +@@ -0,0 +0,0 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl + } + public CompletableFuture lightChunk(ChunkAccess chunk, boolean excludeBlocks) { + // Paper start - replace light engine impl + if (true) { @@ -4794,7 +4808,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } objectListIterator.back(j); -- super.runUpdates(Integer.MAX_VALUE, true, true); +- super.runLightUpdates(); + this.theLightEngine.propagateChanges(); // Paper - rewrite light engine for(int var5 = 0; objectListIterator.hasNext() && var5 < i; ++var5) { @@ -4816,13 +4830,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java +++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java @@ -0,0 +0,0 @@ public abstract class BlockBehaviour implements FeatureElement { - this.emissiveRendering = blockbase_info.emissiveRendering; - this.offsetFunction = blockbase_info.offsetFunction; this.spawnParticlesOnBreak = blockbase_info.spawnParticlesOnBreak; + this.instrument = blockbase_info.instrument; + this.replaceable = blockbase_info.replaceable; + this.conditionallyFullOpaque = this.isOpaque() & this.isTransparentOnSomeFaces(); // Paper } - // Paper start + private boolean calculateSolid() { @@ -0,0 +0,0 @@ public abstract class BlockBehaviour implements FeatureElement { return this.shapeExceedsCube; } @@ -4848,8 +4862,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.shapeExceedsCube = this.cache == null || this.cache.largeCollisionShape; // Paper - moved from actual method to here + this.opacityIfCached = this.cache == null || this.isConditionallyFullOpaque() ? -1 : this.cache.lightBlock; // Paper - starlight - cache opacity for light + this.legacySolid = this.calculateSolid(); } - diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java @@ -4900,7 +4914,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end - rewrite light engine - public ChunkAccess(ChunkPos pos, UpgradeData upgradeData, LevelHeightAccessor heightLimitView, Registry biome, long inhabitedTime, @Nullable LevelChunkSection[] sectionArrayInitializer, @Nullable BlendingData blendingData) { + public ChunkAccess(ChunkPos pos, UpgradeData upgradeData, LevelHeightAccessor heightLimitView, Registry biomeRegistry, long inhabitedTime, @Nullable LevelChunkSection[] sectionArray, @Nullable BlendingData blendingData) { this.locX = pos.x; this.locZ = pos.z; // Paper - reduce need for field lookups diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java b/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 @@ -4974,8 +4988,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java @@ -0,0 +0,0 @@ public class ImposterProtoChunk extends ProtoChunk { - private final LevelChunk wrapped; - private final boolean allowWrites; + this.allowWrites = propagateToWrapped; + } + // Paper start - rewrite light engine + @Override @@ -5019,9 +5033,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end - rewrite light engine + - public ImposterProtoChunk(LevelChunk wrapped, boolean bl) { - super(wrapped.getPos(), UpgradeData.EMPTY, wrapped.levelHeightAccessor, wrapped.getLevel().registryAccess().registryOrThrow(Registries.BIOME), wrapped.getBlendingData()); - this.wrapped = wrapped; + @Nullable + @Override + public BlockEntity getBlockEntity(BlockPos pos) { diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java @@ -5035,8 +5049,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.setSkyNibbles(ca.spottedleaf.starlight.common.light.StarLightEngine.getFilledEmptyLight(world)); + // Paper end - rewrite light engine this.tickersInLevel = Maps.newHashMap(); - this.clientLightReady = false; this.level = (ServerLevel) world; // CraftBukkit - type + this.gameEventListenerRegistrySections = new Int2ObjectOpenHashMap(); @@ -0,0 +0,0 @@ public class LevelChunk extends ChunkAccess { public LevelChunk(ServerLevel world, ProtoChunk protoChunk, @Nullable LevelChunk.PostLoadProcessor entityLoader) { @@ -5089,7 +5103,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public static final String SKY_LIGHT_TAG = "SkyLight"; + // Paper start - replace light engine impl -+ private static final int STARLIGHT_LIGHT_VERSION = 8; ++ private static final int STARLIGHT_LIGHT_VERSION = 9; + + private static final String BLOCKLIGHT_STATE_TAG = "starlight.blocklight_state"; + private static final String SKYLIGHT_STATE_TAG = "starlight.skylight_state"; @@ -5110,7 +5124,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 LevelChunkSection[] achunksection = new LevelChunkSection[i]; boolean flag1 = world.dimensionType().hasSkyLight(); ServerChunkCache chunkproviderserver = world.getChunkSource(); - LevelLightEngine lightengine = chunkproviderserver.getLightEngine(); + LevelLightEngine levellightengine = chunkproviderserver.getLightEngine(); + // Paper start + ca.spottedleaf.starlight.common.light.SWMRNibbleArray[] blockNibbles = ca.spottedleaf.starlight.common.light.StarLightEngine.getFilledEmptyLight(world); + ca.spottedleaf.starlight.common.light.SWMRNibbleArray[] skyNibbles = ca.spottedleaf.starlight.common.light.StarLightEngine.getFilledEmptyLight(world); @@ -5136,7 +5150,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - if (flag3 || flag4) { - if (!flag2) { -- lightengine.retainData(chunkPos, true); +- levellightengine.retainData(chunkPos, true); - flag2 = true; - } - @@ -5146,7 +5160,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + int y = sectionData.getByte("Y"); + // Paper end - rewrite the light engine if (flag3) { -- lightengine.queueSectionData(LightLayer.BLOCK, SectionPos.of(chunkPos, b0), new DataLayer(nbttagcompound1.getByteArray("BlockLight")), true); +- levellightengine.queueSectionData(LightLayer.BLOCK, SectionPos.of(chunkPos, b0), new DataLayer(nbttagcompound1.getByteArray("BlockLight"))); + // Paper start - rewrite the light engine + // this is where our diff is + blockNibbles[y - minSection] = new ca.spottedleaf.starlight.common.light.SWMRNibbleArray(sectionData.getByteArray("BlockLight").clone(), sectionData.getInt(BLOCKLIGHT_STATE_TAG)); // clone for data safety @@ -5156,7 +5170,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } if (flag4) { -- lightengine.queueSectionData(LightLayer.SKY, SectionPos.of(chunkPos, b0), new DataLayer(nbttagcompound1.getByteArray("SkyLight")), true); +- levellightengine.queueSectionData(LightLayer.SKY, SectionPos.of(chunkPos, b0), new DataLayer(nbttagcompound1.getByteArray("SkyLight"))); + // Paper start - rewrite the light engine + // we store under the same key so mod programs editing nbt + // can still read the data, hopefully.