//  [java]
    public void translate(ServerDeclareRecipesPacket packet, GeyserSession session) {
        Map<RecipeType, List<CraftingData>> recipeTypes = Registries.CRAFTING_DATA.forVersion(session.getUpstream().getProtocolVersion());
        // Get the last known network ID (first used for the pregenerated recipes) and increment from there.
        int netId = InventoryUtils.LAST_RECIPE_NET_ID + 1;

        Int2ObjectMap<Recipe> recipeMap = new Int2ObjectOpenHashMap<>(Registries.RECIPES.forVersion(session.getUpstream().getProtocolVersion()));
        Int2ObjectMap<List<StoneCuttingRecipeData>> unsortedStonecutterData = new Int2ObjectOpenHashMap<>();
        CraftingDataPacket craftingDataPacket = new CraftingDataPacket();
        craftingDataPacket.setCleanRecipes(true);
        for (Recipe recipe : packet.getRecipes()) {
            switch (recipe.getType()) {
                case CRAFTING_SHAPELESS: {
                    ShapelessRecipeData shapelessRecipeData = (ShapelessRecipeData) recipe.getData();
                    ItemData output = ItemTranslator.translateToBedrock(session, shapelessRecipeData.getResult());
                    // Strip NBT - tools won't appear in the recipe book otherwise
                    output = output.toBuilder().tag(null).build();
                    ItemData[][] inputCombinations = combinations(session, shapelessRecipeData.getIngredients());
                    for (ItemData[] inputs : inputCombinations) {
                        UUID uuid = UUID.randomUUID();
                        craftingDataPacket.getCraftingData().add(CraftingData.fromShapeless(uuid.toString(),
                                Arrays.asList(inputs), Collections.singletonList(output), uuid, "crafting_table", 0, netId));
                        recipeMap.put(netId++, recipe);
                    }
                    break;
                }
                case CRAFTING_SHAPED: {
                    ShapedRecipeData shapedRecipeData = (ShapedRecipeData) recipe.getData();
                    ItemData output = ItemTranslator.translateToBedrock(session, shapedRecipeData.getResult());
                    // See above
                    output = output.toBuilder().tag(null).build();
                    ItemData[][] inputCombinations = combinations(session, shapedRecipeData.getIngredients());
                    for (ItemData[] inputs : inputCombinations) {
                        UUID uuid = UUID.randomUUID();
                        craftingDataPacket.getCraftingData().add(CraftingData.fromShaped(uuid.toString(),
                                shapedRecipeData.getWidth(), shapedRecipeData.getHeight(), Arrays.asList(inputs),
                                        Collections.singletonList(output), uuid, "crafting_table", 0, netId));
                        recipeMap.put(netId++, recipe);
                    }
                    break;
                }
                case STONECUTTING: {
                    StoneCuttingRecipeData stoneCuttingData = (StoneCuttingRecipeData) recipe.getData();
                    ItemStack ingredient = stoneCuttingData.getIngredient().getOptions()[0];
                    List<StoneCuttingRecipeData> data = unsortedStonecutterData.get(ingredient.getId());
                    if (data == null) {
                        data = new ArrayList<>();
                        unsortedStonecutterData.put(ingredient.getId(), data);
                    }
                    data.add(stoneCuttingData);
                    // Save for processing after all recipes have been received
                    break;
                }
                default: {
                    List<CraftingData> craftingData = recipeTypes.get(recipe.getType());
                    if (craftingData != null) {
                        craftingDataPacket.getCraftingData().addAll(craftingData);
                    }
                    break;
                }
            }
        }
        craftingDataPacket.getCraftingData().addAll(CARTOGRAPHY_RECIPES);
        craftingDataPacket.getPotionMixData().addAll(Registries.POTION_MIXES.get());

        Int2ObjectMap<IntList> stonecutterRecipeMap = new Int2ObjectOpenHashMap<>();
        for (Int2ObjectMap.Entry<List<StoneCuttingRecipeData>> data : unsortedStonecutterData.int2ObjectEntrySet()) {
            // Sort the list by each output item's Java identifier - this is how it's sorted on Java, and therefore
            // We can get the correct order for button pressing
            data.getValue().sort(Comparator.comparing((stoneCuttingRecipeData ->
                    session.getItemMappings().getItems().get(stoneCuttingRecipeData.getResult().getId()).getJavaIdentifier())));

            // Now that it's sorted, let's translate these recipes
            for (StoneCuttingRecipeData stoneCuttingData : data.getValue()) {
                // As of 1.16.4, all stonecutter recipes have one ingredient option
                ItemStack ingredient = stoneCuttingData.getIngredient().getOptions()[0];
                ItemData input = ItemTranslator.translateToBedrock(session, ingredient);
                ItemData output = ItemTranslator.translateToBedrock(session, stoneCuttingData.getResult());
                UUID uuid = UUID.randomUUID();

                // We need to register stonecutting recipes so they show up on Bedrock
                craftingDataPacket.getCraftingData().add(CraftingData.fromShapeless(uuid.toString(),
                        Collections.singletonList(input), Collections.singletonList(output), uuid, "stonecutter", 0, netId++));

                // Save the recipe list for reference when crafting
                IntList outputs = stonecutterRecipeMap.get(ingredient.getId());
                if (outputs == null) {
                    outputs = new IntArrayList();
                    // Add the ingredient as the key and all possible values as the value
                    stonecutterRecipeMap.put(ingredient.getId(), outputs);
                }
                outputs.add(stoneCuttingData.getResult().getId());
            }
        }

        session.sendUpstreamPacket(craftingDataPacket);
        session.setCraftingRecipes(recipeMap);
        session.getUnlockedRecipes().clear();
        session.setStonecutterRecipes(stonecutterRecipeMap);
        session.getLastRecipeNetId().set(netId);
    }