package net.minecraft.util.datafix.fixes; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.datafixers.DataFix; import com.mojang.datafixers.TypeRewriteRule; import com.mojang.datafixers.schemas.Schema; import com.mojang.datafixers.types.Type; import com.mojang.logging.LogUtils; import com.mojang.serialization.Dynamic; import com.mojang.serialization.DynamicOps; import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.stream.IntStream; import java.util.stream.Stream; import net.minecraft.nbt.TagParser; import net.minecraft.util.Mth; import net.minecraft.util.datafix.schemas.NamespacedSchema; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; public class ParticleUnflatteningFix extends DataFix { private static final Logger LOGGER = LogUtils.getLogger(); public ParticleUnflatteningFix(Schema outputSchema) { super(outputSchema, true); } @Override protected TypeRewriteRule makeRule() { Type type = this.getInputSchema().getType(References.PARTICLE); Type type2 = this.getOutputSchema().getType(References.PARTICLE); return this.writeFixAndRead("ParticleUnflatteningFix", type, type2, this::fix); } private Dynamic fix(Dynamic tag) { Optional optional = tag.asString().result(); if (optional.isEmpty()) { return tag; } else { String string = (String)optional.get(); String[] strings = string.split(" ", 2); String string2 = NamespacedSchema.ensureNamespaced(strings[0]); Dynamic dynamic = tag.createMap(Map.of(tag.createString("type"), tag.createString(string2))); return switch (string2) { case "minecraft:item" -> strings.length > 1 ? this.updateItem(dynamic, strings[1]) : dynamic; case "minecraft:block", "minecraft:block_marker", "minecraft:falling_dust", "minecraft:dust_pillar" -> strings.length > 1 ? this.updateBlock(dynamic, strings[1]) : dynamic; case "minecraft:dust" -> strings.length > 1 ? this.updateDust(dynamic, strings[1]) : dynamic; case "minecraft:dust_color_transition" -> strings.length > 1 ? this.updateDustTransition(dynamic, strings[1]) : dynamic; case "minecraft:sculk_charge" -> strings.length > 1 ? this.updateSculkCharge(dynamic, strings[1]) : dynamic; case "minecraft:vibration" -> strings.length > 1 ? this.updateVibration(dynamic, strings[1]) : dynamic; case "minecraft:shriek" -> strings.length > 1 ? this.updateShriek(dynamic, strings[1]) : dynamic; default -> dynamic; }; } } private Dynamic updateItem(Dynamic tag, String item) { int i = item.indexOf("{"); Dynamic dynamic = tag.createMap(Map.of(tag.createString("Count"), tag.createInt(1))); if (i == -1) { dynamic = dynamic.set("id", tag.createString(item)); } else { dynamic = dynamic.set("id", tag.createString(item.substring(0, i))); Dynamic dynamic2 = parseTag(tag.getOps(), item.substring(i)); if (dynamic2 != null) { dynamic = dynamic.set("tag", dynamic2); } } return tag.set("item", dynamic); } @Nullable private static Dynamic parseTag(DynamicOps ops, String tag) { try { return new Dynamic<>(ops, TagParser.create(ops).parseFully(tag)); } catch (Exception var3) { LOGGER.warn("Failed to parse tag: {}", tag, var3); return null; } } private Dynamic updateBlock(Dynamic tag, String block) { int i = block.indexOf("["); Dynamic dynamic = tag.emptyMap(); if (i == -1) { dynamic = dynamic.set("Name", tag.createString(NamespacedSchema.ensureNamespaced(block))); } else { dynamic = dynamic.set("Name", tag.createString(NamespacedSchema.ensureNamespaced(block.substring(0, i)))); Map, Dynamic> map = parseBlockProperties(tag, block.substring(i)); if (!map.isEmpty()) { dynamic = dynamic.set("Properties", tag.createMap(map)); } } return tag.set("block_state", dynamic); } private static Map, Dynamic> parseBlockProperties(Dynamic tag, String properties) { try { Map, Dynamic> map = new HashMap(); StringReader stringReader = new StringReader(properties); stringReader.expect('['); stringReader.skipWhitespace(); while (stringReader.canRead() && stringReader.peek() != ']') { stringReader.skipWhitespace(); String string = stringReader.readString(); stringReader.skipWhitespace(); stringReader.expect('='); stringReader.skipWhitespace(); String string2 = stringReader.readString(); stringReader.skipWhitespace(); map.put(tag.createString(string), tag.createString(string2)); if (stringReader.canRead()) { if (stringReader.peek() != ',') { break; } stringReader.skip(); } } stringReader.expect(']'); return map; } catch (Exception var6) { LOGGER.warn("Failed to parse block properties: {}", properties, var6); return Map.of(); } } private static Dynamic readVector(Dynamic tag, StringReader reader) throws CommandSyntaxException { float f = reader.readFloat(); reader.expect(' '); float g = reader.readFloat(); reader.expect(' '); float h = reader.readFloat(); return tag.createList(Stream.of(f, g, h).map(tag::createFloat)); } private Dynamic updateDust(Dynamic tag, String options) { try { StringReader stringReader = new StringReader(options); Dynamic dynamic = readVector(tag, stringReader); stringReader.expect(' '); float f = stringReader.readFloat(); return tag.set("color", dynamic).set("scale", tag.createFloat(f)); } catch (Exception var6) { LOGGER.warn("Failed to parse particle options: {}", options, var6); return tag; } } private Dynamic updateDustTransition(Dynamic tag, String options) { try { StringReader stringReader = new StringReader(options); Dynamic dynamic = readVector(tag, stringReader); stringReader.expect(' '); float f = stringReader.readFloat(); stringReader.expect(' '); Dynamic dynamic2 = readVector(tag, stringReader); return tag.set("from_color", dynamic).set("to_color", dynamic2).set("scale", tag.createFloat(f)); } catch (Exception var7) { LOGGER.warn("Failed to parse particle options: {}", options, var7); return tag; } } private Dynamic updateSculkCharge(Dynamic tag, String options) { try { StringReader stringReader = new StringReader(options); float f = stringReader.readFloat(); return tag.set("roll", tag.createFloat(f)); } catch (Exception var5) { LOGGER.warn("Failed to parse particle options: {}", options, var5); return tag; } } private Dynamic updateVibration(Dynamic tag, String options) { try { StringReader stringReader = new StringReader(options); float f = (float)stringReader.readDouble(); stringReader.expect(' '); float g = (float)stringReader.readDouble(); stringReader.expect(' '); float h = (float)stringReader.readDouble(); stringReader.expect(' '); int i = stringReader.readInt(); Dynamic dynamic = (Dynamic)tag.createIntList(IntStream.of(new int[]{Mth.floor(f), Mth.floor(g), Mth.floor(h)})); Dynamic dynamic2 = tag.createMap(Map.of(tag.createString("type"), tag.createString("minecraft:block"), tag.createString("pos"), dynamic)); return tag.set("destination", dynamic2).set("arrival_in_ticks", tag.createInt(i)); } catch (Exception var10) { LOGGER.warn("Failed to parse particle options: {}", options, var10); return tag; } } private Dynamic updateShriek(Dynamic tag, String options) { try { StringReader stringReader = new StringReader(options); int i = stringReader.readInt(); return tag.set("delay", tag.createInt(i)); } catch (Exception var5) { LOGGER.warn("Failed to parse particle options: {}", options, var5); return tag; } } }