mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Painting re-implemented. Started on enchantments
This commit is contained in:
parent
214cc5a824
commit
65fd409a00
15 changed files with 187 additions and 117 deletions
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
47
core/src/main/java/org/geysermc/geyser/item/Enchantment.java
Normal file
47
core/src/main/java/org/geysermc/geyser/item/Enchantment.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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())
|
||||||
|
|
|
@ -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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ public class JavaRespawnTranslator extends PacketTranslator<ClientboundRespawnPa
|
||||||
entity.resetMetadata();
|
entity.resetMetadata();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!packet.isKeepAttributes()) {
|
if (!packet.isKeepAttributeModifiers()) {
|
||||||
entity.resetAttributes();
|
entity.resetAttributes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.");
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in a new issue