Jump to content

Recommended Posts

Posted

Ok, a bit of a bug report on this. For one it will only craft one instance of recipe, and then after that it will just delete the ingredients with each attempt, until the current save is reloaded. Another issue is that if a recipe contains similar ingredients to another it seems to spawn the other result.. I.e 1 stack of diamonds become diamond axes.

 

So basically it doesn't craft as many as it can, so that if you drop 90 diamonds, you expect 10 diamond blocks, but instead you get either diamond axes or absolutely nothing. It just doesn't seem to check if other ingredients also match, and such... I have an idea what could be causing it, but not sure.

 

Member of Aerotech Networks, a Multi-Gaming server.

Also Currently porting the "Rise of the Automatons" minecraft mod

Posted

Ok, so I have made good progress in getting the bugs worked out with this. In that it now crafts all it can, and give back proper results, and remainders... Still have one problem, it seems to be something to do with the findMatching method. In the sense that it has problems with recipes with multiple ingredients, doesn't seem to correctly check if the other ingredients are present to craft.

May just be a simple solution xD

Here is the findMatching method, followed by the fully updated code:

 

/**
 * Returns the matching {@link InWorldRecipe} that has the given items as
 * ingredients.
 * 
 * @param items
 *            A {@link List} of {@link ItemStack}s with items to test.
 * @return Either the mathing {@link InWorldRecipe} where the given items
 *         are ingredients or <code>null</code> if no recipe was found
 */
public InWorldRecipe findMatching(List<ItemStack> items) {
	for (InWorldRecipe recipe : recipes) {
		if (recipe.getRecipeSize() != items.size()) {
			continue; // the sizes do not match: next recipe please!
		}
		int nbMatchingItems = 0;
		for (ItemStack is : items) {
			if (recipe.containsIngredient(is)) {
				// okay, is is part of the recipe
				nbMatchingItems++;
			}
		}
		if (nbMatchingItems == recipe.getRecipeSize()) {
			// yeah found recipe (but did not check correct amount!)
			return recipe;
		} else {
			// not enough matching items
			return null;
		}
	}
	return null;
}

 

 

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Vector;

import net.minecraft.entity.item.EntityItem;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.world.World;
import cpw.mods.fml.common.event.FMLInitializationEvent;

/**
* A crafting manager that is capable of managing and crafting
* {@link InWorldRecipe}s.
* 
* It is recommended to add recipes during the {@link FMLInitializationEvent}.
* 
* This crafting manager can (currently only) add recipes of type
* {@link InWorldRecipe}. It is also able to find matching recipes for a given
* list of ingredients and processes the complete 'crafting process' for a given
* world and bounding box.
* 
* <p>
* <b>Warning</b> This class was written quickly and did not went through JUnit
* tests. Its also not very completed, since NBTTags do matter and this class
* just ignores them. The original idea comes from the minecraft forge forums:
* http://www.minecraftforge.net/forum/index.php/topic,24744.0.html
* </p>
* 
* @author pickaxe_engineer
* @Edited By Electrobob99
* @version 1.3
*/
public class InWorldCraftingManager {

private Vector<InWorldRecipe> recipes;

/**
 * The instance of this {@link InWorldCraftingManager}. Its thought to exist
 * only once per server?(not sure actually)
 */
public static InWorldCraftingManager object = new InWorldCraftingManager();

/**
 * Creates a new {@link InWorldCraftingManager}. This is private since it
 * should only exist one craftingmanager per server?
 */
private InWorldCraftingManager() {
	recipes = new Vector<InWorldRecipe>(10);// avarage of such recipes
}

/**
 * Adds the given recipe to the list of recipes this manager knows. Like
 * registering a recipe to the GameRegistry.
 * 
 * @param recipe
 *            The recipe to add
 */
public void addRecipe(InWorldRecipe recipe) {
	recipes.add(recipe);
	Collections.sort(recipes);
}

/**
 * Crafts whatever is possible within the given bounds. This method does a
 * lot at once. It firstly searches for {@link EntityItem}s within the given
 * {@link AxisAlignedBB}. Then it looks if a recipe matches (with
 * {@link InWorldCraftingManager#findMatching(List)}) and if found one - it
 * crafts as many times result as possible and consumes the used
 * ingredients.
 * 
 * @param world
 *            The world where the crafting should happen. This method tests
 *            if its executed on the server and if not, it returns
 *            immediatley.
 * @param bounds
 *            The bounds in where to look for items ( {@link EntityItem}s ).
 * @param x
 *            The x-coordinate on which the result-spawning-calculation will
 *            start
 * @param y
 *            The y-coordinate on which the result-spawning-calculation will
 *            start
 * @param z
 *            The z-coordinate on which the result-spawning-calculation will
 *            start
 */
public void craftIfPossible(World world, AxisAlignedBB bounds, int x,
		int y, int z) {
	if (world.isRemote) {
		return;// don't craft on client
	}
	List<EntityItem> entities = world.getEntitiesWithinAABB(
			EntityItem.class, bounds);
	if (entities == null || entities.size() == 0) {
		return;// no items found or the list has no entries (not sure if
				// possible).
	}
	List<ItemStack> items = extractItemStacks(entities);
	InWorldRecipe recipe = findMatching(items);
	Vector<Integer> nbConsumed = craftRecipe(recipe, items, world, x, y, z);
	if (nbConsumed == null) {
		// nothing crafted
		System.out.println("Did not craft");
		return;
	} else {
		// crafted items spawned already in world!
	}
	for (int i = 0; i < nbConsumed.size(); i++) {
		// going through nbConsumed:
		// if actual nbConsumed > 0 -> entities[i].getEntityItem().stackSize
		// -= nbConsumed
		// if entities[i].getEntityItem().stackSize <= 0:
		// entities[i].setDead
		if (nbConsumed.get(i) > 0) {
			entities.get(i).getEntityItem().stackSize -= nbConsumed.get(i);
			if (entities.get(i).getEntityItem().stackSize <= 0) {
				entities.get(i).setDead();
				world.removeEntity(entities.get(i));
			}
		}
	}
}

/**
 * Crafts a recipe and returns the amount of used items. The returning
 * list's entries do correspond to the argument {@link List} of
 * {@link ItemStack}s. Thus in the returning {@link Vector} at position i is
 * stored how much items of the ItemStack at position i are used.
 * <b>Warning: this method should only be invoked on server side, but does
 * not test it!</b>
 * 
 * @param recipe
 *            The recipe to craft
 * @param items
 *            The ingredients
 * @param world
 *            The world in where the crafting happens
 * @param x
 *            The x-coordinate on which the result-spawning-calculation will
 *            start
 * @param y
 *            The y-coordinate on which the result-spawning-calculation will
 *            start
 * @param z
 *            The z-coordinate on which the result-spawning-calculation will
 *            start
 * @return A {@link Vector} of {@link Integer}s which correspond to the
 *         amount of items used during the crafting process. If no crafting
 *         happend it returns NULL!
 */
private Vector<Integer> craftRecipe(InWorldRecipe recipe,
		List<ItemStack> items, World world, int x, int y, int z) {
	if (recipe != null && items != null && items.size() > 0) {
		Vector<Integer> nbConsumed = new Vector<Integer>(items.size());

		//int nbResults = 0;
		for (ItemStack is : items) {
			if(is.stackSize == recipe.demandedAmount(is)){
				//can craft once the result, craft the item, spawn it, and set new stack size
				ItemStack itemStack = recipe.getResult();
				world.spawnEntityInWorld(new EntityItem(world, x, y+1, z, itemStack));
				is.stackSize -= recipe.demandedAmount(is);
				//return true;
			}
			if(is.stackSize > recipe.demandedAmount(is)){
				int toCraft = is.stackSize / recipe.demandedAmount(is);
				int rest = is.stackSize - (toCraft*recipe.demandedAmount(is));
				ItemStack itemStack = new ItemStack(recipe.getResult().getItem(),toCraft,0);
				world.spawnEntityInWorld(new EntityItem(world, x, y+1, z, itemStack));
				is.stackSize = rest;

			}
			if(is.stackSize < recipe.demandedAmount(is)){
				System.out.println("Did not craft!");
			}	
		}
	}
	// null recipe or empty list
	return null;
}

/**
 * Extracts the {@link ItemStack}s out of a list of {@link EntityItem}s
 * 
 * @param list
 *            The {@link EntityItem} {@link List} from where to extract
 * @return A {@link List} of {@link ItemStack}s which correspond to the
 *         {@link EntityItem} list. Or NULL if the list was null or empty.
 */
private List<ItemStack> extractItemStacks(List<EntityItem> list) {
	if (list == null || list.size() == 0) {
		return null; // emtpy list
	}
	List<ItemStack> out = new Vector<ItemStack>(list.size());
	for (EntityItem ei : list) {
		out.add(ei.getEntityItem());
	}
	return out;
}

/**
 * Returns the matching {@link InWorldRecipe} that has the given items as
 * ingredients.
 * 
 * @param items
 *            A {@link List} of {@link ItemStack}s with items to test.
 * @return Either the mathing {@link InWorldRecipe} where the given items
 *         are ingredients or <code>null</code> if no recipe was found
 */
public InWorldRecipe findMatching(List<ItemStack> items) {
	for (InWorldRecipe recipe : recipes) {
		if (recipe.getRecipeSize() != items.size()) {
			continue; // the sizes do not match: next recipe please!
		}
		int nbMatchingItems = 0;
		for (ItemStack is : items) {
			if (recipe.containsIngredient(is)) {
				// okay, is is part of the recipe
				nbMatchingItems++;
			}
		}
		if (nbMatchingItems == recipe.getRecipeSize()) {
			// yeah found recipe (but did not check correct amount!)
			return recipe;
		} else {
			// not enough matching items
			return null;
		}
	}
	return null;
}
@Deprecated
/**
 * Spawns a given amount of {@link EntityItem}s in the given world, near the
 * given position. This method respects the stacksize limits and thus spawns
 * several entities if the stacksize would overflow.
 * 
 * @param world
 *            The world in where to spawn the items. If this world is
 *            remote, the method does nothing
 * @param x
 *            The x-coordinate on which the result-spawning-calculation will
 *            start
 * @param y
 *            The y-coordinate on which the result-spawning-calculation will
 *            start
 * @param z
 *            The z-coordinate on which the result-spawning-calculation will
 *            start
 * @param item
 *            The item to spawn. If this is null, nothing happens
 * @param nbResults
 *            The amount of times the item should spawn. Example: the item
 *            is 9 redstone pieces and nbResults is 4, a stack of 36
 *            redstone pieces would spawn.
 */
private void spawnItems(World world, int x, int y, int z, ItemStack item,
		int nbResults) {
	if (item != null && nbResults > 0 && !world.isRemote) {
		int total = item.stackSize * nbResults;
		if (total <= item.getMaxStackSize()) {
			item.stackSize = total;
			EntityItem ei = new EntityItem(world, x + 0.5, y + 1.5,
					z + 0.5, item);
			world.spawnEntityInWorld(ei);
		} else {
			int nbStacks = total / item.getMaxStackSize();
			int remaining = total % item.getMaxStackSize();
			for (int i = 0; i < nbStacks; i++) {
				ItemStack is = new ItemStack(item.getItem(),
						item.getMaxStackSize(), item.getItemDamage());
				EntityItem ei = new EntityItem(world, x + 0.5, y + 1.5,
						z + 0.5, is);
				world.spawnEntityInWorld(ei);
			}
			if (remaining > 0) {
				ItemStack is = new ItemStack(item.getItem(), remaining,
						item.getItemDamage());
				EntityItem ei = new EntityItem(world, x + 0.5, y + 1.5,
						z + 0.5, is);
				world.spawnEntityInWorld(ei);
			}
		}
	}
}

}

 

 

I also wouldn't mind making some of the recipes only work with certain items aswell.

Member of Aerotech Networks, a Multi-Gaming server.

Also Currently porting the "Rise of the Automatons" minecraft mod

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.