This commit is contained in:
Eclipse 2024-08-13 20:11:24 +00:00 committed by GitHub
commit 2de5f0b3bf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 479 additions and 319 deletions

View file

@ -25,6 +25,8 @@
package org.geysermc.geyser.api.item.custom; package org.geysermc.geyser.api.item.custom;
import org.checkerframework.checker.index.qual.NonNegative;
import org.checkerframework.checker.index.qual.Positive;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.api.GeyserApi; import org.geysermc.geyser.api.GeyserApi;
@ -114,6 +116,88 @@ public interface CustomItemData {
*/ */
@NonNull Set<String> tags(); @NonNull Set<String> tags();
/**
* Gets the stack size of the item.
*
* <p>Returns 0 if not set. When not set, Geyser defaults to the stack count of the Java item when based on a vanilla item, or 64 when registering a non-vanilla item.</p>
*
* <p>Note that, to copy Java behaviour, setting the stack size of an item to a value above 1 will set the max damage to 0. If a max damage value above 0 was explicitly set, an exception will be thrown.</p>
*
* @return the stack size of the item
*/
@NonNegative int stackSize();
/**
* Gets the max damage of the item.
*
* <p>Returns -1 if not set. When not set, Geyser defaults to the maximum damage of the Java item when based on a vanilla item, or uses 0 when registering a non-vanilla item.</p>
*
* <p>Note that, to copy Java behaviour, setting the max damage value of an item to a value above 0 will set the stack size to 1. If a stack size above 1 was explicitly set, an exception will be thrown.</p>
*
* @return the max damage of the item
*/
int maxDamage();
/**
* Gets the attack damage of the item.
* This is purely visual, and only applied to tools
*
* <p>Returns -1 if not set. When not set, Geyser takes the Java item attack damage when based on a vanilla item, or uses 0 when porting a modded item.</p>
*
* @return the attack damage of the item
*/
int attackDamage();
/**
* Gets the armor type of the item.
*
* <p>This can be "boots", "leggings", "chestplate", or "helmet", and makes the item able to be equipped into its respective equipment slot.
* This should only be set if the Java item can be placed into the specified equipment slot.</p>
*
* @return the armor type of the item
*/
@Nullable String armorType();
/**
* Gets the armor protection value of the item.
*
* <p>Only has a function when {@link CustomItemData#armorType} is set, or when the Java item is an armor item (when based on a vanilla item).</p>
*
* <p>Returns -1 if not set. When not set, Geyser takes the Java item protection value when based on a vanilla item, or uses 0 when porting a modded item.</p>
*
* @return the armor protection value of the item
*/
int protectionValue();
/**
* 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.
*
* @return if the item is a hat
*/
boolean isHat();
/**
* Gets if the item is a foil. This is used to determine if the item should be rendered with an enchantment glint effect.
*
* @return if the item is a foil
*/
boolean isFoil();
/**
* Gets if the item is edible.
*
* @return if the item is edible
*/
boolean isEdible();
/**
* Gets if the food item can always be eaten.
*
* @return if the item is allowed to be eaten all the time
*/
boolean canAlwaysEat();
static CustomItemData.Builder builder() { static CustomItemData.Builder builder() {
return GeyserApi.api().provider(CustomItemData.Builder.class); return GeyserApi.api().provider(CustomItemData.Builder.class);
} }
@ -144,6 +228,24 @@ public interface CustomItemData {
Builder tags(@Nullable Set<String> tags); Builder tags(@Nullable Set<String> tags);
Builder stackSize(@Positive int stackSize);
Builder maxDamage(@NonNegative int maxDamage);
Builder attackDamage(@NonNegative int attackDamage);
Builder armorType(@Nullable String armorType);
Builder protectionValue(@NonNegative int protectionValue);
Builder hat(boolean isHat);
Builder foil(boolean isFoil);
Builder edible(boolean isEdible);
Builder canAlwaysEat(boolean canAlwaysEat);
CustomItemData build(); CustomItemData build();
} }
} }

View file

@ -26,6 +26,7 @@
package org.geysermc.geyser.api.item.custom; package org.geysermc.geyser.api.item.custom;
import org.checkerframework.checker.index.qual.NonNegative; import org.checkerframework.checker.index.qual.NonNegative;
import org.checkerframework.checker.index.qual.Positive;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.api.GeyserApi; import org.geysermc.geyser.api.GeyserApi;
@ -43,35 +44,6 @@ public interface NonVanillaCustomItemData extends CustomItemData {
*/ */
@NonNull String identifier(); @NonNull String identifier();
/**
* Gets the java item id of the item.
*
* @return the java item id of the item
*/
@NonNegative int javaId();
/**
* Gets the stack size of the item.
*
* @return the stack size of the item
*/
@NonNegative int stackSize();
/**
* Gets the max damage of the item.
*
* @return the max damage of the item
*/
int maxDamage();
/**
* Gets the attack damage of the item.
* This is purely visual, and only applied to tools
*
* @return the attack damage of the item
*/
int attackDamage();
/** /**
* Gets the tool type of the item. * Gets the tool type of the item.
* *
@ -87,18 +59,11 @@ public interface NonVanillaCustomItemData extends CustomItemData {
@Nullable String toolTier(); @Nullable String toolTier();
/** /**
* Gets the armor type of the item. * Gets the java item id of the item.
* *
* @return the armor type of the item * @return the java item id of the item
*/ */
@Nullable String armorType(); @NonNegative int javaId();
/**
* Gets the armor protection value of the item.
*
* @return the armor protection value of the item
*/
int protectionValue();
/** /**
* Gets the item's translation string. * Gets the item's translation string.
@ -114,35 +79,6 @@ public interface NonVanillaCustomItemData extends CustomItemData {
*/ */
@Nullable Set<String> repairMaterials(); @Nullable Set<String> repairMaterials();
/**
* 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.
*
* @return if the item is a hat
*/
boolean isHat();
/**
* Gets if the item is a foil. This is used to determine if the item should be rendered with an enchantment glint effect.
*
* @return if the item is a foil
*/
boolean isFoil();
/**
* Gets if the item is edible.
*
* @return if the item is edible
*/
boolean isEdible();
/**
* Gets if the food item can always be eaten.
*
* @return if the item is allowed to be eaten all the time
*/
boolean canAlwaysEat();
/** /**
* Gets if the item is chargable, like a bow. * Gets if the item is chargable, like a bow.
* *
@ -150,6 +86,13 @@ public interface NonVanillaCustomItemData extends CustomItemData {
*/ */
boolean isChargeable(); boolean isChargeable();
/**
* Gets the block the item places.
*
* @return the block the item places
*/
String block();
/** /**
* @deprecated Use {@link #displayHandheld()} instead. * @deprecated Use {@link #displayHandheld()} instead.
* Gets if the item is a tool. This is used to set the render type of the item, if the item is handheld. * Gets if the item is a tool. This is used to set the render type of the item, if the item is handheld.
@ -161,13 +104,6 @@ public interface NonVanillaCustomItemData extends CustomItemData {
return displayHandheld(); return displayHandheld();
} }
/**
* Gets the block the item places.
*
* @return the block the item places
*/
String block();
static NonVanillaCustomItemData.Builder builder() { static NonVanillaCustomItemData.Builder builder() {
return GeyserApi.api().provider(NonVanillaCustomItemData.Builder.class); return GeyserApi.api().provider(NonVanillaCustomItemData.Builder.class);
} }
@ -176,54 +112,6 @@ public interface NonVanillaCustomItemData extends CustomItemData {
@Override @Override
Builder name(@NonNull String name); Builder name(@NonNull String name);
Builder identifier(@NonNull String identifier);
Builder javaId(@NonNegative int javaId);
Builder stackSize(@NonNegative int stackSize);
Builder maxDamage(int maxDamage);
Builder attackDamage(int attackDamage);
Builder toolType(@Nullable String toolType);
Builder toolTier(@Nullable String toolTier);
Builder armorType(@Nullable String armorType);
Builder protectionValue(int protectionValue);
Builder translationString(@Nullable String translationString);
Builder repairMaterials(@Nullable Set<String> repairMaterials);
Builder hat(boolean isHat);
Builder foil(boolean isFoil);
Builder edible(boolean isEdible);
Builder canAlwaysEat(boolean canAlwaysEat);
Builder chargeable(boolean isChargeable);
Builder block(String block);
/**
* @deprecated Use {@link #displayHandheld(boolean)} instead.
*/
@Deprecated
default Builder tool(boolean isTool) {
return displayHandheld(isTool);
}
@Override
Builder creativeCategory(int creativeCategory);
@Override
Builder creativeGroup(@Nullable String creativeGroup);
@Override @Override
Builder customItemOptions(@NonNull CustomItemOptions customItemOptions); Builder customItemOptions(@NonNull CustomItemOptions customItemOptions);
@ -239,6 +127,12 @@ public interface NonVanillaCustomItemData extends CustomItemData {
@Override @Override
Builder displayHandheld(boolean displayHandheld); Builder displayHandheld(boolean displayHandheld);
@Override
Builder creativeCategory(int creativeCategory);
@Override
Builder creativeGroup(@Nullable String creativeGroup);
@Override @Override
Builder textureSize(int textureSize); Builder textureSize(int textureSize);
@ -248,6 +142,57 @@ public interface NonVanillaCustomItemData extends CustomItemData {
@Override @Override
Builder tags(@Nullable Set<String> tags); Builder tags(@Nullable Set<String> tags);
@Override
Builder stackSize(@Positive int stackSize);
@Override
Builder maxDamage(@NonNegative int maxDamage);
@Override
Builder attackDamage(@NonNegative int attackDamage);
@Override
Builder armorType(@Nullable String armorType);
@Override
Builder protectionValue(@NonNegative int protectionValue);
@Override
Builder hat(boolean isHat);
@Override
Builder foil(boolean isFoil);
@Override
Builder edible(boolean isEdible);
@Override
Builder canAlwaysEat(boolean canAlwaysEat);
/**
* @deprecated Use {@link #displayHandheld(boolean)} instead.
*/
@Deprecated
default Builder tool(boolean isTool) {
return displayHandheld(isTool);
}
Builder identifier(@NonNull String identifier);
Builder javaId(@NonNegative int javaId);
Builder toolType(@Nullable String toolType);
Builder toolTier(@Nullable String toolTier);
Builder translationString(@Nullable String translationString);
Builder repairMaterials(@Nullable Set<String> repairMaterials);
Builder chargeable(boolean isChargeable);
Builder block(String block);
NonVanillaCustomItemData build(); NonVanillaCustomItemData build();
} }
} }

View file

@ -25,8 +25,11 @@
package org.geysermc.geyser.item; package org.geysermc.geyser.item;
import java.util.List;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.ToString; import lombok.ToString;
import org.checkerframework.checker.index.qual.NonNegative;
import org.checkerframework.checker.index.qual.Positive;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.api.item.custom.CustomItemData; import org.geysermc.geyser.api.item.custom.CustomItemData;
@ -41,6 +44,8 @@ import java.util.Set;
@EqualsAndHashCode @EqualsAndHashCode
@ToString @ToString
public class GeyserCustomItemData implements CustomItemData { public class GeyserCustomItemData implements CustomItemData {
private static final List<String> VALID_ARMOR_TYPES = List.of("boots", "leggings", "chestplate", "helmet");
private final String name; private final String name;
private final CustomItemOptions customItemOptions; private final CustomItemOptions customItemOptions;
private final String displayName; private final String displayName;
@ -52,29 +57,37 @@ public class GeyserCustomItemData implements CustomItemData {
private final int textureSize; private final int textureSize;
private final CustomRenderOffsets renderOffsets; private final CustomRenderOffsets renderOffsets;
private final Set<String> tags; private final Set<String> tags;
private final int stackSize;
private final int maxDamage;
private final int attackDamage;
private final String armorType;
private final int protectionValue;
private final boolean isHat;
private final boolean isFoil;
private final boolean isEdible;
private final boolean canAlwaysEat;
public GeyserCustomItemData(String name, public GeyserCustomItemData(Builder builder) {
CustomItemOptions customItemOptions, this.name = builder.name;
String displayName, this.customItemOptions = builder.customItemOptions;
String icon, this.displayName = builder.displayName;
boolean allowOffhand, this.icon = builder.icon;
boolean displayHandheld, this.allowOffhand = builder.allowOffhand;
OptionalInt creativeCategory, this.displayHandheld = builder.displayHandheld;
String creativeGroup, this.creativeCategory = builder.creativeCategory;
int textureSize, this.creativeGroup = builder.creativeGroup;
CustomRenderOffsets renderOffsets, this.textureSize = builder.textureSize;
Set<String> tags) { this.renderOffsets = builder.renderOffsets;
this.name = name; this.tags = builder.tags;
this.customItemOptions = customItemOptions; this.stackSize = builder.stackSize;
this.displayName = displayName; this.maxDamage = builder.maxDamage;
this.icon = icon; this.attackDamage = builder.attackDamage;
this.allowOffhand = allowOffhand; this.armorType = builder.armorType;
this.displayHandheld = displayHandheld; this.protectionValue = builder.protectionValue;
this.creativeCategory = creativeCategory; this.isHat = builder.hat;
this.creativeGroup = creativeGroup; this.isFoil = builder.foil;
this.textureSize = textureSize; this.isEdible = builder.edible;
this.renderOffsets = renderOffsets; this.canAlwaysEat = builder.canAlwaysEat;
this.tags = tags;
} }
@Override @Override
@ -132,6 +145,51 @@ public class GeyserCustomItemData implements CustomItemData {
return tags; return tags;
} }
@Override
public int stackSize() {
return stackSize;
}
@Override
public int maxDamage() {
return maxDamage;
}
@Override
public int attackDamage() {
return attackDamage;
}
@Override
public @Nullable String armorType() {
return armorType;
}
@Override
public int protectionValue() {
return protectionValue;
}
@Override
public boolean isHat() {
return isHat;
}
@Override
public boolean isFoil() {
return isFoil;
}
@Override
public boolean isEdible() {
return isEdible;
}
@Override
public boolean canAlwaysEat() {
return canAlwaysEat;
}
public static class Builder implements CustomItemData.Builder { public static class Builder implements CustomItemData.Builder {
protected String name = null; protected String name = null;
protected CustomItemOptions customItemOptions = null; protected CustomItemOptions customItemOptions = null;
@ -144,6 +202,15 @@ public class GeyserCustomItemData implements CustomItemData {
protected int textureSize = 16; protected int textureSize = 16;
protected CustomRenderOffsets renderOffsets = null; protected CustomRenderOffsets renderOffsets = null;
protected Set<String> tags = new HashSet<>(); protected Set<String> tags = new HashSet<>();
private int stackSize = 0;
private int maxDamage = -1;
private int attackDamage = -1;
private String armorType = null;
private int protectionValue = -1;
private boolean hat = false;
private boolean foil = false;
private boolean edible = false;
private boolean canAlwaysEat = false;
@Override @Override
public Builder name(@NonNull String name) { public Builder name(@NonNull String name) {
@ -211,6 +278,89 @@ public class GeyserCustomItemData implements CustomItemData {
return this; return this;
} }
@Override
public Builder stackSize(@Positive int stackSize) {
if (stackSize < 1) {
throw new IllegalArgumentException("Stack size cannot be below 1 (" + stackSize + " was given)");
} else if (stackSize > 1) {
if (this.maxDamage > 0) {
throw new IllegalArgumentException("Stack size cannot be above 1 when max damage is above 0 (" + stackSize + " was given)");
}
// Explicitly set max damage to 0 instead of falling back to the Java vanilla item value
this.maxDamage = 0;
}
this.stackSize = stackSize;
return this;
}
@Override
public Builder maxDamage(@NonNegative int maxDamage) {
if (maxDamage < 0) {
throw new IllegalArgumentException("Max damage cannot be below 0 (" + maxDamage + " was given)");
} else if (maxDamage > 0) {
if (this.stackSize > 1) {
throw new IllegalArgumentException("Max damage cannot be above 0 when stack size is above 1 (" + maxDamage + " was given)");
}
// Explicitly set stack size to 1 instead of falling back to the Java vanilla item value
this.stackSize = 1;
}
this.maxDamage = maxDamage;
return this;
}
@Override
public Builder attackDamage(@NonNegative int attackDamage) {
if (attackDamage < 0) {
throw new IllegalArgumentException("Protection value cannot be below 0 (" + attackDamage + " was given)");
}
this.attackDamage = attackDamage;
return this;
}
@Override
public Builder armorType(@Nullable String armorType) {
if (!VALID_ARMOR_TYPES.contains(armorType)) {
throw new IllegalArgumentException("Invalid armor type " + armorType + "! Can be \"boots\", \"leggings\", \"chestplate\", or \"helmet\"");
}
this.armorType = armorType;
return this;
}
@Override
public Builder protectionValue(@NonNegative int protectionValue) {
if (protectionValue < 0) {
throw new IllegalArgumentException("Protection value cannot be below 0 (" + protectionValue + " was given)");
}
this.protectionValue = protectionValue;
return this;
}
@Override
public Builder hat(boolean isHat) {
this.hat = isHat;
return this;
}
@Override
public Builder foil(boolean isFoil) {
this.foil = isFoil;
return this;
}
@Override
public Builder edible(boolean isEdible) {
this.edible = isEdible;
return this;
}
@Override
public Builder canAlwaysEat(boolean canAlwaysEat) {
this.canAlwaysEat = canAlwaysEat;
return this;
}
@Override @Override
public CustomItemData build() { public CustomItemData build() {
if (this.name == null || this.customItemOptions == null) { if (this.name == null || this.customItemOptions == null) {
@ -223,8 +373,8 @@ public class GeyserCustomItemData implements CustomItemData {
if (this.icon == null) { if (this.icon == null) {
this.icon = this.name; this.icon = this.name;
} }
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); return new GeyserCustomItemData(this);
} }
} }
} }

View file

@ -27,6 +27,8 @@ package org.geysermc.geyser.item;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.ToString; import lombok.ToString;
import org.checkerframework.checker.index.qual.NonNegative;
import org.checkerframework.checker.index.qual.Positive;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.api.item.custom.CustomItemOptions; import org.geysermc.geyser.api.item.custom.CustomItemOptions;
@ -40,44 +42,22 @@ import java.util.Set;
public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData implements NonVanillaCustomItemData { public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData implements NonVanillaCustomItemData {
private final String identifier; private final String identifier;
private final int javaId; private final int javaId;
private final int stackSize;
private final int maxDamage;
private final int attackDamage;
private final String toolType; private final String toolType;
private final String toolTier; private final String toolTier;
private final String armorType;
private final int protectionValue;
private final String translationString; private final String translationString;
private final Set<String> repairMaterials; private final Set<String> repairMaterials;
private final boolean isHat;
private final boolean isFoil;
private final boolean isTool;
private final boolean isEdible;
private final boolean canAlwaysEat;
private final boolean isChargeable; private final boolean isChargeable;
private final String block; private final String block;
public GeyserNonVanillaCustomItemData(Builder builder) { public GeyserNonVanillaCustomItemData(Builder builder) {
super(builder.name, builder.customItemOptions, builder.displayName, builder.icon, builder.allowOffhand, super(builder);
builder.displayHandheld, builder.creativeCategory, builder.creativeGroup,
builder.textureSize, builder.renderOffsets, builder.tags);
this.identifier = builder.identifier; this.identifier = builder.identifier;
this.javaId = builder.javaId; this.javaId = builder.javaId;
this.stackSize = builder.stackSize;
this.maxDamage = builder.maxDamage;
this.attackDamage = builder.attackDamage;
this.toolType = builder.toolType; this.toolType = builder.toolType;
this.toolTier = builder.toolTier; this.toolTier = builder.toolTier;
this.armorType = builder.armorType;
this.protectionValue = builder.protectionValue;
this.translationString = builder.translationString; this.translationString = builder.translationString;
this.repairMaterials = builder.repairMaterials; this.repairMaterials = builder.repairMaterials;
this.isHat = builder.hat;
this.isFoil = builder.foil;
this.isTool = builder.tool;
this.isEdible = builder.edible;
this.canAlwaysEat = builder.canAlwaysEat;
this.isChargeable = builder.chargeable; this.isChargeable = builder.chargeable;
this.block = builder.block; this.block = builder.block;
} }
@ -92,21 +72,6 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
return javaId; return javaId;
} }
@Override
public int stackSize() {
return stackSize;
}
@Override
public int maxDamage() {
return maxDamage;
}
@Override
public int attackDamage() {
return attackDamage;
}
@Override @Override
public String toolType() { public String toolType() {
return toolType; return toolType;
@ -117,16 +82,6 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
return toolTier; return toolTier;
} }
@Override
public @Nullable String armorType() {
return armorType;
}
@Override
public int protectionValue() {
return protectionValue;
}
@Override @Override
public String translationString() { public String translationString() {
return translationString; return translationString;
@ -137,26 +92,6 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
return repairMaterials; return repairMaterials;
} }
@Override
public boolean isHat() {
return isHat;
}
@Override
public boolean isFoil() {
return isFoil;
}
@Override
public boolean isEdible() {
return isEdible;
}
@Override
public boolean canAlwaysEat() {
return canAlwaysEat;
}
@Override @Override
public boolean isChargeable() { public boolean isChargeable() {
return isChargeable; return isChargeable;
@ -170,28 +105,10 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
public static class Builder extends GeyserCustomItemData.Builder implements NonVanillaCustomItemData.Builder { public static class Builder extends GeyserCustomItemData.Builder implements NonVanillaCustomItemData.Builder {
private String identifier = null; private String identifier = null;
private int javaId = -1; private int javaId = -1;
private int stackSize = 64;
private int maxDamage = 0;
private int attackDamage = 0;
private String toolType = null; private String toolType = null;
private String toolTier = null; private String toolTier = null;
private String armorType = null;
private int protectionValue = 0;
private String translationString; private String translationString;
private Set<String> repairMaterials; private Set<String> repairMaterials;
private boolean hat = false;
private boolean foil = false;
private boolean tool = false;
private boolean edible = false;
private boolean canAlwaysEat = false;
private boolean chargeable = false; private boolean chargeable = false;
private String block = null; private String block = null;
@ -206,6 +123,16 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
return this; return this;
} }
@Override
public Builder displayName(@NonNull String displayName) {
return (Builder) super.displayName(displayName);
}
@Override
public Builder icon(@NonNull String icon) {
return (Builder) super.icon(icon);
}
@Override @Override
public Builder allowOffhand(boolean allowOffhand) { public Builder allowOffhand(boolean allowOffhand) {
return (Builder) super.allowOffhand(allowOffhand); return (Builder) super.allowOffhand(allowOffhand);
@ -217,13 +144,13 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
} }
@Override @Override
public Builder displayName(@NonNull String displayName) { public Builder creativeCategory(int creativeCategory) {
return (Builder) super.displayName(displayName); return (Builder) super.creativeCategory(creativeCategory);
} }
@Override @Override
public Builder icon(@NonNull String icon) { public Builder creativeGroup(@Nullable String creativeGroup) {
return (Builder) super.icon(icon); return (Builder) super.creativeGroup(creativeGroup);
} }
@Override @Override
@ -241,6 +168,51 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
return (Builder) super.tags(tags); return (Builder) super.tags(tags);
} }
@Override
public Builder stackSize(@Positive int stackSize) {
return (Builder) super.stackSize(stackSize);
}
@Override
public Builder maxDamage(@NonNegative int maxDamage) {
return (Builder) super.maxDamage(maxDamage);
}
@Override
public Builder attackDamage(@NonNegative int attackDamage) {
return (Builder) super.attackDamage(attackDamage);
}
@Override
public Builder armorType(@Nullable String armorType) {
return (Builder) super.armorType(armorType);
}
@Override
public Builder protectionValue(@NonNegative int protectionValue) {
return (Builder) super.protectionValue(protectionValue);
}
@Override
public Builder hat(boolean isHat) {
return (Builder) super.hat(isHat);
}
@Override
public Builder foil(boolean isFoil) {
return (Builder) super.foil(isFoil);
}
@Override
public Builder edible(boolean isEdible) {
return (Builder) super.edible(isEdible);
}
@Override
public Builder canAlwaysEat(boolean canAlwaysEat) {
return (Builder) super.canAlwaysEat(canAlwaysEat);
}
@Override @Override
public Builder identifier(@NonNull String identifier) { public Builder identifier(@NonNull String identifier) {
this.identifier = identifier; this.identifier = identifier;
@ -253,24 +225,6 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
return this; return this;
} }
@Override
public Builder stackSize(int stackSize) {
this.stackSize = stackSize;
return this;
}
@Override
public Builder maxDamage(int maxDamage) {
this.maxDamage = maxDamage;
return this;
}
@Override
public NonVanillaCustomItemData.Builder attackDamage(int attackDamage) {
this.attackDamage = attackDamage;
return this;
}
@Override @Override
public Builder toolType(@Nullable String toolType) { public Builder toolType(@Nullable String toolType) {
this.toolType = toolType; this.toolType = toolType;
@ -283,18 +237,6 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
return this; return this;
} }
@Override
public Builder armorType(@Nullable String armorType) {
this.armorType = armorType;
return this;
}
@Override
public Builder protectionValue(int protectionValue) {
this.protectionValue = protectionValue;
return this;
}
@Override @Override
public Builder translationString(@Nullable String translationString) { public Builder translationString(@Nullable String translationString) {
this.translationString = translationString; this.translationString = translationString;
@ -307,40 +249,6 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
return this; return this;
} }
@Override
public Builder creativeCategory(int creativeCategory) {
return (Builder) super.creativeCategory(creativeCategory);
}
@Override
public Builder creativeGroup(@Nullable String creativeGroup) {
return (Builder) super.creativeGroup(creativeGroup);
}
@Override
public Builder hat(boolean isHat) {
this.hat = isHat;
return this;
}
@Override
public Builder foil(boolean isFoil) {
this.foil = isFoil;
return this;
}
@Override
public Builder edible(boolean isEdible) {
this.edible = isEdible;
return this;
}
@Override
public Builder canAlwaysEat(boolean canAlwaysEat) {
this.canAlwaysEat = canAlwaysEat;
return this;
}
@Override @Override
public Builder chargeable(boolean isChargeable) { public Builder chargeable(boolean isChargeable) {
this.chargeable = isChargeable; this.chargeable = isChargeable;

View file

@ -213,6 +213,42 @@ public class MappingsReader_v1 extends MappingsReader {
customItemData.tags(tagsSet); customItemData.tags(tagsSet);
} }
if (node.has("stack_size")) {
customItemData.stackSize(node.get("stack_size").asInt());
}
if (node.has("max_damage")) {
customItemData.maxDamage(node.get("max_damage").asInt());
}
if (node.has("attack_damage")) {
customItemData.attackDamage(node.get("attack_damage").asInt());
}
if (node.has("armor_type")) {
customItemData.armorType(node.get("armor_type").asText());
}
if (node.has("protection_value")) {
customItemData.protectionValue(node.get("protection_value").asInt());
}
if (node.has("hat")) {
customItemData.hat(node.get("hat").asBoolean());
}
if (node.has("foil")) {
customItemData.foil(node.get("foil").asBoolean());
}
if (node.has("edible")) {
customItemData.edible(node.get("edible").asBoolean());
}
if (node.has("can_always_eat")) {
customItemData.canAlwaysEat(node.get("can_always_eat").asBoolean());
}
return customItemData.build(); return customItemData.build();
} }

View file

@ -130,8 +130,8 @@ public class CustomItemRegistryPopulator {
Set<String> repairMaterials = customItemData.repairMaterials(); Set<String> repairMaterials = customItemData.repairMaterials();
Item.Builder itemBuilder = Item.builder() Item.Builder itemBuilder = Item.builder()
.stackSize(customItemData.stackSize()) .stackSize(customItemData.stackSize() == 0 ? 64 : customItemData.stackSize())
.maxDamage(customItemData.maxDamage()); .maxDamage(Math.max(customItemData.maxDamage(), 0));
Item item = new Item(customIdentifier, itemBuilder) { Item item = new Item(customIdentifier, itemBuilder) {
@Override @Override
public boolean isValidRepairItem(Item other) { public boolean isValidRepairItem(Item other) {
@ -151,8 +151,7 @@ public class CustomItemRegistryPopulator {
.javaItem(item) .javaItem(item)
.build(); .build();
NbtMapBuilder builder = createComponentNbt(customItemData, customItemData.identifier(), customItemId, NbtMapBuilder builder = createComponentNbt(customItemData, customItemId, protocolVersion);
customItemData.isHat(), customItemData.displayHandheld(), protocolVersion);
ComponentItemData componentItemData = new ComponentItemData(customIdentifier, builder.build()); ComponentItemData componentItemData = new ComponentItemData(customIdentifier, builder.build());
return new NonVanillaItemRegistration(componentItemData, item, customItemMapping); return new NonVanillaItemRegistration(componentItemData, item, customItemMapping);
@ -167,30 +166,50 @@ public class CustomItemRegistryPopulator {
NbtMapBuilder itemProperties = NbtMap.builder(); NbtMapBuilder itemProperties = NbtMap.builder();
NbtMapBuilder componentBuilder = NbtMap.builder(); NbtMapBuilder componentBuilder = NbtMap.builder();
setupBasicItemInfo(javaItem.maxDamage(), javaItem.maxStackSize(), mapping.getToolType() != null || customItemData.displayHandheld(), customItemData, itemProperties, componentBuilder, protocolVersion); setupBasicItemInfo(customItemData.maxDamage() < 0 ? javaItem.maxDamage() : customItemData.maxDamage(),
customItemData.stackSize() == 0 ? javaItem.maxStackSize() : customItemData.stackSize(),
mapping.getToolType() != null || customItemData.displayHandheld(),
customItemData, itemProperties, componentBuilder, protocolVersion);
boolean canDestroyInCreative = true; boolean canDestroyInCreative = true;
if (mapping.getToolType() != null) { // This is not using the isTool boolean because it is not just a render type here. if (mapping.getToolType() != null) {
canDestroyInCreative = computeToolProperties(mapping.getToolType(), itemProperties, componentBuilder, javaItem.attackDamage()); canDestroyInCreative = computeToolProperties(mapping.getToolType(), itemProperties, componentBuilder,
customItemData.attackDamage() == 0 ? javaItem.attackDamage() : customItemData.attackDamage());
} }
itemProperties.putBoolean("can_destroy_in_creative", canDestroyInCreative); itemProperties.putBoolean("can_destroy_in_creative", canDestroyInCreative);
String armorType = null;
int protectionValue = 0;
if (mapping.getArmorType() != null) { if (mapping.getArmorType() != null) {
computeArmorProperties(mapping.getArmorType(), mapping.getProtectionValue(), itemProperties, componentBuilder); armorType = mapping.getArmorType();
protectionValue = customItemData.protectionValue() == -1 ? mapping.getProtectionValue() : customItemData.protectionValue();
} else if (customItemData.armorType() != null) {
armorType = customItemData.armorType();
// Using 0 as fallback here because the Java item doesn't have an armor type - so its protection value would be 0
protectionValue = customItemData.protectionValue() == -1 ? 0 : customItemData.protectionValue();
}
if (armorType != null) {
computeArmorProperties(armorType, protectionValue, itemProperties, componentBuilder);
} }
if (mapping.getFirstBlockRuntimeId() != null) { if (mapping.getFirstBlockRuntimeId() != null) {
computeBlockItemProperties(mapping.getBedrockIdentifier(), componentBuilder); computeBlockItemProperties(mapping.getBedrockIdentifier(), componentBuilder);
} }
if (mapping.isEdible()) { if (mapping.isEdible() || customItemData.isEdible()) {
computeConsumableProperties(itemProperties, componentBuilder, 1, false); computeConsumableProperties(itemProperties, componentBuilder, 1,
customItemData.canAlwaysEat());
} }
if (mapping.isEntityPlacer()) { if (mapping.isEntityPlacer()) {
computeEntityPlacerProperties(componentBuilder); computeEntityPlacerProperties(componentBuilder);
} }
if (customItemData.isFoil()) {
itemProperties.putBoolean("foil", true);
}
switch (mapping.getBedrockIdentifier()) { switch (mapping.getBedrockIdentifier()) {
case "minecraft:fire_charge", "minecraft:flint_and_steel" -> computeBlockItemProperties("minecraft:fire", componentBuilder); case "minecraft:fire_charge", "minecraft:flint_and_steel" -> computeBlockItemProperties("minecraft:fire", componentBuilder);
case "minecraft:bow", "minecraft:crossbow", "minecraft:trident" -> computeChargeableProperties(itemProperties, componentBuilder, mapping.getBedrockIdentifier(), protocolVersion); case "minecraft:bow", "minecraft:crossbow", "minecraft:trident" -> computeChargeableProperties(itemProperties, componentBuilder, mapping.getBedrockIdentifier(), protocolVersion);
@ -200,7 +219,7 @@ public class CustomItemRegistryPopulator {
} }
// Hardcoded on Java, and should extend to the custom item // Hardcoded on Java, and should extend to the custom item
boolean isHat = (javaItem.equals(Items.SKELETON_SKULL) || javaItem.equals(Items.WITHER_SKELETON_SKULL) boolean isHat = (customItemData.isHat() || javaItem.equals(Items.SKELETON_SKULL) || javaItem.equals(Items.WITHER_SKELETON_SKULL)
|| javaItem.equals(Items.CARVED_PUMPKIN) || javaItem.equals(Items.ZOMBIE_HEAD) || javaItem.equals(Items.CARVED_PUMPKIN) || javaItem.equals(Items.ZOMBIE_HEAD)
|| javaItem.equals(Items.PIGLIN_HEAD) || javaItem.equals(Items.DRAGON_HEAD) || javaItem.equals(Items.PIGLIN_HEAD) || javaItem.equals(Items.DRAGON_HEAD)
|| javaItem.equals(Items.CREEPER_HEAD) || javaItem.equals(Items.PLAYER_HEAD) || javaItem.equals(Items.CREEPER_HEAD) || javaItem.equals(Items.PLAYER_HEAD)
@ -213,26 +232,26 @@ public class CustomItemRegistryPopulator {
return builder; return builder;
} }
private static NbtMapBuilder createComponentNbt(NonVanillaCustomItemData customItemData, String customItemName, private static NbtMapBuilder createComponentNbt(NonVanillaCustomItemData customItemData, int customItemId, int protocolVersion) {
int customItemId, boolean isHat, boolean displayHandheld, int protocolVersion) {
NbtMapBuilder builder = NbtMap.builder(); NbtMapBuilder builder = NbtMap.builder();
builder.putString("name", customItemName) builder.putString("name", customItemData.identifier())
.putInt("id", customItemId); .putInt("id", customItemId);
NbtMapBuilder itemProperties = NbtMap.builder(); NbtMapBuilder itemProperties = NbtMap.builder();
NbtMapBuilder componentBuilder = NbtMap.builder(); NbtMapBuilder componentBuilder = NbtMap.builder();
setupBasicItemInfo(customItemData.maxDamage(), customItemData.stackSize(), displayHandheld, customItemData, itemProperties, componentBuilder, protocolVersion); setupBasicItemInfo(Math.max(customItemData.maxDamage(), 0), customItemData.stackSize() == 0 ? 64 : customItemData.stackSize(),
customItemData.displayHandheld(), customItemData, itemProperties, componentBuilder, protocolVersion);
boolean canDestroyInCreative = true; boolean canDestroyInCreative = true;
if (customItemData.toolType() != null) { // This is not using the isTool boolean because it is not just a render type here. if (customItemData.toolType() != null) { // This is not using the isTool boolean because it is not just a render type here.
canDestroyInCreative = computeToolProperties(Objects.requireNonNull(customItemData.toolType()), itemProperties, componentBuilder, customItemData.attackDamage()); canDestroyInCreative = computeToolProperties(Objects.requireNonNull(customItemData.toolType()), itemProperties, componentBuilder, Math.max(0, customItemData.attackDamage()));
} }
itemProperties.putBoolean("can_destroy_in_creative", canDestroyInCreative); itemProperties.putBoolean("can_destroy_in_creative", canDestroyInCreative);
String armorType = customItemData.armorType(); String armorType = customItemData.armorType();
if (armorType != null) { if (armorType != null) {
computeArmorProperties(armorType, customItemData.protectionValue(), itemProperties, componentBuilder); computeArmorProperties(armorType, Math.max(0, customItemData.protectionValue()), itemProperties, componentBuilder);
} }
if (customItemData.isEdible()) { if (customItemData.isEdible()) {
@ -247,7 +266,7 @@ public class CustomItemRegistryPopulator {
computeChargeableProperties(itemProperties, componentBuilder, "minecraft:" + tooltype, protocolVersion); computeChargeableProperties(itemProperties, componentBuilder, "minecraft:" + tooltype, protocolVersion);
} }
computeRenderOffsets(isHat, customItemData, componentBuilder); computeRenderOffsets(customItemData.isHat(), customItemData, componentBuilder);
if (customItemData.isFoil()) { if (customItemData.isFoil()) {
itemProperties.putBoolean("foil", true); itemProperties.putBoolean("foil", true);