package net.minecraft.util.datafix.fixes; import com.google.common.base.Splitter; import com.mojang.datafixers.DataFix; import com.mojang.datafixers.DataFixUtils; import com.mojang.datafixers.TypeRewriteRule; import com.mojang.datafixers.schemas.Schema; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Dynamic; import com.mojang.serialization.DynamicOps; import com.mojang.serialization.MapLike; import com.mojang.serialization.OptionalDynamic; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.Map.Entry; import java.util.function.Function; import java.util.function.UnaryOperator; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.annotation.Nullable; import net.minecraft.util.Mth; import net.minecraft.util.datafix.ExtraDataFixUtils; import net.minecraft.util.datafix.LegacyComponentDataFixUtils; import net.minecraft.util.datafix.schemas.NamespacedSchema; public class ItemStackComponentizationFix extends DataFix { private static final int HIDE_ENCHANTMENTS = 1; private static final int HIDE_MODIFIERS = 2; private static final int HIDE_UNBREAKABLE = 4; private static final int HIDE_CAN_DESTROY = 8; private static final int HIDE_CAN_PLACE = 16; private static final int HIDE_ADDITIONAL = 32; private static final int HIDE_DYE = 64; private static final int HIDE_UPGRADES = 128; private static final Set POTION_HOLDER_IDS = Set.of("minecraft:potion", "minecraft:splash_potion", "minecraft:lingering_potion", "minecraft:tipped_arrow"); private static final Set BUCKETED_MOB_IDS = Set.of( "minecraft:pufferfish_bucket", "minecraft:salmon_bucket", "minecraft:cod_bucket", "minecraft:tropical_fish_bucket", "minecraft:axolotl_bucket", "minecraft:tadpole_bucket" ); private static final List BUCKETED_MOB_TAGS = List.of( "NoAI", "Silent", "NoGravity", "Glowing", "Invulnerable", "Health", "Age", "Variant", "HuntingCooldown", "BucketVariantTag" ); private static final Set BOOLEAN_BLOCK_STATE_PROPERTIES = Set.of( "attached", "bottom", "conditional", "disarmed", "drag", "enabled", "extended", "eye", "falling", "hanging", "has_bottle_0", "has_bottle_1", "has_bottle_2", "has_record", "has_book", "inverted", "in_wall", "lit", "locked", "occupied", "open", "persistent", "powered", "short", "signal_fire", "snowy", "triggered", "unstable", "waterlogged", "berries", "bloom", "shrieking", "can_summon", "up", "down", "north", "east", "south", "west", "slot_0_occupied", "slot_1_occupied", "slot_2_occupied", "slot_3_occupied", "slot_4_occupied", "slot_5_occupied", "cracked", "crafting" ); private static final Splitter PROPERTY_SPLITTER = Splitter.on(','); public ItemStackComponentizationFix(Schema p_331666_) { super(p_331666_, true); } private static void fixItemStack(ItemStackComponentizationFix.ItemStackData p_335726_, Dynamic p_329007_) { int i = p_335726_.removeTag("HideFlags").asInt(0); p_335726_.moveTagToComponent("Damage", "minecraft:damage", p_329007_.createInt(0)); p_335726_.moveTagToComponent("RepairCost", "minecraft:repair_cost", p_329007_.createInt(0)); p_335726_.moveTagToComponent("CustomModelData", "minecraft:custom_model_data"); p_335726_.removeTag("BlockStateTag").result().ifPresent(p_333568_ -> p_335726_.setComponent("minecraft:block_state", fixBlockStateTag((Dynamic)p_333568_))); p_335726_.moveTagToComponent("EntityTag", "minecraft:entity_data"); p_335726_.fixSubTag("BlockEntityTag", false, p_330163_ -> { String s = NamespacedSchema.ensureNamespaced(p_330163_.get("id").asString("")); p_330163_ = fixBlockEntityTag(p_335726_, p_330163_, s); Dynamic dynamic2 = p_330163_.remove("id"); return dynamic2.equals(p_330163_.emptyMap()) ? dynamic2 : p_330163_; }); p_335726_.moveTagToComponent("BlockEntityTag", "minecraft:block_entity_data"); if (p_335726_.removeTag("Unbreakable").asBoolean(false)) { Dynamic dynamic = p_329007_.emptyMap(); if ((i & 4) != 0) { dynamic = dynamic.set("show_in_tooltip", p_329007_.createBoolean(false)); } p_335726_.setComponent("minecraft:unbreakable", dynamic); } fixEnchantments(p_335726_, p_329007_, "Enchantments", "minecraft:enchantments", (i & 1) != 0); if (p_335726_.is("minecraft:enchanted_book")) { fixEnchantments(p_335726_, p_329007_, "StoredEnchantments", "minecraft:stored_enchantments", (i & 32) != 0); } p_335726_.fixSubTag("display", false, p_332023_ -> fixDisplay(p_335726_, p_332023_, i)); fixAdventureModeChecks(p_335726_, p_329007_, i); fixAttributeModifiers(p_335726_, p_329007_, i); Optional> optional = p_335726_.removeTag("Trim").result(); if (optional.isPresent()) { Dynamic dynamic1 = (Dynamic)optional.get(); if ((i & 128) != 0) { dynamic1 = dynamic1.set("show_in_tooltip", dynamic1.createBoolean(false)); } p_335726_.setComponent("minecraft:trim", dynamic1); } if ((i & 32) != 0) { p_335726_.setComponent("minecraft:hide_additional_tooltip", p_329007_.emptyMap()); } if (p_335726_.is("minecraft:crossbow")) { p_335726_.removeTag("Charged"); p_335726_.moveTagToComponent("ChargedProjectiles", "minecraft:charged_projectiles", p_329007_.createList(Stream.empty())); } if (p_335726_.is("minecraft:bundle")) { p_335726_.moveTagToComponent("Items", "minecraft:bundle_contents", p_329007_.createList(Stream.empty())); } if (p_335726_.is("minecraft:filled_map")) { p_335726_.moveTagToComponent("map", "minecraft:map_id"); Map, ? extends Dynamic> map = p_335726_.removeTag("Decorations") .asStream() .map(ItemStackComponentizationFix::fixMapDecoration) .collect(Collectors.toMap(Pair::getFirst, Pair::getSecond, (p_328286_, p_333385_) -> p_328286_)); if (!map.isEmpty()) { p_335726_.setComponent("minecraft:map_decorations", p_329007_.createMap(map)); } } if (p_335726_.is(POTION_HOLDER_IDS)) { fixPotionContents(p_335726_, p_329007_); } if (p_335726_.is("minecraft:writable_book")) { fixWritableBook(p_335726_, p_329007_); } if (p_335726_.is("minecraft:written_book")) { fixWrittenBook(p_335726_, p_329007_); } if (p_335726_.is("minecraft:suspicious_stew")) { p_335726_.moveTagToComponent("effects", "minecraft:suspicious_stew_effects"); } if (p_335726_.is("minecraft:debug_stick")) { p_335726_.moveTagToComponent("DebugProperty", "minecraft:debug_stick_state"); } if (p_335726_.is(BUCKETED_MOB_IDS)) { fixBucketedMobData(p_335726_, p_329007_); } if (p_335726_.is("minecraft:goat_horn")) { p_335726_.moveTagToComponent("instrument", "minecraft:instrument"); } if (p_335726_.is("minecraft:knowledge_book")) { p_335726_.moveTagToComponent("Recipes", "minecraft:recipes"); } if (p_335726_.is("minecraft:compass")) { fixLodestoneTracker(p_335726_, p_329007_); } if (p_335726_.is("minecraft:firework_rocket")) { fixFireworkRocket(p_335726_); } if (p_335726_.is("minecraft:firework_star")) { fixFireworkStar(p_335726_); } if (p_335726_.is("minecraft:player_head")) { p_335726_.removeTag("SkullOwner").result().ifPresent(p_328052_ -> p_335726_.setComponent("minecraft:profile", fixProfile((Dynamic)p_328052_))); } } private static Dynamic fixBlockStateTag(Dynamic p_329060_) { return DataFixUtils.orElse(p_329060_.asMapOpt().result().map(p_331937_ -> p_331937_.collect(Collectors.toMap(Pair::getFirst, p_330078_ -> { String s = ((Dynamic)p_330078_.getFirst()).asString(""); Dynamic dynamic = (Dynamic)p_330078_.getSecond(); if (BOOLEAN_BLOCK_STATE_PROPERTIES.contains(s)) { Optional optional = dynamic.asBoolean().result(); if (optional.isPresent()) { return dynamic.createString(String.valueOf(optional.get())); } } Optional optional1 = dynamic.asNumber().result(); return optional1.isPresent() ? dynamic.createString(optional1.get().toString()) : dynamic; }))).map(p_329060_::createMap), p_329060_); } private static Dynamic fixDisplay(ItemStackComponentizationFix.ItemStackData p_333136_, Dynamic p_329974_, int p_330088_) { p_333136_.setComponent("minecraft:custom_name", p_329974_.get("Name")); p_333136_.setComponent("minecraft:lore", p_329974_.get("Lore")); Optional optional = p_329974_.get("color").asNumber().result().map(Number::intValue); boolean flag = (p_330088_ & 64) != 0; if (optional.isPresent() || flag) { Dynamic dynamic = p_329974_.emptyMap().set("rgb", p_329974_.createInt(optional.orElse(10511680))); if (flag) { dynamic = dynamic.set("show_in_tooltip", p_329974_.createBoolean(false)); } p_333136_.setComponent("minecraft:dyed_color", dynamic); } Optional optional1 = p_329974_.get("LocName").asString().result(); if (optional1.isPresent()) { p_333136_.setComponent("minecraft:item_name", LegacyComponentDataFixUtils.createTranslatableComponent(p_329974_.getOps(), optional1.get())); } if (p_333136_.is("minecraft:filled_map")) { p_333136_.setComponent("minecraft:map_color", p_329974_.get("MapColor")); p_329974_ = p_329974_.remove("MapColor"); } return p_329974_.remove("Name").remove("Lore").remove("color").remove("LocName"); } private static Dynamic fixBlockEntityTag(ItemStackComponentizationFix.ItemStackData p_334120_, Dynamic p_332622_, String p_334133_) { p_334120_.setComponent("minecraft:lock", p_332622_.get("Lock")); p_332622_ = p_332622_.remove("Lock"); Optional> optional = p_332622_.get("LootTable").result(); if (optional.isPresent()) { Dynamic dynamic = p_332622_.emptyMap().set("loot_table", optional.get()); long i = p_332622_.get("LootTableSeed").asLong(0L); if (i != 0L) { dynamic = dynamic.set("seed", p_332622_.createLong(i)); } p_334120_.setComponent("minecraft:container_loot", dynamic); p_332622_ = p_332622_.remove("LootTable").remove("LootTableSeed"); } return switch (p_334133_) { case "minecraft:skull" -> { p_334120_.setComponent("minecraft:note_block_sound", p_332622_.get("note_block_sound")); yield p_332622_.remove("note_block_sound"); } case "minecraft:decorated_pot" -> { p_334120_.setComponent("minecraft:pot_decorations", p_332622_.get("sherds")); Optional> optional2 = p_332622_.get("item").result(); if (optional2.isPresent()) { p_334120_.setComponent( "minecraft:container", p_332622_.createList(Stream.of(p_332622_.emptyMap().set("slot", p_332622_.createInt(0)).set("item", optional2.get()))) ); } yield p_332622_.remove("sherds").remove("item"); } case "minecraft:banner" -> { p_334120_.setComponent("minecraft:banner_patterns", p_332622_.get("patterns")); Optional optional1 = p_332622_.get("Base").asNumber().result(); if (optional1.isPresent()) { p_334120_.setComponent("minecraft:base_color", p_332622_.createString(ExtraDataFixUtils.dyeColorIdToName(optional1.get().intValue()))); } yield p_332622_.remove("patterns").remove("Base"); } case "minecraft:shulker_box", "minecraft:chest", "minecraft:trapped_chest", "minecraft:furnace", "minecraft:ender_chest", "minecraft:dispenser", "minecraft:dropper", "minecraft:brewing_stand", "minecraft:hopper", "minecraft:barrel", "minecraft:smoker", "minecraft:blast_furnace", "minecraft:campfire", "minecraft:chiseled_bookshelf", "minecraft:crafter" -> { List> list = p_332622_.get("Items") .asList( p_334204_ -> p_334204_.emptyMap() .set("slot", p_334204_.createInt(p_334204_.get("Slot").asByte((byte)0) & 255)) .set("item", p_334204_.remove("Slot")) ); if (!list.isEmpty()) { p_334120_.setComponent("minecraft:container", p_332622_.createList(list.stream())); } yield p_332622_.remove("Items"); } case "minecraft:beehive" -> { p_334120_.setComponent("minecraft:bees", p_332622_.get("bees")); yield p_332622_.remove("bees"); } default -> p_332622_; }; } private static void fixEnchantments( ItemStackComponentizationFix.ItemStackData p_332552_, Dynamic p_328849_, String p_333260_, String p_334340_, boolean p_329498_ ) { OptionalDynamic optionaldynamic = p_332552_.removeTag(p_333260_); List> list = optionaldynamic.asList(Function.identity()) .stream() .flatMap(p_331550_ -> parseEnchantment((Dynamic)p_331550_).stream()) .toList(); if (!list.isEmpty() || p_329498_) { Dynamic dynamic = p_328849_.emptyMap(); Dynamic dynamic1 = p_328849_.emptyMap(); for (Pair pair : list) { dynamic1 = dynamic1.set(pair.getFirst(), p_328849_.createInt(pair.getSecond())); } dynamic = dynamic.set("levels", dynamic1); if (p_329498_) { dynamic = dynamic.set("show_in_tooltip", p_328849_.createBoolean(false)); } p_332552_.setComponent(p_334340_, dynamic); } if (optionaldynamic.result().isPresent() && list.isEmpty()) { p_332552_.setComponent("minecraft:enchantment_glint_override", p_328849_.createBoolean(true)); } } private static Optional> parseEnchantment(Dynamic p_328387_) { return p_328387_.get("id") .asString() .apply2stable((p_335475_, p_333076_) -> Pair.of(p_335475_, Mth.clamp(p_333076_.intValue(), 0, 255)), p_328387_.get("lvl").asNumber()) .result(); } private static void fixAdventureModeChecks(ItemStackComponentizationFix.ItemStackData p_328938_, Dynamic p_336252_, int p_331810_) { fixBlockStatePredicates(p_328938_, p_336252_, "CanDestroy", "minecraft:can_break", (p_331810_ & 8) != 0); fixBlockStatePredicates(p_328938_, p_336252_, "CanPlaceOn", "minecraft:can_place_on", (p_331810_ & 16) != 0); } private static void fixBlockStatePredicates( ItemStackComponentizationFix.ItemStackData p_331433_, Dynamic p_332377_, String p_332474_, String p_333138_, boolean p_334219_ ) { Optional> optional = p_331433_.removeTag(p_332474_).result(); if (!optional.isEmpty()) { Dynamic dynamic = p_332377_.emptyMap() .set( "predicates", p_332377_.createList( optional.get() .asStream() .map( p_336172_ -> DataFixUtils.orElse( p_336172_.asString().map(p_330317_ -> fixBlockStatePredicate((Dynamic)p_336172_, p_330317_)).result(), p_336172_ ) ) ) ); if (p_334219_) { dynamic = dynamic.set("show_in_tooltip", p_332377_.createBoolean(false)); } p_331433_.setComponent(p_333138_, dynamic); } } private static Dynamic fixBlockStatePredicate(Dynamic p_330250_, String p_335482_) { int i = p_335482_.indexOf(91); int j = p_335482_.indexOf(123); int k = p_335482_.length(); if (i != -1) { k = i; } if (j != -1) { k = Math.min(k, j); } String s = p_335482_.substring(0, k); Dynamic dynamic = p_330250_.emptyMap().set("blocks", p_330250_.createString(s.trim())); int l = p_335482_.indexOf(93); if (i != -1 && l != -1) { Dynamic dynamic1 = p_330250_.emptyMap(); for (String s1 : PROPERTY_SPLITTER.split(p_335482_.substring(i + 1, l))) { int i1 = s1.indexOf(61); if (i1 != -1) { String s2 = s1.substring(0, i1).trim(); String s3 = s1.substring(i1 + 1).trim(); dynamic1 = dynamic1.set(s2, p_330250_.createString(s3)); } } dynamic = dynamic.set("state", dynamic1); } int j1 = p_335482_.indexOf(125); if (j != -1 && j1 != -1) { dynamic = dynamic.set("nbt", p_330250_.createString(p_335482_.substring(j, j1 + 1))); } return dynamic; } private static void fixAttributeModifiers(ItemStackComponentizationFix.ItemStackData p_329869_, Dynamic p_332943_, int p_330062_) { OptionalDynamic optionaldynamic = p_329869_.removeTag("AttributeModifiers"); if (!optionaldynamic.result().isEmpty()) { boolean flag = (p_330062_ & 2) != 0; List> list = optionaldynamic.asList(ItemStackComponentizationFix::fixAttributeModifier); Dynamic dynamic = p_332943_.emptyMap().set("modifiers", p_332943_.createList(list.stream())); if (flag) { dynamic = dynamic.set("show_in_tooltip", p_332943_.createBoolean(false)); } p_329869_.setComponent("minecraft:attribute_modifiers", dynamic); } } private static Dynamic fixAttributeModifier(Dynamic p_330280_) { Dynamic dynamic = p_330280_.emptyMap() .set("name", p_330280_.createString("")) .set("amount", p_330280_.createDouble(0.0)) .set("operation", p_330280_.createString("add_value")); dynamic = Dynamic.copyField(p_330280_, "AttributeName", dynamic, "type"); dynamic = Dynamic.copyField(p_330280_, "Slot", dynamic, "slot"); dynamic = Dynamic.copyField(p_330280_, "UUID", dynamic, "uuid"); dynamic = Dynamic.copyField(p_330280_, "Name", dynamic, "name"); dynamic = Dynamic.copyField(p_330280_, "Amount", dynamic, "amount"); return Dynamic.copyAndFixField(p_330280_, "Operation", dynamic, "operation", p_334772_ -> { return p_334772_.createString(switch (p_334772_.asInt(0)) { case 1 -> "add_multiplied_base"; case 2 -> "add_multiplied_total"; default -> "add_value"; }); }); } private static Pair, Dynamic> fixMapDecoration(Dynamic p_329859_) { Dynamic dynamic = DataFixUtils.orElseGet(p_329859_.get("id").result(), () -> p_329859_.createString("")); Dynamic dynamic1 = p_329859_.emptyMap() .set("type", p_329859_.createString(fixMapDecorationType(p_329859_.get("type").asInt(0)))) .set("x", p_329859_.createDouble(p_329859_.get("x").asDouble(0.0))) .set("z", p_329859_.createDouble(p_329859_.get("z").asDouble(0.0))) .set("rotation", p_329859_.createFloat((float)p_329859_.get("rot").asDouble(0.0))); return Pair.of(dynamic, dynamic1); } private static String fixMapDecorationType(int p_328497_) { return switch (p_328497_) { case 1 -> "frame"; case 2 -> "red_marker"; case 3 -> "blue_marker"; case 4 -> "target_x"; case 5 -> "target_point"; case 6 -> "player_off_map"; case 7 -> "player_off_limits"; case 8 -> "mansion"; case 9 -> "monument"; case 10 -> "banner_white"; case 11 -> "banner_orange"; case 12 -> "banner_magenta"; case 13 -> "banner_light_blue"; case 14 -> "banner_yellow"; case 15 -> "banner_lime"; case 16 -> "banner_pink"; case 17 -> "banner_gray"; case 18 -> "banner_light_gray"; case 19 -> "banner_cyan"; case 20 -> "banner_purple"; case 21 -> "banner_blue"; case 22 -> "banner_brown"; case 23 -> "banner_green"; case 24 -> "banner_red"; case 25 -> "banner_black"; case 26 -> "red_x"; case 27 -> "village_desert"; case 28 -> "village_plains"; case 29 -> "village_savanna"; case 30 -> "village_snowy"; case 31 -> "village_taiga"; case 32 -> "jungle_temple"; case 33 -> "swamp_hut"; default -> "player"; }; } private static void fixPotionContents(ItemStackComponentizationFix.ItemStackData p_329173_, Dynamic p_331866_) { Dynamic dynamic = p_331866_.emptyMap(); Optional optional = p_329173_.removeTag("Potion").asString().result().filter(p_334871_ -> !p_334871_.equals("minecraft:empty")); if (optional.isPresent()) { dynamic = dynamic.set("potion", p_331866_.createString(optional.get())); } dynamic = p_329173_.moveTagInto("CustomPotionColor", dynamic, "custom_color"); dynamic = p_329173_.moveTagInto("custom_potion_effects", dynamic, "custom_effects"); if (!dynamic.equals(p_331866_.emptyMap())) { p_329173_.setComponent("minecraft:potion_contents", dynamic); } } private static void fixWritableBook(ItemStackComponentizationFix.ItemStackData p_332414_, Dynamic p_329764_) { Dynamic dynamic = fixBookPages(p_332414_, p_329764_); if (dynamic != null) { p_332414_.setComponent("minecraft:writable_book_content", p_329764_.emptyMap().set("pages", dynamic)); } } private static void fixWrittenBook(ItemStackComponentizationFix.ItemStackData p_333609_, Dynamic p_330312_) { Dynamic dynamic = fixBookPages(p_333609_, p_330312_); String s = p_333609_.removeTag("title").asString(""); Optional optional = p_333609_.removeTag("filtered_title").asString().result(); Dynamic dynamic1 = p_330312_.emptyMap(); dynamic1 = dynamic1.set("title", createFilteredText(p_330312_, s, optional)); dynamic1 = p_333609_.moveTagInto("author", dynamic1, "author"); dynamic1 = p_333609_.moveTagInto("resolved", dynamic1, "resolved"); dynamic1 = p_333609_.moveTagInto("generation", dynamic1, "generation"); if (dynamic != null) { dynamic1 = dynamic1.set("pages", dynamic); } p_333609_.setComponent("minecraft:written_book_content", dynamic1); } @Nullable private static Dynamic fixBookPages(ItemStackComponentizationFix.ItemStackData p_335763_, Dynamic p_328532_) { List list = p_335763_.removeTag("pages").asList(p_331615_ -> p_331615_.asString("")); Map map = p_335763_.removeTag("filtered_pages").asMap(p_335169_ -> p_335169_.asString("0"), p_329927_ -> p_329927_.asString("")); if (list.isEmpty()) { return null; } else { List> list1 = new ArrayList<>(list.size()); for (int i = 0; i < list.size(); i++) { String s = list.get(i); String s1 = map.get(String.valueOf(i)); list1.add(createFilteredText(p_328532_, s, Optional.ofNullable(s1))); } return p_328532_.createList(list1.stream()); } } private static Dynamic createFilteredText(Dynamic p_330363_, String p_328510_, Optional p_328222_) { Dynamic dynamic = p_330363_.emptyMap().set("raw", p_330363_.createString(p_328510_)); if (p_328222_.isPresent()) { dynamic = dynamic.set("filtered", p_330363_.createString(p_328222_.get())); } return dynamic; } private static void fixBucketedMobData(ItemStackComponentizationFix.ItemStackData p_328428_, Dynamic p_327719_) { Dynamic dynamic = p_327719_.emptyMap(); for (String s : BUCKETED_MOB_TAGS) { dynamic = p_328428_.moveTagInto(s, dynamic, s); } if (!dynamic.equals(p_327719_.emptyMap())) { p_328428_.setComponent("minecraft:bucket_entity_data", dynamic); } } private static void fixLodestoneTracker(ItemStackComponentizationFix.ItemStackData p_330486_, Dynamic p_329466_) { Optional> optional = p_330486_.removeTag("LodestonePos").result(); Optional> optional1 = p_330486_.removeTag("LodestoneDimension").result(); if (!optional.isEmpty() || !optional1.isEmpty()) { boolean flag = p_330486_.removeTag("LodestoneTracked").asBoolean(true); Dynamic dynamic = p_329466_.emptyMap(); if (optional.isPresent() && optional1.isPresent()) { dynamic = dynamic.set("target", p_329466_.emptyMap().set("pos", (Dynamic)optional.get()).set("dimension", (Dynamic)optional1.get())); } if (!flag) { dynamic = dynamic.set("tracked", p_329466_.createBoolean(false)); } p_330486_.setComponent("minecraft:lodestone_tracker", dynamic); } } private static void fixFireworkStar(ItemStackComponentizationFix.ItemStackData p_334817_) { p_334817_.fixSubTag("Explosion", true, p_334469_ -> { p_334817_.setComponent("minecraft:firework_explosion", fixFireworkExplosion(p_334469_)); return p_334469_.remove("Type").remove("Colors").remove("FadeColors").remove("Trail").remove("Flicker"); }); } private static void fixFireworkRocket(ItemStackComponentizationFix.ItemStackData p_329939_) { p_329939_.fixSubTag( "Fireworks", true, p_335612_ -> { Stream> stream = p_335612_.get("Explosions").asStream().map(ItemStackComponentizationFix::fixFireworkExplosion); int i = p_335612_.get("Flight").asInt(0); p_329939_.setComponent( "minecraft:fireworks", p_335612_.emptyMap().set("explosions", p_335612_.createList(stream)).set("flight_duration", p_335612_.createByte((byte)i)) ); return p_335612_.remove("Explosions").remove("Flight"); } ); } private static Dynamic fixFireworkExplosion(Dynamic p_327955_) { p_327955_ = p_327955_.set("shape", p_327955_.createString(switch (p_327955_.get("Type").asInt(0)) { case 1 -> "large_ball"; case 2 -> "star"; case 3 -> "creeper"; case 4 -> "burst"; default -> "small_ball"; })).remove("Type"); p_327955_ = p_327955_.renameField("Colors", "colors"); p_327955_ = p_327955_.renameField("FadeColors", "fade_colors"); p_327955_ = p_327955_.renameField("Trail", "has_trail"); return p_327955_.renameField("Flicker", "has_twinkle"); } public static Dynamic fixProfile(Dynamic p_331244_) { Optional optional = p_331244_.asString().result(); if (optional.isPresent()) { return isValidPlayerName(optional.get()) ? p_331244_.emptyMap().set("name", p_331244_.createString(optional.get())) : p_331244_.emptyMap(); } else { String s = p_331244_.get("Name").asString(""); Optional> optional1 = p_331244_.get("Id").result(); Dynamic dynamic = fixProfileProperties(p_331244_.get("Properties")); Dynamic dynamic1 = p_331244_.emptyMap(); if (isValidPlayerName(s)) { dynamic1 = dynamic1.set("name", p_331244_.createString(s)); } if (optional1.isPresent()) { dynamic1 = dynamic1.set("id", (Dynamic)optional1.get()); } if (dynamic != null) { dynamic1 = dynamic1.set("properties", dynamic); } return dynamic1; } } private static boolean isValidPlayerName(String p_332205_) { return p_332205_.length() > 16 ? false : p_332205_.chars().filter(p_331992_ -> p_331992_ <= 32 || p_331992_ >= 127).findAny().isEmpty(); } @Nullable private static Dynamic fixProfileProperties(OptionalDynamic p_329629_) { Map>>> map = p_329629_.asMap( p_330311_ -> p_330311_.asString(""), p_331808_ -> p_331808_.asList(p_329294_ -> { String s = p_329294_.get("Value").asString(""); Optional optional = p_329294_.get("Signature").asString().result(); return Pair.of(s, optional); }) ); return map.isEmpty() ? null : p_329629_.createList( map.entrySet() .stream() .flatMap( p_334576_ -> p_334576_.getValue() .stream() .map( p_335577_ -> { Dynamic dynamic = p_329629_.emptyMap() .set("name", p_329629_.createString(p_334576_.getKey())) .set("value", p_329629_.createString(p_335577_.getFirst())); Optional optional = p_335577_.getSecond(); return optional.isPresent() ? dynamic.set("signature", p_329629_.createString(optional.get())) : dynamic; } ) ) ); } @Override protected TypeRewriteRule makeRule() { return this.writeFixAndRead( "ItemStack componentization", this.getInputSchema().getType(References.ITEM_STACK), this.getOutputSchema().getType(References.ITEM_STACK), p_332668_ -> { Optional> optional = ItemStackComponentizationFix.ItemStackData.read(p_332668_).map(p_329220_ -> { fixItemStack(p_329220_, p_329220_.tag); return p_329220_.write(); }); return DataFixUtils.orElse(optional, p_332668_); } ); } static class ItemStackData { private final String item; private final int count; private Dynamic components; private final Dynamic remainder; Dynamic tag; private ItemStackData(String p_330519_, int p_328981_, Dynamic p_329116_) { this.item = NamespacedSchema.ensureNamespaced(p_330519_); this.count = p_328981_; this.components = p_329116_.emptyMap(); this.tag = p_329116_.get("tag").orElseEmptyMap(); this.remainder = p_329116_.remove("tag"); } public static Optional read(Dynamic p_327873_) { return p_327873_.get("id") .asString() .apply2stable( (p_336038_, p_334919_) -> new ItemStackComponentizationFix.ItemStackData( p_336038_, p_334919_.intValue(), p_327873_.remove("id").remove("Count") ), p_327873_.get("Count").asNumber() ) .result(); } public OptionalDynamic removeTag(String p_327670_) { OptionalDynamic optionaldynamic = this.tag.get(p_327670_); this.tag = this.tag.remove(p_327670_); return optionaldynamic; } public void setComponent(String p_334273_, Dynamic p_334484_) { this.components = this.components.set(p_334273_, p_334484_); } public void setComponent(String p_333518_, OptionalDynamic p_335463_) { p_335463_.result().ifPresent(p_334065_ -> this.components = this.components.set(p_333518_, (Dynamic)p_334065_)); } public Dynamic moveTagInto(String p_333380_, Dynamic p_332781_, String p_332207_) { Optional> optional = this.removeTag(p_333380_).result(); return optional.isPresent() ? p_332781_.set(p_332207_, (Dynamic)optional.get()) : p_332781_; } public void moveTagToComponent(String p_330725_, String p_334538_, Dynamic p_328097_) { Optional> optional = this.removeTag(p_330725_).result(); if (optional.isPresent() && !optional.get().equals(p_328097_)) { this.setComponent(p_334538_, (Dynamic)optional.get()); } } public void moveTagToComponent(String p_334513_, String p_335629_) { this.removeTag(p_334513_).result().ifPresent(p_331999_ -> this.setComponent(p_335629_, (Dynamic)p_331999_)); } public void fixSubTag(String p_334224_, boolean p_331760_, UnaryOperator> p_335156_) { OptionalDynamic optionaldynamic = this.tag.get(p_334224_); if (!p_331760_ || !optionaldynamic.result().isEmpty()) { Dynamic dynamic = optionaldynamic.orElseEmptyMap(); dynamic = p_335156_.apply(dynamic); if (dynamic.equals(dynamic.emptyMap())) { this.tag = this.tag.remove(p_334224_); } else { this.tag = this.tag.set(p_334224_, dynamic); } } } public Dynamic write() { Dynamic dynamic = this.tag .emptyMap() .set("id", this.tag.createString(this.item)) .set("count", this.tag.createInt(this.count)); if (!this.tag.equals(this.tag.emptyMap())) { this.components = this.components.set("minecraft:custom_data", this.tag); } if (!this.components.equals(this.tag.emptyMap())) { dynamic = dynamic.set("components", this.components); } return mergeRemainder(dynamic, this.remainder); } private static Dynamic mergeRemainder(Dynamic p_331283_, Dynamic p_335645_) { DynamicOps dynamicops = p_331283_.getOps(); return dynamicops.getMap(p_331283_.getValue()) .flatMap(p_335224_ -> dynamicops.mergeToMap(p_335645_.convert(dynamicops).getValue(), (MapLike)p_335224_)) .map(p_334956_ -> new Dynamic<>(dynamicops, (T)p_334956_)) .result() .orElse(p_331283_); } public boolean is(String p_328447_) { return this.item.equals(p_328447_); } public boolean is(Set p_332697_) { return p_332697_.contains(this.item); } public boolean hasComponent(String p_329543_) { return this.components.get(p_329543_).result().isPresent(); } } }