Compare commits

...

14 Commits

Author SHA1 Message Date
Eclipse 9f07442637
Merge 17c3b78bb4 into 6f4c29c834 2024-05-22 13:38:10 +02:00
gecko10000 6f4c29c834
Match Advancement Packet Behavior Towards Java (#4684)
* Send advancement packet regardless of current tab

* Send advancement close packet when single-advancement form closed
2024-05-22 11:26:32 +02:00
Camotoy 96bfda2ed3
Fix #4683 2024-05-21 20:37:18 -04:00
Eclipse 17c3b78bb4
Merge branch 'master' into customitemapi 2024-05-17 08:59:11 +00:00
Eclipse e8266fff03
Move tool property back to non vanilla custom item 2024-05-11 17:30:39 +00:00
Eclipse d31e94a7b1
Fix edible animation 2024-05-11 11:31:33 +00:00
Eclipse 0a7a06a044
Add new vanilla custom item properties to JSON reader, needs testing 2024-05-11 10:35:06 +00:00
Eclipse 22f5ad12a8
Add overrides for backwards compatibility (testing needed) and reorder a bit 2024-05-11 10:28:01 +00:00
Eclipse 86518d5f39
Merge remote-tracking branch 'upstream/master' into customitemapi 2024-05-11 10:10:35 +00:00
Eclipse 72da5a576b
Move translation string back to non vanilla and move hat to vanilla 2024-05-11 10:08:21 +00:00
Eclipse 965d11c7a1
Move armor type to super class and implement protection value and armor type in vanilla custom registry 2024-05-10 21:23:46 +00:00
Eclipse 97e1bebcbd
Implement logic for new vanilla custom item components in custom item registry 2024-05-10 21:08:21 +00:00
Eclipse 9cd847e1e9
Update implementations 2024-05-10 20:10:30 +00:00
Eclipse e6c9c519c9
Move some functionality from non vanilla custom items to vanilla custom items - updating implementation soon 2024-05-10 17:44:06 +00:00
8 changed files with 530 additions and 371 deletions

View File

@ -25,6 +25,7 @@
package org.geysermc.geyser.api.item.custom;
import org.checkerframework.checker.index.qual.NonNegative;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.api.GeyserApi;
@ -114,6 +115,92 @@ public interface CustomItemData {
*/
@NonNull Set<String> tags();
/**
* Gets the stack size of the item.
*
* Returns 0 if not set. When not set (or 0), takes the Java item stack count when based of a vanilla item, or uses 64 when porting a modded item.
*
* @return the stack size of the item
*/
@NonNegative
int stackSize();
/**
* Gets the max damage of the item.
*
* Returns -1 if not set. When not set (or below 0), takes the Java item max damage when based of a vanilla item, or uses 0 when porting a modded 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
*
* Returns 0 if not set. When 0, takes the Java item attack damage when based of a vanilla item, or uses 0 when porting a modded item.
*
* @return the attack damage of the item
*/
int attackDamage();
/**
* Gets the tool type of the item.
*
* @return the tool type of the item
*/
@Nullable String toolType();
/**
* Gets the tool tier of the item.
*
* @return the tool tier of the item
*/
@Nullable String toolTier();
/**
* Gets the armor type of the item.
*
* @return the armor type of the item
*/
@Nullable String armorType();
/**
* Gets the armor protection value of the item.
*
* @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() {
return GeyserApi.api().provider(CustomItemData.Builder.class);
}
@ -144,6 +231,28 @@ public interface CustomItemData {
Builder tags(@Nullable Set<String> tags);
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 hat(boolean isHat);
Builder foil(boolean isFoil);
Builder edible(boolean isEdible);
Builder canAlwaysEat(boolean canAlwaysEat);
CustomItemData build();
}
}

View File

@ -50,56 +50,6 @@ public interface NonVanillaCustomItemData extends CustomItemData {
*/
@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.
*
* @return the tool type of the item
*/
@Nullable String toolType();
/**
* Gets the tool tier of the item.
*
* @return the tool tier of the item
*/
@Nullable String toolTier();
/**
* Gets the armor type of the item.
*
* @return the armor type of the item
*/
@Nullable String armorType();
/**
* Gets the armor protection value of the item.
*
* @return the armor protection value of the item
*/
int protectionValue();
/**
* Gets the item's translation string.
*
@ -114,35 +64,6 @@ public interface NonVanillaCustomItemData extends CustomItemData {
*/
@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.
*
@ -150,6 +71,13 @@ public interface NonVanillaCustomItemData extends CustomItemData {
*/
boolean isChargeable();
/**
* Gets the block the item places.
*
* @return the block the item places
*/
String block();
/**
* @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.
@ -161,13 +89,6 @@ public interface NonVanillaCustomItemData extends CustomItemData {
return displayHandheld();
}
/**
* Gets the block the item places.
*
* @return the block the item places
*/
String block();
static NonVanillaCustomItemData.Builder builder() {
return GeyserApi.api().provider(NonVanillaCustomItemData.Builder.class);
}
@ -176,54 +97,6 @@ public interface NonVanillaCustomItemData extends CustomItemData {
@Override
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
Builder customItemOptions(@NonNull CustomItemOptions customItemOptions);
@ -239,6 +112,12 @@ public interface NonVanillaCustomItemData extends CustomItemData {
@Override
Builder displayHandheld(boolean displayHandheld);
@Override
Builder creativeCategory(int creativeCategory);
@Override
Builder creativeGroup(@Nullable String creativeGroup);
@Override
Builder textureSize(int textureSize);
@ -248,6 +127,59 @@ public interface NonVanillaCustomItemData extends CustomItemData {
@Override
Builder tags(@Nullable Set<String> tags);
@Override
Builder stackSize(@NonNegative int stackSize);
@Override
Builder maxDamage(int maxDamage);
@Override
Builder attackDamage(int attackDamage);
@Override
Builder toolType(@Nullable String toolType);
@Override
Builder toolTier(@Nullable String toolTier);
@Override
Builder armorType(@Nullable String armorType);
@Override
Builder protectionValue(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 translationString(@Nullable String translationString);
Builder repairMaterials(@Nullable Set<String> repairMaterials);
Builder chargeable(boolean isChargeable);
Builder block(String block);
NonVanillaCustomItemData build();
}
}

View File

@ -52,29 +52,41 @@ public class GeyserCustomItemData implements CustomItemData {
private final int textureSize;
private final CustomRenderOffsets renderOffsets;
private final Set<String> tags;
private final int stackSize;
private final int maxDamage;
private final int attackDamage;
private final String toolType;
private final String toolTier;
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,
CustomItemOptions customItemOptions,
String displayName,
String icon,
boolean allowOffhand,
boolean displayHandheld,
OptionalInt creativeCategory,
String creativeGroup,
int textureSize,
CustomRenderOffsets renderOffsets,
Set<String> tags) {
this.name = name;
this.customItemOptions = customItemOptions;
this.displayName = displayName;
this.icon = icon;
this.allowOffhand = allowOffhand;
this.displayHandheld = displayHandheld;
this.creativeCategory = creativeCategory;
this.creativeGroup = creativeGroup;
this.textureSize = textureSize;
this.renderOffsets = renderOffsets;
this.tags = tags;
public GeyserCustomItemData(Builder builder) {
this.name = builder.name;
this.customItemOptions = builder.customItemOptions;
this.displayName = builder.displayName;
this.icon = builder.icon;
this.allowOffhand = builder.allowOffhand;
this.displayHandheld = builder.displayHandheld;
this.creativeCategory = builder.creativeCategory;
this.creativeGroup = builder.creativeGroup;
this.textureSize = builder.textureSize;
this.renderOffsets = builder.renderOffsets;
this.tags = builder.tags;
this.stackSize = builder.stackSize;
this.maxDamage = builder.maxDamage;
this.attackDamage = builder.attackDamage;
this.toolType = builder.toolType;
this.toolTier = builder.toolTier;
this.armorType = builder.armorType;
this.protectionValue = builder.protectionValue;
this.isHat = builder.hat;
this.isFoil = builder.foil;
this.isEdible = builder.edible;
this.canAlwaysEat = builder.canAlwaysEat;
}
@Override
@ -132,6 +144,61 @@ public class GeyserCustomItemData implements CustomItemData {
return tags;
}
@Override
public int stackSize() {
return stackSize;
}
@Override
public int maxDamage() {
return maxDamage;
}
@Override
public int attackDamage() {
return attackDamage;
}
@Override
public String toolType() {
return toolType;
}
@Override
public String toolTier() {
return toolTier;
}
@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 {
protected String name = null;
protected CustomItemOptions customItemOptions = null;
@ -144,6 +211,17 @@ public class GeyserCustomItemData implements CustomItemData {
protected int textureSize = 16;
protected CustomRenderOffsets renderOffsets = null;
protected Set<String> tags = new HashSet<>();
private int stackSize = 0;
private int maxDamage = -1;
private int attackDamage = 0;
private String toolType = null;
private String toolTier = null;
private String armorType = null;
private int protectionValue = 0;
private boolean hat = false;
private boolean foil = false;
private boolean edible = false;
private boolean canAlwaysEat = false;
@Override
public Builder name(@NonNull String name) {
@ -211,6 +289,72 @@ public class GeyserCustomItemData implements CustomItemData {
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 Builder attackDamage(int attackDamage) {
this.attackDamage = attackDamage;
return this;
}
@Override
public Builder toolType(@Nullable String toolType) {
this.toolType = toolType;
return this;
}
@Override
public Builder toolTier(@Nullable String toolTier) {
this.toolTier = toolTier;
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
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
public CustomItemData build() {
if (this.name == null || this.customItemOptions == null) {
@ -223,8 +367,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.creativeCategory, this.creativeGroup, this.textureSize, this.renderOffsets, this.tags);
return new GeyserCustomItemData(this);
}
}
}

View File

@ -40,44 +40,18 @@ import java.util.Set;
public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData implements NonVanillaCustomItemData {
private final String identifier;
private final int javaId;
private final int stackSize;
private final int maxDamage;
private final int attackDamage;
private final String toolType;
private final String toolTier;
private final String armorType;
private final int protectionValue;
private final String translationString;
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 String block;
public GeyserNonVanillaCustomItemData(Builder builder) {
super(builder.name, builder.customItemOptions, builder.displayName, builder.icon, builder.allowOffhand,
builder.displayHandheld, builder.creativeCategory, builder.creativeGroup,
builder.textureSize, builder.renderOffsets, builder.tags);
super(builder);
this.identifier = builder.identifier;
this.javaId = builder.javaId;
this.stackSize = builder.stackSize;
this.maxDamage = builder.maxDamage;
this.attackDamage = builder.attackDamage;
this.toolType = builder.toolType;
this.toolTier = builder.toolTier;
this.armorType = builder.armorType;
this.protectionValue = builder.protectionValue;
this.translationString = builder.translationString;
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.block = builder.block;
}
@ -92,41 +66,6 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
return javaId;
}
@Override
public int stackSize() {
return stackSize;
}
@Override
public int maxDamage() {
return maxDamage;
}
@Override
public int attackDamage() {
return attackDamage;
}
@Override
public String toolType() {
return toolType;
}
@Override
public String toolTier() {
return toolTier;
}
@Override
public @Nullable String armorType() {
return armorType;
}
@Override
public int protectionValue() {
return protectionValue;
}
@Override
public String translationString() {
return translationString;
@ -137,26 +76,6 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
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
public boolean isChargeable() {
return isChargeable;
@ -170,28 +89,8 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
public static class Builder extends GeyserCustomItemData.Builder implements NonVanillaCustomItemData.Builder {
private String identifier = null;
private int javaId = -1;
private int stackSize = 64;
private int maxDamage = 0;
private int attackDamage = 0;
private String toolType = null;
private String toolTier = null;
private String armorType = null;
private int protectionValue = 0;
private String translationString;
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 String block = null;
@ -206,6 +105,16 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
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
public Builder allowOffhand(boolean allowOffhand) {
return (Builder) super.allowOffhand(allowOffhand);
@ -217,13 +126,13 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
}
@Override
public Builder displayName(@NonNull String displayName) {
return (Builder) super.displayName(displayName);
public Builder creativeCategory(int creativeCategory) {
return (Builder) super.creativeCategory(creativeCategory);
}
@Override
public Builder icon(@NonNull String icon) {
return (Builder) super.icon(icon);
public Builder creativeGroup(@Nullable String creativeGroup) {
return (Builder) super.creativeGroup(creativeGroup);
}
@Override
@ -241,6 +150,61 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
return (Builder) super.tags(tags);
}
@Override
public Builder stackSize(int stackSize) {
return (Builder) super.stackSize(stackSize);
}
@Override
public Builder maxDamage(int maxDamage) {
return (Builder) super.maxDamage(maxDamage);
}
@Override
public Builder attackDamage(int attackDamage) {
return (Builder) super.attackDamage(attackDamage);
}
@Override
public Builder toolType(@Nullable String toolType) {
return (Builder) super.toolType(toolType);
}
@Override
public Builder toolTier(@Nullable String toolTier) {
return (Builder) super.toolTier(toolTier);
}
@Override
public Builder armorType(@Nullable String armorType) {
return (Builder) super.armorType(armorType);
}
@Override
public Builder protectionValue(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
public Builder identifier(@NonNull String identifier) {
this.identifier = identifier;
@ -253,48 +217,6 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
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
public Builder toolType(@Nullable String toolType) {
this.toolType = toolType;
return this;
}
@Override
public Builder toolTier(@Nullable String toolTier) {
this.toolTier = toolTier;
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
public Builder translationString(@Nullable String translationString) {
this.translationString = translationString;
@ -307,40 +229,6 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
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
public Builder chargeable(boolean isChargeable) {
this.chargeable = isChargeable;

View File

@ -225,6 +225,50 @@ public class MappingsReader_v1 extends MappingsReader {
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.maxDamage(node.get("attack_damage").asInt());
}
if (node.has("tool_type")) {
customItemData.toolType(node.get("tool_type").asText());
}
if (node.has("tool_tier")) {
customItemData.toolTier(node.get("tool_tier").asText());
}
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();
}

View File

@ -131,8 +131,8 @@ public class CustomItemRegistryPopulator {
Set<String> repairMaterials = customItemData.repairMaterials();
Item.Builder itemBuilder = Item.builder()
.stackSize(customItemData.stackSize())
.maxDamage(customItemData.maxDamage());
.stackSize(customItemData.stackSize() == 0 ? 64 : customItemData.stackSize())
.maxDamage(Math.max(customItemData.maxDamage(), 0));
Item item = new Item(customIdentifier, itemBuilder) {
@Override
public boolean isValidRepairItem(Item other) {
@ -153,7 +153,7 @@ public class CustomItemRegistryPopulator {
.build();
NbtMapBuilder builder = createComponentNbt(customItemData, customItemData.identifier(), customItemId,
customItemData.isHat(), customItemData.displayHandheld(), protocolVersion);
customItemData.displayHandheld(), protocolVersion);
ComponentItemData componentItemData = new ComponentItemData(customIdentifier, builder.build());
return new NonVanillaItemRegistration(componentItemData, item, customItemMapping);
@ -168,39 +168,66 @@ public class CustomItemRegistryPopulator {
NbtMapBuilder itemProperties = 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;
if (mapping.getToolType() != null) { // This is not using the isTool boolean because it is not just a render type here.
canDestroyInCreative = computeToolProperties(mapping.getToolType(), itemProperties, componentBuilder, javaItem.attackDamage());
String toolType = null;
if (mapping.getToolType() != null) {
toolType = mapping.getToolType();
} else if (customItemData.toolType() != null) {
toolType = customItemData.toolType();
}
if (toolType != null) {
canDestroyInCreative = computeToolProperties(toolType, itemProperties, componentBuilder,
customItemData.attackDamage() == 0 ? javaItem.attackDamage() : customItemData.attackDamage());
}
itemProperties.putBoolean("can_destroy_in_creative", canDestroyInCreative);
String armorType = null;
int protectionValue = 0;
if (mapping.getArmorType() != null) {
computeArmorProperties(mapping.getArmorType(), mapping.getProtectionValue(), itemProperties, componentBuilder);
armorType = mapping.getArmorType();
protectionValue = mapping.getProtectionValue();
} else if (customItemData.armorType() != null) {
armorType = customItemData.armorType();
protectionValue = customItemData.protectionValue();
}
if (armorType != null) {
computeArmorProperties(armorType, protectionValue, itemProperties, componentBuilder);
}
if (mapping.getFirstBlockRuntimeId() != null) {
computeBlockItemProperties(mapping.getBedrockIdentifier(), componentBuilder);
}
if (mapping.isEdible()) {
computeConsumableProperties(itemProperties, componentBuilder, 1, false);
if (mapping.isEdible() || customItemData.isEdible()) {
computeConsumableProperties(itemProperties, componentBuilder, 1,
customItemData.canAlwaysEat(), protocolVersion);
}
if (mapping.isEntityPlacer()) {
computeEntityPlacerProperties(componentBuilder);
}
if (customItemData.isFoil()) {
itemProperties.putBoolean("foil", true);
}
switch (mapping.getBedrockIdentifier()) {
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:honey_bottle", "minecraft:milk_bucket", "minecraft:potion" -> computeConsumableProperties(itemProperties, componentBuilder, 2, true);
case "minecraft:honey_bottle", "minecraft:milk_bucket", "minecraft:potion" -> computeConsumableProperties(itemProperties, componentBuilder, 2, true, protocolVersion);
case "minecraft:experience_bottle", "minecraft:egg", "minecraft:ender_pearl", "minecraft:ender_eye", "minecraft:lingering_potion", "minecraft:snowball", "minecraft:splash_potion" ->
computeThrowableProperties(componentBuilder);
}
computeRenderOffsets(false, customItemData, componentBuilder);
computeRenderOffsets(customItemData.isHat(), customItemData, componentBuilder);
componentBuilder.putCompound("item_properties", itemProperties.build());
builder.putCompound("components", componentBuilder.build());
@ -209,7 +236,7 @@ public class CustomItemRegistryPopulator {
}
private static NbtMapBuilder createComponentNbt(NonVanillaCustomItemData customItemData, String customItemName,
int customItemId, boolean isHat, boolean displayHandheld, int protocolVersion) {
int customItemId, boolean displayHandheld, int protocolVersion) {
NbtMapBuilder builder = NbtMap.builder();
builder.putString("name", customItemName)
.putInt("id", customItemId);
@ -217,7 +244,8 @@ public class CustomItemRegistryPopulator {
NbtMapBuilder itemProperties = 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(),
displayHandheld, customItemData, itemProperties, componentBuilder, protocolVersion);
boolean canDestroyInCreative = true;
if (customItemData.toolType() != null) { // This is not using the isTool boolean because it is not just a render type here.
@ -231,7 +259,7 @@ public class CustomItemRegistryPopulator {
}
if (customItemData.isEdible()) {
computeConsumableProperties(itemProperties, componentBuilder, 1, customItemData.canAlwaysEat());
computeConsumableProperties(itemProperties, componentBuilder, 1, customItemData.canAlwaysEat(), protocolVersion);
}
if (customItemData.isChargeable()) {
@ -242,7 +270,7 @@ public class CustomItemRegistryPopulator {
computeChargeableProperties(itemProperties, componentBuilder, "minecraft:" + tooltype, protocolVersion);
}
computeRenderOffsets(isHat, customItemData, componentBuilder);
computeRenderOffsets(customItemData.isHat(), customItemData, componentBuilder);
if (customItemData.isFoil()) {
itemProperties.putBoolean("foil", true);
@ -488,7 +516,8 @@ public class CustomItemRegistryPopulator {
}
}
private static void computeConsumableProperties(NbtMapBuilder itemProperties, NbtMapBuilder componentBuilder, int useAnimation, boolean canAlwaysEat) {
private static void computeConsumableProperties(NbtMapBuilder itemProperties, NbtMapBuilder componentBuilder,
int useAnimation, boolean canAlwaysEat, int protocolVersion) {
// this is the duration of the use animation in ticks; note that in behavior packs this is set as a float in seconds, but over the network it is an int in ticks
itemProperties.putInt("use_duration", 32);
// this dictates that the item will use the eat or drink animation (in the first person) and play eat or drink sounds
@ -496,6 +525,13 @@ public class CustomItemRegistryPopulator {
itemProperties.putInt("use_animation", useAnimation);
// this component is required to allow the eat animation to play
componentBuilder.putCompound("minecraft:food", NbtMap.builder().putBoolean("can_always_eat", canAlwaysEat).build());
if (GameProtocol.is1_20_60orHigher(protocolVersion)) {
componentBuilder.putCompound("minecraft:use_modifiers", NbtMap.builder()
.putFloat("use_duration", 100F)
.putFloat("movement_modifier", 0.35F)
.build());
}
}
private static void computeEntityPlacerProperties(NbtMapBuilder componentBuilder) {

View File

@ -91,11 +91,9 @@ public class AdvancementsCache {
builder.validResultHandler((response) -> {
String id = rootAdvancementIds.get(response.clickedButtonId());
if (!id.equals("")) {
if (!id.equals(currentAdvancementCategoryId)) {
// Send a packet indicating that we are opening this particular advancement window
ServerboundSeenAdvancementsPacket packet = new ServerboundSeenAdvancementsPacket(id);
session.sendDownstreamGamePacket(packet);
}
// Send a packet indicating that we are opening this particular advancement window
ServerboundSeenAdvancementsPacket packet = new ServerboundSeenAdvancementsPacket(id);
session.sendDownstreamGamePacket(packet);
currentAdvancementCategoryId = id;
buildAndShowListForm();
}
@ -188,6 +186,10 @@ public class AdvancementsCache {
.content(content)
.button(GeyserLocale.getPlayerLocaleString("gui.back", language))
.validResultHandler((response) -> buildAndShowListForm())
.closedResultHandler(() -> {
// Indicate that we have closed the current advancement tab
session.sendDownstreamGamePacket(new ServerboundSeenAdvancementsPacket());
})
);
}

View File

@ -28,7 +28,6 @@ package org.geysermc.geyser.session.cache;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.GlobalPos;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.LodestoneTracker;
@ -53,11 +52,13 @@ public final class LodestoneCache {
private int id = 1;
public void cacheInventoryItem(GeyserItemStack itemStack, LodestoneTracker tracker) {
GlobalPos position = tracker.getPos();
if (!tracker.isTracked()) {
return;
}
GlobalPos position = tracker.getPos();
if (position == null) {
GeyserImpl.getInstance().getLogger().error("Position is null. Find out why.");
Thread.dumpStack();
// As of 1.20.6, position can still be null even if tracking is enabled.
return;
}
int x = position.getX();
@ -84,13 +85,16 @@ public final class LodestoneCache {
}
public int store(LodestoneTracker tracker) {
GlobalPos position = tracker.getPos();
if (position == null) {
GeyserImpl.getInstance().getLogger().error("Position is null. Find out why.");
Thread.dumpStack();
return -1;
if (!tracker.isTracked()) {
// No coordinates; nothing to convert
return 0;
}
GlobalPos position = tracker.getPos();
if (position == null) {
return 0;
}
int x = position.getX();
int y = position.getY();
int z = position.getZ();