Search in sources :

Example 1 with Ingredient

use of com.github.steveice10.mc.protocol.data.game.recipe.Ingredient in project Geyser by GeyserMC.

the class JavaContainerSetSlotTranslator method updateCraftingGrid.

/**
 * Checks for a changed output slot in the crafting grid, and ensures Bedrock sees the recipe.
 */
private static void updateCraftingGrid(GeyserSession session, int slot, ItemStack item, Inventory inventory, InventoryTranslator translator) {
    if (slot != 0) {
        return;
    }
    int gridSize = translator.getGridSize();
    if (gridSize == -1) {
        return;
    }
    if (item == null || item.getId() == 0) {
        return;
    }
    session.setCraftingGridFuture(session.scheduleInEventLoop(() -> {
        int offset = gridSize == 4 ? 28 : 32;
        int gridDimensions = gridSize == 4 ? 2 : 3;
        int firstRow = -1, height = -1;
        int firstCol = -1, width = -1;
        for (int row = 0; row < gridDimensions; row++) {
            for (int col = 0; col < gridDimensions; col++) {
                if (!inventory.getItem(col + (row * gridDimensions) + 1).isEmpty()) {
                    if (firstRow == -1) {
                        firstRow = row;
                        firstCol = col;
                    } else {
                        firstCol = Math.min(firstCol, col);
                    }
                    height = Math.max(height, row);
                    width = Math.max(width, col);
                }
            }
        }
        // empty grid
        if (firstRow == -1) {
            return;
        }
        height += -firstRow + 1;
        width += -firstCol + 1;
        if (InventoryUtils.getValidRecipe(session, item, inventory::getItem, gridDimensions, firstRow, height, firstCol, width) != null) {
            // Recipe is already present on the client; don't send packet
            return;
        }
        UUID uuid = UUID.randomUUID();
        int newRecipeId = session.getLastRecipeNetId().incrementAndGet();
        ItemData[] ingredients = new ItemData[height * width];
        // construct ingredient list and clear slots on client
        Ingredient[] javaIngredients = new Ingredient[height * width];
        int index = 0;
        for (int row = firstRow; row < height + firstRow; row++) {
            for (int col = firstCol; col < width + firstCol; col++) {
                GeyserItemStack geyserItemStack = inventory.getItem(col + (row * gridDimensions) + 1);
                ingredients[index] = geyserItemStack.getItemData(session);
                ItemStack[] itemStacks = new ItemStack[] { geyserItemStack.isEmpty() ? null : geyserItemStack.getItemStack(1) };
                javaIngredients[index] = new Ingredient(itemStacks);
                InventorySlotPacket slotPacket = new InventorySlotPacket();
                slotPacket.setContainerId(ContainerId.UI);
                slotPacket.setSlot(col + (row * gridDimensions) + offset);
                slotPacket.setItem(ItemData.AIR);
                session.sendUpstreamPacket(slotPacket);
                index++;
            }
        }
        // Cache this recipe so we know the client has received it
        session.getCraftingRecipes().put(newRecipeId, new GeyserShapedRecipe(width, height, javaIngredients, item));
        CraftingDataPacket craftPacket = new CraftingDataPacket();
        craftPacket.getCraftingData().add(CraftingData.fromShaped(uuid.toString(), width, height, Arrays.asList(ingredients), Collections.singletonList(ItemTranslator.translateToBedrock(session, item)), uuid, "crafting_table", 0, newRecipeId));
        craftPacket.setCleanRecipes(false);
        session.sendUpstreamPacket(craftPacket);
        index = 0;
        for (int row = firstRow; row < height + firstRow; row++) {
            for (int col = firstCol; col < width + firstCol; col++) {
                InventorySlotPacket slotPacket = new InventorySlotPacket();
                slotPacket.setContainerId(ContainerId.UI);
                slotPacket.setSlot(col + (row * gridDimensions) + offset);
                slotPacket.setItem(ingredients[index]);
                session.sendUpstreamPacket(slotPacket);
                index++;
            }
        }
    }, 150, TimeUnit.MILLISECONDS));
}
Also used : Ingredient(com.github.steveice10.mc.protocol.data.game.recipe.Ingredient) InventorySlotPacket(com.nukkitx.protocol.bedrock.packet.InventorySlotPacket) GeyserShapedRecipe(org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe) UUID(java.util.UUID) CraftingDataPacket(com.nukkitx.protocol.bedrock.packet.CraftingDataPacket) GeyserItemStack(org.geysermc.geyser.inventory.GeyserItemStack)

Example 2 with Ingredient

use of com.github.steveice10.mc.protocol.data.game.recipe.Ingredient in project Geyser by GeyserMC.

the class RecipeRegistryPopulator method getCraftingDataFromJsonNode.

/**
 * Computes a Bedrock crafting recipe from the given JSON data.
 * @param node the JSON data to compute
 * @param recipes a list of all the recipes
 * @return the {@link CraftingData} to send to the Bedrock client.
 */
private static CraftingData getCraftingDataFromJsonNode(JsonNode node, Int2ObjectMap<GeyserRecipe> recipes, ItemMappings mappings) {
    int netId = ++LAST_RECIPE_NET_ID;
    int type = node.get("bedrockRecipeType").asInt();
    JsonNode outputNode = node.get("output");
    ItemMapping outputEntry = mappings.getMapping(outputNode.get("identifier").asText());
    ItemData output = getBedrockItemFromIdentifierJson(outputEntry, outputNode);
    UUID uuid = UUID.randomUUID();
    if (type == 1) {
        // Shaped recipe
        List<String> shape = new ArrayList<>();
        // Get the shape of the recipe
        for (JsonNode chars : node.get("shape")) {
            shape.add(chars.asText());
        }
        // In recipes.json each recipe is mapped by a letter
        Map<String, ItemData> letterToRecipe = new HashMap<>();
        Iterator<Map.Entry<String, JsonNode>> iterator = node.get("inputs").fields();
        while (iterator.hasNext()) {
            Map.Entry<String, JsonNode> entry = iterator.next();
            JsonNode inputNode = entry.getValue();
            ItemMapping inputEntry = mappings.getMapping(inputNode.get("identifier").asText());
            letterToRecipe.put(entry.getKey(), getBedrockItemFromIdentifierJson(inputEntry, inputNode));
        }
        List<ItemData> inputs = new ArrayList<>(shape.size() * shape.get(0).length());
        int i = 0;
        // Create a linear array of items from the "cube" of the shape
        for (int j = 0; i < shape.size() * shape.get(0).length(); j++) {
            for (char c : shape.get(j).toCharArray()) {
                ItemData data = letterToRecipe.getOrDefault(String.valueOf(c), ItemData.AIR);
                inputs.add(data);
                i++;
            }
        }
        /* Convert into a Java recipe class for autocrafting */
        List<Ingredient> ingredients = new ArrayList<>();
        for (ItemData input : inputs) {
            ingredients.add(new Ingredient(new ItemStack[] { ItemTranslator.translateToJava(input, mappings) }));
        }
        GeyserRecipe recipe = new GeyserShapedRecipe(shape.get(0).length(), shape.size(), ingredients.toArray(new Ingredient[0]), ItemTranslator.translateToJava(output, mappings));
        recipes.put(netId, recipe);
        return CraftingData.fromShaped(uuid.toString(), shape.get(0).length(), shape.size(), inputs, Collections.singletonList(output), uuid, "crafting_table", 0, netId);
    }
    List<ItemData> inputs = new ObjectArrayList<>();
    for (JsonNode entry : node.get("inputs")) {
        ItemMapping inputEntry = mappings.getMapping(entry.get("identifier").asText());
        inputs.add(getBedrockItemFromIdentifierJson(inputEntry, entry));
    }
    /* Convert into a Java Recipe class for autocrafting */
    List<Ingredient> ingredients = new ArrayList<>();
    for (ItemData input : inputs) {
        ingredients.add(new Ingredient(new ItemStack[] { ItemTranslator.translateToJava(input, mappings) }));
    }
    GeyserRecipe recipe = new GeyserShapelessRecipe(ingredients.toArray(new Ingredient[0]), ItemTranslator.translateToJava(output, mappings));
    recipes.put(netId, recipe);
    if (type == 5) {
        // Shulker box
        return CraftingData.fromShulkerBox(uuid.toString(), inputs, Collections.singletonList(output), uuid, "crafting_table", 0, netId);
    }
    return CraftingData.fromShapeless(uuid.toString(), inputs, Collections.singletonList(output), uuid, "crafting_table", 0, netId);
}
Also used : GeyserShapelessRecipe(org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe) Int2ObjectOpenHashMap(it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap) ObjectArrayList(it.unimi.dsi.fastutil.objects.ObjectArrayList) JsonNode(com.fasterxml.jackson.databind.JsonNode) GeyserRecipe(org.geysermc.geyser.inventory.recipe.GeyserRecipe) ObjectArrayList(it.unimi.dsi.fastutil.objects.ObjectArrayList) Ingredient(com.github.steveice10.mc.protocol.data.game.recipe.Ingredient) ItemMapping(org.geysermc.geyser.registry.type.ItemMapping) GeyserShapedRecipe(org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe) ItemStack(com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack) NbtMap(com.nukkitx.nbt.NbtMap) Int2ObjectOpenHashMap(it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap) Int2ObjectMap(it.unimi.dsi.fastutil.ints.Int2ObjectMap) ItemData(com.nukkitx.protocol.bedrock.data.inventory.ItemData)

Aggregations

Ingredient (com.github.steveice10.mc.protocol.data.game.recipe.Ingredient)2 GeyserShapedRecipe (org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe)2 JsonNode (com.fasterxml.jackson.databind.JsonNode)1 ItemStack (com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack)1 NbtMap (com.nukkitx.nbt.NbtMap)1 ItemData (com.nukkitx.protocol.bedrock.data.inventory.ItemData)1 CraftingDataPacket (com.nukkitx.protocol.bedrock.packet.CraftingDataPacket)1 InventorySlotPacket (com.nukkitx.protocol.bedrock.packet.InventorySlotPacket)1 Int2ObjectMap (it.unimi.dsi.fastutil.ints.Int2ObjectMap)1 Int2ObjectOpenHashMap (it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap)1 ObjectArrayList (it.unimi.dsi.fastutil.objects.ObjectArrayList)1 UUID (java.util.UUID)1 GeyserItemStack (org.geysermc.geyser.inventory.GeyserItemStack)1 GeyserRecipe (org.geysermc.geyser.inventory.recipe.GeyserRecipe)1 GeyserShapelessRecipe (org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe)1 ItemMapping (org.geysermc.geyser.registry.type.ItemMapping)1