diff options
author | BlueWeabo <76872108+BlueWeabo@users.noreply.github.com> | 2023-01-20 10:23:04 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-20 09:23:04 +0100 |
commit | c7f1646f4b473359d270d55e4dc54cb1f4e7a64b (patch) | |
tree | 146eda529ef20e411b2459cee95ef4909c80bd33 /src/main/java/gregtech | |
parent | 54ce736cf86ba256596588a6e2833711ff36bbd9 (diff) | |
download | GT5-Unofficial-c7f1646f4b473359d270d55e4dc54cb1f4e7a64b.tar.gz GT5-Unofficial-c7f1646f4b473359d270d55e4dc54cb1f4e7a64b.tar.bz2 GT5-Unofficial-c7f1646f4b473359d270d55e4dc54cb1f4e7a64b.zip |
Parallel helper for all addons to use. (#1657)
* work on parallel helper
* spotless hell
* working? parallel
* spotless
* documentation
* spotless
* revert useless addition
* fixes
* spotless bs
* remove commented code
* remove outer if and make batchmode void protected
Diffstat (limited to 'src/main/java/gregtech')
-rw-r--r-- | src/main/java/gregtech/api/util/GT_ParallelHelper.java | 479 | ||||
-rw-r--r-- | src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PCBFactory.java | 37 |
2 files changed, 498 insertions, 18 deletions
diff --git a/src/main/java/gregtech/api/util/GT_ParallelHelper.java b/src/main/java/gregtech/api/util/GT_ParallelHelper.java new file mode 100644 index 0000000000..904afcad16 --- /dev/null +++ b/src/main/java/gregtech/api/util/GT_ParallelHelper.java @@ -0,0 +1,479 @@ +package gregtech.api.util; + +import com.gtnewhorizon.gtnhlib.util.map.ItemStackMap; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Output; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; +import gregtech.api.multitileentity.multiblock.base.MultiBlockController; +import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_OutputBus_ME; +import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_Output_ME; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.PriorityQueue; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; +import org.apache.commons.lang3.tuple.MutablePair; +import org.apache.commons.lang3.tuple.MutableTriple; + +public class GT_ParallelHelper { + /** + * @mMachineMeta a MetaTileEntity Controller + */ + private GT_MetaTileEntity_MultiBlockBase mMachineMeta; + /** + * @mMachineMulti a MultiTileEntity Controller + */ + private MultiBlockController mMachineMulti; + /** + * @mRecipe Recipe used when trying to calculate parallels + */ + private GT_Recipe mRecipe; + /** + * @mAvailtableEUt EUt available to the multiblock (This should be the total eut available) + */ + private long mAvailableEUt; + /** + * @mCurrentParallel The current parallel possible for the multiblock + * @mMaxParallel The maximum possible parallel possible for the multiblock + * @mBatchModifier The Batch Modifier applied when batch mode is enabled. 1 does nothing. 2 doubles max possible parallel, but also duration + */ + private int mCurrentParallel = 0, mMaxParallel = 1, mBatchModifier = 1; + /** + * @mItemInputs The inputs of the multiblock for the current recipe check + * @mItemOutputs The outputs of the recipe with the applied parallel + */ + private ItemStack[] mItemInputs, mItemOutputs; + /** + * @mFluidInputs The inputs of the multiblock for the current recipe check + * @mFluidOutputs The outputs of the recipe with the applied parallel + */ + private FluidStack[] mFluidInputs, mFluidOutputs; + /** + * @mVoidProtection Does the multi have void protectio enabled + * @mConsume Should the Parallel Helper automatically consume for the multi + * @mBatchMode Is batch mode turned on? + * @mCalculateOutputs Should the Parallel Helper automatically calculate the outputs of the recipe with current parallel + * @mBuilt Has the Parallel Helper been built? + */ + private boolean mVoidProtection, mConsume, mBatchMode, mCalculateOutputs, mBuilt; + /** + * @mDurationMultiplier What is the duration multiplier with batch mode enabled + * @mEUtModifer Modifier which is applied on the recipe eut. Usefull for GT++ machines + */ + private float mDurationMultiplier, mEUtModifer = 1; + + public GT_ParallelHelper() {} + + /** + * Enables void protection on a metatile multiblock. Experimental! Still needs to be worked on + */ + public GT_ParallelHelper enableVoidProtection(GT_MetaTileEntity_MultiBlockBase aMachineMeta) { + mVoidProtection = true; + mMachineMeta = aMachineMeta; + return this; + } + + /** + * Enables void protection on a multitile multiblock. Experimental! Still needs to be worked on + */ + public GT_ParallelHelper enableVoidProtection(MultiBlockController aMachineMulti) { + mVoidProtection = true; + mMachineMulti = aMachineMulti; + return this; + } + + /** + * Sets the recipe, which will be used for the parallel calculation + */ + public GT_ParallelHelper setRecipe(GT_Recipe aRecipe) { + mRecipe = aRecipe; + return this; + } + + /** + * Sets the items available for the recipe check + */ + public GT_ParallelHelper setItemInputs(ItemStack... aItemInputs) { + mItemInputs = aItemInputs; + return this; + } + + /** + * Sets the fluid inputs available for the recipe check + */ + public GT_ParallelHelper setFluidInputs(FluidStack... aFluidInputs) { + mFluidInputs = aFluidInputs; + return this; + } + + /** + * Sets the available eut when trying for more parallels + */ + public GT_ParallelHelper setAvailableEUt(long aAvailableEUt) { + mAvailableEUt = aAvailableEUt; + return this; + } + + /** + * Sets the modifier for recipe eut. 1 does nothing 0.9 is 10% less. 1.1 is 10% more + */ + public GT_ParallelHelper setEUtModifier(float aEUtModifier) { + mEUtModifer = aEUtModifier; + return this; + } + + /** + * Consume inputs when trying for parallels + */ + public GT_ParallelHelper enableConsumption() { + mConsume = true; + return this; + } + + /** + * Sets the MaxParallel a multi can handle + */ + public GT_ParallelHelper setMaxParallel(int aMaxParallel) { + mMaxParallel = aMaxParallel; + return this; + } + + /** + * Enables Batch mode. Can do up to an additional processed recipes of mCurrentParallel * mBatchModifier + * A batch modifier of 1 does nothing + */ + public GT_ParallelHelper enableBatchMode(int aBatchModifier) { + mBatchMode = true; + mBatchModifier = aBatchModifier; + return this; + } + + /** + * Enables the outputs to be calculated with its current Parallels, useful if one isn't doing anything special with outputs + */ + public GT_ParallelHelper enableOutputCalculation() { + mCalculateOutputs = true; + return this; + } + + /** + * Finishes the GT_ParallelHelper. Anything changed after this will not effect anything + */ + public GT_ParallelHelper build() { + if (mBuilt) { + throw new IllegalStateException("Tried to build twice"); + } + mBuilt = true; + determnieParallel(); + return this; + } + + /** + * @return The current parallels possible by the multiblock + */ + public int getCurrentParallel() { + if (!mBuilt) { + throw new IllegalStateException("Tried to get parallels before building"); + } + return mCurrentParallel; + } + + /** + * @return The duration multiplier if batch mode was enabled for the multiblock + */ + public float getDurationMultiplier() { + if (!mBuilt) { + throw new IllegalStateException("Tried to get duration multiplier before building"); + } + if (mBatchMode) { + return mDurationMultiplier; + } + return 1; + } + + /** + * @return The ItemOutputs from the recipe + */ + public ItemStack[] getItemOutputs() { + if (!mBuilt || !mCalculateOutputs) { + throw new IllegalStateException( + "Tried to get item outputs before building or without enabling calculation of outputs"); + } + return mItemOutputs; + } + + /** + * @return The FluidOutputs from the recipe + */ + public FluidStack[] getFluidOutputs() { + if (!mBuilt || !mCalculateOutputs) { + throw new IllegalStateException( + "Tried to get fluid outputs before building or without enabling calculation of outputs"); + } + return mFluidOutputs; + } + + /** + * Called by build(). Determines the parallels and everything else that needs to be done at build time + */ + private void determnieParallel() { + ItemStack[] tItemInputs = null; + FluidStack[] tFluidInputs = null; + boolean tMEOutputBus = false; + boolean tMEOutputHatch = false; + long tCurrentUsage = 0; + // see if people want to consume their inputs with the Parallel Helper or not + if (mConsume) { + tItemInputs = mItemInputs; + tFluidInputs = mFluidInputs; + } else { + tItemInputs = new ItemStack[mItemInputs.length]; + for (int i = 0; i < mItemInputs.length; i++) { + tItemInputs[i] = mItemInputs[i].copy(); + } + + tFluidInputs = new FluidStack[mFluidInputs.length]; + for (int i = 0; i < mFluidInputs.length; i++) { + tFluidInputs[i] = mFluidInputs[i].copy(); + } + } + if (mBatchMode) { + mMaxParallel *= mBatchModifier; + } + // Let's look at how many parallels we can get with void protection + if (mVoidProtection) { + for (GT_MetaTileEntity_Hatch tHatch : mMachineMeta.mOutputBusses) { + if (tHatch instanceof GT_MetaTileEntity_Hatch_OutputBus_ME) { + tMEOutputBus = true; + break; + } + } + + for (GT_MetaTileEntity_Hatch tHatch : mMachineMeta.mOutputHatches) { + if (tHatch instanceof GT_MetaTileEntity_Hatch_Output_ME) { + tMEOutputHatch = true; + break; + } + } + if (!tMEOutputBus) { + mMaxParallel = Math.min(calculateMaxParallelsForBusses(), mMaxParallel); + } + + if (!tMEOutputHatch) { + mMaxParallel = Math.min(calculateMaxParallelsForHatches(), mMaxParallel); + } + } + + float tRecipeEUt = mRecipe.mEUt * mEUtModifer; + // Consume inputs to determine normal parallel + for (; + mCurrentParallel < mMaxParallel / mBatchModifier && tCurrentUsage < (mAvailableEUt - tRecipeEUt); + mCurrentParallel++) { + if (mRecipe.isRecipeInputEqual(true, false, tFluidInputs, tItemInputs)) { + tCurrentUsage += tRecipeEUt; + } else { + break; + } + } + + // If Batch Mode is enabled determine how many extra parallels we can get + if (mBatchMode) { + int tExtraParallels = 0; + while (mRecipe.isRecipeInputEqual(true, true, tFluidInputs, tItemInputs) + && tExtraParallels < mCurrentParallel * mBatchModifier) { + tExtraParallels++; + } + mCurrentParallel += tExtraParallels; + mDurationMultiplier = 1.0f + (float) mBatchModifier / tExtraParallels; + } + + // If we want to calculate outputs we do it here + if (mCalculateOutputs) { + mItemOutputs = new ItemStack[mRecipe.mOutputs.length]; + for (int i = 0; i < mRecipe.mOutputs.length; i++) { + if (mRecipe.mChances[i] <= mMachineMulti.getRandomNumber(10000)) { + ItemStack tItem = mRecipe.getOutput(i).copy(); + tItem.stackSize *= mCurrentParallel; + mItemOutputs[i] = tItem; + } + } + mFluidOutputs = new FluidStack[mRecipe.mFluidOutputs.length]; + for (int i = 0; i < mRecipe.mFluidOutputs.length; i++) { + FluidStack tFluid = mRecipe.getFluidOutput(i).copy(); + tFluid.amount *= mCurrentParallel; + mFluidOutputs[i] = tFluid; + } + } + } + + /** + * Calculates the max parallel for fluids if void protection is turned on + */ + private int calculateMaxParallelsForHatches() { + // For now we are gonna ignore MuTEs existence as there are no recipes for them + if (mMachineMeta != null && mMachineMeta.mOutputHatches.size() >= mRecipe.mFluidOutputs.length) { + // A map to hold the items we will be 'inputting' into the output buses. These itemstacks are actually the + // recipe outputs. + Map<FluidStack, Integer> tFluidOutputMap = new HashMap<>(); + + // Map that keeps track of the number of parallel crafts we can accommodate for each fluid output. + // In the pair, we keep track of number of full crafts plus mb of fluid in a partial craft, to avoid + // issues with floating point math not being completely accurate when summing. + Map<FluidStack, MutablePair<Integer, Integer>> tParallels = new HashMap<>(); + + // Iterate over the outputs, calculating require stack spacing they will require. + for (FluidStack aY : mRecipe.mFluidOutputs) { + if (aY == null) { + continue; + } + tFluidOutputMap.merge(aY, aY.amount, Integer::sum); + tParallels.put(aY, new MutablePair<>(0, 0)); + } + + if (tFluidOutputMap.isEmpty()) { + // nothing to output, bail early + return mMaxParallel; + } + + for (GT_MetaTileEntity_Hatch_Output tHatch : mMachineMeta.mOutputHatches) { + int tSpaceLeft = tHatch.getCapacity() - tHatch.getFluidAmount(); + + // check if hatch filled + if (tSpaceLeft <= 0) continue; + + // check if hatch is empty and unrestricted + if (tHatch.mMode == 0 && tHatch.getFluidAmount() == 0) continue; + + String tLockedFluidName = tHatch.getLockedFluidName(); + for (Entry<FluidStack, MutablePair<Integer, Integer>> entry : tParallels.entrySet()) { + FluidStack tFluidOutput = entry.getKey(); + if (GT_ModHandler.isSteam(tFluidOutput)) { + if (!tHatch.outputsSteam()) { + continue; + } + } else { + if (!tHatch.outputsLiquids()) { + continue; + } + if (tHatch.isFluidLocked() + && tLockedFluidName != null + && !tLockedFluidName.equals( + tFluidOutput.getFluid().getName())) { + continue; + } + } + // this fluid is not prevented by restrictions on output hatch + if (tHatch.getFluidAmount() == 0 || GT_Utility.areFluidsEqual(tHatch.getFluid(), tFluidOutput)) { + MutablePair<Integer, Integer> tParallel = entry.getValue(); + Integer tCraftSize = tFluidOutputMap.get(tFluidOutput); + tParallel.left += (tParallel.right + tSpaceLeft) / tCraftSize; + tParallel.right = (tParallel.right + tSpaceLeft) % tCraftSize; + } + } + } + // now that all partial/restricted hatches have been counted, create a priority queue for our outputs + // the lowest priority fluid is the number of complete parallel crafts we can support + PriorityQueue<MutableTriple<Integer, Integer, FluidStack>> aParallelQueue = + new PriorityQueue<>(Comparator.comparing(MutableTriple::getLeft)); + for (Entry<FluidStack, MutablePair<Integer, Integer>> entry : tParallels.entrySet()) { + aParallelQueue.add(new MutableTriple<>(entry.getValue().left, entry.getValue().right, entry.getKey())); + } + // add extra parallels for open slots as well + for (GT_MetaTileEntity_Hatch_Output tHatch : mMachineMeta.mOutputHatches) { + // partially filled or restricted hatch. done in last pass + if (tHatch.getFluidAmount() > 0 || tHatch.mMode != 0) continue; + + MutableTriple<Integer, Integer, FluidStack> tParallel = aParallelQueue.poll(); + assert tParallel != null; // will always be true, specifying assert here to avoid IDE/compiler warnings + Integer tCraftSize = tFluidOutputMap.get(tParallel.right); + int tSpaceLeft = tHatch.getCapacity(); + tParallel.left += (tParallel.middle + tSpaceLeft) / tCraftSize; + tParallel.middle = (tParallel.middle + tSpaceLeft) % tCraftSize; + aParallelQueue.add(tParallel); + } + return aParallelQueue.element().left; + } + return 0; + } + + /** + * Calculates the max parallels one can do with items if void protection is on + */ + private int calculateMaxParallelsForBusses() { + // Same thing we are gonna ignore MuTEs existence for now. should be in theory the same later + + // A map to hold the items we will be 'inputting' into the output buses. These itemstacks are actually the + // recipe outputs. + Map<ItemStack, Integer> tItemOutputMap = new ItemStackMap<>(); + + // Map that keeps track of the number of parallel crafts we can accommodate for each item output. + // In the pair, we keep track of number of full crafts plus number of items in a partial craft, to avoid + // issues with floating point math not being completely accurate when summing. + Map<ItemStack, MutablePair<Integer, Integer>> tParallels = new ItemStackMap<>(); + int tSlotsFree = 0; + for (ItemStack tItem : mRecipe.mOutputs) { + tItemOutputMap.merge(tItem, tItem.stackSize, Integer::sum); + tParallels.put(tItem, new MutablePair<>(0, 0)); + } + + if (tItemOutputMap.isEmpty()) { + // nothing to output, bail early + return mMaxParallel; + } + + if (mRecipe.mOutputs.length > 0 && mMachineMeta != null) { + for (final GT_MetaTileEntity_Hatch tBus : mMachineMeta.mOutputBusses) { + if (!GT_MetaTileEntity_MultiBlockBase.isValidMetaTileEntity(tBus)) { + continue; + } + final IInventory tBusInv = tBus.getBaseMetaTileEntity(); + for (int i = 0; i < tBusInv.getSizeInventory(); i++) { + ItemStack tBusStack = tBus.getStackInSlot(i); + if (tBusStack == null) { + tSlotsFree++; + } else { + // get the real stack size + // we ignore the bus inventory stack limit here as no one set it to anything other than 64 + int tMaxBusStackSize = tBusStack.getMaxStackSize(); + if (tBusStack.stackSize >= tMaxBusStackSize) + // this bus stack is full. no checking + continue; + int tSpaceLeft = tMaxBusStackSize - tBusStack.stackSize; + Integer tCraftSize = tItemOutputMap.get(tBusStack); + if (tCraftSize == null) { + // we don't have a matching stack to output, ignore this bus stack + continue; + } + MutablePair<Integer, Integer> tParallel = tParallels.get(tBusStack); + tParallel.left += (tParallel.right + tSpaceLeft) / tCraftSize; + tParallel.right = (tParallel.right + tSpaceLeft) % tCraftSize; + } + } + } + // now that all partial stacks have been counted, create a priority queue for our outputs + // the lowest priority item is the number of complete parallel crafts we can support + PriorityQueue<MutableTriple<Integer, Integer, ItemStack>> aParallelQueue = + new PriorityQueue<>(Comparator.comparing(MutableTriple::getLeft)); + for (Entry<ItemStack, MutablePair<Integer, Integer>> entry : tParallels.entrySet()) { + aParallelQueue.add(new MutableTriple<>(entry.getValue().left, entry.getValue().right, entry.getKey())); + } + + while (tSlotsFree > 0) { + MutableTriple<Integer, Integer, ItemStack> tParallel = aParallelQueue.poll(); + assert tParallel != null; // will always be true, specifying assert here to avoid IDE/compiler warnings + Integer tCraftSize = tItemOutputMap.get(tParallel.right); + int tStackSize = tParallel.right.getMaxStackSize(); + tParallel.left += (tParallel.middle + tStackSize) / tCraftSize; + tParallel.middle = (tParallel.middle + tStackSize) % tCraftSize; + aParallelQueue.add(tParallel); + --tSlotsFree; + } + + return aParallelQueue.element().left; + } + return 0; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PCBFactory.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PCBFactory.java index 94f03f7fe5..abb3cbcac6 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PCBFactory.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PCBFactory.java @@ -49,6 +49,7 @@ import gregtech.api.util.GT_ModHandler; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; import gregtech.api.util.GT_OreDictUnificator; import gregtech.api.util.GT_OverclockCalculator; +import gregtech.api.util.GT_ParallelHelper; import gregtech.api.util.GT_Recipe; import gregtech.api.util.GT_Utility; import gregtech.common.blocks.GT_Block_Casings8; @@ -499,6 +500,7 @@ public class GT_MetaTileEntity_PCBFactory @Override public boolean checkRecipe(ItemStack aStack) { + mCurrentParallel = 0; GT_Recipe.GT_Recipe_Map aMap = getRecipeMap(); FluidStack[] tFluidInputs = getStoredFluids().toArray(new FluidStack[0]); if (mSeparate) { @@ -520,10 +522,10 @@ public class GT_MetaTileEntity_PCBFactory } private boolean processRecipe( - ItemStack aStack, ItemStack[] tItemInputs, FluidStack[] aFluidInputs, GT_Recipe.GT_Recipe_Map aMap) { + ItemStack aStack, ItemStack[] aItemInputs, FluidStack[] aFluidInputs, GT_Recipe.GT_Recipe_Map aMap) { mOutputItems = null; mOutputFluids = null; - if (tItemInputs == null || aFluidInputs == null) { + if (aItemInputs == null || aFluidInputs == null) { return false; } @@ -532,7 +534,7 @@ public class GT_MetaTileEntity_PCBFactory int tier = GT_Utility.getTier(voltage); GT_Recipe tRecipe = - aMap.findRecipe(getBaseMetaTileEntity(), null, true, false, V[tier], aFluidInputs, aStack, tItemInputs); + aMap.findRecipe(getBaseMetaTileEntity(), null, true, false, V[tier], aFluidInputs, aStack, aItemInputs); if (tRecipe == null) { return false; @@ -544,7 +546,7 @@ public class GT_MetaTileEntity_PCBFactory ItemStack aNanite = tRecipe.getRepresentativeInput(1); if (GT_OreDictUnificator.getAssociation(aNanite).mPrefix.equals(OrePrefixes.nanite)) { - for (ItemStack aItem : tItemInputs) { + for (ItemStack aItem : aItemInputs) { if (aItem.isItemEqual(aNanite)) { aNanitesOfRecipe += aItem.stackSize; } @@ -565,22 +567,21 @@ public class GT_MetaTileEntity_PCBFactory && ((recipeBitMap & mBioBitMap) == 0 || ((recipeBitMap & mBioBitMap) == mBioBitMap && mBioUpgrade)); if (recipeAllowed) { + GT_ParallelHelper helper = new GT_ParallelHelper() + .setRecipe(tRecipe) + .setItemInputs(aItemInputs) + .setFluidInputs(aFluidInputs) + .setMaxParallel(aMaxParallel) + .setAvailableEUt(getMaxInputEu()) + .setEUtModifier(aExtraPower) + .enableConsumption() + .build(); + mCurrentParallel = helper.getCurrentParallel(); - int aCurrentParallel = 0; - for (int i = 0; i < aMaxParallel; i++) { - if (tRecipe.isRecipeInputEqual(true, aFluidInputs, tItemInputs)) { - aCurrentParallel++; - } else { - break; - } - } - - mCurrentParallel = aCurrentParallel; - - if (aCurrentParallel > 0) { + if (mCurrentParallel > 0) { this.mEfficiency = (getMaxEfficiency(aStack) - (getIdealStatus() - getRepairStatus()) * 1000); this.mEfficiencyIncrease = getMaxEfficiency(aStack); - this.lEUt = -(long) Math.ceil(tRecipe.mEUt * aCurrentParallel * aExtraPower); + this.lEUt = -(long) Math.ceil(tRecipe.mEUt * mCurrentParallel * aExtraPower); this.mMaxProgresstime = (int) Math.ceil(tRecipe.mDuration * Math.pow(mRoughnessMultiplier, 2)); if (mOCTier1 || mOCTier2) { @@ -612,7 +613,7 @@ public class GT_MetaTileEntity_PCBFactory mOutputItems = new ItemStack[tRecipe.mOutputs.length]; ArrayList<ItemStack> tOutputs = new ArrayList<ItemStack>(); int repeats = (int) Math.ceil(getMaxEfficiency(aStack) / 10000); - for (int k = 0; k < aCurrentParallel; k++) { + for (int k = 0; k < mCurrentParallel; k++) { int remainingEfficiency = getMaxEfficiency(aStack) < 10000 ? 10000 : getMaxEfficiency(aStack); for (int j = 0; j < repeats; j++) { int chanced = getBaseMetaTileEntity().getRandomNumber(10000); |