Skip to content

Commit

Permalink
Bedrock 1.21.60 support, API 2.6.1
Browse files Browse the repository at this point in the history
  • Loading branch information
onebeastchris authored Feb 11, 2025
2 parents b96f915 + 04586a4 commit 4180c13
Show file tree
Hide file tree
Showing 27 changed files with 20,701 additions and 208 deletions.
3 changes: 0 additions & 3 deletions core/src/main/java/org/geysermc/geyser/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@ public final class Constants {

public static final String FLOODGATE_DOWNLOAD_LOCATION = "https://geysermc.org/download#floodgate";
public static final String GEYSER_DOWNLOAD_LOCATION = "https://geysermc.org/download";

@Deprecated
static final String SAVED_REFRESH_TOKEN_FILE = "saved-refresh-tokens.json";
static final String SAVED_AUTH_CHAINS_FILE = "saved-auth-chains.json";

public static final String GEYSER_CUSTOM_NAMESPACE = "geyser_custom";
Expand Down
51 changes: 0 additions & 51 deletions core/src/main/java/org/geysermc/geyser/GeyserImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import io.netty.channel.epoll.Epoll;
import io.netty.util.NettyRuntime;
import io.netty.util.concurrent.DefaultThreadFactory;
Expand All @@ -39,8 +38,6 @@
import lombok.Setter;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.raphimc.minecraftauth.step.java.session.StepFullJavaSession;
import net.raphimc.minecraftauth.step.msa.StepMsaToken;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
Expand Down Expand Up @@ -99,7 +96,6 @@
import org.geysermc.geyser.util.AssetUtils;
import org.geysermc.geyser.util.CooldownUtils;
import org.geysermc.geyser.util.Metrics;
import org.geysermc.geyser.util.MinecraftAuthLogger;
import org.geysermc.geyser.util.NewsHandler;
import org.geysermc.geyser.util.VersionCheckUtils;
import org.geysermc.geyser.util.WebUtils;
Expand Down Expand Up @@ -566,53 +562,6 @@ private void startInstance() {
// May be written/read to on multiple threads from each GeyserSession as well as writing the config
savedAuthChains = new ConcurrentHashMap<>();

// TODO Remove after a while - just a migration help
//noinspection deprecation
File refreshTokensFile = bootstrap.getSavedUserLoginsFolder().resolve(Constants.SAVED_REFRESH_TOKEN_FILE).toFile();
if (refreshTokensFile.exists()) {
logger.info("Migrating refresh tokens to auth chains...");
TypeReference<Map<String, String>> type = new TypeReference<>() { };
Map<String, String> refreshTokens = null;
try {
refreshTokens = JSON_MAPPER.readValue(refreshTokensFile, type);
} catch (IOException e) {
// ignored - we'll just delete this file :))
}

if (refreshTokens != null) {
List<String> validUsers = config.getSavedUserLogins();
final Gson gson = new Gson();
for (Map.Entry<String, String> entry : refreshTokens.entrySet()) {
String user = entry.getKey();
if (!validUsers.contains(user)) {
continue;
}

// Migrate refresh tokens to auth chains
try {
StepFullJavaSession javaSession = PendingMicrosoftAuthentication.AUTH_FLOW.apply(false, 10);
StepFullJavaSession.FullJavaSession fullJavaSession = javaSession.getFromInput(
MinecraftAuthLogger.INSTANCE,
PendingMicrosoftAuthentication.AUTH_CLIENT,
new StepMsaToken.RefreshToken(entry.getValue())
);

String authChain = gson.toJson(javaSession.toJson(fullJavaSession));
savedAuthChains.put(user, authChain);
} catch (Exception e) {
GeyserImpl.getInstance().getLogger().warning("Could not migrate " + entry.getKey() + " to an auth chain! " +
"They will need to sign in the next time they join Geyser.");
}

// Ensure the new additions are written to the file
scheduleAuthChainsWrite();
}
}

// Finally: Delete it. Goodbye!
refreshTokensFile.delete();
}

File authChainsFile = bootstrap.getSavedUserLoginsFolder().resolve(Constants.SAVED_AUTH_CHAINS_FILE).toFile();
if (authChainsFile.exists()) {
TypeReference<Map<String, String>> type = new TypeReference<>() { };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
package org.geysermc.geyser.item;

import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData;

public record GeyserCustomMappingData(ComponentItemData componentItemData, ItemDefinition itemDefinition, String stringId, int integerId) {
public record GeyserCustomMappingData(ItemDefinition itemDefinition, String stringId, int integerId) {
}
14 changes: 10 additions & 4 deletions core/src/main/java/org/geysermc/geyser/network/GameProtocol.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec;
import org.cloudburstmc.protocol.bedrock.codec.v748.Bedrock_v748;
import org.cloudburstmc.protocol.bedrock.codec.v766.Bedrock_v766;
import org.cloudburstmc.protocol.bedrock.codec.v776.Bedrock_v776;
import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodec;
Expand All @@ -47,8 +48,8 @@ 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 = CodecProcessor.processCodec(Bedrock_v766.CODEC.toBuilder()
.minecraftVersion("1.21.51")
public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v776.CODEC.toBuilder()
.minecraftVersion("1.21.60")
.build());

/**
Expand All @@ -66,9 +67,10 @@ public final class GameProtocol {
SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v748.CODEC.toBuilder()
.minecraftVersion("1.21.40 - 1.21.44")
.build()));
SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder()
SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v766.CODEC.toBuilder()
.minecraftVersion("1.21.50 - 1.21.51")
.build());
.build()));
SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC);
}

/**
Expand All @@ -91,6 +93,10 @@ public static boolean isPreWinterDrop(GeyserSession session) {
return session.getUpstream().getProtocolVersion() == Bedrock_v748.CODEC.getProtocolVersion();
}

public static boolean isPreCreativeInventoryRewrite(int protocolVersion) {
return protocolVersion < 776;
}

/**
* Gets the {@link PacketCodec} for Minecraft: Java Edition.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -896,4 +896,14 @@ public PacketSignal handle(ToggleCrafterSlotRequestPacket packet) {
public PacketSignal handle(TrimDataPacket packet) {
return defaultHandler(packet);
}
}

@Override
public PacketSignal handle(MovementPredictionSyncPacket packet) {
return defaultHandler(packet);
}

@Override
public PacketSignal handle(ServerboundDiagnosticsPacket packet) {
return defaultHandler(packet);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

package org.geysermc.geyser.registry;

import org.cloudburstmc.protocol.bedrock.packet.ServerboundDiagnosticsPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundDelimiterPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundTabListPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundChunkBatchStartPacket;
Expand All @@ -49,6 +50,7 @@ public class PacketTranslatorRegistry<T> extends AbstractMappedRegistry<Class<?
IGNORED_PACKETS.add(ClientboundDelimiterPacket.class); // Not implemented, spams logs
IGNORED_PACKETS.add(ClientboundLightUpdatePacket.class); // Light is handled on Bedrock for us
IGNORED_PACKETS.add(ClientboundTabListPacket.class); // Cant be implemented in Bedrock
IGNORED_PACKETS.add(ServerboundDiagnosticsPacket.class); // spammy
}

protected PacketTranslatorRegistry() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.cloudburstmc.nbt.NbtUtils;
import org.cloudburstmc.protocol.bedrock.codec.v748.Bedrock_v748;
import org.cloudburstmc.protocol.bedrock.codec.v766.Bedrock_v766;
import org.cloudburstmc.protocol.bedrock.codec.v776.Bedrock_v776;
import org.cloudburstmc.protocol.bedrock.data.BlockPropertyData;
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.geysermc.geyser.GeyserImpl;
Expand Down Expand Up @@ -116,7 +117,40 @@ private static void nullifyBlocksNbt() {
private static void registerBedrockBlocks() {
var blockMappers = ImmutableMap.<ObjectIntPair<String>, Remapper>builder()
.put(ObjectIntPair.of("1_21_40", Bedrock_v748.CODEC.getProtocolVersion()), Conversion766_748::remapBlock)
.put(ObjectIntPair.of("1_21_50", Bedrock_v766.CODEC.getProtocolVersion()), tag -> tag)
.put(ObjectIntPair.of("1_21_50", Bedrock_v766.CODEC.getProtocolVersion()), tag -> tag) // TODO: Finish me
.put(ObjectIntPair.of("1_21_60", Bedrock_v776.CODEC.getProtocolVersion()), tag -> {
final String name = tag.getString("name");
if (name.equals("minecraft:creaking_heart") && tag.getCompound("states").containsKey("active")) {
NbtMapBuilder builder = tag.getCompound("states").toBuilder();
builder.remove("active");
builder.putString("creaking_heart_state", "awake");
NbtMap states = builder.build();
return tag.toBuilder().putCompound("states", states).build();
}
if ((name.endsWith("_door") || name.endsWith("fence_gate")) && tag.getCompound("states").containsKey("direction")) {
NbtMapBuilder builder = tag.getCompound("states").toBuilder();
Integer directionCardinality = (Integer) builder.remove("direction");
switch (directionCardinality) {
case 0:
builder.putString("minecraft:cardinal_direction", "south");
break;
case 1:
builder.putString("minecraft:cardinal_direction", "west");
break;
case 2:
builder.putString( "minecraft:cardinal_direction" , "north");
break;
case 3:
builder.putString("minecraft:cardinal_direction", "east");
break;
default:
throw new AssertionError("Invalid direction: " + directionCardinality);
}
NbtMap states = builder.build();
return tag.toBuilder().putCompound("states", states).build();
}
return tag;
})
.build();

// We can keep this strong as nothing should be garbage collected
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
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.CreativeItemCategory;
import org.cloudburstmc.protocol.bedrock.data.inventory.CreativeItemData;
import org.cloudburstmc.protocol.bedrock.data.inventory.CreativeItemGroup;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.geysermc.geyser.GeyserBootstrap;
import org.geysermc.geyser.GeyserImpl;
Expand All @@ -42,19 +45,56 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.BiPredicate;
import java.util.function.Consumer;

public class CreativeItemRegistryPopulator {
private static final List<BiPredicate<String, Integer>> JAVA_ONLY_ITEM_FILTER = List.of(
// Bedrock-only as its own item
(identifier, data) -> identifier.equals("minecraft:empty_map") && data == 2
);

static void populate(ItemRegistryPopulator.PaletteVersion palette, Map<String, ItemDefinition> definitions, Map<String, GeyserMappingItem> items, Consumer<ItemData.Builder> itemConsumer) {
static List<CreativeItemGroup> readCreativeItemGroups(ItemRegistryPopulator.PaletteVersion palette, List<CreativeItemData> creativeItemData) {
GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap();

JsonNode creativeItemEntries;
try (InputStream stream = bootstrap.getResourceOrThrow(String.format("bedrock/creative_items.%s.json", palette.version()))) {
creativeItemEntries = GeyserImpl.JSON_MAPPER.readTree(stream).get("groups");
} catch (Exception e) {
throw new AssertionError("Unable to load creative item groups", e);
}

List<CreativeItemGroup> creativeItemGroups = new ArrayList<>();
for (JsonNode creativeItemEntry : creativeItemEntries) {
CreativeItemCategory category = CreativeItemCategory.valueOf(creativeItemEntry.get("category").asText().toUpperCase(Locale.ROOT));
String name = creativeItemEntry.get("name").asText();

JsonNode icon = creativeItemEntry.get("icon");
String identifier = icon.get("id").asText();

ItemData itemData;
if (identifier.equals("minecraft:air")) {
itemData = ItemData.AIR;
} else {
itemData = creativeItemData.stream()
.map(CreativeItemData::getItem)
.filter(item -> item.getDefinition().getIdentifier().equals(identifier))
.findFirst()
.orElseThrow();
}

creativeItemGroups.add(new CreativeItemGroup(category, name, itemData));
}

return creativeItemGroups;
}

static void populate(ItemRegistryPopulator.PaletteVersion palette, Map<String, ItemDefinition> definitions, Map<String, GeyserMappingItem> items, BiConsumer<ItemData.Builder, Integer> itemConsumer) {
GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap();

// Load creative items
Expand All @@ -72,7 +112,9 @@ static void populate(ItemRegistryPopulator.PaletteVersion palette, Map<String, I
continue;
}

itemConsumer.accept(itemBuilder);
int groupId = itemNode.get("groupId") != null ? itemNode.get("groupId").asInt() : 0;

itemConsumer.accept(itemBuilder, groupId);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
import org.cloudburstmc.nbt.NbtType;
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.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.api.item.custom.CustomItemData;
import org.geysermc.geyser.api.item.custom.CustomRenderOffsets;
Expand Down Expand Up @@ -106,12 +105,10 @@ public boolean register(@NonNull NonVanillaCustomItemData customItemData) {
}

public static GeyserCustomMappingData registerCustomItem(String customItemName, Item javaItem, GeyserMappingItem mapping, CustomItemData customItemData, int bedrockId, int protocolVersion) {
ItemDefinition itemDefinition = new SimpleItemDefinition(customItemName, bedrockId, true);

NbtMapBuilder builder = createComponentNbt(customItemData, javaItem, mapping, customItemName, bedrockId, protocolVersion);
ComponentItemData componentItemData = new ComponentItemData(customItemName, builder.build());
ItemDefinition itemDefinition = new SimpleItemDefinition(customItemName, bedrockId, 1, true, builder.build());

return new GeyserCustomMappingData(componentItemData, itemDefinition, customItemName, bedrockId);
return new GeyserCustomMappingData(itemDefinition, customItemName, bedrockId);
}

static boolean initialCheck(String identifier, CustomItemData item, Map<String, GeyserMappingItem> mappings) {
Expand Down Expand Up @@ -142,9 +139,11 @@ public static NonVanillaItemRegistration registerCustomItem(NonVanillaCustomItem
Item item = new Item(customIdentifier, Item.builder().components(components));
Items.register(item, customItemData.javaId());

NbtMapBuilder builder = createComponentNbt(customItemData, customItemData.identifier(), customItemId,
customItemData.isHat(), customItemData.displayHandheld(), protocolVersion);
ItemMapping customItemMapping = ItemMapping.builder()
.bedrockIdentifier(customIdentifier)
.bedrockDefinition(new SimpleItemDefinition(customIdentifier, customItemId, true))
.bedrockDefinition(new SimpleItemDefinition(customIdentifier, customItemId, 1, true, builder.build()))
.bedrockData(0)
.bedrockBlockDefinition(null)
.toolType(customItemData.toolType())
Expand All @@ -153,11 +152,7 @@ public static NonVanillaItemRegistration registerCustomItem(NonVanillaCustomItem
.javaItem(item)
.build();

NbtMapBuilder builder = createComponentNbt(customItemData, customItemData.identifier(), customItemId,
customItemData.isHat(), customItemData.displayHandheld(), protocolVersion);
ComponentItemData componentItemData = new ComponentItemData(customIdentifier, builder.build());

return new NonVanillaItemRegistration(componentItemData, item, customItemMapping);
return new NonVanillaItemRegistration(item, customItemMapping);
}

private static NbtMapBuilder createComponentNbt(CustomItemData customItemData, Item javaItem, GeyserMappingItem mapping,
Expand Down
Loading

0 comments on commit 4180c13

Please sign in to comment.