Fix: Workaround for recipes involving custom items to show up in the recipe book (#4484)

* Allow adding custom items to the creative inventory in order for recipes outputting said custom items to work

* yeet includeInCreativeInventory as it would break existing nonvanilla extensions - and is pretty pointless anyways

* rename mappings to `creative_group` and `creative_category`

* delete outdated comment
This commit is contained in:
chris 2024-03-10 23:38:38 +01:00 committed by GitHub
parent 527eab0b58
commit 0ad7c4325d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 124 additions and 79 deletions

View File

@ -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();

View File

@ -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);

View File

@ -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<String> 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<String> 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);

View File

@ -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<String> 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<String> 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<String> 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);
}
}
}

View File

@ -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<String> 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<String> 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<String> repairMaterials) {
public Builder repairMaterials(@Nullable Set<String> 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;
}

View File

@ -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());
}

View File

@ -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);
}
}
}

View File

@ -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())

View File

@ -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;