mojira.dev
MC-306998

Item Model Selection fails due to Type Mismatch in SelectItemModel Summary

I am not a native English speaker, so I used a translator for this message. I would appreciate your understanding.


Subject: Item Model Selection fails due to Type Mismatch in SelectItemModel

Summary:

When using minecraft:select with minecraft:component, the model fails to resolve if the data type of the value in the Item's component (e.g., Byte, Short) does not exactly match the type parsed from the JSON (typically Integer). This happens because the system relies on Object2ObjectOpenHashMap and Java's Object.equals(), which returns false for different Class types even if their numeric values are identical.


Detailed Description:

The issue lies in how SelectItemModel retrieves and compares values.

  1. Value Retrieval (ComponentContents.java):

    The get method fetches the raw object from the DataComponent. If a user provides a value like 1b or 1s, it returns a Byte or Short object.

    // ComponentContents.java
    public @Nullable T get(final ItemStack itemStack, ...) {
        return (T)itemStack.get(this.componentType); // Returns raw type (e.g., Byte)
    }
  2. Model Baking & Storage (SelectItemModel.java):

    During the baking process, JSON-defined cases are stored in a FastUtil map. Values parsed from JSON (like 1) are typically instantiated as Integer.

    // SelectItemModel.java
    Object2ObjectMap<T, ItemModel> bakedModels = new Object2ObjectOpenHashMap();
    for (T value : c.values) {
        bakedModels.put(value, bakedCaseModel); // Usually stores Integer keys
    }
  3. The Point of Failure (Object2ObjectOpenHashMap.java):

    The get method of the map uses Object.equals() to verify keys.

    // Object2ObjectOpenHashMap.java
    if ( ( (key[ pos ]) == null ? (k) == null : (key[ pos ]).equals(k) ) ) return value[ pos ];

    In Java, Integer.valueOf(1).equals(Byte.valueOf((byte)1)) is always false. Consequently, even though the numeric values match, the map lookup fails and returns the fallback model.


Steps to Reproduce:

  1. Create an item with a custom_data component containing a byte-type integer: /give @s bow[custom_data={id:1b}].

  2. Define an item model using minecraft:select pointing to minecraft:custom_data with a case for value: 1.

  3. Observe that the model does not change (it uses the fallback) because 1 (Integer) in JSON does not match 1b (Byte) in the item data.

Expected Behavior:

The selection logic should handle numeric type differences (e.g., by comparing .intValue() or using a more flexible comparison for numeric components) so that 1b, 1s, and 1 are treated as the same value for model selection.


Suggested Fix:

In SelectItemModel, instead of a raw object map lookup, the system should normalize numeric values before comparison, or use a custom comparator that handles different Number subclasses.


{
	"model": {
		"type": "minecraft:condition",
		"property": "minecraft:has_component",
		"component": "minecraft:custom_data",
		"on_true": {
			"type": "minecraft:composite",
			"models": [
				{
					"type": "minecraft:condition",
					"property": "minecraft:component",
					"predicate": "minecraft:custom_data",
					"value": {
						"id": "TESTID",
						"modifier": "test"
						"testnumber": 15
					},
					"on_true": {
						"type": "minecraft:model",
						"model": ".."
					},
					"on_false": {
						"type": "minecraft:model",
						"model": ".."
					}
				}
			]
		},
		"on_false": {
			"type": "minecraft:model",
			"model": ".."
		}
	}
}

While string values like id and modifier, or boolean values (0, 1) are correctly returned as true, testnumber is being returned as false even when the values match, which is causing a lot of trouble.

Linked issues

Comments 3

Since this issue has been marked as a 'Duplicate', could you please provide the ticket number of the original report? I would like to follow its progress. Thank you

SimSool

(Unassigned)

Unconfirmed

(Unassigned)

1.21.11

Retrieved