diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHasher.java b/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHasher.java index d8a20140d..913312e8e 100644 --- a/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHasher.java +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHasher.java @@ -73,12 +73,21 @@ public interface ComponentHasher { MinecraftHasher CLICK_EVENT_ACTION = MinecraftHasher.STRING.cast(ClickEvent.Action::toString); + MinecraftHasher CLICK_EVENT_TEXT_PAYLOAD = MinecraftHasher.STRING.cast(ClickEvent.Payload.Text::value); + + MinecraftHasher CLICK_EVENT_INT_PAYLOAD = MinecraftHasher.INT.cast(ClickEvent.Payload.Int::integer); + + // Both dialog and custom click event types are not possible to hash within Geyser, because: + // - Dialog has no proper implementation within Adventure yet. Once it does, we'd probably only hash dialog holders with a resource location, because setting up + // hashers for the full dialog structure can be a lot of work. + // - Custom uses BinaryTagHolder to store NBT data, which essentially only stores a string representation. This won't work with hashing, we need a NBT tag to hash. MinecraftHasher CLICK_EVENT = CLICK_EVENT_ACTION.dispatch("action", ClickEvent::action, action -> switch (action) { - case OPEN_URL -> builder -> builder.accept("url", MinecraftHasher.STRING, ClickEvent::value); - case OPEN_FILE -> builder -> builder.accept("path", MinecraftHasher.STRING, ClickEvent::value); - case RUN_COMMAND, SUGGEST_COMMAND -> builder -> builder.accept("command", MinecraftHasher.STRING, ClickEvent::value); - case CHANGE_PAGE -> builder -> builder.accept("page", MinecraftHasher.STRING, ClickEvent::value); - case COPY_TO_CLIPBOARD -> builder -> builder.accept("value", MinecraftHasher.STRING, ClickEvent::value); + case OPEN_URL -> builder -> builder.accept("url", CLICK_EVENT_TEXT_PAYLOAD, event -> (ClickEvent.Payload.Text) event.payload()); + case OPEN_FILE -> builder -> builder.accept("path", CLICK_EVENT_TEXT_PAYLOAD, event -> (ClickEvent.Payload.Text) event.payload()); + case RUN_COMMAND, SUGGEST_COMMAND -> builder -> builder.accept("command", CLICK_EVENT_TEXT_PAYLOAD, event -> (ClickEvent.Payload.Text) event.payload()); + case CHANGE_PAGE -> builder -> builder.accept("page", CLICK_EVENT_INT_PAYLOAD, event -> (ClickEvent.Payload.Int) event.payload()); + case COPY_TO_CLIPBOARD -> builder -> builder.accept("value", CLICK_EVENT_TEXT_PAYLOAD, event -> (ClickEvent.Payload.Text) event.payload()); + case SHOW_DIALOG, CUSTOM -> MapBuilder.unit(); }); MinecraftHasher> HOVER_EVENT_ACTION = MinecraftHasher.STRING.cast(HoverEvent.Action::toString); diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index deecab1f9..1c5c14c18 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1283,15 +1283,14 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } this.bundleCache.tick(); + this.dialogManager.tick(); + this.waypointCache.tick(); if (spawned && protocol.getOutboundState() == ProtocolState.GAME) { // Could move this to the PlayerAuthInput translator, in the event the player lags // but this will work once we implement matching Java custom tick cycles sendDownstreamGamePacket(ServerboundClientTickEndPacket.INSTANCE); } - - dialogManager.tick(); - waypointCache.tick(); } catch (Throwable throwable) { throwable.printStackTrace(); } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/waypoint/AzimuthWaypoint.java b/core/src/main/java/org/geysermc/geyser/session/cache/waypoint/AzimuthWaypoint.java index 3ca4c2498..2f44a4894 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/waypoint/AzimuthWaypoint.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/waypoint/AzimuthWaypoint.java @@ -50,8 +50,12 @@ public class AzimuthWaypoint extends GeyserWaypoint implements TickingWaypoint { @Override public void setData(WaypointData data) { - angle = ((AzimuthWaypointData) data).angle(); - updatePosition(); + if (data instanceof AzimuthWaypointData azimuthData) { + angle = azimuthData.angle(); + updatePosition(); + } else { + session.getGeyser().getLogger().warning("Received incorrect waypoint data " + data.getClass() + " for azimuth waypoint"); + } } @Override diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/waypoint/ChunkWaypoint.java b/core/src/main/java/org/geysermc/geyser/session/cache/waypoint/ChunkWaypoint.java index 264185b7e..8434c4534 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/waypoint/ChunkWaypoint.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/waypoint/ChunkWaypoint.java @@ -43,8 +43,11 @@ public class ChunkWaypoint extends GeyserWaypoint { @Override public void setData(WaypointData data) { - ChunkWaypointData chunk = (ChunkWaypointData) data; - // Set position in centre of chunk - position = Vector3f.from(chunk.chunkX() * 16.0F + 8.0F, session.getPlayerEntity().position().getY(), chunk.chunkZ() * 16.0F + 8.0F); + if (data instanceof ChunkWaypointData chunkData) { + // Set position in centre of chunk + position = Vector3f.from(chunkData.chunkX() * 16.0F + 8.0F, session.getPlayerEntity().position().getY(), chunkData.chunkZ() * 16.0F + 8.0F); + } else { + session.getGeyser().getLogger().warning("Received incorrect waypoint data " + data.getClass() + " for chunk waypoint"); + } } } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/waypoint/CoordinatesWaypoint.java b/core/src/main/java/org/geysermc/geyser/session/cache/waypoint/CoordinatesWaypoint.java index 946f86f5f..a60dee27f 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/waypoint/CoordinatesWaypoint.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/waypoint/CoordinatesWaypoint.java @@ -42,6 +42,10 @@ public class CoordinatesWaypoint extends GeyserWaypoint { @Override public void setData(WaypointData data) { - position = ((Vec3iWaypointData) data).vector().toFloat(); + if (data instanceof Vec3iWaypointData vec3iData) { + position = vec3iData.vector().toFloat(); + } else { + session.getGeyser().getLogger().warning("Received incorrect waypoint data " + data.getClass() + " for coordinates waypoint"); + } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java index bf515ecbf..bebea2f22 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java @@ -57,6 +57,8 @@ import java.util.UUID; @BlockEntity(type = BlockEntityType.VAULT) public class VaultBlockEntityTranslator extends BlockEntityTranslator { + private static boolean loggedComponentTranslationFailure = false; + // Bedrock 1.21 does not send the position nor ID in the tag. @Override public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, BlockState blockState) { @@ -88,7 +90,14 @@ public class VaultBlockEntityTranslator extends BlockEntityTranslator { for (Map.Entry entry : componentsTag.entrySet()) { var consumer = DATA_COMPONENT_DECODERS.get(entry.getKey()); if (consumer != null) { - consumer.accept(session, (NbtMap) entry.getValue(), components); + try { + consumer.accept(session, (NbtMap) entry.getValue(), components); + } catch (RuntimeException exception) { + if (!loggedComponentTranslationFailure) { + session.getGeyser().getLogger().warning("Failed to translate vault item component data for " + entry.getKey() + "! Did the component structure change?"); + loggedComponentTranslationFailure = true; + } + } } } ItemData bedrockItem = ItemTranslator.translateToBedrock(session, mapping.getJavaItem(), mapping, count, components).build(); diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a362f2b7f..5f966aa1e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-codec = "3.0.0.Beta7-20250730.214113-17" raknet = "1.0.0.CR3-20250218.160705-18" minecraftauth = "4.1.1" mcprotocollib = "1.21.7-20250725.134643-4" -adventure = "4.21.0" +adventure = "4.24.0" adventure-platform = "4.3.0" junit = "5.9.2" checkerframework = "3.19.0"