diff --git a/.editorconfig b/.editorconfig index 7730dd6b..85b4636b 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,4 +10,7 @@ ij_java_class_count_to_use_import_on_demand = 999999 ij_java_names_count_to_use_import_on_demand = 999999 ij_java_imports_layout = *,|,$* ij_java_generate_final_locals = true -ij_java_generate_final_parameters = true \ No newline at end of file +ij_java_generate_final_parameters = true + +[*.json] +indent_size = 2 \ No newline at end of file diff --git a/common/src/main/java/com/viaversion/viabackwards/api/data/BackwardsMappings.java b/common/src/main/java/com/viaversion/viabackwards/api/data/BackwardsMappings.java index 5ecd95fe..cf8405d4 100644 --- a/common/src/main/java/com/viaversion/viabackwards/api/data/BackwardsMappings.java +++ b/common/src/main/java/com/viaversion/viabackwards/api/data/BackwardsMappings.java @@ -26,6 +26,7 @@ import com.viaversion.viaversion.api.data.MappingData; import com.viaversion.viaversion.api.data.MappingDataBase; import com.viaversion.viaversion.api.data.Mappings; import com.viaversion.viaversion.api.protocol.Protocol; +import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectArrayMap; import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectMap; import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectOpenHashMap; import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag; @@ -35,6 +36,7 @@ import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag; import com.viaversion.viaversion.util.Key; import java.util.HashMap; import java.util.Map; +import java.util.logging.Level; import java.util.logging.Logger; import org.checkerframework.checker.nullness.qual.Nullable; @@ -44,6 +46,7 @@ public class BackwardsMappings extends MappingDataBase { protected Int2ObjectMap backwardsItemMappings; private Map backwardsSoundMappings; private Map entityNames; + private Int2ObjectMap enchantmentNames; public BackwardsMappings(final String unmappedVersion, final String mappedVersion) { this(unmappedVersion, mappedVersion, null); @@ -77,23 +80,37 @@ public class BackwardsMappings extends MappingDataBase { } } - final CompoundTag entityNames = data.getCompoundTag("entitynames"); - if (entityNames != null) { - this.entityNames = new HashMap<>(entityNames.size()); - for (final Map.Entry entry : entityNames.entrySet()) { - final StringTag mappedTag = (StringTag) entry.getValue(); - this.entityNames.put(entry.getKey(), mappedTag.getValue()); - } + this.entityNames = loadNameByStringMappings(data, "entitynames"); + this.enchantmentNames = loadNameByIdMappings(data, "enchantmentnames"); + this.backwardsSoundMappings = loadNameByStringMappings(data, "soundnames"); + } + + private @Nullable Map loadNameByStringMappings(final CompoundTag data, final String key) { + final CompoundTag nameMappings = data.getCompoundTag(key); + if (nameMappings == null) { + return null; } - final CompoundTag soundNames = data.getCompoundTag("soundnames"); - if (soundNames != null) { - backwardsSoundMappings = new HashMap<>(soundNames.size()); - for (final Map.Entry entry : soundNames.entrySet()) { - final StringTag mappedTag = (StringTag) entry.getValue(); - backwardsSoundMappings.put(entry.getKey(), mappedTag.getValue()); - } + final Map map = new HashMap<>(nameMappings.size()); + for (final Map.Entry entry : nameMappings.entrySet()) { + final StringTag mappedTag = (StringTag) entry.getValue(); + map.put(entry.getKey(), mappedTag.getValue()); } + return map; + } + + private @Nullable Int2ObjectMap loadNameByIdMappings(final CompoundTag data, final String key) { + final CompoundTag nameMappings = data.getCompoundTag(key); + if (nameMappings == null) { + return null; + } + + final Int2ObjectMap map = new Int2ObjectArrayMap<>(nameMappings.size()); + for (final Map.Entry entry : nameMappings.entrySet()) { + final StringTag mappedTag = (StringTag) entry.getValue(); + map.put(Integer.parseInt(entry.getKey()), mappedTag.getValue()); + } + return map; } @Override @@ -142,13 +159,20 @@ public class BackwardsMappings extends MappingDataBase { public @Nullable String mappedEntityName(final String entityName) { if (entityNames == null) { - ViaBackwards.getPlatform().getLogger().severe("No entity mappings found when requesting them for " + entityName); - new Exception().printStackTrace(); + ViaBackwards.getPlatform().getLogger().log(Level.SEVERE, "No entity mappings found when requesting them for " + entityName, new RuntimeException()); return null; } return entityNames.get(entityName); } + public @Nullable String mappedEnchantmentName(final int enchantmentId) { + if (enchantmentNames == null) { + ViaBackwards.getPlatform().getLogger().log(Level.SEVERE, "No enchantment name mappings found when requesting " + enchantmentId, new RuntimeException()); + return null; + } + return enchantmentNames.get(enchantmentId); + } + public @Nullable Int2ObjectMap getBackwardsItemMappings() { return backwardsItemMappings; } diff --git a/common/src/main/java/com/viaversion/viabackwards/api/rewriters/BackwardsItemRewriterBase.java b/common/src/main/java/com/viaversion/viabackwards/api/rewriters/BackwardsItemRewriterBase.java index c28b0794..3099fe1f 100644 --- a/common/src/main/java/com/viaversion/viabackwards/api/rewriters/BackwardsItemRewriterBase.java +++ b/common/src/main/java/com/viaversion/viabackwards/api/rewriters/BackwardsItemRewriterBase.java @@ -27,6 +27,8 @@ import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag; import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag; import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag; import com.viaversion.viaversion.rewriter.ItemRewriter; +import java.util.ArrayList; +import java.util.List; import org.checkerframework.checker.nullness.qual.Nullable; public abstract class BackwardsItemRewriterBase original, String name) { + protected void saveListTag(CompoundTag tag, ListTag original, String name) { // Multiple places might try to backup data - String backupName = nbtTagName("o" + name); - if (!displayTag.contains(backupName)) { - displayTag.put(backupName, original.copy()); + String backupName = nbtTagName(name); + if (!tag.contains(backupName)) { + tag.put(backupName, original.copy()); } } + protected void saveGenericTagList(CompoundTag tag, List original, String name) { + // List tags cannot contain tags of different types, so we have to store them a bit more awkwardly as an indexed compound tag + String backupName = getNbtTagName() + "|" + name; + if (!tag.contains(backupName)) { + CompoundTag output = new CompoundTag(); + for (int i = 0; i < original.size(); i++) { + output.put(Integer.toString(i), original.get(i)); + } + tag.put(backupName, output); + } + } + + protected List removeGenericTagList(CompoundTag tag, String name) { + String backupName = getNbtTagName() + "|" + name; + CompoundTag data = tag.getCompoundTag(backupName); + if (data == null) { + return null; + } + + tag.remove(backupName); + return new ArrayList<>(data.values()); + } + protected void restoreDisplayTag(Item item) { if (item.tag() == null) return; @@ -90,19 +115,30 @@ public abstract class BackwardsItemRewriterBase) original).copy()); } } + public @Nullable ListTag removeListTag(CompoundTag tag, String tagName, Class tagType) { + String backupName = nbtTagName(tagName); + ListTag data = tag.getListTag(backupName, tagType); + if (data == null) { + return null; + } + + tag.remove(backupName); + return data; + } + @Override public String nbtTagName() { return "VB|" + protocol.getClass().getSimpleName(); diff --git a/common/src/main/java/com/viaversion/viabackwards/api/rewriters/BackwardsStructuredItemRewriter.java b/common/src/main/java/com/viaversion/viabackwards/api/rewriters/BackwardsStructuredItemRewriter.java index 6f952827..c0de1282 100644 --- a/common/src/main/java/com/viaversion/viabackwards/api/rewriters/BackwardsStructuredItemRewriter.java +++ b/common/src/main/java/com/viaversion/viabackwards/api/rewriters/BackwardsStructuredItemRewriter.java @@ -36,6 +36,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; public class BackwardsStructuredItemRewriter> extends BackwardsItemRewriter { + protected final StructuredEnchantmentRewriter enchantmentRewriter = new StructuredEnchantmentRewriter(this); + public BackwardsStructuredItemRewriter(final T protocol, final Type itemType, final Type itemArrayType) { super(protocol, itemType, itemArrayType); } @@ -53,6 +55,10 @@ public class BackwardsStructuredItemRewriter customNameData = data.getNonEmpty(StructuredDataKey.CUSTOM_NAME); @@ -114,6 +120,10 @@ public class BackwardsStructuredItemRewriter enchantmentMappings = new HashMap<>(); - private final BackwardsItemRewriter itemRewriter; + protected final Map enchantmentMappings = new HashMap<>(); + protected final BackwardsItemRewriter itemRewriter; private final boolean jsonFormat; public EnchantmentRewriter(BackwardsItemRewriter itemRewriter, boolean jsonFormat) { @@ -48,7 +49,7 @@ public class EnchantmentRewriter { } public void registerEnchantment(String key, String replacementLore) { - enchantmentMappings.put(key, replacementLore); + enchantmentMappings.put(Key.stripMinecraftNamespace(key), replacementLore); } public void handleToClient(Item item) { @@ -89,7 +90,7 @@ public class EnchantmentRewriter { continue; } - String enchantmentId = idTag.getValue(); + String enchantmentId = Key.stripMinecraftNamespace(idTag.getValue()); String remappedName = enchantmentMappings.get(enchantmentId); if (remappedName != null) { if (!changed) { diff --git a/common/src/main/java/com/viaversion/viabackwards/api/rewriters/StructuredEnchantmentRewriter.java b/common/src/main/java/com/viaversion/viabackwards/api/rewriters/StructuredEnchantmentRewriter.java new file mode 100644 index 00000000..19491c93 --- /dev/null +++ b/common/src/main/java/com/viaversion/viabackwards/api/rewriters/StructuredEnchantmentRewriter.java @@ -0,0 +1,189 @@ +/* + * This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viabackwards.api.rewriters; + +import com.viaversion.viabackwards.api.data.BackwardsMappings; +import com.viaversion.viaversion.api.data.Mappings; +import com.viaversion.viaversion.api.minecraft.data.StructuredData; +import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer; +import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey; +import com.viaversion.viaversion.api.minecraft.item.Item; +import com.viaversion.viaversion.api.minecraft.item.data.Enchantments; +import com.viaversion.viaversion.libs.fastutil.ints.Int2IntMap; +import com.viaversion.viaversion.libs.fastutil.ints.IntIntPair; +import com.viaversion.viaversion.libs.fastutil.objects.ObjectIterator; +import com.viaversion.viaversion.libs.opennbt.tag.builtin.ByteTag; +import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag; +import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag; +import com.viaversion.viaversion.libs.opennbt.tag.builtin.NumberTag; +import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag; +import com.viaversion.viaversion.util.ComponentUtil; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class StructuredEnchantmentRewriter { + + protected final BackwardsItemRewriter itemRewriter; + private boolean rewriteIds = true; + + public StructuredEnchantmentRewriter(final BackwardsItemRewriter itemRewriter) { + this.itemRewriter = itemRewriter; + } + + public void handleToClient(final Item item) { + final StructuredDataContainer data = item.structuredData(); + rewriteEnchantmentsToClient(data, StructuredDataKey.ENCHANTMENTS, false); + rewriteEnchantmentsToClient(data, StructuredDataKey.STORED_ENCHANTMENTS, true); + } + + public void handleToServer(final Item item) { + final StructuredDataContainer data = item.structuredData(); + final StructuredData customData = data.getNonEmpty(StructuredDataKey.CUSTOM_DATA); + if (customData == null) { + return; + } + + final CompoundTag tag = customData.value(); + if (tag.contains(itemRewriter.getNbtTagName() + "|enchantments")) { + rewriteEnchantmentsToServer(data, tag, StructuredDataKey.ENCHANTMENTS, false); + } + if (tag.contains(itemRewriter.getNbtTagName() + "|stored_enchantments")) { + rewriteEnchantmentsToServer(data, tag, StructuredDataKey.STORED_ENCHANTMENTS, true); + } + } + + public void rewriteEnchantmentsToClient(final StructuredDataContainer data, final StructuredDataKey key, final boolean storedEnchant) { + final StructuredData enchantmentsData = data.getNonEmpty(key); + if (enchantmentsData == null) { + return; + } + + final CompoundTag tag = data.computeIfAbsent(StructuredDataKey.CUSTOM_DATA, $ -> new CompoundTag()).value(); + final Enchantments enchantments = enchantmentsData.value(); + final List loreToAdd = new ArrayList<>(); + boolean changed = false; + + final ObjectIterator iterator = enchantments.enchantments().int2IntEntrySet().iterator(); + final List updatedIds = new ArrayList<>(); + while (iterator.hasNext()) { + final Int2IntMap.Entry entry = iterator.next(); + final BackwardsMappings mappingData = itemRewriter.protocol().getMappingData(); + final Mappings mappings = mappingData.getEnchantmentMappings(); + final int mappedId = mappings.getNewId(entry.getIntKey()); + if (mappedId != -1) { + if (rewriteIds) { + // Update the map after to iteration to preserve the current ids before possibly saving the original, avoid CME + updatedIds.add(IntIntPair.of(entry.getIntKey(), mappedId)); + } + continue; + } + + final String remappedName = mappingData.mappedEnchantmentName(entry.getIntKey()); + if (remappedName != null) { + if (!changed) { + // Backup original before doing modifications + itemRewriter.saveListTag(tag, asTag(enchantments), key.identifier()); + changed = true; + } + + final int level = entry.getIntValue(); + loreToAdd.add(ComponentUtil.jsonStringToTag(ComponentUtil.legacyToJsonString("ยง7" + remappedName + " " + EnchantmentRewriter.getRomanNumber(level), true))); + iterator.remove(); + } + } + + for (final IntIntPair pair : updatedIds) { + enchantments.add(pair.firstInt(), pair.secondInt()); + } + + if (loreToAdd.isEmpty()) { + // No removed enchantments + return; + } + + // Add glint override if there are no enchantments left + if (!storedEnchant && enchantments.size() == 0) { + final StructuredData glintOverride = data.getNonEmpty(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE); + if (glintOverride != null) { + tag.putBoolean(itemRewriter.getNbtTagName() + "|glint", glintOverride.value()); + } else { + tag.putBoolean(itemRewriter.getNbtTagName() + "|noglint", true); + } + data.set(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE, true); + } + + // Save original lore + final StructuredData loreData = data.getNonEmpty(StructuredDataKey.LORE); + if (loreData != null) { + final List loreList = Arrays.asList(loreData.value()); + itemRewriter.saveGenericTagList(tag, loreList, "lore"); + loreToAdd.addAll(loreList); + } else { + tag.putBoolean(itemRewriter.getNbtTagName() + "|nolore", true); + } + + if (enchantments.showInTooltip()) { + tag.putBoolean(itemRewriter.getNbtTagName() + "|show_" + key.identifier(), true); + } + + data.set(StructuredDataKey.LORE, loreToAdd.toArray(new Tag[0])); + } + + private ListTag asTag(final Enchantments enchantments) { + final ListTag listTag = new ListTag<>(CompoundTag.class); + for (final Int2IntMap.Entry entry : enchantments.enchantments().int2IntEntrySet()) { + final CompoundTag enchantment = new CompoundTag(); + enchantment.putInt("id", entry.getIntKey()); + enchantment.putInt("lvl", entry.getIntValue()); + listTag.add(enchantment); + } + return listTag; + } + + public void rewriteEnchantmentsToServer(final StructuredDataContainer data, final CompoundTag tag, final StructuredDataKey key, final boolean storedEnchant) { + final ListTag enchantmentsTag = itemRewriter.removeListTag(tag, key.identifier(), CompoundTag.class); + if (enchantmentsTag == null) { + return; + } + + final Tag glintTag = tag.remove(itemRewriter.getNbtTagName() + "|glint"); + if (glintTag instanceof ByteTag) { + data.set(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE, ((NumberTag) glintTag).asBoolean()); + } else if (tag.remove(itemRewriter.getNbtTagName() + "|noglint") != null) { + data.remove(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE); + } + + final List lore = itemRewriter.removeGenericTagList(tag, "lore"); + if (lore != null) { + data.set(StructuredDataKey.LORE, lore.toArray(new Tag[0])); + } else if (tag.remove(itemRewriter.getNbtTagName() + "|nolore") != null) { + data.remove(StructuredDataKey.LORE); + } + + final Enchantments enchantments = new Enchantments(tag.remove(itemRewriter.getNbtTagName() + "|show_" + key.identifier()) != null); + for (final CompoundTag enchantment : enchantmentsTag) { + enchantments.add(enchantment.getInt("id"), enchantment.getInt("lvl")); + } + data.set(key, enchantments); + } + + public void setRewriteIds(final boolean rewriteIds) { + this.rewriteIds = rewriteIds; + } +} diff --git a/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_3to1_20_5/rewriter/BlockItemPacketRewriter1_20_5.java b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_3to1_20_5/rewriter/BlockItemPacketRewriter1_20_5.java index 8dbc653b..a9336dd1 100644 --- a/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_3to1_20_5/rewriter/BlockItemPacketRewriter1_20_5.java +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_3to1_20_5/rewriter/BlockItemPacketRewriter1_20_5.java @@ -18,6 +18,8 @@ package com.viaversion.viabackwards.protocol.protocol1_20_3to1_20_5.rewriter; import com.viaversion.viabackwards.api.rewriters.BackwardsStructuredItemRewriter; +import com.viaversion.viabackwards.api.rewriters.EnchantmentRewriter; +import com.viaversion.viabackwards.api.rewriters.StructuredEnchantmentRewriter; import com.viaversion.viabackwards.protocol.protocol1_20_3to1_20_5.Protocol1_20_3To1_20_5; import com.viaversion.viaversion.api.Via; import com.viaversion.viaversion.api.minecraft.Particle; @@ -42,6 +44,7 @@ public final class BlockItemPacketRewriter1_20_5 extends BackwardsStructuredItem public BlockItemPacketRewriter1_20_5(final Protocol1_20_3To1_20_5 protocol) { super(protocol, Types1_20_5.ITEM, Types1_20_5.ITEM_ARRAY, Type.ITEM1_20_2, Type.ITEM1_20_2_ARRAY); + enchantmentRewriter.setRewriteIds(false); // Let VV handle it } @Override diff --git a/common/src/main/resources/assets/viabackwards/data/mappings-1.20.5to1.20.3.nbt b/common/src/main/resources/assets/viabackwards/data/mappings-1.20.5to1.20.3.nbt index 05291b98..9cf244d3 100644 Binary files a/common/src/main/resources/assets/viabackwards/data/mappings-1.20.5to1.20.3.nbt and b/common/src/main/resources/assets/viabackwards/data/mappings-1.20.5to1.20.3.nbt differ diff --git a/common/src/main/resources/assets/viabackwards/data/translation-mappings.json b/common/src/main/resources/assets/viabackwards/data/translation-mappings.json index 14677847..66730e9f 100644 --- a/common/src/main/resources/assets/viabackwards/data/translation-mappings.json +++ b/common/src/main/resources/assets/viabackwards/data/translation-mappings.json @@ -1,28 +1,189 @@ { "1.20.5": { + "advancements.adventure.blowback.description": "Kill a Breeze with a deflected Breeze-shot Wind Charge", + "advancements.adventure.blowback.title": "Blowback", + "advancements.adventure.crafters_crafting_crafters.description": "Be near a Crafter when it crafts a Crafter", + "advancements.adventure.crafters_crafting_crafters.title": "Crafters Crafting Crafters", + "advancements.adventure.lighten_up.description": "Scrape a Copper Bulb with an Axe to make it brighter", + "advancements.adventure.lighten_up.title": "Lighten Up", + "advancements.adventure.minecraft_trials_edition.description": "Step foot in a Trial Chamber", + "advancements.adventure.minecraft_trials_edition.title": "Minecraft: Trial(s) Edition", + "advancements.adventure.overoverkill.description": "Deal 50 hearts of damage in a single hit using the Mace", + "advancements.adventure.overoverkill.title": "Over-Overkill", + "advancements.adventure.under_lock_and_key.description": "Unlock a Vault with a Trial Key", + "advancements.adventure.under_lock_and_key.title": "Under Lock and Key", + "advancements.adventure.who_needs_rockets.description": "Use a Wind Charge to launch yourself upward 8 blocks", + "advancements.adventure.who_needs_rockets.title": "Who Needs Rockets?", + "argument.resource_or_id.failed_to_parse": "Failed to parse structure: %s", + "argument.resource_or_id.invalid": "Invalid id or tag", + "arguments.item.component.expected": "Expected item component", + "arguments.item.component.malformed": "Malformed '%s' component: '%s'", + "arguments.item.component.repeated": "Item component '%s' was repeated, but only one value can be specified", + "arguments.item.component.unknown": "Unknown item component '%s'", + "arguments.item.predicate.malformed": "Malformed '%s' predicate: '%s'", + "arguments.item.predicate.unknown": "Unknown item predicate '%s''", "attribute.name.generic.block_interaction_range": "Block Interaction Range", "attribute.name.generic.entity_interaction_range": "Entity Interaction Range", + "attribute.name.generic.fall_damage_multiplier": "Fall Damage Multiplier", + "attribute.name.generic.gravity": "Gravity", + "attribute.name.generic.jump_strength": "Jump Strength", + "attribute.name.generic.safe_fall_distance": "Safe Fall Distance", "attribute.name.generic.scale": "Scale", "attribute.name.generic.step_height": "Step Height", + "attribute.name.player.block_break_speed": "Block Break Speed", + "attribute.name.player.block_interaction_range": "Block Interaction Range", + "attribute.name.player.entity_interaction_range": "Entity Interaction Range", + "block.minecraft.heavy_core": "Heavy Core", + "block.minecraft.vault": "Vault", + "chat.disabled.invalid_command_signature": "Command had unexpected or missing command argument signatures.", + "chat.disabled.invalid_signature": "Chat had an invalid signature. Please try reconnecting.", + "chat.disabled.out_of_order_chat": "Chat received out-of-order. Did your system time change?", + "chunk.toast.checkLog": "See log for more details", + "chunk.toast.loadFailure": "Failed to load chunk at %s", + "chunk.toast.lowDiskSpace": "Low disk space!", + "chunk.toast.lowDiskSpace.description": "Might not be able to save the world.", + "chunk.toast.saveFailure": "Failed to save chunk at %s", + "commands.datapack.disable.failed.feature": "Pack '%s' cannot be disabled, since it is part of an enabled flag!", + "commands.setworldspawn.failure.not_overworld": "Can only set the world spawn for overworld", + "commands.transfer.error.no_players": "Must specify at least one player to transfer", + "commands.transfer.success.multiple": "Transferring %s players to %s:%s", + "commands.transfer.success.single": "Transferring %s to %s:%s", + "connect.failed.transfer": "Connection failed while transferring to the server", + "connect.transferring": "Transferring to new server...", + "disconnect.transfer": "Transferred to another server", + "effect.minecraft.infested": "Infested", + "effect.minecraft.oozing": "Oozing", + "effect.minecraft.raid_omen": "Raid Omen", + "effect.minecraft.trial_omen": "Trial Omen", + "effect.minecraft.weaving": "Weaving", + "effect.minecraft.wind_charged": "Wind Charged", + "enchantment.minecraft.breach": "Breach", + "enchantment.minecraft.density": "Density", + "enchantment.minecraft.sweeping_edge": "Sweeping Edge", + "enchantment.minecraft.wind_burst": "Wind Burst", "entity.minecraft.armadillo": "Armadillo", + "entity.minecraft.bogged": "Bogged", + "entity.minecraft.breeze_wind_charge": "Wind Charge", + "entity.minecraft.ominous_item_spawner": "Ominous Item Spawner", + "filled_map.trial_chambers": "Trial Chambers Map", + "gamerule.spawnChunkRadius": "Spawn chunk radius", + "gamerule.spawnChunkRadius.description": "Amount of chunks that stay loaded around the overworld spawn position.", + "gamerule.spawnRadius.description": "Controls the size of the area around the spawn point that players can spawn in.", + "item.canUse.unknown": "Unknown", + "item.components": "%s component(s)", "item.minecraft.armadillo_scute": "Armadillo Scute", "item.minecraft.armadillo_spawn_egg": "Armadillo Spawn Egg", + "item.minecraft.bogged_spawn_egg": "Bogged Spawn Egg", + "item.minecraft.bolt_armor_trim_smithing_template": "Smithing Template", + "item.minecraft.breeze_rod": "Breeze Rod", + "item.minecraft.flow_armor_trim_smithing_template": "Smithing Template", + "item.minecraft.flow_banner_pattern": "Banner Pattern", + "item.minecraft.flow_banner_pattern.desc": "Flow", + "item.minecraft.flow_pottery_sherd": "Flow Pottery Sherd", + "item.minecraft.guster_banner_pattern": "Banner Pattern", + "item.minecraft.guster_banner_pattern.desc": "Guster", + "item.minecraft.guster_pottery_sherd": "Guster Pottery Sherd", + "item.minecraft.lingering_potion.effect.infested": "Lingering Potion of Infestation", + "item.minecraft.lingering_potion.effect.oozing": "Lingering Potion of Oozing", + "item.minecraft.lingering_potion.effect.weaving": "Lingering Potion of Weaving", + "item.minecraft.lingering_potion.effect.wind_charged": "Lingering Potion of Wind Charging", + "item.minecraft.mace": "Mace", + "item.minecraft.ominous_bottle": "Ominous Bottle", + "item.minecraft.ominous_trial_key": "Ominous Trial Key", + "item.minecraft.potion.effect.infested": "Potion of Infestation", + "item.minecraft.potion.effect.oozing": "Potion of Oozing", + "item.minecraft.potion.effect.weaving": "Potion of Weaving", + "item.minecraft.potion.effect.wind_charged": "Potion of Wind Charging", + "item.minecraft.scrape_pottery_sherd": "Scrape Pottery Sherd", + "item.minecraft.splash_potion.effect.infested": "Splash Potion of Infestation", + "item.minecraft.splash_potion.effect.oozing": "Splash Potion of Oozing", + "item.minecraft.splash_potion.effect.weaving": "Splash Potion of Weaving", + "item.minecraft.splash_potion.effect.wind_charged": "Splash Potion of Wind Charging", + "item.minecraft.tipped_arrow.effect.infested": "Arrow of Infestation", + "item.minecraft.tipped_arrow.effect.oozing": "Arrow of Oozing", + "item.minecraft.tipped_arrow.effect.weaving": "Arrow of Weaving", + "item.minecraft.tipped_arrow.effect.wind_charged": "Arrow of Wind Charging", "item.minecraft.turtle_scute": "Turtle Scute", + "item.minecraft.wind_charge": "Wind Charge", "item.minecraft.wolf_armor": "Wolf Armor", + "item.modifiers.body": "When equipped:", + "mco.backup.narration": "Backup from %s", + "mco.client.outdated.stable.version": "Your client version (%s) is not compatible with Realms.\n\nPlease use the most recent version of Minecraft.", + "mco.client.unsupported.snapshot.version": "Your client version (%s) is not compatible with Realms.\n\nRealms is not available for this snapshot version.", + "mco.invited.player.narration": "Invited player %s", + "mco.upload.entry.commands": "%1$s, %2$s", + "multiplayer.disconnect.transfers_disabled": "Server does not accept transfers", + "optimizeWorld.stage.finished.chunks": "Finishing up upgrading chunks...", + "optimizeWorld.stage.finished.entities": "Finishing up upgrading entities...", + "optimizeWorld.stage.finished.poi": "Finishing up upgrading points of interest...", + "optimizeWorld.stage.upgrading.chunks": "Upgrading all chunks...", + "optimizeWorld.stage.upgrading.entities": "Upgrading all entities...", + "optimizeWorld.stage.upgrading.poi": "Upgrading all points of interest...", + "options.accessibility.menu_background_blurriness": "Menu Background Blur", + "options.accessibility.menu_background_blurriness.tooltip": "Changes the blurriness of menu backgrounds", + "options.font": "Font Settings...", + "options.font.title": "Font Settings", + "options.japaneseGlyphVariants": "Japanese Glyph Variants", + "options.japaneseGlyphVariants.tooltip": "Uses Japanese variants of CJK characters in the default font", + "options.telemetry.disabled": "Telemetry is disabled.", + "selectWorld.allowCommands.new": "Allow Commands", + "selectWorld.commands": "Commands", + "selectWorld.warning.lowDiskSpace.description": "There is not much space left on your device.\nRunning out of disk space while in game can lead to your world being damaged.", + "selectWorld.warning.lowDiskSpace.title": "Warning! Low disk space!", + "slot.only_single_allowed": "Only single slots allowed, got '%s'", + "subtitles.block.candle.extinguish": "Candle extinguishes", + "subtitles.block.trial_spawner.about_to_spawn_item": "Ominous item prepares", + "subtitles.block.trial_spawner.ambient_charged": "Ominous Trial Spawner crackles", + "subtitles.block.trial_spawner.charge_activate": "Omen engulfs Trial Spawner", + "subtitles.block.trial_spawner.spawn_item": "Ominous item drops", + "subtitles.block.trial_spawner.spawn_item_begin": "Ominous item appears", + "subtitles.block.vault.activate": "Vault ignites", + "subtitles.block.vault.ambient": "Vault crackles", + "subtitles.block.vault.close_shutter": "Vault closes", + "subtitles.block.vault.deactivate": "Vault extinguishes", + "subtitles.block.vault.eject_item": "Vault ejects item", + "subtitles.block.vault.insert_item": "Vault unlocks", + "subtitles.block.vault.insert_item_fail": "Vault fails unlocking", + "subtitles.block.vault.open_shutter": "Vault opens", + "subtitles.block.wet_sponge.dries": "Sponge dries", "subtitles.entity.armadillo.ambient": "Armadillo grunts", - "subtitles.entity.armadillo.brush": "Armadillo brushes", + "subtitles.entity.armadillo.brush": "Scute is brushed off", "subtitles.entity.armadillo.death": "Armadillo dies", "subtitles.entity.armadillo.eat": "Armadillo eats", "subtitles.entity.armadillo.hurt": "Armadillo hurts", + "subtitles.entity.armadillo.hurt_reduced": "Armadillo shields itself", "subtitles.entity.armadillo.land": "Armadillo lands", + "subtitles.entity.armadillo.peek": "Armadillo peeks", "subtitles.entity.armadillo.roll": "Armadillo rolls up", - "subtitles.entity.armadillo.scute_drop": "Scute drops", - "subtitles.entity.armadillo.unroll": "Armadillo unrolls", + "subtitles.entity.armadillo.scute_drop": "Armadillo sheds scute", + "subtitles.entity.armadillo.unroll_finish": "Armadillo unrolls", + "subtitles.entity.armadillo.unroll_start": "Armadillo peeks", + "subtitles.entity.bogged.ambient": "Bogged rattles", + "subtitles.entity.bogged.death": "Bogged dies", + "subtitles.entity.bogged.hurt": "Bogged hurts", "subtitles.entity.breeze.charge": "Breeze charges", "subtitles.entity.breeze.deflect": "Breeze deflects", "subtitles.entity.breeze.whirl": "Breeze whirls", - "subtitles.item.armor.equip_wolf": "Wolf armor straps", - "subtitles.item.armor.unequip_wolf": "Wolf armor slips off" + "subtitles.entity.breeze.wind_burst": "Wind Charge bursts", + "subtitles.entity.donkey.jump": "Donkey jumps", + "subtitles.entity.mule.jump": "Mule jumps", + "subtitles.entity.parrot.imitate.bogged": "Parrot rattles", + "subtitles.entity.wind_charge.throw": "Wind Charge flies", + "subtitles.entity.wind_charge.wind_burst": "Wind Charge bursts", + "subtitles.event.mob_effect.bad_omen": "Omen takes hold", + "subtitles.event.mob_effect.raid_omen": "Raid looms nearby", + "subtitles.event.mob_effect.trial_omen": "Ominous trial looms nearby", + "subtitles.item.armor.equip_wolf": "Wolf Armor is fastened", + "subtitles.item.armor.unequip_wolf": "Wolf Armor snips away", + "subtitles.item.mace.smash_air": "Mace smashes", + "subtitles.item.mace.smash_ground": "Mace smashes", + "subtitles.item.ominous_bottle.dispose": "Bottle breaks", + "subtitles.item.wolf_armor.break": "Wolf Armor breaks", + "subtitles.item.wolf_armor.crack": "Wolf Armor cracks", + "subtitles.item.wolf_armor.damage": "Wolf Armor takes damage", + "subtitles.item.wolf_armor.repair": "Wolf Armor is repaired", + "trim_pattern.minecraft.bolt": "Bolt Armor Trim", + "trim_pattern.minecraft.flow": "Flow Armor Trim" }, "1.20.3": { "accessibility.onboarding.accessibility.button": "Accessibility Settings...",