mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Initial support for 1.19.30 Bedrock
This commit is contained in:
parent
77827d5cf5
commit
e64e12ff98
10 changed files with 66 additions and 41 deletions
|
@ -31,7 +31,7 @@ object Versions {
|
|||
const val gsonVersion = "2.3.1" // Provided by Spigot 1.8.8
|
||||
const val nbtVersion = "2.1.0"
|
||||
const val websocketVersion = "1.5.1"
|
||||
const val protocolVersion = "0bd459f"
|
||||
const val protocolVersion = "f0feacd"
|
||||
const val raknetVersion = "1.6.28-20220125.214016-6"
|
||||
const val mcauthlibVersion = "d9d773e"
|
||||
const val mcprotocollibversion = "9f78bd5"
|
||||
|
|
|
@ -30,7 +30,7 @@ dependencies {
|
|||
// Network libraries
|
||||
implementation("org.java-websocket", "Java-WebSocket", Versions.websocketVersion)
|
||||
|
||||
api("com.github.CloudburstMC.Protocol", "bedrock-v544", Versions.protocolVersion) {
|
||||
api("com.github.CloudburstMC.Protocol", "bedrock-v553", Versions.protocolVersion) {
|
||||
exclude("com.nukkitx.network", "raknet")
|
||||
exclude("com.nukkitx", "nbt")
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ package org.geysermc.geyser.network;
|
|||
import com.nukkitx.protocol.bedrock.BedrockPong;
|
||||
import com.nukkitx.protocol.bedrock.BedrockServerEventHandler;
|
||||
import com.nukkitx.protocol.bedrock.BedrockServerSession;
|
||||
import com.nukkitx.protocol.bedrock.v553.Bedrock_v553;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.DefaultEventLoopGroup;
|
||||
|
@ -171,7 +172,7 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler {
|
|||
@Override
|
||||
public void onSessionCreation(@Nonnull BedrockServerSession bedrockServerSession) {
|
||||
try {
|
||||
bedrockServerSession.setPacketCodec(GameProtocol.DEFAULT_BEDROCK_CODEC);
|
||||
bedrockServerSession.setPacketCodec(Bedrock_v553.V553_CODEC); // Has the RequestNetworkSettingsPacket
|
||||
bedrockServerSession.setLogging(true);
|
||||
bedrockServerSession.setCompressionLevel(geyser.getConfig().getBedrock().getCompressionLevel());
|
||||
bedrockServerSession.setPacketHandler(new UpstreamPacketHandler(geyser, new GeyserSession(geyser, bedrockServerSession, eventLoopGroup.next())));
|
||||
|
|
|
@ -31,6 +31,7 @@ import com.nukkitx.protocol.bedrock.BedrockPacketCodec;
|
|||
import com.nukkitx.protocol.bedrock.v527.Bedrock_v527;
|
||||
import com.nukkitx.protocol.bedrock.v534.Bedrock_v534;
|
||||
import com.nukkitx.protocol.bedrock.v544.Bedrock_v544;
|
||||
import com.nukkitx.protocol.bedrock.v553.Bedrock_v553;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -71,6 +72,7 @@ public final class GameProtocol {
|
|||
SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder()
|
||||
.minecraftVersion("1.19.21/1.19.22")
|
||||
.build());
|
||||
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v553.V553_CODEC);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -856,4 +856,11 @@ public class LoggingPacketHandler implements BedrockPacketHandler {
|
|||
public boolean handle(FilterTextPacket packet) {
|
||||
return defaultHandler(packet);
|
||||
}
|
||||
|
||||
// 1.19.30 new packet
|
||||
|
||||
@Override
|
||||
public boolean handle(RequestNetworkSettingsPacket packet) {
|
||||
return defaultHandler(packet);
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ package org.geysermc.geyser.network;
|
|||
import com.nukkitx.protocol.bedrock.BedrockPacket;
|
||||
import com.nukkitx.protocol.bedrock.BedrockPacketCodec;
|
||||
import com.nukkitx.protocol.bedrock.data.ExperimentData;
|
||||
import com.nukkitx.protocol.bedrock.data.PacketCompressionAlgorithm;
|
||||
import com.nukkitx.protocol.bedrock.data.ResourcePackType;
|
||||
import com.nukkitx.protocol.bedrock.packet.*;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
|
@ -61,6 +62,20 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
return translateAndDefault(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(RequestNetworkSettingsPacket packet) {
|
||||
// New since 1.19.30 - sent before login packet
|
||||
PacketCompressionAlgorithm algorithm = PacketCompressionAlgorithm.ZLIB;
|
||||
|
||||
NetworkSettingsPacket responsePacket = new NetworkSettingsPacket();
|
||||
responsePacket.setCompressionAlgorithm(algorithm);
|
||||
responsePacket.setCompressionThreshold(512);
|
||||
session.sendUpstreamPacketImmediately(responsePacket);
|
||||
|
||||
session.getUpstream().getSession().setCompression(algorithm);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(LoginPacket loginPacket) {
|
||||
if (geyser.isShuttingDown()) {
|
||||
|
|
|
@ -33,6 +33,7 @@ import com.nukkitx.nbt.NbtMap;
|
|||
import com.nukkitx.nbt.NbtUtils;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.CraftingData;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
|
@ -171,7 +172,7 @@ public class RecipeRegistryPopulator {
|
|||
/* Convert end */
|
||||
|
||||
return CraftingData.fromShaped(uuid.toString(), shape.get(0).length(), shape.size(),
|
||||
inputs, Collections.singletonList(output), uuid, "crafting_table", 0, netId);
|
||||
inputs.stream().map(ItemDescriptorWithCount::fromItem).toList(), Collections.singletonList(output), uuid, "crafting_table", 0, netId);
|
||||
}
|
||||
List<ItemData> inputs = new ObjectArrayList<>();
|
||||
for (JsonNode entry : node.get("inputs")) {
|
||||
|
@ -191,10 +192,10 @@ public class RecipeRegistryPopulator {
|
|||
if (type == 5) {
|
||||
// Shulker box
|
||||
return CraftingData.fromShulkerBox(uuid.toString(),
|
||||
inputs, Collections.singletonList(output), uuid, "crafting_table", 0, netId);
|
||||
inputs.stream().map(ItemDescriptorWithCount::fromItem).toList(), Collections.singletonList(output), uuid, "crafting_table", 0, netId);
|
||||
}
|
||||
return CraftingData.fromShapeless(uuid.toString(),
|
||||
inputs, Collections.singletonList(output), uuid, "crafting_table", 0, netId);
|
||||
inputs.stream().map(ItemDescriptorWithCount::fromItem).toList(), Collections.singletonList(output), uuid, "crafting_table", 0, netId);
|
||||
}
|
||||
|
||||
private static ItemData getBedrockItemFromIdentifierJson(ItemMapping mapping, JsonNode itemNode) {
|
||||
|
|
|
@ -62,7 +62,8 @@ public final class SessionManager {
|
|||
}
|
||||
|
||||
public void removeSession(GeyserSession session) {
|
||||
if (sessions.remove(session.getPlayerEntity().getUuid()) == null) {
|
||||
UUID uuid = session.getPlayerEntity().getUuid();
|
||||
if (uuid == null || sessions.remove(uuid) == null) {
|
||||
// Connection was likely pending
|
||||
pendingSessions.remove(session);
|
||||
}
|
||||
|
|
|
@ -34,9 +34,10 @@ import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeDa
|
|||
import com.github.steveice10.mc.protocol.data.game.recipe.data.SmithingRecipeData;
|
||||
import com.github.steveice10.mc.protocol.data.game.recipe.data.StoneCuttingRecipeData;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUpdateRecipesPacket;
|
||||
import com.nukkitx.nbt.NbtMap;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.CraftingData;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.descriptor.DefaultDescriptor;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount;
|
||||
import com.nukkitx.protocol.bedrock.packet.CraftingDataPacket;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
@ -99,8 +100,8 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
|
|||
}
|
||||
// Strip NBT - tools won't appear in the recipe book otherwise
|
||||
output = output.toBuilder().tag(null).build();
|
||||
ItemData[][] inputCombinations = combinations(session, shapelessRecipeData.getIngredients());
|
||||
for (ItemData[] inputs : inputCombinations) {
|
||||
ItemDescriptorWithCount[][] inputCombinations = combinations(session, shapelessRecipeData.getIngredients());
|
||||
for (ItemDescriptorWithCount[] inputs : inputCombinations) {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
craftingDataPacket.getCraftingData().add(CraftingData.fromShapeless(uuid.toString(),
|
||||
Arrays.asList(inputs), Collections.singletonList(output), uuid, "crafting_table", 0, netId));
|
||||
|
@ -116,8 +117,8 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
|
|||
}
|
||||
// See above
|
||||
output = output.toBuilder().tag(null).build();
|
||||
ItemData[][] inputCombinations = combinations(session, shapedRecipeData.getIngredients());
|
||||
for (ItemData[] inputs : inputCombinations) {
|
||||
ItemDescriptorWithCount[][] inputCombinations = combinations(session, shapedRecipeData.getIngredients());
|
||||
for (ItemDescriptorWithCount[] inputs : inputCombinations) {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
craftingDataPacket.getCraftingData().add(CraftingData.fromShaped(uuid.toString(),
|
||||
shapedRecipeData.getWidth(), shapedRecipeData.getHeight(), Arrays.asList(inputs),
|
||||
|
@ -141,14 +142,14 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
|
|||
SmithingRecipeData recipeData = (SmithingRecipeData) recipe.getData();
|
||||
ItemData output = ItemTranslator.translateToBedrock(session, recipeData.getResult());
|
||||
for (ItemStack base : recipeData.getBase().getOptions()) {
|
||||
ItemData bedrockBase = ItemTranslator.translateToBedrock(session, base);
|
||||
ItemDescriptorWithCount bedrockBase = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, base));
|
||||
|
||||
for (ItemStack addition : recipeData.getAddition().getOptions()) {
|
||||
ItemData bedrockAddition = ItemTranslator.translateToBedrock(session, addition);
|
||||
ItemDescriptorWithCount bedrockAddition = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, addition));
|
||||
|
||||
UUID uuid = UUID.randomUUID();
|
||||
craftingDataPacket.getCraftingData().add(CraftingData.fromShapeless(uuid.toString(),
|
||||
Arrays.asList(bedrockBase, bedrockAddition),
|
||||
List.of(bedrockBase, bedrockAddition),
|
||||
Collections.singletonList(output), uuid, "smithing_table", 2, netId++));
|
||||
}
|
||||
}
|
||||
|
@ -178,6 +179,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
|
|||
// As of 1.16.4, all stonecutter recipes have one ingredient option
|
||||
ItemStack ingredient = stoneCuttingData.getIngredient().getOptions()[0];
|
||||
ItemData input = ItemTranslator.translateToBedrock(session, ingredient);
|
||||
ItemDescriptorWithCount descriptor = ItemDescriptorWithCount.fromItem(input);
|
||||
ItemStack javaOutput = stoneCuttingData.getResult();
|
||||
ItemData output = ItemTranslator.translateToBedrock(session, javaOutput);
|
||||
if (input.equals(ItemData.AIR) || output.equals(ItemData.AIR)) {
|
||||
|
@ -188,7 +190,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
|
|||
|
||||
// We need to register stonecutting recipes so they show up on Bedrock
|
||||
craftingDataPacket.getCraftingData().add(CraftingData.fromShapeless(uuid.toString(),
|
||||
Collections.singletonList(input), Collections.singletonList(output), uuid, "stonecutter", 0, netId));
|
||||
Collections.singletonList(descriptor), Collections.singletonList(output), uuid, "stonecutter", 0, netId));
|
||||
|
||||
// Save the recipe list for reference when crafting
|
||||
// Add the net ID as the key and the button required + output for the value
|
||||
|
@ -209,19 +211,19 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
|
|||
*
|
||||
* @return the Java ingredient list as an array that Bedrock can understand
|
||||
*/
|
||||
private ItemData[][] combinations(GeyserSession session, Ingredient[] ingredients) {
|
||||
Map<Set<ItemData>, IntSet> squashedOptions = new HashMap<>();
|
||||
private ItemDescriptorWithCount[][] combinations(GeyserSession session, Ingredient[] ingredients) {
|
||||
Map<Set<ItemDescriptorWithCount>, IntSet> squashedOptions = new HashMap<>();
|
||||
for (int i = 0; i < ingredients.length; i++) {
|
||||
if (ingredients[i].getOptions().length == 0) {
|
||||
squashedOptions.computeIfAbsent(Collections.singleton(ItemData.AIR), k -> new IntOpenHashSet()).add(i);
|
||||
squashedOptions.computeIfAbsent(Collections.singleton(ItemDescriptorWithCount.EMPTY), k -> new IntOpenHashSet()).add(i);
|
||||
continue;
|
||||
}
|
||||
Ingredient ingredient = ingredients[i];
|
||||
Map<GroupedItem, List<ItemData>> groupedByIds = Arrays.stream(ingredient.getOptions())
|
||||
.map(item -> ItemTranslator.translateToBedrock(session, item))
|
||||
.collect(Collectors.groupingBy(item -> new GroupedItem(item.getId(), item.getCount(), item.getTag())));
|
||||
Set<ItemData> optionSet = new HashSet<>(groupedByIds.size());
|
||||
for (Map.Entry<GroupedItem, List<ItemData>> entry : groupedByIds.entrySet()) {
|
||||
Map<GroupedItem, List<ItemDescriptorWithCount>> groupedByIds = Arrays.stream(ingredient.getOptions())
|
||||
.map(item -> ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, item)))
|
||||
.collect(Collectors.groupingBy(item -> new GroupedItem(((DefaultDescriptor) item.getDescriptor()).getItemId(), item.getCount())));
|
||||
Set<ItemDescriptorWithCount> optionSet = new HashSet<>(groupedByIds.size());
|
||||
for (Map.Entry<GroupedItem, List<ItemDescriptorWithCount>> entry : groupedByIds.entrySet()) {
|
||||
if (entry.getValue().size() > 1) {
|
||||
GroupedItem groupedItem = entry.getKey();
|
||||
int idCount = 0;
|
||||
|
@ -234,42 +236,38 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
|
|||
if (entry.getValue().size() < idCount) {
|
||||
optionSet.addAll(entry.getValue());
|
||||
} else {
|
||||
optionSet.add(ItemData.builder()
|
||||
.id(groupedItem.id)
|
||||
.damage(Short.MAX_VALUE)
|
||||
.count(groupedItem.count)
|
||||
.tag(groupedItem.tag).build());
|
||||
optionSet.add(new ItemDescriptorWithCount(new DefaultDescriptor(groupedItem.id, Short.MAX_VALUE), groupedItem.count));
|
||||
}
|
||||
} else {
|
||||
ItemData item = entry.getValue().get(0);
|
||||
ItemDescriptorWithCount item = entry.getValue().get(0);
|
||||
optionSet.add(item);
|
||||
}
|
||||
}
|
||||
squashedOptions.computeIfAbsent(optionSet, k -> new IntOpenHashSet()).add(i);
|
||||
}
|
||||
int totalCombinations = 1;
|
||||
for (Set<ItemData> optionSet : squashedOptions.keySet()) {
|
||||
for (Set<ItemDescriptorWithCount> optionSet : squashedOptions.keySet()) {
|
||||
totalCombinations *= optionSet.size();
|
||||
}
|
||||
if (totalCombinations > 500) {
|
||||
ItemData[] translatedItems = new ItemData[ingredients.length];
|
||||
ItemDescriptorWithCount[] translatedItems = new ItemDescriptorWithCount[ingredients.length];
|
||||
for (int i = 0; i < ingredients.length; i++) {
|
||||
if (ingredients[i].getOptions().length > 0) {
|
||||
translatedItems[i] = ItemTranslator.translateToBedrock(session, ingredients[i].getOptions()[0]);
|
||||
translatedItems[i] = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, ingredients[i].getOptions()[0]));
|
||||
} else {
|
||||
translatedItems[i] = ItemData.AIR;
|
||||
translatedItems[i] = ItemDescriptorWithCount.EMPTY;
|
||||
}
|
||||
}
|
||||
return new ItemData[][]{translatedItems};
|
||||
return new ItemDescriptorWithCount[][]{translatedItems};
|
||||
}
|
||||
List<Set<ItemData>> sortedSets = new ArrayList<>(squashedOptions.keySet());
|
||||
List<Set<ItemDescriptorWithCount>> sortedSets = new ArrayList<>(squashedOptions.keySet());
|
||||
sortedSets.sort(Comparator.comparing(Set::size, Comparator.reverseOrder()));
|
||||
ItemData[][] combinations = new ItemData[totalCombinations][ingredients.length];
|
||||
ItemDescriptorWithCount[][] combinations = new ItemDescriptorWithCount[totalCombinations][ingredients.length];
|
||||
int x = 1;
|
||||
for (Set<ItemData> set : sortedSets) {
|
||||
for (Set<ItemDescriptorWithCount> set : sortedSets) {
|
||||
IntSet slotSet = squashedOptions.get(set);
|
||||
int i = 0;
|
||||
for (ItemData item : set) {
|
||||
for (ItemDescriptorWithCount item : set) {
|
||||
for (int j = 0; j < totalCombinations / set.size(); j++) {
|
||||
final int comboIndex = (i * x) + (j % x) + ((j / x) * set.size() * x);
|
||||
for (int slot : slotSet) {
|
||||
|
@ -288,6 +286,5 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
|
|||
private static class GroupedItem {
|
||||
int id;
|
||||
int count;
|
||||
NbtMap tag;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.clientbound.inventory.Cli
|
|||
import com.nukkitx.protocol.bedrock.data.inventory.ContainerId;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.CraftingData;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount;
|
||||
import com.nukkitx.protocol.bedrock.packet.CraftingDataPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
|
@ -186,7 +187,7 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator<Clientbound
|
|||
uuid.toString(),
|
||||
width,
|
||||
height,
|
||||
Arrays.asList(ingredients),
|
||||
Arrays.stream(ingredients).map(ItemDescriptorWithCount::fromItem).toList(),
|
||||
Collections.singletonList(ItemTranslator.translateToBedrock(session, item)),
|
||||
uuid,
|
||||
"crafting_table",
|
||||
|
|
Loading…
Reference in a new issue