Search in sources :

Example 1 with IIngredient

use of org.lanternpowered.server.item.recipe.IIngredient in project LanternServer by LanternPowered.

the class LanternFurnace method pulse.

@Override
public void pulse() {
    super.pulse();
    if (this.lastTick == -1) {
        this.lastTick = LanternGame.currentTimeTicks();
        return;
    }
    final long ticks = LanternGame.currentTimeTicks();
    long elapsed = ticks - this.lastTick;
    // This shouldn't happen
    if (elapsed == 0) {
        return;
    }
    this.lastTick = ticks;
    while (elapsed > 0) {
        int maxCookTime = 0;
        Optional<SmeltingResult> smeltingResult = Optional.empty();
        Optional<SmeltingRecipe> smeltingRecipe = Optional.empty();
        ItemStack itemStack = this.inventory.getInputSlot().getRawItemStack();
        final ItemStackSnapshot inputSlotItemSnapshot = itemStack == null ? null : itemStack.createSnapshot();
        if (inputSlotItemSnapshot != null) {
            // Check if the item can be smelted, this means finding a compatible
            // recipe and the output has to be empty.
            smeltingRecipe = Lantern.getRegistry().getSmeltingRecipeRegistry().findMatchingRecipe(inputSlotItemSnapshot);
            if (smeltingRecipe.isPresent()) {
                final int quantity = ((ISmeltingRecipe) smeltingRecipe.get()).getIngredient().getQuantity(inputSlotItemSnapshot);
                if (inputSlotItemSnapshot.getQuantity() >= quantity) {
                    smeltingResult = smeltingRecipe.get().getResult(inputSlotItemSnapshot);
                    // Check if the item can be smelted
                    if (smeltingResult.isPresent()) {
                        // Check if the result could be added to the output
                        final PeekedOfferTransactionResult peekResult = this.inventory.getOutputSlot().peekOffer(smeltingResult.get().getResult().createStack());
                        if (peekResult.isSuccess()) {
                            maxCookTime = ((ISmeltingRecipe) smeltingRecipe.get()).getSmeltTime(inputSlotItemSnapshot).orElse(200);
                        }
                    }
                }
            }
        }
        // The ticks that are elapsed in this loop, limit
        // this to one cooking cycle, this can only happen
        // if actually a item is being cooked
        long elapsed1 = elapsed;
        int elapsedCookTime = get(Keys.PASSED_COOK_TIME).get();
        int remainingCookTime = maxCookTime - elapsedCookTime;
        if (maxCookTime > 0 && elapsed1 > remainingCookTime) {
            elapsed1 = remainingCookTime;
        }
        elapsed -= elapsed1;
        // Burn items until the furnace is burning properly
        int maxBurnTime = get(Keys.MAX_BURN_TIME).get();
        int elapsedBurnTime = get(Keys.PASSED_BURN_TIME).get();
        int remainingBurnTime = maxBurnTime - elapsedBurnTime;
        long elapsed2 = elapsed1;
        while (elapsed2 >= remainingBurnTime) {
            elapsed2 -= remainingBurnTime;
            // Reset the max burn time
            maxBurnTime = 0;
            // Only burn a new item if the target item can be smelted
            itemStack = this.inventory.getFuelSlot().getRawItemStack();
            if (itemStack != null && maxCookTime > 0) {
                // Check for the next fuel item
                final ItemStackSnapshot itemStackSnapshot = itemStack.createSnapshot();
                final Optional<IFuel> result = Lantern.getRegistry().getFuelRegistry().findMatching(itemStackSnapshot);
                if (result.isPresent()) {
                    final OptionalInt optBurnTime = result.get().getBurnTime(itemStackSnapshot);
                    // We have a next matching burn item, check if we can poll one and then continue burning
                    if (optBurnTime.isPresent() && this.inventory.getFuelSlot().poll(1).isPresent()) {
                        maxBurnTime = optBurnTime.getAsInt();
                        remainingBurnTime = maxBurnTime;
                        elapsedBurnTime = 0;
                        // Put the rest item in the slot, if the slot is empty
                        if (this.inventory.getFuelSlot().size() == 0) {
                            final IIngredient ingredient = result.get().getIngredient();
                            final Optional<ItemStack> remainingItem = ingredient.getRemainingItem(itemStackSnapshot);
                            remainingItem.ifPresent(this.inventory.getFuelSlot()::setForced);
                        }
                    }
                }
            }
            if (maxBurnTime == 0) {
                break;
            }
        }
        elapsedBurnTime = maxBurnTime == 0 ? 0 : (int) (elapsedBurnTime + elapsed2);
        remainingBurnTime = maxBurnTime - elapsedBurnTime;
        offer(Keys.MAX_BURN_TIME, maxBurnTime);
        offer(Keys.PASSED_BURN_TIME, elapsedBurnTime);
        if (maxCookTime > 0) {
            // The furnace is still burning
            if (remainingBurnTime > 0) {
                // The item is smelted
                if (elapsed1 >= remainingCookTime) {
                    offer(Keys.MAX_COOK_TIME, 0);
                    offer(Keys.PASSED_COOK_TIME, 0);
                    final int quantity = ((ISmeltingRecipe) smeltingRecipe.get()).getIngredient().getQuantity(inputSlotItemSnapshot);
                    this.inventory.getOutputSlot().offer(smeltingResult.get().getResult().createStack());
                    this.inventory.getInputSlot().poll(quantity);
                    // Put the rest item in the slot
                    if (this.inventory.getInputSlot().size() == 0) {
                        final IIngredient ingredient = ((ISmeltingRecipe) smeltingRecipe.get()).getIngredient();
                        final Optional<ItemStack> remainingItem = ingredient.getRemainingItem(inputSlotItemSnapshot);
                        remainingItem.ifPresent(this.inventory.getInputSlot()::set);
                    }
                } else {
                    // Keep on smelting
                    offer(Keys.MAX_COOK_TIME, maxCookTime);
                    offer(Keys.PASSED_COOK_TIME, (int) (elapsedCookTime + elapsed1));
                    break;
                }
            } else if (elapsedCookTime > 0) {
                // Undo smelting progress
                final long time = elapsedCookTime - elapsed1 * 2;
                offer(Keys.MAX_COOK_TIME, time <= 0 ? 0 : maxCookTime);
                offer(Keys.PASSED_COOK_TIME, (int) (time <= 0 ? 0 : time));
                break;
            }
        } else {
            offer(Keys.MAX_COOK_TIME, 0);
            offer(Keys.PASSED_COOK_TIME, 0);
        }
    }
    BlockState blockState = getLocation().getBlock();
    final boolean burning = get(Keys.PASSED_BURN_TIME).get() < get(Keys.MAX_BURN_TIME).get();
    final boolean blockBurning = blockState.getType() == BlockTypes.LIT_FURNACE;
    if (burning != blockBurning) {
        blockState = (burning ? BlockTypes.LIT_FURNACE : BlockTypes.FURNACE).getDefaultState().withTrait(LanternEnumTraits.HORIZONTAL_FACING, blockState.getTraitValue(LanternEnumTraits.HORIZONTAL_FACING).get()).get();
        getLocation().setBlock(blockState);
    }
}
Also used : IIngredient(org.lanternpowered.server.item.recipe.IIngredient) PeekedOfferTransactionResult(org.lanternpowered.server.inventory.PeekedOfferTransactionResult) OptionalInt(java.util.OptionalInt) BlockState(org.spongepowered.api.block.BlockState) SmeltingRecipe(org.spongepowered.api.item.recipe.smelting.SmeltingRecipe) ISmeltingRecipe(org.lanternpowered.server.item.recipe.smelting.ISmeltingRecipe) ItemStackSnapshot(org.spongepowered.api.item.inventory.ItemStackSnapshot) IFuel(org.lanternpowered.server.item.recipe.fuel.IFuel) ISmeltingRecipe(org.lanternpowered.server.item.recipe.smelting.ISmeltingRecipe) ItemStack(org.spongepowered.api.item.inventory.ItemStack) SmeltingResult(org.spongepowered.api.item.recipe.smelting.SmeltingResult)

Example 2 with IIngredient

use of org.lanternpowered.server.item.recipe.IIngredient in project LanternServer by LanternPowered.

the class LanternShapelessCraftingRecipe method match.

@Override
public Optional<Result> match(CraftingMatrix craftingMatrix, @Nullable World world, int flags) {
    final int w = craftingMatrix.width();
    final int h = craftingMatrix.height();
    final int s = w * h;
    // Check if all the ingredients can fit in the crafting grid
    if (this.ingredients.size() > s) {
        return Optional.empty();
    }
    final boolean resultItem = (flags & Flags.RESULT_ITEM) != 0;
    final boolean remainingItems = (flags & Flags.REMAINING_ITEMS) != 0;
    final List<Ingredient> ingredients = new ArrayList<>(this.ingredients);
    // Generate a ingredient map that can be useful to generate a result item
    final Multimap<Ingredient, ItemStack> ingredientItems = resultItem && !(this.resultProvider instanceof ConstantCraftingResultProvider) ? HashMultimap.create() : null;
    final ImmutableList.Builder<ItemStackSnapshot> remainingItemsBuilder = remainingItems ? ImmutableList.builder() : null;
    int times = -1;
    int[][] itemQuantities = remainingItems ? new int[w][h] : null;
    for (int j = 0; j < h; j++) {
        for (int i = 0; i < w; i++) {
            final ItemStack itemStack = craftingMatrix.get(i, j);
            // Don't check empty item stacks
            if (itemStack.isEmpty()) {
                remainingItemsBuilder.add(ItemStackSnapshot.NONE);
                continue;
            }
            final Iterator<Ingredient> it = ingredients.iterator();
            Optional<ItemStack> remainingItem = Optional.empty();
            boolean success = false;
            while (it.hasNext()) {
                final IIngredient ingredient = (IIngredient) it.next();
                if (!ingredient.test(itemStack)) {
                    continue;
                }
                final int quantity = ingredient.getQuantity(itemStack);
                if (quantity < itemStack.getQuantity()) {
                    continue;
                }
                itemQuantities[i][j] = quantity;
                final int times1 = itemStack.getQuantity() / quantity;
                if (times == -1 || times1 < times) {
                    times = times1;
                }
                if (ingredientItems != null) {
                    ingredientItems.put(ingredient, itemStack);
                }
                if (remainingItemsBuilder != null) {
                    remainingItem = ingredient.getRemainingItem(itemStack);
                }
                it.remove();
                success = true;
                break;
            }
            // A faulty input ingredient was found
            if (!success) {
                return Optional.empty();
            }
            if (remainingItemsBuilder != null) {
                remainingItemsBuilder.add(remainingItem.map(ItemStack::createSnapshot).orElse(ItemStackSnapshot.NONE));
            }
        }
    }
    // Not all the ingredients were found
    if (!ingredients.isEmpty()) {
        return Optional.empty();
    }
    // Generate the result item
    ItemStackSnapshot resultItemStack = null;
    if (resultItem) {
        resultItemStack = this.resultProvider.getSnapshot(craftingMatrix, ingredientItems == null ? null : new SimpleIngredientList(ingredientItems));
        checkNotNull(resultItemStack, "Something funky happened.");
    }
    return Optional.of(new Result(resultItemStack, remainingItemsBuilder == null ? null : remainingItemsBuilder.build(), itemQuantities, times));
}
Also used : IIngredient(org.lanternpowered.server.item.recipe.IIngredient) ImmutableList(com.google.common.collect.ImmutableList) ArrayList(java.util.ArrayList) IIngredient(org.lanternpowered.server.item.recipe.IIngredient) Ingredient(org.spongepowered.api.item.recipe.crafting.Ingredient) ItemStackSnapshot(org.spongepowered.api.item.inventory.ItemStackSnapshot) ItemStack(org.spongepowered.api.item.inventory.ItemStack)

Example 3 with IIngredient

use of org.lanternpowered.server.item.recipe.IIngredient in project LanternServer by LanternPowered.

the class LanternShapedCraftingRecipe method matchAt.

/**
 * Matches this recipe at the given start x
 * and y coordinates within the {@link CraftingMatrix}.
 *
 * @param craftingMatrix The crafting matrix
 * @param startX The initial x coordinate
 * @param startY The initial y coordinate
 * @return Whether the recipe matches
 */
@Nullable
private Result matchAt(CraftingMatrix craftingMatrix, int startX, int startY, int flags, int[][] itemQuantities) {
    // Clear the quantities
    fill(itemQuantities, 0);
    final int cw = craftingMatrix.width();
    final int ch = craftingMatrix.height();
    final int rw = getWidth();
    final int rh = getHeight();
    final int ew = startX + rw;
    final int eh = startY + rh;
    // The recipe no longer fits within the grid when starting from the coordinates
    if (ew > cw || eh > ch) {
        return null;
    }
    final boolean resultItem = (flags & Flags.RESULT_ITEM) != 0;
    // Generate a ingredient map that can be useful to generate a result item
    final Multimap<Ingredient, ItemStack> ingredientItems = resultItem && !(this.resultProvider instanceof ConstantCraftingResultProvider) ? HashMultimap.create() : null;
    int times = -1;
    for (int y = 0; y < ch; y++) {
        for (int x = 0; x < cw; x++) {
            final ItemStack itemStack = craftingMatrix.get(x, y);
            final int i = x - startX;
            final int j = y - startY;
            final IIngredient ingredient = i < 0 || i >= rw || j < 0 || j >= rh ? null : this.ingredients[i][j];
            if (ingredient == null) {
                if (itemStack.isEmpty()) {
                    continue;
                }
                return null;
            }
            final int quantity = ingredient.getQuantity(itemStack);
            if (!ingredient.test(itemStack) || itemStack.getQuantity() < quantity) {
                return null;
            }
            itemQuantities[x][y] = quantity;
            final int times1 = itemStack.getQuantity() / quantity;
            if (times == -1 || times1 < times) {
                times = times1;
            }
            if (ingredientItems != null) {
                ingredientItems.put(ingredient, itemStack);
            }
        }
    }
    // Generate the result item
    ItemStackSnapshot resultItemStack = null;
    if (resultItem) {
        resultItemStack = this.resultProvider.getSnapshot(craftingMatrix, ingredientItems == null ? null : new SimpleIngredientList(ingredientItems));
        checkNotNull(resultItemStack, "Something funky happened.");
    }
    // Generate a list with all the remaining items, doing this for every
    // slot, even empty ones, empty ones are added as a empty remaining
    // item.
    List<ItemStackSnapshot> remainingItemsList = null;
    if ((flags & Flags.REMAINING_ITEMS) != 0) {
        final List<ItemStackSnapshot> builder = new ArrayList<>();
        for (int i = 0; i < ch * cw; i++) {
            builder.add(ItemStackSnapshot.NONE);
        }
        for (int j = 0; j < rh; j++) {
            for (int i = 0; i < rw; i++) {
                final IIngredient ingredient = this.ingredients[i][j];
                if (ingredient != null) {
                    final Optional<ItemStack> remainingItem = ingredient.getRemainingItem(craftingMatrix.get(i, j));
                    if (remainingItem.isPresent()) {
                        builder.set((j + startY) * cw + (i + startX), LanternItemStack.toSnapshot(remainingItem.get()));
                    }
                }
            }
        }
        remainingItemsList = ImmutableList.copyOf(builder);
    }
    return new Result(resultItemStack, remainingItemsList, itemQuantities, times);
}
Also used : IIngredient(org.lanternpowered.server.item.recipe.IIngredient) ArrayList(java.util.ArrayList) IIngredient(org.lanternpowered.server.item.recipe.IIngredient) Ingredient(org.spongepowered.api.item.recipe.crafting.Ingredient) ItemStackSnapshot(org.spongepowered.api.item.inventory.ItemStackSnapshot) ItemStack(org.spongepowered.api.item.inventory.ItemStack) LanternItemStack(org.lanternpowered.server.inventory.LanternItemStack) Nullable(javax.annotation.Nullable)

Example 4 with IIngredient

use of org.lanternpowered.server.item.recipe.IIngredient in project LanternServer by LanternPowered.

the class LanternShapedCraftingRecipeBuilder method build.

@Override
public IShapedCraftingRecipe build(String id, Object plugin) {
    checkState(!this.aisle.isEmpty(), "aisle has not been set");
    checkState(!this.ingredientMap.isEmpty(), "no ingredients set");
    checkState(this.resultProvider != null, "no result provider");
    checkNotNull(id, "id");
    checkNotNull(id, "plugin");
    final PluginContainer container = checkPlugin(plugin, "plugin");
    final int index = id.indexOf(':');
    if (index != -1) {
        final String pluginId = id.substring(0, index);
        checkState(pluginId.equals(container.getId()), "Plugin ids mismatch, " + "found %s in the id but got %s from the container", pluginId, container.getId());
        id = id.substring(index + 1);
    }
    final int h = this.aisle.size();
    checkState(h > 0, "The aisle cannot be empty.");
    final int w = this.aisle.get(0).length();
    checkState(w > 0, "The aisle cannot be empty.");
    final IIngredient[][] ingredients = new IIngredient[w][h];
    for (int j = 0; j < h; j++) {
        final String s = this.aisle.get(j);
        checkState(s.length() == w, "The aisle has an inconsistent width.");
        for (int i = 0; i < w; i++) {
            final char c = s.charAt(i);
            final Ingredient ingredient;
            if (c == ' ') {
                ingredient = Ingredient.NONE;
            } else {
                ingredient = this.ingredientMap.get(c);
                checkState(ingredient != null, "No ingredient is present for the character: %s", c);
            }
            ingredients[i][j] = (IIngredient) ingredient;
        }
    }
    final ItemStackSnapshot exemplary = this.resultProvider.getSnapshot(EmptyCraftingMatrix.INSTANCE, EmptyIngredientList.INSTANCE);
    return new LanternShapedCraftingRecipe(container.getId(), id, exemplary, this.groupName, this.resultProvider, ingredients);
}
Also used : IIngredient(org.lanternpowered.server.item.recipe.IIngredient) PluginContainer(org.spongepowered.api.plugin.PluginContainer) IIngredient(org.lanternpowered.server.item.recipe.IIngredient) Ingredient(org.spongepowered.api.item.recipe.crafting.Ingredient) ItemStackSnapshot(org.spongepowered.api.item.inventory.ItemStackSnapshot)

Aggregations

IIngredient (org.lanternpowered.server.item.recipe.IIngredient)4 ItemStackSnapshot (org.spongepowered.api.item.inventory.ItemStackSnapshot)4 ItemStack (org.spongepowered.api.item.inventory.ItemStack)3 Ingredient (org.spongepowered.api.item.recipe.crafting.Ingredient)3 ArrayList (java.util.ArrayList)2 ImmutableList (com.google.common.collect.ImmutableList)1 OptionalInt (java.util.OptionalInt)1 Nullable (javax.annotation.Nullable)1 LanternItemStack (org.lanternpowered.server.inventory.LanternItemStack)1 PeekedOfferTransactionResult (org.lanternpowered.server.inventory.PeekedOfferTransactionResult)1 IFuel (org.lanternpowered.server.item.recipe.fuel.IFuel)1 ISmeltingRecipe (org.lanternpowered.server.item.recipe.smelting.ISmeltingRecipe)1 BlockState (org.spongepowered.api.block.BlockState)1 SmeltingRecipe (org.spongepowered.api.item.recipe.smelting.SmeltingRecipe)1 SmeltingResult (org.spongepowered.api.item.recipe.smelting.SmeltingResult)1 PluginContainer (org.spongepowered.api.plugin.PluginContainer)1