mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 11:06:11 -10:00
NeoForge oracle: export items' data components and armour facts
Each item now carries its default components (vanilla's codecs, 1.21.1's form), its effective attribute modifiers (armour's come from a method, not a component), enchantability and repair items, and for armour its slot, defense, toughness, knockback resistance, equip sound and texture layers: the ground truth an item port is compared against. The export also creates its output folder instead of failing to write. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
5c66b27c9a
commit
df96b6787d
3 files changed
+74
-1
No files matched your search
+3
-1
@@ -759,7 +759,9 @@ python3 tools/mod_port_harness.py --work <work> # or --jars/--deps to expor
|
||||
namespaces and every vanilla block: the class chain, states, per-state hardness, light, tool
|
||||
need, map colour, sounds, outline and collision shapes; drops for hand, diamond tools, shears
|
||||
and silk touch; placement on a floor and a wall; BlockSetType and WoodType. Then items (class,
|
||||
stack size, rarity, food), recipes (type, result, count, resolved ingredients) and tags. One run
|
||||
stack size, rarity, food; every default data component in 1.21.1's form, the effective attribute
|
||||
modifiers, enchantability and repair items; armour's slot, defense, toughness, knockback resistance,
|
||||
equip sound and texture layers), recipes (type, result, count, resolved ingredients) and tags. One run
|
||||
with the seven mods below takes about 30 s.
|
||||
- `crates/horizon-client/examples/mod_port_probe.rs` builds the content root from the carried
|
||||
mods and dumps what Horizon's loaders make of the same blocks, drops, recipes and tags.
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package dev.horizonlab.neoforge;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import com.mojang.serialization.DataResult;
|
||||
import com.mojang.serialization.DynamicOps;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -16,6 +20,7 @@ import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.component.TypedDataComponent;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
@@ -23,10 +28,14 @@ import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.item.ArmorItem;
|
||||
import net.minecraft.world.item.ArmorMaterial;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.TieredItem;
|
||||
import net.minecraft.world.item.component.ItemAttributeModifiers;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
import net.minecraft.world.item.crafting.Ingredient;
|
||||
import net.minecraft.world.item.crafting.RecipeHolder;
|
||||
@@ -346,11 +355,72 @@ public final class FactsExporter {
|
||||
json.name("saturation").value(food.saturation());
|
||||
json.endObject();
|
||||
}
|
||||
itemComponents(item, stack);
|
||||
json.endObject();
|
||||
}
|
||||
json.endObject();
|
||||
}
|
||||
|
||||
// The item's own numbers in 1.21.1's forms: its default components, and what it keeps outside them.
|
||||
void itemComponents(Item item, ItemStack stack) throws IOException {
|
||||
DynamicOps<JsonElement> ops = server.registryAccess().createSerializationContext(JsonOps.INSTANCE);
|
||||
json.name("components");
|
||||
json.beginObject();
|
||||
for (TypedDataComponent<?> c : stack.getComponents()) {
|
||||
var encoded = c.encodeValue(ops).result();
|
||||
if (encoded.isPresent()) {
|
||||
json.name(BuiltInRegistries.DATA_COMPONENT_TYPE.getKey(c.type()).toString());
|
||||
json.jsonValue(encoded.get().toString());
|
||||
}
|
||||
}
|
||||
json.endObject();
|
||||
// Armor's come from ArmorItem.getDefaultAttributeModifiers, not a component.
|
||||
raw("attribute_modifiers", ItemAttributeModifiers.CODEC.encodeStart(ops, stack.getAttributeModifiers()));
|
||||
json.name("enchantment_value").value(item.getEnchantmentValue());
|
||||
Ingredient repair = null;
|
||||
if (item instanceof TieredItem tiered) {
|
||||
repair = tiered.getTier().getRepairIngredient();
|
||||
} else if (item instanceof ArmorItem armor) {
|
||||
repair = armor.getMaterial().value().repairIngredient().get();
|
||||
}
|
||||
if (repair != null) {
|
||||
json.name("repair_items");
|
||||
json.beginArray();
|
||||
for (ItemStack s : repair.getItems()) json.value(BuiltInRegistries.ITEM.getKey(s.getItem()).toString());
|
||||
json.endArray();
|
||||
}
|
||||
if (item instanceof ArmorItem armor) {
|
||||
ArmorMaterial material = armor.getMaterial().value();
|
||||
json.name("armor");
|
||||
json.beginObject();
|
||||
json.name("slot").value(armor.getEquipmentSlot().getName());
|
||||
json.name("material").value(armor.getMaterial().unwrapKey().map(k -> k.location().toString()).orElse(""));
|
||||
json.name("defense").value(armor.getDefense());
|
||||
json.name("toughness").value(armor.getToughness());
|
||||
json.name("knockback_resistance").value(material.knockbackResistance());
|
||||
json.name("equip_sound").value(BuiltInRegistries.SOUND_EVENT.getKey(material.equipSound().value()).toString());
|
||||
json.name("layers");
|
||||
json.beginArray();
|
||||
for (ArmorMaterial.Layer layer : material.layers()) {
|
||||
json.beginObject();
|
||||
json.name("texture").value(layer.texture(false).toString());
|
||||
json.name("texture_legs").value(layer.texture(true).toString());
|
||||
json.name("dyeable").value(layer.dyeable());
|
||||
json.endObject();
|
||||
}
|
||||
json.endArray();
|
||||
json.endObject();
|
||||
}
|
||||
}
|
||||
|
||||
void raw(String name, DataResult<JsonElement> encoded) throws IOException {
|
||||
var value = encoded.result();
|
||||
if (value.isPresent()) {
|
||||
json.name(name);
|
||||
json.jsonValue(value.get().toString());
|
||||
}
|
||||
}
|
||||
|
||||
void recipes() throws IOException {
|
||||
json.name("recipes");
|
||||
json.beginObject();
|
||||
|
||||
@@ -215,6 +215,7 @@ def export(args):
|
||||
exporter = build(home)
|
||||
home, run = instance('export', jars, [*deps, exporter])
|
||||
out = Path(args.out).resolve()
|
||||
out.parent.mkdir(parents=True, exist_ok=True)
|
||||
out.unlink(missing_ok=True)
|
||||
seconds, log = start(home, run, {'horizon.oracle.out': out, 'horizon.oracle.namespaces': namespaces})
|
||||
if not out.exists():
|
||||
|
||||
Reference in new issue
Block a user