Get some bits going

This commit is contained in:
Camotoy 2024-10-19 22:38:04 -04:00
parent d64c0b38da
commit e2f40569f8
No known key found for this signature in database
GPG key ID: 7EEFB66FE798081F
18 changed files with 2528 additions and 2382 deletions

View file

@ -25,11 +25,6 @@
package org.geysermc.geyser.entity.type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
@ -71,6 +66,12 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.particle.EntityEffect
import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle;
import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ParticleType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@Getter
@Setter
public class LivingEntity extends Entity {
@ -445,35 +446,35 @@ public class LivingEntity extends Entity {
protected void updateAttribute(Attribute javaAttribute, List<AttributeData> newAttributes) {
if (javaAttribute.getType() instanceof AttributeType.Builtin type) {
switch (type) {
case GENERIC_MAX_HEALTH -> {
case MAX_HEALTH -> {
// Since 1.18.0, setting the max health to 0 or below causes the entity to die on Bedrock but not on Java
// See https://github.com/GeyserMC/Geyser/issues/2971
this.maxHealth = Math.max((float) AttributeUtils.calculateValue(javaAttribute), 1f);
newAttributes.add(createHealthAttribute());
}
case GENERIC_MOVEMENT_SPEED -> {
case MOVEMENT_SPEED -> {
AttributeData attributeData = calculateAttribute(javaAttribute, GeyserAttributeType.MOVEMENT_SPEED);
newAttributes.add(attributeData);
if (this instanceof ClientVehicle clientVehicle) {
clientVehicle.getVehicleComponent().setMoveSpeed(attributeData.getValue());
}
}
case GENERIC_STEP_HEIGHT -> {
case STEP_HEIGHT -> {
if (this instanceof ClientVehicle clientVehicle) {
clientVehicle.getVehicleComponent().setStepHeight((float) AttributeUtils.calculateValue(javaAttribute));
}
}
case GENERIC_GRAVITY -> {
case GRAVITY -> {
if (this instanceof ClientVehicle clientVehicle) {
clientVehicle.getVehicleComponent().setGravity(AttributeUtils.calculateValue(javaAttribute));
}
}
case GENERIC_ATTACK_DAMAGE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.ATTACK_DAMAGE));
case GENERIC_FLYING_SPEED -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.FLYING_SPEED));
case GENERIC_FOLLOW_RANGE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.FOLLOW_RANGE));
case GENERIC_KNOCKBACK_RESISTANCE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.KNOCKBACK_RESISTANCE));
case GENERIC_JUMP_STRENGTH -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.HORSE_JUMP_STRENGTH));
case GENERIC_SCALE -> {
case ATTACK_DAMAGE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.ATTACK_DAMAGE));
case FLYING_SPEED -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.FLYING_SPEED));
case FOLLOW_RANGE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.FOLLOW_RANGE));
case KNOCKBACK_RESISTANCE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.KNOCKBACK_RESISTANCE));
case JUMP_STRENGTH -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.HORSE_JUMP_STRENGTH));
case SCALE -> {
// Attribute on Java, entity data on Bedrock
setAttributeScale((float) AttributeUtils.calculateValue(javaAttribute));
updateBedrockMetadata();

View file

@ -141,7 +141,7 @@ public class CamelEntity extends AbstractHorseEntity implements ClientVehicle {
@Override
protected AttributeData calculateAttribute(Attribute javaAttribute, GeyserAttributeType type) {
AttributeData attributeData = super.calculateAttribute(javaAttribute, type);
if (javaAttribute.getType() == AttributeType.Builtin.GENERIC_JUMP_STRENGTH) {
if (javaAttribute.getType() == AttributeType.Builtin.JUMP_STRENGTH) {
vehicleComponent.setHorseJumpStrength(attributeData.getValue());
}
return attributeData;

View file

@ -247,9 +247,9 @@ public class SessionPlayerEntity extends PlayerEntity {
@Override
protected void updateAttribute(Attribute javaAttribute, List<AttributeData> newAttributes) {
if (javaAttribute.getType() == AttributeType.Builtin.GENERIC_ATTACK_SPEED) {
if (javaAttribute.getType() == AttributeType.Builtin.ATTACK_SPEED) {
session.setAttackSpeed(AttributeUtils.calculateValue(javaAttribute));
} else if (javaAttribute.getType() == AttributeType.Builtin.PLAYER_BLOCK_INTERACTION_RANGE) {
} else if (javaAttribute.getType() == AttributeType.Builtin.BLOCK_INTERACTION_RANGE) {
this.blockInteractionRange = AttributeUtils.calculateValue(javaAttribute);
} else {
super.updateAttribute(javaAttribute, newAttributes);

View file

@ -76,8 +76,8 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
public VehicleComponent(T vehicle, float stepHeight) {
this.vehicle = vehicle;
this.stepHeight = stepHeight;
this.moveSpeed = (float) AttributeType.Builtin.GENERIC_MOVEMENT_SPEED.getDef();
this.gravity = AttributeType.Builtin.GENERIC_GRAVITY.getDef();
this.moveSpeed = (float) AttributeType.Builtin.MOVEMENT_SPEED.getDef();
this.gravity = AttributeType.Builtin.GRAVITY.getDef();
double width = vehicle.getBoundingBoxWidth();
double height = vehicle.getBoundingBoxHeight();

View file

@ -99,7 +99,7 @@ public enum Potion {
}
public PotionContents toComponent() {
return new PotionContents(this.ordinal(), -1, Collections.emptyList());
return new PotionContents(this.ordinal(), -1, Collections.emptyList(), null);
}
public static Potion getByJavaIdentifier(String javaIdentifier) {

View file

@ -25,9 +25,39 @@
package org.geysermc.geyser.item;
import org.geysermc.geyser.item.components.Rarity;
import org.geysermc.geyser.item.components.ToolTier;
import org.geysermc.geyser.item.type.*;
import org.geysermc.geyser.item.type.ArmorItem;
import org.geysermc.geyser.item.type.ArrowItem;
import org.geysermc.geyser.item.type.AxolotlBucketItem;
import org.geysermc.geyser.item.type.BannerItem;
import org.geysermc.geyser.item.type.BlockItem;
import org.geysermc.geyser.item.type.BoatItem;
import org.geysermc.geyser.item.type.CompassItem;
import org.geysermc.geyser.item.type.CrossbowItem;
import org.geysermc.geyser.item.type.DecoratedPotItem;
import org.geysermc.geyser.item.type.DyeItem;
import org.geysermc.geyser.item.type.DyeableArmorItem;
import org.geysermc.geyser.item.type.ElytraItem;
import org.geysermc.geyser.item.type.EnchantedBookItem;
import org.geysermc.geyser.item.type.FilledMapItem;
import org.geysermc.geyser.item.type.FireworkRocketItem;
import org.geysermc.geyser.item.type.FireworkStarItem;
import org.geysermc.geyser.item.type.FishingRodItem;
import org.geysermc.geyser.item.type.GoatHornItem;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.item.type.MaceItem;
import org.geysermc.geyser.item.type.MapItem;
import org.geysermc.geyser.item.type.PlayerHeadItem;
import org.geysermc.geyser.item.type.PotionItem;
import org.geysermc.geyser.item.type.ShieldItem;
import org.geysermc.geyser.item.type.ShulkerBoxItem;
import org.geysermc.geyser.item.type.SpawnEggItem;
import org.geysermc.geyser.item.type.TieredItem;
import org.geysermc.geyser.item.type.TippedArrowItem;
import org.geysermc.geyser.item.type.TropicalFishBucketItem;
import org.geysermc.geyser.item.type.WolfArmorItem;
import org.geysermc.geyser.item.type.WritableBookItem;
import org.geysermc.geyser.item.type.WrittenBookItem;
import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.registry.Registries;
@ -81,6 +111,7 @@ public final class Items {
public static final Item ACACIA_PLANKS = register(new BlockItem(builder(), Blocks.ACACIA_PLANKS));
public static final Item CHERRY_PLANKS = register(new BlockItem(builder(), Blocks.CHERRY_PLANKS));
public static final Item DARK_OAK_PLANKS = register(new BlockItem(builder(), Blocks.DARK_OAK_PLANKS));
public static final Item PALE_OAK_PLANKS = register(new BlockItem(builder(), Blocks.PALE_OAK_PLANKS));
public static final Item MANGROVE_PLANKS = register(new BlockItem(builder(), Blocks.MANGROVE_PLANKS));
public static final Item BAMBOO_PLANKS = register(new BlockItem(builder(), Blocks.BAMBOO_PLANKS));
public static final Item CRIMSON_PLANKS = register(new BlockItem(builder(), Blocks.CRIMSON_PLANKS));
@ -93,6 +124,7 @@ public final class Items {
public static final Item ACACIA_SAPLING = register(new BlockItem(builder(), Blocks.ACACIA_SAPLING));
public static final Item CHERRY_SAPLING = register(new BlockItem(builder(), Blocks.CHERRY_SAPLING));
public static final Item DARK_OAK_SAPLING = register(new BlockItem(builder(), Blocks.DARK_OAK_SAPLING));
public static final Item PALE_OAK_SAPLING = register(new BlockItem(builder(), Blocks.PALE_OAK_SAPLING));
public static final Item MANGROVE_PROPAGULE = register(new BlockItem(builder(), Blocks.MANGROVE_PROPAGULE));
public static final Item BEDROCK = register(new BlockItem(builder(), Blocks.BEDROCK));
public static final Item SAND = register(new BlockItem(builder(), Blocks.SAND));
@ -123,7 +155,7 @@ public final class Items {
public static final Item RAW_IRON_BLOCK = register(new BlockItem(builder(), Blocks.RAW_IRON_BLOCK));
public static final Item RAW_COPPER_BLOCK = register(new BlockItem(builder(), Blocks.RAW_COPPER_BLOCK));
public static final Item RAW_GOLD_BLOCK = register(new BlockItem(builder(), Blocks.RAW_GOLD_BLOCK));
public static final Item HEAVY_CORE = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.HEAVY_CORE));
public static final Item HEAVY_CORE = register(new BlockItem(builder(), Blocks.HEAVY_CORE));
public static final Item AMETHYST_BLOCK = register(new BlockItem(builder(), Blocks.AMETHYST_BLOCK));
public static final Item BUDDING_AMETHYST = register(new BlockItem(builder(), Blocks.BUDDING_AMETHYST));
public static final Item IRON_BLOCK = register(new BlockItem(builder(), Blocks.IRON_BLOCK));
@ -176,6 +208,7 @@ public final class Items {
public static final Item JUNGLE_LOG = register(new BlockItem(builder(), Blocks.JUNGLE_LOG));
public static final Item ACACIA_LOG = register(new BlockItem(builder(), Blocks.ACACIA_LOG));
public static final Item CHERRY_LOG = register(new BlockItem(builder(), Blocks.CHERRY_LOG));
public static final Item PALE_OAK_LOG = register(new BlockItem(builder(), Blocks.PALE_OAK_LOG));
public static final Item DARK_OAK_LOG = register(new BlockItem(builder(), Blocks.DARK_OAK_LOG));
public static final Item MANGROVE_LOG = register(new BlockItem(builder(), Blocks.MANGROVE_LOG));
public static final Item MANGROVE_ROOTS = register(new BlockItem(builder(), Blocks.MANGROVE_ROOTS));
@ -190,6 +223,7 @@ public final class Items {
public static final Item STRIPPED_ACACIA_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_ACACIA_LOG));
public static final Item STRIPPED_CHERRY_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_CHERRY_LOG));
public static final Item STRIPPED_DARK_OAK_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_DARK_OAK_LOG));
public static final Item STRIPPED_PALE_OAK_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_PALE_OAK_LOG));
public static final Item STRIPPED_MANGROVE_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_MANGROVE_LOG));
public static final Item STRIPPED_CRIMSON_STEM = register(new BlockItem(builder(), Blocks.STRIPPED_CRIMSON_STEM));
public static final Item STRIPPED_WARPED_STEM = register(new BlockItem(builder(), Blocks.STRIPPED_WARPED_STEM));
@ -200,6 +234,7 @@ public final class Items {
public static final Item STRIPPED_ACACIA_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_ACACIA_WOOD));
public static final Item STRIPPED_CHERRY_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_CHERRY_WOOD));
public static final Item STRIPPED_DARK_OAK_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_DARK_OAK_WOOD));
public static final Item STRIPPED_PALE_OAK_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_PALE_OAK_WOOD));
public static final Item STRIPPED_MANGROVE_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_MANGROVE_WOOD));
public static final Item STRIPPED_CRIMSON_HYPHAE = register(new BlockItem(builder(), Blocks.STRIPPED_CRIMSON_HYPHAE));
public static final Item STRIPPED_WARPED_HYPHAE = register(new BlockItem(builder(), Blocks.STRIPPED_WARPED_HYPHAE));
@ -210,6 +245,7 @@ public final class Items {
public static final Item JUNGLE_WOOD = register(new BlockItem(builder(), Blocks.JUNGLE_WOOD));
public static final Item ACACIA_WOOD = register(new BlockItem(builder(), Blocks.ACACIA_WOOD));
public static final Item CHERRY_WOOD = register(new BlockItem(builder(), Blocks.CHERRY_WOOD));
public static final Item PALE_OAK_WOOD = register(new BlockItem(builder(), Blocks.PALE_OAK_WOOD));
public static final Item DARK_OAK_WOOD = register(new BlockItem(builder(), Blocks.DARK_OAK_WOOD));
public static final Item MANGROVE_WOOD = register(new BlockItem(builder(), Blocks.MANGROVE_WOOD));
public static final Item CRIMSON_HYPHAE = register(new BlockItem(builder(), Blocks.CRIMSON_HYPHAE));
@ -221,6 +257,7 @@ public final class Items {
public static final Item ACACIA_LEAVES = register(new BlockItem(builder(), Blocks.ACACIA_LEAVES));
public static final Item CHERRY_LEAVES = register(new BlockItem(builder(), Blocks.CHERRY_LEAVES));
public static final Item DARK_OAK_LEAVES = register(new BlockItem(builder(), Blocks.DARK_OAK_LEAVES));
public static final Item PALE_OAK_LEAVES = register(new BlockItem(builder(), Blocks.PALE_OAK_LEAVES));
public static final Item MANGROVE_LEAVES = register(new BlockItem(builder(), Blocks.MANGROVE_LEAVES));
public static final Item AZALEA_LEAVES = register(new BlockItem(builder(), Blocks.AZALEA_LEAVES));
public static final Item FLOWERING_AZALEA_LEAVES = register(new BlockItem(builder(), Blocks.FLOWERING_AZALEA_LEAVES));
@ -283,9 +320,12 @@ public final class Items {
public static final Item TWISTING_VINES = register(new BlockItem(builder(), Blocks.TWISTING_VINES));
public static final Item SUGAR_CANE = register(new BlockItem(builder(), Blocks.SUGAR_CANE));
public static final Item KELP = register(new BlockItem(builder(), Blocks.KELP));
public static final Item MOSS_CARPET = register(new BlockItem(builder(), Blocks.MOSS_CARPET));
public static final Item PINK_PETALS = register(new BlockItem(builder(), Blocks.PINK_PETALS));
public static final Item MOSS_CARPET = register(new BlockItem(builder(), Blocks.MOSS_CARPET));
public static final Item MOSS_BLOCK = register(new BlockItem(builder(), Blocks.MOSS_BLOCK));
public static final Item PALE_MOSS_CARPET = register(new BlockItem(builder(), Blocks.PALE_MOSS_CARPET));
public static final Item PALE_HANGING_MOSS = register(new BlockItem(builder(), Blocks.PALE_HANGING_MOSS));
public static final Item PALE_MOSS_BLOCK = register(new BlockItem(builder(), Blocks.PALE_MOSS_BLOCK));
public static final Item HANGING_ROOTS = register(new BlockItem(builder(), Blocks.HANGING_ROOTS));
public static final Item BIG_DRIPLEAF = register(new BlockItem(builder(), Blocks.BIG_DRIPLEAF, Blocks.BIG_DRIPLEAF_STEM));
public static final Item SMALL_DRIPLEAF = register(new BlockItem(builder(), Blocks.SMALL_DRIPLEAF));
@ -297,6 +337,7 @@ public final class Items {
public static final Item ACACIA_SLAB = register(new BlockItem(builder(), Blocks.ACACIA_SLAB));
public static final Item CHERRY_SLAB = register(new BlockItem(builder(), Blocks.CHERRY_SLAB));
public static final Item DARK_OAK_SLAB = register(new BlockItem(builder(), Blocks.DARK_OAK_SLAB));
public static final Item PALE_OAK_SLAB = register(new BlockItem(builder(), Blocks.PALE_OAK_SLAB));
public static final Item MANGROVE_SLAB = register(new BlockItem(builder(), Blocks.MANGROVE_SLAB));
public static final Item BAMBOO_SLAB = register(new BlockItem(builder(), Blocks.BAMBOO_SLAB));
public static final Item BAMBOO_MOSAIC_SLAB = register(new BlockItem(builder(), Blocks.BAMBOO_MOSAIC_SLAB));
@ -337,6 +378,7 @@ public final class Items {
public static final Item PURPUR_PILLAR = register(new BlockItem(builder(), Blocks.PURPUR_PILLAR));
public static final Item PURPUR_STAIRS = register(new BlockItem(builder(), Blocks.PURPUR_STAIRS));
public static final Item SPAWNER = register(new BlockItem(builder(), Blocks.SPAWNER));
public static final Item CREAKING_HEART = register(new BlockItem(builder(), Blocks.CREAKING_HEART));
public static final Item CHEST = register(new BlockItem(builder(), Blocks.CHEST));
public static final Item CRAFTING_TABLE = register(new BlockItem(builder(), Blocks.CRAFTING_TABLE));
public static final Item FARMLAND = register(new BlockItem(builder(), Blocks.FARMLAND));
@ -356,6 +398,7 @@ public final class Items {
public static final Item ACACIA_FENCE = register(new BlockItem(builder(), Blocks.ACACIA_FENCE));
public static final Item CHERRY_FENCE = register(new BlockItem(builder(), Blocks.CHERRY_FENCE));
public static final Item DARK_OAK_FENCE = register(new BlockItem(builder(), Blocks.DARK_OAK_FENCE));
public static final Item PALE_OAK_FENCE = register(new BlockItem(builder(), Blocks.PALE_OAK_FENCE));
public static final Item MANGROVE_FENCE = register(new BlockItem(builder(), Blocks.MANGROVE_FENCE));
public static final Item BAMBOO_FENCE = register(new BlockItem(builder(), Blocks.BAMBOO_FENCE));
public static final Item CRIMSON_FENCE = register(new BlockItem(builder(), Blocks.CRIMSON_FENCE));
@ -417,7 +460,7 @@ public final class Items {
public static final Item END_PORTAL_FRAME = register(new BlockItem(builder(), Blocks.END_PORTAL_FRAME));
public static final Item END_STONE = register(new BlockItem(builder(), Blocks.END_STONE));
public static final Item END_STONE_BRICKS = register(new BlockItem(builder(), Blocks.END_STONE_BRICKS));
public static final Item DRAGON_EGG = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.DRAGON_EGG));
public static final Item DRAGON_EGG = register(new BlockItem(builder(), Blocks.DRAGON_EGG));
public static final Item SANDSTONE_STAIRS = register(new BlockItem(builder(), Blocks.SANDSTONE_STAIRS));
public static final Item ENDER_CHEST = register(new BlockItem(builder(), Blocks.ENDER_CHEST));
public static final Item EMERALD_BLOCK = register(new BlockItem(builder(), Blocks.EMERALD_BLOCK));
@ -428,13 +471,14 @@ public final class Items {
public static final Item ACACIA_STAIRS = register(new BlockItem(builder(), Blocks.ACACIA_STAIRS));
public static final Item CHERRY_STAIRS = register(new BlockItem(builder(), Blocks.CHERRY_STAIRS));
public static final Item DARK_OAK_STAIRS = register(new BlockItem(builder(), Blocks.DARK_OAK_STAIRS));
public static final Item PALE_OAK_STAIRS = register(new BlockItem(builder(), Blocks.PALE_OAK_STAIRS));
public static final Item MANGROVE_STAIRS = register(new BlockItem(builder(), Blocks.MANGROVE_STAIRS));
public static final Item BAMBOO_STAIRS = register(new BlockItem(builder(), Blocks.BAMBOO_STAIRS));
public static final Item BAMBOO_MOSAIC_STAIRS = register(new BlockItem(builder(), Blocks.BAMBOO_MOSAIC_STAIRS));
public static final Item CRIMSON_STAIRS = register(new BlockItem(builder(), Blocks.CRIMSON_STAIRS));
public static final Item WARPED_STAIRS = register(new BlockItem(builder(), Blocks.WARPED_STAIRS));
public static final Item COMMAND_BLOCK = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.COMMAND_BLOCK));
public static final Item BEACON = register(new BlockItem(builder().rarity(Rarity.RARE), Blocks.BEACON));
public static final Item COMMAND_BLOCK = register(new BlockItem(builder(), Blocks.COMMAND_BLOCK));
public static final Item BEACON = register(new BlockItem(builder(), Blocks.BEACON));
public static final Item COBBLESTONE_WALL = register(new BlockItem(builder(), Blocks.COBBLESTONE_WALL));
public static final Item MOSSY_COBBLESTONE_WALL = register(new BlockItem(builder(), Blocks.MOSSY_COBBLESTONE_WALL));
public static final Item BRICK_WALL = register(new BlockItem(builder(), Blocks.BRICK_WALL));
@ -481,8 +525,8 @@ public final class Items {
public static final Item GREEN_TERRACOTTA = register(new BlockItem(builder(), Blocks.GREEN_TERRACOTTA));
public static final Item RED_TERRACOTTA = register(new BlockItem(builder(), Blocks.RED_TERRACOTTA));
public static final Item BLACK_TERRACOTTA = register(new BlockItem(builder(), Blocks.BLACK_TERRACOTTA));
public static final Item BARRIER = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.BARRIER));
public static final Item LIGHT = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.LIGHT));
public static final Item BARRIER = register(new BlockItem(builder(), Blocks.BARRIER));
public static final Item LIGHT = register(new BlockItem(builder(), Blocks.LIGHT));
public static final Item HAY_BLOCK = register(new BlockItem(builder(), Blocks.HAY_BLOCK));
public static final Item WHITE_CARPET = register(new BlockItem(builder(), Blocks.WHITE_CARPET));
public static final Item ORANGE_CARPET = register(new BlockItem(builder(), Blocks.ORANGE_CARPET));
@ -552,14 +596,14 @@ public final class Items {
public static final Item CHISELED_RED_SANDSTONE = register(new BlockItem(builder(), Blocks.CHISELED_RED_SANDSTONE));
public static final Item CUT_RED_SANDSTONE = register(new BlockItem(builder(), Blocks.CUT_RED_SANDSTONE));
public static final Item RED_SANDSTONE_STAIRS = register(new BlockItem(builder(), Blocks.RED_SANDSTONE_STAIRS));
public static final Item REPEATING_COMMAND_BLOCK = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.REPEATING_COMMAND_BLOCK));
public static final Item CHAIN_COMMAND_BLOCK = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.CHAIN_COMMAND_BLOCK));
public static final Item REPEATING_COMMAND_BLOCK = register(new BlockItem(builder(), Blocks.REPEATING_COMMAND_BLOCK));
public static final Item CHAIN_COMMAND_BLOCK = register(new BlockItem(builder(), Blocks.CHAIN_COMMAND_BLOCK));
public static final Item MAGMA_BLOCK = register(new BlockItem(builder(), Blocks.MAGMA_BLOCK));
public static final Item NETHER_WART_BLOCK = register(new BlockItem(builder(), Blocks.NETHER_WART_BLOCK));
public static final Item WARPED_WART_BLOCK = register(new BlockItem(builder(), Blocks.WARPED_WART_BLOCK));
public static final Item RED_NETHER_BRICKS = register(new BlockItem(builder(), Blocks.RED_NETHER_BRICKS));
public static final Item BONE_BLOCK = register(new BlockItem(builder(), Blocks.BONE_BLOCK));
public static final Item STRUCTURE_VOID = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.STRUCTURE_VOID));
public static final Item STRUCTURE_VOID = register(new BlockItem(builder(), Blocks.STRUCTURE_VOID));
public static final Item SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.SHULKER_BOX));
public static final Item WHITE_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.WHITE_SHULKER_BOX));
public static final Item ORANGE_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.ORANGE_SHULKER_BOX));
@ -658,7 +702,7 @@ public final class Items {
public static final Item DEAD_FIRE_CORAL_FAN = register(new BlockItem(builder(), Blocks.DEAD_FIRE_CORAL_FAN, Blocks.DEAD_FIRE_CORAL_WALL_FAN));
public static final Item DEAD_HORN_CORAL_FAN = register(new BlockItem(builder(), Blocks.DEAD_HORN_CORAL_FAN, Blocks.DEAD_HORN_CORAL_WALL_FAN));
public static final Item BLUE_ICE = register(new BlockItem(builder(), Blocks.BLUE_ICE));
public static final Item CONDUIT = register(new BlockItem(builder().rarity(Rarity.RARE), Blocks.CONDUIT));
public static final Item CONDUIT = register(new BlockItem(builder(), Blocks.CONDUIT));
public static final Item POLISHED_GRANITE_STAIRS = register(new BlockItem(builder(), Blocks.POLISHED_GRANITE_STAIRS));
public static final Item SMOOTH_RED_SANDSTONE_STAIRS = register(new BlockItem(builder(), Blocks.SMOOTH_RED_SANDSTONE_STAIRS));
public static final Item MOSSY_STONE_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.MOSSY_STONE_BRICK_STAIRS));
@ -729,6 +773,7 @@ public final class Items {
public static final Item ACACIA_BUTTON = register(new BlockItem(builder(), Blocks.ACACIA_BUTTON));
public static final Item CHERRY_BUTTON = register(new BlockItem(builder(), Blocks.CHERRY_BUTTON));
public static final Item DARK_OAK_BUTTON = register(new BlockItem(builder(), Blocks.DARK_OAK_BUTTON));
public static final Item PALE_OAK_BUTTON = register(new BlockItem(builder(), Blocks.PALE_OAK_BUTTON));
public static final Item MANGROVE_BUTTON = register(new BlockItem(builder(), Blocks.MANGROVE_BUTTON));
public static final Item BAMBOO_BUTTON = register(new BlockItem(builder(), Blocks.BAMBOO_BUTTON));
public static final Item CRIMSON_BUTTON = register(new BlockItem(builder(), Blocks.CRIMSON_BUTTON));
@ -744,6 +789,7 @@ public final class Items {
public static final Item ACACIA_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.ACACIA_PRESSURE_PLATE));
public static final Item CHERRY_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.CHERRY_PRESSURE_PLATE));
public static final Item DARK_OAK_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.DARK_OAK_PRESSURE_PLATE));
public static final Item PALE_OAK_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.PALE_OAK_PRESSURE_PLATE));
public static final Item MANGROVE_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.MANGROVE_PRESSURE_PLATE));
public static final Item BAMBOO_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.BAMBOO_PRESSURE_PLATE));
public static final Item CRIMSON_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.CRIMSON_PRESSURE_PLATE));
@ -756,6 +802,7 @@ public final class Items {
public static final Item ACACIA_DOOR = register(new BlockItem(builder(), Blocks.ACACIA_DOOR));
public static final Item CHERRY_DOOR = register(new BlockItem(builder(), Blocks.CHERRY_DOOR));
public static final Item DARK_OAK_DOOR = register(new BlockItem(builder(), Blocks.DARK_OAK_DOOR));
public static final Item PALE_OAK_DOOR = register(new BlockItem(builder(), Blocks.PALE_OAK_DOOR));
public static final Item MANGROVE_DOOR = register(new BlockItem(builder(), Blocks.MANGROVE_DOOR));
public static final Item BAMBOO_DOOR = register(new BlockItem(builder(), Blocks.BAMBOO_DOOR));
public static final Item CRIMSON_DOOR = register(new BlockItem(builder(), Blocks.CRIMSON_DOOR));
@ -776,6 +823,7 @@ public final class Items {
public static final Item ACACIA_TRAPDOOR = register(new BlockItem(builder(), Blocks.ACACIA_TRAPDOOR));
public static final Item CHERRY_TRAPDOOR = register(new BlockItem(builder(), Blocks.CHERRY_TRAPDOOR));
public static final Item DARK_OAK_TRAPDOOR = register(new BlockItem(builder(), Blocks.DARK_OAK_TRAPDOOR));
public static final Item PALE_OAK_TRAPDOOR = register(new BlockItem(builder(), Blocks.PALE_OAK_TRAPDOOR));
public static final Item MANGROVE_TRAPDOOR = register(new BlockItem(builder(), Blocks.MANGROVE_TRAPDOOR));
public static final Item BAMBOO_TRAPDOOR = register(new BlockItem(builder(), Blocks.BAMBOO_TRAPDOOR));
public static final Item CRIMSON_TRAPDOOR = register(new BlockItem(builder(), Blocks.CRIMSON_TRAPDOOR));
@ -795,6 +843,7 @@ public final class Items {
public static final Item ACACIA_FENCE_GATE = register(new BlockItem(builder(), Blocks.ACACIA_FENCE_GATE));
public static final Item CHERRY_FENCE_GATE = register(new BlockItem(builder(), Blocks.CHERRY_FENCE_GATE));
public static final Item DARK_OAK_FENCE_GATE = register(new BlockItem(builder(), Blocks.DARK_OAK_FENCE_GATE));
public static final Item PALE_OAK_FENCE_GATE = register(new BlockItem(builder(), Blocks.PALE_OAK_FENCE_GATE));
public static final Item MANGROVE_FENCE_GATE = register(new BlockItem(builder(), Blocks.MANGROVE_FENCE_GATE));
public static final Item BAMBOO_FENCE_GATE = register(new BlockItem(builder(), Blocks.BAMBOO_FENCE_GATE));
public static final Item CRIMSON_FENCE_GATE = register(new BlockItem(builder(), Blocks.CRIMSON_FENCE_GATE));
@ -811,7 +860,8 @@ public final class Items {
public static final Item HOPPER_MINECART = register(new Item("hopper_minecart", builder().stackSize(1)));
public static final Item CARROT_ON_A_STICK = register(new Item("carrot_on_a_stick", builder().stackSize(1).maxDamage(25)));
public static final Item WARPED_FUNGUS_ON_A_STICK = register(new Item("warped_fungus_on_a_stick", builder().stackSize(1).maxDamage(100)));
public static final Item ELYTRA = register(new ElytraItem("elytra", builder().stackSize(1).maxDamage(432).rarity(Rarity.UNCOMMON)));
public static final Item PHANTOM_MEMBRANE = register(new Item("phantom_membrane", builder()));
public static final Item ELYTRA = register(new ElytraItem("elytra", builder().stackSize(1).maxDamage(432)));
public static final Item OAK_BOAT = register(new BoatItem("oak_boat", builder().stackSize(1)));
public static final Item OAK_CHEST_BOAT = register(new BoatItem("oak_chest_boat", builder().stackSize(1)));
public static final Item SPRUCE_BOAT = register(new BoatItem("spruce_boat", builder().stackSize(1)));
@ -826,12 +876,14 @@ public final class Items {
public static final Item CHERRY_CHEST_BOAT = register(new BoatItem("cherry_chest_boat", builder().stackSize(1)));
public static final Item DARK_OAK_BOAT = register(new BoatItem("dark_oak_boat", builder().stackSize(1)));
public static final Item DARK_OAK_CHEST_BOAT = register(new BoatItem("dark_oak_chest_boat", builder().stackSize(1)));
public static final Item PALE_OAK_BOAT = register(new BoatItem("pale_oak_boat", builder().stackSize(1)));
public static final Item PALE_OAK_CHEST_BOAT = register(new BoatItem("pale_oak_chest_boat", builder().stackSize(1)));
public static final Item MANGROVE_BOAT = register(new BoatItem("mangrove_boat", builder().stackSize(1)));
public static final Item MANGROVE_CHEST_BOAT = register(new BoatItem("mangrove_chest_boat", builder().stackSize(1)));
public static final Item BAMBOO_RAFT = register(new BoatItem("bamboo_raft", builder().stackSize(1)));
public static final Item BAMBOO_CHEST_RAFT = register(new BoatItem("bamboo_chest_raft", builder().stackSize(1)));
public static final Item STRUCTURE_BLOCK = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.STRUCTURE_BLOCK));
public static final Item JIGSAW = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.JIGSAW));
public static final Item STRUCTURE_BLOCK = register(new BlockItem(builder(), Blocks.STRUCTURE_BLOCK));
public static final Item JIGSAW = register(new BlockItem(builder(), Blocks.JIGSAW));
public static final Item TURTLE_HELMET = register(new ArmorItem("turtle_helmet", ArmorMaterial.TURTLE, builder().stackSize(1).maxDamage(275)));
public static final Item TURTLE_SCUTE = register(new Item("turtle_scute", builder()));
public static final Item ARMADILLO_SCUTE = register(new Item("armadillo_scute", builder()));
@ -922,8 +974,8 @@ public final class Items {
public static final Item PORKCHOP = register(new Item("porkchop", builder()));
public static final Item COOKED_PORKCHOP = register(new Item("cooked_porkchop", builder()));
public static final Item PAINTING = register(new Item("painting", builder()));
public static final Item GOLDEN_APPLE = register(new Item("golden_apple", builder().rarity(Rarity.RARE)));
public static final Item ENCHANTED_GOLDEN_APPLE = register(new Item("enchanted_golden_apple", builder().rarity(Rarity.EPIC)));
public static final Item GOLDEN_APPLE = register(new Item("golden_apple", builder()));
public static final Item ENCHANTED_GOLDEN_APPLE = register(new Item("enchanted_golden_apple", builder()));
public static final Item OAK_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.OAK_SIGN, Blocks.OAK_WALL_SIGN));
public static final Item SPRUCE_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.SPRUCE_SIGN, Blocks.SPRUCE_WALL_SIGN));
public static final Item BIRCH_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.BIRCH_SIGN, Blocks.BIRCH_WALL_SIGN));
@ -931,6 +983,7 @@ public final class Items {
public static final Item ACACIA_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.ACACIA_SIGN, Blocks.ACACIA_WALL_SIGN));
public static final Item CHERRY_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.CHERRY_SIGN, Blocks.CHERRY_WALL_SIGN));
public static final Item DARK_OAK_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.DARK_OAK_SIGN, Blocks.DARK_OAK_WALL_SIGN));
public static final Item PALE_OAK_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.PALE_OAK_SIGN, Blocks.PALE_OAK_WALL_SIGN));
public static final Item MANGROVE_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.MANGROVE_SIGN, Blocks.MANGROVE_WALL_SIGN));
public static final Item BAMBOO_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.BAMBOO_SIGN, Blocks.BAMBOO_WALL_SIGN));
public static final Item CRIMSON_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.CRIMSON_SIGN, Blocks.CRIMSON_WALL_SIGN));
@ -942,6 +995,7 @@ public final class Items {
public static final Item ACACIA_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.ACACIA_HANGING_SIGN, Blocks.ACACIA_WALL_HANGING_SIGN));
public static final Item CHERRY_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.CHERRY_HANGING_SIGN, Blocks.CHERRY_WALL_HANGING_SIGN));
public static final Item DARK_OAK_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.DARK_OAK_HANGING_SIGN, Blocks.DARK_OAK_WALL_HANGING_SIGN));
public static final Item PALE_OAK_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.PALE_OAK_HANGING_SIGN, Blocks.PALE_OAK_WALL_HANGING_SIGN));
public static final Item MANGROVE_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.MANGROVE_HANGING_SIGN, Blocks.MANGROVE_WALL_HANGING_SIGN));
public static final Item BAMBOO_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.BAMBOO_HANGING_SIGN, Blocks.BAMBOO_WALL_HANGING_SIGN));
public static final Item CRIMSON_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.CRIMSON_HANGING_SIGN, Blocks.CRIMSON_WALL_HANGING_SIGN));
@ -969,6 +1023,22 @@ public final class Items {
public static final Item COMPASS = register(new CompassItem("compass", builder()));
public static final Item RECOVERY_COMPASS = register(new Item("recovery_compass", builder()));
public static final Item BUNDLE = register(new Item("bundle", builder().stackSize(1)));
public static final Item WHITE_BUNDLE = register(new Item("white_bundle", builder().stackSize(1)));
public static final Item ORANGE_BUNDLE = register(new Item("orange_bundle", builder().stackSize(1)));
public static final Item MAGENTA_BUNDLE = register(new Item("magenta_bundle", builder().stackSize(1)));
public static final Item LIGHT_BLUE_BUNDLE = register(new Item("light_blue_bundle", builder().stackSize(1)));
public static final Item YELLOW_BUNDLE = register(new Item("yellow_bundle", builder().stackSize(1)));
public static final Item LIME_BUNDLE = register(new Item("lime_bundle", builder().stackSize(1)));
public static final Item PINK_BUNDLE = register(new Item("pink_bundle", builder().stackSize(1)));
public static final Item GRAY_BUNDLE = register(new Item("gray_bundle", builder().stackSize(1)));
public static final Item LIGHT_GRAY_BUNDLE = register(new Item("light_gray_bundle", builder().stackSize(1)));
public static final Item CYAN_BUNDLE = register(new Item("cyan_bundle", builder().stackSize(1)));
public static final Item PURPLE_BUNDLE = register(new Item("purple_bundle", builder().stackSize(1)));
public static final Item BLUE_BUNDLE = register(new Item("blue_bundle", builder().stackSize(1)));
public static final Item BROWN_BUNDLE = register(new Item("brown_bundle", builder().stackSize(1)));
public static final Item GREEN_BUNDLE = register(new Item("green_bundle", builder().stackSize(1)));
public static final Item RED_BUNDLE = register(new Item("red_bundle", builder().stackSize(1)));
public static final Item BLACK_BUNDLE = register(new Item("black_bundle", builder().stackSize(1)));
public static final Item FISHING_ROD = register(new FishingRodItem("fishing_rod", builder().stackSize(1).maxDamage(64)));
public static final Item CLOCK = register(new Item("clock", builder()));
public static final Item SPYGLASS = register(new Item("spyglass", builder().stackSize(1)));
@ -1036,14 +1106,14 @@ public final class Items {
public static final Item GHAST_TEAR = register(new Item("ghast_tear", builder()));
public static final Item GOLD_NUGGET = register(new Item("gold_nugget", builder()));
public static final Item NETHER_WART = register(new BlockItem(builder(), Blocks.NETHER_WART));
public static final Item POTION = register(new PotionItem("potion", builder().stackSize(1)));
public static final Item GLASS_BOTTLE = register(new Item("glass_bottle", builder()));
public static final Item POTION = register(new PotionItem("potion", builder().stackSize(1)));
public static final Item SPIDER_EYE = register(new Item("spider_eye", builder()));
public static final Item FERMENTED_SPIDER_EYE = register(new Item("fermented_spider_eye", builder()));
public static final Item BLAZE_POWDER = register(new Item("blaze_powder", builder()));
public static final Item MAGMA_CREAM = register(new Item("magma_cream", builder()));
public static final Item BREWING_STAND = register(new BlockItem(builder(), Blocks.BREWING_STAND));
public static final Item CAULDRON = register(new BlockItem(builder(), Blocks.CAULDRON, Blocks.WATER_CAULDRON, Blocks.POWDER_SNOW_CAULDRON, Blocks.LAVA_CAULDRON));
public static final Item CAULDRON = register(new BlockItem(builder(), Blocks.CAULDRON, Blocks.LAVA_CAULDRON, Blocks.WATER_CAULDRON, Blocks.POWDER_SNOW_CAULDRON));
public static final Item ENDER_EYE = register(new Item("ender_eye", builder()));
public static final Item GLISTERING_MELON_SLICE = register(new Item("glistering_melon_slice", builder()));
public static final Item ARMADILLO_SPAWN_EGG = register(new SpawnEggItem("armadillo_spawn_egg", builder()));
@ -1122,16 +1192,18 @@ public final class Items {
public static final Item WITHER_SKELETON_SPAWN_EGG = register(new SpawnEggItem("wither_skeleton_spawn_egg", builder()));
public static final Item WOLF_SPAWN_EGG = register(new SpawnEggItem("wolf_spawn_egg", builder()));
public static final Item ZOGLIN_SPAWN_EGG = register(new SpawnEggItem("zoglin_spawn_egg", builder()));
public static final Item CREAKING_SPAWN_EGG = register(new SpawnEggItem("creaking_spawn_egg", builder()));
public static final Item ZOMBIE_SPAWN_EGG = register(new SpawnEggItem("zombie_spawn_egg", builder()));
public static final Item ZOMBIE_HORSE_SPAWN_EGG = register(new SpawnEggItem("zombie_horse_spawn_egg", builder()));
public static final Item ZOMBIE_VILLAGER_SPAWN_EGG = register(new SpawnEggItem("zombie_villager_spawn_egg", builder()));
public static final Item ZOMBIFIED_PIGLIN_SPAWN_EGG = register(new SpawnEggItem("zombified_piglin_spawn_egg", builder()));
public static final Item EXPERIENCE_BOTTLE = register(new Item("experience_bottle", builder().rarity(Rarity.UNCOMMON)));
public static final Item EXPERIENCE_BOTTLE = register(new Item("experience_bottle", builder()));
public static final Item FIRE_CHARGE = register(new Item("fire_charge", builder()));
public static final Item WIND_CHARGE = register(new Item("wind_charge", builder()));
public static final Item WRITABLE_BOOK = register(new WritableBookItem("writable_book", builder().stackSize(1)));
public static final Item WRITTEN_BOOK = register(new WrittenBookItem("written_book", builder().stackSize(16)));
public static final Item MACE = register(new MaceItem("mace", builder().stackSize(1).maxDamage(500).rarity(Rarity.EPIC)));
public static final Item BREEZE_ROD = register(new Item("breeze_rod", builder()));
public static final Item MACE = register(new MaceItem("mace", builder().stackSize(1).maxDamage(500)));
public static final Item ITEM_FRAME = register(new Item("item_frame", builder()));
public static final Item GLOW_ITEM_FRAME = register(new Item("glow_item_frame", builder()));
public static final Item FLOWER_POT = register(new BlockItem(builder(), Blocks.FLOWER_POT));
@ -1141,18 +1213,18 @@ public final class Items {
public static final Item POISONOUS_POTATO = register(new Item("poisonous_potato", builder()));
public static final Item MAP = register(new MapItem("map", builder()));
public static final Item GOLDEN_CARROT = register(new Item("golden_carrot", builder()));
public static final Item SKELETON_SKULL = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.SKELETON_SKULL, Blocks.SKELETON_WALL_SKULL));
public static final Item WITHER_SKELETON_SKULL = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.WITHER_SKELETON_SKULL, Blocks.WITHER_SKELETON_WALL_SKULL));
public static final Item PLAYER_HEAD = register(new PlayerHeadItem(builder().rarity(Rarity.UNCOMMON), Blocks.PLAYER_HEAD, Blocks.PLAYER_WALL_HEAD));
public static final Item ZOMBIE_HEAD = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.ZOMBIE_HEAD, Blocks.ZOMBIE_WALL_HEAD));
public static final Item CREEPER_HEAD = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.CREEPER_HEAD, Blocks.CREEPER_WALL_HEAD));
public static final Item DRAGON_HEAD = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.DRAGON_HEAD, Blocks.DRAGON_WALL_HEAD));
public static final Item PIGLIN_HEAD = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.PIGLIN_HEAD, Blocks.PIGLIN_WALL_HEAD));
public static final Item NETHER_STAR = register(new Item("nether_star", builder().rarity(Rarity.UNCOMMON)));
public static final Item SKELETON_SKULL = register(new BlockItem(builder(), Blocks.SKELETON_SKULL, Blocks.SKELETON_WALL_SKULL));
public static final Item WITHER_SKELETON_SKULL = register(new BlockItem(builder(), Blocks.WITHER_SKELETON_SKULL, Blocks.WITHER_SKELETON_WALL_SKULL));
public static final Item PLAYER_HEAD = register(new PlayerHeadItem(builder(), Blocks.PLAYER_HEAD, Blocks.PLAYER_WALL_HEAD));
public static final Item ZOMBIE_HEAD = register(new BlockItem(builder(), Blocks.ZOMBIE_HEAD, Blocks.ZOMBIE_WALL_HEAD));
public static final Item CREEPER_HEAD = register(new BlockItem(builder(), Blocks.CREEPER_HEAD, Blocks.CREEPER_WALL_HEAD));
public static final Item DRAGON_HEAD = register(new BlockItem(builder(), Blocks.DRAGON_HEAD, Blocks.DRAGON_WALL_HEAD));
public static final Item PIGLIN_HEAD = register(new BlockItem(builder(), Blocks.PIGLIN_HEAD, Blocks.PIGLIN_WALL_HEAD));
public static final Item NETHER_STAR = register(new Item("nether_star", builder()));
public static final Item PUMPKIN_PIE = register(new Item("pumpkin_pie", builder()));
public static final Item FIREWORK_ROCKET = register(new FireworkRocketItem("firework_rocket", builder()));
public static final Item FIREWORK_STAR = register(new FireworkStarItem("firework_star", builder()));
public static final Item ENCHANTED_BOOK = register(new EnchantedBookItem("enchanted_book", builder().stackSize(1).rarity(Rarity.UNCOMMON)));
public static final Item ENCHANTED_BOOK = register(new EnchantedBookItem("enchanted_book", builder().stackSize(1)));
public static final Item NETHER_BRICK = register(new Item("nether_brick", builder()));
public static final Item PRISMARINE_SHARD = register(new Item("prismarine_shard", builder()));
public static final Item PRISMARINE_CRYSTALS = register(new Item("prismarine_crystals", builder()));
@ -1162,13 +1234,13 @@ public final class Items {
public static final Item RABBIT_FOOT = register(new Item("rabbit_foot", builder()));
public static final Item RABBIT_HIDE = register(new Item("rabbit_hide", builder()));
public static final Item ARMOR_STAND = register(new Item("armor_stand", builder().stackSize(16)));
public static final Item IRON_HORSE_ARMOR = register(new ArmorItem("iron_horse_armor", ArmorMaterial.IRON, builder().stackSize(1)));
public static final Item GOLDEN_HORSE_ARMOR = register(new ArmorItem("golden_horse_armor", ArmorMaterial.GOLD, builder().stackSize(1)));
public static final Item DIAMOND_HORSE_ARMOR = register(new ArmorItem("diamond_horse_armor", ArmorMaterial.DIAMOND, builder().stackSize(1)));
public static final Item LEATHER_HORSE_ARMOR = register(new DyeableArmorItem("leather_horse_armor", ArmorMaterial.LEATHER, builder().stackSize(1)));
public static final Item IRON_HORSE_ARMOR = register(new Item("iron_horse_armor", builder().stackSize(1)));
public static final Item GOLDEN_HORSE_ARMOR = register(new Item("golden_horse_armor", builder().stackSize(1)));
public static final Item DIAMOND_HORSE_ARMOR = register(new Item("diamond_horse_armor", builder().stackSize(1)));
public static final Item LEATHER_HORSE_ARMOR = register(new Item("leather_horse_armor", builder().stackSize(1)));
public static final Item LEAD = register(new Item("lead", builder()));
public static final Item NAME_TAG = register(new Item("name_tag", builder()));
public static final Item COMMAND_BLOCK_MINECART = register(new Item("command_block_minecart", builder().stackSize(1).rarity(Rarity.EPIC)));
public static final Item COMMAND_BLOCK_MINECART = register(new Item("command_block_minecart", builder().stackSize(1)));
public static final Item MUTTON = register(new Item("mutton", builder()));
public static final Item COOKED_MUTTON = register(new Item("cooked_mutton", builder()));
public static final Item WHITE_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.WHITE_BANNER, Blocks.WHITE_WALL_BANNER));
@ -1187,7 +1259,7 @@ public final class Items {
public static final Item GREEN_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.GREEN_BANNER, Blocks.GREEN_WALL_BANNER));
public static final Item RED_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.RED_BANNER, Blocks.RED_WALL_BANNER));
public static final Item BLACK_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.BLACK_BANNER, Blocks.BLACK_WALL_BANNER));
public static final Item END_CRYSTAL = register(new Item("end_crystal", builder().rarity(Rarity.RARE)));
public static final Item END_CRYSTAL = register(new Item("end_crystal", 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 TORCHFLOWER_SEEDS = register(new BlockItem("torchflower_seeds", builder(), Blocks.TORCHFLOWER_CROP));
@ -1195,52 +1267,53 @@ public final class Items {
public static final Item BEETROOT = register(new Item("beetroot", builder()));
public static final Item BEETROOT_SEEDS = register(new BlockItem("beetroot_seeds", builder(), Blocks.BEETROOTS));
public static final Item BEETROOT_SOUP = register(new Item("beetroot_soup", builder().stackSize(1)));
public static final Item DRAGON_BREATH = register(new Item("dragon_breath", builder().rarity(Rarity.UNCOMMON)));
public static final Item DRAGON_BREATH = register(new Item("dragon_breath", builder()));
public static final Item SPLASH_POTION = register(new PotionItem("splash_potion", builder().stackSize(1)));
public static final Item SPECTRAL_ARROW = register(new Item("spectral_arrow", builder()));
public static final Item TIPPED_ARROW = register(new TippedArrowItem("tipped_arrow", builder()));
public static final Item LINGERING_POTION = register(new PotionItem("lingering_potion", builder().stackSize(1)));
public static final Item SHIELD = register(new ShieldItem("shield", builder().stackSize(1).maxDamage(336)));
public static final Item TOTEM_OF_UNDYING = register(new Item("totem_of_undying", builder().stackSize(1).rarity(Rarity.UNCOMMON)));
public static final Item TOTEM_OF_UNDYING = register(new Item("totem_of_undying", builder().stackSize(1)));
public static final Item SHULKER_SHELL = register(new Item("shulker_shell", builder()));
public static final Item IRON_NUGGET = register(new Item("iron_nugget", builder()));
public static final Item KNOWLEDGE_BOOK = register(new Item("knowledge_book", builder().stackSize(1).rarity(Rarity.EPIC)));
public static final Item DEBUG_STICK = register(new Item("debug_stick", builder().stackSize(1).rarity(Rarity.EPIC).glint(true)));
public static final Item MUSIC_DISC_13 = register(new Item("music_disc_13", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_CAT = register(new Item("music_disc_cat", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_BLOCKS = register(new Item("music_disc_blocks", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_CHIRP = register(new Item("music_disc_chirp", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_CREATOR = register(new Item("music_disc_creator", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_CREATOR_MUSIC_BOX = register(new Item("music_disc_creator_music_box", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_FAR = register(new Item("music_disc_far", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_MALL = register(new Item("music_disc_mall", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_MELLOHI = register(new Item("music_disc_mellohi", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_STAL = register(new Item("music_disc_stal", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_STRAD = register(new Item("music_disc_strad", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_WARD = register(new Item("music_disc_ward", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_11 = register(new Item("music_disc_11", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_WAIT = register(new Item("music_disc_wait", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_OTHERSIDE = register(new Item("music_disc_otherside", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_RELIC = register(new Item("music_disc_relic", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_5 = register(new Item("music_disc_5", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_PIGSTEP = register(new Item("music_disc_pigstep", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_PRECIPICE = register(new Item("music_disc_precipice", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item KNOWLEDGE_BOOK = register(new Item("knowledge_book", builder().stackSize(1)));
public static final Item DEBUG_STICK = register(new Item("debug_stick", builder().stackSize(1)));
public static final Item MUSIC_DISC_13 = register(new Item("music_disc_13", builder().stackSize(1)));
public static final Item MUSIC_DISC_CAT = register(new Item("music_disc_cat", builder().stackSize(1)));
public static final Item MUSIC_DISC_BLOCKS = register(new Item("music_disc_blocks", builder().stackSize(1)));
public static final Item MUSIC_DISC_CHIRP = register(new Item("music_disc_chirp", builder().stackSize(1)));
public static final Item MUSIC_DISC_CREATOR = register(new Item("music_disc_creator", builder().stackSize(1)));
public static final Item MUSIC_DISC_CREATOR_MUSIC_BOX = register(new Item("music_disc_creator_music_box", builder().stackSize(1)));
public static final Item MUSIC_DISC_FAR = register(new Item("music_disc_far", builder().stackSize(1)));
public static final Item MUSIC_DISC_MALL = register(new Item("music_disc_mall", builder().stackSize(1)));
public static final Item MUSIC_DISC_MELLOHI = register(new Item("music_disc_mellohi", builder().stackSize(1)));
public static final Item MUSIC_DISC_STAL = register(new Item("music_disc_stal", builder().stackSize(1)));
public static final Item MUSIC_DISC_STRAD = register(new Item("music_disc_strad", builder().stackSize(1)));
public static final Item MUSIC_DISC_WARD = register(new Item("music_disc_ward", 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_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_PIGSTEP = register(new Item("music_disc_pigstep", builder().stackSize(1)));
public static final Item MUSIC_DISC_PRECIPICE = register(new Item("music_disc_precipice", builder().stackSize(1)));
public static final Item DISC_FRAGMENT_5 = register(new Item("disc_fragment_5", builder()));
public static final Item TRIDENT = register(new Item("trident", builder().stackSize(1).maxDamage(250).attackDamage(9.0).rarity(Rarity.EPIC)));
public static final Item PHANTOM_MEMBRANE = register(new Item("phantom_membrane", builder()));
public static final Item TRIDENT = register(new Item("trident", builder().stackSize(1).maxDamage(250).attackDamage(9.0)));
public static final Item NAUTILUS_SHELL = register(new Item("nautilus_shell", builder()));
public static final Item HEART_OF_THE_SEA = register(new Item("heart_of_the_sea", builder().rarity(Rarity.UNCOMMON)));
public static final Item HEART_OF_THE_SEA = register(new Item("heart_of_the_sea", builder()));
public static final Item CROSSBOW = register(new CrossbowItem("crossbow", builder().stackSize(1).maxDamage(465)));
public static final Item SUSPICIOUS_STEW = register(new Item("suspicious_stew", builder().stackSize(1)));
public static final Item LOOM = register(new BlockItem(builder(), Blocks.LOOM));
public static final Item FLOWER_BANNER_PATTERN = register(new Item("flower_banner_pattern", builder().stackSize(1)));
public static final Item CREEPER_BANNER_PATTERN = register(new Item("creeper_banner_pattern", builder().stackSize(1).rarity(Rarity.UNCOMMON)));
public static final Item SKULL_BANNER_PATTERN = register(new Item("skull_banner_pattern", builder().stackSize(1).rarity(Rarity.UNCOMMON)));
public static final Item MOJANG_BANNER_PATTERN = register(new Item("mojang_banner_pattern", builder().stackSize(1).rarity(Rarity.EPIC)));
public static final Item CREEPER_BANNER_PATTERN = register(new Item("creeper_banner_pattern", builder().stackSize(1)));
public static final Item SKULL_BANNER_PATTERN = register(new Item("skull_banner_pattern", builder().stackSize(1)));
public static final Item MOJANG_BANNER_PATTERN = register(new Item("mojang_banner_pattern", builder().stackSize(1)));
public static final Item GLOBE_BANNER_PATTERN = register(new Item("globe_banner_pattern", builder().stackSize(1)));
public static final Item PIGLIN_BANNER_PATTERN = register(new Item("piglin_banner_pattern", builder().stackSize(1).rarity(Rarity.UNCOMMON)));
public static final Item FLOW_BANNER_PATTERN = register(new Item("flow_banner_pattern", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item GUSTER_BANNER_PATTERN = register(new Item("guster_banner_pattern", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item PIGLIN_BANNER_PATTERN = register(new Item("piglin_banner_pattern", builder().stackSize(1)));
public static final Item FLOW_BANNER_PATTERN = register(new Item("flow_banner_pattern", builder().stackSize(1)));
public static final Item GUSTER_BANNER_PATTERN = register(new Item("guster_banner_pattern", builder().stackSize(1)));
public static final Item FIELD_MASONED_BANNER_PATTERN = register(new Item("field_masoned_banner_pattern", builder().stackSize(1)));
public static final Item BORDURE_INDENTED_BANNER_PATTERN = register(new Item("bordure_indented_banner_pattern", builder().stackSize(1)));
public static final Item GOAT_HORN = register(new GoatHornItem("goat_horn", builder().stackSize(1)));
public static final Item COMPOSTER = register(new BlockItem(builder(), Blocks.COMPOSTER));
public static final Item BARREL = register(new BlockItem(builder(), Blocks.BARREL));
@ -1369,8 +1442,7 @@ public final class Items {
public static final Item TRIAL_KEY = register(new Item("trial_key", builder()));
public static final Item OMINOUS_TRIAL_KEY = register(new Item("ominous_trial_key", builder()));
public static final Item VAULT = register(new BlockItem(builder(), Blocks.VAULT));
public static final Item OMINOUS_BOTTLE = register(new OminousBottleItem("ominous_bottle", builder()));
public static final Item BREEZE_ROD = register(new Item("breeze_rod", builder()));
public static final Item OMINOUS_BOTTLE = register(new Item("ominous_bottle", builder()));
public static final int AIR_ID = AIR.javaId();

File diff suppressed because it is too large Load diff

View file

@ -47,6 +47,7 @@ public final class Properties {
public static final BooleanProperty INVERTED = BooleanProperty.create("inverted");
public static final BooleanProperty IN_WALL = BooleanProperty.create("in_wall");
public static final BooleanProperty LIT = BooleanProperty.create("lit");
public static final BooleanProperty TIP = BooleanProperty.create("tip");
public static final BooleanProperty LOCKED = BooleanProperty.create("locked");
public static final BooleanProperty OCCUPIED = BooleanProperty.create("occupied");
public static final BooleanProperty OPEN = BooleanProperty.create("open");
@ -142,5 +143,6 @@ public final class Properties {
public static final BooleanProperty CRAFTING = BooleanProperty.create("crafting");
public static final BasicEnumProperty TRIAL_SPAWNER_STATE = BasicEnumProperty.create("trial_spawner_state", "inactive", "waiting_for_players", "active", "waiting_for_reward_ejection", "ejecting_reward", "cooldown");
public static final BasicEnumProperty VAULT_STATE = BasicEnumProperty.create("vault_state", "inactive", "active", "unlocking", "ejecting");
public static final BasicEnumProperty CREAKING = BasicEnumProperty.create("creaking", "disabled", "dormant", "active");
public static final BooleanProperty OMINOUS = BooleanProperty.create("ominous");
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2024 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.level.physics;
import org.cloudburstmc.math.vector.Vector3d;
/**
* Holds the result of a collision check.
*/
public record CollisionResult(Vector3d correctedMovement, boolean horizontalCollision) {
}

View file

@ -191,7 +191,6 @@ import org.geysermc.mcprotocollib.network.event.session.SessionAdapter;
import org.geysermc.mcprotocollib.network.packet.Packet;
import org.geysermc.mcprotocollib.network.tcp.TcpClientSession;
import org.geysermc.mcprotocollib.network.tcp.TcpSession;
import org.geysermc.mcprotocollib.protocol.ClientListener;
import org.geysermc.mcprotocollib.protocol.MinecraftConstants;
import org.geysermc.mcprotocollib.protocol.MinecraftProtocol;
import org.geysermc.mcprotocollib.protocol.data.ProtocolState;
@ -207,8 +206,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.setting.SkinPart;
import org.geysermc.mcprotocollib.protocol.data.game.statistic.CustomStatistic;
import org.geysermc.mcprotocollib.protocol.data.game.statistic.Statistic;
import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundClientInformationPacket;
import org.geysermc.mcprotocollib.protocol.packet.configuration.clientbound.ClientboundFinishConfigurationPacket;
import org.geysermc.mcprotocollib.protocol.packet.configuration.serverbound.ServerboundFinishConfigurationPacket;
import org.geysermc.mcprotocollib.protocol.packet.handshake.serverbound.ClientIntentionPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundChatCommandSignedPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundChatPacket;
@ -1275,7 +1272,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
Vector3d position = collisionManager.adjustBedrockPosition(playerEntity.getPosition(), playerEntity.isOnGround(), false);
// A null return value cancels the packet
if (position != null) {
ServerboundMovePlayerPosPacket packet = new ServerboundMovePlayerPosPacket(playerEntity.isOnGround(),
ServerboundMovePlayerPosPacket packet = new ServerboundMovePlayerPosPacket(playerEntity.isOnGround(), false, //FIXME
position.getX(), position.getY(), position.getZ());
sendDownstreamGamePacket(packet);
}

View file

@ -729,10 +729,10 @@ public abstract class InventoryTranslator {
if (ingRemaining == 0) {
while (++ingredientIndex < ingredients.length) {
if (ingredients[ingredientIndex].getOptions().length != 0) {
ingRemaining = timesCrafted;
break;
}
// if (ingredients[ingredientIndex].getOptions().length != 0) {
// ingRemaining = timesCrafted;
// break;
// }
}
}

View file

@ -1,82 +0,0 @@
/*
* 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.protocol.java;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundRecipePacket;
import org.cloudburstmc.protocol.bedrock.packet.UnlockedRecipesPacket;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import java.util.ArrayList;
import java.util.List;
@Translator(packet = ClientboundRecipePacket.class)
public class JavaClientboundRecipesTranslator extends PacketTranslator<ClientboundRecipePacket> {
@Override
public void translate(GeyserSession session, ClientboundRecipePacket packet) {
UnlockedRecipesPacket recipesPacket = new UnlockedRecipesPacket();
switch (packet.getAction()) {
case INIT -> {
recipesPacket.setAction(UnlockedRecipesPacket.ActionType.INITIALLY_UNLOCKED);
recipesPacket.getUnlockedRecipes().addAll(getBedrockRecipes(session, packet.getAlreadyKnownRecipes()));
}
case ADD -> {
List<String> recipes = getBedrockRecipes(session, packet.getRecipes());
if (recipes.isEmpty()) {
// Sending an empty list here packet will crash the client as of 1.20.60
return;
}
recipesPacket.setAction(UnlockedRecipesPacket.ActionType.NEWLY_UNLOCKED);
recipesPacket.getUnlockedRecipes().addAll(recipes);
}
case REMOVE -> {
List<String> recipes = getBedrockRecipes(session, packet.getRecipes());
if (recipes.isEmpty()) {
// Sending an empty list here will crash the client as of 1.20.60
return;
}
recipesPacket.setAction(UnlockedRecipesPacket.ActionType.REMOVE_UNLOCKED);
recipesPacket.getUnlockedRecipes().addAll(recipes);
}
}
session.sendUpstreamPacket(recipesPacket);
}
private List<String> getBedrockRecipes(GeyserSession session, String[] javaRecipeIdentifiers) {
List<String> recipes = new ArrayList<>();
for (String javaIdentifier : javaRecipeIdentifiers) {
List<String> bedrockRecipes = session.getJavaToBedrockRecipeIds().get(javaIdentifier);
// Some recipes are not (un)lockable on Bedrock edition, like furnace or stonecutter recipes.
// So we don't store/send these.
if (bedrockRecipes != null) {
recipes.addAll(bedrockRecipes);
}
}
return recipes;
}
}

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.translator.protocol.java;
import org.geysermc.mcprotocollib.auth.GameProfile;
import net.kyori.adventure.key.Key;
import org.geysermc.geyser.api.network.AuthType;
import org.geysermc.geyser.entity.type.player.PlayerEntity;
@ -34,17 +33,18 @@ import org.geysermc.geyser.skin.SkinManager;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.PluginMessageUtils;
import org.geysermc.mcprotocollib.auth.GameProfile;
import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket;
import org.geysermc.mcprotocollib.protocol.packet.login.clientbound.ClientboundGameProfilePacket;
import org.geysermc.mcprotocollib.protocol.packet.login.clientbound.ClientboundLoginFinishedPacket;
/**
* ClientboundGameProfilePacket triggers protocol change LOGIN -> CONFIGURATION
* Triggers protocol change LOGIN -> CONFIGURATION
*/
@Translator(packet = ClientboundGameProfilePacket.class)
public class JavaGameProfileTranslator extends PacketTranslator<ClientboundGameProfilePacket> {
@Translator(packet = ClientboundLoginFinishedPacket.class)
public class JavaLoginFinishedTranslator extends PacketTranslator<ClientboundLoginFinishedPacket> {
@Override
public void translate(GeyserSession session, ClientboundGameProfilePacket packet) {
public void translate(GeyserSession session, ClientboundLoginFinishedPacket packet) {
PlayerEntity playerEntity = session.getPlayerEntity();
AuthType remoteAuthType = session.remoteServer().authType();

View file

@ -0,0 +1,81 @@
/*
* 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.protocol.java;
import org.cloudburstmc.protocol.bedrock.packet.UnlockedRecipesPacket;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundRecipeBookAddPacket;
@Translator(packet = ClientboundRecipeBookAddPacket.class)
public class JavaRecipeBookAddTranslator extends PacketTranslator<ClientboundRecipeBookAddPacket> {
@Override
public void translate(GeyserSession session, ClientboundRecipeBookAddPacket packet) {
UnlockedRecipesPacket recipesPacket = new UnlockedRecipesPacket();
recipesPacket.setAction(packet.isReplace() ? UnlockedRecipesPacket.ActionType.INITIALLY_UNLOCKED : UnlockedRecipesPacket.ActionType.NEWLY_UNLOCKED);
// List<String> recipes = getBedrockRecipes(session, packet.getEntries());
// if (recipes.isEmpty() && !packet.isReplace()) {
// // Sending an empty list here packet will crash the client as of 1.20.60
// return;
// }
// switch (packet.getAction()) {
// case INIT -> {
// recipesPacket.setAction(UnlockedRecipesPacket.ActionType.INITIALLY_UNLOCKED);
// recipesPacket.getUnlockedRecipes().addAll(getBedrockRecipes(session, packet.getAlreadyKnownRecipes()));
// }
// case ADD -> {
//
// recipesPacket.setAction(UnlockedRecipesPacket.ActionType.NEWLY_UNLOCKED);
// recipesPacket.getUnlockedRecipes().addAll(recipes);
// }
// case REMOVE -> {
// List<String> recipes = getBedrockRecipes(session, packet.getRecipes());
// if (recipes.isEmpty()) {
// // Sending an empty list here will crash the client as of 1.20.60
// return;
// }
// recipesPacket.setAction(UnlockedRecipesPacket.ActionType.REMOVE_UNLOCKED);
// recipesPacket.getUnlockedRecipes().addAll(recipes);
// }
// }
// session.sendUpstreamPacket(recipesPacket);
}
// private List<String> getBedrockRecipes(GeyserSession session, List<ClientboundRecipeBookAddPacket.Entry> entry) {
// List<String> recipes = new ArrayList<>();
// for (String javaIdentifier : javaRecipeIdentifiers) {
// List<String> bedrockRecipes = session.getJavaToBedrockRecipeIds().get(javaIdentifier);
// // Some recipes are not (un)lockable on Bedrock edition, like furnace or stonecutter recipes.
// // So we don't store/send these.
// if (bedrockRecipes != null) {
// recipes.addAll(bedrockRecipes);
// }
// }
// return recipes;
// }
}

View file

@ -25,61 +25,18 @@
package org.geysermc.geyser.translator.protocol.java;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntIterator;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.RecipeUnlockingRequirement;
import net.kyori.adventure.key.Key;
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.SmithingTrimRecipeData;
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.ItemTagDescriptor;
import org.cloudburstmc.protocol.bedrock.packet.CraftingDataPacket;
import org.cloudburstmc.protocol.bedrock.packet.TrimDataPacket;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe;
import org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe;
import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData;
import org.geysermc.geyser.inventory.recipe.TrimRecipe;
import org.geysermc.geyser.item.type.BedrockRequiresTagItem;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.item.ItemTranslator;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.InventoryUtils;
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import org.geysermc.mcprotocollib.protocol.data.game.recipe.Ingredient;
import org.geysermc.mcprotocollib.protocol.data.game.recipe.Recipe;
import org.geysermc.mcprotocollib.protocol.data.game.recipe.RecipeType;
import org.geysermc.mcprotocollib.protocol.data.game.recipe.data.ShapedRecipeData;
import org.geysermc.mcprotocollib.protocol.data.game.recipe.data.ShapelessRecipeData;
import org.geysermc.mcprotocollib.protocol.data.game.recipe.data.SmithingTransformRecipeData;
import org.geysermc.mcprotocollib.protocol.data.game.recipe.data.StoneCuttingRecipeData;
import org.geysermc.geyser.util.MinecraftKey;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundUpdateRecipesPacket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import static org.geysermc.geyser.util.InventoryUtils.LAST_RECIPE_NET_ID;
@ -121,437 +78,443 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
"minecraft:wooden_slab", "minecraft:wooden_slabs",
"minecraft:planks", "minecraft:planks");
private static final Key SMITHING_BASE = MinecraftKey.key("smithing_base");
private static final Key SMITHING_TEMPLATE = MinecraftKey.key("smithing_template");
private static final Key SMITHING_ADDITION = MinecraftKey.key("smithing_addition");
@Override
public void translate(GeyserSession session, ClientboundUpdateRecipesPacket packet) {
boolean sendTrimRecipes = false;
Map<String, List<String>> recipeIDs = session.getJavaToBedrockRecipeIds();
recipeIDs.clear();
Int2ObjectMap<GeyserRecipe> recipeMap = new Int2ObjectOpenHashMap<>();
Int2ObjectMap<List<StoneCuttingRecipeData>> unsortedStonecutterData = new Int2ObjectOpenHashMap<>();
CraftingDataPacket craftingDataPacket = new CraftingDataPacket();
craftingDataPacket.setCleanRecipes(true);
RecipeContext context = new RecipeContext(session, craftingDataPacket, recipeMap);
for (Recipe recipe : packet.getRecipes()) {
switch (recipe.getType()) {
case CRAFTING_SHAPELESS -> {
ShapelessRecipeData shapelessRecipeData = (ShapelessRecipeData) recipe.getData();
List<String> bedrockRecipeIDs = context.translateShapelessRecipe(new GeyserShapelessRecipe(shapelessRecipeData));
if (bedrockRecipeIDs != null) {
context.addRecipeIdentifier(session, recipe.getIdentifier().asString(), bedrockRecipeIDs);
}
}
case CRAFTING_SHAPED -> {
ShapedRecipeData shapedRecipeData = (ShapedRecipeData) recipe.getData();
List<String> bedrockRecipeIDs = context.translateShapedRecipe(new GeyserShapedRecipe(shapedRecipeData));
if (bedrockRecipeIDs != null) {
context.addRecipeIdentifier(session, recipe.getIdentifier().asString(), bedrockRecipeIDs);
}
}
case STONECUTTING -> {
StoneCuttingRecipeData stoneCuttingData = (StoneCuttingRecipeData) recipe.getData();
if (stoneCuttingData.getIngredient().getOptions().length == 0) {
if (GeyserImpl.getInstance().getConfig().isDebugMode()) {
GeyserImpl.getInstance().getLogger().debug("Received broken stone cutter recipe: " + stoneCuttingData + " " +
recipe.getIdentifier() + " " + Registries.JAVA_ITEMS.get().get(stoneCuttingData.getResult().getId()).javaIdentifier());
}
continue;
}
ItemStack ingredient = stoneCuttingData.getIngredient().getOptions()[0];
List<StoneCuttingRecipeData> data = unsortedStonecutterData.get(ingredient.getId());
if (data == null) {
data = new ArrayList<>();
unsortedStonecutterData.put(ingredient.getId(), data);
}
// Save for processing after all recipes have been received
data.add(stoneCuttingData);
}
case SMITHING_TRANSFORM -> {
SmithingTransformRecipeData data = (SmithingTransformRecipeData) recipe.getData();
ItemData output = ItemTranslator.translateToBedrock(session, data.getResult());
for (ItemStack template : data.getTemplate().getOptions()) {
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));
String id = recipe.getIdentifier().asString();
// Note: vanilla inputs use aux value of Short.MAX_VALUE
craftingDataPacket.getCraftingData().add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.SmithingTransformRecipeData.of(id,
bedrockTemplate, bedrockBase, bedrockAddition, output, "smithing_table", context.getAndIncrementNetId()));
recipeIDs.put(id, new ArrayList<>(Collections.singletonList(id)));
}
}
}
}
case SMITHING_TRIM -> {
sendTrimRecipes = true;
// ignored currently - see below
}
case CRAFTING_DECORATED_POT -> {
// Paper 1.20 seems to send only one recipe, which seems to be hardcoded to include all recipes.
// We can send the equivalent Bedrock MultiRecipe! :)
craftingDataPacket.getCraftingData().add(MultiRecipeData.of(UUID.fromString("685a742a-c42e-4a4e-88ea-5eb83fc98e5b"), context.getAndIncrementNetId()));
}
case CRAFTING_SPECIAL_BOOKCLONING -> {
craftingDataPacket.getCraftingData().add(MultiRecipeData.of(UUID.fromString("d1ca6b84-338e-4f2f-9c6b-76cc8b4bd98d"), context.getAndIncrementNetId()));
}
case CRAFTING_SPECIAL_REPAIRITEM -> {
craftingDataPacket.getCraftingData().add(MultiRecipeData.of(UUID.fromString("00000000-0000-0000-0000-000000000001"), context.getAndIncrementNetId()));
}
case CRAFTING_SPECIAL_MAPEXTENDING -> {
craftingDataPacket.getCraftingData().add(MultiRecipeData.of(UUID.fromString("d392b075-4ba1-40ae-8789-af868d56f6ce"), context.getAndIncrementNetId()));
}
case CRAFTING_SPECIAL_MAPCLONING -> {
craftingDataPacket.getCraftingData().add(MultiRecipeData.of(UUID.fromString("85939755-ba10-4d9d-a4cc-efb7a8e943c4"), context.getAndIncrementNetId()));
}
case CRAFTING_SPECIAL_FIREWORK_ROCKET -> {
craftingDataPacket.getCraftingData().add(MultiRecipeData.of(UUID.fromString("00000000-0000-0000-0000-000000000002"), context.getAndIncrementNetId()));
}
default -> {
List<GeyserRecipe> recipes = Registries.RECIPES.get(recipe.getType());
if (recipes != null) {
List<String> bedrockRecipeIds = new ArrayList<>();
if (recipe.getType() == RecipeType.CRAFTING_SPECIAL_TIPPEDARROW) {
// Only shaped recipe at this moment
for (GeyserRecipe builtInRecipe : recipes) {
var recipeIds = context.translateShapedRecipe((GeyserShapedRecipe) builtInRecipe);
if (recipeIds != null) {
bedrockRecipeIds.addAll(recipeIds);
}
}
} else if (recipe.getType() == RecipeType.CRAFTING_SPECIAL_SHULKERBOXCOLORING) {
for (GeyserRecipe builtInRecipe : recipes) {
var recipeIds = context.translateShulkerBoxRecipe((GeyserShapelessRecipe) builtInRecipe);
if (recipeIds != null) {
bedrockRecipeIds.addAll(recipeIds);
}
}
} else {
for (GeyserRecipe builtInRecipe : recipes) {
var recipeIds = context.translateShapelessRecipe((GeyserShapelessRecipe) builtInRecipe);
if (recipeIds != null) {
bedrockRecipeIds.addAll(recipeIds);
}
}
}
context.addSpecialRecipesIdentifiers(recipe, bedrockRecipeIds);
}
}
}
}
craftingDataPacket.getCraftingData().addAll(CARTOGRAPHY_RECIPES);
craftingDataPacket.getPotionMixData().addAll(Registries.POTION_MIXES.forVersion(session.getUpstream().getProtocolVersion()));
Int2ObjectMap<GeyserStonecutterData> stonecutterRecipeMap = new Int2ObjectOpenHashMap<>();
for (Int2ObjectMap.Entry<List<StoneCuttingRecipeData>> data : unsortedStonecutterData.int2ObjectEntrySet()) {
// Sort the list by each output item's Java identifier - this is how it's sorted on Java, and therefore
// We can get the correct order for button pressing
data.getValue().sort(Comparator.comparing((stoneCuttingRecipeData ->
Registries.JAVA_ITEMS.get().get(stoneCuttingRecipeData.getResult().getId())
// See RecipeManager#getRecipesFor as of 1.21
.translationKey())));
// Now that it's sorted, let's translate these recipes
int buttonId = 0;
for (StoneCuttingRecipeData stoneCuttingData : data.getValue()) {
// As of 1.16.4, all stonecutter recipes have one ingredient option
ItemStack ingredient = stoneCuttingData.getIngredient().getOptions()[0];
ItemData input = ItemTranslator.translateToBedrock(session, ingredient);
ItemDescriptorWithCount descriptor = ItemDescriptorWithCount.fromItem(input);
ItemStack javaOutput = stoneCuttingData.getResult();
ItemData output = ItemTranslator.translateToBedrock(session, javaOutput);
if (!input.isValid() || !output.isValid()) {
// Probably modded items
continue;
}
UUID uuid = UUID.randomUUID();
// We need to register stonecutting recipes, so they show up on Bedrock
craftingDataPacket.getCraftingData().add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapelessRecipeData.shapeless(uuid.toString(),
Collections.singletonList(descriptor), Collections.singletonList(output), uuid, "stonecutter", 0, context.netId, RecipeUnlockingRequirement.INVALID));
// Save the recipe list for reference when crafting
// Add the net ID as the key and the button required + output for the value
stonecutterRecipeMap.put(context.getAndIncrementNetId(), new GeyserStonecutterData(buttonId++, javaOutput));
// Currently, stone cutter recipes are not locked/unlocked on Bedrock; so no need to cache their identifiers.
}
}
session.getLastRecipeNetId().set(context.netId); // No increment
// Only send smithing trim recipes if Java/ViaVersion sends them.
if (sendTrimRecipes) {
// BDS sends armor trim templates and materials before the CraftingDataPacket
TrimDataPacket trimDataPacket = new TrimDataPacket();
trimDataPacket.getPatterns().addAll(session.getRegistryCache().trimPatterns().values());
trimDataPacket.getMaterials().addAll(session.getRegistryCache().trimMaterials().values());
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", session.getLastRecipeNetId().getAndIncrement()));
} else {
// manually add recipes for the upgrade template (workaround), since Java pre-1.20 doesn't
craftingDataPacket.getCraftingData().addAll(getSmithingTransformRecipes(session));
}
session.setOldSmithingTable(!sendTrimRecipes);
session.sendUpstreamPacket(craftingDataPacket);
session.setCraftingRecipes(recipeMap);
session.setStonecutterRecipes(stonecutterRecipeMap);
}
//TODO: rewrite
/**
* The Java server sends an array of items for each ingredient you can use per slot in the crafting grid.
* Bedrock recipes take only one ingredient per crafting grid slot.
*
* @return the Java ingredient list as an array that Bedrock can understand
*/
private static ItemDescriptorWithCount[][] combinations(GeyserSession session, Ingredient[] ingredients) {
boolean empty = true;
Map<Set<ItemDescriptorWithCount>, IntSet> squashedOptions = new HashMap<>();
for (int i = 0; i < ingredients.length; i++) {
if (ingredients[i].getOptions().length == 0) {
squashedOptions.computeIfAbsent(Collections.singleton(ItemDescriptorWithCount.EMPTY), k -> new IntOpenHashSet()).add(i);
continue;
}
empty = false;
Ingredient ingredient = ingredients[i];
Map<GroupedItem, List<ItemDescriptorWithCount>> groupedByIds = Arrays.stream(ingredient.getOptions())
.map(item -> ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, item)))
.collect(Collectors.groupingBy(item -> item == ItemDescriptorWithCount.EMPTY ? new GroupedItem(ItemDefinition.AIR, 0) : new GroupedItem(((DefaultDescriptor) item.getDescriptor()).getItemId(), item.getCount())));
Set<ItemDescriptorWithCount> optionSet = new HashSet<>(groupedByIds.size());
for (Map.Entry<GroupedItem, List<ItemDescriptorWithCount>> entry : groupedByIds.entrySet()) {
if (entry.getValue().size() > 1) {
GroupedItem groupedItem = entry.getKey();
String recipeTag = RECIPE_TAGS.get(groupedItem.id.getIdentifier());
if (recipeTag != null && ingredients.length > 1) {
optionSet.add(new ItemDescriptorWithCount(new ItemTagDescriptor(recipeTag), groupedItem.count));
continue;
}
int idCount = 0;
//not optimal
for (ItemMapping mapping : session.getItemMappings().getItems()) {
if (mapping.getBedrockDefinition() == groupedItem.id) {
idCount++;
}
}
if (entry.getValue().size() < idCount) {
optionSet.addAll(entry.getValue());
} else {
optionSet.add(groupedItem.id == ItemDefinition.AIR ? ItemDescriptorWithCount.EMPTY : new ItemDescriptorWithCount(new DefaultDescriptor(groupedItem.id, Short.MAX_VALUE), groupedItem.count));
}
} else {
ItemDescriptorWithCount item = entry.getValue().get(0);
optionSet.add(item);
}
}
squashedOptions.computeIfAbsent(optionSet, k -> new IntOpenHashSet()).add(i);
}
if (empty) {
// Crashes Bedrock 1.19.70 otherwise
// Fixes https://github.com/GeyserMC/Geyser/issues/3549
return null;
}
int totalCombinations = 1;
for (Set<ItemDescriptorWithCount> optionSet : squashedOptions.keySet()) {
totalCombinations *= optionSet.size();
}
if (totalCombinations > 500) {
ItemDescriptorWithCount[] translatedItems = new ItemDescriptorWithCount[ingredients.length];
for (int i = 0; i < ingredients.length; i++) {
if (ingredients[i].getOptions().length > 0) {
translatedItems[i] = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, ingredients[i].getOptions()[0]));
} else {
translatedItems[i] = ItemDescriptorWithCount.EMPTY;
}
}
return new ItemDescriptorWithCount[][]{translatedItems};
}
List<Set<ItemDescriptorWithCount>> sortedSets = new ArrayList<>(squashedOptions.keySet());
sortedSets.sort(Comparator.comparing(Set::size, Comparator.reverseOrder()));
ItemDescriptorWithCount[][] combinations = new ItemDescriptorWithCount[totalCombinations][ingredients.length];
int x = 1;
for (Set<ItemDescriptorWithCount> set : sortedSets) {
IntSet slotSet = squashedOptions.get(set);
int i = 0;
for (ItemDescriptorWithCount item : set) {
for (int j = 0; j < totalCombinations / set.size(); j++) {
final int comboIndex = (i * x) + (j % x) + ((j / x) * set.size() * x);
for (IntIterator it = slotSet.iterator(); it.hasNext(); ) {
combinations[comboIndex][it.nextInt()] = item;
}
}
i++;
}
x *= set.size();
}
return combinations;
}
private List<RecipeData> getSmithingTransformRecipes(GeyserSession session) {
List<RecipeData> recipes = new ArrayList<>();
ItemMapping template = session.getItemMappings().getStoredItems().upgradeTemplate();
for (String identifier : NETHERITE_UPGRADES) {
recipes.add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.SmithingTransformRecipeData.of(identifier + "_smithing",
getDescriptorFromId(session, template.getBedrockIdentifier()),
getDescriptorFromId(session, identifier.replace("netherite", "diamond")),
getDescriptorFromId(session, "minecraft:netherite_ingot"),
ItemData.builder().definition(Objects.requireNonNull(session.getItemMappings().getDefinition(identifier))).count(1).build(),
"smithing_table",
session.getLastRecipeNetId().getAndIncrement()));
}
return recipes;
}
private ItemDescriptorWithCount getDescriptorFromId(GeyserSession session, String bedrockId) {
ItemDefinition bedrockDefinition = session.getItemMappings().getDefinition(bedrockId);
if (bedrockDefinition != null) {
return ItemDescriptorWithCount.fromItem(ItemData.builder().definition(bedrockDefinition).count(1).build());
}
GeyserImpl.getInstance().getLogger().debug("Unable to find item with identifier " + bedrockId);
return ItemDescriptorWithCount.EMPTY;
}
@EqualsAndHashCode
@AllArgsConstructor
private static class GroupedItem {
ItemDefinition id;
int count;
}
private static final class RecipeContext {
private final GeyserSession session;
private final CraftingDataPacket packet;
private final Int2ObjectMap<GeyserRecipe> recipeMap;
// Get the last known network ID (first used for some pregenerated recipes) and increment from there.
private int netId = InventoryUtils.LAST_RECIPE_NET_ID + 1;
private RecipeContext(GeyserSession session, CraftingDataPacket packet, Int2ObjectMap<GeyserRecipe> recipeMap) {
this.session = session;
this.packet = packet;
this.recipeMap = recipeMap;
}
List<String> translateShulkerBoxRecipe(GeyserShapelessRecipe recipe) {
ItemStack result = recipe.result();
ItemData output = ItemTranslator.translateToBedrock(session, result);
if (!output.isValid()) {
// Likely modded item that Bedrock will complain about if it persists
return null;
}
Item javaItem = Registries.JAVA_ITEMS.get(result.getId());
if (!(javaItem instanceof BedrockRequiresTagItem)) {
// Strip NBT - tools won't appear in the recipe book otherwise
output = output.toBuilder().tag(null).build();
}
ItemDescriptorWithCount[][] inputCombinations = combinations(session, recipe.ingredients());
if (inputCombinations == null) {
return null;
}
List<String> bedrockRecipeIDs = new ArrayList<>();
for (ItemDescriptorWithCount[] inputs : inputCombinations) {
UUID uuid = UUID.randomUUID();
bedrockRecipeIDs.add(uuid.toString());
packet.getCraftingData().add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapelessRecipeData.shulkerBox(uuid.toString(),
Arrays.asList(inputs), Collections.singletonList(output), uuid, "crafting_table", 0, netId));
recipeMap.put(netId++, recipe);
}
return bedrockRecipeIDs;
}
List<String> translateShapelessRecipe(GeyserShapelessRecipe recipe) {
ItemStack result = recipe.result();
ItemData output = ItemTranslator.translateToBedrock(session, result);
if (!output.isValid()) {
// Likely modded item that Bedrock will complain about if it persists
return null;
}
Item javaItem = Registries.JAVA_ITEMS.get(result.getId());
if (!(javaItem instanceof BedrockRequiresTagItem)) {
// Strip NBT - tools won't appear in the recipe book otherwise
output = output.toBuilder().tag(null).build();
}
ItemDescriptorWithCount[][] inputCombinations = combinations(session, recipe.ingredients());
if (inputCombinations == null) {
return null;
}
List<String> bedrockRecipeIDs = new ArrayList<>();
for (ItemDescriptorWithCount[] inputs : inputCombinations) {
UUID uuid = UUID.randomUUID();
bedrockRecipeIDs.add(uuid.toString());
packet.getCraftingData().add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapelessRecipeData.shapeless(uuid.toString(),
Arrays.asList(inputs), Collections.singletonList(output), uuid, "crafting_table", 0, netId, RecipeUnlockingRequirement.INVALID));
recipeMap.put(netId++, recipe);
}
return bedrockRecipeIDs;
}
List<String> translateShapedRecipe(GeyserShapedRecipe recipe) {
ItemStack result = recipe.result();
ItemData output = ItemTranslator.translateToBedrock(session, result);
if (!output.isValid()) {
// Likely modded item that Bedrock will complain about if it persists
return null;
}
Item javaItem = Registries.JAVA_ITEMS.get(result.getId());
if (!(javaItem instanceof BedrockRequiresTagItem)) {
// Strip NBT - tools won't appear in the recipe book otherwise
output = output.toBuilder().tag(null).build();
}
ItemDescriptorWithCount[][] inputCombinations = combinations(session, recipe.ingredients());
if (inputCombinations == null) {
return null;
}
List<String> bedrockRecipeIDs = new ArrayList<>();
for (ItemDescriptorWithCount[] inputs : inputCombinations) {
UUID uuid = UUID.randomUUID();
bedrockRecipeIDs.add(uuid.toString());
packet.getCraftingData().add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapedRecipeData.shaped(uuid.toString(),
recipe.width(), recipe.height(), Arrays.asList(inputs),
Collections.singletonList(output), uuid, "crafting_table", 0, netId, false, RecipeUnlockingRequirement.INVALID));
recipeMap.put(netId++, recipe);
}
return bedrockRecipeIDs;
}
void addSpecialRecipesIdentifiers(Recipe recipe, List<String> identifiers) {
String javaRecipeID = switch (recipe.getType()) {
case CRAFTING_SPECIAL_SHULKERBOXCOLORING ->
// BDS (un)locks the dyeing with the shulker box recipe, Java never - we want BDS behavior for ease of use
"minecraft:shulker_box";
case CRAFTING_SPECIAL_TIPPEDARROW ->
// similar as above
"minecraft:arrow";
default -> recipe.getIdentifier().asString();
};
addRecipeIdentifier(session, javaRecipeID, identifiers);
}
void addRecipeIdentifier(GeyserSession session, String javaIdentifier, List<String> bedrockIdentifiers) {
session.getJavaToBedrockRecipeIds().computeIfAbsent(javaIdentifier, k -> new ArrayList<>()).addAll(bedrockIdentifiers);
}
int getAndIncrementNetId() {
return this.netId++;
}
// :(
}
// boolean sendTrimRecipes = false;
// Map<String, List<String>> recipeIDs = session.getJavaToBedrockRecipeIds();
// recipeIDs.clear();
// Int2ObjectMap<GeyserRecipe> recipeMap = new Int2ObjectOpenHashMap<>();
// Int2ObjectMap<List<StoneCuttingRecipeData>> unsortedStonecutterData = new Int2ObjectOpenHashMap<>();
// CraftingDataPacket craftingDataPacket = new CraftingDataPacket();
// craftingDataPacket.setCleanRecipes(true);
//
// RecipeContext context = new RecipeContext(session, craftingDataPacket, recipeMap);
//
// for (Recipe recipe : packet.getRecipes()) {
// switch (recipe.getType()) {
// case CRAFTING_SHAPELESS -> {
// ShapelessRecipeData shapelessRecipeData = (ShapelessRecipeData) recipe.getData();
// List<String> bedrockRecipeIDs = context.translateShapelessRecipe(new GeyserShapelessRecipe(shapelessRecipeData));
// if (bedrockRecipeIDs != null) {
// context.addRecipeIdentifier(session, recipe.getIdentifier().asString(), bedrockRecipeIDs);
// }
// }
// case CRAFTING_SHAPED -> {
// ShapedRecipeData shapedRecipeData = (ShapedRecipeData) recipe.getData();
// List<String> bedrockRecipeIDs = context.translateShapedRecipe(new GeyserShapedRecipe(shapedRecipeData));
// if (bedrockRecipeIDs != null) {
// context.addRecipeIdentifier(session, recipe.getIdentifier().asString(), bedrockRecipeIDs);
// }
// }
// case STONECUTTING -> {
// StoneCuttingRecipeData stoneCuttingData = (StoneCuttingRecipeData) recipe.getData();
// if (stoneCuttingData.getIngredient().getOptions().length == 0) {
// if (GeyserImpl.getInstance().getConfig().isDebugMode()) {
// GeyserImpl.getInstance().getLogger().debug("Received broken stone cutter recipe: " + stoneCuttingData + " " +
// recipe.getIdentifier() + " " + Registries.JAVA_ITEMS.get().get(stoneCuttingData.getResult().getId()).javaIdentifier());
// }
// continue;
// }
// ItemStack ingredient = stoneCuttingData.getIngredient().getOptions()[0];
// List<StoneCuttingRecipeData> data = unsortedStonecutterData.get(ingredient.getId());
// if (data == null) {
// data = new ArrayList<>();
// unsortedStonecutterData.put(ingredient.getId(), data);
// }
// // Save for processing after all recipes have been received
// data.add(stoneCuttingData);
// }
// case SMITHING_TRANSFORM -> {
// SmithingTransformRecipeData data = (SmithingTransformRecipeData) recipe.getData();
// ItemData output = ItemTranslator.translateToBedrock(session, data.getResult());
//
// for (ItemStack template : data.getTemplate().getOptions()) {
// 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));
//
// String id = recipe.getIdentifier().asString();
// // Note: vanilla inputs use aux value of Short.MAX_VALUE
// craftingDataPacket.getCraftingData().add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.SmithingTransformRecipeData.of(id,
// bedrockTemplate, bedrockBase, bedrockAddition, output, "smithing_table", context.getAndIncrementNetId()));
//
// recipeIDs.put(id, new ArrayList<>(Collections.singletonList(id)));
// }
// }
// }
// }
// case SMITHING_TRIM -> {
// sendTrimRecipes = true;
// // ignored currently - see below
// }
// case CRAFTING_DECORATED_POT -> {
// // Paper 1.20 seems to send only one recipe, which seems to be hardcoded to include all recipes.
// // We can send the equivalent Bedrock MultiRecipe! :)
// craftingDataPacket.getCraftingData().add(MultiRecipeData.of(UUID.fromString("685a742a-c42e-4a4e-88ea-5eb83fc98e5b"), context.getAndIncrementNetId()));
// }
// case CRAFTING_SPECIAL_BOOKCLONING -> {
// craftingDataPacket.getCraftingData().add(MultiRecipeData.of(UUID.fromString("d1ca6b84-338e-4f2f-9c6b-76cc8b4bd98d"), context.getAndIncrementNetId()));
// }
// case CRAFTING_SPECIAL_REPAIRITEM -> {
// craftingDataPacket.getCraftingData().add(MultiRecipeData.of(UUID.fromString("00000000-0000-0000-0000-000000000001"), context.getAndIncrementNetId()));
// }
// case CRAFTING_SPECIAL_MAPEXTENDING -> {
// craftingDataPacket.getCraftingData().add(MultiRecipeData.of(UUID.fromString("d392b075-4ba1-40ae-8789-af868d56f6ce"), context.getAndIncrementNetId()));
// }
// case CRAFTING_SPECIAL_MAPCLONING -> {
// craftingDataPacket.getCraftingData().add(MultiRecipeData.of(UUID.fromString("85939755-ba10-4d9d-a4cc-efb7a8e943c4"), context.getAndIncrementNetId()));
// }
// case CRAFTING_SPECIAL_FIREWORK_ROCKET -> {
// craftingDataPacket.getCraftingData().add(MultiRecipeData.of(UUID.fromString("00000000-0000-0000-0000-000000000002"), context.getAndIncrementNetId()));
// }
// default -> {
// List<GeyserRecipe> recipes = Registries.RECIPES.get(recipe.getType());
// if (recipes != null) {
// List<String> bedrockRecipeIds = new ArrayList<>();
// if (recipe.getType() == RecipeType.CRAFTING_SPECIAL_TIPPEDARROW) {
// // Only shaped recipe at this moment
// for (GeyserRecipe builtInRecipe : recipes) {
// var recipeIds = context.translateShapedRecipe((GeyserShapedRecipe) builtInRecipe);
// if (recipeIds != null) {
// bedrockRecipeIds.addAll(recipeIds);
// }
// }
// } else if (recipe.getType() == RecipeType.CRAFTING_SPECIAL_SHULKERBOXCOLORING) {
// for (GeyserRecipe builtInRecipe : recipes) {
// var recipeIds = context.translateShulkerBoxRecipe((GeyserShapelessRecipe) builtInRecipe);
// if (recipeIds != null) {
// bedrockRecipeIds.addAll(recipeIds);
// }
// }
// } else {
// for (GeyserRecipe builtInRecipe : recipes) {
// var recipeIds = context.translateShapelessRecipe((GeyserShapelessRecipe) builtInRecipe);
// if (recipeIds != null) {
// bedrockRecipeIds.addAll(recipeIds);
// }
// }
// }
// context.addSpecialRecipesIdentifiers(recipe, bedrockRecipeIds);
// }
// }
// }
// }
// craftingDataPacket.getCraftingData().addAll(CARTOGRAPHY_RECIPES);
// craftingDataPacket.getPotionMixData().addAll(Registries.POTION_MIXES.forVersion(session.getUpstream().getProtocolVersion()));
//
// Int2ObjectMap<GeyserStonecutterData> stonecutterRecipeMap = new Int2ObjectOpenHashMap<>();
// for (Int2ObjectMap.Entry<List<StoneCuttingRecipeData>> data : unsortedStonecutterData.int2ObjectEntrySet()) {
// // Sort the list by each output item's Java identifier - this is how it's sorted on Java, and therefore
// // We can get the correct order for button pressing
// data.getValue().sort(Comparator.comparing((stoneCuttingRecipeData ->
// Registries.JAVA_ITEMS.get().get(stoneCuttingRecipeData.getResult().getId())
// // See RecipeManager#getRecipesFor as of 1.21
// .translationKey())));
//
// // Now that it's sorted, let's translate these recipes
// int buttonId = 0;
// for (StoneCuttingRecipeData stoneCuttingData : data.getValue()) {
// // As of 1.16.4, all stonecutter recipes have one ingredient option
// ItemStack ingredient = stoneCuttingData.getIngredient().getOptions()[0];
// ItemData input = ItemTranslator.translateToBedrock(session, ingredient);
// ItemDescriptorWithCount descriptor = ItemDescriptorWithCount.fromItem(input);
// ItemStack javaOutput = stoneCuttingData.getResult();
// ItemData output = ItemTranslator.translateToBedrock(session, javaOutput);
// if (!input.isValid() || !output.isValid()) {
// // Probably modded items
// continue;
// }
// UUID uuid = UUID.randomUUID();
// // We need to register stonecutting recipes, so they show up on Bedrock
// craftingDataPacket.getCraftingData().add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapelessRecipeData.shapeless(uuid.toString(),
// Collections.singletonList(descriptor), Collections.singletonList(output), uuid, "stonecutter", 0, context.netId, RecipeUnlockingRequirement.INVALID));
//
// // Save the recipe list for reference when crafting
// // Add the net ID as the key and the button required + output for the value
// stonecutterRecipeMap.put(context.getAndIncrementNetId(), new GeyserStonecutterData(buttonId++, javaOutput));
//
// // Currently, stone cutter recipes are not locked/unlocked on Bedrock; so no need to cache their identifiers.
// }
// }
//
// session.getLastRecipeNetId().set(context.netId); // No increment
//
// // Only send smithing trim recipes if Java/ViaVersion sends them.
// if (sendTrimRecipes) {
// // BDS sends armor trim templates and materials before the CraftingDataPacket
// TrimDataPacket trimDataPacket = new TrimDataPacket();
// trimDataPacket.getPatterns().addAll(session.getRegistryCache().trimPatterns().values());
// trimDataPacket.getMaterials().addAll(session.getRegistryCache().trimMaterials().values());
// 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", session.getLastRecipeNetId().getAndIncrement()));
// } else {
// // manually add recipes for the upgrade template (workaround), since Java pre-1.20 doesn't
// craftingDataPacket.getCraftingData().addAll(getSmithingTransformRecipes(session));
// }
// session.setOldSmithingTable(!sendTrimRecipes);
// session.sendUpstreamPacket(craftingDataPacket);
// session.setCraftingRecipes(recipeMap);
// session.setStonecutterRecipes(stonecutterRecipeMap);
// }
//
// //TODO: rewrite
// /**
// * The Java server sends an array of items for each ingredient you can use per slot in the crafting grid.
// * Bedrock recipes take only one ingredient per crafting grid slot.
// *
// * @return the Java ingredient list as an array that Bedrock can understand
// */
// private static ItemDescriptorWithCount[][] combinations(GeyserSession session, Ingredient[] ingredients) {
// boolean empty = true;
// Map<Set<ItemDescriptorWithCount>, IntSet> squashedOptions = new HashMap<>();
// for (int i = 0; i < ingredients.length; i++) {
// if (ingredients[i].getOptions().length == 0) {
// squashedOptions.computeIfAbsent(Collections.singleton(ItemDescriptorWithCount.EMPTY), k -> new IntOpenHashSet()).add(i);
// continue;
// }
// empty = false;
// Ingredient ingredient = ingredients[i];
// Map<GroupedItem, List<ItemDescriptorWithCount>> groupedByIds = Arrays.stream(ingredient.getOptions())
// .map(item -> ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, item)))
// .collect(Collectors.groupingBy(item -> item == ItemDescriptorWithCount.EMPTY ? new GroupedItem(ItemDefinition.AIR, 0) : new GroupedItem(((DefaultDescriptor) item.getDescriptor()).getItemId(), item.getCount())));
// Set<ItemDescriptorWithCount> optionSet = new HashSet<>(groupedByIds.size());
// for (Map.Entry<GroupedItem, List<ItemDescriptorWithCount>> entry : groupedByIds.entrySet()) {
// if (entry.getValue().size() > 1) {
// GroupedItem groupedItem = entry.getKey();
//
// String recipeTag = RECIPE_TAGS.get(groupedItem.id.getIdentifier());
// if (recipeTag != null && ingredients.length > 1) {
// optionSet.add(new ItemDescriptorWithCount(new ItemTagDescriptor(recipeTag), groupedItem.count));
// continue;
// }
//
// int idCount = 0;
// //not optimal
// for (ItemMapping mapping : session.getItemMappings().getItems()) {
// if (mapping.getBedrockDefinition() == groupedItem.id) {
// idCount++;
// }
// }
// if (entry.getValue().size() < idCount) {
// optionSet.addAll(entry.getValue());
// } else {
// optionSet.add(groupedItem.id == ItemDefinition.AIR ? ItemDescriptorWithCount.EMPTY : new ItemDescriptorWithCount(new DefaultDescriptor(groupedItem.id, Short.MAX_VALUE), groupedItem.count));
// }
// } else {
// ItemDescriptorWithCount item = entry.getValue().get(0);
// optionSet.add(item);
// }
// }
// squashedOptions.computeIfAbsent(optionSet, k -> new IntOpenHashSet()).add(i);
// }
// if (empty) {
// // Crashes Bedrock 1.19.70 otherwise
// // Fixes https://github.com/GeyserMC/Geyser/issues/3549
// return null;
// }
// int totalCombinations = 1;
// for (Set<ItemDescriptorWithCount> optionSet : squashedOptions.keySet()) {
// totalCombinations *= optionSet.size();
// }
// if (totalCombinations > 500) {
// ItemDescriptorWithCount[] translatedItems = new ItemDescriptorWithCount[ingredients.length];
// for (int i = 0; i < ingredients.length; i++) {
// if (ingredients[i].getOptions().length > 0) {
// translatedItems[i] = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, ingredients[i].getOptions()[0]));
// } else {
// translatedItems[i] = ItemDescriptorWithCount.EMPTY;
// }
// }
// return new ItemDescriptorWithCount[][]{translatedItems};
// }
// List<Set<ItemDescriptorWithCount>> sortedSets = new ArrayList<>(squashedOptions.keySet());
// sortedSets.sort(Comparator.comparing(Set::size, Comparator.reverseOrder()));
// ItemDescriptorWithCount[][] combinations = new ItemDescriptorWithCount[totalCombinations][ingredients.length];
// int x = 1;
// for (Set<ItemDescriptorWithCount> set : sortedSets) {
// IntSet slotSet = squashedOptions.get(set);
// int i = 0;
// for (ItemDescriptorWithCount item : set) {
// for (int j = 0; j < totalCombinations / set.size(); j++) {
// final int comboIndex = (i * x) + (j % x) + ((j / x) * set.size() * x);
// for (IntIterator it = slotSet.iterator(); it.hasNext(); ) {
// combinations[comboIndex][it.nextInt()] = item;
// }
// }
// i++;
// }
// x *= set.size();
// }
// return combinations;
// }
//
// private List<RecipeData> getSmithingTransformRecipes(GeyserSession session) {
// List<RecipeData> recipes = new ArrayList<>();
// ItemMapping template = session.getItemMappings().getStoredItems().upgradeTemplate();
//
// for (String identifier : NETHERITE_UPGRADES) {
// recipes.add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.SmithingTransformRecipeData.of(identifier + "_smithing",
// getDescriptorFromId(session, template.getBedrockIdentifier()),
// getDescriptorFromId(session, identifier.replace("netherite", "diamond")),
// getDescriptorFromId(session, "minecraft:netherite_ingot"),
// ItemData.builder().definition(Objects.requireNonNull(session.getItemMappings().getDefinition(identifier))).count(1).build(),
// "smithing_table",
// session.getLastRecipeNetId().getAndIncrement()));
// }
// return recipes;
// }
//
// private ItemDescriptorWithCount getDescriptorFromId(GeyserSession session, String bedrockId) {
// ItemDefinition bedrockDefinition = session.getItemMappings().getDefinition(bedrockId);
// if (bedrockDefinition != null) {
// return ItemDescriptorWithCount.fromItem(ItemData.builder().definition(bedrockDefinition).count(1).build());
// }
// GeyserImpl.getInstance().getLogger().debug("Unable to find item with identifier " + bedrockId);
// return ItemDescriptorWithCount.EMPTY;
// }
//
// @EqualsAndHashCode
// @AllArgsConstructor
// private static class GroupedItem {
// ItemDefinition id;
// int count;
// }
//
// private static final class RecipeContext {
// private final GeyserSession session;
// private final CraftingDataPacket packet;
// private final Int2ObjectMap<GeyserRecipe> recipeMap;
// // Get the last known network ID (first used for some pregenerated recipes) and increment from there.
// private int netId = InventoryUtils.LAST_RECIPE_NET_ID + 1;
//
// private RecipeContext(GeyserSession session, CraftingDataPacket packet, Int2ObjectMap<GeyserRecipe> recipeMap) {
// this.session = session;
// this.packet = packet;
// this.recipeMap = recipeMap;
// }
//
// List<String> translateShulkerBoxRecipe(GeyserShapelessRecipe recipe) {
// ItemStack result = recipe.result();
// ItemData output = ItemTranslator.translateToBedrock(session, result);
// if (!output.isValid()) {
// // Likely modded item that Bedrock will complain about if it persists
// return null;
// }
//
// Item javaItem = Registries.JAVA_ITEMS.get(result.getId());
// if (!(javaItem instanceof BedrockRequiresTagItem)) {
// // Strip NBT - tools won't appear in the recipe book otherwise
// output = output.toBuilder().tag(null).build();
// }
// ItemDescriptorWithCount[][] inputCombinations = combinations(session, recipe.ingredients());
// if (inputCombinations == null) {
// return null;
// }
//
// List<String> bedrockRecipeIDs = new ArrayList<>();
// for (ItemDescriptorWithCount[] inputs : inputCombinations) {
// UUID uuid = UUID.randomUUID();
// bedrockRecipeIDs.add(uuid.toString());
// packet.getCraftingData().add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapelessRecipeData.shulkerBox(uuid.toString(),
// Arrays.asList(inputs), Collections.singletonList(output), uuid, "crafting_table", 0, netId));
// recipeMap.put(netId++, recipe);
// }
// return bedrockRecipeIDs;
// }
//
// List<String> translateShapelessRecipe(GeyserShapelessRecipe recipe) {
// ItemStack result = recipe.result();
// ItemData output = ItemTranslator.translateToBedrock(session, result);
// if (!output.isValid()) {
// // Likely modded item that Bedrock will complain about if it persists
// return null;
// }
//
// Item javaItem = Registries.JAVA_ITEMS.get(result.getId());
// if (!(javaItem instanceof BedrockRequiresTagItem)) {
// // Strip NBT - tools won't appear in the recipe book otherwise
// output = output.toBuilder().tag(null).build();
// }
// ItemDescriptorWithCount[][] inputCombinations = combinations(session, recipe.ingredients());
// if (inputCombinations == null) {
// return null;
// }
//
// List<String> bedrockRecipeIDs = new ArrayList<>();
// for (ItemDescriptorWithCount[] inputs : inputCombinations) {
// UUID uuid = UUID.randomUUID();
// bedrockRecipeIDs.add(uuid.toString());
// packet.getCraftingData().add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapelessRecipeData.shapeless(uuid.toString(),
// Arrays.asList(inputs), Collections.singletonList(output), uuid, "crafting_table", 0, netId, RecipeUnlockingRequirement.INVALID));
// recipeMap.put(netId++, recipe);
// }
// return bedrockRecipeIDs;
// }
//
// List<String> translateShapedRecipe(GeyserShapedRecipe recipe) {
// ItemStack result = recipe.result();
// ItemData output = ItemTranslator.translateToBedrock(session, result);
// if (!output.isValid()) {
// // Likely modded item that Bedrock will complain about if it persists
// return null;
// }
//
// Item javaItem = Registries.JAVA_ITEMS.get(result.getId());
// if (!(javaItem instanceof BedrockRequiresTagItem)) {
// // Strip NBT - tools won't appear in the recipe book otherwise
// output = output.toBuilder().tag(null).build();
// }
// ItemDescriptorWithCount[][] inputCombinations = combinations(session, recipe.ingredients());
// if (inputCombinations == null) {
// return null;
// }
//
// List<String> bedrockRecipeIDs = new ArrayList<>();
// for (ItemDescriptorWithCount[] inputs : inputCombinations) {
// UUID uuid = UUID.randomUUID();
// bedrockRecipeIDs.add(uuid.toString());
// packet.getCraftingData().add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapedRecipeData.shaped(uuid.toString(),
// recipe.width(), recipe.height(), Arrays.asList(inputs),
// Collections.singletonList(output), uuid, "crafting_table", 0, netId, false, RecipeUnlockingRequirement.INVALID));
// recipeMap.put(netId++, recipe);
// }
// return bedrockRecipeIDs;
// }
//
// void addSpecialRecipesIdentifiers(Recipe recipe, List<String> identifiers) {
// String javaRecipeID = switch (recipe.getType()) {
// case CRAFTING_SPECIAL_SHULKERBOXCOLORING ->
// // BDS (un)locks the dyeing with the shulker box recipe, Java never - we want BDS behavior for ease of use
// "minecraft:shulker_box";
// case CRAFTING_SPECIAL_TIPPEDARROW ->
// // similar as above
// "minecraft:arrow";
// default -> recipe.getIdentifier().asString();
// };
//
// addRecipeIdentifier(session, javaRecipeID, identifiers);
// }
//
// void addRecipeIdentifier(GeyserSession session, String javaIdentifier, List<String> bedrockIdentifiers) {
// session.getJavaToBedrockRecipeIds().computeIfAbsent(javaIdentifier, k -> new ArrayList<>()).addAll(bedrockIdentifiers);
// }
//
// int getAndIncrementNetId() {
// return this.netId++;
// }
// }
}

View file

@ -25,17 +25,17 @@
package org.geysermc.geyser.translator.protocol.java.entity.player;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.player.ClientboundSetCarriedItemPacket;
import org.cloudburstmc.protocol.bedrock.packet.PlayerHotbarPacket;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.player.ClientboundSetHeldSlotPacket;
@Translator(packet = ClientboundSetCarriedItemPacket.class)
public class JavaSetCarriedItemTranslator extends PacketTranslator<ClientboundSetCarriedItemPacket> {
@Translator(packet = ClientboundSetHeldSlotPacket.class)
public class JavaSetHeldSlotTranslator extends PacketTranslator<ClientboundSetHeldSlotPacket> {
@Override
public void translate(GeyserSession session, ClientboundSetCarriedItemPacket packet) {
public void translate(GeyserSession session, ClientboundSetHeldSlotPacket packet) {
PlayerHotbarPacket hotbarPacket = new PlayerHotbarPacket();
hotbarPacket.setContainerId(0);
hotbarPacket.setSelectedHotbarSlot(packet.getSlot());

View file

@ -59,7 +59,7 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator<Clientbound
@Override
public void translate(GeyserSession session, ClientboundContainerSetSlotPacket packet) {
if (packet.getContainerId() == 255) { //cursor
if (packet.getContainerId() == 255) { //cursor //TODO new packet
GeyserItemStack newItem = GeyserItemStack.from(packet.getItem());
session.getPlayerInventory().setCursor(newItem, session);
InventoryUtils.updateCursor(session);
@ -90,7 +90,7 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator<Clientbound
updateCraftingGrid(session, slot, packet.getItem(), inventory, translator);
GeyserItemStack newItem = GeyserItemStack.from(packet.getItem());
if (packet.getContainerId() == 0 && !(translator instanceof PlayerInventoryTranslator)) {
if (packet.getContainerId() == 0 && !(translator instanceof PlayerInventoryTranslator)) { //TODO new packet
// In rare cases, the window ID can still be 0 but Java treats it as valid
session.getPlayerInventory().setItem(slot, newItem, session);
InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR.updateSlot(session, session.getPlayerInventory(), slot);

View file

@ -15,7 +15,7 @@ protocol-common = "3.0.0.Beta5-20240916.181041-6"
protocol-codec = "3.0.0.Beta5-20240916.181041-6"
raknet = "1.0.0.CR3-20240416.144209-1"
minecraftauth = "4.1.1"
mcprotocollib = "1.21-20241010.155958-24"
mcprotocollib = "1.21.2-SNAPSHOT"
adventure = "4.14.0"
adventure-platform = "4.3.0"
junit = "5.9.2"