From d0236bec2d81e1374be3878bafb5973d2060dc8f Mon Sep 17 00:00:00 2001 From: Lizbeth Rika Date: Sun, 15 Feb 2015 19:06:12 +0000 Subject: [PATCH] Working requests! --- .../botania/api/corporea/CorporeaHelper.java | 70 ++++--- .../tile/corporea/TileCorporeaIndex.java | 178 ++++++++++++++++-- .../resources/assets/botania/lang/en_US.lang | 1 + 3 files changed, 203 insertions(+), 46 deletions(-) diff --git a/src/main/java/vazkii/botania/api/corporea/CorporeaHelper.java b/src/main/java/vazkii/botania/api/corporea/CorporeaHelper.java index a299c004e..6309953f3 100644 --- a/src/main/java/vazkii/botania/api/corporea/CorporeaHelper.java +++ b/src/main/java/vazkii/botania/api/corporea/CorporeaHelper.java @@ -29,6 +29,15 @@ public final class CorporeaHelper { private static final List empty = Collections.unmodifiableList(new ArrayList()); private static final WeakHashMap, List> cachedNetworks = new WeakHashMap(); + /** + * How many items were matched in the last request. If java had "out" params like C# this wouldn't be needed :V + */ + public static int lastRequestMatches = 0; + /** + * How many items were extracted in the last request. + */ + public static int lastRequestExtractions = 0; + /** * Gets a list of all the inventories on this spark network. This list is cached for use once every tick, * and if something changes during that tick it'll still have the first result. @@ -113,7 +122,7 @@ public final class CorporeaHelper { for(int i = 0; i < inv.getSizeInventory(); i++) { if(!isValidSlot(inv, i)) continue; - + ItemStack stackAt = inv.getStackInSlot(i); if(stacksMatch(stack, stackAt, checkNBT)) count += stackAt.stackSize; @@ -132,7 +141,7 @@ public final class CorporeaHelper { public static List requestItem(ItemStack stack, ICorporeaSpark spark, boolean checkNBT, boolean doit) { return requestItem(stack, stack.stackSize, spark, checkNBT, doit); } - + /** * Bridge for requestItem() using a String and an item count. */ @@ -152,35 +161,42 @@ public final class CorporeaHelper { public static List requestItem(Object matcher, int itemCount, ICorporeaSpark spark, boolean checkNBT, boolean doit) { List inventories = getInventoriesOnNetwork(spark); List stacks = new ArrayList(); + + lastRequestMatches = 0; + lastRequestExtractions = 0; int count = itemCount; - checkInvs : { - for(IInventory inv : inventories) { - for(int i = 0; i < inv.getSizeInventory(); i++) { - if(!isValidSlot(inv, i)) - continue; + for(IInventory inv : inventories) { + for(int i = 0; i < inv.getSizeInventory(); i++) { + if(!isValidSlot(inv, i)) + continue; - ItemStack stackAt = inv.getStackInSlot(i); - if(matcher instanceof ItemStack ? stacksMatch((ItemStack) matcher, stackAt, checkNBT) : matcher instanceof String ? stacksMatch(stackAt, (String) matcher) : false) { - int rem = Math.min(stackAt.stackSize, count); - stacks.add(stackAt.copy()); - if(doit) { - stackAt.stackSize -= rem; - if(stackAt.stackSize == 0) - inv.setInventorySlotContents(i, null); - } - count -= rem; + ItemStack stackAt = inv.getStackInSlot(i); + if(matcher instanceof ItemStack ? stacksMatch((ItemStack) matcher, stackAt, checkNBT) : matcher instanceof String ? stacksMatch(stackAt, (String) matcher) : false) { + int rem = Math.min(stackAt.stackSize, count); - if(count <= 0) - break checkInvs; + if(rem > 0) { + ItemStack copy = stackAt.copy(); + if(rem < copy.stackSize) + copy.stackSize = rem; + stacks.add(copy); } + + lastRequestMatches += stackAt.stackSize; + lastRequestExtractions += rem; + if(doit && rem > 0) { + stackAt.stackSize -= rem; + if(stackAt.stackSize == 0) + inv.setInventorySlotContents(i, null); + } + count -= rem; } } } return stacks; } - + /** * Gets the spark attached to the block in the coords passed in. Note that the coords passed * in are for the block that the spark will be on, not the coords of the spark itself. @@ -189,7 +205,7 @@ public final class CorporeaHelper { List sparks = world.getEntitiesWithinAABB(ICorporeaSpark.class, AxisAlignedBB.getBoundingBox(x, y + 1, z, x + 1, y + 2, z + 1)); return sparks.isEmpty() ? null : sparks.get(0); } - + /** * Gets if the block in the coords passed in has a spark attached. Note that the coords passed * in are for the block that the spark will be on, not the coords of the spark itself. @@ -197,28 +213,28 @@ public final class CorporeaHelper { public static boolean doesBlockHaveSpark(World world, int x, int y, int z) { return getSparkForBlock(world, x, y, z) != null; } - + /** * Gets if the slot passed in can be extracted from by a spark. */ public static boolean isValidSlot(IInventory inv, int slot) { return !(inv instanceof ISidedInventory) || arrayHas(((ISidedInventory) inv).getAccessibleSlotsFromSide(ForgeDirection.UP.ordinal()), slot); } - + /** * Gets if two stacks match. */ public static boolean stacksMatch(ItemStack stack1, ItemStack stack2, boolean checkNBT) { return stack1 != null && stack2 != null && stack1.isItemEqual(stack2) && (!checkNBT || ItemStack.areItemStackTagsEqual(stack1, stack2)); } - + /** * Gets if the name of a stack matches the string passed in. */ public static boolean stacksMatch(ItemStack stack, String s) { if(stack == null) return false; - + String name = stack.getDisplayName().toLowerCase().trim(); return name.equals(s) || (name + "s").equals(s) || (name + "es").equals(s) || (name.endsWith("y") && (name.substring(0, name.length() - 1) + "ies").equals(s)); } @@ -230,7 +246,7 @@ public final class CorporeaHelper { public static void clearCache() { cachedNetworks.clear(); } - + /** * Helper method to check if an int array contains an int. */ @@ -238,7 +254,7 @@ public final class CorporeaHelper { for(int i = 0; i < arr.length; i++) if(arr[i] == val) return true; - + return false; } } diff --git a/src/main/java/vazkii/botania/common/block/tile/corporea/TileCorporeaIndex.java b/src/main/java/vazkii/botania/common/block/tile/corporea/TileCorporeaIndex.java index 3f291ef2e..23cdb4adf 100644 --- a/src/main/java/vazkii/botania/common/block/tile/corporea/TileCorporeaIndex.java +++ b/src/main/java/vazkii/botania/common/block/tile/corporea/TileCorporeaIndex.java @@ -12,43 +12,141 @@ package vazkii.botania.common.block.tile.corporea; import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.WeakHashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.Items; import net.minecraft.item.ItemStack; import net.minecraft.util.AxisAlignedBB; -import net.minecraft.world.World; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.ChatStyle; +import net.minecraft.util.EnumChatFormatting; import net.minecraftforge.event.ServerChatEvent; import vazkii.botania.api.corporea.CorporeaHelper; import vazkii.botania.api.corporea.ICorporeaSpark; -import vazkii.botania.common.block.ModBlocks; import vazkii.botania.common.core.helper.MathHelper; import cpw.mods.fml.common.eventhandler.SubscribeEvent; public class TileCorporeaIndex extends TileCorporeaBase { public static final double RADIUS = 2.5; - + public static final InputHandler input = new InputHandler(); public static final Set indexes = Collections.newSetFromMap(new WeakHashMap()); - + + private static final Map patterns = new LinkedHashMap(); + + /** + * (name) = Item name, or "this" for the name of the item in your hand + * (n), (n1), (n2), etc = Numbers + * [text] = Optional + * = Either a or b + */ + static { + // (name) = 1 + addPattern("(.+)", new IRegexStacker() { + @Override public int getCount(Matcher m) { return 1; } + @Override public String getName(Matcher m) { return m.group(1); } + }); + + // [a][n] (name) = 1 + addPattern("a??n?? (.+)", new IRegexStacker() { + @Override public int getCount(Matcher m) { return 1; } + @Override public String getName(Matcher m) { return m.group(1); } + }); + + //(n)[x][ of] (name) = n + addPattern("(\\d+)x?(?: of)? (.+)", new IRegexStacker() { + @Override public int getCount(Matcher m) { return i(m, 1); } + @Override public String getName(Matcher m) { return m.group(2); } + }); + + // [a ]stack[ of] (name) = 64 + addPattern("(?:a )?stack(?: of)? (.+)", new IRegexStacker() { + @Override public int getCount(Matcher m) { return 64; } + @Override public String getName(Matcher m) { return m.group(1); } + }); + + // (n)[x] stack[s][ of] (name) = n * 64 + addPattern("(\\d+)x?? stacks?(?: of)? (.+)", new IRegexStacker() { + @Override public int getCount(Matcher m) { return 64 * i(m, 1); } + @Override public String getName(Matcher m) { return m.group(2); } + }); + + // [a ]stack (n)[x][ of] (name) = 64 + n + addPattern("(?:a )?stack (?:(?:and)|(?:\\+)) (\\d+)(?: of)? (.+)", new IRegexStacker() { + @Override public int getCount(Matcher m) { return 64 + i(m, 1); } + @Override public String getName(Matcher m) { return m.group(2); } + }); + + // (n1)[x] stack[s] (n2)[x][ of] (name) = n1 * 64 + n2 + addPattern("(\\d+)x?? stacks? (?:(?:and)|(?:\\+)) (\\d+)x?(?: of)? (.+)", new IRegexStacker() { + @Override public int getCount(Matcher m) { return 64 * i(m, 1) + i(m, 2); } + @Override public String getName(Matcher m) { return m.group(3); } + }); + + // [a ]half [of ][a ]stack[ of] (name) = 32 + addPattern("(?:a )?half (?:of )?(?:a )?stack(?: of)? (.+)", new IRegexStacker() { + @Override public int getCount(Matcher m) { return 32; } + @Override public String getName(Matcher m) { return m.group(1); } + }); + + // [a ]quarter [of ][a ]stack[ of] (name) = 16 + addPattern("(?:a )?quarter (?:of )?(?:a )?stack(?: of)? (.+)", new IRegexStacker() { + @Override public int getCount(Matcher m) { return 16; } + @Override public String getName(Matcher m) { return m.group(1); } + }); + + // [a ]dozen[ of] (name) = 12 + addPattern("(?:a )?dozen(?: of)? (.+)", new IRegexStacker() { + @Override public int getCount(Matcher m) { return 12; } + @Override public String getName(Matcher m) { return m.group(1); } + }); + + // (n)[x] dozen[s][ of] (name) = n * 12 + addPattern("(\\d+)x?? dozens?(?: of)? (.+)", new IRegexStacker() { + @Override public int getCount(Matcher m) { return 12 * i(m, 1); } + @Override public String getName(Matcher m) { return m.group(2); } + }); + + // [ ](name) = 2147483647 + addPattern("(?:all|every) (?:(?:of|the) )?(.+)", new IRegexStacker() { + @Override public int getCount(Matcher m) { return Integer.MAX_VALUE; } + @Override public String getName(Matcher m) { return m.group(1); } + }); + + // [the ]answer to life[,] the universe and everything [of ](name) = 42 + addPattern("(?:the )?answer to life,? the universe and everything (?:of )?(.+)", new IRegexStacker() { + @Override public int getCount(Matcher m) { return 42; } + @Override public String getName(Matcher m) { return m.group(1); } + }); + + // (name) = 0 (display only) + addPattern("(?:count|show|display|tell) (.+)", new IRegexStacker() { + @Override public int getCount(Matcher m) { return 0; } + @Override public String getName(Matcher m) { return m.group(1); } + }); + } + public int ticks = 0; public int ticksWithCloseby = 0; public float closeby = 0F; public boolean hasCloseby; - + @Override public void updateEntity() { super.updateEntity(); - + double x = xCoord + 0.5; double y = yCoord + 0.5; double z = zCoord + 0.5; - + List players = worldObj.getEntitiesWithinAABB(EntityPlayer.class, AxisAlignedBB.getBoundingBox(x - RADIUS, y - RADIUS, z - RADIUS, x + RADIUS, y + RADIUS, z + RADIUS)); hasCloseby = false; for(EntityPlayer player : players) @@ -56,7 +154,7 @@ public class TileCorporeaIndex extends TileCorporeaBase { hasCloseby = true; break; } - + float step = 0.2F; ticks++; if(hasCloseby) { @@ -65,11 +163,11 @@ public class TileCorporeaIndex extends TileCorporeaBase { closeby += step; } else if(closeby > 0F) closeby -= step; - + if(!isInvalid() && !indexes.contains(this)) indexes.add(this); } - + @Override public void invalidate() { super.invalidate(); @@ -81,7 +179,7 @@ public class TileCorporeaIndex extends TileCorporeaBase { super.onChunkUnload(); indexes.remove(this); } - + @Override public int getSizeInventory() { return 1; @@ -91,13 +189,26 @@ public class TileCorporeaIndex extends TileCorporeaBase { public String getInventoryName() { return null; } - + public static boolean isInRangeOfIndex(EntityPlayer player, TileCorporeaIndex index) { return MathHelper.pointDistanceSpace(index.xCoord + 0.5, index.yCoord + 0.5, index.zCoord + 0.5, player.posX, player.posY, player.posZ) < RADIUS; } - + + public static void addPattern(String pattern, IRegexStacker stacker) { + patterns.put(Pattern.compile(pattern), stacker); + } + + public static int i(Matcher m, int g) { + try { + int i = Math.abs(Integer.parseInt(m.group(g))); + return i; + } catch(NumberFormatException e) { + return 0; + } + } + public static final class InputHandler { - + @SubscribeEvent public void onChatMessage(ServerChatEvent event) { List nearbyIndexes = getNearbyIndexes(event.player); @@ -106,19 +217,40 @@ public class TileCorporeaIndex extends TileCorporeaBase { for(TileCorporeaIndex index : nearbyIndexes) { ICorporeaSpark spark = index.getSpark(); if(spark != null) { - List stacks = CorporeaHelper.requestItem(msg, 64, spark, true); + String matchedPattern = ""; + String name = ""; + int count = 0; + for(Pattern pattern : patterns.keySet()) { + Matcher matcher = pattern.matcher(msg); + if(matcher.matches()) { + IRegexStacker stacker = patterns.get(pattern); + count = stacker.getCount(matcher); + name = stacker.getName(matcher).toLowerCase().trim(); + matchedPattern = pattern.toString(); + } + } + + if(name.equals("this")) { + ItemStack stack = event.player.getCurrentEquippedItem(); + if(stack != null) + name = stack.getDisplayName().toLowerCase().trim(); + } + + List stacks = CorporeaHelper.requestItem(name, count, spark, true); for(ItemStack stack : stacks) if(stack != null) { EntityItem item = new EntityItem(index.worldObj, index.xCoord + 0.5, index.yCoord + 1.5, index.zCoord + 0.5, stack); index.worldObj.spawnEntityInWorld(item); } + + event.player.addChatMessage(new ChatComponentTranslation("botaniamisc.requestMsg", count, name, CorporeaHelper.lastRequestMatches, CorporeaHelper.lastRequestExtractions).setChatStyle(new ChatStyle().setColor(EnumChatFormatting.LIGHT_PURPLE))); } } - + event.setCanceled(true); } } - + public List getNearbyIndexes(EntityPlayer player) { List indexList = new ArrayList(); for(TileCorporeaIndex index : indexes) @@ -126,7 +258,15 @@ public class TileCorporeaIndex extends TileCorporeaBase { indexList.add(index); return indexList; } - + + } + + public static interface IRegexStacker { + + public int getCount(Matcher m); + + public String getName(Matcher m); + } } diff --git a/src/main/resources/assets/botania/lang/en_US.lang b/src/main/resources/assets/botania/lang/en_US.lang index c288d0d69..d9a1f3fde 100644 --- a/src/main/resources/assets/botania/lang/en_US.lang +++ b/src/main/resources/assets/botania/lang/en_US.lang @@ -76,6 +76,7 @@ botaniamisc.hasClip=&6Has Lens Clip botaniamisc.clipEmpty=(Empty) botaniamisc.armorset=&bArmor Set&r: botaniamisc.craftToAddWill=&aCraft with a Terrasteel Helmet to add the following effect: +botaniamisc.requestMsg=Requested %d x "%s" out of %d. %d taken. # NEI INTEGRATION botania.nei.brewery=Botanical Brewery