From eda8abf55ca08ef21f9e892aa31eda4372c79b8c Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Sun, 13 Mar 2022 11:29:34 +0100 Subject: [PATCH] Handle new biomes for <1.16 clients Fixes #422 --- .../packets/BlockItemPackets1_16.java | 34 ++-- .../Protocol1_16_1To1_16_2.java | 2 + .../data/BiomeMappings.java | 149 ++++++++++++++++++ .../packets/EntityPackets1_16_2.java | 29 +++- .../storage/BiomeStorage.java | 44 ++++++ .../viabackwards/data/biome-mappings.json | 26 +++ 6 files changed, 273 insertions(+), 11 deletions(-) create mode 100644 common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_16_1to1_16_2/data/BiomeMappings.java create mode 100644 common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_16_1to1_16_2/storage/BiomeStorage.java create mode 100644 common/src/main/resources/assets/viabackwards/data/biome-mappings.json diff --git a/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_15_2to1_16/packets/BlockItemPackets1_16.java b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_15_2to1_16/packets/BlockItemPackets1_16.java index 96cc28a6..c6d4efba 100644 --- a/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_15_2to1_16/packets/BlockItemPackets1_16.java +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_15_2to1_16/packets/BlockItemPackets1_16.java @@ -17,16 +17,19 @@ */ package com.viaversion.viabackwards.protocol.protocol1_15_2to1_16.packets; +import com.viaversion.viabackwards.ViaBackwards; import com.viaversion.viabackwards.api.rewriters.EnchantmentRewriter; import com.viaversion.viabackwards.api.rewriters.MapColorRewriter; import com.viaversion.viabackwards.protocol.protocol1_15_2to1_16.Protocol1_15_2To1_16; import com.viaversion.viabackwards.protocol.protocol1_15_2to1_16.data.MapColorRewrites; +import com.viaversion.viabackwards.protocol.protocol1_16_1to1_16_2.storage.BiomeStorage; import com.viaversion.viaversion.api.minecraft.Position; import com.viaversion.viaversion.api.minecraft.chunks.Chunk; import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection; import com.viaversion.viaversion.api.minecraft.item.Item; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper; +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.types.UUIDIntArrayType; import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag; @@ -170,15 +173,28 @@ public class BlockItemPackets1_16 extends com.viaversion.viabackwards.api.rewrit } if (chunk.isBiomeData()) { - for (int i = 0; i < 1024; i++) { - int biome = chunk.getBiomeData()[i]; - switch (biome) { - case 170: // new nether biomes - case 171: - case 172: - case 173: - chunk.getBiomeData()[i] = 8; - break; + if (wrapper.user().getProtocolInfo().getServerProtocolVersion() >= ProtocolVersion.v1_16_2.getVersion()) { + BiomeStorage biomeStorage = wrapper.user().get(BiomeStorage.class); + for (int i = 0; i < 1024; i++) { + int biome = chunk.getBiomeData()[i]; + int legacyBiome = biomeStorage.legacyBiome(biome); + if (legacyBiome == -1) { + ViaBackwards.getPlatform().getLogger().warning("Biome sent that does not exist in the biome registry: " + biome); + legacyBiome = 1; + } + chunk.getBiomeData()[i] = legacyBiome; + } + } else { + for (int i = 0; i < 1024; i++) { + int biome = chunk.getBiomeData()[i]; + switch (biome) { + case 170: // new nether biomes + case 171: + case 172: + case 173: + chunk.getBiomeData()[i] = 8; + break; + } } } } diff --git a/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_16_1to1_16_2/Protocol1_16_1To1_16_2.java b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_16_1to1_16_2/Protocol1_16_1To1_16_2.java index dec24430..a1abcc62 100644 --- a/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_16_1to1_16_2/Protocol1_16_1To1_16_2.java +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_16_1to1_16_2/Protocol1_16_1To1_16_2.java @@ -24,6 +24,7 @@ import com.viaversion.viabackwards.api.rewriters.TranslatableRewriter; import com.viaversion.viabackwards.protocol.protocol1_16_1to1_16_2.data.CommandRewriter1_16_2; import com.viaversion.viabackwards.protocol.protocol1_16_1to1_16_2.packets.BlockItemPackets1_16_2; import com.viaversion.viabackwards.protocol.protocol1_16_1to1_16_2.packets.EntityPackets1_16_2; +import com.viaversion.viabackwards.protocol.protocol1_16_1to1_16_2.storage.BiomeStorage; import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.minecraft.RegistryType; import com.viaversion.viaversion.api.minecraft.entities.Entity1_16_2Types; @@ -136,6 +137,7 @@ public class Protocol1_16_1To1_16_2 extends BackwardsProtocol. + */ +package com.viaversion.viabackwards.protocol.protocol1_16_1to1_16_2.data; + +import com.viaversion.viabackwards.ViaBackwards; +import com.viaversion.viabackwards.api.data.VBMappingDataLoader; +import com.viaversion.viaversion.api.Via; +import com.viaversion.viaversion.libs.fastutil.objects.Object2IntMap; +import com.viaversion.viaversion.libs.fastutil.objects.Object2IntOpenHashMap; +import com.viaversion.viaversion.libs.gson.JsonElement; +import com.viaversion.viaversion.libs.gson.JsonObject; + +import java.util.Map; + +public final class BiomeMappings { + + private static final Object2IntMap MODERN_TO_LEGACY_ID = new Object2IntOpenHashMap<>(); + private static final Object2IntMap LEGACY_BIOMES = new Object2IntOpenHashMap<>(); + + static { + LEGACY_BIOMES.defaultReturnValue(-1); + MODERN_TO_LEGACY_ID.defaultReturnValue(-1); + + add(0, "ocean"); + add(1, "plains"); + add(2, "desert"); + add(3, "mountains"); + add(4, "forest"); + add(5, "taiga"); + add(6, "swamp"); + add(7, "river"); + add(8, "nether"); + add(9, "the_end"); + add(10, "frozen_ocean"); + add(11, "frozen_river"); + add(12, "snowy_tundra"); + add(13, "snowy_mountains"); + add(14, "mushroom_fields"); + add(15, "mushroom_field_shore"); + add(16, "beach"); + add(17, "desert_hills"); + add(18, "wooded_hills"); + add(19, "taiga_hills"); + add(20, "mountain_edge"); + add(21, "jungle"); + add(22, "jungle_hills"); + add(23, "jungle_edge"); + add(24, "deep_ocean"); + add(25, "stone_shore"); + add(26, "snowy_beach"); + add(27, "birch_forest"); + add(28, "birch_forest_hills"); + add(29, "dark_forest"); + add(30, "snowy_taiga"); + add(31, "snowy_taiga_hills"); + add(32, "giant_tree_taiga"); + add(33, "giant_tree_taiga_hills"); + add(34, "wooded_mountains"); + add(35, "savanna"); + add(36, "savanna_plateau"); + add(37, "badlands"); + add(38, "wooded_badlands_plateau"); + add(39, "badlands_plateau"); + add(40, "small_end_islands"); + add(41, "end_midlands"); + add(42, "end_highlands"); + add(43, "end_barrens"); + add(44, "warm_ocean"); + add(45, "lukewarm_ocean"); + add(46, "cold_ocean"); + add(47, "deep_warm_ocean"); + add(48, "deep_lukewarm_ocean"); + add(49, "deep_cold_ocean"); + add(50, "deep_frozen_ocean"); + add(127, "the_void"); + add(129, "sunflower_plains"); + add(130, "desert_lakes"); + add(131, "gravelly_mountains"); + add(132, "flower_forest"); + add(133, "taiga_mountains"); + add(134, "swamp_hills"); + add(140, "ice_spikes"); + add(149, "modified_jungle"); + add(151, "modified_jungle_edge"); + add(155, "tall_birch_forest"); + add(156, "tall_birch_hills"); + add(157, "dark_forest_hills"); + add(158, "snowy_taiga_mountains"); + add(160, "giant_spruce_taiga"); + add(161, "giant_spruce_taiga_hills"); + add(162, "modified_gravelly_mountains"); + add(163, "shattered_savanna"); + add(164, "shattered_savanna_plateau"); + add(165, "eroded_badlands"); + add(166, "modified_wooded_badlands_plateau"); + add(167, "modified_badlands_plateau"); + add(168, "bamboo_jungle"); + add(169, "bamboo_jungle_hills"); + + // Include the legacy biomes themselves + for (final Object2IntMap.Entry entry : LEGACY_BIOMES.object2IntEntrySet()) { + MODERN_TO_LEGACY_ID.put("minecraft:" + entry.getKey(), entry.getIntValue()); + } + + final JsonObject mappings = VBMappingDataLoader.loadFromDataDir("biome-mappings.json"); + for (final Map.Entry entry : mappings.entrySet()) { + final int legacyBiome = LEGACY_BIOMES.getInt(entry.getValue().getAsString()); + if (legacyBiome == -1) { + ViaBackwards.getPlatform().getLogger().warning("Unknown legacy biome: " + entry.getValue().getAsString()); + continue; + } + + MODERN_TO_LEGACY_ID.put(entry.getKey(), legacyBiome); + } + } + + private static void add(final int id, final String biome) { + LEGACY_BIOMES.put(biome, id); + } + + public static int toLegacyBiome(String biome) { + if (biome.indexOf(':') == -1) { + biome = "minecraft:" + biome; + } + final int legacyBiome = MODERN_TO_LEGACY_ID.getInt(biome); + if (legacyBiome == -1) { + if (!Via.getConfig().isSuppressConversionWarnings()) { + ViaBackwards.getPlatform().getLogger().warning("Biome with id " + biome + " has no legacy biome mapping (custom datapack?)"); + } + return 1; // Plains + } + return legacyBiome; + } +} diff --git a/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_16_1to1_16_2/packets/EntityPackets1_16_2.java b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_16_1to1_16_2/packets/EntityPackets1_16_2.java index 0727349e..dbbc261d 100644 --- a/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_16_1to1_16_2/packets/EntityPackets1_16_2.java +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_16_1to1_16_2/packets/EntityPackets1_16_2.java @@ -18,16 +18,22 @@ package com.viaversion.viabackwards.protocol.protocol1_16_1to1_16_2.packets; import com.google.common.collect.Sets; +import com.viaversion.viabackwards.ViaBackwards; import com.viaversion.viabackwards.api.rewriters.EntityRewriter; import com.viaversion.viabackwards.protocol.protocol1_16_1to1_16_2.Protocol1_16_1To1_16_2; +import com.viaversion.viabackwards.protocol.protocol1_16_1to1_16_2.storage.BiomeStorage; import com.viaversion.viaversion.api.minecraft.entities.Entity1_16Types; import com.viaversion.viaversion.api.minecraft.entities.Entity1_16_2Types; import com.viaversion.viaversion.api.minecraft.entities.EntityType; import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper; +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.types.version.Types1_16; import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag; +import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag; +import com.viaversion.viaversion.libs.opennbt.tag.builtin.NumberTag; import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag; +import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag; import com.viaversion.viaversion.protocols.protocol1_16_2to1_16_1.ClientboundPackets1_16_2; import com.viaversion.viaversion.protocols.protocol1_16to1_15_2.packets.EntityPackets; @@ -36,6 +42,7 @@ import java.util.Set; public class EntityPackets1_16_2 extends EntityRewriter { private final Set oldDimensions = Sets.newHashSet("minecraft:overworld", "minecraft:the_nether", "minecraft:the_end"); + private boolean warned; public EntityPackets1_16_2(Protocol1_16_1To1_16_2 protocol) { super(protocol); @@ -66,8 +73,25 @@ public class EntityPackets1_16_2 extends EntityRewriter map(Type.BYTE); // Previous Gamemode map(Type.STRING_ARRAY); // World List handler(wrapper -> { + CompoundTag registry = wrapper.read(Type.NBT); + if (wrapper.user().getProtocolInfo().getProtocolVersion() <= ProtocolVersion.v1_15_2.getVersion()) { + // Store biomes for <1.16 client handling + CompoundTag biomeRegistry = registry.get("minecraft:worldgen/biome"); + ListTag biomes = biomeRegistry.get("value"); + BiomeStorage biomeStorage = wrapper.user().get(BiomeStorage.class); + biomeStorage.clear(); + for (Tag biome : biomes) { + CompoundTag biomeCompound = (CompoundTag) biome; + StringTag name = biomeCompound.get("name"); + NumberTag id = biomeCompound.get("id"); + biomeStorage.addBiome(name.getValue(), id.asInt()); + } + } else if (!warned) { + warned = true; + ViaBackwards.getPlatform().getLogger().warning("1.16 and 1.16.1 clients are only partially supported and may have wrong biomes displayed."); + } + // Just screw the registry and write the defaults for 1.16 and 1.16.1 clients - wrapper.read(Type.NBT); wrapper.write(Type.NBT, EntityPackets.DIMENSIONS_TAG); CompoundTag dimensionData = wrapper.read(Type.NBT); @@ -98,7 +122,8 @@ public class EntityPackets1_16_2 extends EntityRewriter private String getDimensionFromData(CompoundTag dimensionData) { // This may technically break other custom dimension settings for 1.16/1.16.1 clients, so those cases are considered semi "unsupported" here StringTag effectsLocation = dimensionData.get("effects"); - return effectsLocation != null && oldDimensions.contains(effectsLocation.getValue()) ? effectsLocation.getValue() : "minecraft:overworld"; + return effectsLocation != null && oldDimensions.contains(effectsLocation.getValue()) ? + effectsLocation.getValue() : "minecraft:overworld"; } @Override diff --git a/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_16_1to1_16_2/storage/BiomeStorage.java b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_16_1to1_16_2/storage/BiomeStorage.java new file mode 100644 index 00000000..350c20ff --- /dev/null +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_16_1to1_16_2/storage/BiomeStorage.java @@ -0,0 +1,44 @@ +/* + * This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards + * Copyright (C) 2016-2022 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viabackwards.protocol.protocol1_16_1to1_16_2.storage; + +import com.viaversion.viabackwards.protocol.protocol1_16_1to1_16_2.data.BiomeMappings; +import com.viaversion.viaversion.api.connection.StorableObject; +import com.viaversion.viaversion.libs.fastutil.ints.Int2IntMap; +import com.viaversion.viaversion.libs.fastutil.ints.Int2IntOpenHashMap; + +public final class BiomeStorage implements StorableObject { + + private final Int2IntMap modernToLegacyBiomes = new Int2IntOpenHashMap(); + + public BiomeStorage() { + modernToLegacyBiomes.defaultReturnValue(-1); + } + + public void addBiome(final String biome, final int id) { + modernToLegacyBiomes.put(id, BiomeMappings.toLegacyBiome(biome)); + } + + public int legacyBiome(final int biome) { + return modernToLegacyBiomes.get(biome); + } + + public void clear() { + modernToLegacyBiomes.clear(); + } +} diff --git a/common/src/main/resources/assets/viabackwards/data/biome-mappings.json b/common/src/main/resources/assets/viabackwards/data/biome-mappings.json new file mode 100644 index 00000000..6416d4cf --- /dev/null +++ b/common/src/main/resources/assets/viabackwards/data/biome-mappings.json @@ -0,0 +1,26 @@ +{ + "minecraft:nether_wastes": "nether", + "minecraft:soul_sand_valley": "nether", + "minecraft:crimson_forest": "nether", + "minecraft:warped_forest": "nether", + "minecraft:basalt_deltas": "nether", + "minecraft:dripstone_caves": "mountains", + "minecraft:lush_caves": "mountains", + "minecraft:meadow": "plains", + "minecraft:grove": "snowy_mountains", + "minecraft:snowy_slopes": "snowy_mountains", + "minecraft:frozen_peaks": "snowy_mountains", + "minecraft:jagged_peaks": "mountains", + "minecraft:stony_peaks": "mountains", + "minecraft:windswept_hills": "mountains", + "minecraft:snowy_plains": "snowy_tundra", + "minecraft:sparse_jungle": "jungle_edge", + "minecraft:stony_shore": "stone_shore", + "minecraft:old_growth_pine_taiga": "giant_spruce_taiga", + "minecraft:windswept_forest": "forest", + "minecraft:wooded_badlands": "wooded_badlands_plateau", + "minecraft:windswept_gravelly_hills": "gravelly_mountains", + "minecraft:old_growth_birch_forest": "tall_birch_forest", + "minecraft:old_growth_spruce_taiga": "giant_spruce_taiga", + "minecraft:windswept_savanna": "shattered_savanna" +} \ No newline at end of file