Painting re-implemented. Started on enchantments

This commit is contained in:
Camotoy 2024-06-02 20:42:53 -04:00
parent 214cc5a824
commit 65fd409a00
No known key found for this signature in database
GPG key ID: 7EEFB66FE798081F
15 changed files with 187 additions and 117 deletions

View file

@ -30,6 +30,8 @@ import org.cloudburstmc.protocol.bedrock.packet.AddPaintingPacket;
import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.level.PaintingType; import org.geysermc.geyser.level.PaintingType;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.PaintingVariant;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction; import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction;
@ -49,8 +51,14 @@ public class PaintingEntity extends Entity {
// Wait until we get the metadata needed // Wait until we get the metadata needed
} }
public void setPaintingType(ObjectEntityMetadata<org.geysermc.mcprotocollib.protocol.data.game.entity.type.PaintingType> entityMetadata) { public void setPaintingType(ObjectEntityMetadata<Holder<PaintingVariant>> entityMetadata) {
PaintingType type = PaintingType.getByPaintingType(entityMetadata.getValue()); if (!entityMetadata.getValue().isId()) {
return;
}
PaintingType type = session.getRegistryCache().paintings().byId(entityMetadata.getValue().id());
if (type == null) {
return;
}
AddPaintingPacket addPaintingPacket = new AddPaintingPacket(); AddPaintingPacket addPaintingPacket = new AddPaintingPacket();
addPaintingPacket.setUniqueEntityId(geyserId); addPaintingPacket.setUniqueEntityId(geyserId);
addPaintingPacket.setRuntimeEntityId(geyserId); addPaintingPacket.setRuntimeEntityId(geyserId);
@ -79,7 +87,7 @@ public class PaintingEntity extends Entity {
private Vector3f fixOffset(PaintingType paintingName) { private Vector3f fixOffset(PaintingType paintingName) {
Vector3f position = super.position; Vector3f position = super.position;
position = position.add(0.5, 0.5, 0.5); position = position.add(0.5, 0.5, 0.5);
double widthOffset = paintingName.getWidth() > 1 ? 0.5 : 0; double widthOffset = paintingName.getWidth() > 1 && paintingName.getWidth() != 3 ? 0.5 : 0;
double heightOffset = paintingName.getHeight() > 1 && paintingName.getHeight() != 3 ? 0.5 : 0; double heightOffset = paintingName.getHeight() > 1 && paintingName.getHeight() != 3 ? 0.5 : 0;
return switch (direction) { return switch (direction) {

View file

@ -36,33 +36,25 @@ import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.inventory.item.Enchantment; import org.geysermc.geyser.inventory.item.Enchantment;
import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.DyeItem; import org.geysermc.geyser.item.type.DyeItem;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.geyser.util.ItemUtils; import org.geysermc.geyser.util.ItemUtils;
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.WolfVariant;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import java.util.Collections; import java.util.Collections;
import java.util.Locale; import java.util.Locale;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
public class WolfEntity extends TameableEntity { public class WolfEntity extends TameableEntity {
/**
* A list of all foods a wolf can eat on Java Edition.
* Used to display interactive tag or particles if needed.
* TODO generate
*/
private static final Set<Item> WOLF_FOODS = Set.of(Items.PUFFERFISH, Items.TROPICAL_FISH, Items.CHICKEN, Items.COOKED_CHICKEN,
Items.PORKCHOP, Items.BEEF, Items.RABBIT, Items.COOKED_PORKCHOP, Items.COOKED_BEEF, Items.ROTTEN_FLESH, Items.MUTTON, Items.COOKED_MUTTON,
Items.COOKED_RABBIT);
private byte collarColor = 14; // Red - default private byte collarColor = 14; // Red - default
private boolean isCurseOfBinding = false; private boolean isCurseOfBinding = false;
@ -112,12 +104,14 @@ public class WolfEntity extends TameableEntity {
} }
// 1.20.5+ // 1.20.5+
public void setWolfVariant(IntEntityMetadata entityMetadata) { public void setWolfVariant(ObjectEntityMetadata<Holder<WolfVariant>> entityMetadata) {
WolfVariant wolfVariant = session.getRegistryCache().wolfVariants().byId(entityMetadata.getPrimitiveValue()); entityMetadata.getValue().ifId(id -> {
if (wolfVariant == null) { BuiltInWolfVariant wolfVariant = session.getRegistryCache().wolfVariants().byId(id);
wolfVariant = WolfVariant.PALE; if (wolfVariant == null) {
} wolfVariant = BuiltInWolfVariant.PALE;
dirtyMetadata.put(EntityDataTypes.VARIANT, wolfVariant.ordinal()); }
dirtyMetadata.put(EntityDataTypes.VARIANT, wolfVariant.ordinal());
});
} }
@Override @Override
@ -187,7 +181,7 @@ public class WolfEntity extends TameableEntity {
} }
// Ordered by bedrock id // Ordered by bedrock id
public enum WolfVariant { public enum BuiltInWolfVariant {
PALE, PALE,
ASHEN, ASHEN,
BLACK, BLACK,
@ -198,16 +192,16 @@ public class WolfEntity extends TameableEntity {
STRIPED, STRIPED,
WOODS; WOODS;
private static final WolfVariant[] VALUES = values(); private static final BuiltInWolfVariant[] VALUES = values();
private final String javaIdentifier; private final String javaIdentifier;
WolfVariant() { BuiltInWolfVariant() {
this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ROOT); this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ROOT);
} }
public static @Nullable WolfVariant getByJavaIdentifier(String javaIdentifier) { public static @Nullable BuiltInWolfVariant getByJavaIdentifier(String javaIdentifier) {
for (WolfVariant wolfVariant : VALUES) { for (BuiltInWolfVariant wolfVariant : VALUES) {
if (wolfVariant.javaIdentifier.equals(javaIdentifier)) { if (wolfVariant.javaIdentifier.equals(javaIdentifier)) {
return wolfVariant; return wolfVariant;
} }

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2024 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.item;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.nbt.NbtMap;
import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry;
/**
* @param anvilCost also as a rarity multiplier
*/
public record Enchantment(String supportedItemsTag, int maxLevel, int anvilCost, @Nullable String exclusiveSetTag) {
// Implementation note: I have a feeling the tags can be a list of items, because in vanilla they're HolderSet classes.
// I'm not sure how that's wired over the network, so we'll put it off.
public static Enchantment read(RegistryEntry entry) {
NbtMap data = entry.getData();
String supportedItems = data.getString("supported_items");
int maxLevel = data.getInt("max_level");
int anvilCost = data.getInt("anvil_cost");
String exclusiveSet = data.getString("exclusive_set", null);
return new Enchantment(supportedItems, maxLevel, anvilCost, exclusiveSet);
}
}

View file

@ -146,8 +146,8 @@ public class BannerItem extends BlockItem {
} else { } else {
List<NbtMap> patternList = new ArrayList<>(patterns.size()); List<NbtMap> patternList = new ArrayList<>(patterns.size());
for (BannerPatternLayer patternLayer : patterns) { for (BannerPatternLayer patternLayer : patterns) {
patternLayer.getPattern().ifId(holder -> { patternLayer.getPattern().ifId(id -> {
BannerPattern bannerPattern = session.getRegistryCache().bannerPatterns().byId(holder.id()); BannerPattern bannerPattern = session.getRegistryCache().bannerPatterns().byId(id);
if (bannerPattern != null) { if (bannerPattern != null) {
NbtMap tag = NbtMap.builder() NbtMap tag = NbtMap.builder()
.putString("Pattern", bannerPattern.getBedrockIdentifier()) .putString("Pattern", bannerPattern.getBedrockIdentifier())

View file

@ -29,6 +29,8 @@ import lombok.AccessLevel;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import java.util.Locale;
@AllArgsConstructor(access = AccessLevel.PRIVATE) @AllArgsConstructor(access = AccessLevel.PRIVATE)
@Getter @Getter
public enum PaintingType { public enum PaintingType {
@ -61,7 +63,27 @@ public enum PaintingType {
EARTH("Earth", 2, 2), EARTH("Earth", 2, 2),
WIND("Wind", 2, 2), WIND("Wind", 2, 2),
WATER("Water", 2, 2), WATER("Water", 2, 2),
FIRE("Fire", 2, 2); FIRE("Fire", 2, 2),
MEDITATIVE("meditative", 1, 1),
PRAIRIE_RIDE("prairie_ride", 1, 2),
BAROQUE("baroque", 2, 2),
HUMBLE("humble", 2, 2),
UNPACKED("unpacked", 4, 4),
BACKYARD("backyard", 3, 4),
BOUQUET("bouquet", 3, 3),
CAVEBIRD("cavebird", 3, 3),
CHANGING("changing", 4, 2),
COTAN("cotan", 3, 3),
ENDBOSS("endboss", 3, 3),
FERN("fern", 3, 3),
FINDING("finding", 4, 2),
LOWMIST("lowmist", 4, 2),
ORB("orb", 4, 4),
OWLEMONS("owlemons", 3, 3),
PASSAGE("passage", 4, 2),
POND("pond", 3, 4),
SUNFLOWERS("sunflowers", 3, 3),
TIDES("tides", 3, 3);
private static final PaintingType[] VALUES = values(); private static final PaintingType[] VALUES = values();
private final String bedrockName; private final String bedrockName;
@ -70,12 +92,8 @@ public enum PaintingType {
public static PaintingType getByName(String javaName) { public static PaintingType getByName(String javaName) {
for (PaintingType paintingName : VALUES) { for (PaintingType paintingName : VALUES) {
if (paintingName.name().equalsIgnoreCase(javaName)) return paintingName; if (("minecraft:" + paintingName.name().toLowerCase(Locale.ROOT)).equals(javaName)) return paintingName;
} }
return KEBAB; return null;
}
public static PaintingType getByPaintingType(org.geysermc.mcprotocollib.protocol.data.game.entity.type.PaintingType paintingType) {
return getByName(paintingType.name());
} }
} }

View file

@ -44,7 +44,7 @@ public class Conversion685_671 {
private static final List<String> MODIFIED_BLOCKS = Stream.of(NEW_BLOCKS, OMINOUS_BLOCKS).flatMap(List::stream).toList(); private static final List<String> MODIFIED_BLOCKS = Stream.of(NEW_BLOCKS, OMINOUS_BLOCKS).flatMap(List::stream).toList();
private static final List<Item> NEW_MUSIC_DISCS = List.of(Items.MUSIC_DISC_CREATOR, Items.MUSIC_DISC_CREATOR_MUSIC_BOX, Items.MUSIC_DISC_PRECIPICE); private static final List<Item> NEW_MUSIC_DISCS = List.of(Items.MUSIC_DISC_CREATOR, Items.MUSIC_DISC_CREATOR_MUSIC_BOX, Items.MUSIC_DISC_PRECIPICE);
static GeyserMappingItem remapItem(@SuppressWarnings("unused") Item item, GeyserMappingItem mapping) { static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) {
String identifer = mapping.getBedrockIdentifier(); String identifer = mapping.getBedrockIdentifier();
if (NEW_MUSIC_DISCS.contains(item)) { if (NEW_MUSIC_DISCS.contains(item)) {

View file

@ -1302,22 +1302,28 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
} }
} }
/**
* Convenience method to reduce amount of duplicate code. Sends ServerboundUseItemPacket.
*/
public void useItem(Hand hand) {
sendDownstreamGamePacket(new ServerboundUseItemPacket(
hand, worldCache.nextPredictionSequence(), playerEntity.getPitch(), playerEntity.getYaw()));
}
/** /**
* Checks to see if a shield is in either hand to activate blocking. If so, it sets the Bedrock client to display * Checks to see if a shield is in either hand to activate blocking. If so, it sets the Bedrock client to display
* blocking and sends a packet to the Java server. * blocking and sends a packet to the Java server.
*/ */
private boolean attemptToBlock() { private boolean attemptToBlock() {
ServerboundUseItemPacket useItemPacket;
if (playerInventory.getItemInHand().asItem() == Items.SHIELD) { if (playerInventory.getItemInHand().asItem() == Items.SHIELD) {
useItemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, worldCache.nextPredictionSequence()); useItem(Hand.MAIN_HAND);
} else if (playerInventory.getOffhand().asItem() == Items.SHIELD) { } else if (playerInventory.getOffhand().asItem() == Items.SHIELD) {
useItemPacket = new ServerboundUseItemPacket(Hand.OFF_HAND, worldCache.nextPredictionSequence()); useItem(Hand.OFF_HAND);
} else { } else {
// No blocking // No blocking
return false; return false;
} }
sendDownstreamGamePacket(useItemPacket);
playerEntity.setFlag(EntityFlag.BLOCKING, true); playerEntity.setFlag(EntityFlag.BLOCKING, true);
// Metadata should be updated later // Metadata should be updated later
return true; return true;

View file

@ -38,7 +38,9 @@ import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.entity.type.living.animal.tameable.WolfEntity; import org.geysermc.geyser.entity.type.living.animal.tameable.WolfEntity;
import org.geysermc.geyser.inventory.item.BannerPattern; import org.geysermc.geyser.inventory.item.BannerPattern;
import org.geysermc.geyser.inventory.recipe.TrimRecipe; import org.geysermc.geyser.inventory.recipe.TrimRecipe;
import org.geysermc.geyser.item.Enchantment;
import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.level.JavaDimension;
import org.geysermc.geyser.level.PaintingType;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.registry.JavaRegistry; import org.geysermc.geyser.session.cache.registry.JavaRegistry;
import org.geysermc.geyser.session.cache.registry.SimpleJavaRegistry; import org.geysermc.geyser.session.cache.registry.SimpleJavaRegistry;
@ -46,6 +48,7 @@ import org.geysermc.geyser.text.TextDecoration;
import org.geysermc.geyser.translator.level.BiomeTranslator; import org.geysermc.geyser.translator.level.BiomeTranslator;
import org.geysermc.mcprotocollib.protocol.MinecraftProtocol; import org.geysermc.mcprotocollib.protocol.MinecraftProtocol;
import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry;
import org.geysermc.mcprotocollib.protocol.data.game.chat.ChatType;
import org.geysermc.mcprotocollib.protocol.packet.configuration.clientbound.ClientboundRegistryDataPacket; import org.geysermc.mcprotocollib.protocol.packet.configuration.clientbound.ClientboundRegistryDataPacket;
import java.util.ArrayList; import java.util.ArrayList;
@ -72,11 +75,13 @@ public final class RegistryCache {
static { static {
register("chat_type", cache -> cache.chatTypes, ($, entry) -> TextDecoration.readChatType(entry)); register("chat_type", cache -> cache.chatTypes, ($, entry) -> TextDecoration.readChatType(entry));
register("dimension_type", cache -> cache.dimensions, ($, entry) -> JavaDimension.read(entry)); register("dimension_type", cache -> cache.dimensions, ($, entry) -> JavaDimension.read(entry));
register("enchantment", cache -> cache.enchantments, ($, entry) -> Enchantment.read(entry));
register("painting_variant", cache -> cache.paintings, ($, entry) -> PaintingType.getByName(entry.getId()));
register("trim_material", cache -> cache.trimMaterials, TrimRecipe::readTrimMaterial); register("trim_material", cache -> cache.trimMaterials, TrimRecipe::readTrimMaterial);
register("trim_pattern", cache -> cache.trimPatterns, TrimRecipe::readTrimPattern); register("trim_pattern", cache -> cache.trimPatterns, TrimRecipe::readTrimPattern);
register("worldgen/biome", (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome); register("worldgen/biome", (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome);
register("banner_pattern", cache -> cache.bannerPatterns, ($, entry) -> BannerPattern.getByJavaIdentifier(entry.getId())); register("banner_pattern", cache -> cache.bannerPatterns, ($, entry) -> BannerPattern.getByJavaIdentifier(entry.getId()));
register("wolf_variant", cache -> cache.wolfVariants, ($, entry) -> WolfEntity.WolfVariant.getByJavaIdentifier(entry.getId())); register("wolf_variant", cache -> cache.wolfVariants, ($, entry) -> WolfEntity.BuiltInWolfVariant.getByJavaIdentifier(entry.getId()));
// Load from MCProtocolLib's classloader // Load from MCProtocolLib's classloader
NbtMap tag = MinecraftProtocol.loadNetworkCodec(); NbtMap tag = MinecraftProtocol.loadNetworkCodec();
@ -104,16 +109,18 @@ public final class RegistryCache {
* Java -> Bedrock biome network IDs. * Java -> Bedrock biome network IDs.
*/ */
private int[] biomeTranslations; private int[] biomeTranslations;
private final JavaRegistry<TextDecoration> chatTypes = new SimpleJavaRegistry<>(); private final JavaRegistry<ChatType> chatTypes = new SimpleJavaRegistry<>();
/** /**
* All dimensions that the client could possibly connect to. * All dimensions that the client could possibly connect to.
*/ */
private final JavaRegistry<JavaDimension> dimensions = new SimpleJavaRegistry<>(); private final JavaRegistry<JavaDimension> dimensions = new SimpleJavaRegistry<>();
private final JavaRegistry<Enchantment> enchantments = new SimpleJavaRegistry<>();
private final JavaRegistry<PaintingType> paintings = new SimpleJavaRegistry<>();
private final JavaRegistry<TrimMaterial> trimMaterials = new SimpleJavaRegistry<>(); private final JavaRegistry<TrimMaterial> trimMaterials = new SimpleJavaRegistry<>();
private final JavaRegistry<TrimPattern> trimPatterns = new SimpleJavaRegistry<>(); private final JavaRegistry<TrimPattern> trimPatterns = new SimpleJavaRegistry<>();
private final JavaRegistry<BannerPattern> bannerPatterns = new SimpleJavaRegistry<>(); private final JavaRegistry<BannerPattern> bannerPatterns = new SimpleJavaRegistry<>();
private final JavaRegistry<WolfEntity.WolfVariant> wolfVariants = new SimpleJavaRegistry<>(); private final JavaRegistry<WolfEntity.BuiltInWolfVariant> wolfVariants = new SimpleJavaRegistry<>();
public RegistryCache(GeyserSession session) { public RegistryCache(GeyserSession session) {
this.session = session; this.session = session;

View file

@ -57,4 +57,9 @@ public class SimpleJavaRegistry<T> implements JavaRegistry<T> {
public List<T> values() { public List<T> values() {
return this.values; return this.values;
} }
@Override
public String toString() {
return this.values.toString();
}
} }

View file

@ -30,21 +30,49 @@ import net.kyori.adventure.text.format.Style;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.nbt.NbtType;
import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry;
import org.geysermc.mcprotocollib.protocol.data.game.chat.ChatType;
import org.geysermc.mcprotocollib.protocol.data.game.chat.ChatTypeDecoration;
import java.util.EnumSet; import java.util.*;
import java.util.List;
import java.util.Locale;
import java.util.Set;
public final class TextDecoration { public record TextDecoration(String translationKey, List<Parameter> parameters, Style deserializedStyle) implements ChatTypeDecoration {
private final String translationKey;
private final Style style;
private final Set<Parameter> parameters;
public TextDecoration(NbtMap tag) { @Override
translationKey = tag.getString("translation_key"); public NbtMap style() {
// Should not ever be called.
throw new UnsupportedOperationException();
}
NbtMap styleTag = tag.getCompound("style"); public static ChatType readChatType(RegistryEntry entry) {
// Note: The ID is NOT ALWAYS THE SAME! ViaVersion as of 1.19 adds two registry entries that do NOT match vanilla.
// (This note has been passed around through several classes and iterations. It stays as a warning
// to anyone that dares to try and hardcode registry IDs.)
NbtMap tag = entry.getData();
NbtMap chat = tag.getCompound("chat", null);
if (chat != null) {
String translationKey = tag.getString("translation_key");
NbtMap styleTag = tag.getCompound("style");
Style style = deserializeStyle(styleTag);
List<ChatTypeDecoration.Parameter> parameters = new ArrayList<>();
List<String> parametersNbt = tag.getList("parameters", NbtType.STRING);
for (String parameter : parametersNbt) {
parameters.add(ChatTypeDecoration.Parameter.valueOf(parameter.toUpperCase(Locale.ROOT)));
}
return new ChatType(new TextDecoration(translationKey, parameters, style), null);
}
return new ChatType(null, null);
}
public static Style getStyle(ChatTypeDecoration decoration) {
if (decoration instanceof TextDecoration textDecoration) {
return textDecoration.deserializedStyle();
}
return deserializeStyle(decoration.style());
}
private static Style deserializeStyle(NbtMap styleTag) {
Style.Builder builder = Style.style(); Style.Builder builder = Style.style();
if (!styleTag.isEmpty()) { if (!styleTag.isEmpty()) {
String color = styleTag.getString("color", null); String color = styleTag.getString("color", null);
@ -57,50 +85,6 @@ public final class TextDecoration {
builder.decorate(net.kyori.adventure.text.format.TextDecoration.ITALIC); builder.decorate(net.kyori.adventure.text.format.TextDecoration.ITALIC);
} }
} }
style = builder.build(); return builder.build();
this.parameters = EnumSet.noneOf(Parameter.class);
List<String> parameters = tag.getList("parameters", NbtType.STRING);
for (String parameter : parameters) {
this.parameters.add(Parameter.valueOf(parameter.toUpperCase(Locale.ROOT)));
}
}
public String translationKey() {
return translationKey;
}
public Style style() {
return style;
}
public Set<Parameter> parameters() {
return parameters;
}
@Override
public String toString() {
return "TextDecoration{" +
"translationKey='" + translationKey + '\'' +
", style=" + style +
", parameters=" + parameters +
'}';
}
public static TextDecoration readChatType(RegistryEntry entry) {
// Note: The ID is NOT ALWAYS THE SAME! ViaVersion as of 1.19 adds two registry entries that do NOT match vanilla.
NbtMap tag = entry.getData();
NbtMap chat = tag.getCompound("chat", null);
TextDecoration textDecoration = null;
if (chat != null) {
textDecoration = new TextDecoration(chat);
}
return textDecoration;
}
public enum Parameter {
CONTENT,
SENDER,
TARGET
} }
} }

View file

@ -394,8 +394,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
} }
} }
ServerboundUseItemPacket useItemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getWorldCache().nextPredictionSequence()); session.useItem(Hand.MAIN_HAND);
session.sendDownstreamGamePacket(useItemPacket);
List<LegacySetItemSlotData> legacySlots = packet.getLegacySlots(); List<LegacySetItemSlotData> legacySlots = packet.getLegacySlots();
if (packet.getActions().size() == 1 && !legacySlots.isEmpty()) { if (packet.getActions().size() == 1 && !legacySlots.isEmpty()) {
@ -639,8 +638,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
Vector3f target = packet.getBlockPosition().toFloat().add(packet.getClickPosition()); Vector3f target = packet.getBlockPosition().toFloat().add(packet.getClickPosition());
lookAt(session, target); lookAt(session, target);
ServerboundUseItemPacket itemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getWorldCache().nextPredictionSequence()); session.useItem(Hand.MAIN_HAND);
session.sendDownstreamGamePacket(itemPacket);
return true; return true;
} }

View file

@ -25,9 +25,6 @@
package org.geysermc.geyser.translator.protocol.bedrock; package org.geysermc.geyser.translator.protocol.bedrock;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundSetCarriedItemPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
import org.cloudburstmc.protocol.bedrock.packet.MobEquipmentPacket; import org.cloudburstmc.protocol.bedrock.packet.MobEquipmentPacket;
import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.GeyserItemStack;
@ -36,6 +33,8 @@ import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.CooldownUtils; import org.geysermc.geyser.util.CooldownUtils;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundSetCarriedItemPacket;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -66,7 +65,7 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator<MobEquipment
// Activate shield since we are already sneaking // Activate shield since we are already sneaking
// (No need to send a release item packet - Java doesn't do this when swapping items) // (No need to send a release item packet - Java doesn't do this when swapping items)
// Required to do it a tick later or else it doesn't register // Required to do it a tick later or else it doesn't register
session.scheduleInEventLoop(() -> session.sendDownstreamGamePacket(new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getWorldCache().nextPredictionSequence())), session.scheduleInEventLoop(() -> session.useItem(Hand.MAIN_HAND),
50, TimeUnit.MILLISECONDS); 50, TimeUnit.MILLISECONDS);
} }

View file

@ -53,7 +53,7 @@ public class JavaRespawnTranslator extends PacketTranslator<ClientboundRespawnPa
entity.resetMetadata(); entity.resetMetadata();
} }
if (!packet.isKeepAttributes()) { if (!packet.isKeepAttributeModifiers()) {
entity.resetAttributes(); entity.resetAttributes();
} }

View file

@ -25,8 +25,6 @@
package org.geysermc.geyser.translator.text; package org.geysermc.geyser.translator.text;
import org.geysermc.mcprotocollib.protocol.data.DefaultComponentSerializer;
import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ScoreComponent; import net.kyori.adventure.text.ScoreComponent;
import net.kyori.adventure.text.TranslatableComponent; import net.kyori.adventure.text.TranslatableComponent;
@ -41,6 +39,11 @@ import org.cloudburstmc.protocol.bedrock.packet.TextPacket;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.*; import org.geysermc.geyser.text.*;
import org.geysermc.mcprotocollib.protocol.data.DefaultComponentSerializer;
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
import org.geysermc.mcprotocollib.protocol.data.game.chat.ChatType;
import org.geysermc.mcprotocollib.protocol.data.game.chat.ChatTypeDecoration;
import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor;
import java.util.*; import java.util.*;
@ -321,7 +324,7 @@ public class MessageTranslator {
return PlainTextComponentSerializer.plainText().serialize(messageComponent); return PlainTextComponentSerializer.plainText().serialize(messageComponent);
} }
public static void handleChatPacket(GeyserSession session, Component message, int chatType, Component targetName, Component sender) { public static void handleChatPacket(GeyserSession session, Component message, Holder<ChatType> chatTypeHolder, Component targetName, Component sender) {
TextPacket textPacket = new TextPacket(); TextPacket textPacket = new TextPacket();
textPacket.setPlatformChatId(""); textPacket.setPlatformChatId("");
textPacket.setSourceName(""); textPacket.setSourceName("");
@ -330,14 +333,15 @@ public class MessageTranslator {
textPacket.setNeedsTranslation(false); textPacket.setNeedsTranslation(false);
TextDecoration decoration = session.getRegistryCache().chatTypes().byId(chatType); ChatType chatType = chatTypeHolder.getOrCompute(session.getRegistryCache().chatTypes()::byId);
if (decoration != null) { if (chatType != null && chatType.chat() != null) {
var chat = chatType.chat();
// As of 1.19 - do this to apply all the styling for signed messages // As of 1.19 - do this to apply all the styling for signed messages
// Though, Bedrock cannot care about the signed stuff. // Though, Bedrock cannot care about the signed stuff.
TranslatableComponent.Builder withDecoration = Component.translatable() TranslatableComponent.Builder withDecoration = Component.translatable()
.key(decoration.translationKey()) .key(chat.translationKey())
.style(decoration.style()); .style(TextDecoration.getStyle(chat));
Set<TextDecoration.Parameter> parameters = decoration.parameters(); List<ChatTypeDecoration.Parameter> parameters = chat.parameters();
List<Component> args = new ArrayList<>(3); List<Component> args = new ArrayList<>(3);
if (parameters.contains(TextDecoration.Parameter.TARGET)) { if (parameters.contains(TextDecoration.Parameter.TARGET)) {
args.add(targetName); args.add(targetName);
@ -348,7 +352,7 @@ public class MessageTranslator {
if (parameters.contains(TextDecoration.Parameter.CONTENT)) { if (parameters.contains(TextDecoration.Parameter.CONTENT)) {
args.add(message); args.add(message);
} }
withDecoration.args(args); withDecoration.arguments(args);
textPacket.setMessage(MessageTranslator.convertMessage(withDecoration.build(), session.locale())); textPacket.setMessage(MessageTranslator.convertMessage(withDecoration.build(), session.locale()));
} else { } else {
session.getGeyser().getLogger().debug("Likely illegal chat type detection found."); session.getGeyser().getLogger().debug("Likely illegal chat type detection found.");

View file

@ -13,7 +13,7 @@ websocket = "1.5.1"
protocol = "3.0.0.Beta2-20240520.153053-5" protocol = "3.0.0.Beta2-20240520.153053-5"
raknet = "1.0.0.CR3-20240416.144209-1" raknet = "1.0.0.CR3-20240416.144209-1"
mcauthlib = "e5b0bcc" mcauthlib = "e5b0bcc"
mcprotocollib = "1.20.6-2-20240520.030045-8" mcprotocollib = "1.21-SNAPSHOT"
adventure = "4.14.0" adventure = "4.14.0"
adventure-platform = "4.3.0" adventure-platform = "4.3.0"
junit = "5.9.2" junit = "5.9.2"