diff --git a/common/src/main/java/com/viaversion/viabackwards/protocol/v1_21_2to1_21/rewriter/BlockItemPacketRewriter1_21_2.java b/common/src/main/java/com/viaversion/viabackwards/protocol/v1_21_2to1_21/rewriter/BlockItemPacketRewriter1_21_2.java index 73f1132d..64be2e24 100644 --- a/common/src/main/java/com/viaversion/viabackwards/protocol/v1_21_2to1_21/rewriter/BlockItemPacketRewriter1_21_2.java +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/v1_21_2to1_21/rewriter/BlockItemPacketRewriter1_21_2.java @@ -180,12 +180,16 @@ public final class BlockItemPacketRewriter1_21_2 extends BackwardsStructuredItem protocol.registerClientbound(ClientboundPackets1_21_2.RECIPE_BOOK_ADD, null, wrapper -> { final RecipeStorage recipeStorage = wrapper.user().get(RecipeStorage.class); - recipeStorage.clearRecipes(); - final int size = wrapper.read(Types.VAR_INT); for (int i = 0; i < size; i++) { recipeStorage.readRecipe(wrapper); } + + final boolean replace = wrapper.read(Types.BOOLEAN); + if (replace) { + recipeStorage.clearRecipes(); + } + recipeStorage.sendRecipes(wrapper.user()); wrapper.cancel(); }); @@ -243,6 +247,29 @@ public final class BlockItemPacketRewriter1_21_2 extends BackwardsStructuredItem wrapper.write(Types.VAR_INT, intId); } + @Override + public void rewriteParticle(final UserConnection connection, final Particle particle) { + super.rewriteParticle(connection, particle); + + final String identifier = protocol.getMappingData().getParticleMappings().mappedIdentifier(particle.id()); + if (identifier.equals("minecraft:dust_color_transition")) { + argbToVector(particle, 0); + argbToVector(particle, 3); + } else if (identifier.equals("minecraft:dust")) { + argbToVector(particle, 0); + } + } + + private void argbToVector(final Particle particle, final int index) { + final int argb = particle.removeArgument(index).getValue(); + final float r = ((argb >> 16) & 0xFF) / 255F; + final float g = ((argb >> 8) & 0xFF) / 255F; + final float b = (argb & 0xFF) / 255F; + particle.add(index, Types.FLOAT, r); + particle.add(index + 1, Types.FLOAT, g); + particle.add(index + 2, Types.FLOAT, b); + } + @Override public Item handleItemToClient(final UserConnection connection, final Item item) { super.handleItemToClient(connection, item); diff --git a/common/src/main/java/com/viaversion/viabackwards/protocol/v1_21_2to1_21/storage/RecipeStorage.java b/common/src/main/java/com/viaversion/viabackwards/protocol/v1_21_2to1_21/storage/RecipeStorage.java index 010cddb3..6ab60e7f 100644 --- a/common/src/main/java/com/viaversion/viabackwards/protocol/v1_21_2to1_21/storage/RecipeStorage.java +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/v1_21_2to1_21/storage/RecipeStorage.java @@ -36,10 +36,10 @@ public final class RecipeStorage implements StorableObject { // Pairs of open + filtering for: Crafting, furnace, blast furnace, smoker public static final int RECIPE_BOOK_SETTINGS = 4 * 2; private final List recipes = new ArrayList<>(); + private final List tempRecipes = new ArrayList<>(); private final List stoneCutterRecipes = new ArrayList<>(); private boolean[] recipeBookSettings = new boolean[RECIPE_BOOK_SETTINGS]; private final Protocol1_21_2To1_21 protocol; - private int highestIndex; public RecipeStorage(final Protocol1_21_2To1_21 protocol) { this.protocol = protocol; @@ -86,6 +86,17 @@ public final class RecipeStorage implements StorableObject { } public void sendRecipes(final UserConnection connection) { + // Fill from temp recipes so we can clear before if needed + if (!tempRecipes.isEmpty()) { + this.recipes.addAll(tempRecipes); + tempRecipes.clear(); + } + + int highestIndex = -1; + for (final Recipe recipe : recipes) { + highestIndex = Math.max(highestIndex, recipe.index); + } + // Add stonecutter recipes from update_recipes final List recipes = new ArrayList<>(this.recipes); for (final StoneCutterRecipe recipe : stoneCutterRecipes) { @@ -170,7 +181,6 @@ public final class RecipeStorage implements StorableObject { recipe.group = group; recipe.category = category; } - highestIndex = Math.max(highestIndex, id); } private Recipe readShapeless(final PacketWrapper wrapper) { @@ -194,25 +204,31 @@ public final class RecipeStorage implements StorableObject { readSlotDisplay(wrapper); // Fuel final Item result = readSingleSlotDisplay(wrapper); readSlotDisplay(wrapper); // Crafting station - return add(new FurnaceRecipe(ingredient, result)); + final int duration = wrapper.read(Types.VAR_INT); + final float experience = wrapper.read(Types.FLOAT); + return add(new FurnaceRecipe(ingredient, result, duration, experience)); } private Recipe readStoneCutter(final PacketWrapper wrapper) { // Use values from UPDATE_RECIPES instead + readSlotDisplay(wrapper); // Input readSlotDisplay(wrapper); // Result readSlotDisplay(wrapper); // Crafting station return null; } private Recipe readSmithing(final PacketWrapper wrapper) { - // TODO Combine with update_recipes + // TODO Combine with update_recipes? + readSlotDisplay(wrapper); // Template + readSlotDisplay(wrapper); // Base + readSlotDisplay(wrapper); // Addition readSlotDisplay(wrapper); // Result readSlotDisplay(wrapper); // Crafting station return null; } private Recipe add(final Recipe recipe) { - recipes.add(recipe); + tempRecipes.add(recipe); return recipe; } @@ -255,7 +271,18 @@ public final class RecipeStorage implements StorableObject { wrapper.read(Types.STRING); // Tag key // TODO yield new Item[0]; } - case 6 -> readSlotDisplayList(wrapper)[0]; // Composite + case 5 -> { + readSlotDisplay(wrapper); // Base + readSlotDisplay(wrapper); // Material + readSlotDisplay(wrapper); // Pattern + yield new Item[0]; + } + case 6 -> { + readSlotDisplay(wrapper); // Input + readSlotDisplay(wrapper); // Remainder + yield new Item[0]; + } + case 7 -> readSlotDisplayList(wrapper)[0]; // Composite default -> new Item[0]; }; } @@ -348,10 +375,14 @@ public final class RecipeStorage implements StorableObject { private static final class FurnaceRecipe extends Recipe { private final Item[] ingredient; private final Item result; + private final float experience; + private final int cookingTime; - private FurnaceRecipe(final Item[] ingredient, final Item result) { + private FurnaceRecipe(final Item[] ingredient, final Item result, final int cookingTime, final float experience) { this.ingredient = ingredient; this.result = result; + this.experience = experience; + this.cookingTime = cookingTime; } @Override @@ -361,8 +392,8 @@ public final class RecipeStorage implements StorableObject { writeCategory(wrapper); writeIngredient(wrapper, ingredient); writeResult(wrapper, result); - wrapper.write(Types.FLOAT, 0F); // XP - wrapper.write(Types.VAR_INT, 200); // Cooking time, determined by the client in 1.21.2 + wrapper.write(Types.FLOAT, experience); + wrapper.write(Types.VAR_INT, cookingTime); } private int serializerId() { @@ -401,6 +432,5 @@ public final class RecipeStorage implements StorableObject { public void clearRecipes() { recipes.clear(); - highestIndex = 0; } } diff --git a/common/src/main/resources/assets/viabackwards/data/mappings-1.21.2to1.21.nbt b/common/src/main/resources/assets/viabackwards/data/mappings-1.21.2to1.21.nbt index b0f42eb5..41081c86 100644 Binary files a/common/src/main/resources/assets/viabackwards/data/mappings-1.21.2to1.21.nbt and b/common/src/main/resources/assets/viabackwards/data/mappings-1.21.2to1.21.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 2537fbfc..ada31d1f 100644 --- a/common/src/main/resources/assets/viabackwards/data/translation-mappings.json +++ b/common/src/main/resources/assets/viabackwards/data/translation-mappings.json @@ -1,40 +1,113 @@ { "1.21.2": { "attribute.name.tempt_range": "Mob Tempt Range", + "block.minecraft.creaking_heart": "Creaking Heart", + "block.minecraft.pale_hanging_moss": "Pale Hanging Moss", + "block.minecraft.pale_moss_block": "Pale Moss Block", + "block.minecraft.pale_moss_carpet": "Pale Moss Carpet", + "block.minecraft.pale_oak_button": "Pale Oak Button", + "block.minecraft.pale_oak_door": "Pale Oak Door", + "block.minecraft.pale_oak_fence": "Pale Oak Fence", + "block.minecraft.pale_oak_fence_gate": "Pale Oak Fence Gate", + "block.minecraft.pale_oak_hanging_sign": "Pale Oak Hanging Sign", + "block.minecraft.pale_oak_leaves": "Pale Oak Leaves", + "block.minecraft.pale_oak_log": "Pale Oak Log", + "block.minecraft.pale_oak_planks": "Pale Oak Planks", + "block.minecraft.pale_oak_pressure_plate": "Pale Oak Pressure Plate", + "block.minecraft.pale_oak_sapling": "Pale Oak Sapling", + "block.minecraft.pale_oak_sign": "Pale Oak Sign", + "block.minecraft.pale_oak_slab": "Pale Oak Slab", + "block.minecraft.pale_oak_stairs": "Pale Oak Stairs", + "block.minecraft.pale_oak_trapdoor": "Pale Oak Trapdoor", + "block.minecraft.pale_oak_wood": "Pale Oak Wood", + "block.minecraft.potted_pale_oak_sapling": "Potted Pale Oak Sapling", + "block.minecraft.stripped_pale_oak_log": "Stripped Pale Oak Log", + "block.minecraft.stripped_pale_oak_wood": "Stripped Pale Oak Wood", + "commands.drop.no_loot_table.block": "Block %s has no loot table", + "commands.rotate.success": "Rotated %s", "commands.schedule.macro": "Can't schedule a macro", "commands.setidletimeout.success.disabled": "The player idle timeout is now disabled", + "container.beehive.bees": "Bees: %s / %s", + "container.beehive.honey": "Honey: %s / %s", "dataPack.minecart_improvements.description": "Improved movement for Minecarts", "dataPack.minecart_improvements.name": "Minecart Improvements", "dataPack.redstone_experiments.description": "Experimental Redstone changes", "dataPack.redstone_experiments.name": "Redstone Experiments", + "dataPack.winter_drop.description": "New features and content for the Winter Drop", + "dataPack.winter_drop.name": "Winter Drop", "death.attack.mace_smash": "%1$s was smashed by %2$s", "death.attack.mace_smash.item": "%1$s was smashed by %2$s with %3$s", + "entity.minecraft.creaking": "Creaking", + "entity.minecraft.creaking_transient": "Creaking", + "entity.minecraft.pale_oak_boat": "Pale Oak Boat", + "entity.minecraft.pale_oak_chest_boat": "Pale Oak Boat with Chest", + "gamerule.disablePlayerMovementCheck": "Disable player movement check", "gamerule.minecartMaxSpeed": "Minecart max speed", - "gamerule.minecartMaxSpeed.description": "Maximum default speed of a moving Minecart on land", + "gamerule.minecartMaxSpeed.description": "Maximum default speed of a moving Minecart on land.", "gui.abuseReport.name.comment_box_label": "Please describe why you want to report this name:", "gui.abuseReport.reason.sexually_inappropriate": "Sexually inappropriate", "gui.abuseReport.reason.sexually_inappropriate.description": "Skins that are graphic in nature relating to sexual acts, sexual organs, and sexual violence.", + "item.minecraft.black_bundle": "Black Bundle", + "item.minecraft.blue_bundle": "Blue Bundle", "item.minecraft.bordure_indented_banner_pattern": "Bordure Indented Banner Pattern", + "item.minecraft.brown_bundle": "Brown Bundle", "item.minecraft.bundle.empty.description": "Can hold a mixed stack of items", "item.minecraft.bundle.full": "Full", + "item.minecraft.creaking_spawn_egg": "Creaking Spawn Egg", "item.minecraft.creeper_banner_pattern.new": "Creeper Charge Banner Pattern", + "item.minecraft.cyan_bundle": "Cyan Bundle", "item.minecraft.field_masoned_banner_pattern": "Field Masoned Banner Pattern", "item.minecraft.flow_banner_pattern.new": "Flow Banner Pattern", "item.minecraft.flower_banner_pattern.new": "Flower Charge Banner Pattern", "item.minecraft.globe_banner_pattern.new": "Globe Banner Pattern", + "item.minecraft.gray_bundle": "Gray Bundle", + "item.minecraft.green_bundle": "Green Bundle", "item.minecraft.guster_banner_pattern.new": "Guster Banner Pattern", + "item.minecraft.light_blue_bundle": "Light Blue Bundle", + "item.minecraft.light_gray_bundle": "Light Gray Bundle", + "item.minecraft.lime_bundle": "Lime Bundle", + "item.minecraft.magenta_bundle": "Magenta Bundle", "item.minecraft.mojang_banner_pattern.new": "Thing Banner Pattern", + "item.minecraft.orange_bundle": "Orange Bundle", + "item.minecraft.pale_oak_boat": "Pale Oak Boat", + "item.minecraft.pale_oak_chest_boat": "Pale Oak Boat with Chest", "item.minecraft.piglin_banner_pattern.new": "Snout Banner Pattern", + "item.minecraft.pink_bundle": "Pink Bundle", + "item.minecraft.purple_bundle": "Purple Bundle", + "item.minecraft.red_bundle": "Red Bundle", "item.minecraft.skull_banner_pattern.new": "Skull Charge Banner Pattern", + "item.minecraft.white_bundle": "White Bundle", + "item.minecraft.yellow_bundle": "Yellow Bundle", + "mco.create.world.failed": "Failed to create world!", + "mco.errorMessage.initialize.failed": "Failed to initialize Realm", + "mco.upload.failed.too_big.description": "The selected world is too big. The maximum allowed size is %s.", + "mco.upload.failed.too_big.title": "World too big", "optimizeWorld.confirm.proceed": "Create Backup and Optimize", + "options.accessibility.high_contrast_block_outline": "High Contrast Block Outlines", + "options.accessibility.high_contrast_block_outline.tooltip": "Enhances the block outline contrast of targeted block.", "options.inactivityFpsLimit": "Reduce FPS when", "options.inactivityFpsLimit.afk": "AFK", "options.inactivityFpsLimit.afk.tooltip": "Limits framerate to 30 when the game is not getting any player input for more than a minute. Further limits it to 10 after 9 more minutes.", "options.inactivityFpsLimit.minimized": "Minimized", "options.inactivityFpsLimit.minimized.tooltip": "Limits framerate only when the game window is minimized.", "options.rotateWithMinecart": "Rotate with Minecarts", - "options.rotateWithMinecart.tooltip": "If the player's view should rotate with a turning Minecart. Only available in worlds with the 'Minecart Improvements' experimental setting turned on.", - "subtitles.item.bundle.insert_fail": "Bundle full" + "options.rotateWithMinecart.tooltip": "Whether the player's view should rotate with a turning Minecart. Only available in worlds with the 'Minecart Improvements' experimental setting turned on.", + "resourcePack.runtime_failure": "Resource pack error detected", + "subtitles.block.creaking_heart.hurt": "Creaking Heart screams", + "subtitles.block.creaking_heart.spawn": "Creaking Heart awakens", + "subtitles.entity.creaking.activate": "Creaking activates", + "subtitles.entity.creaking.ambient": "Creaking creaks", + "subtitles.entity.creaking.angry": "Creaking sees player", + "subtitles.entity.creaking.attack": "Creaking attacks", + "subtitles.entity.creaking.deactivate": "Creaking deactivates", + "subtitles.entity.creaking.death": "Creaking dies", + "subtitles.entity.creaking.freeze": "Creaking stops", + "subtitles.entity.creaking.spawn": "Creaking lives", + "subtitles.entity.creaking.sway": "Creaking is shielded", + "subtitles.entity.creaking.unfreeze": "Creaking moves", + "subtitles.entity.parrot.imitate.creaking": "Parrot creaks", + "subtitles.item.bundle.insert_fail": "Bundle full", + "subtitles.ui.hud.bubble_pop": "Breath meter dropping" }, "1.21": { "argument.entity.selector.nearestEntity": "Nearest entity",