Support for 1.20.10 (#3961)

Co-authored-by: chris <github@onechris.mozmail.com>
Co-authored-by: RednedEpic <redned235@gmail.com>
This commit is contained in:
Konicai 2023-07-11 19:17:01 -04:00 committed by GitHub
parent 6296d4a97f
commit 3a0c1b788a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 11209 additions and 21 deletions

View File

@ -14,7 +14,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t
Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here!
### Currently supporting Minecraft Bedrock 1.19.80 - 1.20 and Minecraft Java 1.20/1.20.1.
### Currently supporting Minecraft Bedrock 1.19.80 - 1.20.10 and Minecraft Java 1.20/1.20.1.
## Setting Up
Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser.

View File

@ -30,6 +30,7 @@ import com.github.steveice10.mc.protocol.codec.PacketCodec;
import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec;
import org.cloudburstmc.protocol.bedrock.codec.v582.Bedrock_v582;
import org.cloudburstmc.protocol.bedrock.codec.v589.Bedrock_v589;
import org.cloudburstmc.protocol.bedrock.codec.v594.Bedrock_v594;
import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec;
import org.geysermc.geyser.session.GeyserSession;
@ -45,7 +46,7 @@ public final class GameProtocol {
* Default Bedrock codec that should act as a fallback. Should represent the latest available
* release of the game that Geyser supports.
*/
public static final BedrockCodec DEFAULT_BEDROCK_CODEC = Bedrock_v589.CODEC;
public static final BedrockCodec DEFAULT_BEDROCK_CODEC = Bedrock_v594.CODEC;
/**
* A list of all supported Bedrock versions that can join Geyser
@ -62,6 +63,7 @@ public final class GameProtocol {
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v582.CODEC.toBuilder()
.minecraftVersion("1.19.80/1.19.81")
.build());
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v589.CODEC);
SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC);
}

View File

@ -34,6 +34,7 @@ import it.unimi.dsi.fastutil.objects.*;
import org.cloudburstmc.nbt.*;
import org.cloudburstmc.protocol.bedrock.codec.v582.Bedrock_v582;
import org.cloudburstmc.protocol.bedrock.codec.v589.Bedrock_v589;
import org.cloudburstmc.protocol.bedrock.codec.v594.Bedrock_v594;
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.level.block.BlockStateValues;
@ -69,6 +70,34 @@ public final class BlockRegistryPopulator {
private static void registerBedrockBlocks() {
BiFunction<String, NbtMapBuilder, String> emptyMapper = (bedrockIdentifier, statesBuilder) -> null;
// adapt 1.20 mappings to 1.20.10+
BiFunction<String, NbtMapBuilder, String> concreteAndShulkerBoxMapper = (bedrockIdentifier, statesBuilder) -> {
if (bedrockIdentifier.equals("minecraft:concrete")) {
String color = (String) statesBuilder.remove("color");
if (color.equals("silver")) {
color = "light_gray";
}
return "minecraft:" + color + "_concrete";
}
if (bedrockIdentifier.equals("minecraft:shulker_box")) {
String color = (String) statesBuilder.remove("color");
if (color.equals("silver")) {
color = "light_gray";
}
return "minecraft:" + color + "_shulker_box";
}
if (bedrockIdentifier.equals("minecraft:observer")) {
int direction = (int) statesBuilder.remove("facing_direction");
statesBuilder.putString("minecraft:facing_direction", switch (direction) {
case 0 -> "east";
case 1 -> "south";
case 2 -> "north";
default -> "west";
});
}
return null;
};
// We are using mappings that directly support 1.20, so this maps it back to 1.19.80
BiFunction<String, NbtMapBuilder, String> legacyMapper = (bedrockIdentifier, statesBuilder) -> {
if (bedrockIdentifier.endsWith("pumpkin")) {
@ -115,6 +144,7 @@ public final class BlockRegistryPopulator {
ImmutableMap<ObjectIntPair<String>, BiFunction<String, NbtMapBuilder, String>> blockMappers = ImmutableMap.<ObjectIntPair<String>, BiFunction<String, NbtMapBuilder, String>>builder()
.put(ObjectIntPair.of("1_19_80", Bedrock_v582.CODEC.getProtocolVersion()), legacyMapper)
.put(ObjectIntPair.of("1_20_0", Bedrock_v589.CODEC.getProtocolVersion()), emptyMapper)
.put(ObjectIntPair.of("1_20_10", Bedrock_v594.CODEC.getProtocolVersion()), concreteAndShulkerBoxMapper)
.build();
// We can keep this strong as nothing should be garbage collected
@ -242,6 +272,7 @@ public final class BlockRegistryPopulator {
BlockRegistries.BLOCKS.register(palette.getKey().valueInt(), builder.blockStateVersion(stateVersion)
.bedrockRuntimeMap(bedrockRuntimeMap)
.javaToBedrockBlocks(javaToBedrockBlocks)
.stateDefinitionMap(blockStateOrderedMap)
.itemFrames(itemFrames)
.flowerPotBlocks(flowerPotBlocks)
.jigsawStates(jigsawDefinitions)

View File

@ -26,7 +26,10 @@
package org.geysermc.geyser.registry.populator;
import com.fasterxml.jackson.databind.JsonNode;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectMaps;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtUtils;
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
@ -34,6 +37,7 @@ import org.geysermc.geyser.GeyserBootstrap;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.type.BlockMappings;
import org.geysermc.geyser.registry.type.GeyserBedrockBlock;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@ -99,12 +103,32 @@ public class CreativeItemRegistryPopulator {
count = countNode.asInt();
}
GeyserBedrockBlock blockDefinition = null;
JsonNode blockRuntimeIdNode = itemNode.get("blockRuntimeId");
JsonNode blockStateNode;
if (blockRuntimeIdNode != null) {
bedrockBlockRuntimeId = blockRuntimeIdNode.asInt();
if (bedrockBlockRuntimeId == 0 && !identifier.equals("minecraft:blue_candle")) { // FIXME
bedrockBlockRuntimeId = -1;
}
blockDefinition = bedrockBlockRuntimeId == -1 ? null : blockMappings.getDefinition(bedrockBlockRuntimeId);
} else if ((blockStateNode = itemNode.get("block_state_b64")) != null) {
byte[] bytes = Base64.getDecoder().decode(blockStateNode.asText());
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
try {
NbtMap stateTag = (NbtMap) NbtUtils.createReaderLE(bais).readTag();
// We remove these from the state definition map in
// BlockMappings, so we need to remove it from here
NbtMapBuilder builder = stateTag.toBuilder();
builder.remove("name_hash");
builder.remove("network_id");
blockDefinition = blockMappings.getDefinition(builder.build());
} catch (IOException e) {
e.printStackTrace();
}
}
JsonNode nbtNode = itemNode.get("nbt_b64");
@ -129,6 +153,6 @@ public class CreativeItemRegistryPopulator {
.damage(damage)
.count(count)
.tag(tag)
.blockDefinition(bedrockBlockRuntimeId == -1 ? null : blockMappings.getDefinition(bedrockBlockRuntimeId));
.blockDefinition(blockDefinition);
}
}

View File

@ -40,12 +40,13 @@ import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType;
import org.cloudburstmc.protocol.bedrock.codec.v582.Bedrock_v582;
import org.cloudburstmc.protocol.bedrock.codec.v589.Bedrock_v589;
import org.cloudburstmc.protocol.bedrock.codec.v594.Bedrock_v594;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.definitions.SimpleItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
import org.geysermc.geyser.GeyserBootstrap;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.api.item.custom.CustomItemData;
@ -82,6 +83,7 @@ public class ItemRegistryPopulator {
}
public static void populate() {
// Used for the 1.19.80 item palette
Map<Item, String> legacyJavaOnly = new HashMap<>();
legacyJavaOnly.put(Items.MUSIC_DISC_RELIC, "minecraft:music_disc_wait");
legacyJavaOnly.put(Items.PITCHER_PLANT, "minecraft:chorus_flower");
@ -90,6 +92,7 @@ public class ItemRegistryPopulator {
List<PaletteVersion> paletteVersions = new ArrayList<>(2);
paletteVersions.add(new PaletteVersion("1_19_80", Bedrock_v582.CODEC.getProtocolVersion(), legacyJavaOnly, (item, mapping) -> {
// Backward-map 1.20 mappings to 1.19.80
String id = item.javaIdentifier();
if (id.endsWith("pottery_sherd")) {
return mapping.withBedrockIdentifier(id.replace("sherd", "shard"));
@ -102,6 +105,17 @@ public class ItemRegistryPopulator {
return mapping;
}));
paletteVersions.add(new PaletteVersion("1_20_0", Bedrock_v589.CODEC.getProtocolVersion()));
paletteVersions.add(new PaletteVersion("1_20_10", Bedrock_v594.CODEC.getProtocolVersion(), Collections.emptyMap(), (item, mapping) -> {
// Forward-map 1.20 mappings to 1.20.10
// 1.20.10+ received parity for concrete and shulker boxes
String id = item.javaIdentifier();
if (id.endsWith("_concrete") || id.endsWith("_shulker_box")) {
// the first underscore in "_shulker_box" accounts for ignoring "minecraft:shulker_box"
// which is mapped to "minecraft:undyed_shulker_box"
return mapping.withBedrockIdentifier(id);
}
return mapping;
}));
GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap();

View File

@ -45,6 +45,7 @@ public class BlockMappings implements DefinitionRegistry<GeyserBedrockBlock> {
GeyserBedrockBlock[] javaToBedrockBlocks;
Map<NbtMap, GeyserBedrockBlock> stateDefinitionMap;
GeyserBedrockBlock[] bedrockRuntimeMap;
BlockDefinition commandBlock;
@ -85,6 +86,14 @@ public class BlockMappings implements DefinitionRegistry<GeyserBedrockBlock> {
return bedrockRuntimeMap[bedrockId];
}
public GeyserBedrockBlock getDefinition(NbtMap tag) {
if (tag == null) {
return null;
}
return this.stateDefinitionMap.get(tag);
}
@Override
public boolean isRegistered(GeyserBedrockBlock bedrockBlock) {
return getDefinition(bedrockBlock.getRuntimeId()) == bedrockBlock;

View File

@ -79,8 +79,8 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
if (!a.description().equals(b.description())) return false;
if (a.paramData().length != b.paramData().length) return false;
for (int i = 0; i < a.paramData().length; i++) {
CommandParamData[] a1 = a.paramData()[i];
CommandParamData[] b1 = b.paramData()[i];
CommandParamData[] a1 = a.paramData()[i].getOverloads();
CommandParamData[] b1 = b.paramData()[i].getOverloads();
if (a1.length != b1.length) return false;
for (int j = 0; j < a1.length; j++) {
@ -141,7 +141,7 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
}
// Get and parse all params
CommandParamData[][] params = getParams(session, nodes[nodeIndex], nodes);
CommandOverloadData[] params = getParams(session, nodes[nodeIndex], nodes);
// Insert the alias name into the command list
commands.computeIfAbsent(new BedrockCommandInfo(node.getName().toLowerCase(Locale.ROOT), manager.description(node.getName().toLowerCase(Locale.ROOT)), params),
@ -179,7 +179,7 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
CommandEnumData aliases = new CommandEnumData(commandName + "Aliases", values, false);
// Build the completed command and add it to the final list
CommandData data = new CommandData(commandName, entry.getKey().description(), flags, CommandPermission.ANY, aliases, entry.getKey().paramData());
CommandData data = new CommandData(commandName, entry.getKey().description(), flags, CommandPermission.ANY, aliases, Collections.emptyList(), entry.getKey().paramData());
commandData.add(data);
}
@ -201,7 +201,7 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
* @param allNodes Every command node
* @return An array of parameter option arrays
*/
private static CommandParamData[][] getParams(GeyserSession session, CommandNode commandNode, CommandNode[] allNodes) {
private static CommandOverloadData[] getParams(GeyserSession session, CommandNode commandNode, CommandNode[] allNodes) {
// Check if the command is an alias and redirect it
if (commandNode.getRedirectIndex().isPresent()) {
int redirectIndex = commandNode.getRedirectIndex().getAsInt();
@ -214,12 +214,12 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
ParamInfo rootParam = new ParamInfo(commandNode, null);
rootParam.buildChildren(new CommandBuilderContext(session), allNodes);
List<CommandParamData[]> treeData = rootParam.getTree();
List<CommandOverloadData> treeData = rootParam.getTree();
return treeData.toArray(new CommandParamData[0][]);
return treeData.toArray(new CommandOverloadData[0]);
}
return new CommandParamData[0][0];
return new CommandOverloadData[0];
}
/**
@ -272,7 +272,7 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
/**
* Stores the command description and parameter data for best optimizing the Bedrock commands packet.
*/
private record BedrockCommandInfo(String name, String description, CommandParamData[][] paramData) implements
private record BedrockCommandInfo(String name, String description, CommandOverloadData[] paramData) implements
org.geysermc.geyser.api.event.downstream.ServerDefineCommandsEvent.CommandInfo,
ServerDefineCommandsEvent.CommandInfo
{
@ -542,25 +542,26 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
*
* @return List of parameter options arrays for the command
*/
public List<CommandParamData[]> getTree() {
List<CommandParamData[]> treeParamData = new ArrayList<>();
public List<CommandOverloadData> getTree() {
List<CommandOverloadData> treeParamData = new ArrayList<>();
for (ParamInfo child : children) {
// Get the tree from the child
List<CommandParamData[]> childTree = child.getTree();
List<CommandOverloadData> childTree = child.getTree();
// Un-pack the tree append the child node to it and push into the list
for (CommandParamData[] subChild : childTree) {
for (CommandOverloadData subChildData : childTree) {
CommandParamData[] subChild = subChildData.getOverloads();
CommandParamData[] tmpTree = new CommandParamData[subChild.length + 1];
tmpTree[0] = child.getParamData();
System.arraycopy(subChild, 0, tmpTree, 1, subChild.length);
treeParamData.add(tmpTree);
treeParamData.add(new CommandOverloadData(false, tmpTree));
}
// If we have no more child parameters just the child
if (childTree.size() == 0) {
treeParamData.add(new CommandParamData[] { child.getParamData() });
treeParamData.add(new CommandOverloadData(false, new CommandParamData[] { child.getParamData() }));
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -9,8 +9,8 @@ netty = "4.1.80.Final"
guava = "29.0-jre"
gson = "2.3.1" # Provided by Spigot 1.8.8
websocket = "1.5.1"
protocol = "3.0.0.Beta1-20230627.180522-98"
protocol-connection = "3.0.0.Beta1-20230627.180522-97"
protocol = "3.0.0.Beta1-20230708.191602-100"
protocol-connection = "3.0.0.Beta1-20230708.191602-99"
raknet = "1.0.0.CR1-20230703.195238-9"
mcauthlib = "d9d773e"
mcprotocollib = "1.20-1-20230607.135651-6" # Temporary hack - needs to be updated to release once publishing is fixed