This commit is contained in:
Nassim Jahnke 2024-03-27 20:48:12 +01:00
parent fd4db24d44
commit a2c1c52f51
No known key found for this signature in database
GPG Key ID: EF6771C01F6EF02F
16 changed files with 111 additions and 15 deletions

View File

@ -59,6 +59,7 @@ public final class StructuredDataKey<T> {
public static final StructuredDataKey<Integer> DAMAGE = new StructuredDataKey<>("damage", Type.VAR_INT); public static final StructuredDataKey<Integer> DAMAGE = new StructuredDataKey<>("damage", Type.VAR_INT);
public static final StructuredDataKey<Unbreakable> UNBREAKABLE = new StructuredDataKey<>("unbreakable", Unbreakable.TYPE); public static final StructuredDataKey<Unbreakable> UNBREAKABLE = new StructuredDataKey<>("unbreakable", Unbreakable.TYPE);
public static final StructuredDataKey<Tag> CUSTOM_NAME = new StructuredDataKey<>("custom_name", Type.TAG); public static final StructuredDataKey<Tag> CUSTOM_NAME = new StructuredDataKey<>("custom_name", Type.TAG);
public static final StructuredDataKey<Tag> ITEM_NAME = new StructuredDataKey<>("item_name", Type.TAG);
public static final StructuredDataKey<Tag[]> LORE = new StructuredDataKey<>("lore", Type.TAG_ARRAY); public static final StructuredDataKey<Tag[]> LORE = new StructuredDataKey<>("lore", Type.TAG_ARRAY);
public static final StructuredDataKey<Integer> RARITY = new StructuredDataKey<>("rarity", Type.VAR_INT); public static final StructuredDataKey<Integer> RARITY = new StructuredDataKey<>("rarity", Type.VAR_INT);
public static final StructuredDataKey<Enchantments> ENCHANTMENTS = new StructuredDataKey<>("enchantments", Enchantments.TYPE); public static final StructuredDataKey<Enchantments> ENCHANTMENTS = new StructuredDataKey<>("enchantments", Enchantments.TYPE);
@ -93,6 +94,7 @@ public final class StructuredDataKey<T> {
public static final StructuredDataKey<CompoundTag> BUCKET_ENTITY_DATA = new StructuredDataKey<>("bucket_entity_data", Type.COMPOUND_TAG); public static final StructuredDataKey<CompoundTag> BUCKET_ENTITY_DATA = new StructuredDataKey<>("bucket_entity_data", Type.COMPOUND_TAG);
public static final StructuredDataKey<CompoundTag> BLOCK_ENTITY_DATA = new StructuredDataKey<>("block_entity_data", Type.COMPOUND_TAG); public static final StructuredDataKey<CompoundTag> BLOCK_ENTITY_DATA = new StructuredDataKey<>("block_entity_data", Type.COMPOUND_TAG);
public static final StructuredDataKey<Holder<Instrument>> INSTRUMENT = new StructuredDataKey<>("instrument", Instrument.TYPE); public static final StructuredDataKey<Holder<Instrument>> INSTRUMENT = new StructuredDataKey<>("instrument", Instrument.TYPE);
public static final StructuredDataKey<Integer> OMINOUS_BOTTLE_AMPLIFIER = new StructuredDataKey<>("ominous_bottle_amplifier", Type.VAR_INT);
public static final StructuredDataKey<Tag> RECIPES = new StructuredDataKey<>("recipes", Type.TAG); public static final StructuredDataKey<Tag> RECIPES = new StructuredDataKey<>("recipes", Type.TAG);
public static final StructuredDataKey<LodestoneTracker> LODESTONE_TRACKER = new StructuredDataKey<>("lodestone_tracker", LodestoneTracker.TYPE); public static final StructuredDataKey<LodestoneTracker> LODESTONE_TRACKER = new StructuredDataKey<>("lodestone_tracker", LodestoneTracker.TYPE);
public static final StructuredDataKey<FireworkExplosion> FIREWORK_EXPLOSION = new StructuredDataKey<>("firework_explosion", FireworkExplosion.TYPE); public static final StructuredDataKey<FireworkExplosion> FIREWORK_EXPLOSION = new StructuredDataKey<>("firework_explosion", FireworkExplosion.TYPE);

View File

@ -44,6 +44,7 @@ public enum EntityTypes1_20_5 implements EntityType {
TNT(ENTITY), TNT(ENTITY),
SHULKER_BULLET(ENTITY), SHULKER_BULLET(ENTITY),
FISHING_BOBBER(ENTITY), FISHING_BOBBER(ENTITY),
OMINOUS_ITEM_SPAWNER(ENTITY),
LIVINGENTITY(ENTITY, null), LIVINGENTITY(ENTITY, null),
ARMOR_STAND(LIVINGENTITY), ARMOR_STAND(LIVINGENTITY),

View File

@ -83,7 +83,7 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
public static final ProtocolVersion v1_20 = register(763, "1.20/1.20.1", new SubVersionRange("1.20", 0, 1)); public static final ProtocolVersion v1_20 = register(763, "1.20/1.20.1", new SubVersionRange("1.20", 0, 1));
public static final ProtocolVersion v1_20_2 = register(764, "1.20.2"); public static final ProtocolVersion v1_20_2 = register(764, "1.20.2");
public static final ProtocolVersion v1_20_3 = register(765, "1.20.3/1.20.4", new SubVersionRange("1.20", 3, 4)); public static final ProtocolVersion v1_20_3 = register(765, "1.20.3/1.20.4", new SubVersionRange("1.20", 3, 4));
public static final ProtocolVersion v1_20_5 = register(766, 181, "1.20.5"); public static final ProtocolVersion v1_20_5 = register(766, 182, "1.20.5");
public static final ProtocolVersion unknown = new ProtocolVersion(VersionType.SPECIAL, -1, -1, "UNKNOWN", null); public static final ProtocolVersion unknown = new ProtocolVersion(VersionType.SPECIAL, -1, -1, "UNKNOWN", null);
public static ProtocolVersion register(int version, String name) { public static ProtocolVersion register(int version, String name) {

View File

@ -194,6 +194,7 @@ public abstract class Type<T> implements ByteBufReader<T>, ByteBufWriter<T> {
public static final BitSetType PROFILE_ACTIONS_ENUM = new BitSetType(6); public static final BitSetType PROFILE_ACTIONS_ENUM = new BitSetType(6);
public static final ByteArrayType SIGNATURE_BYTES = new ByteArrayType(256); public static final ByteArrayType SIGNATURE_BYTES = new ByteArrayType(256);
public static final BitSetType ACKNOWLEDGED_BIT_SET = new BitSetType(20);
public static final ByteArrayType.OptionalByteArrayType OPTIONAL_SIGNATURE_BYTES = new ByteArrayType.OptionalByteArrayType(256); public static final ByteArrayType.OptionalByteArrayType OPTIONAL_SIGNATURE_BYTES = new ByteArrayType.OptionalByteArrayType(256);
public static final Type<RegistryEntry> REGISTRY_ENTRY = new RegistryEntryType(); public static final Type<RegistryEntry> REGISTRY_ENTRY = new RegistryEntryType();

View File

@ -62,7 +62,6 @@ import java.util.concurrent.ThreadLocalRandom;
public final class Protocol1_19_3To1_19_1 extends AbstractProtocol<ClientboundPackets1_19_1, ClientboundPackets1_19_3, ServerboundPackets1_19_1, ServerboundPackets1_19_3> { public final class Protocol1_19_3To1_19_1 extends AbstractProtocol<ClientboundPackets1_19_1, ClientboundPackets1_19_3, ServerboundPackets1_19_1, ServerboundPackets1_19_3> {
public static final MappingData MAPPINGS = new MappingDataBase("1.19", "1.19.3"); public static final MappingData MAPPINGS = new MappingDataBase("1.19", "1.19.3");
private static final BitSetType ACKNOWLEDGED_BIT_SET_TYPE = new BitSetType(20);
private static final UUID ZERO_UUID = new UUID(0, 0); private static final UUID ZERO_UUID = new UUID(0, 0);
private static final byte[] EMPTY_BYTES = new byte[0]; private static final byte[] EMPTY_BYTES = new byte[0];
private final EntityPackets entityRewriter = new EntityPackets(this); private final EntityPackets entityRewriter = new EntityPackets(this);
@ -247,7 +246,7 @@ public final class Protocol1_19_3To1_19_1 extends AbstractProtocol<ClientboundPa
wrapper.write(Type.OPTIONAL_PLAYER_MESSAGE_SIGNATURE, null); // No last unacknowledged wrapper.write(Type.OPTIONAL_PLAYER_MESSAGE_SIGNATURE, null); // No last unacknowledged
}); });
read(Type.VAR_INT); // Offset read(Type.VAR_INT); // Offset
read(ACKNOWLEDGED_BIT_SET_TYPE); // Acknowledged read(Type.ACKNOWLEDGED_BIT_SET); // Acknowledged
} }
}); });
registerServerbound(ServerboundPackets1_19_3.CHAT_MESSAGE, new PacketHandlers() { registerServerbound(ServerboundPackets1_19_3.CHAT_MESSAGE, new PacketHandlers() {
@ -283,7 +282,7 @@ public final class Protocol1_19_3To1_19_1 extends AbstractProtocol<ClientboundPa
wrapper.write(Type.OPTIONAL_PLAYER_MESSAGE_SIGNATURE, null); // No last unacknowledged wrapper.write(Type.OPTIONAL_PLAYER_MESSAGE_SIGNATURE, null); // No last unacknowledged
}); });
read(Type.VAR_INT); // Offset read(Type.VAR_INT); // Offset
read(ACKNOWLEDGED_BIT_SET_TYPE); // Acknowledged read(Type.ACKNOWLEDGED_BIT_SET); // Acknowledged
} }
}); });

View File

@ -47,6 +47,7 @@ import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.packet.Serverb
import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.packet.ServerboundPackets1_20_5; import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.packet.ServerboundPackets1_20_5;
import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.rewriter.BlockItemPacketRewriter1_20_5; import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.rewriter.BlockItemPacketRewriter1_20_5;
import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.rewriter.EntityPacketRewriter1_20_5; import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.rewriter.EntityPacketRewriter1_20_5;
import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.storage.AcknowledgedMessagesStorage;
import com.viaversion.viaversion.rewriter.SoundRewriter; import com.viaversion.viaversion.rewriter.SoundRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter; import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter; import com.viaversion.viaversion.rewriter.TagRewriter;
@ -90,6 +91,23 @@ public final class Protocol1_20_5To1_20_3 extends AbstractProtocol<ClientboundPa
wrapper.read(Type.BOOLEAN); // Enforces secure chat - moved to join game wrapper.read(Type.BOOLEAN); // Enforces secure chat - moved to join game
}); });
registerClientbound(ClientboundPackets1_20_3.PLAYER_CHAT, wrapper -> wrapper.user().get(AcknowledgedMessagesStorage.class).add());
registerServerbound(ServerboundPackets1_20_5.CHAT_MESSAGE, wrapper -> wrapper.user().get(AcknowledgedMessagesStorage.class).clearOffset());
registerServerbound(ServerboundPackets1_20_5.CHAT_ACK, wrapper -> wrapper.user().get(AcknowledgedMessagesStorage.class).clearOffset());
registerServerbound(ServerboundPackets1_20_5.CHAT_COMMAND_SIGNED, ServerboundPackets1_20_3.CHAT_COMMAND);
registerServerbound(ServerboundPackets1_20_5.CHAT_COMMAND, wrapper -> {
wrapper.passthrough(Type.STRING); // Command
final AcknowledgedMessagesStorage messagesStorage = wrapper.user().get(AcknowledgedMessagesStorage.class);
wrapper.write(Type.LONG, System.currentTimeMillis()); // Timestamp
wrapper.write(Type.LONG, 0L); // Salt
wrapper.write(Type.VAR_INT, 0); // No signatures
wrapper.write(Type.VAR_INT, messagesStorage.offset()); // TODO Fix offset
wrapper.write(Type.ACKNOWLEDGED_BIT_SET, messagesStorage.toAck());
messagesStorage.clearOffset();
});
registerClientbound(ClientboundPackets1_20_3.START_CONFIGURATION, wrapper -> wrapper.user().put(new AcknowledgedMessagesStorage()));
new CommandRewriter1_19_4<>(this).registerDeclareCommands1_19(ClientboundPackets1_20_3.DECLARE_COMMANDS); new CommandRewriter1_19_4<>(this).registerDeclareCommands1_19(ClientboundPackets1_20_3.DECLARE_COMMANDS);
cancelServerbound(State.LOGIN, ServerboundLoginPackets.COOKIE_RESPONSE.getId()); cancelServerbound(State.LOGIN, ServerboundLoginPackets.COOKIE_RESPONSE.getId());
@ -108,6 +126,7 @@ public final class Protocol1_20_5To1_20_3 extends AbstractProtocol<ClientboundPa
.reader("block", ParticleType.Readers.BLOCK) .reader("block", ParticleType.Readers.BLOCK)
.reader("block_marker", ParticleType.Readers.BLOCK) .reader("block_marker", ParticleType.Readers.BLOCK)
.reader("dust", ParticleType.Readers.DUST) .reader("dust", ParticleType.Readers.DUST)
.reader("dust_pillar", ParticleType.Readers.BLOCK)
.reader("falling_dust", ParticleType.Readers.BLOCK) .reader("falling_dust", ParticleType.Readers.BLOCK)
.reader("dust_color_transition", ParticleType.Readers.DUST_TRANSITION) .reader("dust_color_transition", ParticleType.Readers.DUST_TRANSITION)
.reader("item", ParticleType.Readers.ITEM1_20_2) .reader("item", ParticleType.Readers.ITEM1_20_2)
@ -133,7 +152,8 @@ public final class Protocol1_20_5To1_20_3 extends AbstractProtocol<ClientboundPa
.add(StructuredDataKey.FIREWORKS).add(StructuredDataKey.PROFILE).add(StructuredDataKey.NOTE_BLOCK_SOUND) .add(StructuredDataKey.FIREWORKS).add(StructuredDataKey.PROFILE).add(StructuredDataKey.NOTE_BLOCK_SOUND)
.add(StructuredDataKey.BANNER_PATTERNS).add(StructuredDataKey.BASE_COLOR).add(StructuredDataKey.POT_DECORATIONS) .add(StructuredDataKey.BANNER_PATTERNS).add(StructuredDataKey.BASE_COLOR).add(StructuredDataKey.POT_DECORATIONS)
.add(StructuredDataKey.CONTAINER).add(StructuredDataKey.BLOCK_STATE).add(StructuredDataKey.BEES) .add(StructuredDataKey.CONTAINER).add(StructuredDataKey.BLOCK_STATE).add(StructuredDataKey.BEES)
.add(StructuredDataKey.LOCK).add(StructuredDataKey.CONTAINER_LOOT).add(StructuredDataKey.TOOL); .add(StructuredDataKey.LOCK).add(StructuredDataKey.CONTAINER_LOOT).add(StructuredDataKey.TOOL)
.add(StructuredDataKey.ITEM_NAME).add(StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER);
tagRewriter.addTag(RegistryType.ITEM, "minecraft:dyeable", 853, 854, 855, 856, 1120); tagRewriter.addTag(RegistryType.ITEM, "minecraft:dyeable", 853, 854, 855, 856, 1120);
} }
@ -141,6 +161,7 @@ public final class Protocol1_20_5To1_20_3 extends AbstractProtocol<ClientboundPa
@Override @Override
public void init(final UserConnection connection) { public void init(final UserConnection connection) {
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_20_5.PLAYER)); addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_20_5.PLAYER));
connection.put(new AcknowledgedMessagesStorage());
} }
@Override @Override

View File

@ -37,7 +37,7 @@ public class MappingData extends MappingDataBase {
protected void loadExtras(final CompoundTag data) { protected void loadExtras(final CompoundTag data) {
super.loadExtras(data); super.loadExtras(data);
final CompoundTag extraMappings = MappingDataLoader.loadNBT("items-blocks-1.20.3.nbt"); final CompoundTag extraMappings = MappingDataLoader.INSTANCE.loadNBT("items-blocks-1.20.3.nbt");
items = new KeyMappings(extraMappings.getListTag("items", StringTag.class)); items = new KeyMappings(extraMappings.getListTag("items", StringTag.class));
blocks = new KeyMappings(extraMappings.getListTag("blocks", StringTag.class)); blocks = new KeyMappings(extraMappings.getListTag("blocks", StringTag.class));
} }

View File

@ -27,14 +27,15 @@ public enum ClientboundConfigurationPackets1_20_5 implements ClientboundPacket1_
FINISH_CONFIGURATION, // 0x03 FINISH_CONFIGURATION, // 0x03
KEEP_ALIVE, // 0x04 KEEP_ALIVE, // 0x04
PING, // 0x05 PING, // 0x05
REGISTRY_DATA, // 0x06 RESET_CHAT, // 0x06
RESOURCE_PACK_POP, // 0x07 REGISTRY_DATA, // 0x07
RESOURCE_PACK_PUSH, // 0x08 RESOURCE_PACK_POP, // 0x08
STORE_COOKIE, // 0x09 RESOURCE_PACK_PUSH, // 0x09
TRANSFER, // 0x0A STORE_COOKIE, // 0x0A
UPDATE_ENABLED_FEATURES, // 0x0B TRANSFER, // 0x0B
UPDATE_TAGS, // 0x0C UPDATE_ENABLED_FEATURES, // 0x0C
SELECT_KNOWN_PACKS; // 0x0D UPDATE_TAGS, // 0x0D
SELECT_KNOWN_PACKS; // 0x0E
@Override @Override
public int getId() { public int getId() {

View File

@ -24,6 +24,7 @@ public enum ServerboundPackets1_20_5 implements ServerboundPacket1_20_5 {
SET_DIFFICULTY, // 0x02 SET_DIFFICULTY, // 0x02
CHAT_ACK, // 0x03 CHAT_ACK, // 0x03
CHAT_COMMAND, // 0x04 CHAT_COMMAND, // 0x04
CHAT_COMMAND_SIGNED, // 0x04
CHAT_MESSAGE, // 0x05 CHAT_MESSAGE, // 0x05
CHAT_SESSION_UPDATE, // 0x06 CHAT_SESSION_UPDATE, // 0x06
CHUNK_BATCH_RECEIVED, // 0x07 CHUNK_BATCH_RECEIVED, // 0x07

View File

@ -64,6 +64,18 @@ public final class EntityPacketRewriter1_20_5 extends EntityRewriter<Clientbound
cacheDimensionData(wrapper.user(), registryData); cacheDimensionData(wrapper.user(), registryData);
trackBiomeSize(wrapper.user(), registryData); trackBiomeSize(wrapper.user(), registryData);
// Update format of height provider
final ListTag<CompoundTag> dimensionTypes = registryData.getCompoundTag("minecraft:dimension_type").getListTag("value", CompoundTag.class);
for (final CompoundTag dimensionType : dimensionTypes) {
final CompoundTag elementTag = dimensionType.getCompoundTag("element");
final CompoundTag monsterSpawnLightLevel = elementTag.getCompoundTag("monster_spawn_light_level");
if (monsterSpawnLightLevel != null) {
final CompoundTag value = monsterSpawnLightLevel.removeUnchecked("value");
monsterSpawnLightLevel.putInt("min_inclusive", value.getInt("min_inclusive"));
monsterSpawnLightLevel.putInt("max_inclusive", value.getInt("max_inclusive"));
}
}
for (final Map.Entry<String, Tag> entry : registryData.entrySet()) { for (final Map.Entry<String, Tag> entry : registryData.entrySet()) {
final CompoundTag entryTag = (CompoundTag) entry.getValue(); final CompoundTag entryTag = (CompoundTag) entry.getValue();
final String type = entryTag.getString("type"); final String type = entryTag.getString("type");

View File

@ -85,6 +85,12 @@ final class StructuredDataConverter {
} }
}); });
register(StructuredDataKey.CUSTOM_NAME, (data, tag) -> getDisplayTag(tag).putString("Name", ComponentUtil.tagToJsonString(data))); register(StructuredDataKey.CUSTOM_NAME, (data, tag) -> getDisplayTag(tag).putString("Name", ComponentUtil.tagToJsonString(data)));
register(StructuredDataKey.ITEM_NAME, (data, tag) -> {
final CompoundTag displayTag = tag.getCompoundTag("display");
if (displayTag != null && !displayTag.contains("Name")) {
displayTag.putString("Name", ComponentUtil.tagToJsonString(data));
}
});
register(StructuredDataKey.LORE, (data, tag) -> { register(StructuredDataKey.LORE, (data, tag) -> {
final ListTag<StringTag> lore = new ListTag<>(StringTag.class); final ListTag<StringTag> lore = new ListTag<>(StringTag.class);
for (final Tag loreEntry : data) { for (final Tag loreEntry : data) {
@ -448,6 +454,7 @@ final class StructuredDataConverter {
noop(StructuredDataKey.FOOD); noop(StructuredDataKey.FOOD);
noop(StructuredDataKey.FIRE_RESISTANT); noop(StructuredDataKey.FIRE_RESISTANT);
noop(StructuredDataKey.TOOL); noop(StructuredDataKey.TOOL);
noop(StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER);
} }
private static String toItemName(final int id) { private static String toItemName(final int id) {

View File

@ -0,0 +1,51 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 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 <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
import java.util.BitSet;
public final class AcknowledgedMessagesStorage implements StorableObject {
private static final int MAX_HISTORY = 20;
private final boolean[] trackedMessages = new boolean[MAX_HISTORY];
private int offset;
private int tail;
public void add() {
this.offset++;
this.trackedMessages[this.tail] = true;
this.tail = (this.tail + 1) % MAX_HISTORY;
}
public BitSet toAck() {
final BitSet acks = new BitSet(MAX_HISTORY);
for (int i = 0; i < MAX_HISTORY; i++) {
final int messageIndex = (this.tail + i) % MAX_HISTORY;
acks.set(i, this.trackedMessages[messageIndex]);
}
return acks;
}
public int offset() {
return this.offset;
}
public void clearOffset() {
this.offset = 0;
}
}

View File

@ -1,5 +1,5 @@
# Project properties - we put these here so they can be modified without causing a recompile of the build scripts # Project properties - we put these here so they can be modified without causing a recompile of the build scripts
projectVersion=4.10.0-24w12a-SNAPSHOT projectVersion=4.10.0-24w13a-SNAPSHOT
# Smile emoji # Smile emoji
mcVersions=1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2, 1.18.1, 1.18, 1.17.1, 1.17, 1.16.5, 1.16.4, 1.16.3, 1.16.2, 1.16.1, 1.16, 1.15.2, 1.15.1, 1.15, 1.14.4, 1.14.3, 1.14.2, 1.14.1, 1.14, 1.13.2, 1.13.1, 1.13, 1.12.2, 1.12.1, 1.12, 1.11.2, 1.11.1, 1.11, 1.10.2, 1.10.1, 1.10, 1.9.4, 1.9.3, 1.9.2, 1.9.1, 1.9, 1.8.9 mcVersions=1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2, 1.18.1, 1.18, 1.17.1, 1.17, 1.16.5, 1.16.4, 1.16.3, 1.16.2, 1.16.1, 1.16, 1.15.2, 1.15.1, 1.15, 1.14.4, 1.14.3, 1.14.2, 1.14.1, 1.14, 1.13.2, 1.13.1, 1.13, 1.12.2, 1.12.1, 1.12, 1.11.2, 1.11.1, 1.11, 1.10.2, 1.10.1, 1.10, 1.9.4, 1.9.3, 1.9.2, 1.9.1, 1.9, 1.8.9