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