diff --git a/api/src/main/java/org/geysermc/geyser/api/block/custom/CustomBlockData.java b/api/src/main/java/org/geysermc/geyser/api/block/custom/CustomBlockData.java index 9f142faab..2605cda21 100644 --- a/api/src/main/java/org/geysermc/geyser/api/block/custom/CustomBlockData.java +++ b/api/src/main/java/org/geysermc/geyser/api/block/custom/CustomBlockData.java @@ -61,16 +61,16 @@ public interface CustomBlockData { boolean includedInCreativeInventory(); /** - * Gets the item's creative category, or tab id. + * Gets the block's creative category, or tab id. * - * @return the item's creative category + * @return the block's creative category */ @Nullable CreativeCategory creativeCategory(); /** - * Gets the item's creative group. + * Gets the block's creative group. * - * @return the item's creative group + * @return the block's creative group */ @Nullable String creativeGroup(); diff --git a/api/src/main/java/org/geysermc/geyser/api/item/custom/CustomItemData.java b/api/src/main/java/org/geysermc/geyser/api/item/custom/CustomItemData.java index 404679e60..3b871cd74 100644 --- a/api/src/main/java/org/geysermc/geyser/api/item/custom/CustomItemData.java +++ b/api/src/main/java/org/geysermc/geyser/api/item/custom/CustomItemData.java @@ -29,6 +29,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.api.GeyserApi; +import java.util.OptionalInt; import java.util.Set; /** @@ -77,6 +78,20 @@ public interface CustomItemData { */ boolean displayHandheld(); + /** + * Gets the item's creative category, or tab id. + * + * @return the item's creative category + */ + @NonNull OptionalInt creativeCategory(); + + /** + * Gets the item's creative group. + * + * @return the item's creative group + */ + @Nullable String creativeGroup(); + /** * Gets the item's texture size. This is to resize the item if the texture is not 16x16. * @@ -119,6 +134,10 @@ public interface CustomItemData { Builder displayHandheld(boolean displayHandheld); + Builder creativeCategory(int creativeCategory); + + Builder creativeGroup(@Nullable String creativeGroup); + Builder textureSize(int textureSize); Builder renderOffsets(@Nullable CustomRenderOffsets renderOffsets); diff --git a/api/src/main/java/org/geysermc/geyser/api/item/custom/NonVanillaCustomItemData.java b/api/src/main/java/org/geysermc/geyser/api/item/custom/NonVanillaCustomItemData.java index 616a5bba6..37a4247d1 100644 --- a/api/src/main/java/org/geysermc/geyser/api/item/custom/NonVanillaCustomItemData.java +++ b/api/src/main/java/org/geysermc/geyser/api/item/custom/NonVanillaCustomItemData.java @@ -30,7 +30,6 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.api.GeyserApi; -import java.util.OptionalInt; import java.util.Set; /** @@ -107,20 +106,6 @@ public interface NonVanillaCustomItemData extends CustomItemData { */ @Nullable Set repairMaterials(); - /** - * Gets the item's creative category, or tab id. - * - * @return the item's creative category - */ - @NonNull OptionalInt creativeCategory(); - - /** - * Gets the item's creative group. - * - * @return the item's creative group - */ - @Nullable String creativeGroup(); - /** * Gets if the item is a hat. This is used to determine if the item should be rendered on the player's head, and * normally allow the player to equip it. This is not meant for armor. @@ -196,10 +181,6 @@ public interface NonVanillaCustomItemData extends CustomItemData { Builder repairMaterials(@Nullable Set repairMaterials); - Builder creativeCategory(int creativeCategory); - - Builder creativeGroup(@Nullable String creativeGroup); - Builder hat(boolean isHat); Builder foil(boolean isFoil); @@ -218,6 +199,12 @@ public interface NonVanillaCustomItemData extends CustomItemData { return displayHandheld(isTool); } + @Override + Builder creativeCategory(int creativeCategory); + + @Override + Builder creativeGroup(@Nullable String creativeGroup); + @Override Builder customItemOptions(@NonNull CustomItemOptions customItemOptions); diff --git a/core/src/main/java/org/geysermc/geyser/item/GeyserCustomItemData.java b/core/src/main/java/org/geysermc/geyser/item/GeyserCustomItemData.java index 2906a9be3..a2054f78a 100644 --- a/core/src/main/java/org/geysermc/geyser/item/GeyserCustomItemData.java +++ b/core/src/main/java/org/geysermc/geyser/item/GeyserCustomItemData.java @@ -35,6 +35,7 @@ import org.geysermc.geyser.api.item.custom.CustomRenderOffsets; import java.util.HashSet; import java.util.Objects; +import java.util.OptionalInt; import java.util.Set; @EqualsAndHashCode @@ -46,6 +47,8 @@ public class GeyserCustomItemData implements CustomItemData { private final String icon; private final boolean allowOffhand; private final boolean displayHandheld; + private final OptionalInt creativeCategory; + private final String creativeGroup; private final int textureSize; private final CustomRenderOffsets renderOffsets; private final Set tags; @@ -56,6 +59,8 @@ public class GeyserCustomItemData implements CustomItemData { String icon, boolean allowOffhand, boolean displayHandheld, + OptionalInt creativeCategory, + String creativeGroup, int textureSize, CustomRenderOffsets renderOffsets, Set tags) { @@ -65,6 +70,8 @@ public class GeyserCustomItemData implements CustomItemData { this.icon = icon; this.allowOffhand = allowOffhand; this.displayHandheld = displayHandheld; + this.creativeCategory = creativeCategory; + this.creativeGroup = creativeGroup; this.textureSize = textureSize; this.renderOffsets = renderOffsets; this.tags = tags; @@ -100,6 +107,16 @@ public class GeyserCustomItemData implements CustomItemData { return this.displayHandheld; } + @Override + public @NonNull OptionalInt creativeCategory() { + return this.creativeCategory; + } + + @Override + public @Nullable String creativeGroup() { + return this.creativeGroup; + } + @Override public int textureSize() { return textureSize; @@ -118,11 +135,12 @@ public class GeyserCustomItemData implements CustomItemData { public static class Builder implements CustomItemData.Builder { protected String name = null; protected CustomItemOptions customItemOptions = null; - protected String displayName = null; protected String icon = null; protected boolean allowOffhand = true; // Bedrock doesn't give items offhand allowance unless they serve gameplay purpose, but we want to be friendly with Java protected boolean displayHandheld = false; + protected OptionalInt creativeCategory = OptionalInt.empty(); + protected String creativeGroup = null; protected int textureSize = 16; protected CustomRenderOffsets renderOffsets = null; protected Set tags = new HashSet<>(); @@ -163,6 +181,18 @@ public class GeyserCustomItemData implements CustomItemData { return this; } + @Override + public Builder creativeCategory(int creativeCategory) { + this.creativeCategory = OptionalInt.of(creativeCategory); + return this; + } + + @Override + public Builder creativeGroup(@Nullable String creativeGroup) { + this.creativeGroup = creativeGroup; + return this; + } + @Override public Builder textureSize(int textureSize) { this.textureSize = textureSize; @@ -193,7 +223,8 @@ public class GeyserCustomItemData implements CustomItemData { if (this.icon == null) { this.icon = this.name; } - return new GeyserCustomItemData(this.name, this.customItemOptions, this.displayName, this.icon, this.allowOffhand, this.displayHandheld, this.textureSize, this.renderOffsets, this.tags); + return new GeyserCustomItemData(this.name, this.customItemOptions, this.displayName, this.icon, this.allowOffhand, + this.displayHandheld, this.creativeCategory, this.creativeGroup, this.textureSize, this.renderOffsets, this.tags); } } } diff --git a/core/src/main/java/org/geysermc/geyser/item/GeyserNonVanillaCustomItemData.java b/core/src/main/java/org/geysermc/geyser/item/GeyserNonVanillaCustomItemData.java index bb4e60589..14f8c3a39 100644 --- a/core/src/main/java/org/geysermc/geyser/item/GeyserNonVanillaCustomItemData.java +++ b/core/src/main/java/org/geysermc/geyser/item/GeyserNonVanillaCustomItemData.java @@ -33,10 +33,8 @@ import org.geysermc.geyser.api.item.custom.CustomItemOptions; import org.geysermc.geyser.api.item.custom.CustomRenderOffsets; import org.geysermc.geyser.api.item.custom.NonVanillaCustomItemData; -import java.util.OptionalInt; import java.util.Set; -@SuppressWarnings("OptionalUsedAsFieldOrParameterType") @EqualsAndHashCode(callSuper = true) @ToString public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData implements NonVanillaCustomItemData { @@ -50,8 +48,6 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i private final int protectionValue; private final String translationString; private final Set repairMaterials; - private final OptionalInt creativeCategory; - private final String creativeGroup; private final boolean isHat; private final boolean isFoil; private final boolean isTool; @@ -61,7 +57,8 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i public GeyserNonVanillaCustomItemData(Builder builder) { super(builder.name, builder.customItemOptions, builder.displayName, builder.icon, builder.allowOffhand, - builder.displayHandheld, builder.textureSize, builder.renderOffsets, builder.tags); + builder.displayHandheld, builder.creativeCategory, builder.creativeGroup, + builder.textureSize, builder.renderOffsets, builder.tags); this.identifier = builder.identifier; this.javaId = builder.javaId; @@ -73,8 +70,6 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i this.protectionValue = builder.protectionValue; this.translationString = builder.translationString; this.repairMaterials = builder.repairMaterials; - this.creativeCategory = builder.creativeCategory; - this.creativeGroup = builder.creativeGroup; this.isHat = builder.hat; this.isFoil = builder.foil; this.isTool = builder.tool; @@ -133,16 +128,6 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i return repairMaterials; } - @Override - public @NonNull OptionalInt creativeCategory() { - return creativeCategory; - } - - @Override - public String creativeGroup() { - return creativeGroup; - } - @Override public boolean isHat() { return isHat; @@ -186,9 +171,6 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i private Set repairMaterials; - private OptionalInt creativeCategory = OptionalInt.empty(); - private String creativeGroup = null; - private boolean hat = false; private boolean foil = false; private boolean tool = false; @@ -243,103 +225,101 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i } @Override - public NonVanillaCustomItemData.Builder identifier(@NonNull String identifier) { + public Builder identifier(@NonNull String identifier) { this.identifier = identifier; return this; } @Override - public NonVanillaCustomItemData.Builder javaId(int javaId) { + public Builder javaId(int javaId) { this.javaId = javaId; return this; } @Override - public NonVanillaCustomItemData.Builder stackSize(int stackSize) { + public Builder stackSize(int stackSize) { this.stackSize = stackSize; return this; } @Override - public NonVanillaCustomItemData.Builder maxDamage(int maxDamage) { + public Builder maxDamage(int maxDamage) { this.maxDamage = maxDamage; return this; } @Override - public NonVanillaCustomItemData.Builder toolType(@Nullable String toolType) { + public Builder toolType(@Nullable String toolType) { this.toolType = toolType; return this; } @Override - public NonVanillaCustomItemData.Builder toolTier(@Nullable String toolTier) { + public Builder toolTier(@Nullable String toolTier) { this.toolTier = toolTier; return this; } @Override - public NonVanillaCustomItemData.Builder armorType(@Nullable String armorType) { + public Builder armorType(@Nullable String armorType) { this.armorType = armorType; return this; } @Override - public NonVanillaCustomItemData.Builder protectionValue(int protectionValue) { + public Builder protectionValue(int protectionValue) { this.protectionValue = protectionValue; return this; } @Override - public NonVanillaCustomItemData.Builder translationString(@Nullable String translationString) { + public Builder translationString(@Nullable String translationString) { this.translationString = translationString; return this; } @Override - public NonVanillaCustomItemData.Builder repairMaterials(@Nullable Set repairMaterials) { + public Builder repairMaterials(@Nullable Set repairMaterials) { this.repairMaterials = repairMaterials; return this; } @Override - public NonVanillaCustomItemData.Builder creativeCategory(int creativeCategory) { - this.creativeCategory = OptionalInt.of(creativeCategory); - return this; + public Builder creativeCategory(int creativeCategory) { + return (Builder) super.creativeCategory(creativeCategory); } @Override - public NonVanillaCustomItemData.Builder creativeGroup(@Nullable String creativeGroup) { - this.creativeGroup = creativeGroup; - return this; + public Builder creativeGroup(@Nullable String creativeGroup) { + return (Builder) super.creativeGroup(creativeGroup); } @Override - public NonVanillaCustomItemData.Builder hat(boolean isHat) { + public Builder hat(boolean isHat) { this.hat = isHat; return this; } @Override - public NonVanillaCustomItemData.Builder foil(boolean isFoil) { + public Builder foil(boolean isFoil) { this.foil = isFoil; return this; } @Override - public NonVanillaCustomItemData.Builder edible(boolean isEdible) { + public Builder edible(boolean isEdible) { this.edible = isEdible; return this; } @Override - public NonVanillaCustomItemData.Builder canAlwaysEat(boolean canAlwaysEat) { + public Builder canAlwaysEat(boolean canAlwaysEat) { this.canAlwaysEat = canAlwaysEat; return this; } @Override - public NonVanillaCustomItemData.Builder chargeable(boolean isChargeable) { + public Builder chargeable(boolean isChargeable) { this.chargeable = isChargeable; return this; } diff --git a/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v1.java b/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v1.java index ce4a8f30e..e8901a550 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v1.java +++ b/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v1.java @@ -193,6 +193,14 @@ public class MappingsReader_v1 extends MappingsReader { customItemData.icon(node.get("icon").asText()); } + if (node.has("creative_category")) { + customItemData.creativeCategory(node.get("creative_category").asInt()); + } + + if (node.has("creative_group")) { + customItemData.creativeGroup(node.get("creative_group").asText()); + } + if (node.has("allow_offhand")) { customItemData.allowOffhand(node.get("allow_offhand").asBoolean()); } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java index c1f1bb10c..2e00bd4ad 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java @@ -246,13 +246,6 @@ public class CustomItemRegistryPopulator { computeRenderOffsets(isHat, customItemData, componentBuilder); - if (creativeGroup != null) { - itemProperties.putString("creative_group", creativeGroup); - } - if (creativeCategory.isPresent()) { - itemProperties.putInt("creative_category", creativeCategory.getAsInt()); - } - if (customItemData.isFoil()) { itemProperties.putBoolean("foil", true); } @@ -278,6 +271,14 @@ public class CustomItemRegistryPopulator { } itemProperties.putCompound("minecraft:icon", iconMap); + if (customItemData.creativeCategory().isPresent()) { + itemProperties.putInt("creative_category", customItemData.creativeCategory().getAsInt()); + + if (customItemData.creativeGroup() != null) { + itemProperties.putString("creative_group", customItemData.creativeGroup()); + } + } + componentBuilder.putCompound("minecraft:display_name", NbtMap.builder().putString("value", customItemData.displayName()).build()); // Add a Geyser tag to the item, allowing Molang queries @@ -370,21 +371,33 @@ public class CustomItemRegistryPopulator { componentBuilder.putString("minecraft:render_offsets", "boots"); componentBuilder.putCompound("minecraft:wearable", WearableSlot.FEET.getSlotNbt()); componentBuilder.putCompound("minecraft:armor", NbtMap.builder().putInt("protection", protectionValue).build()); + + itemProperties.putString("enchantable_slot", "armor_feet"); + itemProperties.putInt("enchantable_value", 15); } case "chestplate" -> { componentBuilder.putString("minecraft:render_offsets", "chestplates"); componentBuilder.putCompound("minecraft:wearable", WearableSlot.CHEST.getSlotNbt()); componentBuilder.putCompound("minecraft:armor", NbtMap.builder().putInt("protection", protectionValue).build()); + + itemProperties.putString("enchantable_slot", "armor_torso"); + itemProperties.putInt("enchantable_value", 15); } case "leggings" -> { componentBuilder.putString("minecraft:render_offsets", "leggings"); componentBuilder.putCompound("minecraft:wearable", WearableSlot.LEGS.getSlotNbt()); componentBuilder.putCompound("minecraft:armor", NbtMap.builder().putInt("protection", protectionValue).build()); + + itemProperties.putString("enchantable_slot", "armor_legs"); + itemProperties.putInt("enchantable_value", 15); } case "helmet" -> { componentBuilder.putString("minecraft:render_offsets", "helmets"); componentBuilder.putCompound("minecraft:wearable", WearableSlot.HEAD.getSlotNbt()); componentBuilder.putCompound("minecraft:armor", NbtMap.builder().putInt("protection", protectionValue).build()); + + itemProperties.putString("enchantable_slot", "armor_head"); + itemProperties.putInt("enchantable_value", 15); } } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 539452169..c1593447d 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -425,6 +425,16 @@ public class ItemRegistryPopulator { GeyserCustomMappingData customMapping = CustomItemRegistryPopulator.registerCustomItem( customItemName, javaItem, mappingItem, customItem, customProtocolId, palette.protocolVersion ); + + if (customItem.creativeCategory().isPresent()) { + creativeItems.add(ItemData.builder() + .netId(creativeNetId.incrementAndGet()) + .definition(customMapping.itemDefinition()) + .blockDefinition(null) + .count(1) + .build()); + } + // ComponentItemData - used to register some custom properties componentItemData.add(customMapping.componentItemData()); customItemOptions.add(Pair.of(customItem.customItemOptions(), customMapping.itemDefinition())); @@ -523,7 +533,7 @@ public class ItemRegistryPopulator { mappings.set(javaItem.javaId(), mapping); registry.put(customItemId, mapping.getBedrockDefinition()); - if (customItem.creativeGroup() != null || customItem.creativeCategory().isPresent()) { + if (customItem.creativeCategory().isPresent()) { creativeItems.add(ItemData.builder() .definition(registration.mapping().getBedrockDefinition()) .netId(creativeNetId.incrementAndGet()) diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 73cbf32c8..7a4a8ff6f 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -113,8 +113,6 @@ import org.geysermc.geyser.api.event.bedrock.SessionLoginEvent; import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.api.network.RemoteServer; import org.geysermc.geyser.api.util.PlatformType; -import org.geysermc.geyser.impl.camera.CameraDefinitions; -import org.geysermc.geyser.impl.camera.GeyserCameraData; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.configuration.EmoteOffhandWorkaroundOption; import org.geysermc.geyser.configuration.GeyserConfiguration; @@ -127,6 +125,8 @@ import org.geysermc.geyser.entity.type.Tickable; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; import org.geysermc.geyser.erosion.AbstractGeyserboundPacketHandler; import org.geysermc.geyser.erosion.GeyserboundHandshakePacketHandler; +import org.geysermc.geyser.impl.camera.CameraDefinitions; +import org.geysermc.geyser.impl.camera.GeyserCameraData; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.inventory.recipe.GeyserRecipe; @@ -1464,9 +1464,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } public void setServerRenderDistance(int renderDistance) { - // +1 is for Fabric and Spigot - // Without the client misses loading some chunks per https://github.com/GeyserMC/Geyser/issues/3490 - // Fog still appears essentially normally // Ensure render distance is not above 96 as sending a larger value at any point crashes mobile clients and 96 is the max of any bedrock platform renderDistance = Math.min(renderDistance, 96); this.serverRenderDistance = renderDistance;