3
0
Mirror von https://github.com/GeyserMC/Geyser.git synchronisiert 2024-11-20 06:50:09 +01:00

Merge pull request #3817 from GeyserMC/feature/1.20

Dieser Commit ist enthalten in:
Redned 2023-06-07 10:47:44 -05:00 committet von GitHub
Commit b78ca431b6
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 4AEE18F83AFDEB23
68 geänderte Dateien mit 12483 neuen und 40804 gelöschten Zeilen

Datei anzeigen

@ -6,7 +6,7 @@ plugins {
allprojects { allprojects {
group = "org.geysermc.geyser" group = "org.geysermc.geyser"
version = "2.1.0-SNAPSHOT" version = "2.1.1-SNAPSHOT"
description = "Allows for players from Minecraft: Bedrock Edition to join Minecraft: Java Edition servers." description = "Allows for players from Minecraft: Bedrock Edition to join Minecraft: Java Edition servers."
tasks.withType<JavaCompile> { tasks.withType<JavaCompile> {

Datei anzeigen

@ -133,6 +133,7 @@ public final class EntityDefinitions {
public static final EntityDefinition<AbstractFishEntity> SALMON; public static final EntityDefinition<AbstractFishEntity> SALMON;
public static final EntityDefinition<SheepEntity> SHEEP; public static final EntityDefinition<SheepEntity> SHEEP;
public static final EntityDefinition<ShulkerEntity> SHULKER; public static final EntityDefinition<ShulkerEntity> SHULKER;
public static final EntityDefinition<SnifferEntity> SNIFFER;
public static final EntityDefinition<ThrowableEntity> SHULKER_BULLET; public static final EntityDefinition<ThrowableEntity> SHULKER_BULLET;
public static final EntityDefinition<MonsterEntity> SILVERFISH; public static final EntityDefinition<MonsterEntity> SILVERFISH;
public static final EntityDefinition<SkeletonEntity> SKELETON; public static final EntityDefinition<SkeletonEntity> SKELETON;
@ -235,7 +236,7 @@ public final class EntityDefinitions {
.type(EntityType.EXPERIENCE_ORB) .type(EntityType.EXPERIENCE_ORB)
.identifier("minecraft:xp_orb") .identifier("minecraft:xp_orb")
.build(); .build();
EVOKER_FANGS = EntityDefinition.builder(EvokerFangsEntity::new) // No entity metadata to listen to as of 1.18.1 EVOKER_FANGS = EntityDefinition.inherited(EvokerFangsEntity::new, entityBase)
.type(EntityType.EVOKER_FANGS) .type(EntityType.EVOKER_FANGS)
.height(0.8f).width(0.5f) .height(0.8f).width(0.5f)
.identifier("minecraft:evocation_fang") .identifier("minecraft:evocation_fang")
@ -842,6 +843,12 @@ public final class EntityDefinitions {
.height(1.3f).width(0.9f) .height(1.3f).width(0.9f)
.addTranslator(MetadataType.BYTE, SheepEntity::setSheepFlags) .addTranslator(MetadataType.BYTE, SheepEntity::setSheepFlags)
.build(); .build();
SNIFFER = EntityDefinition.inherited(SnifferEntity::new, ageableEntityBase)
.type(EntityType.SNIFFER)
.height(1.75f).width(1.9f)
.addTranslator(MetadataType.SNIFFER_STATE, SnifferEntity::setSnifferState)
.addTranslator(null) // Integer, drop seed at tick
.build();
STRIDER = EntityDefinition.inherited(StriderEntity::new, ageableEntityBase) STRIDER = EntityDefinition.inherited(StriderEntity::new, ageableEntityBase)
.type(EntityType.STRIDER) .type(EntityType.STRIDER)
.height(1.7f).width(0.9f) .height(1.7f).width(0.9f)
@ -884,7 +891,6 @@ public final class EntityDefinitions {
.build(); .build();
CAMEL = EntityDefinition.inherited(CamelEntity::new, abstractHorseEntityBase) CAMEL = EntityDefinition.inherited(CamelEntity::new, abstractHorseEntityBase)
.type(EntityType.CAMEL) .type(EntityType.CAMEL)
.identifier("minecraft:llama") // todo 1.20
.height(2.375f).width(1.7f) .height(2.375f).width(1.7f)
.addTranslator(MetadataType.BOOLEAN, CamelEntity::setDashing) .addTranslator(MetadataType.BOOLEAN, CamelEntity::setDashing)
.addTranslator(null) // Last pose change tick .addTranslator(null) // Last pose change tick

Datei anzeigen

@ -35,7 +35,7 @@ import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket; import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;

Datei anzeigen

@ -41,7 +41,7 @@ import lombok.Setter;
import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.protocol.bedrock.data.AttributeData; import org.cloudburstmc.protocol.bedrock.data.AttributeData;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;

Datei anzeigen

@ -0,0 +1,124 @@
/*
* Copyright (c) 2019-2023 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.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.SnifferState;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.LevelEvent;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.entity.type.Tickable;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
import java.util.UUID;
public class SnifferEntity extends AnimalEntity implements Tickable {
private static final float DIGGING_HEIGHT = EntityDefinitions.SNIFFER.height() - 0.4f;
private static final int DIG_END = 120;
private static final int DIG_START = DIG_END - 34;
private Pose pose = Pose.STANDING; // Needed to call setDimensions for DIGGING state
private int digTicks;
public SnifferEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
}
@Override
public void setPose(Pose pose) {
this.pose = pose;
super.setPose(pose);
}
@Override
protected void setDimensions(Pose pose) {
if (getFlag(EntityFlag.DIGGING)) {
setBoundingBoxHeight(DIGGING_HEIGHT);
setBoundingBoxWidth(definition.width());
} else {
super.setDimensions(pose);
}
}
@Override
public boolean canEat(Item item) {
return session.getTagCache().isSnifferFood(item);
}
public void setSnifferState(ObjectEntityMetadata<SnifferState> entityMetadata) {
SnifferState snifferState = entityMetadata.getValue();
// SnifferState.SCENTING and SnifferState.IDLING not used in bedrock
// The bedrock client does the scenting animation and sound on its own
setFlag(EntityFlag.FEELING_HAPPY, snifferState == SnifferState.FEELING_HAPPY);
setFlag(EntityFlag.SCENTING, snifferState == SnifferState.SNIFFING); // SnifferState.SNIFFING -> EntityFlag.SCENTING
setFlag(EntityFlag.SEARCHING, snifferState == SnifferState.SEARCHING);
setFlag(EntityFlag.DIGGING, snifferState == SnifferState.DIGGING);
setFlag(EntityFlag.RISING, snifferState == SnifferState.RISING);
setDimensions(pose);
if (getFlag(EntityFlag.DIGGING)) {
digTicks = DIG_END;
} else {
// Handles situations where the DIGGING state is exited earlier than expected,
// such as hitting the sniffer or joining the game while it is digging
digTicks = 0;
}
}
@Override
public void tick() {
// The java client renders digging particles on its own, but bedrock does not
if (digTicks > 0 && --digTicks < DIG_START && digTicks % 5 == 0) {
Vector3f rot = Vector3f.createDirectionDeg(0, -getYaw()).mul(2.25f);
Vector3f pos = getPosition().add(rot).up(0.2f).floor(); // Handle non-full blocks
int blockId = session.getBlockMappings().getBedrockBlockId(session.getGeyser().getWorldManager().getBlockAt(session, pos.toInt().down()));
LevelEventPacket levelEventPacket = new LevelEventPacket();
levelEventPacket.setType(LevelEvent.PARTICLE_DESTROY_BLOCK_NO_SOUND);
levelEventPacket.setPosition(pos);
levelEventPacket.setData(blockId);
session.sendUpstreamPacket(levelEventPacket);
if (digTicks % 10 == 0) {
LevelSoundEventPacket levelSoundEventPacket = new LevelSoundEventPacket();
levelSoundEventPacket.setSound(SoundEvent.HIT);
levelSoundEventPacket.setPosition(pos);
levelSoundEventPacket.setExtraData(blockId);
levelSoundEventPacket.setIdentifier(":");
session.sendUpstreamPacket(levelSoundEventPacket);
}
}
}
}

Datei anzeigen

@ -27,8 +27,13 @@ package org.geysermc.geyser.entity.type.living.animal.horse;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.item.type.Item;
@ -42,12 +47,46 @@ public class CamelEntity extends AbstractHorseEntity {
public CamelEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { public CamelEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
dirtyMetadata.put(EntityDataTypes.CONTAINER_TYPE, (byte) ContainerType.HORSE.getId());
// Always tamed, but not indicated in horse flags
setFlag(EntityFlag.TAMED, true);
} }
@Override public void setHorseFlags(ByteEntityMetadata entityMetadata) {
protected void initializeMetadata() { byte xd = entityMetadata.getPrimitiveValue();
super.initializeMetadata(); boolean saddled = (xd & 0x04) == 0x04;
this.dirtyMetadata.put(EntityDataTypes.VARIANT, 2); // Closest llama colour to camel setFlag(EntityFlag.SADDLED, saddled);
setFlag(EntityFlag.EATING, (xd & 0x10) == 0x10);
setFlag(EntityFlag.STANDING, (xd & 0x20) == 0x20);
// HorseFlags
// Bred 0x10
// Eating 0x20
// Open mouth 0x80
int horseFlags = 0x0;
horseFlags = (xd & 0x40) == 0x40 ? horseFlags | 0x80 : horseFlags;
// Only set eating when we don't have mouth open so a player interaction doesn't trigger the eating animation
horseFlags = (xd & 0x10) == 0x10 && (xd & 0x40) != 0x40 ? horseFlags | 0x20 : horseFlags;
// Set the flags into the horse flags
dirtyMetadata.put(EntityDataTypes.HORSE_FLAGS, horseFlags);
// Send the eating particles
// We use the wheat metadata as static particles since Java
// doesn't send over what item was used to feed the horse
if ((xd & 0x40) == 0x40) {
EntityEventPacket entityEventPacket = new EntityEventPacket();
entityEventPacket.setRuntimeEntityId(geyserId);
entityEventPacket.setType(EntityEventType.EATING_ITEM);
entityEventPacket.setData(session.getItemMappings().getStoredItems().wheat().getBedrockDefinition().getRuntimeId() << 16);
session.sendUpstreamPacket(entityEventPacket);
}
// Shows the dash meter
setFlag(EntityFlag.CAN_DASH, saddled);
} }
@Override @Override
@ -55,6 +94,12 @@ public class CamelEntity extends AbstractHorseEntity {
return item == Items.CACTUS; return item == Items.CACTUS;
} }
@Override
public void setPose(Pose pose) {
setFlag(EntityFlag.SITTING, pose == Pose.SITTING);
super.setPose(pose);
}
@Override @Override
protected void setDimensions(Pose pose) { protected void setDimensions(Pose pose) {
if (pose == Pose.SITTING) { if (pose == Pose.SITTING) {

Datei anzeigen

@ -29,7 +29,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanE
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet; import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet;

Datei anzeigen

@ -33,7 +33,7 @@ import org.cloudburstmc.math.vector.Vector3i;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;

Datei anzeigen

@ -0,0 +1,94 @@
/*
* Copyright (c) 2019-2023 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.inventory.recipe;
import org.cloudburstmc.protocol.bedrock.data.TrimMaterial;
import org.cloudburstmc.protocol.bedrock.data.TrimPattern;
import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount;
import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemTagDescriptor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Hardcoded recipe information about armor trims until further improvements can be made. This information was scraped
* from BDS 1.19.81 with a world with the next_major_update and sniffer features enabled, using ProxyPass.
*/
public class TrimRecipe {
// For TrimDataPacket, which BDS sends just before the CraftingDataPacket
public static final List<TrimPattern> PATTERNS;
public static final List<TrimMaterial> MATERIALS;
// For CraftingDataPacket
public static final String ID = "minecraft:smithing_armor_trim";
public static final ItemDescriptorWithCount BASE = tagDescriptor("minecraft:trimmable_armors");
public static final ItemDescriptorWithCount ADDITION = tagDescriptor("minecraft:trim_materials");
public static final ItemDescriptorWithCount TEMPLATE = tagDescriptor("minecraft:trim_templates");
static {
List<TrimPattern> patterns = new ArrayList<>(16);
patterns.add(new TrimPattern("minecraft:ward_armor_trim_smithing_template", "ward"));
patterns.add(new TrimPattern("minecraft:sentry_armor_trim_smithing_template", "sentry"));
patterns.add(new TrimPattern("minecraft:snout_armor_trim_smithing_template", "snout"));
patterns.add(new TrimPattern("minecraft:dune_armor_trim_smithing_template", "dune"));
patterns.add(new TrimPattern("minecraft:spire_armor_trim_smithing_template", "spire"));
patterns.add(new TrimPattern("minecraft:tide_armor_trim_smithing_template", "tide"));
patterns.add(new TrimPattern("minecraft:wild_armor_trim_smithing_template", "wild"));
patterns.add(new TrimPattern("minecraft:rib_armor_trim_smithing_template", "rib"));
patterns.add(new TrimPattern("minecraft:coast_armor_trim_smithing_template", "coast"));
patterns.add(new TrimPattern("minecraft:shaper_armor_trim_smithing_template", "shaper"));
patterns.add(new TrimPattern("minecraft:eye_armor_trim_smithing_template", "eye"));
patterns.add(new TrimPattern("minecraft:vex_armor_trim_smithing_template", "vex"));
patterns.add(new TrimPattern("minecraft:silence_armor_trim_smithing_template", "silence"));
patterns.add(new TrimPattern("minecraft:wayfinder_armor_trim_smithing_template", "wayfinder"));
patterns.add(new TrimPattern("minecraft:raiser_armor_trim_smithing_template", "raiser"));
patterns.add(new TrimPattern("minecraft:host_armor_trim_smithing_template", "host"));
PATTERNS = Collections.unmodifiableList(patterns);
List<TrimMaterial> materials = new ArrayList<>(10);
materials.add(new TrimMaterial("quartz", "§h", "minecraft:quartz"));
materials.add(new TrimMaterial("iron", "§i", "minecraft:iron_ingot"));
materials.add(new TrimMaterial("netherite", "§j", "minecraft:netherite_ingot"));
materials.add(new TrimMaterial("redstone", "§m", "minecraft:redstone"));
materials.add(new TrimMaterial("copper", "§n", "minecraft:copper_ingot"));
materials.add(new TrimMaterial("gold", "§p", "minecraft:gold_ingot"));
materials.add(new TrimMaterial("emerald", "§q", "minecraft:emerald"));
materials.add(new TrimMaterial("diamond", "§s", "minecraft:diamond"));
materials.add(new TrimMaterial("lapis", "§t", "minecraft:lapis_lazuli"));
materials.add(new TrimMaterial("amethyst", "§u", "minecraft:amethyst_shard"));
MATERIALS = Collections.unmodifiableList(materials);
}
private TrimRecipe() {
//no-op
}
private static ItemDescriptorWithCount tagDescriptor(String tag) {
return new ItemDescriptorWithCount(new ItemTagDescriptor(tag), 1);
}
}

Datei anzeigen

@ -25,7 +25,7 @@
package org.geysermc.geyser.item; package org.geysermc.geyser.item;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData;
import org.cloudburstmc.protocol.bedrock.packet.StartGamePacket; import org.cloudburstmc.protocol.bedrock.packet.StartGamePacket;

Datei anzeigen

@ -84,6 +84,7 @@ public final class Items {
public static final Item BEDROCK = register(new BlockItem("bedrock", builder())); public static final Item BEDROCK = register(new BlockItem("bedrock", builder()));
public static final Item SAND = register(new BlockItem("sand", builder())); public static final Item SAND = register(new BlockItem("sand", builder()));
public static final Item SUSPICIOUS_SAND = register(new BlockItem("suspicious_sand", builder())); public static final Item SUSPICIOUS_SAND = register(new BlockItem("suspicious_sand", builder()));
public static final Item SUSPICIOUS_GRAVEL = register(new BlockItem("suspicious_gravel", builder()));
public static final Item RED_SAND = register(new BlockItem("red_sand", builder())); public static final Item RED_SAND = register(new BlockItem("red_sand", builder()));
public static final Item GRAVEL = register(new BlockItem("gravel", builder())); public static final Item GRAVEL = register(new BlockItem("gravel", builder()));
public static final Item COAL_ORE = register(new BlockItem("coal_ore", builder())); public static final Item COAL_ORE = register(new BlockItem("coal_ore", builder()));
@ -247,6 +248,7 @@ public final class Items {
public static final Item LILY_OF_THE_VALLEY = register(new FlowerItem("lily_of_the_valley", builder())); public static final Item LILY_OF_THE_VALLEY = register(new FlowerItem("lily_of_the_valley", builder()));
public static final Item WITHER_ROSE = register(new FlowerItem("wither_rose", builder())); public static final Item WITHER_ROSE = register(new FlowerItem("wither_rose", builder()));
public static final Item TORCHFLOWER = register(new FlowerItem("torchflower", builder())); public static final Item TORCHFLOWER = register(new FlowerItem("torchflower", builder()));
public static final Item PITCHER_PLANT = register(new BlockItem("pitcher_plant", builder()));
public static final Item SPORE_BLOSSOM = register(new BlockItem("spore_blossom", builder())); public static final Item SPORE_BLOSSOM = register(new BlockItem("spore_blossom", builder()));
public static final Item BROWN_MUSHROOM = register(new BlockItem("brown_mushroom", builder())); public static final Item BROWN_MUSHROOM = register(new BlockItem("brown_mushroom", builder()));
public static final Item RED_MUSHROOM = register(new BlockItem("red_mushroom", builder())); public static final Item RED_MUSHROOM = register(new BlockItem("red_mushroom", builder()));
@ -602,6 +604,7 @@ public final class Items {
public static final Item RED_CONCRETE_POWDER = register(new BlockItem("red_concrete_powder", builder())); public static final Item RED_CONCRETE_POWDER = register(new BlockItem("red_concrete_powder", builder()));
public static final Item BLACK_CONCRETE_POWDER = register(new BlockItem("black_concrete_powder", builder())); public static final Item BLACK_CONCRETE_POWDER = register(new BlockItem("black_concrete_powder", builder()));
public static final Item TURTLE_EGG = register(new BlockItem("turtle_egg", builder())); public static final Item TURTLE_EGG = register(new BlockItem("turtle_egg", builder()));
public static final Item SNIFFER_EGG = register(new BlockItem("sniffer_egg", builder()));
public static final Item DEAD_TUBE_CORAL_BLOCK = register(new BlockItem("dead_tube_coral_block", builder())); public static final Item DEAD_TUBE_CORAL_BLOCK = register(new BlockItem("dead_tube_coral_block", builder()));
public static final Item DEAD_BRAIN_CORAL_BLOCK = register(new BlockItem("dead_brain_coral_block", builder())); public static final Item DEAD_BRAIN_CORAL_BLOCK = register(new BlockItem("dead_brain_coral_block", builder()));
public static final Item DEAD_BUBBLE_CORAL_BLOCK = register(new BlockItem("dead_bubble_coral_block", builder())); public static final Item DEAD_BUBBLE_CORAL_BLOCK = register(new BlockItem("dead_bubble_coral_block", builder()));
@ -689,6 +692,7 @@ public final class Items {
public static final Item LIGHTNING_ROD = register(new BlockItem("lightning_rod", builder())); public static final Item LIGHTNING_ROD = register(new BlockItem("lightning_rod", builder()));
public static final Item DAYLIGHT_DETECTOR = register(new BlockItem("daylight_detector", builder())); public static final Item DAYLIGHT_DETECTOR = register(new BlockItem("daylight_detector", builder()));
public static final Item SCULK_SENSOR = register(new BlockItem("sculk_sensor", builder())); public static final Item SCULK_SENSOR = register(new BlockItem("sculk_sensor", builder()));
public static final Item CALIBRATED_SCULK_SENSOR = register(new BlockItem("calibrated_sculk_sensor", builder()));
public static final Item TRIPWIRE_HOOK = register(new BlockItem("tripwire_hook", builder())); public static final Item TRIPWIRE_HOOK = register(new BlockItem("tripwire_hook", builder()));
public static final Item TRAPPED_CHEST = register(new BlockItem("trapped_chest", builder())); public static final Item TRAPPED_CHEST = register(new BlockItem("trapped_chest", builder()));
public static final Item TNT = register(new BlockItem("tnt", builder())); public static final Item TNT = register(new BlockItem("tnt", builder()));
@ -1141,6 +1145,7 @@ public final class Items {
public static final Item CHORUS_FRUIT = register(new Item("chorus_fruit", builder())); public static final Item CHORUS_FRUIT = register(new Item("chorus_fruit", builder()));
public static final Item POPPED_CHORUS_FRUIT = register(new Item("popped_chorus_fruit", builder())); public static final Item POPPED_CHORUS_FRUIT = register(new Item("popped_chorus_fruit", builder()));
public static final Item TORCHFLOWER_SEEDS = register(new BlockItem("torchflower_seeds", builder())); public static final Item TORCHFLOWER_SEEDS = register(new BlockItem("torchflower_seeds", builder()));
public static final Item PITCHER_POD = register(new BlockItem("pitcher_pod", builder()));
public static final Item BEETROOT = register(new Item("beetroot", builder())); public static final Item BEETROOT = register(new Item("beetroot", builder()));
public static final Item BEETROOT_SEEDS = register(new BlockItem("beetroot_seeds", builder())); public static final Item BEETROOT_SEEDS = register(new BlockItem("beetroot_seeds", builder()));
public static final Item BEETROOT_SOUP = register(new Item("beetroot_soup", builder().stackSize(1))); public static final Item BEETROOT_SOUP = register(new Item("beetroot_soup", builder().stackSize(1)));
@ -1168,6 +1173,7 @@ public final class Items {
public static final Item MUSIC_DISC_11 = register(new Item("music_disc_11", builder().stackSize(1))); public static final Item MUSIC_DISC_11 = register(new Item("music_disc_11", builder().stackSize(1)));
public static final Item MUSIC_DISC_WAIT = register(new Item("music_disc_wait", builder().stackSize(1))); public static final Item MUSIC_DISC_WAIT = register(new Item("music_disc_wait", builder().stackSize(1)));
public static final Item MUSIC_DISC_OTHERSIDE = register(new Item("music_disc_otherside", builder().stackSize(1))); public static final Item MUSIC_DISC_OTHERSIDE = register(new Item("music_disc_otherside", builder().stackSize(1)));
public static final Item MUSIC_DISC_RELIC = register(new Item("music_disc_relic", builder().stackSize(1)));
public static final Item MUSIC_DISC_5 = register(new Item("music_disc_5", builder().stackSize(1))); public static final Item MUSIC_DISC_5 = register(new Item("music_disc_5", builder().stackSize(1)));
public static final Item MUSIC_DISC_PIGSTEP = register(new Item("music_disc_pigstep", builder().stackSize(1))); public static final Item MUSIC_DISC_PIGSTEP = register(new Item("music_disc_pigstep", builder().stackSize(1)));
public static final Item DISC_FRAGMENT_5 = register(new Item("disc_fragment_5", builder())); public static final Item DISC_FRAGMENT_5 = register(new Item("disc_fragment_5", builder()));
@ -1262,10 +1268,31 @@ public final class Items {
public static final Item SNOUT_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("snout_armor_trim_smithing_template", builder())); public static final Item SNOUT_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("snout_armor_trim_smithing_template", builder()));
public static final Item RIB_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("rib_armor_trim_smithing_template", builder())); public static final Item RIB_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("rib_armor_trim_smithing_template", builder()));
public static final Item SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("spire_armor_trim_smithing_template", builder())); public static final Item SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("spire_armor_trim_smithing_template", builder()));
public static final Item POTTERY_SHARD_ARCHER = register(new Item("pottery_shard_archer", builder())); public static final Item WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("wayfinder_armor_trim_smithing_template", builder()));
public static final Item POTTERY_SHARD_PRIZE = register(new Item("pottery_shard_prize", builder())); public static final Item SHAPER_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("shaper_armor_trim_smithing_template", builder()));
public static final Item POTTERY_SHARD_ARMS_UP = register(new Item("pottery_shard_arms_up", builder())); public static final Item SILENCE_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("silence_armor_trim_smithing_template", builder()));
public static final Item POTTERY_SHARD_SKULL = register(new Item("pottery_shard_skull", builder())); public static final Item RAISER_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("raiser_armor_trim_smithing_template", builder()));
public static final Item HOST_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("host_armor_trim_smithing_template", builder()));
public static final Item ANGLER_POTTERY_SHERD = register(new Item("angler_pottery_sherd", builder()));
public static final Item ARCHER_POTTERY_SHERD = register(new Item("archer_pottery_sherd", builder()));
public static final Item ARMS_UP_POTTERY_SHERD = register(new Item("arms_up_pottery_sherd", builder()));
public static final Item BLADE_POTTERY_SHERD = register(new Item("blade_pottery_sherd", builder()));
public static final Item BREWER_POTTERY_SHERD = register(new Item("brewer_pottery_sherd", builder()));
public static final Item BURN_POTTERY_SHERD = register(new Item("burn_pottery_sherd", builder()));
public static final Item DANGER_POTTERY_SHERD = register(new Item("danger_pottery_sherd", builder()));
public static final Item EXPLORER_POTTERY_SHERD = register(new Item("explorer_pottery_sherd", builder()));
public static final Item FRIEND_POTTERY_SHERD = register(new Item("friend_pottery_sherd", builder()));
public static final Item HEART_POTTERY_SHERD = register(new Item("heart_pottery_sherd", builder()));
public static final Item HEARTBREAK_POTTERY_SHERD = register(new Item("heartbreak_pottery_sherd", builder()));
public static final Item HOWL_POTTERY_SHERD = register(new Item("howl_pottery_sherd", builder()));
public static final Item MINER_POTTERY_SHERD = register(new Item("miner_pottery_sherd", builder()));
public static final Item MOURNER_POTTERY_SHERD = register(new Item("mourner_pottery_sherd", builder()));
public static final Item PLENTY_POTTERY_SHERD = register(new Item("plenty_pottery_sherd", builder()));
public static final Item PRIZE_POTTERY_SHERD = register(new Item("prize_pottery_sherd", builder()));
public static final Item SHEAF_POTTERY_SHERD = register(new Item("sheaf_pottery_sherd", builder()));
public static final Item SHELTER_POTTERY_SHERD = register(new Item("shelter_pottery_sherd", builder()));
public static final Item SKULL_POTTERY_SHERD = register(new Item("skull_pottery_sherd", builder()));
public static final Item SNORT_POTTERY_SHERD = register(new Item("snort_pottery_sherd", builder()));
private static <T extends Item> T register(T item) { private static <T extends Item> T register(T item) {
return register(item, Registries.JAVA_ITEMS.get().size()); return register(item, Registries.JAVA_ITEMS.get().size());

Datei anzeigen

@ -28,7 +28,7 @@ package org.geysermc.geyser.item.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag; import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.inventory.item.Potion; import org.geysermc.geyser.inventory.item.Potion;

Datei anzeigen

@ -25,13 +25,40 @@
package org.geysermc.geyser.item.type; package org.geysermc.geyser.item.type;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.IntTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.item.components.ToolTier; import org.geysermc.geyser.item.components.ToolTier;
import org.geysermc.geyser.session.GeyserSession;
public class ShieldItem extends Item { public class ShieldItem extends Item {
public ShieldItem(String javaIdentifier, Builder builder) { public ShieldItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder); super(javaIdentifier, builder);
} }
@Override
public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) {
super.translateNbtToBedrock(session, tag);
if (tag.remove("BlockEntityTag") instanceof CompoundTag blockEntityTag) {
if (blockEntityTag.get("Patterns") instanceof ListTag patterns) {
for (Tag pattern : patterns) {
if (((CompoundTag) pattern).get("Color") instanceof IntTag color) {
color.setValue(15 - color.getValue());
}
}
// Bedrock looks for patterns at the root
tag.put(patterns);
}
if (blockEntityTag.get("Base") instanceof IntTag base) {
base.setValue(15 - base.getValue());
tag.put(base);
}
}
}
@Override @Override
public boolean isValidRepairItem(Item other) { public boolean isValidRepairItem(Item other) {
// Java Edition 1.19.3 checks the tag, but TODO check to see if we want it or are simulating what Bedrock is doing // Java Edition 1.19.3 checks the tag, but TODO check to see if we want it or are simulating what Bedrock is doing

Datei anzeigen

@ -45,6 +45,7 @@ import java.util.Locale;
*/ */
public final class BlockStateValues { public final class BlockStateValues {
private static final IntSet ALL_CAULDRONS = new IntOpenHashSet(); private static final IntSet ALL_CAULDRONS = new IntOpenHashSet();
private static final IntSet HANGING_SIGNS = new IntOpenHashSet();
private static final Int2IntMap BANNER_COLORS = new FixedInt2IntMap(); private static final Int2IntMap BANNER_COLORS = new FixedInt2IntMap();
private static final Int2ByteMap BED_COLORS = new FixedInt2ByteMap(); private static final Int2ByteMap BED_COLORS = new FixedInt2ByteMap();
private static final Int2ByteMap COMMAND_BLOCK_VALUES = new Int2ByteOpenHashMap(); private static final Int2ByteMap COMMAND_BLOCK_VALUES = new Int2ByteOpenHashMap();
@ -86,6 +87,12 @@ public final class BlockStateValues {
* @param blockData JsonNode of info about the block from blocks.json * @param blockData JsonNode of info about the block from blocks.json
*/ */
public static void storeBlockStateValues(String javaId, int javaBlockState, JsonNode blockData) { public static void storeBlockStateValues(String javaId, int javaBlockState, JsonNode blockData) {
if (javaId.contains("_hanging_sign")) {
// covers hanging_sign and wall_hanging_sign
HANGING_SIGNS.add(javaBlockState);
return;
}
JsonNode bannerColor = blockData.get("banner_color"); JsonNode bannerColor = blockData.get("banner_color");
if (bannerColor != null) { if (bannerColor != null) {
BANNER_COLORS.put(javaBlockState, (byte) bannerColor.intValue()); BANNER_COLORS.put(javaBlockState, (byte) bannerColor.intValue());
@ -203,6 +210,17 @@ public final class BlockStateValues {
} }
} }
/**
* Hanging signs have a different maximum text width than "normal" signs. As a result, when the client
* updates the text of a sign without indication of the sign type, we must determine it.
*
* @param state BlockState of the block
* @return true if the sign is any hanging variant
*/
public static boolean isHangingSign(int state) {
return HANGING_SIGNS.contains(state);
}
/** /**
* Banner colors are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock. * Banner colors are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock.
* This gives an integer color that Bedrock can use. * This gives an integer color that Bedrock can use.

Datei anzeigen

@ -28,12 +28,8 @@ package org.geysermc.geyser.network;
import com.github.steveice10.mc.protocol.codec.MinecraftCodec; import com.github.steveice10.mc.protocol.codec.MinecraftCodec;
import com.github.steveice10.mc.protocol.codec.PacketCodec; import com.github.steveice10.mc.protocol.codec.PacketCodec;
import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec;
import org.cloudburstmc.protocol.bedrock.codec.v557.Bedrock_v557;
import org.cloudburstmc.protocol.bedrock.codec.v560.Bedrock_v560;
import org.cloudburstmc.protocol.bedrock.codec.v567.Bedrock_v567;
import org.cloudburstmc.protocol.bedrock.codec.v568.Bedrock_v568;
import org.cloudburstmc.protocol.bedrock.codec.v575.Bedrock_v575;
import org.cloudburstmc.protocol.bedrock.codec.v582.Bedrock_v582; import org.cloudburstmc.protocol.bedrock.codec.v582.Bedrock_v582;
import org.cloudburstmc.protocol.bedrock.codec.v589.Bedrock_v589;
import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec; import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
@ -49,9 +45,8 @@ public final class GameProtocol {
* Default Bedrock codec that should act as a fallback. Should represent the latest available * Default Bedrock codec that should act as a fallback. Should represent the latest available
* release of the game that Geyser supports. * release of the game that Geyser supports.
*/ */
public static final BedrockCodec DEFAULT_BEDROCK_CODEC = Bedrock_v582.CODEC.toBuilder() public static final BedrockCodec DEFAULT_BEDROCK_CODEC = Bedrock_v589.CODEC;
.minecraftVersion("1.19.81")
.build();
/** /**
* A list of all supported Bedrock versions that can join Geyser * A list of all supported Bedrock versions that can join Geyser
*/ */
@ -64,20 +59,10 @@ public final class GameProtocol {
private static final PacketCodec DEFAULT_JAVA_CODEC = MinecraftCodec.CODEC; private static final PacketCodec DEFAULT_JAVA_CODEC = MinecraftCodec.CODEC;
static { static {
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v557.CODEC.toBuilder() SUPPORTED_BEDROCK_CODECS.add(Bedrock_v582.CODEC.toBuilder()
.minecraftVersion("1.19.40/1.19.41")
.build());
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v560.CODEC.toBuilder()
.minecraftVersion("1.19.50/1.19.51")
.build());
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v567.CODEC);
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v568.CODEC);
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v575.CODEC.toBuilder()
.minecraftVersion("1.19.70/1.19.71/1.19.73")
.build());
SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder()
.minecraftVersion("1.19.80/1.19.81") .minecraftVersion("1.19.80/1.19.81")
.build()); .build());
SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC);
} }
/** /**
@ -96,16 +81,8 @@ public final class GameProtocol {
/* Bedrock convenience methods to gatekeep features and easily remove the check on version removal */ /* Bedrock convenience methods to gatekeep features and easily remove the check on version removal */
public static boolean supports1_19_50(GeyserSession session) { public static boolean isPre1_20(GeyserSession session) {
return session.getUpstream().getProtocolVersion() >= Bedrock_v560.CODEC.getProtocolVersion(); return session.getUpstream().getProtocolVersion() < Bedrock_v589.CODEC.getProtocolVersion();
}
public static boolean supports1_19_60(GeyserSession session) {
return session.getUpstream().getProtocolVersion() >= Bedrock_v567.CODEC.getProtocolVersion();
}
public static boolean supports1_19_80(GeyserSession session) {
return session.getUpstream().getProtocolVersion() >= Bedrock_v582.CODEC.getProtocolVersion();
} }
/** /**

Datei anzeigen

@ -47,11 +47,6 @@ public class GeyserServerInitializer extends BedrockServerInitializer {
this.geyser = geyser; this.geyser = geyser;
} }
@Override
protected void postInitChannel(Channel channel) throws Exception {
super.postInitChannel(channel);
}
@Override @Override
public void initSession(@Nonnull BedrockServerSession bedrockServerSession) { public void initSession(@Nonnull BedrockServerSession bedrockServerSession) {
try { try {

Datei anzeigen

@ -28,8 +28,6 @@ package org.geysermc.geyser.network;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import org.cloudburstmc.protocol.bedrock.BedrockDisconnectReasons; import org.cloudburstmc.protocol.bedrock.BedrockDisconnectReasons;
import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec;
import org.cloudburstmc.protocol.bedrock.codec.v567.Bedrock_v567;
import org.cloudburstmc.protocol.bedrock.codec.v568.Bedrock_v568;
import org.cloudburstmc.protocol.bedrock.data.ExperimentData; import org.cloudburstmc.protocol.bedrock.data.ExperimentData;
import org.cloudburstmc.protocol.bedrock.data.PacketCompressionAlgorithm; import org.cloudburstmc.protocol.bedrock.data.PacketCompressionAlgorithm;
import org.cloudburstmc.protocol.bedrock.data.ResourcePackType; import org.cloudburstmc.protocol.bedrock.data.ResourcePackType;
@ -173,11 +171,6 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
return PacketSignal.HANDLED; return PacketSignal.HANDLED;
} }
// Hack for... whatever this is
if (loginPacket.getProtocolVersion() == Bedrock_v567.CODEC.getProtocolVersion() && !session.getClientData().getGameVersion().equals("1.19.60")) {
session.getUpstream().getSession().setCodec(Bedrock_v568.CODEC);
}
PlayStatusPacket playStatus = new PlayStatusPacket(); PlayStatusPacket playStatus = new PlayStatusPacket();
playStatus.setStatus(PlayStatusPacket.Status.LOGIN_SUCCESS); playStatus.setStatus(PlayStatusPacket.Status.LOGIN_SUCCESS);
session.sendUpstreamPacket(playStatus); session.sendUpstreamPacket(playStatus);
@ -232,6 +225,11 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
stackPacket.getExperiments().add(new ExperimentData("data_driven_items", true)); stackPacket.getExperiments().add(new ExperimentData("data_driven_items", true));
} }
if (GameProtocol.isPre1_20(session)) {
stackPacket.getExperiments().add(new ExperimentData("next_major_update", true));
stackPacket.getExperiments().add(new ExperimentData("sniffer", true));
}
session.sendUpstreamPacket(stackPacket); session.sendUpstreamPacket(stackPacket);
break; break;

Datei anzeigen

@ -32,12 +32,9 @@ import com.google.common.collect.Interner;
import com.google.common.collect.Interners; import com.google.common.collect.Interners;
import it.unimi.dsi.fastutil.objects.*; import it.unimi.dsi.fastutil.objects.*;
import org.cloudburstmc.nbt.*; import org.cloudburstmc.nbt.*;
import org.cloudburstmc.protocol.bedrock.codec.v544.Bedrock_v544;
import org.cloudburstmc.protocol.bedrock.codec.v560.Bedrock_v560;
import org.cloudburstmc.protocol.bedrock.codec.v567.Bedrock_v567;
import org.cloudburstmc.protocol.bedrock.codec.v575.Bedrock_v575;
import org.cloudburstmc.protocol.bedrock.codec.v582.Bedrock_v582; import org.cloudburstmc.protocol.bedrock.codec.v582.Bedrock_v582;
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.codec.v589.Bedrock_v589;
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.level.physics.PistonBehavior;
@ -70,41 +67,54 @@ public final class BlockRegistryPopulator {
} }
private static void registerBedrockBlocks() { private static void registerBedrockBlocks() {
BiFunction<String, NbtMapBuilder, String> woolMapper = (bedrockIdentifier, statesBuilder) -> { BiFunction<String, NbtMapBuilder, String> emptyMapper = (bedrockIdentifier, statesBuilder) -> null;
if (bedrockIdentifier.equals("minecraft:wool")) {
String color = (String) statesBuilder.remove("color"); // We are using mappings that directly support 1.20, so this maps it back to 1.19.80
if ("silver".equals(color)) { BiFunction<String, NbtMapBuilder, String> legacyMapper = (bedrockIdentifier, statesBuilder) -> {
color = "light_gray"; if (bedrockIdentifier.endsWith("pumpkin")) {
String direction = statesBuilder.remove("minecraft:cardinal_direction").toString();
statesBuilder.putInt("direction", switch (direction) {
case "north" -> 2;
case "east" -> 3;
case "west" -> 1;
default -> 0; // south
});
} else if (bedrockIdentifier.endsWith("carpet") && !bedrockIdentifier.startsWith("minecraft:moss")) {
String color = bedrockIdentifier.replace("minecraft:", "").replace("_carpet", "");
if (color.equals("light_gray")) {
color = "silver";
} }
return "minecraft:" + color + "_wool"; statesBuilder.putString("color", color);
return "minecraft:carpet";
} else if (bedrockIdentifier.equals("minecraft:sniffer_egg")) {
statesBuilder.remove("cracked_state");
return "minecraft:dragon_egg";
} else if (bedrockIdentifier.endsWith("coral")) {
statesBuilder.putString("coral_color", "blue"); // all blue
statesBuilder.putBoolean("dead_bit", bedrockIdentifier.startsWith("minecraft:dead"));
return "minecraft:coral";
} else if (bedrockIdentifier.endsWith("sculk_sensor")) {
int phase = (int) statesBuilder.remove("sculk_sensor_phase");
statesBuilder.putBoolean("powered_bit", phase != 0);
} else if (bedrockIdentifier.endsWith("pitcher_plant")) {
statesBuilder.putString("double_plant_type", "sunflower");
return "minecraft:double_plant";
} else if (bedrockIdentifier.endsWith("pitcher_crop")) {
statesBuilder.remove("growth");
if (((byte) statesBuilder.remove("upper_block_bit")) == 1){
statesBuilder.putString("flower_type", "orchid");
return "minecraft:red_flower"; // top
}
statesBuilder.putBoolean("update_bit", false);
return "minecraft:flower_pot"; // bottom
} }
return null; return null;
}; };
BiFunction<String, NbtMapBuilder, String> emptyMapper = (bedrockIdentifier, statesBuilder) -> null;
ImmutableMap<ObjectIntPair<String>, BiFunction<String, NbtMapBuilder, String>> blockMappers = ImmutableMap.<ObjectIntPair<String>, BiFunction<String, NbtMapBuilder, String>>builder() ImmutableMap<ObjectIntPair<String>, BiFunction<String, NbtMapBuilder, String>> blockMappers = ImmutableMap.<ObjectIntPair<String>, BiFunction<String, NbtMapBuilder, String>>builder()
.put(ObjectIntPair.of("1_19_20", Bedrock_v544.CODEC.getProtocolVersion()), emptyMapper) .put(ObjectIntPair.of("1_19_80", Bedrock_v582.CODEC.getProtocolVersion()), legacyMapper)
.put(ObjectIntPair.of("1_19_50", Bedrock_v560.CODEC.getProtocolVersion()), emptyMapper) .put(ObjectIntPair.of("1_20_0", Bedrock_v589.CODEC.getProtocolVersion()), emptyMapper)
.put(ObjectIntPair.of("1_19_60", Bedrock_v567.CODEC.getProtocolVersion()), emptyMapper)
.put(ObjectIntPair.of("1_19_70", Bedrock_v575.CODEC.getProtocolVersion()), woolMapper)
.put(ObjectIntPair.of("1_19_80", Bedrock_v582.CODEC.getProtocolVersion()), (bedrockIdentifier, statesBuilder) -> {
String identifier = woolMapper.apply(bedrockIdentifier, statesBuilder);
if (identifier != null) {
return identifier;
}
switch (bedrockIdentifier) {
case "minecraft:log", "minecraft:log2" -> {
String woodType = (String) statesBuilder.remove(bedrockIdentifier.equals("minecraft:log") ? "old_log_type" : "new_log_type");
return "minecraft:" + woodType + "_log";
}
case "minecraft:fence" -> {
String woodType = (String) statesBuilder.remove("wood_type");
return "minecraft:" + woodType + "_fence";
}
default -> {
return null;
}
}
})
.build(); .build();
// We can keep this strong as nothing should be garbage collected // We can keep this strong as nothing should be garbage collected
@ -167,8 +177,8 @@ public final class BlockRegistryPopulator {
GeyserBedrockBlock bedrockDefinition = blockStateOrderedMap.get(buildBedrockState(entry.getValue(), stateVersion, stateMapper)); GeyserBedrockBlock bedrockDefinition = blockStateOrderedMap.get(buildBedrockState(entry.getValue(), stateVersion, stateMapper));
if (bedrockDefinition == null) { if (bedrockDefinition == null) {
throw new RuntimeException("Unable to find " + javaId + " Bedrock BlockDefinition! Built NBT tag: \n" + throw new RuntimeException("Unable to find " + javaId + " Bedrock BlockDefinition on version "
buildBedrockState(entry.getValue(), stateVersion, stateMapper)); + palette.getKey().key() + "! Built NBT tag: \n" + buildBedrockState(entry.getValue(), stateVersion, stateMapper));
} }
switch (javaId) { switch (javaId) {

Datei anzeigen

@ -28,7 +28,7 @@ package org.geysermc.geyser.registry.populator;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtUtils; import org.cloudburstmc.nbt.NbtUtils;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserBootstrap;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;

Datei anzeigen

@ -30,8 +30,8 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.nbt.NbtType;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.defintions.SimpleItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.SimpleItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.api.item.custom.CustomItemData; import org.geysermc.geyser.api.item.custom.CustomItemData;

Datei anzeigen

@ -34,17 +34,15 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.objects.*; import it.unimi.dsi.fastutil.objects.*;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.nbt.NbtType;
import org.cloudburstmc.protocol.bedrock.codec.v544.Bedrock_v544;
import org.cloudburstmc.protocol.bedrock.codec.v560.Bedrock_v560;
import org.cloudburstmc.protocol.bedrock.codec.v567.Bedrock_v567;
import org.cloudburstmc.protocol.bedrock.codec.v575.Bedrock_v575;
import org.cloudburstmc.protocol.bedrock.codec.v582.Bedrock_v582; import org.cloudburstmc.protocol.bedrock.codec.v582.Bedrock_v582;
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.codec.v589.Bedrock_v589;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.data.defintions.SimpleItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.definitions.SimpleItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
@ -70,22 +68,40 @@ import java.util.concurrent.atomic.AtomicInteger;
*/ */
public class ItemRegistryPopulator { public class ItemRegistryPopulator {
record PaletteVersion(int protocolVersion, Map<Item, String> additionalTranslatedItems) { record PaletteVersion(int protocolVersion, Map<Item, String> javaOnlyItems, Remapper remapper) {
public PaletteVersion(int protocolVersion) {
this(protocolVersion, Collections.emptyMap(), (item, mapping) -> mapping);
}
}
@FunctionalInterface
interface Remapper {
@NonNull
GeyserMappingItem remap(Item item, GeyserMappingItem mapping);
} }
public static void populate() { public static void populate() {
Map<Item, String> manualFallback = new HashMap<>(); Map<Item, String> legacyJavaOnly = new HashMap<>();
manualFallback.put(Items.ENDER_DRAGON_SPAWN_EGG, "minecraft:enderman_spawn_egg"); legacyJavaOnly.put(Items.MUSIC_DISC_RELIC, "minecraft:music_disc_wait");
manualFallback.put(Items.WITHER_SPAWN_EGG, "minecraft:wither_skeleton_spawn_egg"); legacyJavaOnly.put(Items.PITCHER_PLANT, "minecraft:chorus_flower");
manualFallback.put(Items.SNOW_GOLEM_SPAWN_EGG, "minecraft:polar_bear_spawn_egg"); legacyJavaOnly.put(Items.PITCHER_POD, "minecraft:beetroot");
manualFallback.put(Items.IRON_GOLEM_SPAWN_EGG, "minecraft:villager_spawn_egg"); legacyJavaOnly.put(Items.SNIFFER_EGG, "minecraft:sniffer_spawn_egg"); // the BlockItem of the sniffer egg block
Map<String, PaletteVersion> paletteVersions = new Object2ObjectOpenHashMap<>(); Map<String, PaletteVersion> paletteVersions = new Object2ObjectOpenHashMap<>();
paletteVersions.put("1_19_20", new PaletteVersion(Bedrock_v544.CODEC.getProtocolVersion(), manualFallback)); paletteVersions.put("1_19_80", new PaletteVersion(Bedrock_v582.CODEC.getProtocolVersion(), legacyJavaOnly, (item, mapping) -> {
paletteVersions.put("1_19_50", new PaletteVersion(Bedrock_v560.CODEC.getProtocolVersion(), manualFallback)); String id = item.javaIdentifier();
paletteVersions.put("1_19_60", new PaletteVersion(Bedrock_v567.CODEC.getProtocolVersion(), Collections.emptyMap())); if (id.endsWith("pottery_sherd")) {
paletteVersions.put("1_19_70", new PaletteVersion(Bedrock_v575.CODEC.getProtocolVersion(), Collections.emptyMap())); return mapping.withBedrockIdentifier(id.replace("sherd", "shard"));
paletteVersions.put("1_19_80", new PaletteVersion(Bedrock_v582.CODEC.getProtocolVersion(), Collections.emptyMap())); } else if (id.endsWith("carpet") && !id.startsWith("minecraft:moss")) {
return mapping.withBedrockIdentifier("minecraft:carpet");
} else if (id.endsWith("coral")) {
return mapping.withBedrockIdentifier("minecraft:coral");
}
return mapping;
}));
paletteVersions.put("1_20_0", new PaletteVersion(Bedrock_v589.CODEC.getProtocolVersion()));
GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap();
@ -182,17 +198,11 @@ public class ItemRegistryPopulator {
Set<Item> javaOnlyItems = new ObjectOpenHashSet<>(); Set<Item> javaOnlyItems = new ObjectOpenHashSet<>();
Collections.addAll(javaOnlyItems, Items.SPECTRAL_ARROW, Items.DEBUG_STICK, Collections.addAll(javaOnlyItems, Items.SPECTRAL_ARROW, Items.DEBUG_STICK,
Items.KNOWLEDGE_BOOK, Items.TIPPED_ARROW, Items.BUNDLE); Items.KNOWLEDGE_BOOK, Items.TIPPED_ARROW, Items.BUNDLE);
// these spawn eggs exist in 1.19.60+;
if (palette.getValue().protocolVersion() < Bedrock_v567.CODEC.getProtocolVersion()) {
Collections.addAll(javaOnlyItems, Items.IRON_GOLEM_SPAWN_EGG, Items.SNOW_GOLEM_SPAWN_EGG,
Items.WITHER_SPAWN_EGG, Items.ENDER_DRAGON_SPAWN_EGG);
}
javaOnlyItems.add(Items.DECORATED_POT);
if (!customItemsAllowed) { if (!customItemsAllowed) {
javaOnlyItems.add(Items.FURNACE_MINECART); javaOnlyItems.add(Items.FURNACE_MINECART);
} }
// Java-only items for this version // Java-only items for this version
javaOnlyItems.addAll(palette.getValue().additionalTranslatedItems().keySet()); javaOnlyItems.addAll(palette.getValue().javaOnlyItems().keySet());
Int2ObjectMap<String> customIdMappings = new Int2ObjectOpenHashMap<>(); Int2ObjectMap<String> customIdMappings = new Int2ObjectOpenHashMap<>();
Set<String> registeredItemNames = new ObjectOpenHashSet<>(); // This is used to check for duplicate item names Set<String> registeredItemNames = new ObjectOpenHashSet<>(); // This is used to check for duplicate item names
@ -203,12 +213,12 @@ public class ItemRegistryPopulator {
throw new RuntimeException("Extra item in mappings? " + entry.getKey()); throw new RuntimeException("Extra item in mappings? " + entry.getKey());
} }
GeyserMappingItem mappingItem; GeyserMappingItem mappingItem;
String replacementItem = palette.getValue().additionalTranslatedItems().get(javaItem); String replacementItem = palette.getValue().javaOnlyItems().get(javaItem);
if (replacementItem != null) { if (replacementItem != null) {
mappingItem = items.get(replacementItem); mappingItem = items.get(replacementItem); // java only item, a java id fallback has been provided
} else { } else {
// This items has a mapping specifically for this version of the game // check if any mapping changes need to be made on this version
mappingItem = entry.getValue(); mappingItem = palette.getValue().remapper().remap(javaItem, entry.getValue());
} }
if (customItemsAllowed && javaItem == Items.FURNACE_MINECART) { if (customItemsAllowed && javaItem == Items.FURNACE_MINECART) {
@ -217,26 +227,10 @@ public class ItemRegistryPopulator {
continue; continue;
} }
String bedrockIdentifier; String bedrockIdentifier = mappingItem.getBedrockIdentifier();
// 1.19.70+
if (palette.getValue().protocolVersion() >= Bedrock_v575.CODEC.getProtocolVersion() && mappingItem.getBedrockIdentifier().equals("minecraft:wool")) {
bedrockIdentifier = javaItem.javaIdentifier();
} else {
bedrockIdentifier = mappingItem.getBedrockIdentifier();
}
//1.19.80+
if (palette.getValue().protocolVersion >= Bedrock_v582.CODEC.getProtocolVersion()) {
if (mappingItem.getBedrockIdentifier().equals("minecraft:log") ||
mappingItem.getBedrockIdentifier().equals("minecraft:log2") ||
mappingItem.getBedrockIdentifier().equals("minecraft:fence")) {
bedrockIdentifier = javaItem.javaIdentifier();
}
}
ItemDefinition definition = definitions.get(bedrockIdentifier); ItemDefinition definition = definitions.get(bedrockIdentifier);
if (definition == null) { if (definition == null) {
throw new RuntimeException("Missing Bedrock ItemDefinition in mappings: " + bedrockIdentifier); throw new RuntimeException("Missing Bedrock ItemDefinition in version " + palette.getKey() + " for mapping: " + mappingItem);
} }
BlockDefinition bedrockBlock = null; BlockDefinition bedrockBlock = null;
@ -430,7 +424,7 @@ public class ItemRegistryPopulator {
} else if (javaItem.javaIdentifier().startsWith("minecraft:music_disc_")) { } else if (javaItem.javaIdentifier().startsWith("minecraft:music_disc_")) {
// The Java record level event uses the item ID as the "key" to play the record // The Java record level event uses the item ID as the "key" to play the record
Registries.RECORDS.register(javaItem.javaId(), SoundEvent.valueOf("RECORD_" + Registries.RECORDS.register(javaItem.javaId(), SoundEvent.valueOf("RECORD_" +
javaItem.javaIdentifier().replace("minecraft:music_disc_", "").toUpperCase(Locale.ENGLISH))); mapping.getBedrockIdentifier().replace("minecraft:music_disc_", "").toUpperCase(Locale.ENGLISH)));
} }
mappings.add(mapping); mappings.add(mapping);

Datei anzeigen

@ -28,7 +28,7 @@ package org.geysermc.geyser.registry.type;
import lombok.Builder; import lombok.Builder;
import lombok.Value; import lombok.Value;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.cloudburstmc.protocol.common.DefinitionRegistry; import org.cloudburstmc.protocol.common.DefinitionRegistry;
import java.util.Map; import java.util.Map;

Datei anzeigen

@ -26,7 +26,7 @@
package org.geysermc.geyser.registry.type; package org.geysermc.geyser.registry.type;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
public class GeyserBedrockBlock implements BlockDefinition { public class GeyserBedrockBlock implements BlockDefinition {
private final int runtimeId; private final int runtimeId;

Datei anzeigen

@ -25,7 +25,7 @@
package org.geysermc.geyser.registry.type; package org.geysermc.geyser.registry.type;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.item.type.Item;
/** /**

Datei anzeigen

@ -26,12 +26,22 @@
package org.geysermc.geyser.registry.type; package org.geysermc.geyser.registry.type;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data; import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.With;
/** /**
* Represents Geyser's own serialized item information before being processed per-version * Represents Geyser's own serialized item information before being processed per-version
*/ */
@Data @ToString
@EqualsAndHashCode
@Getter
@With
@NoArgsConstructor
@AllArgsConstructor
public class GeyserMappingItem { public class GeyserMappingItem {
@JsonProperty("bedrock_identifier") String bedrockIdentifier; @JsonProperty("bedrock_identifier") String bedrockIdentifier;
@JsonProperty("bedrock_data") int bedrockData; @JsonProperty("bedrock_data") int bedrockData;

Datei anzeigen

@ -30,8 +30,8 @@ import lombok.Builder;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Value; import lombok.Value;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.geysermc.geyser.api.item.custom.CustomItemOptions; import org.geysermc.geyser.api.item.custom.CustomItemOptions;
import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.item.type.Item;

Datei anzeigen

@ -29,7 +29,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import lombok.Builder; import lombok.Builder;
import lombok.Value; import lombok.Value;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.common.DefinitionRegistry; import org.cloudburstmc.protocol.common.DefinitionRegistry;

Datei anzeigen

@ -124,6 +124,7 @@ import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.level.JavaDimension;
import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.level.WorldManager;
import org.geysermc.geyser.level.physics.CollisionManager; import org.geysermc.geyser.level.physics.CollisionManager;
import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.network.netty.LocalSession; import org.geysermc.geyser.network.netty.LocalSession;
import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.registry.type.BlockMappings; import org.geysermc.geyser.registry.type.BlockMappings;
@ -1540,6 +1541,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
startGamePacket.setRewindHistorySize(0); startGamePacket.setRewindHistorySize(0);
startGamePacket.setServerAuthoritativeBlockBreaking(false); startGamePacket.setServerAuthoritativeBlockBreaking(false);
if (GameProtocol.isPre1_20(this)) {
startGamePacket.getExperiments().add(new ExperimentData("next_major_update", true));
startGamePacket.getExperiments().add(new ExperimentData("sniffer", true));
}
upstream.sendPacket(startGamePacket); upstream.sendPacket(startGamePacket);
} }

Datei anzeigen

@ -64,6 +64,7 @@ public class TagCache {
private IntList foxFood; private IntList foxFood;
private IntList piglinLoved; private IntList piglinLoved;
private IntList smallFlowers; private IntList smallFlowers;
private IntList snifferFood;
public TagCache() { public TagCache() {
// Ensure all lists are non-null // Ensure all lists are non-null
@ -101,6 +102,7 @@ public class TagCache {
this.foxFood = IntList.of(itemTags.get("minecraft:fox_food")); this.foxFood = IntList.of(itemTags.get("minecraft:fox_food"));
this.piglinLoved = IntList.of(itemTags.get("minecraft:piglin_loved")); this.piglinLoved = IntList.of(itemTags.get("minecraft:piglin_loved"));
this.smallFlowers = IntList.of(itemTags.get("minecraft:small_flowers")); this.smallFlowers = IntList.of(itemTags.get("minecraft:small_flowers"));
this.snifferFood = load(itemTags.get("minecraft:sniffer_food"));
// Hack btw // Hack btw
boolean emulatePost1_13Logic = itemTags.get("minecraft:signs").length > 1; boolean emulatePost1_13Logic = itemTags.get("minecraft:signs").length > 1;
@ -137,6 +139,7 @@ public class TagCache {
this.foxFood = IntLists.emptyList(); this.foxFood = IntLists.emptyList();
this.piglinLoved = IntLists.emptyList(); this.piglinLoved = IntLists.emptyList();
this.smallFlowers = IntLists.emptyList(); this.smallFlowers = IntLists.emptyList();
this.snifferFood = IntLists.emptyList();
} }
public boolean isAxolotlTemptItem(Item item) { public boolean isAxolotlTemptItem(Item item) {
@ -167,6 +170,10 @@ public class TagCache {
return smallFlowers.contains(itemStack.getJavaId()); return smallFlowers.contains(itemStack.getJavaId());
} }
public boolean isSnifferFood(Item item) {
return snifferFood.contains(item.javaId());
}
public boolean isAxeEffective(BlockMapping blockMapping) { public boolean isAxeEffective(BlockMapping blockMapping) {
return axeEffective.contains(blockMapping.getJavaBlockId()); return axeEffective.contains(blockMapping.getJavaBlockId());
} }

Datei anzeigen

@ -61,6 +61,10 @@ public final class WorldCache {
private int currentSequence; private int currentSequence;
private final Object2IntMap<Vector3i> unverifiedPredictions = new Object2IntOpenHashMap<>(1); private final Object2IntMap<Vector3i> unverifiedPredictions = new Object2IntOpenHashMap<>(1);
@Getter
@Setter
private boolean editingSignOnFront;
public WorldCache(GeyserSession session) { public WorldCache(GeyserSession session) {
this.session = session; this.session = session;
this.scoreboard = new Scoreboard(session); this.scoreboard = new Scoreboard(session);

Datei anzeigen

@ -94,7 +94,7 @@ public abstract class InventoryTranslator {
put(ContainerType.LOOM, new LoomInventoryTranslator()); put(ContainerType.LOOM, new LoomInventoryTranslator());
put(ContainerType.MERCHANT, new MerchantInventoryTranslator()); put(ContainerType.MERCHANT, new MerchantInventoryTranslator());
put(ContainerType.SHULKER_BOX, new ShulkerInventoryTranslator()); put(ContainerType.SHULKER_BOX, new ShulkerInventoryTranslator());
put(ContainerType.LEGACY_SMITHING, new SmithingInventoryTranslator()); put(ContainerType.SMITHING, new SmithingInventoryTranslator());
put(ContainerType.STONECUTTER, new StonecutterInventoryTranslator()); put(ContainerType.STONECUTTER, new StonecutterInventoryTranslator());
/* Lectern */ /* Lectern */

Datei anzeigen

@ -33,15 +33,16 @@ import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslator { public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslator {
public SmithingInventoryTranslator() { public SmithingInventoryTranslator() {
super(3, "minecraft:smithing_table", ContainerType.SMITHING_TABLE, UIInventoryUpdater.INSTANCE); super(4, "minecraft:smithing_table", ContainerType.SMITHING_TABLE, UIInventoryUpdater.INSTANCE);
} }
@Override @Override
public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) { public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) {
return switch (slotInfoData.getContainer()) { return switch (slotInfoData.getContainer()) {
case SMITHING_TABLE_INPUT -> 0; case SMITHING_TABLE_TEMPLATE -> 0;
case SMITHING_TABLE_MATERIAL -> 1; case SMITHING_TABLE_INPUT -> 1;
case SMITHING_TABLE_RESULT, CREATED_OUTPUT -> 2; case SMITHING_TABLE_MATERIAL -> 2;
case SMITHING_TABLE_RESULT, CREATED_OUTPUT -> 3;
default -> super.bedrockSlotToJava(slotInfoData); default -> super.bedrockSlotToJava(slotInfoData);
}; };
} }
@ -49,9 +50,10 @@ public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslato
@Override @Override
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
return switch (slot) { return switch (slot) {
case 0 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_INPUT, 51); case 0 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_TEMPLATE, 53);
case 1 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_MATERIAL, 52); case 1 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_INPUT, 51);
case 2 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_RESULT, 50); case 2 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_MATERIAL, 52);
case 3 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_RESULT, 50);
default -> super.javaSlotToBedrockContainer(slot); default -> super.javaSlotToBedrockContainer(slot);
}; };
} }
@ -59,9 +61,10 @@ public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslato
@Override @Override
public int javaSlotToBedrock(int slot) { public int javaSlotToBedrock(int slot) {
return switch (slot) { return switch (slot) {
case 0 -> 51; case 0 -> 53;
case 1 -> 52; case 1 -> 51;
case 2 -> 50; case 2 -> 52;
case 3 -> 50;
default -> super.javaSlotToBedrock(slot); default -> super.javaSlotToBedrock(slot);
}; };
} }

Datei anzeigen

@ -28,7 +28,7 @@ package org.geysermc.geyser.translator.inventory.chest;
import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket; import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
import org.cloudburstmc.protocol.bedrock.packet.ContainerClosePacket; import org.cloudburstmc.protocol.bedrock.packet.ContainerClosePacket;

Datei anzeigen

@ -30,7 +30,7 @@ import com.github.steveice10.opennbt.tag.builtin.IntTag;
import com.github.steveice10.opennbt.tag.builtin.Tag; import com.github.steveice10.opennbt.tag.builtin.Tag;
import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.Pair;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.geysermc.geyser.api.item.custom.CustomItemOptions; import org.geysermc.geyser.api.item.custom.CustomItemOptions;
import org.geysermc.geyser.api.util.TriState; import org.geysermc.geyser.api.util.TriState;
import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMapping;

Datei anzeigen

@ -37,7 +37,7 @@ import org.cloudburstmc.nbt.NbtList;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.nbt.NbtType;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.GeyserItemStack;

Datei anzeigen

@ -0,0 +1,38 @@
/*
* Copyright (c) 2019-2023 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.level.block.entity;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
import org.geysermc.geyser.util.SignUtils;
@BlockEntity(type = BlockEntityType.HANGING_SIGN)
public class HangingSignBlockEntityTranslator extends SignBlockEntityTranslator {
@Override
public int signWidthMax() {
return SignUtils.HANGING_SIGN_WIDTH_MAX; // Smaller than that for BlockEntityType.SIGN
}
}

Datei anzeigen

@ -42,7 +42,6 @@ import org.geysermc.geyser.level.physics.Axis;
import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.level.physics.CollisionManager; import org.geysermc.geyser.level.physics.CollisionManager;
import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.level.physics.Direction;
import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.PistonCache; import org.geysermc.geyser.session.cache.PistonCache;
@ -622,10 +621,6 @@ public class PistonBlockEntity {
Vector3i movement = getMovement(); Vector3i movement = getMovement();
attachedBlocks.forEach((blockPos, javaId) -> { attachedBlocks.forEach((blockPos, javaId) -> {
blockPos = blockPos.add(movement); blockPos = blockPos.add(movement);
if (!GameProtocol.supports1_19_50(session)) {
// Send a final block entity packet to detach blocks for clients older than 1.19.50
BlockEntityUtils.updateBlockEntity(session, buildMovingBlockTag(blockPos, javaId, Direction.DOWN.getUnitVector()), blockPos);
}
// Don't place blocks that collide with the player // Don't place blocks that collide with the player
if (!SOLID_BOUNDING_BOX.checkIntersection(blockPos.toDouble(), session.getCollisionManager().getPlayerBoundingBox())) { if (!SOLID_BOUNDING_BOX.checkIntersection(blockPos.toDouble(), session.getCollisionManager().getPlayerBoundingBox())) {
ChunkUtils.updateBlock(session, javaId, blockPos); ChunkUtils.updateBlock(session, javaId, blockPos);

Datei anzeigen

@ -27,12 +27,15 @@ package org.geysermc.geyser.translator.level.block.entity;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.Tag; import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.text.ChatColor;
import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.geyser.util.SignUtils; import org.geysermc.geyser.util.SignUtils;
@BlockEntity(type = {BlockEntityType.SIGN, BlockEntityType.HANGING_SIGN}) @BlockEntity(type = BlockEntityType.SIGN)
public class SignBlockEntityTranslator extends BlockEntityTranslator { public class SignBlockEntityTranslator extends BlockEntityTranslator {
/** /**
* Maps a color stored in a sign's Color tag to its ARGB value. * Maps a color stored in a sign's Color tag to its ARGB value.
@ -64,54 +67,80 @@ public class SignBlockEntityTranslator extends BlockEntityTranslator {
return dyeColor | (255 << 24); return dyeColor | (255 << 24);
} }
public int signWidthMax() {
return SignUtils.SIGN_WIDTH_MAX;
}
@Override @Override
public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) {
StringBuilder signText = new StringBuilder(); builder.putCompound("FrontText", translateSide(tag.get("front_text")));
for (int i = 0; i < 4; i++) { builder.putCompound("BackText", translateSide(tag.get("back_text")));
int currentLine = i + 1; var waxed = tag.get("is_waxed");
String signLine = getOrDefault(tag.getValue().get("Text" + currentLine), ""); builder.putBoolean("IsWaxed", waxed != null && waxed.getValue() instanceof Number number && number.byteValue() != 0);
signLine = MessageTranslator.convertMessageLenient(signLine); }
// Check the character width on the sign to ensure there is no overflow that is usually hidden private NbtMap translateSide(Tag tag) {
// to Java Edition clients but will appear to Bedrock clients if (!(tag instanceof CompoundTag signData)) {
int signWidth = 0; return NbtMap.EMPTY;
StringBuilder finalSignLine = new StringBuilder(); }
boolean previousCharacterWasFormatting = false; // Color changes do not count for maximum width NbtMapBuilder builder = NbtMap.builder();
for (char c : signLine.toCharArray()) {
if (c == '\u00a7') { StringBuilder signText = new StringBuilder();
// Don't count this character Tag messages = signData.get("messages");
previousCharacterWasFormatting = true; if (messages instanceof ListTag listTag) {
} else if (previousCharacterWasFormatting) { var it = listTag.iterator();
// Don't count this character either while (it.hasNext()) {
previousCharacterWasFormatting = false; String signLine = (String) it.next().getValue();
} else { signLine = MessageTranslator.convertMessageLenient(signLine);
signWidth += SignUtils.getCharacterWidth(c);
// Check the character width on the sign to ensure there is no overflow that is usually hidden
// to Java Edition clients but will appear to Bedrock clients
int signWidth = 0;
StringBuilder finalSignLine = new StringBuilder();
boolean previousCharacterWasFormatting = false; // Color changes do not count for maximum width
for (char c : signLine.toCharArray()) {
if (c == ChatColor.ESCAPE) {
// Don't count this character
previousCharacterWasFormatting = true;
} else if (previousCharacterWasFormatting) {
// Don't count this character either
previousCharacterWasFormatting = false;
} else {
signWidth += SignUtils.getCharacterWidth(c);
}
if (signWidth <= signWidthMax()) {
finalSignLine.append(c);
} else {
// Adding the character would make Bedrock move to the next line - Java doesn't do that, so we do not want to
break;
}
} }
// todo 1.20: update for hanging signs (smaller width). Currently OK because bedrock sees hanging signs as normal signs signText.append(finalSignLine);
if (signWidth <= SignUtils.BEDROCK_CHARACTER_WIDTH_MAX) { if (it.hasNext()) {
finalSignLine.append(c); signText.append("\n");
} else {
// Adding the character would make Bedrock move to the next line - Java doesn't do that, so we do not want to
break;
} }
} }
}
signText.append(finalSignLine); // Trim extra newlines - this makes editing difficult if preserved because the cursor starts at the bottom,
signText.append("\n"); // Which can easily go over the screen
while (!signText.isEmpty() && signText.charAt(signText.length() - 1) == '\n') {
signText.deleteCharAt(signText.length() - 1);
} }
builder.putString("Text", signText.toString()); builder.putString("Text", signText.toString());
// Java Edition 1.14 added the ability to change the text color of the whole sign using dye // Java Edition 1.14 added the ability to change the text color of the whole sign using dye
Tag color = tag.get("Color"); Tag color = signData.get("Color");
if (color != null) { if (color != null) {
builder.putInt("SignTextColor", getBedrockSignColor(color.getValue().toString())); builder.putInt("SignTextColor", getBedrockSignColor(color.getValue().toString()));
} }
// Glowing text // Glowing text
boolean isGlowing = getOrDefault(tag.getValue().get("GlowingText"), (byte) 0) != (byte) 0; boolean isGlowing = getOrDefault(signData.get("GlowingText"), (byte) 0) != (byte) 0;
builder.putBoolean("IgnoreLighting", isGlowing); builder.putBoolean("IgnoreLighting", isGlowing);
builder.putBoolean("TextIgnoreLegacyBugResolved", isGlowing); // ??? required return builder.build();
} }
} }

Datei anzeigen

@ -30,7 +30,6 @@ import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.Serverb
import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket; import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.session.GeyserSession; 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;
@ -45,15 +44,11 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator<BlockEnti
NbtMap tag = packet.getData(); NbtMap tag = packet.getData();
String id = tag.getString("id"); String id = tag.getString("id");
if (id.equals("Sign")) { if (id.equals("Sign")) {
String text; // Hanging signs are narrower
if (GameProtocol.supports1_19_80(session)) { int widthMax = SignUtils.getSignWidthMax(session.getGeyser().getWorldManager().getBlockAt(session, packet.getBlockPosition()));
// The other side is called... you guessed it... BackText
text = tag.getCompound("FrontText") String text = MessageTranslator.convertToPlainText(
.getString("Text"); tag.getCompound(session.getWorldCache().isEditingSignOnFront() ? "FrontText" : "BackText").getString("Text"));
} else {
text = tag.getString("Text");
}
text = MessageTranslator.convertToPlainText(text);
// Note: as of 1.18.30, only one packet is sent from Bedrock when the sign is finished. // Note: as of 1.18.30, only one packet is sent from Bedrock when the sign is finished.
// Previous versions did not have this behavior. // Previous versions did not have this behavior.
StringBuilder newMessage = new StringBuilder(); StringBuilder newMessage = new StringBuilder();
@ -68,13 +63,10 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator<BlockEnti
for (char character : text.toCharArray()) { for (char character : text.toCharArray()) {
widthCount += SignUtils.getCharacterWidth(character); widthCount += SignUtils.getCharacterWidth(character);
// todo 1.20: update for hanging signs (smaller width). Currently bedrock thinks hanging signs are normal,
// so it thinks hanging signs have more width than they actually do. Seems like JE just truncates it.
// If we get a return in Bedrock, or go over the character width max, that signals to use the next line. // If we get a return in Bedrock, or go over the character width max, that signals to use the next line.
if (character == '\n' || widthCount > SignUtils.JAVA_CHARACTER_WIDTH_MAX) { if (character == '\n' || widthCount > widthMax) {
// We need to apply some more logic if we went over the character width max // We need to apply some more logic if we went over the character width max
boolean wentOverMax = widthCount > SignUtils.JAVA_CHARACTER_WIDTH_MAX && character != '\n'; boolean wentOverMax = widthCount > widthMax && character != '\n';
widthCount = 0; widthCount = 0;
// Saves if we're moving a word to the next line // Saves if we're moving a word to the next line
String word = null; String word = null;
@ -115,7 +107,7 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator<BlockEnti
// Put the final line on since it isn't done in the for loop // Put the final line on since it isn't done in the for loop
if (iterator < lines.length) lines[iterator] = newMessage.toString(); if (iterator < lines.length) lines[iterator] = newMessage.toString();
Vector3i pos = Vector3i.from(tag.getInt("x"), tag.getInt("y"), tag.getInt("z")); Vector3i pos = Vector3i.from(tag.getInt("x"), tag.getInt("y"), tag.getInt("z"));
ServerboundSignUpdatePacket signUpdatePacket = new ServerboundSignUpdatePacket(pos, lines); ServerboundSignUpdatePacket signUpdatePacket = new ServerboundSignUpdatePacket(pos, lines, session.getWorldCache().isEditingSignOnFront());
session.sendDownstreamPacket(signUpdatePacket); session.sendDownstreamPacket(signUpdatePacket);
} else if (id.equals("JigsawBlock")) { } else if (id.equals("JigsawBlock")) {

Datei anzeigen

@ -39,7 +39,7 @@ import org.cloudburstmc.math.vector.Vector3d;
import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.data.LevelEvent;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.data.inventory.transaction.InventoryActionData; import org.cloudburstmc.protocol.bedrock.data.inventory.transaction.InventoryActionData;

Datei anzeigen

@ -29,27 +29,28 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient;
import com.github.steveice10.mc.protocol.data.game.recipe.Recipe; import com.github.steveice10.mc.protocol.data.game.recipe.Recipe;
import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType; import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType;
import com.github.steveice10.mc.protocol.data.game.recipe.data.LegacyUpgradeRecipeData;
import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData; import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData;
import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData; import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData;
import com.github.steveice10.mc.protocol.data.game.recipe.data.SmithingTransformRecipeData;
import com.github.steveice10.mc.protocol.data.game.recipe.data.StoneCuttingRecipeData; import com.github.steveice10.mc.protocol.data.game.recipe.data.StoneCuttingRecipeData;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUpdateRecipesPacket; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUpdateRecipesPacket;
import it.unimi.dsi.fastutil.ints.*; import it.unimi.dsi.fastutil.ints.*;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.MultiRecipeData; import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.MultiRecipeData;
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.RecipeData; import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.RecipeData;
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.SmithingTransformRecipeData; import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.SmithingTrimRecipeData;
import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.DefaultDescriptor; import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.DefaultDescriptor;
import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount; import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount;
import org.cloudburstmc.protocol.bedrock.packet.CraftingDataPacket; import org.cloudburstmc.protocol.bedrock.packet.CraftingDataPacket;
import org.cloudburstmc.protocol.bedrock.packet.TrimDataPacket;
import org.geysermc.geyser.inventory.recipe.GeyserRecipe; import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe; import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe;
import org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe; import org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe;
import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData; import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData;
import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.inventory.recipe.TrimRecipe;
import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
@ -145,28 +146,29 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
data.add(stoneCuttingData); data.add(stoneCuttingData);
// Save for processing after all recipes have been received // Save for processing after all recipes have been received
} }
case SMITHING -> { case SMITHING_TRANSFORM -> {
// Required to translate these as of 1.18.10, or else they cannot be crafted SmithingTransformRecipeData data = (SmithingTransformRecipeData) recipe.getData();
LegacyUpgradeRecipeData recipeData = (LegacyUpgradeRecipeData) recipe.getData(); ItemData output = ItemTranslator.translateToBedrock(session, data.getResult());
ItemData output = ItemTranslator.translateToBedrock(session, recipeData.getResult());
for (ItemStack base : recipeData.getBase().getOptions()) {
ItemDescriptorWithCount bedrockBase = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, base));
for (ItemStack addition : recipeData.getAddition().getOptions()) { for (ItemStack template : data.getTemplate().getOptions()) {
ItemDescriptorWithCount bedrockAddition = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, addition)); ItemDescriptorWithCount bedrockTemplate = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, template));
for (ItemStack base : data.getBase().getOptions()) {
ItemDescriptorWithCount bedrockBase = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, base));
for (ItemStack addition : data.getAddition().getOptions()) {
ItemDescriptorWithCount bedrockAddition = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, addition));
if (GameProtocol.supports1_19_60(session)) {
// Note: vanilla inputs use aux value of Short.MAX_VALUE // Note: vanilla inputs use aux value of Short.MAX_VALUE
craftingDataPacket.getCraftingData().add(SmithingTransformRecipeData.of(recipe.getIdentifier(), craftingDataPacket.getCraftingData().add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.SmithingTransformRecipeData.of(recipe.getIdentifier(),
ItemDescriptorWithCount.EMPTY, bedrockBase, bedrockAddition, output, "smithing_table", netId++)); bedrockTemplate, bedrockBase, bedrockAddition, output, "smithing_table", netId++));
} else {
UUID uuid = UUID.randomUUID();
craftingDataPacket.getCraftingData().add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapelessRecipeData.shapeless(uuid.toString(),
List.of(bedrockBase, bedrockAddition),
Collections.singletonList(output), uuid, "smithing_table", 2, netId++));
} }
} }
} }
}
case SMITHING_TRIM -> {
// ignored currently - see below
} }
default -> { default -> {
List<RecipeData> craftingData = recipeTypes.get(recipe.getType()); List<RecipeData> craftingData = recipeTypes.get(recipe.getType());
@ -212,6 +214,19 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
} }
} }
// FIXME: if the server/viaversion doesn't send trim recipes then we shouldn't either.
// BDS sends armor trim templates and materials before the CraftingDataPacket
TrimDataPacket trimDataPacket = new TrimDataPacket();
trimDataPacket.getPatterns().addAll(TrimRecipe.PATTERNS);
trimDataPacket.getMaterials().addAll(TrimRecipe.MATERIALS);
session.sendUpstreamPacket(trimDataPacket);
// Identical smithing_trim recipe sent by BDS that uses tag-descriptors, as the client seems to ignore the
// approach of using many default-descriptors (which we do for smithing_transform)
craftingDataPacket.getCraftingData().add(SmithingTrimRecipeData.of(TrimRecipe.ID,
TrimRecipe.BASE, TrimRecipe.ADDITION, TrimRecipe.TEMPLATE, "smithing_table", netId++));
session.sendUpstreamPacket(craftingDataPacket); session.sendUpstreamPacket(craftingDataPacket);
session.setCraftingRecipes(recipeMap); session.setCraftingRecipes(recipeMap);
session.setStonecutterRecipes(stonecutterRecipeMap); session.setStonecutterRecipes(stonecutterRecipeMap);

Datei anzeigen

@ -32,6 +32,7 @@ import org.cloudburstmc.nbt.NbtType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
import org.cloudburstmc.protocol.bedrock.packet.UpdateEquipPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateEquipPacket;
import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.entity.type.living.animal.horse.CamelEntity;
import org.geysermc.geyser.entity.type.living.animal.horse.ChestedHorseEntity; import org.geysermc.geyser.entity.type.living.animal.horse.ChestedHorseEntity;
import org.geysermc.geyser.entity.type.living.animal.horse.LlamaEntity; import org.geysermc.geyser.entity.type.living.animal.horse.LlamaEntity;
import org.geysermc.geyser.inventory.Container; import org.geysermc.geyser.inventory.Container;
@ -118,6 +119,10 @@ public class JavaHorseScreenOpenTranslator extends PacketTranslator<ClientboundH
} else if (entity instanceof ChestedHorseEntity) { } else if (entity instanceof ChestedHorseEntity) {
inventoryTranslator = new DonkeyInventoryTranslator(packet.getNumberOfSlots()); inventoryTranslator = new DonkeyInventoryTranslator(packet.getNumberOfSlots());
slots.add(SADDLE_SLOT); slots.add(SADDLE_SLOT);
} else if (entity instanceof CamelEntity) {
// The camel has an invisible armor slot and needs special handling, same as the donkey
inventoryTranslator = new DonkeyInventoryTranslator(packet.getNumberOfSlots());
slots.add(SADDLE_SLOT);
} else { } else {
inventoryTranslator = new HorseInventoryTranslator(packet.getNumberOfSlots()); inventoryTranslator = new HorseInventoryTranslator(packet.getNumberOfSlots());
slots.add(SADDLE_SLOT); slots.add(SADDLE_SLOT);

Datei anzeigen

@ -27,7 +27,6 @@ package org.geysermc.geyser.translator.protocol.java.level;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundOpenSignEditorPacket; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundOpenSignEditorPacket;
import org.cloudburstmc.protocol.bedrock.packet.OpenSignPacket; import org.cloudburstmc.protocol.bedrock.packet.OpenSignPacket;
import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.session.GeyserSession; 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;
@ -37,11 +36,11 @@ public class JavaOpenSignEditorTranslator extends PacketTranslator<ClientboundOp
@Override @Override
public void translate(GeyserSession session, ClientboundOpenSignEditorPacket packet) { public void translate(GeyserSession session, ClientboundOpenSignEditorPacket packet) {
if (GameProtocol.supports1_19_80(session)) { OpenSignPacket openSignPacket = new OpenSignPacket();
OpenSignPacket openSignPacket = new OpenSignPacket(); openSignPacket.setPosition(packet.getPosition());
openSignPacket.setPosition(packet.getPosition()); openSignPacket.setFrontSide(packet.isFrontText());
openSignPacket.setFrontSide(true); // Will be remedied in 1.20 session.sendUpstreamPacket(openSignPacket);
session.sendUpstreamPacket(openSignPacket);
} session.getWorldCache().setEditingSignOnFront(packet.isFrontText());
} }
} }

Datei anzeigen

@ -33,7 +33,7 @@ import lombok.experimental.UtilityClass;
import org.cloudburstmc.math.GenericMath; import org.cloudburstmc.math.GenericMath;
import org.cloudburstmc.math.vector.Vector2i; import org.cloudburstmc.math.vector.Vector2i;
import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.packet.LevelChunkPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelChunkPacket;
import org.cloudburstmc.protocol.bedrock.packet.NetworkChunkPublisherUpdatePacket; import org.cloudburstmc.protocol.bedrock.packet.NetworkChunkPublisherUpdatePacket;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;

Datei anzeigen

@ -36,7 +36,6 @@ import org.cloudburstmc.protocol.bedrock.packet.PlayerActionPacket;
import org.cloudburstmc.protocol.bedrock.packet.StopSoundPacket; import org.cloudburstmc.protocol.bedrock.packet.StopSoundPacket;
import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.level.BedrockDimension;
import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import java.util.Set; import java.util.Set;
@ -122,18 +121,16 @@ public class DimensionUtils {
stopSoundPacket.setSoundName(""); stopSoundPacket.setSoundName("");
session.sendUpstreamPacket(stopSoundPacket); session.sendUpstreamPacket(stopSoundPacket);
// Kind of silly but Bedrock 1.19.50 requires an acknowledgement after the // Kind of silly but Bedrock 1.19.50 and later requires an acknowledgement after the
// initial chunks are sent, prior to the client acknowledgement // initial chunks are sent, prior to the client acknowledgement
if (GameProtocol.supports1_19_50(session)) { // Note: send this before chunks are sent. Fixed https://github.com/GeyserMC/Geyser/issues/3421
// Note: send this before chunks are sent. Fixed https://github.com/GeyserMC/Geyser/issues/3421 PlayerActionPacket ackPacket = new PlayerActionPacket();
PlayerActionPacket ackPacket = new PlayerActionPacket(); ackPacket.setRuntimeEntityId(player.getGeyserId());
ackPacket.setRuntimeEntityId(player.getGeyserId()); ackPacket.setAction(PlayerActionType.DIMENSION_CHANGE_SUCCESS);
ackPacket.setAction(PlayerActionType.DIMENSION_CHANGE_SUCCESS); ackPacket.setBlockPosition(Vector3i.ZERO);
ackPacket.setBlockPosition(Vector3i.ZERO); ackPacket.setResultPosition(Vector3i.ZERO);
ackPacket.setResultPosition(Vector3i.ZERO); ackPacket.setFace(0);
ackPacket.setFace(0); session.sendUpstreamPacket(ackPacket);
session.sendUpstreamPacket(ackPacket);
}
// TODO - fix this hack of a fix by sending the final dimension switching logic after sections have been sent. // TODO - fix this hack of a fix by sending the final dimension switching logic after sections have been sent.
// The client wants sections sent to it before it can successfully respawn. // The client wants sections sent to it before it can successfully respawn.

Datei anzeigen

@ -35,7 +35,7 @@ import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.nbt.NbtType;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket;

Datei anzeigen

@ -57,9 +57,11 @@ import javax.crypto.SecretKey;
import java.net.URI; import java.net.URI;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.KeyPairGenerator; import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.interfaces.ECPublicKey; import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec; import java.security.spec.ECGenParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -70,6 +72,18 @@ public class LoginEncryptionUtils {
private static boolean HAS_SENT_ENCRYPTION_MESSAGE = false; private static boolean HAS_SENT_ENCRYPTION_MESSAGE = false;
private static final ECPublicKey MOJANG_PUBLIC_KEY_OLD;
private static final ECPublicKey MOJANG_PUBLIC_KEY;
static {
try {
MOJANG_PUBLIC_KEY_OLD = EncryptionUtils.generateKey("MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V");
MOJANG_PUBLIC_KEY = EncryptionUtils.generateKey("MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAECRXueJeTDqNRRgJi/vlRufByu/2G0i2Ebt6YMar5QX/R0DIIyrJMcUpruK4QveTfJSTp3Shlq4Gk34cD/4GUWwkv0DVuzeuB+tXija7HBxii03NHDbPAD0AKnLr2wdAp");
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
throw new AssertionError("Unable to initialize required encryption", e);
}
}
private static boolean validateChainData(List<SignedJWT> chain) throws Exception { private static boolean validateChainData(List<SignedJWT> chain) throws Exception {
if (chain.size() != 3) { if (chain.size() != 3) {
return false; return false;
@ -105,7 +119,7 @@ public class LoginEncryptionUtils {
return !iterator.hasNext(); return !iterator.hasNext();
} }
if (lastKey.equals(EncryptionUtils.getMojangPublicKey())) { if (verifyMojangPublicKey(lastKey)) {
mojangSigned = true; mojangSigned = true;
} }
@ -120,6 +134,10 @@ public class LoginEncryptionUtils {
return mojangSigned; return mojangSigned;
} }
public static boolean verifyMojangPublicKey(ECPublicKey key) {
return MOJANG_PUBLIC_KEY.equals(key) || MOJANG_PUBLIC_KEY_OLD.equals(key);
}
public static void encryptPlayerConnection(GeyserSession session, LoginPacket loginPacket) { public static void encryptPlayerConnection(GeyserSession session, LoginPacket loginPacket) {
encryptConnectionWithCert(session, loginPacket.getExtra().getParsedString(), loginPacket.getChain()); encryptConnectionWithCert(session, loginPacket.getExtra().getParsedString(), loginPacket.getChain());
} }

Datei anzeigen

@ -25,6 +25,8 @@
package org.geysermc.geyser.util; package org.geysermc.geyser.util;
import org.geysermc.geyser.level.block.BlockStateValues;
/** /**
* Provides utilities for interacting with signs. Mainly, it deals with the widths of each character. * Provides utilities for interacting with signs. Mainly, it deals with the widths of each character.
* Since Bedrock auto-wraps signs and Java does not, we have to take this into account when translating signs. * Since Bedrock auto-wraps signs and Java does not, we have to take this into account when translating signs.
@ -33,14 +35,15 @@ public class SignUtils {
// TODO: If we send the Java font via resource pack, does width change? // TODO: If we send the Java font via resource pack, does width change?
/** /**
* The maximum character width that a sign can hold in Bedrock * The maximum character width that a non-hanging sign can hold in both Java and Bedrock
*/ */
public static final int BEDROCK_CHARACTER_WIDTH_MAX = 88; public static final int SIGN_WIDTH_MAX = 90;
/** /**
* The maximum character width that a sign can hold in Java * The maximum character width that a hanging sign can hold in both Java and Bedrock. Hanging signs are narrower.
*/ */
public static final int JAVA_CHARACTER_WIDTH_MAX = 90; public static final int HANGING_SIGN_WIDTH_MAX = 60;
/** /**
* Gets the Minecraft width of a character * Gets the Minecraft width of a character
@ -58,4 +61,10 @@ public class SignUtils {
}; };
} }
public static int getSignWidthMax(int javaBlockState) {
if (BlockStateValues.isHangingSign(javaBlockState)) {
return HANGING_SIGN_WIDTH_MAX;
}
return SIGN_WIDTH_MAX;
}
} }

Binäre Datei nicht angezeigt.

Datei-Diff unterdrückt, da er zu groß ist Diff laden

Datei-Diff unterdrückt, da er zu groß ist Diff laden

@ -1 +1 @@
Subproject commit 56c3eee7a5241b5609d1936f2a11b05dd1a3d568 Subproject commit f69b4db9a6f0e8fff8b29564195c76074210b924

Datei anzeigen

@ -30,8 +30,8 @@ package org.geysermc.geyser.translator.inventory.item;
//import com.github.steveice10.opennbt.tag.builtin.IntTag; //import com.github.steveice10.opennbt.tag.builtin.IntTag;
//import it.unimi.dsi.fastutil.Pair; //import it.unimi.dsi.fastutil.Pair;
//import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; //import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
//import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition; //import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
//import org.cloudburstmc.protocol.bedrock.data.defintions.SimpleItemDefinition; //import org.cloudburstmc.protocol.bedrock.data.definitions.SimpleItemDefinition;
//import org.geysermc.geyser.api.item.custom.CustomItemOptions; //import org.geysermc.geyser.api.item.custom.CustomItemOptions;
//import org.geysermc.geyser.api.util.TriState; //import org.geysermc.geyser.api.util.TriState;
//import org.geysermc.geyser.item.GeyserCustomItemOptions; //import org.geysermc.geyser.item.GeyserCustomItemOptions;

Datei anzeigen

@ -5,7 +5,7 @@ org.gradle.caching=true
org.gradle.parallel=true org.gradle.parallel=true
group=org.geysermc group=org.geysermc
version=2.1.0-SNAPSHOT version=2.1.1-SNAPSHOT
org.gradle.caching=true org.gradle.caching=true
org.gradle.parallel=true org.gradle.parallel=true

Datei anzeigen

@ -9,11 +9,11 @@ netty = "4.1.80.Final"
guava = "29.0-jre" guava = "29.0-jre"
gson = "2.3.1" # Provided by Spigot 1.8.8 gson = "2.3.1" # Provided by Spigot 1.8.8
websocket = "1.5.1" websocket = "1.5.1"
protocol = "3.0.0.Beta1-20230507.200054-78" protocol = "3.0.0.Beta1-20230604.143616-86"
protocol-connection = "3.0.0.Beta1-20230507.200054-77" protocol-connection = "3.0.0.Beta1-20230604.143616-85"
raknet = "1.0.0.CR1-20230430.211932-7" raknet = "1.0.0.CR1-20230430.211932-7"
mcauthlib = "d9d773e" mcauthlib = "d9d773e"
mcprotocollib = "1.19.4-2-20230503.145414-3" mcprotocollib = "1.20-1-20230607.135651-6" # Temporary hack - needs to be updated to release once publishing is fixed
adventure = "4.14.0-20230424.215040-7" adventure = "4.14.0-20230424.215040-7"
adventure-platform = "4.1.2" adventure-platform = "4.1.2"
junit = "5.9.2" junit = "5.9.2"