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);
}
}
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));
}
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);
}
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);
}
Aggregations