All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ca.spottedleaf.dataconverter.minecraft.versions.V2514 Maven / Gradle / Ivy

package ca.spottedleaf.dataconverter.minecraft.versions;

import ca.spottedleaf.dataconverter.converters.DataConverter;
import ca.spottedleaf.dataconverter.minecraft.MCVersions;
import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry;
import ca.spottedleaf.dataconverter.types.ListType;
import ca.spottedleaf.dataconverter.types.MapType;
import ca.spottedleaf.dataconverter.types.ObjectType;
import ca.spottedleaf.dataconverter.types.Types;

import java.util.Set;
import java.util.UUID;

public final class V2514 {

    private static final int VERSION = MCVersions.V20W11A + 1;

    private static final Set ABSTRACT_HORSES = Set.of(
            "minecraft:donkey",
            "minecraft:horse",
            "minecraft:llama",
            "minecraft:mule",
            "minecraft:skeleton_horse",
            "minecraft:trader_llama",
            "minecraft:zombie_horse"
    );
    private static final Set TAMEABLE_ANIMALS = Set.of(
            "minecraft:cat",
            "minecraft:parrot",
            "minecraft:wolf"
    );
    private static final Set ANIMALS = Set.of(
            "minecraft:bee",
            "minecraft:chicken",
            "minecraft:cow",
            "minecraft:fox",
            "minecraft:mooshroom",
            "minecraft:ocelot",
            "minecraft:panda",
            "minecraft:pig",
            "minecraft:polar_bear",
            "minecraft:rabbit",
            "minecraft:sheep",
            "minecraft:turtle",
            "minecraft:hoglin"
    );
    private static final Set MOBS = Set.of(
            "minecraft:bat",
            "minecraft:blaze",
            "minecraft:cave_spider",
            "minecraft:cod",
            "minecraft:creeper",
            "minecraft:dolphin",
            "minecraft:drowned",
            "minecraft:elder_guardian",
            "minecraft:ender_dragon",
            "minecraft:enderman",
            "minecraft:endermite",
            "minecraft:evoker",
            "minecraft:ghast",
            "minecraft:giant",
            "minecraft:guardian",
            "minecraft:husk",
            "minecraft:illusioner",
            "minecraft:magma_cube",
            "minecraft:pufferfish",
            "minecraft:zombified_piglin",
            "minecraft:salmon",
            "minecraft:shulker",
            "minecraft:silverfish",
            "minecraft:skeleton",
            "minecraft:slime",
            "minecraft:snow_golem",
            "minecraft:spider",
            "minecraft:squid",
            "minecraft:stray",
            "minecraft:tropical_fish",
            "minecraft:vex",
            "minecraft:villager",
            "minecraft:iron_golem",
            "minecraft:vindicator",
            "minecraft:pillager",
            "minecraft:wandering_trader",
            "minecraft:witch",
            "minecraft:wither",
            "minecraft:wither_skeleton",
            "minecraft:zombie",
            "minecraft:zombie_villager",
            "minecraft:phantom",
            "minecraft:ravager",
            "minecraft:piglin"
    );
    private static final Set LIVING_ENTITIES = Set.of("minecraft:armor_stand");
    private static final Set PROJECTILES = Set.of(
            "minecraft:arrow",
            "minecraft:dragon_fireball",
            "minecraft:firework_rocket",
            "minecraft:fireball",
            "minecraft:llama_spit",
            "minecraft:small_fireball",
            "minecraft:snowball",
            "minecraft:spectral_arrow",
            "minecraft:egg",
            "minecraft:ender_pearl",
            "minecraft:experience_bottle",
            "minecraft:potion",
            "minecraft:trident",
            "minecraft:wither_skull"
    );

    static int[] createUUIDArray(final long most, final long least) {
        return new int[]{
                (int) (most >>> 32),
                (int) most,
                (int) (least >>> 32),
                (int) least
        };
    }

    static int[] createUUIDFromString(final MapType data, final String path) {
        if (data == null) {
            return null;
        }

        final String uuidString = data.getString(path);
        if (uuidString == null) {
            return null;
        }

        try {
            final UUID uuid = UUID.fromString(uuidString);
            return createUUIDArray(uuid.getMostSignificantBits(), uuid.getLeastSignificantBits());
        } catch (final IllegalArgumentException ignore) {
            return null;
        }
    }

    static int[] createUUIDFromLongs(final MapType data, final String most, final String least) {
        if (data == null) {
            return null;
        }

        final long mostBits = data.getLong(most);
        final long leastBits = data.getLong(least);

        return (mostBits != 0 || leastBits != 0) ? createUUIDArray(mostBits, leastBits) : null;
    }

    static void replaceUUIDString(final MapType data, final String oldPath, final String newPath) {
        final int[] newUUID = createUUIDFromString(data, oldPath);
        if (newUUID != null) {
            data.remove(oldPath);
            data.setInts(newPath, newUUID);
        }
    }

    static void replaceUUIDMLTag(final MapType data, final String oldPath, final String newPath) {
        final int[] uuid = createUUIDFromLongs(data.getMap(oldPath), "M", "L");
        if (uuid != null) {
            data.remove(oldPath);
            data.setInts(newPath, uuid);
        }
    }

    static void replaceUUIDLeastMost(final MapType data, final String prefix, final String newPath) {
        final String mostPath = prefix.concat("Most");
        final String leastPath = prefix.concat("Least");

        final int[] uuid = createUUIDFromLongs(data, mostPath, leastPath);
        if (uuid != null) {
            data.remove(mostPath);
            data.remove(leastPath);
            data.setInts(newPath, uuid);
        }
    }

    private static void updatePiglin(final MapType data) {
        final MapType brain = data.getMap("Brain");
        if (brain == null) {
            return;
        }

        final MapType memories = brain.getMap("memories");
        if (memories == null) {
            return;
        }

        final MapType angryAt = memories.getMap("minecraft:angry_at");

        replaceUUIDString(angryAt, "value", "value");
    }

    private static void updateEvokerFangs(final MapType data) {
        replaceUUIDLeastMost(data, "OwnerUUID", "Owner");
    }

    private static void updateZombieVillager(final MapType data) {
        replaceUUIDLeastMost(data, "ConversionPlayer", "ConversionPlayer");
    }

    private static void updateAreaEffectCloud(final MapType data) {
        replaceUUIDLeastMost(data, "OwnerUUID", "Owner");
    }

    private static void updateShulkerBullet(final MapType data) {
        replaceUUIDMLTag(data, "Owner", "Owner");
        replaceUUIDMLTag(data, "Target", "Target");
    }

    private static void updateItem(final MapType data) {
        replaceUUIDMLTag(data, "Owner", "Owner");
        replaceUUIDMLTag(data, "Thrower", "Thrower");
    }

    private static void updateFox(final MapType data) {
        final ListType trustedUUIDS = data.getList("TrustedUUIDs", ObjectType.MAP);
        if (trustedUUIDS == null) {
            return;
        }

        final ListType newUUIDs = Types.NBT.createEmptyList();
        data.remove("TrustedUUIDs");
        data.setList("Trusted", newUUIDs);

        for (int i = 0, len = trustedUUIDS.size(); i < len; ++i) {
            final MapType uuid = trustedUUIDS.getMap(i);
            final int[] newUUID = createUUIDFromLongs(uuid, "M", "L");
            if (newUUID != null) {
                newUUIDs.addIntArray(newUUID);
            }
        }
    }

    private static void updateHurtBy(final MapType data) {
        replaceUUIDString(data, "HurtBy", "HurtBy");
    }

    private static void updateAnimalOwner(final MapType data) {
        updateAnimal(data);

        replaceUUIDString(data, "OwnerUUID", "Owner");
    }

    private static void updateAnimal(final MapType data) {
        updateMob(data);

        replaceUUIDLeastMost(data, "LoveCause", "LoveCause");
    }

    private static void updateMob(final MapType data) {
        updateLivingEntity(data);

        final MapType leash = data.getMap("Leash");
        if (leash == null) {
            return;
        }

        replaceUUIDLeastMost(leash, "UUID", "UUID");
    }

    private static void updateLivingEntity(final MapType data) {
        final ListType attributes = data.getList("Attributes", ObjectType.MAP);
        if (attributes == null) {
            return;
        }

        for (int i = 0, len = attributes.size(); i < len; ++i) {
            final MapType attribute = attributes.getMap(i);

            final ListType modifiers = attribute.getList("Modifiers", ObjectType.MAP);
            if (modifiers == null) {
                continue;
            }

            for (int k = 0; k < modifiers.size(); ++k) {
                replaceUUIDLeastMost(modifiers.getMap(k), "UUID", "UUID");
            }
        }
    }

    private static void updateProjectile(final MapType data) {
        final Object ownerUUID = data.getGeneric("OwnerUUID");
        if (ownerUUID != null) {
            data.remove("OwnerUUID");
            data.setGeneric("Owner", ownerUUID);
        }
    }

    private static void updateEntityUUID(final MapType data) {
        replaceUUIDLeastMost(data, "UUID", "UUID");
    }

    public static void register() {
        // Entity UUID fixes

        MCTypeRegistry.ENTITY.addStructureConverter(new DataConverter<>(VERSION) {
            @Override
            public MapType convert(final MapType data, final long sourceVersion, final long toVersion) {
                updateEntityUUID(data);
                return null;
            }
        });

        final DataConverter, MapType> animalOwnerConverter = new DataConverter<>(VERSION) {
            @Override
            public MapType convert(final MapType data, final long sourceVersion, final long toVersion) {
                updateAnimalOwner(data);
                return null;
            }
        };
        final DataConverter, MapType> animalConverter = new DataConverter<>(VERSION) {
            @Override
            public MapType convert(final MapType data, final long sourceVersion, final long toVersion) {
                updateAnimal(data);
                return null;
            }
        };
        final DataConverter, MapType> mobConverter = new DataConverter<>(VERSION) {
            @Override
            public MapType convert(final MapType data, final long sourceVersion, final long toVersion) {
                updateMob(data);
                return null;
            }
        };
        final DataConverter, MapType> livingEntityConverter = new DataConverter<>(VERSION) {
            @Override
            public MapType convert(final MapType data, final long sourceVersion, final long toVersion) {
                updateLivingEntity(data);
                return null;
            }
        };
        final DataConverter, MapType> projectileConverter = new DataConverter<>(VERSION) {
            @Override
            public MapType convert(final MapType data, final long sourceVersion, final long toVersion) {
                updateProjectile(data);
                return null;
            }
        };
        for (final String id : ABSTRACT_HORSES) {
            MCTypeRegistry.ENTITY.addConverterForId(id, animalOwnerConverter);
        }
        for (final String id : TAMEABLE_ANIMALS) {
            MCTypeRegistry.ENTITY.addConverterForId(id, animalOwnerConverter);
        }
        for (final String id : ANIMALS) {
            MCTypeRegistry.ENTITY.addConverterForId(id, animalConverter);
        }
        for (final String id : MOBS) {
            MCTypeRegistry.ENTITY.addConverterForId(id, mobConverter);
        }
        for (final String id : LIVING_ENTITIES) {
            MCTypeRegistry.ENTITY.addConverterForId(id, livingEntityConverter);
        }
        for (final String id : PROJECTILES) {
            MCTypeRegistry.ENTITY.addConverterForId(id, projectileConverter);
        }


        MCTypeRegistry.ENTITY.addConverterForId("minecraft:bee", new DataConverter<>(VERSION) {
            @Override
            public MapType convert(final MapType data, final long sourceVersion, final long toVersion) {
                updateHurtBy(data);
                return null;
            }
        });
        MCTypeRegistry.ENTITY.addConverterForId("minecraft:zombified_piglin", new DataConverter<>(VERSION) {
            @Override
            public MapType convert(final MapType data, final long sourceVersion, final long toVersion) {
                updateHurtBy(data);
                return null;
            }
        });
        MCTypeRegistry.ENTITY.addConverterForId("minecraft:fox", new DataConverter<>(VERSION) {
            @Override
            public MapType convert(final MapType data, final long sourceVersion, final long toVersion) {
                updateFox(data);
                return null;
            }
        });
        MCTypeRegistry.ENTITY.addConverterForId("minecraft:item", new DataConverter<>(VERSION) {
            @Override
            public MapType convert(final MapType data, final long sourceVersion, final long toVersion) {
                updateItem(data);
                return null;
            }
        });
        MCTypeRegistry.ENTITY.addConverterForId("minecraft:shulker_bullet", new DataConverter<>(VERSION) {
            @Override
            public MapType convert(final MapType data, final long sourceVersion, final long toVersion) {
                updateShulkerBullet(data);
                return null;
            }
        });
        MCTypeRegistry.ENTITY.addConverterForId("minecraft:area_effect_cloud", new DataConverter<>(VERSION) {
            @Override
            public MapType convert(final MapType data, final long sourceVersion, final long toVersion) {
                updateAreaEffectCloud(data);
                return null;
            }
        });
        MCTypeRegistry.ENTITY.addConverterForId("minecraft:zombie_villager", new DataConverter<>(VERSION) {
            @Override
            public MapType convert(final MapType data, final long sourceVersion, final long toVersion) {
                updateZombieVillager(data);
                return null;
            }
        });
        MCTypeRegistry.ENTITY.addConverterForId("minecraft:evoker_fangs", new DataConverter<>(VERSION) {
            @Override
            public MapType convert(final MapType data, final long sourceVersion, final long toVersion) {
                updateEvokerFangs(data);
                return null;
            }
        });
        MCTypeRegistry.ENTITY.addConverterForId("minecraft:piglin", new DataConverter<>(VERSION) {
            @Override
            public MapType convert(final MapType data, final long sourceVersion, final long toVersion) {
                updatePiglin(data);
                return null;
            }
        });


        // Update TE
        MCTypeRegistry.TILE_ENTITY.addConverterForId("minecraft:conduit", new DataConverter<>(VERSION) {
            @Override
            public MapType convert(final MapType data, final long sourceVersion, final long toVersion) {
                replaceUUIDMLTag(data, "target_uuid", "Target");
                return null;
            }
        });
        MCTypeRegistry.TILE_ENTITY.addConverterForId("minecraft:skull", new DataConverter<>(VERSION) {
            @Override
            public MapType convert(final MapType data, final long sourceVersion, final long toVersion) {
                final MapType owner = data.getMap("Owner");
                if (owner == null) {
                    return null;
                }

                data.remove("Owner");

                replaceUUIDString(owner, "Id", "Id");

                data.setMap("SkullOwner", owner);

                return null;
            }
        });

        // Player UUID
        MCTypeRegistry.PLAYER.addStructureConverter(new DataConverter<>(VERSION) {
            @Override
            public MapType convert(final MapType data, final long sourceVersion, final long toVersion) {
                updateLivingEntity(data);
                updateEntityUUID(data);

                final MapType rootVehicle = data.getMap("RootVehicle");
                if (rootVehicle == null) {
                    return null;
                }

                replaceUUIDLeastMost(rootVehicle, "Attach", "Attach");

                return null;
            }
        });

        // Level.dat
        MCTypeRegistry.LEVEL.addStructureConverter(new DataConverter<>(VERSION) {
            @Override
            public MapType convert(final MapType data, final long sourceVersion, final long toVersion) {
                replaceUUIDString(data, "WanderingTraderId", "WanderingTraderId");

                final MapType dimensionData = data.getMap("DimensionData");
                if (dimensionData != null) {
                    for (final String key : dimensionData.keys()) {
                        final MapType dimension = dimensionData.getMap(key);

                        final MapType dragonFight = dimension.getMap("DragonFight");
                        if (dragonFight == null) {
                            continue;
                        }

                        replaceUUIDLeastMost(dragonFight, "DragonUUID", "Dragon");
                    }
                }

                final MapType customBossEvents = data.getMap("CustomBossEvents");
                if (customBossEvents != null) {
                    for (final String key : customBossEvents.keys()) {
                        final MapType customBossEvent = customBossEvents.getMap(key);

                        final ListType players = customBossEvent.getList("Players", ObjectType.MAP);
                        if (players == null) {
                            continue;
                        }

                        final ListType newPlayers = Types.NBT.createEmptyList();
                        customBossEvent.setList("Players", newPlayers);

                        for (int i = 0, len = players.size(); i < len; ++i) {
                            final int[] newUUID = createUUIDFromLongs(players.getMap(i), "M", "L");
                            if (newUUID != null) {
                                newPlayers.addIntArray(newUUID);
                            }
                        }
                    }
                }

                return null;
            }
        });

        MCTypeRegistry.SAVED_DATA_RAIDS.addStructureConverter(new DataConverter<>(VERSION) {
            @Override
            public MapType convert(final MapType root, final long sourceVersion, final long toVersion) {
                final MapType data = root.getMap("data");
                if (data == null) {
                    return null;
                }

                final ListType raids = data.getList("Raids", ObjectType.MAP);
                if (raids == null) {
                    return null;
                }

                for (int i = 0, len = raids.size(); i < len; ++i) {
                    final MapType raid = raids.getMap(i);

                    final ListType heros = raid.getList("HeroesOfTheVillage", ObjectType.MAP);

                    if (heros == null) {
                        continue;
                    }

                    final ListType newHeros = Types.NBT.createEmptyList();
                    raid.setList("HeroesOfTheVillage", newHeros);

                    for (int k = 0, klen = heros.size(); k < klen; ++k) {
                        final MapType uuidOld = heros.getMap(i);
                        final int[] uuidNew = createUUIDFromLongs(uuidOld, "UUIDMost", "UUIDLeast");
                        if (uuidNew != null) {
                            newHeros.addIntArray(uuidNew);
                        }
                    }
                }

                return null;
            }
        });

        MCTypeRegistry.ITEM_STACK.addStructureConverter(new DataConverter<>(VERSION) {
            @Override
            public MapType convert(final MapType data, final long sourceVersion, final long toVersion) {
                final MapType tag = data.getMap("tag");
                if (tag == null) {
                    return null;
                }

                updateAttributeModifiers(tag);

                if ("minecraft:player_head".equals(data.getString("id"))) {
                    updateSkullOwner(tag);
                }

                return null;
            }
        });
    }

    private static void updateAttributeModifiers(final MapType tag) {
        final ListType attributes = tag.getList("AttributeModifiers", ObjectType.MAP);
        if (attributes == null) {
            return;
        }

        for (int i = 0, len = attributes.size(); i < len; ++i) {
            replaceUUIDLeastMost(attributes.getMap(i), "UUID", "UUID");
        }
    }

    private static void updateSkullOwner(final MapType tag) {
        replaceUUIDString(tag.getMap("SkullOwner"), "Id", "Id");
    }

    private V2514() {}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy