Mapping option for handheld display & fix for #3346 (#3672)

* Mapping option for handheld display and fix for #3346

* Fix custom items
This commit is contained in:
ImDaBigBoss 2023-04-11 20:32:31 +02:00 committed by GitHub
parent d22ee51633
commit 98dceee5e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 106 additions and 26 deletions

View file

@ -68,6 +68,13 @@ public interface CustomItemData {
*/
boolean allowOffhand();
/**
* Gets if the item should be displayed as handheld, like a tool.
*
* @return true if the item should be displayed as handheld, false otherwise
*/
boolean displayHandheld();
/**
* Gets the item's texture size. This is to resize the item if the texture is not 16x16.
*
@ -100,6 +107,8 @@ public interface CustomItemData {
Builder allowOffhand(boolean allowOffhand);
Builder displayHandheld(boolean displayHandheld);
Builder textureSize(int textureSize);
Builder renderOffsets(@Nullable CustomRenderOffsets renderOffsets);

View file

@ -56,6 +56,14 @@ public interface CustomItemOptions {
*/
@NonNull OptionalInt damagePredicate();
/**
* Gets if this mapping should just translate to the default item.
* This is used for the damage predicate of damaged 1 damage 0 that is required to allow the default item to exist.
*
* @return true if this mapping should just translate to the default item, false otherwise
*/
boolean defaultItem();
/**
* Checks if the item has at least one option set
*
@ -78,6 +86,8 @@ public interface CustomItemOptions {
Builder damagePredicate(int damagePredicate);
Builder defaultItem(boolean defaultItem);
CustomItemOptions build();
}
}

View file

@ -130,17 +130,22 @@ public interface NonVanillaCustomItemData extends CustomItemData {
boolean isHat();
/**
* @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.
*
* @return if the item is a tool
*/
boolean isTool();
@Deprecated
default boolean isTool() {
return displayHandheld();
}
static NonVanillaCustomItemData.Builder builder() {
return GeyserApi.api().provider(NonVanillaCustomItemData.Builder.class);
}
interface Builder extends CustomItemData.Builder {
@Override
Builder name(@NonNull String name);
Builder identifier(@NonNull String identifier);
@ -169,14 +174,29 @@ public interface NonVanillaCustomItemData extends CustomItemData {
Builder hat(boolean isHat);
Builder tool(boolean isTool);
/**
* @deprecated Use {@link #displayHandheld(boolean)} instead.
*/
@Deprecated
default Builder tool(boolean isTool) {
return displayHandheld(isTool);
}
@Override
Builder customItemOptions(@NonNull CustomItemOptions customItemOptions);
@Override
Builder displayName(@NonNull String displayName);
@Override
Builder icon(@NonNull String icon);
@Override
Builder allowOffhand(boolean allowOffhand);
@Override
Builder displayHandheld(boolean displayHandheld);
@Override
Builder textureSize(int textureSize);

View file

@ -41,6 +41,7 @@ public class GeyserCustomItemData implements CustomItemData {
private final String displayName;
private final String icon;
private final boolean allowOffhand;
private final boolean displayHandheld;
private final int textureSize;
private final CustomRenderOffsets renderOffsets;
@ -49,6 +50,7 @@ public class GeyserCustomItemData implements CustomItemData {
String displayName,
String icon,
boolean allowOffhand,
boolean displayHandheld,
int textureSize,
CustomRenderOffsets renderOffsets) {
this.name = name;
@ -56,34 +58,47 @@ public class GeyserCustomItemData implements CustomItemData {
this.displayName = displayName;
this.icon = icon;
this.allowOffhand = allowOffhand;
this.displayHandheld = displayHandheld;
this.textureSize = textureSize;
this.renderOffsets = renderOffsets;
}
@Override
public @NotNull String name() {
return name;
}
@Override
public CustomItemOptions customItemOptions() {
return customItemOptions;
}
@Override
public @NotNull String displayName() {
return displayName;
}
@Override
public @NotNull String icon() {
return icon;
}
@Override
public boolean allowOffhand() {
return allowOffhand;
}
@Override
public boolean displayHandheld() {
return this.displayHandheld;
}
@Override
public int textureSize() {
return textureSize;
}
@Override
public CustomRenderOffsets renderOffsets() {
return renderOffsets;
}
@ -95,6 +110,7 @@ public class GeyserCustomItemData implements CustomItemData {
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 int textureSize = 16;
protected CustomRenderOffsets renderOffsets = null;
@ -128,6 +144,12 @@ public class GeyserCustomItemData implements CustomItemData {
return this;
}
@Override
public Builder displayHandheld(boolean displayHandheld) {
this.displayHandheld = displayHandheld;
return this;
}
@Override
public Builder textureSize(int textureSize) {
this.textureSize = textureSize;
@ -152,7 +174,7 @@ 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.textureSize, this.renderOffsets);
return new GeyserCustomItemData(this.name, this.customItemOptions, this.displayName, this.icon, this.allowOffhand, this.displayHandheld, this.textureSize, this.renderOffsets);
}
}
}

View file

@ -32,12 +32,18 @@ import java.util.OptionalInt;
public record GeyserCustomItemOptions(TriState unbreakable,
OptionalInt customModelData,
OptionalInt damagePredicate) implements CustomItemOptions {
OptionalInt damagePredicate,
boolean defaultItem) implements CustomItemOptions {
public GeyserCustomItemOptions(TriState unbreakable, OptionalInt customModelData, OptionalInt damagePredicate) {
this(unbreakable, customModelData, damagePredicate, false);
}
public static class CustomItemOptionsBuilder implements CustomItemOptions.Builder {
private TriState unbreakable = TriState.NOT_SET;
private OptionalInt customModelData = OptionalInt.empty();
private OptionalInt damagePredicate = OptionalInt.empty();
private boolean defaultItem = false;
@Override
public Builder unbreakable(boolean unbreakable) {
@ -61,9 +67,15 @@ public record GeyserCustomItemOptions(TriState unbreakable,
return this;
}
@Override
public Builder defaultItem(boolean defaultItem) {
this.defaultItem = defaultItem;
return this;
}
@Override
public CustomItemOptions build() {
return new GeyserCustomItemOptions(unbreakable, customModelData, damagePredicate);
return new GeyserCustomItemOptions(this.unbreakable, this.customModelData, this.damagePredicate, this.defaultItem);
}
}
}

View file

@ -57,7 +57,7 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
public GeyserNonVanillaCustomItemData(NonVanillaCustomItemDataBuilder builder) {
super(builder.name, builder.customItemOptions, builder.displayName, builder.icon, builder.allowOffhand,
builder.textureSize, builder.renderOffsets);
builder.displayHandheld, builder.textureSize, builder.renderOffsets);
this.identifier = builder.identifier;
this.javaId = builder.javaId;
@ -140,11 +140,6 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
return isHat;
}
@Override
public boolean isTool() {
return isTool;
}
public static class NonVanillaCustomItemDataBuilder extends GeyserCustomItemData.CustomItemDataBuilder implements NonVanillaCustomItemData.Builder {
private String identifier = null;
private int javaId = -1;
@ -185,6 +180,11 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
return (NonVanillaCustomItemData.Builder) super.allowOffhand(allowOffhand);
}
@Override
public NonVanillaCustomItemData.Builder displayHandheld(boolean displayHandheld) {
return (NonVanillaCustomItemData.Builder) super.displayHandheld(displayHandheld);
}
@Override
public NonVanillaCustomItemData.Builder displayName(@NonNull String displayName) {
return (NonVanillaCustomItemData.Builder) super.displayName(displayName);
@ -283,12 +283,6 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
return this;
}
@Override
public NonVanillaCustomItemData.Builder tool(boolean isTool) {
this.tool = isTool;
return this;
}
@Override
public NonVanillaCustomItemData build() {
if (identifier == null || javaId == -1) {

View file

@ -77,6 +77,11 @@ public class MappingsReader_v1 extends MappingsReader {
customItemOptions.unbreakable(unbreakable.asBoolean());
}
JsonNode defaultItem = node.get("default");
if (defaultItem != null && defaultItem.isBoolean()) {
customItemOptions.defaultItem(defaultItem.asBoolean());
}
return customItemOptions.build();
}
@ -86,13 +91,13 @@ public class MappingsReader_v1 extends MappingsReader {
throw new InvalidCustomMappingsFileException("Invalid item mappings entry");
}
String name = node.get("name").asText();
if (name == null || name.isEmpty()) {
JsonNode name = node.get("name");
if (name == null || !name.isTextual() || name.asText().isEmpty()) {
throw new InvalidCustomMappingsFileException("An item entry has no name");
}
CustomItemData.Builder customItemData = CustomItemData.builder()
.name(name)
.name(name.asText())
.customItemOptions(this.readItemCustomItemOptions(node));
//The next entries are optional
@ -108,6 +113,10 @@ public class MappingsReader_v1 extends MappingsReader {
customItemData.allowOffhand(node.get("allow_offhand").asBoolean());
}
if (node.has("display_handheld")) {
customItemData.displayHandheld(node.get("display_handheld").asBoolean());
}
if (node.has("texture_size")) {
customItemData.textureSize(node.get("texture_size").asInt());
}

View file

@ -153,7 +153,7 @@ public class CustomItemRegistryPopulator {
.build();
NbtMapBuilder builder = createComponentNbt(customItemData, customItemData.identifier(), customItemId,
customItemData.creativeCategory(), customItemData.creativeGroup(), customItemData.isHat(), customItemData.isTool());
customItemData.creativeCategory(), customItemData.creativeGroup(), customItemData.isHat(), customItemData.displayHandheld());
ComponentItemData componentItemData = new ComponentItemData(customIdentifier, builder.build());
return new NonVanillaItemRegistration(componentItemData, item, customItemMapping);
@ -168,7 +168,7 @@ public class CustomItemRegistryPopulator {
NbtMapBuilder itemProperties = NbtMap.builder();
NbtMapBuilder componentBuilder = NbtMap.builder();
setupBasicItemInfo(mapping.getMaxDamage(), mapping.getStackSize(), mapping.getToolType() != null, customItemData, itemProperties, componentBuilder);
setupBasicItemInfo(mapping.getMaxDamage(), mapping.getStackSize(), mapping.getToolType() != null || customItemData.displayHandheld(), customItemData, itemProperties, componentBuilder);
boolean canDestroyInCreative = true;
if (mapping.getToolType() != null) { // This is not using the isTool boolean because it is not just a render type here.
@ -217,7 +217,7 @@ public class CustomItemRegistryPopulator {
private static NbtMapBuilder createComponentNbt(NonVanillaCustomItemData customItemData, String customItemName,
int customItemId, OptionalInt creativeCategory,
String creativeGroup, boolean isHat, boolean isTool) {
String creativeGroup, boolean isHat, boolean displayHandheld) {
NbtMapBuilder builder = NbtMap.builder();
builder.putString("name", customItemName)
.putInt("id", customItemId);
@ -225,7 +225,7 @@ public class CustomItemRegistryPopulator {
NbtMapBuilder itemProperties = NbtMap.builder();
NbtMapBuilder componentBuilder = NbtMap.builder();
setupBasicItemInfo(customItemData.maxDamage(), customItemData.stackSize(), isTool, customItemData, itemProperties, componentBuilder);
setupBasicItemInfo(customItemData.maxDamage(), customItemData.stackSize(), displayHandheld, customItemData, itemProperties, componentBuilder);
boolean canDestroyInCreative = true;
if (customItemData.toolType() != null) { // This is not using the isTool boolean because it is not just a render type here.
@ -253,14 +253,14 @@ public class CustomItemRegistryPopulator {
return builder;
}
private static void setupBasicItemInfo(int maxDamage, int stackSize, boolean isTool, CustomItemData customItemData, NbtMapBuilder itemProperties, NbtMapBuilder componentBuilder) {
private static void setupBasicItemInfo(int maxDamage, int stackSize, boolean displayHandheld, CustomItemData customItemData, NbtMapBuilder itemProperties, NbtMapBuilder componentBuilder) {
itemProperties.putCompound("minecraft:icon", NbtMap.builder()
.putString("texture", customItemData.icon())
.build());
componentBuilder.putCompound("minecraft:display_name", NbtMap.builder().putString("value", customItemData.displayName()).build());
itemProperties.putBoolean("allow_off_hand", customItemData.allowOffhand());
itemProperties.putBoolean("hand_equipped", isTool);
itemProperties.putBoolean("hand_equipped", displayHandheld);
itemProperties.putInt("max_stack_size", stackSize);
// Ignore durability if the item's predicate requires that it be unbreakable
if (maxDamage > 0 && customItemData.customItemOptions().unbreakable() != TriState.TRUE) {

View file

@ -93,6 +93,10 @@ public final class CustomItemTranslator {
continue;
}
if (options.defaultItem()) {
return null;
}
return mappingTypes.value();
}