1
0
mirror of https://github.com/GeyserMC/Geyser.git synced 2025-12-19 14:59:27 +00:00

Initial 1.21.5 changes

This commit is contained in:
onebeastchris
2025-03-20 16:26:10 +01:00
parent 61fea614f3
commit acb858f0ab
35 changed files with 9197 additions and 6154 deletions

View File

@@ -70,4 +70,5 @@ repositories {
content { includeGroupByRegex("com\\.github\\..*") }
}
mavenLocal()
}

View File

@@ -473,8 +473,9 @@ public final class EntityDefinitions {
.heightAndWidth(0.25f)
.identifier("minecraft:xp_bottle")
.build();
// TODO 1.21.5 lingering potion
POTION = EntityDefinition.inherited(ThrownPotionEntity::new, throwableItemBase)
.type(EntityType.POTION)
.type(EntityType.SPLASH_POTION)
.heightAndWidth(0.25f)
.identifier("minecraft:splash_potion")
.build();
@@ -960,6 +961,7 @@ public final class EntityDefinitions {
.type(EntityType.CHICKEN)
.height(0.7f).width(0.4f)
.properties(VanillaEntityProperties.CLIMATE_VARIANT)
.addTranslator(MetadataTypes.CHICKEN_VARIANT, ChickenEntity::setVariant)
.build();
COW = EntityDefinition.inherited(CowEntity::new, ageableEntityBase)
.type(EntityType.COW)
@@ -1016,8 +1018,8 @@ public final class EntityDefinitions {
.type(EntityType.PIG)
.heightAndWidth(0.9f)
.properties(VanillaEntityProperties.CLIMATE_VARIANT)
.addTranslator(MetadataTypes.BOOLEAN, (pigEntity, entityMetadata) -> pigEntity.setFlag(EntityFlag.SADDLED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue()))
.addTranslator(MetadataTypes.INT, PigEntity::setBoost)
.addTranslator(MetadataTypes.PIG_VARIANT, PigEntity::setVariant)
.build();
POLAR_BEAR = EntityDefinition.inherited(PolarBearEntity::new, ageableEntityBase)
.type(EntityType.POLAR_BEAR)
@@ -1045,7 +1047,6 @@ public final class EntityDefinitions {
.height(1.7f).width(0.9f)
.addTranslator(MetadataTypes.INT, StriderEntity::setBoost)
.addTranslator(MetadataTypes.BOOLEAN, StriderEntity::setCold)
.addTranslator(MetadataTypes.BOOLEAN, StriderEntity::setSaddled)
.build();
TURTLE = EntityDefinition.inherited(TurtleEntity::new, ageableEntityBase)
.type(EntityType.TURTLE)
@@ -1144,7 +1145,7 @@ public final class EntityDefinitions {
EntityDefinition<TameableEntity> tameableEntityBase = EntityDefinition.<TameableEntity>inherited(null, ageableEntityBase) // No factory, is abstract
.addTranslator(MetadataTypes.BYTE, TameableEntity::setTameableFlags)
.addTranslator(MetadataTypes.OPTIONAL_UUID, TameableEntity::setOwner)
.addTranslator(MetadataTypes.OPTIONAL_LIVING_ENTITY_REFERENCE, TameableEntity::setOwner)
.build();
CAT = EntityDefinition.inherited(CatEntity::new, tameableEntityBase)
.type(EntityType.CAT)

View File

@@ -35,7 +35,7 @@ import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.MathUtils;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.level.particle.EntityEffectParticleData;
import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ColorParticleData;
import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle;
import java.util.UUID;
@@ -72,7 +72,7 @@ public class AreaEffectCloudEntity extends Entity {
Registries.PARTICLES.map(particle.getType(), p -> p.levelEventType() instanceof ParticleType particleType ? particleType : null).ifPresent(type ->
dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_PARTICLE, type));
if (particle.getData() instanceof EntityEffectParticleData effectParticleData) {
if (particle.getData() instanceof ColorParticleData effectParticleData) {
dirtyMetadata.put(EntityDataTypes.EFFECT_COLOR, effectParticleData.getColor());
}
}

View File

@@ -62,7 +62,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.Object
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.component.DataComponentTypes;
import org.geysermc.mcprotocollib.protocol.data.game.level.particle.EntityEffectParticleData;
import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ColorParticleData;
import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle;
import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ParticleType;
@@ -80,6 +80,7 @@ public class LivingEntity extends Entity {
protected ItemData leggings = ItemData.AIR;
protected ItemData boots = ItemData.AIR;
protected ItemData body = ItemData.AIR;
protected ItemData saddle = ItemData.AIR;
protected ItemData hand = ItemData.AIR;
protected ItemData offhand = ItemData.AIR;
@@ -118,10 +119,6 @@ public class LivingEntity extends Entity {
this.chestplate = ItemTranslator.translateToBedrock(session, stack);
}
public void setBody(ItemStack stack) {
this.body = ItemTranslator.translateToBedrock(session, stack);
}
public void setLeggings(ItemStack stack) {
this.leggings = ItemTranslator.translateToBedrock(session, stack);
}
@@ -130,6 +127,15 @@ public class LivingEntity extends Entity {
this.boots = ItemTranslator.translateToBedrock(session, stack);
}
public void setBody(ItemStack stack) {
this.body = ItemTranslator.translateToBedrock(session, stack);
}
public void setSaddle(ItemStack stack) {
this.saddle = ItemTranslator.translateToBedrock(session, stack);
updateSaddled(stack.getId() == Items.SADDLE.javaId());
}
public void setHand(ItemStack stack) {
this.hand = ItemTranslator.translateToBedrock(session, stack);
}
@@ -138,6 +144,18 @@ public class LivingEntity extends Entity {
this.offhand = ItemTranslator.translateToBedrock(session, stack);
}
protected void updateSaddled(boolean saddled) {
setFlag(EntityFlag.SADDLED, saddled);
updateBedrockMetadata();
// Update the interactive tag, if necessary
// TODO 1.21.5 retest
Entity mouseoverEntity = session.getMouseoverEntity();
if (mouseoverEntity != null && mouseoverEntity.getEntityId() == entityId) {
mouseoverEntity.updateInteractiveTag();
}
}
public void switchHands() {
ItemData offhand = this.offhand;
this.offhand = this.hand;
@@ -202,7 +220,7 @@ public class LivingEntity extends Entity {
continue;
}
int color = ((EntityEffectParticleData) particle.getData()).getColor();
int color = ((ColorParticleData) particle.getData()).getColor();
r += ((color >> 16) & 0xFF) / 255f;
g += ((color >> 8) & 0xFF) / 255f;
b += ((color) & 0xFF) / 255f;

View File

@@ -120,7 +120,7 @@ public class ThrowableEntity extends Entity implements Tickable {
protected float getGravity() {
if (getFlag(EntityFlag.HAS_GRAVITY)) {
switch (definition.entityType()) {
case POTION:
case LINGERING_POTION, SPLASH_POTION:
return 0.05f;
case EXPERIENCE_BOTTLE:
return 0.07f;
@@ -146,7 +146,7 @@ public class ThrowableEntity extends Entity implements Tickable {
return 0.8f;
} else {
switch (definition.entityType()) {
case POTION:
case LINGERING_POTION, SPLASH_POTION:
case EXPERIENCE_BOTTLE:
case SNOWBALL:
case EGG:

View File

@@ -48,6 +48,10 @@ import org.geysermc.geyser.session.cache.tags.Tag;
import org.geysermc.geyser.util.EntityUtils;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.PigVariant;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
@@ -155,4 +159,8 @@ public class PigEntity extends AnimalEntity implements Tickable, ClientVehicle {
public boolean isClientControlled() {
return getPlayerPassenger() == session.getPlayerEntity() && session.getPlayerInventory().isHolding(Items.CARROT_ON_A_STICK);
}
public void setVariant(EntityMetadata<Holder<PigVariant>,? extends MetadataType<Holder<PigVariant>>> holderEntityMetadata) {
// TODO
}
}

View File

@@ -69,10 +69,6 @@ public class StriderEntity extends AnimalEntity implements Tickable, ClientVehic
isCold = entityMetadata.getPrimitiveValue();
}
public void setSaddled(BooleanEntityMetadata entityMetadata) {
setFlag(EntityFlag.SADDLED, entityMetadata.getPrimitiveValue());
}
@Override
public void updateBedrockMetadata() {
// Make sure they are not shaking when riding another entity

View File

@@ -79,12 +79,19 @@ public class AbstractHorseEntity extends AnimalEntity {
session.sendUpstreamPacket(attributesPacket);
}
@Override
public void updateSaddled(boolean saddled) {
// Shows the jump meter
setFlag(EntityFlag.CAN_POWER_JUMP, saddled);
super.updateSaddled(saddled);
}
// TODO 1.21.5 saddled flag doesnt exist anymore
public void setHorseFlags(ByteEntityMetadata entityMetadata) {
byte xd = entityMetadata.getPrimitiveValue();
boolean tamed = (xd & 0x02) == 0x02;
boolean saddled = (xd & 0x04) == 0x04;
setFlag(EntityFlag.TAMED, tamed);
setFlag(EntityFlag.SADDLED, saddled);
setFlag(EntityFlag.EATING, (xd & 0x10) == 0x10);
setFlag(EntityFlag.STANDING, (xd & 0x20) == 0x20);
@@ -114,9 +121,6 @@ public class AbstractHorseEntity extends AnimalEntity {
// Set container type if tamed
dirtyMetadata.put(EntityDataTypes.CONTAINER_TYPE, tamed ? (byte) ContainerType.HORSE.getId() : (byte) 0);
// Shows the jump meter
setFlag(EntityFlag.CAN_POWER_JUMP, saddled);
}
@Override

View File

@@ -34,11 +34,13 @@ import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
import org.geysermc.mcprotocollib.protocol.data.game.inventory.VillagerTrade;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundMerchantOffersPacket;
import java.util.List;
public class MerchantContainer extends Container {
@Getter @Setter
private Entity villager;
@Setter
private VillagerTrade[] villagerTrades;
private List<VillagerTrade> villagerTrades;
@Getter @Setter
private ClientboundMerchantOffersPacket pendingOffersPacket;
@Getter @Setter
@@ -49,9 +51,9 @@ public class MerchantContainer extends Container {
}
public void onTradeSelected(GeyserSession session, int slot) {
if (villagerTrades != null && slot >= 0 && slot < villagerTrades.length) {
VillagerTrade trade = villagerTrades[slot];
setItem(2, GeyserItemStack.from(trade.getOutput()), session);
if (villagerTrades != null && slot >= 0 && slot < villagerTrades.size()) {
VillagerTrade trade = villagerTrades.get(slot);
setItem(2, GeyserItemStack.from(trade.getResult()), session);
tradeExperience += trade.getXp();
villager.getDirtyMetadata().put(EntityDataTypes.TRADE_EXPERIENCE, tradeExperience);

View File

@@ -34,8 +34,7 @@ import org.geysermc.geyser.session.cache.registry.RegistryEntryContext;
import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.geyser.util.MinecraftKey;
import org.geysermc.geyser.util.SoundUtils;
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.Instrument;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.InstrumentComponent;
import org.geysermc.mcprotocollib.protocol.data.game.level.sound.BuiltinSound;
import java.util.Locale;
@@ -90,34 +89,35 @@ public interface GeyserInstrument {
return -1;
}
static GeyserInstrument fromHolder(GeyserSession session, Holder<Instrument> holder) {
if (holder.isId()) {
return session.getRegistryCache().instruments().byId(holder.id());
// TODO 1.21.5
static GeyserInstrument fromComponent(GeyserSession session, InstrumentComponent component) {
if (component.instrumentHolder().isId()) {
return session.getRegistryCache().instruments().byId(component.instrumentHolder().id());
}
Instrument custom = holder.custom();
InstrumentComponent.Instrument custom = component.instrumentHolder().custom();
return new Wrapper(custom, session.locale());
}
record Wrapper(Instrument instrument, String locale) implements GeyserInstrument {
record Wrapper(InstrumentComponent.Instrument instrument, String locale) implements GeyserInstrument {
@Override
public String soundEvent() {
return instrument.getSoundEvent().getName();
return instrument.soundEvent().getName();
}
@Override
public float range() {
return instrument.getRange();
return instrument.range();
}
@Override
public String description() {
return MessageTranslator.convertMessageForTooltip(instrument.getDescription(), locale);
return MessageTranslator.convertMessageForTooltip(instrument.description(), locale);
}
@Override
public BedrockInstrument bedrockInstrument() {
if (instrument.getSoundEvent() instanceof BuiltinSound) {
return BedrockInstrument.getByJavaIdentifier(MinecraftKey.key(instrument.getSoundEvent().getName()));
if (instrument.soundEvent() instanceof BuiltinSound) {
return BedrockInstrument.getByJavaIdentifier(MinecraftKey.key(instrument.soundEvent().getName()));
}
// Probably custom
return null;

View File

@@ -270,9 +270,13 @@ public final class Items {
public static final Item COBWEB = register(new BlockItem(builder(), Blocks.COBWEB));
public static final Item SHORT_GRASS = register(new BlockItem(builder(), Blocks.SHORT_GRASS));
public static final Item FERN = register(new BlockItem(builder(), Blocks.FERN));
public static final Item BUSH = register(new BlockItem(builder(), Blocks.BUSH));
public static final Item AZALEA = register(new BlockItem(builder(), Blocks.AZALEA));
public static final Item FLOWERING_AZALEA = register(new BlockItem(builder(), Blocks.FLOWERING_AZALEA));
public static final Item DEAD_BUSH = register(new BlockItem(builder(), Blocks.DEAD_BUSH));
public static final Item FIREFLY_BUSH = register(new BlockItem(builder(), Blocks.FIREFLY_BUSH));
public static final Item SHORT_DRY_GRASS = register(new BlockItem(builder(), Blocks.SHORT_DRY_GRASS));
public static final Item TALL_DRY_GRASS = register(new BlockItem(builder(), Blocks.TALL_DRY_GRASS));
public static final Item SEAGRASS = register(new BlockItem(builder(), Blocks.SEAGRASS));
public static final Item SEA_PICKLE = register(new BlockItem(builder(), Blocks.SEA_PICKLE));
public static final Item WHITE_WOOL = register(new BlockItem(builder(), Blocks.WHITE_WOOL));
@@ -321,6 +325,8 @@ public final class Items {
public static final Item SUGAR_CANE = register(new BlockItem(builder(), Blocks.SUGAR_CANE));
public static final Item KELP = register(new BlockItem(builder(), Blocks.KELP));
public static final Item PINK_PETALS = register(new BlockItem(builder(), Blocks.PINK_PETALS));
public static final Item WILDFLOWERS = register(new BlockItem(builder(), Blocks.WILDFLOWERS));
public static final Item LEAF_LITTER = register(new BlockItem(builder(), Blocks.LEAF_LITTER));
public static final Item MOSS_CARPET = register(new BlockItem(builder(), Blocks.MOSS_CARPET));
public static final Item MOSS_BLOCK = register(new BlockItem(builder(), Blocks.MOSS_BLOCK));
public static final Item PALE_MOSS_CARPET = register(new BlockItem(builder(), Blocks.PALE_MOSS_CARPET));
@@ -389,6 +395,7 @@ public final class Items {
public static final Item ICE = register(new BlockItem(builder(), Blocks.ICE));
public static final Item SNOW_BLOCK = register(new BlockItem(builder(), Blocks.SNOW_BLOCK));
public static final Item CACTUS = register(new BlockItem(builder(), Blocks.CACTUS));
public static final Item CACTUS_FLOWER = register(new BlockItem(builder(), Blocks.CACTUS_FLOWER));
public static final Item CLAY = register(new BlockItem(builder(), Blocks.CLAY));
public static final Item JUKEBOX = register(new BlockItem(builder(), Blocks.JUKEBOX));
public static final Item OAK_FENCE = register(new BlockItem(builder(), Blocks.OAK_FENCE));
@@ -891,6 +898,8 @@ public final class Items {
public static final Item BAMBOO_CHEST_RAFT = register(new BoatItem("bamboo_chest_raft", builder()));
public static final Item STRUCTURE_BLOCK = register(new BlockItem(builder(), Blocks.STRUCTURE_BLOCK));
public static final Item JIGSAW = register(new BlockItem(builder(), Blocks.JIGSAW));
public static final Item TEST_BLOCK = register(new BlockItem(builder(), Blocks.TEST_BLOCK));
public static final Item TEST_INSTANCE_BLOCK = register(new BlockItem(builder(), Blocks.TEST_INSTANCE_BLOCK));
public static final Item TURTLE_HELMET = register(new ArmorItem("turtle_helmet", builder()));
public static final Item TURTLE_SCUTE = register(new Item("turtle_scute", builder()));
public static final Item ARMADILLO_SCUTE = register(new Item("armadillo_scute", builder()));
@@ -1027,6 +1036,8 @@ public final class Items {
public static final Item BOOK = register(new Item("book", builder()));
public static final Item SLIME_BALL = register(new Item("slime_ball", builder()));
public static final Item EGG = register(new Item("egg", builder()));
public static final Item BLUE_EGG = register(new Item("blue_egg", builder()));
public static final Item BROWN_EGG = register(new Item("brown_egg", builder()));
public static final Item COMPASS = register(new CompassItem("compass", builder()));
public static final Item RECOVERY_COMPASS = register(new Item("recovery_compass", builder()));
public static final Item BUNDLE = register(new Item("bundle", builder()));
@@ -1120,7 +1131,7 @@ public final class Items {
public static final Item BLAZE_POWDER = register(new Item("blaze_powder", builder()));
public static final Item MAGMA_CREAM = register(new Item("magma_cream", builder()));
public static final Item BREWING_STAND = register(new BlockItem(builder(), Blocks.BREWING_STAND));
public static final Item CAULDRON = register(new BlockItem(builder(), Blocks.CAULDRON, Blocks.POWDER_SNOW_CAULDRON, Blocks.LAVA_CAULDRON, Blocks.WATER_CAULDRON));
public static final Item CAULDRON = register(new BlockItem(builder(), Blocks.CAULDRON, Blocks.POWDER_SNOW_CAULDRON, Blocks.WATER_CAULDRON, Blocks.LAVA_CAULDRON));
public static final Item ENDER_EYE = register(new Item("ender_eye", builder()));
public static final Item GLISTERING_MELON_SLICE = register(new Item("glistering_melon_slice", builder()));
public static final Item ARMADILLO_SPAWN_EGG = register(new SpawnEggItem("armadillo_spawn_egg", builder()));
@@ -1210,7 +1221,7 @@ public final class Items {
public static final Item WRITABLE_BOOK = register(new WritableBookItem("writable_book", builder()));
public static final Item WRITTEN_BOOK = register(new WrittenBookItem("written_book", builder()));
public static final Item BREEZE_ROD = register(new Item("breeze_rod", builder()));
public static final Item MACE = register(new Item("mace", builder()));
public static final Item MACE = register(new Item("mace", builder().attackDamage(6.0)));
public static final Item ITEM_FRAME = register(new Item("item_frame", builder()));
public static final Item GLOW_ITEM_FRAME = register(new Item("glow_item_frame", builder()));
public static final Item FLOWER_POT = register(new BlockItem(builder(), Blocks.FLOWER_POT));

View File

@@ -46,7 +46,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.Holder;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.Unit;
import java.util.ArrayList;
import java.util.List;
@@ -226,7 +225,7 @@ public class BannerItem extends BlockItem {
}
components.put(DataComponentTypes.BANNER_PATTERNS, patternLayers);
components.put(DataComponentTypes.HIDE_ADDITIONAL_TOOLTIP, Unit.INSTANCE);
// TODO 1.21.5 hide components???
components.put(DataComponentTypes.ITEM_NAME, Component
.translatable("block.minecraft.ominous_banner")
.style(Style.style(TextColor.color(16755200)))

View File

@@ -36,7 +36,7 @@ import org.geysermc.geyser.translator.item.BedrockItemBuilder;
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.Instrument;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.InstrumentComponent;
public class GoatHornItem extends Item {
public GoatHornItem(String javaIdentifier, Builder builder) {
@@ -50,9 +50,9 @@ public class GoatHornItem extends Item {
return builder;
}
Holder<Instrument> holder = components.get(DataComponentTypes.INSTRUMENT);
if (holder != null) {
GeyserInstrument instrument = GeyserInstrument.fromHolder(session, holder);
InstrumentComponent instrumentComponent = components.get(DataComponentTypes.INSTRUMENT);
if (instrumentComponent != null) {
GeyserInstrument instrument = GeyserInstrument.fromComponent(session, instrumentComponent);
int bedrockId = instrument.bedrockId();
if (bedrockId >= 0) {
builder.damage(bedrockId);
@@ -66,10 +66,10 @@ public class GoatHornItem extends Item {
public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) {
super.translateComponentsToBedrock(session, components, builder);
Holder<Instrument> holder = components.get(DataComponentTypes.INSTRUMENT);
if (holder != null && components.get(DataComponentTypes.HIDE_TOOLTIP) == null
&& components.get(DataComponentTypes.HIDE_ADDITIONAL_TOOLTIP) == null) {
GeyserInstrument instrument = GeyserInstrument.fromHolder(session, holder);
InstrumentComponent component = components.get(DataComponentTypes.INSTRUMENT);
// TODO 1.21.5 hiding????
if (component != null) {
GeyserInstrument instrument = GeyserInstrument.fromComponent(session, component);
if (instrument.bedrockInstrument() == null) {
builder.getOrCreateLore().add(instrument.description());
}
@@ -82,7 +82,7 @@ public class GoatHornItem extends Item {
int damage = itemData.getDamage();
// This could cause an issue since -1 is returned for non-vanilla goat horns
itemStack.getOrCreateComponents().put(DataComponentTypes.INSTRUMENT, Holder.ofId(GeyserInstrument.bedrockIdToJava(session, damage)));
itemStack.getOrCreateComponents().put(DataComponentTypes.INSTRUMENT, new InstrumentComponent(Holder.ofId(GeyserInstrument.bedrockIdToJava(session, damage)), null));
return itemStack;
}

View File

@@ -46,12 +46,10 @@ import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.ChatColor;
import org.geysermc.geyser.text.MinecraftLocale;
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.geyser.util.MinecraftKey;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DyedItemColor;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemEnchantments;
import org.jetbrains.annotations.UnmodifiableView;
@@ -159,12 +157,13 @@ public class Item {
*/
public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) {
List<Component> loreComponents = components.get(DataComponentTypes.LORE);
if (loreComponents != null && components.get(DataComponentTypes.HIDE_TOOLTIP) == null) {
List<String> lore = builder.getOrCreateLore();
for (Component loreComponent : loreComponents) {
lore.add(MessageTranslator.convertMessage(loreComponent, session.locale()));
}
}
// TODO 1.21.5
// if (loreComponents != null && components.get(DataComponentTypes.HIDE_TOOLTIP) == null) {
// List<String> lore = builder.getOrCreateLore();
// for (Component loreComponent : loreComponents) {
// lore.add(MessageTranslator.convertMessage(loreComponent, session.locale()));
// }
// }
Integer damage = components.get(DataComponentTypes.DAMAGE);
if (damage != null) {
@@ -266,10 +265,11 @@ public class Item {
}
protected final void translateDyedColor(DataComponents components, BedrockItemBuilder builder) {
DyedItemColor dyedItemColor = components.get(DataComponentTypes.DYED_COLOR);
if (dyedItemColor != null) {
builder.putInt("customColor", dyedItemColor.getRgb());
}
// TODO 1.21.5
// DyedItemColor dyedItemColor = components.get(DataComponentTypes.DYED_COLOR);
// if (dyedItemColor != null) {
// builder.putInt("customColor", dyedItemColor.getRgb());
// }
}
/**

View File

@@ -325,6 +325,9 @@ public final class Blocks {
public static final Block SHORT_GRASS = register(new Block("short_grass", builder().pushReaction(PistonBehavior.DESTROY)));
public static final Block FERN = register(new Block("fern", builder().pushReaction(PistonBehavior.DESTROY)));
public static final Block DEAD_BUSH = register(new Block("dead_bush", builder().pushReaction(PistonBehavior.DESTROY)));
public static final Block BUSH = register(new Block("bush", builder().pushReaction(PistonBehavior.DESTROY)));
public static final Block SHORT_DRY_GRASS = register(new Block("short_dry_grass", builder().pushReaction(PistonBehavior.DESTROY)));
public static final Block TALL_DRY_GRASS = register(new Block("tall_dry_grass", builder().pushReaction(PistonBehavior.DESTROY)));
public static final Block SEAGRASS = register(new Block("seagrass", builder().pushReaction(PistonBehavior.DESTROY)));
public static final Block TALL_SEAGRASS = register(new Block("tall_seagrass", builder().pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.SEAGRASS)
.enumState(DOUBLE_BLOCK_HALF)));
@@ -399,8 +402,8 @@ public final class Blocks {
public static final Block SOUL_FIRE = register(new Block("soul_fire", builder().pushReaction(PistonBehavior.DESTROY)));
public static final Block SPAWNER = register(new SpawnerBlock("spawner", builder().setBlockEntity(BlockEntityType.MOB_SPAWNER).requiresCorrectToolForDrops().destroyTime(5.0f)));
public static final Block CREAKING_HEART = register(new Block("creaking_heart", builder().setBlockEntity(BlockEntityType.CREAKING_HEART).destroyTime(10.0f)
.booleanState(ACTIVE)
.enumState(AXIS, Axis.VALUES)
.enumState(CREAKING_HEART_STATE)
.booleanState(NATURAL)));
public static final Block OAK_STAIRS = register(new Block("oak_stairs", builder().destroyTime(2.0f)
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
@@ -630,7 +633,7 @@ public final class Blocks {
public static final Block REDSTONE_WALL_TORCH = register(new Block("redstone_wall_torch", builder().pushReaction(PistonBehavior.DESTROY)
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
.booleanState(LIT)));
public static final Block STONE_BUTTON = register(new ButtonBlock("stone_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
public static final Block STONE_BUTTON = register(new Block("stone_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
.enumState(ATTACH_FACE)
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
.booleanState(POWERED)));
@@ -640,6 +643,7 @@ public final class Blocks {
public static final Block SNOW_BLOCK = register(new Block("snow_block", builder().requiresCorrectToolForDrops().destroyTime(0.2f)));
public static final Block CACTUS = register(new Block("cactus", builder().destroyTime(0.4f).pushReaction(PistonBehavior.DESTROY)
.intState(AGE_15)));
public static final Block CACTUS_FLOWER = register(new Block("cactus_flower", builder().pushReaction(PistonBehavior.DESTROY)));
public static final Block CLAY = register(new Block("clay", builder().destroyTime(0.6f)));
public static final Block SUGAR_CANE = register(new Block("sugar_cane", builder().pushReaction(PistonBehavior.DESTROY)
.intState(AGE_15)));
@@ -997,43 +1001,43 @@ public final class Blocks {
.intState(AGE_7)));
public static final Block POTATOES = register(new Block("potatoes", builder().pushReaction(PistonBehavior.DESTROY)
.intState(AGE_7)));
public static final Block OAK_BUTTON = register(new ButtonBlock("oak_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
public static final Block OAK_BUTTON = register(new Block("oak_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
.enumState(ATTACH_FACE)
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
.booleanState(POWERED)));
public static final Block SPRUCE_BUTTON = register(new ButtonBlock("spruce_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
public static final Block SPRUCE_BUTTON = register(new Block("spruce_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
.enumState(ATTACH_FACE)
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
.booleanState(POWERED)));
public static final Block BIRCH_BUTTON = register(new ButtonBlock("birch_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
public static final Block BIRCH_BUTTON = register(new Block("birch_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
.enumState(ATTACH_FACE)
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
.booleanState(POWERED)));
public static final Block JUNGLE_BUTTON = register(new ButtonBlock("jungle_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
public static final Block JUNGLE_BUTTON = register(new Block("jungle_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
.enumState(ATTACH_FACE)
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
.booleanState(POWERED)));
public static final Block ACACIA_BUTTON = register(new ButtonBlock("acacia_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
public static final Block ACACIA_BUTTON = register(new Block("acacia_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
.enumState(ATTACH_FACE)
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
.booleanState(POWERED)));
public static final Block CHERRY_BUTTON = register(new ButtonBlock("cherry_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
public static final Block CHERRY_BUTTON = register(new Block("cherry_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
.enumState(ATTACH_FACE)
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
.booleanState(POWERED)));
public static final Block DARK_OAK_BUTTON = register(new ButtonBlock("dark_oak_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
public static final Block DARK_OAK_BUTTON = register(new Block("dark_oak_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
.enumState(ATTACH_FACE)
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
.booleanState(POWERED)));
public static final Block PALE_OAK_BUTTON = register(new ButtonBlock("pale_oak_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
public static final Block PALE_OAK_BUTTON = register(new Block("pale_oak_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
.enumState(ATTACH_FACE)
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
.booleanState(POWERED)));
public static final Block MANGROVE_BUTTON = register(new ButtonBlock("mangrove_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
public static final Block MANGROVE_BUTTON = register(new Block("mangrove_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
.enumState(ATTACH_FACE)
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
.booleanState(POWERED)));
public static final Block BAMBOO_BUTTON = register(new ButtonBlock("bamboo_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
public static final Block BAMBOO_BUTTON = register(new Block("bamboo_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
.enumState(ATTACH_FACE)
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
.booleanState(POWERED)));
@@ -2232,11 +2236,11 @@ public final class Blocks {
.enumState(HALF)
.enumState(STAIRS_SHAPE)
.booleanState(WATERLOGGED)));
public static final Block CRIMSON_BUTTON = register(new ButtonBlock("crimson_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
public static final Block CRIMSON_BUTTON = register(new Block("crimson_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
.enumState(ATTACH_FACE)
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
.booleanState(POWERED)));
public static final Block WARPED_BUTTON = register(new ButtonBlock("warped_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
public static final Block WARPED_BUTTON = register(new Block("warped_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
.enumState(ATTACH_FACE)
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
.booleanState(POWERED)));
@@ -2268,6 +2272,9 @@ public final class Blocks {
.enumState(STRUCTUREBLOCK_MODE)));
public static final Block JIGSAW = register(new Block("jigsaw", builder().setBlockEntity(BlockEntityType.JIGSAW).requiresCorrectToolForDrops().destroyTime(-1.0f)
.enumState(ORIENTATION, FrontAndTop.VALUES)));
public static final Block TEST_BLOCK = register(new Block("test_block", builder().setBlockEntity(BlockEntityType.TEST_BLOCK).destroyTime(-1.0f)
.enumState(TEST_BLOCK_MODE)));
public static final Block TEST_INSTANCE_BLOCK = register(new Block("test_instance_block", builder().setBlockEntity(BlockEntityType.TEST_INSTANCE_BLOCK).destroyTime(-1.0f)));
public static final Block COMPOSTER = register(new Block("composter", builder().destroyTime(0.6f)
.intState(LEVEL_COMPOSTER)));
public static final Block TARGET = register(new Block("target", builder().destroyTime(0.5f)
@@ -2336,7 +2343,7 @@ public final class Blocks {
.booleanState(WATERLOGGED)));
public static final Block POLISHED_BLACKSTONE_PRESSURE_PLATE = register(new Block("polished_blackstone_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
.booleanState(POWERED)));
public static final Block POLISHED_BLACKSTONE_BUTTON = register(new ButtonBlock("polished_blackstone_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
public static final Block POLISHED_BLACKSTONE_BUTTON = register(new Block("polished_blackstone_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
.enumState(ATTACH_FACE)
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
.booleanState(POWERED)));
@@ -2790,6 +2797,12 @@ public final class Blocks {
public static final Block PINK_PETALS = register(new Block("pink_petals", builder().pushReaction(PistonBehavior.DESTROY)
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
.intState(FLOWER_AMOUNT)));
public static final Block WILDFLOWERS = register(new Block("wildflowers", builder().pushReaction(PistonBehavior.DESTROY)
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
.intState(FLOWER_AMOUNT)));
public static final Block LEAF_LITTER = register(new Block("leaf_litter", builder().pushReaction(PistonBehavior.DESTROY)
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
.intState(SEGMENT_AMOUNT)));
public static final Block MOSS_BLOCK = register(new Block("moss_block", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY)));
public static final Block BIG_DRIPLEAF = register(new Block("big_dripleaf", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY)
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
@@ -2921,6 +2934,7 @@ public final class Blocks {
public static final Block CLOSED_EYEBLOSSOM = register(new Block("closed_eyeblossom", builder().pushReaction(PistonBehavior.DESTROY)));
public static final Block POTTED_OPEN_EYEBLOSSOM = register(new FlowerPotBlock("potted_open_eyeblossom", OPEN_EYEBLOSSOM, builder().pushReaction(PistonBehavior.DESTROY)));
public static final Block POTTED_CLOSED_EYEBLOSSOM = register(new FlowerPotBlock("potted_closed_eyeblossom", CLOSED_EYEBLOSSOM, builder().pushReaction(PistonBehavior.DESTROY)));
public static final Block FIREFLY_BUSH = register(new Block("firefly_bush", builder().pushReaction(PistonBehavior.DESTROY)));
private static <T extends Block> T register(T block) {
block.setJavaId(BlockRegistries.JAVA_BLOCKS.get().size());

View File

@@ -29,7 +29,6 @@ import org.geysermc.geyser.level.physics.Axis;
import org.geysermc.geyser.level.physics.Direction;
public final class Properties {
public static final BooleanProperty ACTIVE = BooleanProperty.create("active");
public static final BooleanProperty ATTACHED = BooleanProperty.create("attached");
public static final BooleanProperty BERRIES = BooleanProperty.create("berries");
public static final BooleanProperty BLOOM = BooleanProperty.create("bloom");
@@ -77,6 +76,7 @@ public final class Properties {
public static final EnumProperty<Direction> FACING_HOPPER = EnumProperty.create("facing", Direction.DOWN, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST);
public static final EnumProperty<Direction> HORIZONTAL_FACING = EnumProperty.create("facing", Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST);
public static final IntegerProperty FLOWER_AMOUNT = IntegerProperty.create("flower_amount", 1, 4);
public static final IntegerProperty SEGMENT_AMOUNT = IntegerProperty.create("segment_amount", 1, 4);
public static final EnumProperty<FrontAndTop> ORIENTATION = EnumProperty.create("orientation", FrontAndTop.VALUES);
public static final BasicEnumProperty ATTACH_FACE = BasicEnumProperty.create("face", "floor", "wall", "ceiling");
public static final BasicEnumProperty BELL_ATTACHMENT = BasicEnumProperty.create("attachment", "floor", "ceiling", "single_wall", "double_wall");
@@ -145,5 +145,8 @@ public final class Properties {
public static final BooleanProperty CRAFTING = BooleanProperty.create("crafting");
public static final BasicEnumProperty TRIAL_SPAWNER_STATE = BasicEnumProperty.create("trial_spawner_state", "inactive", "waiting_for_players", "active", "waiting_for_reward_ejection", "ejecting_reward", "cooldown");
public static final BasicEnumProperty VAULT_STATE = BasicEnumProperty.create("vault_state", "inactive", "active", "unlocking", "ejecting");
public static final BasicEnumProperty CREAKING_HEART_STATE = BasicEnumProperty.create("creaking_heart_state", "uprooted", "dormant", "awake");
public static final BooleanProperty OMINOUS = BooleanProperty.create("ominous");
public static final BasicEnumProperty TEST_BLOCK_MODE = BasicEnumProperty.create("mode", "start", "log", "fail", "accept");
public static final BooleanProperty MAP = BooleanProperty.create("map");
}

View File

@@ -41,6 +41,7 @@ import org.geysermc.mcprotocollib.network.helper.NettyHelper;
import org.geysermc.mcprotocollib.network.netty.MinecraftChannelInitializer;
import org.geysermc.mcprotocollib.network.packet.PacketProtocol;
import org.geysermc.mcprotocollib.network.session.ClientNetworkSession;
import org.geysermc.mcprotocollib.protocol.MinecraftProtocol;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
@@ -56,7 +57,7 @@ public final class LocalSession extends ClientNetworkSession {
private final SocketAddress spoofedRemoteAddress;
public LocalSession(SocketAddress targetAddress, String clientIp, PacketProtocol protocol, Executor packetHandlerExecutor) {
public LocalSession(SocketAddress targetAddress, String clientIp, MinecraftProtocol protocol, Executor packetHandlerExecutor) {
super(targetAddress, protocol, packetHandlerExecutor, null, null);
this.spoofedRemoteAddress = new InetSocketAddress(clientIp, 0);
}

View File

@@ -58,6 +58,9 @@ import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.block.type.FlowerPotBlock;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.populator.conversion.Conversion766_748;
import org.geysermc.geyser.registry.populator.conversion.Conversion776_766;
import org.geysermc.geyser.registry.populator.conversion.Conversion786_776;
import org.geysermc.geyser.registry.type.BlockMappings;
import org.geysermc.geyser.registry.type.GeyserBedrockBlock;
@@ -119,7 +122,7 @@ public final class BlockRegistryPopulator {
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()), Conversion776_766::remapBlock)
.put(ObjectIntPair.of("1_21_60", Bedrock_v776.CODEC.getProtocolVersion()), tag -> tag)
.put(ObjectIntPair.of("1_21_60", Bedrock_v776.CODEC.getProtocolVersion()), Conversion786_776::remapBlock)
.put(ObjectIntPair.of("1_21_70", Bedrock_v786.CODEC.getProtocolVersion()), tag -> tag)
.build();

View File

@@ -75,6 +75,7 @@ public final class DataComponentRegistryPopulator {
byte[] bytes = Base64.getDecoder().decode(encodedValue);
ByteBuf buf = Unpooled.wrappedBuffer(bytes);
int varInt = MinecraftTypes.readVarInt(buf);
System.out.println("int: " + varInt + " " + componentEntry.getKey());
DataComponentType<?> dataComponentType = DataComponentTypes.from(varInt);
DataComponent<?, ?> dataComponent = dataComponentType.readDataComponent(buf);
@@ -84,6 +85,7 @@ public final class DataComponentRegistryPopulator {
defaultComponents.add(new DataComponents(ImmutableMap.copyOf(map)));
}
} catch (Exception e) {
// TODO 1.21.5 enchantment reading is broken
throw new AssertionError("Unable to load or parse components", e);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2024 GeyserMC. http://geysermc.org
* Copyright (c) 2024-2025 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
@@ -23,16 +23,18 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.registry.populator;
package org.geysermc.geyser.registry.populator.conversion;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.level.block.Blocks;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static org.geysermc.geyser.registry.populator.conversion.ConversionHelper.withName;
import static org.geysermc.geyser.registry.populator.conversion.ConversionHelper.withoutStates;
public class Conversion766_748 {
static List<String> PALE_WOODEN_BLOCKS = new ArrayList<>();
static List<String> OTHER_NEW_BLOCKS = new ArrayList<>();
@@ -84,7 +86,7 @@ public class Conversion766_748 {
OTHER_NEW_BLOCKS.add("resin_brick_double_slab");
}
static NbtMap remapBlock(NbtMap tag) {
public static NbtMap remapBlock(NbtMap tag) {
// First: Downgrade from 1.21.60 -> 1.21.50
tag = Conversion776_766.remapBlock(tag);
@@ -116,17 +118,4 @@ public class Conversion766_748 {
return tag;
}
static NbtMap withName(NbtMap tag, String name) {
NbtMapBuilder builder = tag.toBuilder();
builder.replace("name", "minecraft:" + name);
return builder.build();
}
static NbtMap withoutStates(String name) {
NbtMapBuilder tagBuilder = NbtMap.builder();
tagBuilder.putString("name", "minecraft:" + name);
tagBuilder.putCompound("states", NbtMap.builder().build());
return tagBuilder.build();
}
}

View File

@@ -23,7 +23,7 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.registry.populator;
package org.geysermc.geyser.registry.populator.conversion;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
@@ -31,6 +31,10 @@ import org.cloudburstmc.nbt.NbtMapBuilder;
public class Conversion776_766 {
public static NbtMap remapBlock(NbtMap tag) {
// First: Downgrade from 1.21.70
tag = Conversion786_776.remapBlock(tag);
final String name = tag.getString("name");
if (name.equals("minecraft:creaking_heart")) {

View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) 2025 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.registry.populator.conversion;
import org.cloudburstmc.nbt.NbtMap;
import static org.geysermc.geyser.registry.populator.conversion.ConversionHelper.withName;
import static org.geysermc.geyser.registry.populator.conversion.ConversionHelper.withoutStates;
public class Conversion786_776 {
public static NbtMap remapBlock(NbtMap nbtMap) {
final String name = nbtMap.getString("name");
if (name.equals("minecraft:bush")) {
return withName(nbtMap, "fern");
}
if (name.equals("minecraft:firefly_bush")) {
return withName(nbtMap, "deadbush");
}
if (name.equals("minecraft:tall_dry_grass") || name.equals("minecraft:short_dry_grass")) {
return withName(nbtMap, "short_grass");
}
if (name.equals("minecraft:cactus_flower")) {
return withName(nbtMap, "unknown");
}
if (name.equals("minecraft:leaf_litter") || name.equals("minecraft:wildflowers")) {
return withoutStates("unknown");
}
return nbtMap;
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2025 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.registry.populator.conversion;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
// A variety of methods to help with re-mapping blocks and items to older versions.
public class ConversionHelper {
static NbtMap withName(NbtMap tag, String name) {
NbtMapBuilder builder = tag.toBuilder();
builder.replace("name", "minecraft:" + name);
return builder.build();
}
static NbtMap withoutStates(String name) {
NbtMapBuilder tagBuilder = NbtMap.builder();
tagBuilder.putString("name", "minecraft:" + name);
tagBuilder.putCompound("states", NbtMap.EMPTY);
return tagBuilder.build();
}
}

View File

@@ -141,6 +141,7 @@ public final class BlockTag {
public static final Tag<Block> FENCE_GATES = create("fence_gates");
public static final Tag<Block> UNSTABLE_BOTTOM_CENTER = create("unstable_bottom_center");
public static final Tag<Block> MUSHROOM_GROW_BLOCK = create("mushroom_grow_block");
public static final Tag<Block> EDIBLE_FOR_SHEEP = create("edible_for_sheep");
public static final Tag<Block> INFINIBURN_OVERWORLD = create("infiniburn_overworld");
public static final Tag<Block> INFINIBURN_NETHER = create("infiniburn_nether");
public static final Tag<Block> INFINIBURN_END = create("infiniburn_end");
@@ -171,6 +172,7 @@ public final class BlockTag {
public static final Tag<Block> MINEABLE_PICKAXE = create("mineable/pickaxe");
public static final Tag<Block> MINEABLE_SHOVEL = create("mineable/shovel");
public static final Tag<Block> SWORD_EFFICIENT = create("sword_efficient");
public static final Tag<Block> SWORD_INSTANTLY_MINES = create("sword_instantly_mines");
public static final Tag<Block> NEEDS_DIAMOND_TOOL = create("needs_diamond_tool");
public static final Tag<Block> NEEDS_IRON_TOOL = create("needs_iron_tool");
public static final Tag<Block> NEEDS_STONE_TOOL = create("needs_stone_tool");
@@ -200,13 +202,15 @@ public final class BlockTag {
public static final Tag<Block> WOLVES_SPAWNABLE_ON = create("wolves_spawnable_on");
public static final Tag<Block> FROGS_SPAWNABLE_ON = create("frogs_spawnable_on");
public static final Tag<Block> BATS_SPAWNABLE_ON = create("bats_spawnable_on");
public static final Tag<Block> CAMELS_SPAWNABLE_ON = create("camels_spawnable_on");
public static final Tag<Block> AZALEA_GROWS_ON = create("azalea_grows_on");
public static final Tag<Block> CONVERTABLE_TO_MUD = create("convertable_to_mud");
public static final Tag<Block> MANGROVE_LOGS_CAN_GROW_THROUGH = create("mangrove_logs_can_grow_through");
public static final Tag<Block> MANGROVE_ROOTS_CAN_GROW_THROUGH = create("mangrove_roots_can_grow_through");
public static final Tag<Block> DEAD_BUSH_MAY_PLACE_ON = create("dead_bush_may_place_on");
public static final Tag<Block> DRY_VEGETATION_MAY_PLACE_ON = create("dry_vegetation_may_place_on");
public static final Tag<Block> SNAPS_GOAT_HORN = create("snaps_goat_horn");
public static final Tag<Block> REPLACEABLE_BY_TREES = create("replaceable_by_trees");
public static final Tag<Block> REPLACEABLE_BY_MUSHROOMS = create("replaceable_by_mushrooms");
public static final Tag<Block> SNOW_LAYER_CANNOT_SURVIVE_ON = create("snow_layer_cannot_survive_on");
public static final Tag<Block> SNOW_LAYER_CAN_SURVIVE_ON = create("snow_layer_can_survive_on");
public static final Tag<Block> INVALID_SPAWN_INSIDE = create("invalid_spawn_inside");
@@ -219,6 +223,7 @@ public final class BlockTag {
public static final Tag<Block> MAINTAINS_FARMLAND = create("maintains_farmland");
public static final Tag<Block> BLOCKS_WIND_CHARGE_EXPLOSIONS = create("blocks_wind_charge_explosions");
public static final Tag<Block> DOES_NOT_BLOCK_HOPPERS = create("does_not_block_hoppers");
public static final Tag<Block> PLAYS_AMBIENT_DESERT_BLOCK_SOUNDS = create("plays_ambient_desert_block_sounds");
public static final Tag<Block> AIR = create("air");
private BlockTag() {}

View File

@@ -76,6 +76,7 @@ public final class ItemTag {
public static final Tag<Item> LEAVES = create("leaves");
public static final Tag<Item> TRAPDOORS = create("trapdoors");
public static final Tag<Item> SMALL_FLOWERS = create("small_flowers");
public static final Tag<Item> FLOWERS = create("flowers");
public static final Tag<Item> BEDS = create("beds");
public static final Tag<Item> FENCES = create("fences");
public static final Tag<Item> PIGLIN_REPELLENTS = create("piglin_repellents");
@@ -85,6 +86,7 @@ public final class ItemTag {
public static final Tag<Item> DUPLICATES_ALLAYS = create("duplicates_allays");
public static final Tag<Item> BREWING_FUEL = create("brewing_fuel");
public static final Tag<Item> SHULKER_BOXES = create("shulker_boxes");
public static final Tag<Item> EGGS = create("eggs");
public static final Tag<Item> MEAT = create("meat");
public static final Tag<Item> SNIFFER_FOOD = create("sniffer_food");
public static final Tag<Item> PIGLIN_FOOD = create("piglin_food");
@@ -181,6 +183,7 @@ public final class ItemTag {
public static final Tag<Item> DYEABLE = create("dyeable");
public static final Tag<Item> FURNACE_MINECART_FUEL = create("furnace_minecart_fuel");
public static final Tag<Item> BUNDLES = create("bundles");
public static final Tag<Item> BOOK_CLONING_TARGET = create("book_cloning_target");
public static final Tag<Item> SKELETON_PREFERRED_WEAPONS = create("skeleton_preferred_weapons");
public static final Tag<Item> DROWNED_PREFERRED_WEAPONS = create("drowned_preferred_weapons");
public static final Tag<Item> PIGLIN_PREFERRED_WEAPONS = create("piglin_preferred_weapons");

View File

@@ -168,6 +168,9 @@ public final class ItemTranslator {
public static ItemData.@NonNull Builder translateToBedrock(GeyserSession session, Item javaItem, ItemMapping bedrockItem, int count, @Nullable DataComponents customComponents) {
BedrockItemBuilder nbtBuilder = new BedrockItemBuilder();
// TODO 1.21.5:
// - Hiding components
// Populates default components that aren't sent over the network
DataComponents components = javaItem.gatherComponents(customComponents);
@@ -180,22 +183,22 @@ public final class ItemTranslator {
PotionContents potionContents = components.get(DataComponentTypes.POTION_CONTENTS);
// Make custom effect information visible
// Ignore when item have "hide_additional_tooltip" component
if (potionContents != null && components.get(DataComponentTypes.HIDE_ADDITIONAL_TOOLTIP) == null) {
if (potionContents != null) { // && components.get(DataComponentTypes.HIDE_ADDITIONAL_TOOLTIP) == null) {
customName += getPotionEffectInfo(potionContents, session.locale());
}
nbtBuilder.setCustomName(customName);
}
boolean hideTooltips = components.get(DataComponentTypes.HIDE_TOOLTIP) != null;
//boolean hideTooltips = components.get(DataComponentTypes.HIDE_TOOLTIP) != null;
ItemAttributeModifiers attributeModifiers = components.get(DataComponentTypes.ATTRIBUTE_MODIFIERS);
if (attributeModifiers != null && attributeModifiers.isShowInTooltip() && !hideTooltips) {
if (attributeModifiers != null) { //&& attributeModifiers.isShowInTooltip() && !hideTooltips) {
// only add if attribute modifiers do not indicate to hide them
addAttributeLore(session, attributeModifiers, nbtBuilder, session.locale());
}
if (session.isAdvancedTooltips() && !hideTooltips) {
if (session.isAdvancedTooltips()) { //&& !hideTooltips) {
addAdvancedTooltips(components, nbtBuilder, javaItem, session.locale());
}
@@ -545,7 +548,8 @@ public final class ItemTranslator {
if (!customNameOnly) {
PotionContents potionContents = components.get(DataComponentTypes.POTION_CONTENTS);
if (potionContents != null) {
String potionName = getPotionName(potionContents, mapping, components.get(DataComponentTypes.HIDE_ADDITIONAL_TOOLTIP) != null, session.locale());
// TODO 1.21.5
String potionName = getPotionName(potionContents, mapping, false /*components.get(DataComponentTypes.HIDE_ADDITIONAL_TOOLTIP) != null */, session.locale());
if (potionName != null) {
return ChatColor.RESET + ChatColor.ESCAPE + translationColor + potionName;
}

View File

@@ -30,7 +30,6 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import org.cloudburstmc.math.vector.Vector3d;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
@@ -41,8 +40,6 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.transaction.InventoryTra
import org.cloudburstmc.protocol.bedrock.data.inventory.transaction.LegacySetItemSlotData;
import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket;
import org.cloudburstmc.protocol.bedrock.packet.InventoryTransactionPacket;
import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket;
import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.entity.type.Entity;
@@ -52,7 +49,6 @@ import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.inventory.PlayerInventory;
import org.geysermc.geyser.inventory.click.Click;
import org.geysermc.geyser.inventory.item.GeyserInstrument;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.BlockItem;
import org.geysermc.geyser.item.type.BoatItem;
@@ -78,16 +74,12 @@ import org.geysermc.geyser.util.CooldownUtils;
import org.geysermc.geyser.util.EntityUtils;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InventoryUtils;
import org.geysermc.geyser.util.SoundUtils;
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction;
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.InteractAction;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerAction;
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.Instrument;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket;
@@ -388,29 +380,30 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
session.setCurrentBook(packet.getItemInHand());
} else if (session.getPlayerInventory().getItemInHand().asItem() == Items.GOAT_HORN) {
// Temporary workaround while we don't have full item/block use tracking.
// TODO 1.21.5
if (!session.getWorldCache().hasCooldown(session.getPlayerInventory().getItemInHand())) {
Holder<Instrument> holder = session.getPlayerInventory()
.getItemInHand()
.getComponent(DataComponentTypes.INSTRUMENT);
if (holder != null) {
GeyserInstrument instrument = GeyserInstrument.fromHolder(session, holder);
if (instrument.bedrockInstrument() != null) {
// BDS uses a LevelSoundEvent2Packet, but that doesn't work here... (as of 1.21.20)
LevelSoundEventPacket soundPacket = new LevelSoundEventPacket();
soundPacket.setSound(SoundEvent.valueOf("GOAT_CALL_" + instrument.bedrockInstrument().ordinal()));
soundPacket.setPosition(session.getPlayerEntity().getPosition());
soundPacket.setIdentifier("minecraft:player");
soundPacket.setExtraData(-1);
session.sendUpstreamPacket(soundPacket);
} else {
PlaySoundPacket playSoundPacket = new PlaySoundPacket();
playSoundPacket.setPosition(session.getPlayerEntity().position());
playSoundPacket.setSound(SoundUtils.translatePlaySound(instrument.soundEvent()));
playSoundPacket.setPitch(1.0F);
playSoundPacket.setVolume(instrument.range() / 16.0F);
session.sendUpstreamPacket(playSoundPacket);
}
}
// Holder<Instrument> holder = session.getPlayerInventory()
// .getItemInHand()
// .getComponent(DataComponentTypes.INSTRUMENT);
// if (holder != null) {
// GeyserInstrument instrument = GeyserInstrument.fromComponent(session, holder);
// if (instrument.bedrockInstrument() != null) {
// // BDS uses a LevelSoundEvent2Packet, but that doesn't work here... (as of 1.21.20)
// LevelSoundEventPacket soundPacket = new LevelSoundEventPacket();
// soundPacket.setSound(SoundEvent.valueOf("GOAT_CALL_" + instrument.bedrockInstrument().ordinal()));
// soundPacket.setPosition(session.getPlayerEntity().getPosition());
// soundPacket.setIdentifier("minecraft:player");
// soundPacket.setExtraData(-1);
// session.sendUpstreamPacket(soundPacket);
// } else {
// PlaySoundPacket playSoundPacket = new PlaySoundPacket();
// playSoundPacket.setPosition(session.getPlayerEntity().position());
// playSoundPacket.setSound(SoundUtils.translatePlaySound(instrument.soundEvent()));
// playSoundPacket.setPitch(1.0F);
// playSoundPacket.setVolume(instrument.range() / 16.0F);
// session.sendUpstreamPacket(playSoundPacket);
// }
// }
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2025 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
@@ -23,7 +23,7 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.protocol.java.entity.spawn;
package org.geysermc.geyser.translator.protocol.java.entity;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.GeyserImpl;
@@ -47,7 +47,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.object.FallingBlockD
import org.geysermc.mcprotocollib.protocol.data.game.entity.object.ProjectileData;
import org.geysermc.mcprotocollib.protocol.data.game.entity.object.WardenData;
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddEntityPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundAddEntityPacket;
@Translator(packet = ClientboundAddEntityPacket.class)
public class JavaAddEntityTranslator extends PacketTranslator<ClientboundAddEntityPacket> {

View File

@@ -1,49 +0,0 @@
/*
* Copyright (c) 2019-2022 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.translator.protocol.java.entity.spawn;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddExperienceOrbPacket;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.entity.type.ExpOrbEntity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
@Translator(packet = ClientboundAddExperienceOrbPacket.class)
public class JavaAddExperienceOrbTranslator extends PacketTranslator<ClientboundAddExperienceOrbPacket> {
@Override
public void translate(GeyserSession session, ClientboundAddExperienceOrbPacket packet) {
Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ());
Entity entity = new ExpOrbEntity(
session, packet.getExp(), packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(), position
);
session.getEntityCache().spawnEntity(entity);
}
}

View File

@@ -73,11 +73,11 @@ public class JavaMerchantOffersTranslator extends PacketTranslator<ClientboundMe
public static void openMerchant(GeyserSession session, ClientboundMerchantOffersPacket packet, MerchantContainer merchantInventory) {
// Retrieve the fake villager involved in the trade, and update its metadata to match with the window information
merchantInventory.setVillagerTrades(packet.getTrades());
merchantInventory.setTradeExperience(packet.getExperience());
merchantInventory.setVillagerTrades(packet.getOffers());
merchantInventory.setTradeExperience(packet.getVillagerXp());
Entity villager = merchantInventory.getVillager();
if (packet.isRegularVillager()) {
if (packet.isShowProgress()) {
villager.getDirtyMetadata().put(EntityDataTypes.TRADE_TIER, packet.getVillagerLevel() - 1);
villager.getDirtyMetadata().put(EntityDataTypes.MAX_TRADE_TIER, 4);
} else {
@@ -85,7 +85,7 @@ public class JavaMerchantOffersTranslator extends PacketTranslator<ClientboundMe
villager.getDirtyMetadata().put(EntityDataTypes.TRADE_TIER, 0);
villager.getDirtyMetadata().put(EntityDataTypes.MAX_TRADE_TIER, 0);
}
villager.getDirtyMetadata().put(EntityDataTypes.TRADE_EXPERIENCE, packet.getExperience());
villager.getDirtyMetadata().put(EntityDataTypes.TRADE_EXPERIENCE, packet.getVillagerXp());
villager.updateBedrockMetadata();
// Construct the packet that opens the trading window
@@ -101,29 +101,29 @@ public class JavaMerchantOffersTranslator extends PacketTranslator<ClientboundMe
updateTradePacket.setTraderUniqueEntityId(villager.getGeyserId());
NbtMapBuilder builder = NbtMap.builder();
boolean addExtraTrade = packet.isRegularVillager() && packet.getVillagerLevel() < 5;
List<NbtMap> tags = new ArrayList<>(addExtraTrade ? packet.getTrades().length + 1 : packet.getTrades().length);
for (int i = 0; i < packet.getTrades().length; i++) {
VillagerTrade trade = packet.getTrades()[i];
boolean addExtraTrade = packet.isShowProgress() && packet.getVillagerLevel() < 5;
List<NbtMap> tags = new ArrayList<>(addExtraTrade ? packet.getOffers().size() + 1 : packet.getOffers().size());
for (int i = 0; i < packet.getOffers().size(); i++) {
VillagerTrade trade = packet.getOffers().get(i);
NbtMapBuilder recipe = NbtMap.builder();
recipe.putInt("netId", i + 1);
recipe.putInt("maxUses", trade.isTradeDisabled() ? 0 : trade.getMaxUses());
recipe.putInt("maxUses", trade.isOutOfStock() ? 0 : trade.getMaxUses());
recipe.putInt("traderExp", trade.getXp());
recipe.putFloat("priceMultiplierA", trade.getPriceMultiplier());
recipe.putFloat("priceMultiplierB", 0.0f);
recipe.put("sell", getItemTag(session, trade.getOutput()));
recipe.put("sell", getItemTag(session, trade.getResult()));
// The buy count before demand and special price adjustments
// The first input CAN be null as of Java 1.19.0/Bedrock 1.19.10
// Replicable item: https://gist.github.com/Camotoy/3f3f23d1f80981d1b4472bdb23bba698 from https://github.com/GeyserMC/Geyser/issues/3171
recipe.putInt("buyCountA", trade.getFirstInput() != null ? Math.max(trade.getFirstInput().getAmount(), 0) : 0);
recipe.putInt("buyCountB", trade.getSecondInput() != null ? Math.max(trade.getSecondInput().getAmount(), 0) : 0);
recipe.putInt("buyCountA", trade.getItemCostA() != null ? Math.max(trade.getItemCostA().count(), 0) : 0);
recipe.putInt("buyCountB", trade.getItemCostB() != null ? Math.max(trade.getItemCostB().count(), 0) : 0);
recipe.putInt("demand", trade.getDemand()); // Seems to have no effect
recipe.putInt("tier", packet.getVillagerLevel() > 0 ? packet.getVillagerLevel() - 1 : 0); // -1 crashes client
recipe.put("buyA", getItemTag(session, trade.getFirstInput(), trade.getSpecialPrice(), trade.getDemand(), trade.getPriceMultiplier()));
recipe.put("buyB", getItemTag(session, trade.getSecondInput()));
recipe.putInt("uses", trade.getNumUses());
recipe.put("buyA", getItemTag(session, toItemStack(trade.getItemCostA()), trade.getSpecialPriceDiff(), trade.getDemand(), trade.getPriceMultiplier()));
recipe.put("buyB", getItemTag(session, toItemStack(trade.getItemCostB())));
recipe.putInt("uses", trade.getUses());
recipe.putByte("rewardExp", (byte) 1);
tags.add(recipe.build());
}
@@ -158,6 +158,11 @@ public class JavaMerchantOffersTranslator extends PacketTranslator<ClientboundMe
session.sendUpstreamPacket(updateTradePacket);
}
private static ItemStack toItemStack(VillagerTrade.ItemCost itemCost) {
// TODO 1.21.5 figure out how to deal with components here!
return new ItemStack(itemCost.itemId(), itemCost.count());
}
private static NbtMap getItemTag(GeyserSession session, ItemStack stack) {
if (InventoryUtils.isEmpty(stack)) { // Negative item counts appear as air on Java
return NbtMap.EMPTY;

View File

@@ -59,23 +59,23 @@ public class JavaGameEventTranslator extends PacketTranslator<ClientboundGameEve
// However, it seems most server software (at least Spigot and Paper) did not go along with this
// As a result many developers use these packets for the opposite of what their names implies
// Behavior last verified with Java 1.19.4 and Bedrock 1.19.71
case START_RAIN:
case START_RAINING:
session.updateRain(0);
break;
case STOP_RAIN:
case STOP_RAINING:
session.updateRain(1);
break;
case RAIN_STRENGTH:
case RAIN_LEVEL_CHANGE:
// This is the rain strength on LevelEventType.START_RAINING, but can be any value on LevelEventType.STOP_RAINING
float rainStrength = ((RainStrengthValue) packet.getValue()).getStrength();
session.updateRain(rainStrength);
break;
case THUNDER_STRENGTH:
case THUNDER_LEVEL_CHANGE:
// See above, same process
float thunderStrength = ((ThunderStrengthValue) packet.getValue()).getStrength();
session.updateThunder(thunderStrength);
break;
case CHANGE_GAMEMODE:
case CHANGE_GAME_MODE:
GameMode gameMode = (GameMode) packet.getValue();
SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket();
@@ -100,7 +100,7 @@ public class JavaGameEventTranslator extends PacketTranslator<ClientboundGameEve
// Update the crafting grid to add/remove barriers for creative inventory
PlayerInventoryTranslator.updateCraftingGrid(session, session.getPlayerInventory());
break;
case ENTER_CREDITS:
case WIN_GAME:
switch ((EnterCreditsValue) packet.getValue()) {
case SEEN_BEFORE -> {
ServerboundClientCommandPacket javaRespawnPacket = new ServerboundClientCommandPacket(ClientCommand.RESPAWN);
@@ -114,7 +114,7 @@ public class JavaGameEventTranslator extends PacketTranslator<ClientboundGameEve
}
}
break;
case AFFECTED_BY_ELDER_GUARDIAN:
case GUARDIAN_ELDER_EFFECT:
// note: There is a ElderGuardianEffectValue that determines if a sound should be made or not,
// but that doesn't seem to be controllable on Bedrock Edition
EntityEventPacket eventPacket = new EntityEventPacket();
@@ -123,18 +123,18 @@ public class JavaGameEventTranslator extends PacketTranslator<ClientboundGameEve
eventPacket.setRuntimeEntityId(entity.getGeyserId());
session.sendUpstreamPacket(eventPacket);
break;
case ENABLE_RESPAWN_SCREEN:
case IMMEDIATE_RESPAWN:
GameRulesChangedPacket gamerulePacket = new GameRulesChangedPacket();
gamerulePacket.getGameRules().add(new GameRuleData<>("doimmediaterespawn",
packet.getValue() == RespawnScreenValue.IMMEDIATE_RESPAWN));
session.sendUpstreamPacket(gamerulePacket);
break;
case INVALID_BED:
case NO_RESPAWN_BLOCK_AVAILABLE:
// Not sent as a proper message? Odd.
session.sendMessage(MinecraftLocale.getLocaleString("block.minecraft.spawn.not_valid",
session.locale()));
break;
case ARROW_HIT_PLAYER:
case PLAY_ARROW_HIT_SOUND:
PlaySoundPacket arrowSoundPacket = new PlaySoundPacket();
arrowSoundPacket.setSound("random.orb");
arrowSoundPacket.setPitch(0.5f);
@@ -143,9 +143,9 @@ public class JavaGameEventTranslator extends PacketTranslator<ClientboundGameEve
session.sendUpstreamPacket(arrowSoundPacket);
break;
default:
// DEMO_MESSAGE - for JE game demo
// DEMO_EVENT - for JE game demo
// LEVEL_CHUNKS_LOAD_START - ???
// PUFFERFISH_STING_SOUND - doesn't exist on bedrock
// PUFFER_FISH_STING - doesn't exist on bedrock
break;
}
}

View File

@@ -156,7 +156,8 @@ public class StructureBlockUtils {
settings.getIntegritySeed(),
settings.isIgnoringEntities(),
false,
boundingBoxVisible
boundingBoxVisible,
false // TODO 1.21.5 test
);
session.sendDownstreamPacket(structureBlockPacket);

File diff suppressed because it is too large Load Diff

View File

@@ -25,40 +25,18 @@
package org.geysermc.geyser.scoreboard.network;
import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacket;
import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacketMatch;
import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacketType;
import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNoNextPacket;
import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockContextScoreboard;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.EnumSet;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import net.kyori.adventure.text.Component;
import org.cloudburstmc.protocol.bedrock.data.ScoreInfo;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket;
import org.cloudburstmc.protocol.bedrock.packet.AddPlayerPacket;
import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket;
import org.cloudburstmc.protocol.bedrock.packet.PlayerListPacket;
import org.cloudburstmc.protocol.bedrock.packet.RemoveEntityPacket;
import org.cloudburstmc.protocol.bedrock.packet.SetDisplayObjectivePacket;
import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket;
import org.cloudburstmc.protocol.bedrock.packet.SetScorePacket;
import org.geysermc.geyser.entity.type.living.monster.EnderDragonPartEntity;
import org.geysermc.geyser.session.cache.EntityCache;
import org.geysermc.geyser.translator.protocol.java.entity.JavaRemoveEntitiesTranslator;
import org.geysermc.geyser.translator.protocol.java.entity.JavaSetEntityDataTranslator;
import org.geysermc.geyser.translator.protocol.java.entity.player.JavaPlayerInfoUpdateTranslator;
import org.geysermc.geyser.translator.protocol.java.entity.spawn.JavaAddEntityTranslator;
import org.geysermc.geyser.translator.protocol.java.entity.spawn.JavaAddExperienceOrbTranslator;
import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetDisplayObjectiveTranslator;
import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetObjectiveTranslator;
import org.geysermc.geyser.translator.protocol.java.entity.JavaAddEntityTranslator;
import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetPlayerTeamTranslator;
import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetScoreTranslator;
import org.geysermc.mcprotocollib.auth.GameProfile;
import org.geysermc.mcprotocollib.protocol.data.game.PlayerListEntry;
import org.geysermc.mcprotocollib.protocol.data.game.PlayerListEntryAction;
@@ -71,53 +49,55 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.CollisionRule;
import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.NameTagVisibility;
import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ObjectiveAction;
import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreType;
import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition;
import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamAction;
import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundPlayerInfoUpdatePacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundRemoveEntitiesPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundSetEntityDataPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddEntityPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddExperienceOrbPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetDisplayObjectivePacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetObjectivePacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetPlayerTeamPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetScorePacket;
import org.junit.jupiter.api.Test;
import java.util.EnumSet;
import java.util.Optional;
import java.util.UUID;
import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.*;
import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockContextScoreboard;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* Tests for issues reported on GitHub.
*/
public class ScoreboardIssueTests {
/**
* Test for <a href="https://github.com/GeyserMC/Geyser/issues/5075">#5075</a>
*/
@Test
void entityWithoutUuid() {
// experience orbs are the only known entities without an uuid, see Entity#teamIdentifier for more info
mockContextScoreboard(context -> {
var addExperienceOrbTranslator = new JavaAddExperienceOrbTranslator();
var removeEntitiesTranslator = new JavaRemoveEntitiesTranslator();
// Entity#teamIdentifier used to throw because it returned uuid.toString where uuid could be null.
// this would result in both EntityCache#spawnEntity and EntityCache#removeEntity throwing an exception,
// because the entity would be registered and deregistered to the scoreboard.
assertDoesNotThrow(() -> {
context.translate(addExperienceOrbTranslator, new ClientboundAddExperienceOrbPacket(2, 0, 0, 0, 1));
String displayName = context.mockOrSpy(EntityCache.class).getEntityByJavaId(2).getDisplayName();
assertEquals("entity.minecraft.experience_orb", displayName);
context.translate(removeEntitiesTranslator, new ClientboundRemoveEntitiesPacket(new int[]{2}));
});
// we know that spawning and removing the entity should be fine
assertNextPacketType(context, AddEntityPacket.class);
assertNextPacketType(context, RemoveEntityPacket.class);
});
}
// TODO 1.21.5
// /**
// * Test for <a href="https://github.com/GeyserMC/Geyser/issues/5075">#5075</a>
// */
// @Test
// void entityWithoutUuid() {
// // experience orbs are the only known entities without an uuid, see Entity#teamIdentifier for more info
// mockContextScoreboard(context -> {
// var addExperienceOrbTranslator = new JavaAddExperienceOrbTranslator();
// var removeEntitiesTranslator = new JavaRemoveEntitiesTranslator();
//
// // Entity#teamIdentifier used to throw because it returned uuid.toString where uuid could be null.
// // this would result in both EntityCache#spawnEntity and EntityCache#removeEntity throwing an exception,
// // because the entity would be registered and deregistered to the scoreboard.
// assertDoesNotThrow(() -> {
// context.translate(addExperienceOrbTranslator, new ClientboundAddExperienceOrbPacket(2, 0, 0, 0, 1));
//
// String displayName = context.mockOrSpy(EntityCache.class).getEntityByJavaId(2).getDisplayName();
// assertEquals("entity.minecraft.experience_orb", displayName);
//
// context.translate(removeEntitiesTranslator, new ClientboundRemoveEntitiesPacket(new int[] { 2 }));
// });
//
// // we know that spawning and removing the entity should be fine
// assertNextPacketType(context, AddEntityPacket.class);
// assertNextPacketType(context, RemoveEntityPacket.class);
// });
// }
/**
* Test for <a href="https://github.com/GeyserMC/Geyser/issues/5078">#5078</a>
@@ -270,76 +250,4 @@ public class ScoreboardIssueTests {
});
});
}
/**
* Test for <a href="https://github.com/GeyserMC/Geyser/issues/5353">#5353</a>.
* It follows a code snippet provided in <a href="https://github.com/GeyserMC/Geyser/pull/5415">the PR description</a>.
*/
@Test
void prefixNotShowing() {
mockContextScoreboard(context -> {
var setObjectiveTranslator = new JavaSetObjectiveTranslator();
var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator();
var setPlayerTeamTranslator = new JavaSetPlayerTeamTranslator();
var setScoreTranslator = new JavaSetScoreTranslator();
context.translate(
setObjectiveTranslator,
new ClientboundSetObjectivePacket(
"sb-0",
ObjectiveAction.ADD,
Component.text("Test Scoreboard"),
ScoreType.INTEGER,
null
)
);
assertNoNextPacket(context);
context.translate(
setDisplayObjectiveTranslator,
new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "sb-0")
);
assertNextPacket(context, () -> {
var packet = new SetDisplayObjectivePacket();
packet.setObjectiveId("0");
packet.setDisplayName("Test Scoreboard");
packet.setCriteria("dummy");
packet.setDisplaySlot("sidebar");
packet.setSortOrder(1);
return packet;
});
context.translate(
setPlayerTeamTranslator,
new ClientboundSetPlayerTeamPacket(
"sbt-1",
Component.text("displaynametest"),
Component.text("§aScore: 10"),
Component.empty(),
false,
false,
NameTagVisibility.NEVER,
CollisionRule.NEVER,
TeamColor.DARK_GREEN,
new String[]{"§0"})
);
assertNoNextPacket(context);
context.translate(
setScoreTranslator,
new ClientboundSetScorePacket(
"§0",
"sb-0",
10
).withDisplay(Component.empty())
);
assertNextPacket(context, () -> {
var packet = new SetScorePacket();
packet.setAction(SetScorePacket.Action.SET);
packet.setInfos(List.of(new ScoreInfo(1, "0", 10, "§2§aScore: 10§r§2§r§2")));
return packet;
});
assertNoNextPacket(context);
});
}
}

View File

@@ -15,7 +15,7 @@ protocol-common = "3.0.0.Beta6-20250324.162731-5"
protocol-codec = "3.0.0.Beta6-20250324.162731-5"
raknet = "1.0.0.CR3-20250218.160705-18"
minecraftauth = "4.1.1"
mcprotocollib = "1.21.4-20250311.232133-24"
mcprotocollib = "1.21.5-SNAPSHOT"
adventure = "4.14.0"
adventure-platform = "4.3.0"
junit = "5.9.2"