* Just a few Utility Functions I use.
*/
public class GTUtility {
/**
* Formats a number with group separator and at most 2 fraction digits.
*/
private static final Map decimalFormatters = new HashMap<>();
/**
* Forge screwed the Fluid Registry up again, so I make my own, which is also much more efficient than the stupid
* Stuff over there.
*/
private static final List sFluidContainerList = new ArrayList<>();
private static final Map sFilledContainerToData = new /* Concurrent */ HashMap<>();
private static final Map> sEmptyContainerToFluidToData = new HashMap<>();
private static final Map> sFluidToContainers = new HashMap<>();
/**
* Must use {@code Supplier} here because the ore prefixes have not yet been registered at class load time.
*/
private static final Map> sOreToCobble = new HashMap<>();
private static final Map sOreTable = new HashMap<>();
public static boolean TE_CHECK = false, BC_CHECK = false, CHECK_ALL = true, RF_CHECK = false;
public static Map sPlayedSoundMap = new /* Concurrent */ HashMap<>();
private static int sBookCount = 0;
public static UUID defaultUuid = null; // maybe default non-null?
// UUID.fromString("00000000-0000-0000-0000-000000000000");
static {
GregTechAPI.sItemStackMappings.add(sFilledContainerToData);
GregTechAPI.sItemStackMappings.add(sEmptyContainerToFluidToData);
// 1 is the magic index to get the cobblestone block.
// See: GT_Block_Stones.java, GT_Block_Granites.java
Function> materialToCobble = m -> Suppliers.memoize(
() -> GTOreDictUnificator.getOres(OrePrefixes.stone, m)
.get(1))::get;
sOreToCobble.put(OrePrefixes.oreBlackgranite, materialToCobble.apply(Materials.GraniteBlack));
sOreToCobble.put(OrePrefixes.oreRedgranite, materialToCobble.apply(Materials.GraniteRed));
sOreToCobble.put(OrePrefixes.oreMarble, materialToCobble.apply(Materials.Marble));
sOreToCobble.put(OrePrefixes.oreBasalt, materialToCobble.apply(Materials.Basalt));
sOreToCobble.put(OrePrefixes.oreNetherrack, () -> new ItemStack(Blocks.netherrack));
sOreToCobble.put(OrePrefixes.oreEndstone, () -> new ItemStack(Blocks.end_stone));
}
public static int safeInt(long number, int margin) {
return number > Integer.MAX_VALUE - margin ? Integer.MAX_VALUE - margin : (int) number;
}
public static int safeInt(long number) {
return number > V[V.length - 1] ? safeInt(V[V.length - 1], 1)
: number < Integer.MIN_VALUE ? Integer.MIN_VALUE : (int) number;
}
public static Field getPublicField(Object aObject, String aField) {
Field rField = null;
try {
rField = aObject.getClass()
.getDeclaredField(aField);
} catch (Throwable e) {
/* Do nothing */
}
return rField;
}
public static Field getField(Object aObject, String aField) {
Field rField = null;
try {
rField = aObject.getClass()
.getDeclaredField(aField);
rField.setAccessible(true);
} catch (Throwable e) {
/* Do nothing */
}
return rField;
}
public static Field getField(Class> aObject, String aField) {
Field rField = null;
try {
rField = aObject.getDeclaredField(aField);
rField.setAccessible(true);
} catch (Throwable e) {
/* Do nothing */
}
return rField;
}
public static Method getMethod(Class> aObject, String aMethod, Class>... aParameterTypes) {
Method rMethod = null;
try {
rMethod = aObject.getMethod(aMethod, aParameterTypes);
rMethod.setAccessible(true);
} catch (Throwable e) {
/* Do nothing */
}
return rMethod;
}
public static Method getMethod(Object aObject, String aMethod, Class>... aParameterTypes) {
Method rMethod = null;
try {
rMethod = aObject.getClass()
.getMethod(aMethod, aParameterTypes);
rMethod.setAccessible(true);
} catch (Throwable e) {
/* Do nothing */
}
return rMethod;
}
public static Field getField(Object aObject, String aField, boolean aPrivate, boolean aLogErrors) {
try {
Field tField = (aObject instanceof Class) ? ((Class>) aObject).getDeclaredField(aField)
: (aObject instanceof String) ? Class.forName((String) aObject)
.getDeclaredField(aField)
: aObject.getClass()
.getDeclaredField(aField);
if (aPrivate) tField.setAccessible(true);
return tField;
} catch (Throwable e) {
if (aLogErrors) e.printStackTrace(GTLog.err);
}
return null;
}
public static Object getFieldContent(Object aObject, String aField, boolean aPrivate, boolean aLogErrors) {
try {
Field tField = (aObject instanceof Class) ? ((Class>) aObject).getDeclaredField(aField)
: (aObject instanceof String) ? Class.forName((String) aObject)
.getDeclaredField(aField)
: aObject.getClass()
.getDeclaredField(aField);
if (aPrivate) tField.setAccessible(true);
return tField.get(aObject instanceof Class || aObject instanceof String ? null : aObject);
} catch (Throwable e) {
if (aLogErrors) e.printStackTrace(GTLog.err);
}
return null;
}
public static Object callPublicMethod(Object aObject, String aMethod, Object... aParameters) {
return callMethod(aObject, aMethod, false, false, true, aParameters);
}
public static Object callPrivateMethod(Object aObject, String aMethod, Object... aParameters) {
return callMethod(aObject, aMethod, true, false, true, aParameters);
}
public static Object callMethod(Object aObject, String aMethod, boolean aPrivate, boolean aUseUpperCasedDataTypes,
boolean aLogErrors, Object... aParameters) {
try {
Class>[] tParameterTypes = new Class>[aParameters.length];
for (byte i = 0; i < aParameters.length; i++) {
if (aParameters[i] instanceof Class) {
tParameterTypes[i] = (Class>) aParameters[i];
aParameters[i] = null;
} else {
tParameterTypes[i] = aParameters[i].getClass();
}
if (!aUseUpperCasedDataTypes) {
if (tParameterTypes[i] == Boolean.class) tParameterTypes[i] = boolean.class;
else if (tParameterTypes[i] == Byte.class) tParameterTypes[i] = byte.class;
else if (tParameterTypes[i] == Short.class) tParameterTypes[i] = short.class;
else if (tParameterTypes[i] == Integer.class) tParameterTypes[i] = int.class;
else if (tParameterTypes[i] == Long.class) tParameterTypes[i] = long.class;
else if (tParameterTypes[i] == Float.class) tParameterTypes[i] = float.class;
else if (tParameterTypes[i] == Double.class) tParameterTypes[i] = double.class;
}
}
Method tMethod = (aObject instanceof Class) ? ((Class>) aObject).getMethod(aMethod, tParameterTypes)
: aObject.getClass()
.getMethod(aMethod, tParameterTypes);
if (aPrivate) tMethod.setAccessible(true);
return tMethod.invoke(aObject, aParameters);
} catch (Throwable e) {
if (aLogErrors) e.printStackTrace(GTLog.err);
}
return null;
}
public static Object callConstructor(Class> aClass, int aConstructorIndex, Object aReplacementObject,
boolean aLogErrors, Object... aParameters) {
if (aConstructorIndex < 0) {
try {
for (Constructor> tConstructor : aClass.getConstructors()) {
try {
return tConstructor.newInstance(aParameters);
} catch (Throwable ignored) {}
}
} catch (Throwable e) {
if (aLogErrors) e.printStackTrace(GTLog.err);
}
} else {
try {
return aClass.getConstructors()[aConstructorIndex].newInstance(aParameters);
} catch (Throwable e) {
if (aLogErrors) e.printStackTrace(GTLog.err);
}
}
return aReplacementObject;
}
public static String capitalizeString(String s) {
if (s != null && !s.isEmpty()) {
return s.substring(0, 1)
.toUpperCase() + s.substring(1);
}
return "";
}
public static String getClassName(Object aObject) {
if (aObject == null) return "null";
return aObject.getClass()
.getName()
.substring(
aObject.getClass()
.getName()
.lastIndexOf(".") + 1);
}
public static boolean getFullInvisibility(EntityPlayer aPlayer) {
try {
if (aPlayer.isInvisible()) {
for (int i = 0; i < 4; i++) {
if (aPlayer.inventory.armorInventory[i] != null) {
if (aPlayer.inventory.armorInventory[i].getItem() instanceof ItemEnergyArmor) {
if ((((ItemEnergyArmor) aPlayer.inventory.armorInventory[i].getItem()).mSpecials & 512)
!= 0) {
if (GTModHandler.canUseElectricItem(aPlayer.inventory.armorInventory[i], 10000)) {
return true;
}
}
}
}
}
}
} catch (Throwable e) {
if (D1) e.printStackTrace(GTLog.err);
}
return false;
}
public static ItemStack suckOneItemStackAt(World aWorld, double aX, double aY, double aZ, double aL, double aH,
double aW) {
for (EntityItem tItem : aWorld.getEntitiesWithinAABB(
EntityItem.class,
AxisAlignedBB.getBoundingBox(aX, aY, aZ, aX + aL, aY + aH, aZ + aW))) {
if (!tItem.isDead) {
aWorld.removeEntity(tItem);
tItem.setDead();
return tItem.getEntityItem();
}
}
return null;
}
public static byte getOppositeSide(ForgeDirection side) {
return (byte) side.getOpposite()
.ordinal();
}
public static byte getTier(long l) {
if (l > V[14]) return 15;
if (l <= V[0]) return 0;
// numberOfLeadingZeros is implemented in hardware by x86 LZCNT
// and is extremely efficient (takes only a couple of hardware cycles)
// (64 - numberOfLeadingZeros(l - 1)) = ceil(log_2(l))
int log2L = 64 - Long.numberOfLeadingZeros(l - 1);
return (byte) ((log2L - 2) / 2);
}
public static long getAmperageForTier(long voltage, byte tier) {
return ceilDiv(voltage, GTValues.V[tier]);
}
/**
* Rounds up partial voltage that exceeds tiered voltage, e.g. 4,096 -> 8,192(IV)
*/
public static long roundUpVoltage(long voltage) {
if (voltage > V[V.length - 1]) {
return voltage;
}
return V[GTUtility.getTier(voltage)];
}
public static String getColoredTierNameFromVoltage(long voltage) {
return getColoredTierNameFromTier(getTier(voltage));
}
public static String getColoredTierNameFromTier(byte tier) {
return GTValues.TIER_COLORS[tier] + GTValues.VN[tier] + EnumChatFormatting.RESET;
}
/**
* @return e.g. {@code " (LV)"}
*/
@Nonnull
public static String getTierNameWithParentheses(long voltage) {
byte tier = getTier(voltage);
if (tier < 0) {
return "";
} else if (tier == 0) {
return " (" + GTValues.VN[1] + ")";
} else if (tier >= GTValues.VN.length - 1) {
return " (MAX+)";
}
return " (" + GTValues.VN[tier] + ")";
}
public static void sendChatToPlayer(EntityPlayer aPlayer, String aChatMessage) {
if (aPlayer instanceof EntityPlayerMP && aChatMessage != null) {
aPlayer.addChatComponentMessage(new ChatComponentText(aChatMessage));
}
}
public static void checkAvailabilities() {
if (CHECK_ALL) {
try {
Class tClass = IItemDuct.class;
tClass.getCanonicalName();
TE_CHECK = true;
} catch (Throwable e) {
/**/
}
try {
Class tClass = buildcraft.api.transport.IPipeTile.class;
tClass.getCanonicalName();
BC_CHECK = true;
} catch (Throwable e) {
/**/
}
try {
Class tClass = cofh.api.energy.IEnergyReceiver.class;
tClass.getCanonicalName();
RF_CHECK = true;
} catch (Throwable e) {
/**/
}
CHECK_ALL = false;
}
}
public static boolean isConnectableNonInventoryPipe(TileEntity tileEntity, ForgeDirection side) {
if (tileEntity == null) return false;
checkAvailabilities();
if (TE_CHECK && tileEntity instanceof IItemDuct) return true;
if (BC_CHECK && tileEntity instanceof buildcraft.api.transport.IPipeTile pipeTile)
return pipeTile.isPipeConnected(side);
return Translocator.isModLoaded() && tileEntity instanceof codechicken.translocator.TileItemTranslocator;
}
/**
* Moves Stack from Inv-Slot to Inv-Slot, without checking if its even allowed.
*
* @return the Amount of moved Items
*/
public static byte moveStackIntoPipe(IInventory aTileEntity1, Object aTileEntity2, int[] aGrabSlots,
ForgeDirection fromSide, ForgeDirection putSide, List aFilter, boolean aInvertFilter,
byte aMaxTargetStackSize, byte aMinTargetStackSize, byte aMaxMoveAtOnce, byte aMinMoveAtOnce) {
return moveStackIntoPipe(
aTileEntity1,
aTileEntity2,
aGrabSlots,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
true);
}
/**
* Moves Stack from Inv-Slot to Inv-Slot, without checking if it is even allowed.
*
* @return the Amount of moved Items
*/
public static byte moveStackIntoPipe(IInventory fromInventory, Object toObject, int[] fromSlots,
ForgeDirection fromSide, ForgeDirection putSide, List aFilter, boolean aInvertFilter,
byte aMaxTargetStackSize, byte aMinTargetStackSize, byte aMaxMoveAtOnce, byte aMinMoveAtOnce,
boolean dropItem) {
if (fromInventory == null || aMaxTargetStackSize <= 0
|| aMinTargetStackSize <= 0
|| aMinTargetStackSize > aMaxTargetStackSize
|| aMaxMoveAtOnce <= 0
|| aMinMoveAtOnce > aMaxMoveAtOnce) return 0;
if (toObject != null) {
checkAvailabilities();
if (TE_CHECK && toObject instanceof IItemDuct itemDuct) {
for (final int aGrabSlot : fromSlots) {
if (listContainsItem(aFilter, fromInventory.getStackInSlot(aGrabSlot), true, aInvertFilter)) {
if (isAllowedToTakeFromSlot(
fromInventory,
aGrabSlot,
fromSide,
fromInventory.getStackInSlot(aGrabSlot))) {
if (Math.max(aMinMoveAtOnce, aMinTargetStackSize)
<= fromInventory.getStackInSlot(aGrabSlot).stackSize) {
ItemStack tStack = copyAmount(
Math.min(
fromInventory.getStackInSlot(aGrabSlot).stackSize,
Math.min(aMaxMoveAtOnce, aMaxTargetStackSize)),
fromInventory.getStackInSlot(aGrabSlot));
ItemStack rStack = itemDuct.insertItem(putSide, copyOrNull(tStack));
byte tMovedItemCount = (byte) (tStack.stackSize
- (rStack == null ? 0 : rStack.stackSize));
if (tMovedItemCount >= 1 /* Math.max(aMinMoveAtOnce, aMinTargetStackSize) */) {
fromInventory.decrStackSize(aGrabSlot, tMovedItemCount);
fromInventory.markDirty();
return tMovedItemCount;
}
}
}
}
}
return 0;
}
if (BC_CHECK && toObject instanceof buildcraft.api.transport.IPipeTile bcPipe) {
for (int fromSlot : fromSlots) {
if (listContainsItem(aFilter, fromInventory.getStackInSlot(fromSlot), true, aInvertFilter)) {
if (isAllowedToTakeFromSlot(
fromInventory,
fromSlot,
fromSide,
fromInventory.getStackInSlot(fromSlot))) {
if (Math.max(aMinMoveAtOnce, aMinTargetStackSize)
<= fromInventory.getStackInSlot(fromSlot).stackSize) {
ItemStack tStack = copyAmount(
Math.min(
fromInventory.getStackInSlot(fromSlot).stackSize,
Math.min(aMaxMoveAtOnce, aMaxTargetStackSize)),
fromInventory.getStackInSlot(fromSlot));
byte tMovedItemCount = (byte) bcPipe.injectItem(copyOrNull(tStack), false, putSide);
if (tMovedItemCount >= Math.max(aMinMoveAtOnce, aMinTargetStackSize)) {
tMovedItemCount = (byte) (bcPipe
.injectItem(copyAmount(tMovedItemCount, tStack), true, putSide));
fromInventory.decrStackSize(fromSlot, tMovedItemCount);
fromInventory.markDirty();
return tMovedItemCount;
}
}
}
}
}
return 0;
}
}
if (fromInventory instanceof TileEntity fromTileEntity && fromSide != ForgeDirection.UNKNOWN
&& fromSide.getOpposite() == ForgeDirection.getOrientation(putSide.ordinal())) {
int tX = fromTileEntity.xCoord + fromSide.offsetX, tY = fromTileEntity.yCoord + fromSide.offsetY,
tZ = fromTileEntity.zCoord + fromSide.offsetZ;
if (!hasBlockHitBox(((TileEntity) fromInventory).getWorldObj(), tX, tY, tZ) && dropItem) {
for (final int fromSlot : fromSlots) {
if (listContainsItem(aFilter, fromInventory.getStackInSlot(fromSlot), true, aInvertFilter)) {
if (isAllowedToTakeFromSlot(
fromInventory,
fromSlot,
fromSide,
fromInventory.getStackInSlot(fromSlot))) {
if (Math.max(aMinMoveAtOnce, aMinTargetStackSize)
<= fromInventory.getStackInSlot(fromSlot).stackSize) {
final ItemStack tStack = copyAmount(
Math.min(
fromInventory.getStackInSlot(fromSlot).stackSize,
Math.min(aMaxMoveAtOnce, aMaxTargetStackSize)),
fromInventory.getStackInSlot(fromSlot));
final EntityItem tEntity = new EntityItem(
((TileEntity) fromInventory).getWorldObj(),
tX + 0.5,
tY + 0.5,
tZ + 0.5,
tStack);
tEntity.motionX = tEntity.motionY = tEntity.motionZ = 0;
((TileEntity) fromInventory).getWorldObj()
.spawnEntityInWorld(tEntity);
assert tStack != null;
fromInventory.decrStackSize(fromSlot, tStack.stackSize);
fromInventory.markDirty();
return (byte) tStack.stackSize;
}
}
}
}
}
}
return 0;
}
/**
* Moves Stack from Inv-Slot to Inv-Slot, without checking if its even allowed. (useful for internal Inventory
* Operations)
*
* @return the Amount of moved Items
*/
public static byte moveStackFromSlotAToSlotB(IInventory aTileEntity1, IInventory aTileEntity2, int aGrabFrom,
int aPutTo, byte aMaxTargetStackSize, byte aMinTargetStackSize, byte aMaxMoveAtOnce, byte aMinMoveAtOnce) {
if (aTileEntity1 == null || aTileEntity2 == null
|| aMinTargetStackSize <= 0
|| aMinTargetStackSize > aMaxTargetStackSize
|| aMaxMoveAtOnce <= 0
|| aMinMoveAtOnce > aMaxMoveAtOnce) return 0;
ItemStack tStack1 = aTileEntity1.getStackInSlot(aGrabFrom), tStack2 = aTileEntity2.getStackInSlot(aPutTo),
tStack3;
if (tStack1 != null) {
if (tStack2 != null && !areStacksEqual(tStack1, tStack2)) return 0;
tStack3 = copyOrNull(tStack1);
aMaxTargetStackSize = (byte) Math.min(
aMaxTargetStackSize,
Math.min(
tStack3.getMaxStackSize(),
Math.min(
tStack2 == null ? Integer.MAX_VALUE : tStack2.getMaxStackSize(),
aTileEntity2.getInventoryStackLimit())));
tStack3.stackSize = Math
.min(tStack3.stackSize, aMaxTargetStackSize - (tStack2 == null ? 0 : tStack2.stackSize));
if (tStack3.stackSize > aMaxMoveAtOnce) tStack3.stackSize = aMaxMoveAtOnce;
if (tStack3.stackSize + (tStack2 == null ? 0 : tStack2.stackSize)
>= Math.min(tStack3.getMaxStackSize(), aMinTargetStackSize) && tStack3.stackSize >= aMinMoveAtOnce) {
tStack3 = aTileEntity1.decrStackSize(aGrabFrom, tStack3.stackSize);
aTileEntity1.markDirty();
if (tStack3 != null) {
if (tStack2 == null) {
aTileEntity2.setInventorySlotContents(aPutTo, copyOrNull(tStack3));
} else {
tStack2.stackSize += tStack3.stackSize;
}
aTileEntity2.markDirty();
return (byte) tStack3.stackSize;
}
}
}
return 0;
}
public static boolean isAllowedToTakeFromSlot(IInventory aTileEntity, int aSlot, ForgeDirection side,
ItemStack aStack) {
if (side == ForgeDirection.UNKNOWN) {
return Arrays.stream(ForgeDirection.VALID_DIRECTIONS)
.anyMatch(d -> isAllowedToTakeFromSlot(aTileEntity, aSlot, d, aStack));
}
if (aTileEntity instanceof ISidedInventory sided) return sided.canExtractItem(aSlot, aStack, side.ordinal());
return true;
}
public static boolean isAllowedToPutIntoSlot(IInventory aTileEntity, int aSlot, ForgeDirection side,
ItemStack aStack, byte aMaxStackSize) {
ItemStack tStack = aTileEntity.getStackInSlot(aSlot);
if (tStack != null && (!areStacksEqual(tStack, aStack) || tStack.stackSize >= tStack.getMaxStackSize()))
return false;
if (side == ForgeDirection.UNKNOWN) {
return Arrays.stream(ForgeDirection.VALID_DIRECTIONS)
.anyMatch(d -> isAllowedToPutIntoSlot(aTileEntity, aSlot, d, aStack, aMaxStackSize));
}
if (aTileEntity instanceof ISidedInventory
&& !((ISidedInventory) aTileEntity).canInsertItem(aSlot, aStack, side.ordinal())) return false;
return aSlot < aTileEntity.getSizeInventory() && aTileEntity.isItemValidForSlot(aSlot, aStack);
}
/**
* moves multiple stacks from Inv-Side to Inv-Side
*
* @return the Amount of moved Items
*/
public static int moveMultipleItemStacks(Object aTileEntity1, Object aTileEntity2, ForgeDirection fromSide,
ForgeDirection putSide, List aFilter, boolean aInvertFilter, byte aMaxTargetStackSize,
byte aMinTargetStackSize, byte aMaxMoveAtOnce, byte aMinMoveAtOnce, int aStackAmount) {
if (aTileEntity1 instanceof IInventory) return moveMultipleItemStacks(
(IInventory) aTileEntity1,
aTileEntity2,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
aStackAmount,
true);
return 0;
}
public static int moveMultipleItemStacks(IInventory fromInventory, Object toObject, ForgeDirection fromSide,
ForgeDirection putSide, List aFilter, boolean aInvertFilter, byte aMaxTargetStackSize,
byte aMinTargetStackSize, byte aMaxMoveAtOnce, byte aMinMoveAtOnce, int aMaxStackTransfer,
boolean aDoCheckChests) {
if (fromInventory == null || aMaxTargetStackSize <= 0
|| aMinTargetStackSize <= 0
|| aMaxMoveAtOnce <= 0
|| aMinTargetStackSize > aMaxTargetStackSize
|| aMinMoveAtOnce > aMaxMoveAtOnce
|| aMaxStackTransfer == 0) return 0;
// find where to take from
final int[] tGrabSlots = new int[fromInventory.getSizeInventory()];
int tGrabSlotsSize = 0;
if (fromInventory instanceof ISidedInventory) {
for (int i : ((ISidedInventory) fromInventory).getAccessibleSlotsFromSide(fromSide.ordinal())) {
final ItemStack s = fromInventory.getStackInSlot(i);
if (s == null || !isAllowedToTakeFromSlot(fromInventory, i, fromSide, s)
|| s.stackSize < aMinMoveAtOnce
|| !listContainsItem(aFilter, s, true, aInvertFilter)) continue;
tGrabSlots[tGrabSlotsSize++] = i;
}
} else {
for (int i = 0; i < tGrabSlots.length; i++) {
ItemStack s = fromInventory.getStackInSlot(i);
if (s == null || s.stackSize < aMinMoveAtOnce || !listContainsItem(aFilter, s, true, aInvertFilter))
continue;
tGrabSlots[tGrabSlotsSize++] = i;
}
}
// no source, bail out
if (tGrabSlotsSize == 0) {
// maybe source is a double chest. check it
if (aDoCheckChests && fromInventory instanceof TileEntityChest chest) return moveFromAdjacentChests(
chest,
toObject,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
aMaxStackTransfer);
return 0;
}
// if target is an inventory, e.g. chest, machine, drawers...
if (toObject instanceof IInventory toInventory) {
// partially filled slot spare space mapping.
// value is the sum of all spare space left not counting completely empty slot
final HashMap tPutItems = new HashMap<>(toInventory.getSizeInventory());
// partially filled slot contents
final HashMap> tPutItemStacks = new HashMap<>(toInventory.getSizeInventory());
// completely empty slots
final List tPutFreeSlots = new ArrayList<>(toInventory.getSizeInventory());
// find possible target slots
int[] accessibleSlots = null;
if (toObject instanceof ISidedInventory sided)
accessibleSlots = sided.getAccessibleSlotsFromSide(putSide.ordinal());
for (int i = 0; i < toInventory.getSizeInventory(); i++) {
int slot = i;
if (accessibleSlots != null) {
if (accessibleSlots.length <= i) break;
slot = accessibleSlots[slot];
}
ItemStack s = toInventory.getStackInSlot(slot);
if (s == null) {
tPutFreeSlots.add(slot);
} else if ((s.stackSize < s.getMaxStackSize() && s.stackSize < toInventory.getInventoryStackLimit())
&& aMinMoveAtOnce <= s.getMaxStackSize() - s.stackSize
&& isAllowedToPutIntoSlot(toInventory, slot, putSide, s, (byte) 64)) {
ItemId sID = ItemId.createNoCopy(s);
tPutItems.merge(
sID,
(Math.min(s.getMaxStackSize(), toInventory.getInventoryStackLimit()) - s.stackSize),
Integer::sum);
tPutItemStacks.computeIfAbsent(sID, k -> new ArrayList<>())
.add(s);
}
}
// target completely filled, bail out
if (tPutItems.isEmpty() && tPutFreeSlots.isEmpty()) {
// maybe target is a double chest. check it.
if (aDoCheckChests && toObject instanceof TileEntityChest chest) return moveToAdjacentChests(
fromInventory,
chest,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
aMaxStackTransfer);
return 0;
}
// go over source stacks one by one
int tStacksMoved = 0, tTotalItemsMoved = 0;
for (int j = 0; j < tGrabSlotsSize; j++) {
final int grabSlot = tGrabSlots[j];
int tMovedItems;
int tStackSize;
do {
tMovedItems = 0;
final ItemStack tGrabStack = fromInventory.getStackInSlot(grabSlot);
if (tGrabStack == null) break;
tStackSize = tGrabStack.stackSize;
final ItemId sID = ItemId.createNoCopy(tGrabStack);
if (tPutItems.containsKey(sID)) {
// there is a partially filled slot, try merging
final int canPut = Math.min(tPutItems.get(sID), aMaxMoveAtOnce);
if (canPut >= aMinMoveAtOnce) {
final List putStack = tPutItemStacks.get(sID);
if (!putStack.isEmpty()) {
// can move, do merge
int toPut = Math.min(canPut, tStackSize);
tMovedItems = toPut;
for (int i = 0; i < putStack.size(); i++) {
final ItemStack s = putStack.get(i);
final int sToPut = Math.min(
Math.min(
Math.min(toPut, s.getMaxStackSize() - s.stackSize),
toInventory.getInventoryStackLimit() - s.stackSize),
aMaxTargetStackSize - s.stackSize);
if (sToPut <= 0) continue;
if (sToPut < aMinMoveAtOnce) continue;
if (s.stackSize + sToPut < aMinTargetStackSize) continue;
toPut -= sToPut;
s.stackSize += sToPut;
if (s.stackSize == s.getMaxStackSize()
|| s.stackSize == toInventory.getInventoryStackLimit()) {
// this slot is full. remove this stack from candidate list
putStack.remove(i);
i--;
}
if (toPut == 0) break;
}
tMovedItems -= toPut;
if (tMovedItems > 0) {
tStackSize -= tMovedItems;
tTotalItemsMoved += tMovedItems;
// deduct spare space
tPutItems.merge(sID, tMovedItems, (a, b) -> a.equals(b) ? null : a - b);
if (tStackSize == 0) fromInventory.setInventorySlotContents(grabSlot, null);
else tGrabStack.stackSize = tStackSize;
fromInventory.markDirty();
toInventory.markDirty();
}
}
}
}
// still stuff to move & have completely empty slots
if (tStackSize > 0 && !tPutFreeSlots.isEmpty()) {
for (int i = 0; i < tPutFreeSlots.size(); i++) {
final int tPutSlot = tPutFreeSlots.get(i);
if (isAllowedToPutIntoSlot(toInventory, tPutSlot, putSide, tGrabStack, (byte) 64)) {
// allowed, now do moving
final int tMoved = moveStackFromSlotAToSlotB(
fromInventory,
toInventory,
grabSlot,
tPutSlot,
aMaxTargetStackSize,
aMinTargetStackSize,
(byte) (aMaxMoveAtOnce - tMovedItems),
aMinMoveAtOnce);
if (tMoved > 0) {
final ItemStack s = toInventory.getStackInSlot(tPutSlot);
if (s != null) {
// s might be null if tPutInventory is very special, e.g. infinity chest
// if s is null, we will not mark this slot as target candidate for anything
final int spare = Math
.min(s.getMaxStackSize(), toInventory.getInventoryStackLimit())
- s.stackSize;
if (spare > 0) {
final ItemId ssID = ItemId.createNoCopy(s);
// add back to spare space count
tPutItems.merge(ssID, spare, Integer::sum);
// add to partially filled slot list
tPutItemStacks.computeIfAbsent(ssID, k -> new ArrayList<>())
.add(s);
}
// this is no longer free
tPutFreeSlots.remove(i);
i--;
}
// else -> noop
// this is still a free slot. no need to do anything.
tTotalItemsMoved += tMoved;
tMovedItems += tMoved;
tStackSize -= tMoved;
if (tStackSize == 0) break;
}
}
}
}
if (tMovedItems > 0) {
// check if we have moved enough stacks
if (++tStacksMoved >= aMaxStackTransfer) return tTotalItemsMoved;
}
} while (tMovedItems > 0 && tStackSize > 0); // support inventories that store more than a stack in a
// slot
}
// check if source is a double chest, if yes, try move from the adjacent as well
if (aDoCheckChests && fromInventory instanceof TileEntityChest chest) {
final int tAmount = moveFromAdjacentChests(
chest,
toObject,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
aMaxStackTransfer - tStacksMoved);
if (tAmount != 0) return tAmount + tTotalItemsMoved;
}
// check if target is a double chest, if yes, try move to the adjacent as well
if (aDoCheckChests && toObject instanceof TileEntityChest chest) {
final int tAmount = moveToAdjacentChests(
fromInventory,
chest,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
aMaxStackTransfer - tStacksMoved);
if (tAmount != 0) return tAmount + tTotalItemsMoved;
}
return tTotalItemsMoved;
}
// there should be a function to transfer more than 1 stack in a pipe
// however I do not see any ways to improve it. too much work for what it is worth
int tTotalItemsMoved = 0;
final int tGrabInventorySize = tGrabSlots.length;
for (int i = 0; i < tGrabInventorySize; i++) {
final int tMoved = moveStackIntoPipe(
fromInventory,
toObject,
tGrabSlots,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
aDoCheckChests);
if (tMoved == 0) return tTotalItemsMoved;
else tTotalItemsMoved += tMoved;
}
return 0;
}
private static int moveToAdjacentChests(IInventory aTileEntity1, TileEntityChest aTargetChest,
ForgeDirection fromSide, ForgeDirection putSide, List aFilter, boolean aInvertFilter,
byte aMaxTargetStackSize, byte aMinTargetStackSize, byte aMaxMoveAtOnce, byte aMinMoveAtOnce,
int aMaxStackTransfer) {
if (aTargetChest.adjacentChestChecked) {
if (aTargetChest.adjacentChestXNeg != null) {
return moveMultipleItemStacks(
aTileEntity1,
aTargetChest.adjacentChestXNeg,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
aMaxStackTransfer,
false);
} else if (aTargetChest.adjacentChestZNeg != null) {
return moveMultipleItemStacks(
aTileEntity1,
aTargetChest.adjacentChestZNeg,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
aMaxStackTransfer,
false);
} else if (aTargetChest.adjacentChestXPos != null) {
return moveMultipleItemStacks(
aTileEntity1,
aTargetChest.adjacentChestXPos,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
aMaxStackTransfer,
false);
} else if (aTargetChest.adjacentChestZPos != null) {
return moveMultipleItemStacks(
aTileEntity1,
aTargetChest.adjacentChestZPos,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
aMaxStackTransfer,
false);
}
}
return 0;
}
private static int moveFromAdjacentChests(TileEntityChest fromTileEntityChest, Object toObject,
ForgeDirection fromSide, ForgeDirection putSide, List aFilter, boolean aInvertFilter,
byte aMaxTargetStackSize, byte aMinTargetStackSize, byte aMaxMoveAtOnce, byte aMinMoveAtOnce,
int aMaxStackTransfer) {
if (fromTileEntityChest.adjacentChestXNeg != null) {
return moveMultipleItemStacks(
fromTileEntityChest.adjacentChestXNeg,
toObject,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
aMaxStackTransfer,
false);
} else if (fromTileEntityChest.adjacentChestZNeg != null) {
return moveMultipleItemStacks(
fromTileEntityChest.adjacentChestZNeg,
toObject,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
aMaxStackTransfer,
false);
} else if (fromTileEntityChest.adjacentChestXPos != null) {
return moveMultipleItemStacks(
fromTileEntityChest.adjacentChestXPos,
toObject,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
aMaxStackTransfer,
false);
} else if (fromTileEntityChest.adjacentChestZPos != null) {
return moveMultipleItemStacks(
fromTileEntityChest.adjacentChestZPos,
toObject,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
aMaxStackTransfer,
false);
}
return 0;
}
/**
* Moves Stack from Inv-Side to Inv-Side.
*
* @return the Amount of moved Items
*/
public static byte moveOneItemStack(Object fromObject, Object toObject, ForgeDirection fromSide,
ForgeDirection putSide, List aFilter, boolean aInvertFilter, byte aMaxTargetStackSize,
byte aMinTargetStackSize, byte aMaxMoveAtOnce, byte aMinMoveAtOnce) {
if (fromObject instanceof IInventory inv) return moveOneItemStack(
inv,
toObject,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
true);
return 0;
}
/**
* This is only because I needed an additional Parameter for the Double Chest Check.
*/
private static byte moveOneItemStack(IInventory fromInventory, Object toObject, ForgeDirection fromSide,
ForgeDirection putSide, List aFilter, boolean aInvertFilter, byte aMaxTargetStackSize,
byte aMinTargetStackSize, byte aMaxMoveAtOnce, byte aMinMoveAtOnce, boolean aDoCheckChests) {
if (fromInventory == null || aMaxTargetStackSize <= 0
|| aMinTargetStackSize <= 0
|| aMaxMoveAtOnce <= 0
|| aMinTargetStackSize > aMaxTargetStackSize
|| aMinMoveAtOnce > aMaxMoveAtOnce) return 0;
int[] tGrabSlots = null;
if (fromInventory instanceof ISidedInventory)
tGrabSlots = ((ISidedInventory) fromInventory).getAccessibleSlotsFromSide(fromSide.ordinal());
if (tGrabSlots == null) {
tGrabSlots = new int[fromInventory.getSizeInventory()];
for (int i = 0; i < tGrabSlots.length; i++) tGrabSlots[i] = i;
}
if (toObject instanceof IInventory inv) {
int[] tPutSlots = null;
if (toObject instanceof ISidedInventory sided)
tPutSlots = sided.getAccessibleSlotsFromSide(putSide.ordinal());
if (tPutSlots == null) {
tPutSlots = new int[inv.getSizeInventory()];
for (int i = 0; i < tPutSlots.length; i++) tPutSlots[i] = i;
}
for (final int tGrabSlot : tGrabSlots) {
byte tMovedItemCount = 0;
final ItemStack tGrabStack = fromInventory.getStackInSlot(tGrabSlot);
if (listContainsItem(aFilter, tGrabStack, true, aInvertFilter)
&& (tGrabStack.stackSize >= aMinMoveAtOnce
&& isAllowedToTakeFromSlot(fromInventory, tGrabSlot, fromSide, tGrabStack))) {
for (final int tPutSlot : tPutSlots) {
if (isAllowedToPutIntoSlot(inv, tPutSlot, putSide, tGrabStack, aMaxTargetStackSize)) {
tMovedItemCount += moveStackFromSlotAToSlotB(
fromInventory,
inv,
tGrabSlot,
tPutSlot,
aMaxTargetStackSize,
aMinTargetStackSize,
(byte) (aMaxMoveAtOnce - tMovedItemCount),
aMinMoveAtOnce);
if (tMovedItemCount >= aMaxMoveAtOnce || (tMovedItemCount > 0 && aMaxTargetStackSize < 64))
return tMovedItemCount;
}
}
}
if (tMovedItemCount > 0) return tMovedItemCount;
}
if (aDoCheckChests && fromInventory instanceof TileEntityChest fromChest
&& (fromChest.adjacentChestChecked)) {
byte tAmount = 0;
if (fromChest.adjacentChestXNeg != null) {
tAmount = moveOneItemStack(
fromChest.adjacentChestXNeg,
toObject,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
false);
} else if (fromChest.adjacentChestZNeg != null) {
tAmount = moveOneItemStack(
fromChest.adjacentChestZNeg,
toObject,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
false);
} else if (fromChest.adjacentChestXPos != null) {
tAmount = moveOneItemStack(
fromChest.adjacentChestXPos,
toObject,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
false);
} else if (fromChest.adjacentChestZPos != null) {
tAmount = moveOneItemStack(
fromChest.adjacentChestZPos,
toObject,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
false);
}
if (tAmount != 0) return tAmount;
}
if (aDoCheckChests && toObject instanceof TileEntityChest toChest && (toChest.adjacentChestChecked)) {
byte tAmount = 0;
if (toChest.adjacentChestXNeg != null) {
tAmount = moveOneItemStack(
fromInventory,
toChest.adjacentChestXNeg,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
false);
} else if (toChest.adjacentChestZNeg != null) {
tAmount = moveOneItemStack(
fromInventory,
toChest.adjacentChestZNeg,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
false);
} else if (toChest.adjacentChestXPos != null) {
tAmount = moveOneItemStack(
fromInventory,
toChest.adjacentChestXPos,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
false);
} else if (toChest.adjacentChestZPos != null) {
tAmount = moveOneItemStack(
fromInventory,
toChest.adjacentChestZPos,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
false);
}
if (tAmount != 0) return tAmount;
}
}
return moveStackIntoPipe(
fromInventory,
toObject,
tGrabSlots,
fromSide,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
aDoCheckChests);
}
/**
* Moves Stack from Inv-Side to Inv-Slot.
*
* @return the Amount of moved Items
*/
public static byte moveOneItemStackIntoSlot(Object fromTileEntity, Object toTileEntity, ForgeDirection fromSide,
int putSlot, List aFilter, boolean aInvertFilter, byte aMaxTargetStackSize, byte aMinTargetStackSize,
byte aMaxMoveAtOnce, byte aMinMoveAtOnce) {
if (!(fromTileEntity instanceof IInventory fromInv) || aMaxTargetStackSize <= 0
|| aMinTargetStackSize <= 0
|| aMaxMoveAtOnce <= 0
|| aMinTargetStackSize > aMaxTargetStackSize
|| aMinMoveAtOnce > aMaxMoveAtOnce) return 0;
int[] tGrabSlots = null;
if (fromTileEntity instanceof ISidedInventory sided)
tGrabSlots = sided.getAccessibleSlotsFromSide(fromSide.ordinal());
if (tGrabSlots == null) {
tGrabSlots = new int[fromInv.getSizeInventory()];
for (int i = 0; i < tGrabSlots.length; i++) tGrabSlots[i] = i;
}
if (toTileEntity instanceof IInventory toInv) {
for (final int tGrabSlot : tGrabSlots) {
if (listContainsItem(aFilter, fromInv.getStackInSlot(tGrabSlot), true, aInvertFilter)) {
if (isAllowedToTakeFromSlot(fromInv, tGrabSlot, fromSide, fromInv.getStackInSlot(tGrabSlot))) {
if (isAllowedToPutIntoSlot(
toInv,
putSlot,
ForgeDirection.UNKNOWN,
fromInv.getStackInSlot(tGrabSlot),
aMaxTargetStackSize)) {
byte tMovedItemCount = moveStackFromSlotAToSlotB(
fromInv,
toInv,
tGrabSlot,
putSlot,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce);
if (tMovedItemCount > 0) return tMovedItemCount;
}
}
}
}
}
final ForgeDirection toSide = fromSide.getOpposite();
moveStackIntoPipe(
fromInv,
toTileEntity,
tGrabSlots,
fromSide,
ForgeDirection.UNKNOWN,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce);
return 0;
}
/**
* Moves Stack from Inv-Slot to Inv-Slot.
*
* @return the Amount of moved Items
*/
public static byte moveFromSlotToSlot(IInventory fromInv, IInventory toInv, int aGrabFrom, int aPutTo,
List aFilter, boolean aInvertFilter, byte aMaxTargetStackSize, byte aMinTargetStackSize,
byte aMaxMoveAtOnce, byte aMinMoveAtOnce) {
if (fromInv == null || toInv == null
|| aGrabFrom < 0
|| aPutTo < 0
|| aMinTargetStackSize <= 0
|| aMaxMoveAtOnce <= 0
|| aMinTargetStackSize > aMaxTargetStackSize
|| aMinMoveAtOnce > aMaxMoveAtOnce) return 0;
if (listContainsItem(aFilter, fromInv.getStackInSlot(aGrabFrom), true, aInvertFilter)) {
if (isAllowedToTakeFromSlot(
fromInv,
aGrabFrom,
ForgeDirection.UNKNOWN,
fromInv.getStackInSlot(aGrabFrom))) {
if (isAllowedToPutIntoSlot(
toInv,
aPutTo,
ForgeDirection.UNKNOWN,
fromInv.getStackInSlot(aGrabFrom),
aMaxTargetStackSize)) {
byte tMovedItemCount = moveStackFromSlotAToSlotB(
fromInv,
toInv,
aGrabFrom,
aPutTo,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce);
if (tMovedItemCount > 0) return tMovedItemCount;
}
}
}
return 0;
}
/**
* Moves Stack from Inv-Side to Inv-Slot.
*
* @return the Amount of moved Items
*/
public static byte moveFromSlotToSide(IInventory fromTile, Object toTile, int fromSlot, ForgeDirection putSide,
List aFilter, boolean aInvertFilter, byte aMaxTargetStackSize, byte aMinTargetStackSize,
byte aMaxMoveAtOnce, byte aMinMoveAtOnce, boolean aDoCheckChests) {
if (fromTile == null || fromSlot < 0
|| aMinTargetStackSize <= 0
|| aMaxMoveAtOnce <= 0
|| aMinTargetStackSize > aMaxTargetStackSize
|| aMinMoveAtOnce > aMaxMoveAtOnce) return 0;
if (!listContainsItem(aFilter, fromTile.getStackInSlot(fromSlot), true, aInvertFilter)
|| !isAllowedToTakeFromSlot(fromTile, fromSlot, ForgeDirection.UNKNOWN, fromTile.getStackInSlot(fromSlot)))
return 0;
if (toTile instanceof IInventory) {
int[] tPutSlots = null;
if (toTile instanceof ISidedInventory sided)
tPutSlots = sided.getAccessibleSlotsFromSide(putSide.ordinal());
if (tPutSlots == null) {
tPutSlots = new int[((IInventory) toTile).getSizeInventory()];
for (int i = 0; i < tPutSlots.length; i++) tPutSlots[i] = i;
}
byte tMovedItemCount = 0;
for (final int tPutSlot : tPutSlots) {
if (isAllowedToPutIntoSlot(
(IInventory) toTile,
tPutSlot,
putSide,
fromTile.getStackInSlot(fromSlot),
aMaxTargetStackSize)) {
tMovedItemCount += moveStackFromSlotAToSlotB(
fromTile,
(IInventory) toTile,
fromSlot,
tPutSlot,
aMaxTargetStackSize,
aMinTargetStackSize,
(byte) (aMaxMoveAtOnce - tMovedItemCount),
aMinMoveAtOnce);
if (tMovedItemCount >= aMaxMoveAtOnce) {
return tMovedItemCount;
}
}
}
if (tMovedItemCount > 0) return tMovedItemCount;
if (aDoCheckChests && toTile instanceof TileEntityChest tTileEntity2) {
if (tTileEntity2.adjacentChestChecked) {
if (tTileEntity2.adjacentChestXNeg != null) {
tMovedItemCount = moveFromSlotToSide(
fromTile,
tTileEntity2.adjacentChestXNeg,
fromSlot,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
false);
} else if (tTileEntity2.adjacentChestZNeg != null) {
tMovedItemCount = moveFromSlotToSide(
fromTile,
tTileEntity2.adjacentChestZNeg,
fromSlot,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
false);
} else if (tTileEntity2.adjacentChestXPos != null) {
tMovedItemCount = moveFromSlotToSide(
fromTile,
tTileEntity2.adjacentChestXPos,
fromSlot,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
false);
} else if (tTileEntity2.adjacentChestZPos != null) {
tMovedItemCount = moveFromSlotToSide(
fromTile,
tTileEntity2.adjacentChestZPos,
fromSlot,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
false);
}
if (tMovedItemCount > 0) return tMovedItemCount;
}
}
}
return moveStackIntoPipe(
fromTile,
toTile,
new int[] { fromSlot },
ForgeDirection.UNKNOWN,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
aDoCheckChests);
}
public static byte moveFromSlotToSide(IInventory fromTile, Object toTile, int fromSlot, ForgeDirection putSide,
List aFilter, boolean aInvertFilter, byte aMaxTargetStackSize, byte aMinTargetStackSize,
byte aMaxMoveAtOnce, byte aMinMoveAtOnce) {
return moveFromSlotToSide(
fromTile,
toTile,
fromSlot,
putSide,
aFilter,
aInvertFilter,
aMaxTargetStackSize,
aMinTargetStackSize,
aMaxMoveAtOnce,
aMinMoveAtOnce,
true);
}
/**
* Move up to maxAmount amount of fluid from source to dest, with optional filtering via allowMove. note that this
* filter cannot bypass filtering done by IFluidHandlers themselves.
*
* this overload will assume the fill side is the opposite of drainSide
*
* @param source tank to drain from. method become noop if this is null
* @param dest tank to fill to. method become noop if this is null
* @param drainSide side used during draining operation
* @param maxAmount max amount of fluid to transfer. method become noop if this is not a positive integer
* @param allowMove filter. can be null to signal all fluids are accepted
*/
public static void moveFluid(IFluidHandler source, IFluidHandler dest, ForgeDirection drainSide, int maxAmount,
@Nullable Predicate allowMove) {
moveFluid(source, dest, drainSide, drainSide.getOpposite(), maxAmount, allowMove);
}
/**
* Move up to maxAmount amount of fluid from source to dest, with optional filtering via allowMove. note that this
* filter cannot bypass filtering done by IFluidHandlers themselves.
*
* @param source tank to drain from. method become noop if this is null
* @param dest tank to fill to. method become noop if this is null
* @param drainSide side used during draining operation
* @param fillSide side used during filling operation
* @param maxAmount max amount of fluid to transfer. method become noop if this is not a positive integer
* @param allowMove filter. can be null to signal all fluids are accepted
*/
public static void moveFluid(IFluidHandler source, IFluidHandler dest, ForgeDirection drainSide,
ForgeDirection fillSide, int maxAmount, @Nullable Predicate allowMove) {
if (source == null || dest == null || maxAmount <= 0) return;
FluidStack liquid = source.drain(drainSide, maxAmount, false);
if (liquid == null) return;
liquid = liquid.copy();
liquid.amount = dest.fill(fillSide, liquid, false);
if (liquid.amount > 0 && (allowMove == null || allowMove.test(liquid))) {
dest.fill(fillSide, source.drain(drainSide, liquid.amount, true), true);
}
}
public static boolean listContainsItem(Collection aList, ItemStack aStack, boolean aTIfListEmpty,
boolean aInvertFilter) {
if (aStack == null || aStack.stackSize < 1) return false;
if (aList == null) return aTIfListEmpty;
boolean tEmpty = true;
for (ItemStack tStack : aList) {
if (tStack != null) {
tEmpty = false;
if (areStacksEqual(aStack, tStack)) {
return !aInvertFilter;
}
}
}
return tEmpty ? aTIfListEmpty : aInvertFilter;
}
public static boolean areStacksOrToolsEqual(ItemStack aStack1, ItemStack aStack2) {
if (aStack1 != null && aStack2 != null && aStack1.getItem() == aStack2.getItem()) {
if (aStack1.getItem()
.isDamageable()) return true;
return ((aStack1.getTagCompound() == null) == (aStack2.getTagCompound() == null))
&& (aStack1.getTagCompound() == null || aStack1.getTagCompound()
.equals(aStack2.getTagCompound()))
&& (Items.feather.getDamage(aStack1) == Items.feather.getDamage(aStack2)
|| Items.feather.getDamage(aStack1) == W
|| Items.feather.getDamage(aStack2) == W);
}
return false;
}
public static boolean areFluidsEqual(FluidStack aFluid1, FluidStack aFluid2) {
return areFluidsEqual(aFluid1, aFluid2, false);
}
public static boolean areFluidsEqual(FluidStack aFluid1, FluidStack aFluid2, boolean aIgnoreNBT) {
return aFluid1 != null && aFluid2 != null
&& aFluid1.getFluid() == aFluid2.getFluid()
&& (aIgnoreNBT || ((aFluid1.tag == null) == (aFluid2.tag == null))
&& (aFluid1.tag == null || aFluid1.tag.equals(aFluid2.tag)));
}
public static boolean areStacksEqual(ItemStack aStack1, ItemStack aStack2) {
return areStacksEqual(aStack1, aStack2, false);
}
public static boolean areStacksEqual(ItemStack aStack1, ItemStack aStack2, boolean aIgnoreNBT) {
return aStack1 != null && aStack2 != null
&& aStack1.getItem() == aStack2.getItem()
&& (Items.feather.getDamage(aStack1) == Items.feather.getDamage(aStack2)
|| Items.feather.getDamage(aStack1) == W
|| Items.feather.getDamage(aStack2) == W)
&& (aIgnoreNBT || (((aStack1.getTagCompound() == null) == (aStack2.getTagCompound() == null))
&& (aStack1.getTagCompound() == null || aStack1.getTagCompound()
.equals(aStack2.getTagCompound()))));
}
public static boolean areStacksEqualOrNull(ItemStack stack1, ItemStack stack2) {
return (stack1 == null && stack2 == null) || GTUtility.areStacksEqual(stack1, stack2);
}
/**
* Treat both null list, or both null item stack at same list position as equal.
*
* Since ItemStack doesn't override equals and hashCode, you cannot just use Objects.equals
*/
public static boolean areStackListsEqual(List lhs, List rhs, boolean ignoreStackSize,
boolean ignoreNBT) {
if (lhs == null) return rhs == null;
if (rhs == null) return false;
if (lhs.size() != rhs.size()) return false;
for (Iterator it1 = lhs.iterator(), it2 = rhs.iterator(); it1.hasNext() && it2.hasNext();) {
if (!areStacksEqualExtended(it1.next(), it2.next(), ignoreStackSize, ignoreNBT)) return false;
}
return true;
}
private static boolean areStacksEqualExtended(ItemStack lhs, ItemStack rhs, boolean ignoreStackSize,
boolean ignoreNBT) {
if (lhs == null) return rhs == null;
if (rhs == null) return false;
return lhs.getItem() == rhs.getItem()
&& (ignoreNBT || Objects.equals(lhs.stackTagCompound, rhs.stackTagCompound))
&& (ignoreStackSize || lhs.stackSize == rhs.stackSize);
}
public static boolean areUnificationsEqual(ItemStack aStack1, ItemStack aStack2) {
return areUnificationsEqual(aStack1, aStack2, false);
}
public static boolean areUnificationsEqual(ItemStack aStack1, ItemStack aStack2, boolean aIgnoreNBT) {
return areStacksEqual(
GTOreDictUnificator.get_nocopy(aStack1),
GTOreDictUnificator.get_nocopy(aStack2),
aIgnoreNBT);
}
public static String getFluidName(Fluid aFluid, boolean aLocalized) {
if (aFluid == null) return E;
String rName = aLocalized ? aFluid.getLocalizedName(new FluidStack(aFluid, 0)) : aFluid.getUnlocalizedName();
if (rName.contains("fluid.") || rName.contains("tile.")) return capitalizeString(
rName.replaceAll("fluid.", E)
.replaceAll("tile.", E));
return rName;
}
public static String getFluidName(FluidStack aFluid, boolean aLocalized) {
if (aFluid == null) return E;
return getFluidName(aFluid.getFluid(), aLocalized);
}
public static void reInit() {
sFilledContainerToData.clear();
sEmptyContainerToFluidToData.clear();
sFluidToContainers.clear();
for (FluidContainerData tData : sFluidContainerList) {
String fluidName = tData.fluid.getFluid()
.getName();
sFilledContainerToData.put(new GTItemStack(tData.filledContainer), tData);
Map tFluidToContainer = sEmptyContainerToFluidToData
.get(new GTItemStack(tData.emptyContainer));
List tContainers = sFluidToContainers.get(fluidName);
if (tFluidToContainer == null) {
sEmptyContainerToFluidToData
.put(new GTItemStack(tData.emptyContainer), tFluidToContainer = new /* Concurrent */ HashMap<>());
}
tFluidToContainer.put(fluidName, tData);
if (tContainers == null) {
tContainers = new ArrayList<>();
tContainers.add(tData.filledContainer);
sFluidToContainers.put(fluidName, tContainers);
} else tContainers.add(tData.filledContainer);
}
}
public static void addFluidContainerData(FluidContainerData aData) {
String fluidName = aData.fluid.getFluid()
.getName();
sFluidContainerList.add(aData);
sFilledContainerToData.put(new GTItemStack(aData.filledContainer), aData);
Map tFluidToContainer = sEmptyContainerToFluidToData
.get(new GTItemStack(aData.emptyContainer));
List tContainers = sFluidToContainers.get(fluidName);
if (tFluidToContainer == null) {
sEmptyContainerToFluidToData
.put(new GTItemStack(aData.emptyContainer), tFluidToContainer = new /* Concurrent */ HashMap<>());
}
tFluidToContainer.put(fluidName, aData);
if (tContainers == null) {
tContainers = new ArrayList<>();
tContainers.add(aData.filledContainer);
sFluidToContainers.put(fluidName, tContainers);
} else tContainers.add(aData.filledContainer);
}
public static List getContainersFromFluid(FluidStack tFluidStack) {
if (tFluidStack != null) {
List tContainers = sFluidToContainers.get(
tFluidStack.getFluid()
.getName());
if (tContainers == null) return new ArrayList<>();
return tContainers;
}
return new ArrayList<>();
}
public static ItemStack fillFluidContainer(FluidStack aFluid, ItemStack aStack, boolean aRemoveFluidDirectly,
boolean aCheckIFluidContainerItems) {
if (isStackInvalid(aStack) || aFluid == null) return null;
if (GTModHandler.isWater(aFluid) && ItemList.Bottle_Empty.isStackEqual(aStack)) {
if (aFluid.amount >= 1000) {
return new ItemStack(Items.potionitem, 1, 0);
}
return null;
}
if (aCheckIFluidContainerItems && aStack.getItem() instanceof IFluidContainerItem
&& ((IFluidContainerItem) aStack.getItem()).getFluid(aStack) == null
&& ((IFluidContainerItem) aStack.getItem()).getCapacity(aStack) <= aFluid.amount) {
if (aRemoveFluidDirectly) aFluid.amount -= ((IFluidContainerItem) aStack.getItem())
.fill(aStack = copyAmount(1, aStack), aFluid, true);
else((IFluidContainerItem) aStack.getItem()).fill(aStack = copyAmount(1, aStack), aFluid, true);
return aStack;
}
Map tFluidToContainer = sEmptyContainerToFluidToData.get(new GTItemStack(aStack));
if (tFluidToContainer == null) return null;
FluidContainerData tData = tFluidToContainer.get(
aFluid.getFluid()
.getName());
if (tData == null || tData.fluid.amount > aFluid.amount) return null;
if (aRemoveFluidDirectly) aFluid.amount -= tData.fluid.amount;
return copyAmount(1, tData.filledContainer);
}
public static int calculateRecipeEU(Materials aMaterial, int defaultRecipeEUPerTick) {
return aMaterial.getProcessingMaterialTierEU() == 0 ? defaultRecipeEUPerTick
: aMaterial.getProcessingMaterialTierEU();
}
public static ItemStack getFluidDisplayStack(Fluid aFluid) {
return aFluid == null ? null : getFluidDisplayStack(new FluidStack(aFluid, 0), false);
}
public static ItemStack getFluidDisplayStack(FluidStack aFluid, boolean aUseStackSize) {
return getFluidDisplayStack(aFluid, aUseStackSize, false);
}
public static ItemStack getFluidDisplayStack(FluidStack aFluid, boolean aUseStackSize, boolean aHideStackSize) {
if (aFluid == null || aFluid.getFluid() == null) return null;
int tmp = 0;
try {
tmp = aFluid.getFluid()
.getID();
} catch (Exception e) {
e.printStackTrace();
}
ItemStack rStack = ItemList.Display_Fluid.getWithDamage(1, tmp);
NBTTagCompound tNBT = new NBTTagCompound();
tNBT.setLong("mFluidDisplayAmount", aUseStackSize ? aFluid.amount : 0);
tNBT.setLong(
"mFluidDisplayHeat",
aFluid.getFluid()
.getTemperature(aFluid));
tNBT.setBoolean(
"mFluidState",
aFluid.getFluid()
.isGaseous(aFluid));
tNBT.setBoolean("mHideStackSize", aHideStackSize);
try {
tNBT.setString("mFluidMaterialName", FLUID_MAP.get(aFluid.getFluid()).mName);
} catch (Exception ignored) {}
rStack.setTagCompound(tNBT);
return rStack;
}
public static FluidStack getFluidFromDisplayStack(ItemStack aDisplayStack) {
if (!isStackValid(aDisplayStack) || aDisplayStack.getItem() != ItemList.Display_Fluid.getItem()
|| !aDisplayStack.hasTagCompound()) return null;
Fluid tFluid = FluidRegistry.getFluid(
ItemList.Display_Fluid.getItem()
.getDamage(aDisplayStack));
return new FluidStack(
tFluid,
(int) aDisplayStack.getTagCompound()
.getLong("mFluidDisplayAmount"));
}
public static boolean containsFluid(ItemStack aStack, FluidStack aFluid, boolean aCheckIFluidContainerItems) {
if (isStackInvalid(aStack) || aFluid == null) return false;
if (aCheckIFluidContainerItems && aStack.getItem() instanceof IFluidContainerItem
&& ((IFluidContainerItem) aStack.getItem()).getCapacity(aStack) > 0)
return aFluid
.isFluidEqual(((IFluidContainerItem) aStack.getItem()).getFluid(aStack = copyAmount(1, aStack)));
FluidContainerData tData = sFilledContainerToData.get(new GTItemStack(aStack));
return tData != null && tData.fluid.isFluidEqual(aFluid);
}
public static FluidStack getFluidForFilledItem(ItemStack aStack, boolean aCheckIFluidContainerItems) {
if (isStackInvalid(aStack)) return null;
if (aCheckIFluidContainerItems && aStack.getItem() instanceof IFluidContainerItem
&& ((IFluidContainerItem) aStack.getItem()).getCapacity(aStack) > 0)
return ((IFluidContainerItem) aStack.getItem()).drain(copyAmount(1, aStack), Integer.MAX_VALUE, true);
FluidContainerData tData = sFilledContainerToData.get(new GTItemStack(aStack));
return tData == null ? null : tData.fluid.copy();
}
/**
* Get empty fluid container from filled one.
*/
public static ItemStack getContainerForFilledItem(ItemStack aStack, boolean aCheckIFluidContainerItems) {
if (isStackInvalid(aStack)) return null;
FluidContainerData tData = sFilledContainerToData.get(new GTItemStack(aStack));
if (tData != null) return copyAmount(1, tData.emptyContainer);
if (aCheckIFluidContainerItems && aStack.getItem() instanceof IFluidContainerItem
&& ((IFluidContainerItem) aStack.getItem()).getCapacity(aStack) > 0) {
((IFluidContainerItem) aStack.getItem()).drain(aStack = copyAmount(1, aStack), Integer.MAX_VALUE, true);
return aStack;
}
return null;
}
/**
* This is NOT meant for fluid manipulation! It's for getting item container, which is generally used for
* crafting recipes. While it also works for many of the fluid containers, some don't.
*
* Use {@link #getContainerForFilledItem} for getting empty fluid container.
*/
public static ItemStack getContainerItem(ItemStack aStack, boolean aCheckIFluidContainerItems) {
if (isStackInvalid(aStack)) return null;
if (aStack.getItem()
.hasContainerItem(aStack))
return aStack.getItem()
.getContainerItem(aStack);
/*
* These are all special Cases, in which it is intended to have only GT Blocks outputting those Container Items
*/
if (ItemList.Cell_Empty.isStackEqual(aStack, false, true)) return null;
if (aStack.getItem() == Items.potionitem || aStack.getItem() == Items.experience_bottle
|| ItemList.TF_Vial_FieryBlood.isStackEqual(aStack)
|| ItemList.TF_Vial_FieryTears.isStackEqual(aStack)) return ItemList.Bottle_Empty.get(1);
if (aCheckIFluidContainerItems && aStack.getItem() instanceof IFluidContainerItem
&& ((IFluidContainerItem) aStack.getItem()).getCapacity(aStack) > 0) {
ItemStack tStack = copyAmount(1, aStack);
((IFluidContainerItem) aStack.getItem()).drain(tStack, Integer.MAX_VALUE, true);
if (!areStacksEqual(aStack, tStack)) return tStack;
return null;
}
int tCapsuleCount = GTModHandler.getCapsuleCellContainerCount(aStack);
if (tCapsuleCount > 0) return ItemList.Cell_Empty.get(tCapsuleCount);
if (ItemList.IC2_ForgeHammer.isStackEqual(aStack) || ItemList.IC2_WireCutter.isStackEqual(aStack))
return copyMetaData(Items.feather.getDamage(aStack) + 1, aStack);
return null;
}
public static FluidStack getFluidFromContainerOrFluidDisplay(ItemStack stack) {
FluidStack fluidStack = GTUtility.getFluidForFilledItem(stack, true);
if (fluidStack == null) {
fluidStack = GTUtility.getFluidFromDisplayStack(stack);
}
return fluidStack;
}
public static synchronized boolean removeIC2BottleRecipe(ItemStack aContainer, ItemStack aInput,
Map aRecipeList, ItemStack aOutput) {
if ((isStackInvalid(aInput) && isStackInvalid(aOutput) && isStackInvalid(aContainer)) || aRecipeList == null)
return false;
boolean rReturn = false;
Iterator> tIterator = aRecipeList
.entrySet()
.iterator();
aOutput = GTOreDictUnificator.get(aOutput);
while (tIterator.hasNext()) {
Map.Entry tEntry = tIterator.next();
if (aInput == null || tEntry.getKey()
.matches(aContainer, aInput)) {
List tList = tEntry.getValue().items;
if (tList != null) for (ItemStack tOutput : tList)
if (aOutput == null || areStacksEqual(GTOreDictUnificator.get(tOutput), aOutput)) {
tIterator.remove();
rReturn = true;
break;
}
}
}
return rReturn;
}
public static synchronized boolean removeSimpleIC2MachineRecipe(ItemStack aInput,
Map aRecipeList, ItemStack aOutput) {
if ((isStackInvalid(aInput) && isStackInvalid(aOutput)) || aRecipeList == null) return false;
boolean rReturn = false;
Iterator> tIterator = aRecipeList.entrySet()
.iterator();
aOutput = GTOreDictUnificator.get(aOutput);
while (tIterator.hasNext()) {
Map.Entry tEntry = tIterator.next();
if (aInput == null || tEntry.getKey()
.matches(aInput)) {
List tList = tEntry.getValue().items;
if (tList != null) for (ItemStack tOutput : tList)
if (aOutput == null || areStacksEqual(GTOreDictUnificator.get(tOutput), aOutput)) {
tIterator.remove();
rReturn = true;
break;
}
}
}
return rReturn;
}
public static synchronized void bulkRemoveSimpleIC2MachineRecipe(Map toRemove,
Map aRecipeList) {
if (aRecipeList == null || aRecipeList.isEmpty()) return;
toRemove.entrySet()
.removeIf(aEntry -> (isStackInvalid(aEntry.getKey()) && isStackInvalid(aEntry.getValue())));
final Map finalToRemove = Maps.transformValues(toRemove, GTOreDictUnificator::get_nocopy);
aRecipeList.entrySet()
.removeIf(
tEntry -> finalToRemove.entrySet()
.stream()
.anyMatch(aEntry -> {
final ItemStack aInput = aEntry.getKey(), aOutput = aEntry.getValue();
final List tList = tEntry.getValue().items;
if (tList == null) return false;
if (aInput != null && !tEntry.getKey()
.matches(aInput)) return false;
return tList.stream()
.anyMatch(
tOutput -> (aOutput == null
|| areStacksEqual(GTOreDictUnificator.get(tOutput), aOutput)));
}));
}
public static boolean addSimpleIC2MachineRecipe(ItemStack aInput, Map aRecipeList,
NBTTagCompound aNBT, Object... aOutput) {
if (isStackInvalid(aInput) || aOutput.length == 0 || aRecipeList == null) return false;
ItemData tOreName = GTOreDictUnificator.getAssociation(aInput);
for (Object o : aOutput) {
if (o == null) {
GT_FML_LOGGER.info("EmptyIC2Output!" + aInput.getUnlocalizedName());
return false;
}
}
ItemStack[] tStack = GTOreDictUnificator.getStackArray(true, aOutput);
if (tStack.length > 0 && areStacksEqual(aInput, tStack[0])) return false;
if (tOreName != null) {
if (tOreName.toString()
.equals("dustAsh")
&& tStack[0].getUnlocalizedName()
.equals("tile.volcanicAsh"))
return false;
aRecipeList
.put(new RecipeInputOreDict(tOreName.toString(), aInput.stackSize), new RecipeOutput(aNBT, tStack));
} else {
aRecipeList
.put(new RecipeInputItemStack(copyOrNull(aInput), aInput.stackSize), new RecipeOutput(aNBT, tStack));
}
return true;
}
public static ItemStack getWrittenBook(String aMapping, ItemStack aStackToPutNBT) {
if (isStringInvalid(aMapping)) return null;
ItemStack rStack = GregTechAPI.sBookList.get(aMapping);
if (rStack == null) return aStackToPutNBT;
if (aStackToPutNBT != null) {
aStackToPutNBT.setTagCompound(rStack.getTagCompound());
return aStackToPutNBT;
}
return copyAmount(1, rStack);
}
public static ItemStack getWrittenBook(String aMapping, String aTitle, String aAuthor, String... aPages) {
if (isStringInvalid(aMapping)) return null;
ItemStack rStack = GregTechAPI.sBookList.get(aMapping);
if (rStack != null) return copyAmount(1, rStack);
if (isStringInvalid(aTitle) || isStringInvalid(aAuthor) || aPages.length == 0) return null;
sBookCount++;
rStack = new ItemStack(Items.written_book, 1);
NBTTagCompound tNBT = new NBTTagCompound();
tNBT.setString("title", GTLanguageManager.addStringLocalization("Book." + aTitle + ".Name", aTitle));
tNBT.setString("author", aAuthor);
NBTTagList tNBTList = new NBTTagList();
for (byte i = 0; i < aPages.length; i++) {
aPages[i] = GTLanguageManager
.addStringLocalization("Book." + aTitle + ".Page" + ((i < 10) ? "0" + i : i), aPages[i]);
if (i < 48) {
if (aPages[i].length() < 256) tNBTList.appendTag(new NBTTagString(aPages[i]));
else GTLog.err.println("WARNING: String for written Book too long! -> " + aPages[i]);
} else {
GTLog.err.println("WARNING: Too much Pages for written Book! -> " + aTitle);
break;
}
}
tNBTList.appendTag(
new NBTTagString(
"Credits to " + aAuthor
+ " for writing this Book. This was Book Nr. "
+ sBookCount
+ " at its creation. Gotta get 'em all!"));
tNBT.setTag("pages", tNBTList);
rStack.setTagCompound(tNBT);
GTLog.out.println(
"GTMod: Added Book to Book List - Mapping: '" + aMapping
+ "' - Name: '"
+ aTitle
+ "' - Author: '"
+ aAuthor
+ "'");
GregTechAPI.sBookList.put(aMapping, rStack);
return copyOrNull(rStack);
}
public static boolean doSoundAtClient(String aSoundName, int aTimeUntilNextSound, float aSoundStrength) {
if (aSoundName == null) return false;
return doSoundAtClient(aSoundName, aTimeUntilNextSound, aSoundStrength, GT.getThePlayer());
}
public static boolean doSoundAtClient(SoundResource sound, int aTimeUntilNextSound, float aSoundStrength) {
return doSoundAtClient(sound.resourceLocation, aTimeUntilNextSound, aSoundStrength, GT.getThePlayer());
}
public static boolean doSoundAtClient(ResourceLocation aSoundResourceLocation, int aTimeUntilNextSound,
float aSoundStrength) {
return doSoundAtClient(aSoundResourceLocation, aTimeUntilNextSound, aSoundStrength, GT.getThePlayer());
}
public static boolean doSoundAtClient(String aSoundName, int aTimeUntilNextSound, float aSoundStrength,
Entity aEntity) {
if (aEntity == null || aSoundName == null) return false;
return doSoundAtClient(
aSoundName,
aTimeUntilNextSound,
aSoundStrength,
aEntity.posX,
aEntity.posY,
aEntity.posZ);
}
public static boolean doSoundAtClient(ResourceLocation aSoundResourceLocation, int aTimeUntilNextSound,
float aSoundStrength, Entity aEntity) {
if (aEntity == null) return false;
return doSoundAtClient(
aSoundResourceLocation.toString(),
aTimeUntilNextSound,
aSoundStrength,
aEntity.posX,
aEntity.posY,
aEntity.posZ);
}
public static boolean doSoundAtClient(ResourceLocation aSoundResourceLocation, int aTimeUntilNextSound,
float aSoundStrength, double aX, double aY, double aZ) {
return doSoundAtClient(aSoundResourceLocation, aTimeUntilNextSound, aSoundStrength, 1.01818028F, aX, aY, aZ);
}
/**
* @inheritDoc
* @deprecated Use {@link #doSoundAtClient(ResourceLocation, int, float, double, double, double)}
*/
@Deprecated
public static boolean doSoundAtClient(String aSoundName, int aTimeUntilNextSound, float aSoundStrength, double aX,
double aY, double aZ) {
if (aSoundName == null) return false;
return doSoundAtClient(
new ResourceLocation(aSoundName),
aTimeUntilNextSound,
aSoundStrength,
1.01818028F,
aX,
aY,
aZ);
}
public static boolean doSoundAtClient(SoundResource aSound, int aTimeUntilNextSound, float aSoundStrength,
double aX, double aY, double aZ) {
return doSoundAtClient(aSound.resourceLocation, aTimeUntilNextSound, aSoundStrength, aX, aY, aZ);
}
public static boolean doSoundAtClient(SoundResource aSound, int aTimeUntilNextSound, float aSoundStrength,
float aSoundModulation, double aX, double aY, double aZ) {
return doSoundAtClient(
aSound.resourceLocation,
aTimeUntilNextSound,
aSoundStrength,
aSoundModulation,
aX,
aY,
aZ);
}
public static boolean doSoundAtClient(ResourceLocation aSoundResourceLocation, int aTimeUntilNextSound,
float aSoundStrength, float aSoundModulation, double aX, double aY, double aZ) {
if (!FMLCommonHandler.instance()
.getEffectiveSide()
.isClient() || GT.getThePlayer() == null || !GT.getThePlayer().worldObj.isRemote) return false;
if (GregTechAPI.sMultiThreadedSounds) new Thread(
new RunnableSound(
GT.getThePlayer().worldObj,
aX,
aY,
aZ,
aTimeUntilNextSound,
aSoundResourceLocation,
aSoundStrength,
aSoundModulation),
"Sound Effect").start();
else new RunnableSound(
GT.getThePlayer().worldObj,
aX,
aY,
aZ,
aTimeUntilNextSound,
aSoundResourceLocation,
aSoundStrength,
aSoundModulation).run();
return true;
}
public static boolean sendSoundToPlayers(World aWorld, String aSoundName, float aSoundStrength,
float aSoundModulation, int aX, int aY, int aZ) {
if (isStringInvalid(aSoundName) || aWorld == null || aWorld.isRemote) return false;
NW.sendPacketToAllPlayersInRange(
aWorld,
new GTPacketSound(aSoundName, aSoundStrength, aSoundModulation, aX, (short) aY, aZ),
aX,
aZ);
return true;
}
public static boolean sendSoundToPlayers(World aWorld, SoundResource sound, float aSoundStrength,
float aSoundModulation, int aX, int aY, int aZ) {
if (aWorld == null || aWorld.isRemote) return false;
NW.sendPacketToAllPlayersInRange(
aWorld,
new GTPacketSound(sound.resourceLocation.toString(), aSoundStrength, aSoundModulation, aX, (short) aY, aZ),
aX,
aZ);
return true;
}
public static int stackToInt(ItemStack aStack) {
if (isStackInvalid(aStack)) return 0;
return itemToInt(aStack.getItem(), Items.feather.getDamage(aStack));
}
public static int itemToInt(Item aItem, int aMeta) {
return Item.getIdFromItem(aItem) | (aMeta << 16);
}
public static int stackToWildcard(ItemStack aStack) {
if (isStackInvalid(aStack)) return 0;
return Item.getIdFromItem(aStack.getItem()) | (W << 16);
}
public static ItemStack intToStack(int aStack) {
int tID = aStack & (~0 >>> 16), tMeta = aStack >>> 16;
Item tItem = Item.getItemById(tID);
if (tItem != null) return new ItemStack(tItem, 1, tMeta);
return null;
}
public static Integer[] stacksToIntegerArray(ItemStack... aStacks) {
Integer[] rArray = new Integer[aStacks.length];
for (int i = 0; i < rArray.length; i++) {
rArray[i] = stackToInt(aStacks[i]);
}
return rArray;
}
public static int[] stacksToIntArray(ItemStack... aStacks) {
int[] rArray = new int[aStacks.length];
for (int i = 0; i < rArray.length; i++) {
rArray[i] = stackToInt(aStacks[i]);
}
return rArray;
}
public static boolean arrayContains(Object aObject, Object... aObjects) {
return listContains(aObject, Arrays.asList(aObjects));
}
public static boolean listContains(Object aObject, Collection> aObjects) {
if (aObjects == null) return false;
return aObjects.contains(aObject);
}
@SafeVarargs
public static boolean arrayContainsNonNull(T... aArray) {
if (aArray != null) for (Object tObject : aArray) if (tObject != null) return true;
return false;
}
/**
* Note: use {@link ArrayExt#withoutNulls(Object[], IntFunction)} if you want an array as a result.
*/
@SafeVarargs
public static ArrayList getArrayListWithoutNulls(T... aArray) {
if (aArray == null) return new ArrayList<>();
ArrayList rList = new ArrayList<>(Arrays.asList(aArray));
for (int i = 0; i < rList.size(); i++) if (rList.get(i) == null) rList.remove(i--);
return rList;
}
/**
* Note: use {@link ArrayExt#withoutTrailingNulls(Object[], IntFunction)} if you want an array as a result.
*/
@SafeVarargs
public static ArrayList getArrayListWithoutTrailingNulls(T... aArray) {
if (aArray == null) return new ArrayList<>();
ArrayList rList = new ArrayList<>(Arrays.asList(aArray));
for (int i = rList.size() - 1; i >= 0 && rList.get(i) == null;) rList.remove(i--);
return rList;
}
public static Block getBlockFromStack(ItemStack itemStack) {
if (isStackInvalid(itemStack)) return Blocks.air;
return getBlockFromItem(itemStack.getItem());
}
public static Block getBlockFromItem(Item item) {
return Block.getBlockFromItem(item);
}
public static boolean isStringValid(Object aString) {
return aString != null && !aString.toString()
.isEmpty();
}
public static boolean isStringInvalid(Object aString) {
return aString == null || aString.toString()
.isEmpty();
}
@Deprecated
public static boolean isStackValid(Object aStack) {
return (aStack instanceof ItemStack stack) && isStackValid(stack);
}
public static boolean isStackValid(ItemStack aStack) {
return (aStack != null) && aStack.getItem() != null && aStack.stackSize >= 0;
}
@Deprecated
public static boolean isStackInvalid(Object aStack) {
return !(aStack instanceof ItemStack stack) || isStackInvalid(stack);
}
public static boolean isStackInvalid(ItemStack aStack) {
return aStack == null || aStack.getItem() == null || aStack.stackSize < 0;
}
public static boolean isDebugItem(ItemStack aStack) {
return /* ItemList.Armor_Cheat.isStackEqual(aStack, T, T) || */ areStacksEqual(
GTModHandler.getIC2Item("debug", 1),
aStack,
true);
}
public static ItemStack updateItemStack(ItemStack aStack) {
if (isStackValid(aStack) && aStack.getItem() instanceof GTGenericItem)
((GTGenericItem) aStack.getItem()).isItemStackUsable(aStack);
return aStack;
}
public static boolean isOpaqueBlock(World aWorld, int aX, int aY, int aZ) {
return aWorld.getBlock(aX, aY, aZ)
.isOpaqueCube();
}
public static boolean isBlockAir(World aWorld, int aX, int aY, int aZ) {
return aWorld.getBlock(aX, aY, aZ)
.isAir(aWorld, aX, aY, aZ);
}
public static boolean hasBlockHitBox(World aWorld, int aX, int aY, int aZ) {
return aWorld.getBlock(aX, aY, aZ)
.getCollisionBoundingBoxFromPool(aWorld, aX, aY, aZ) != null;
}
public static void setCoordsOnFire(World aWorld, int aX, int aY, int aZ, boolean aReplaceCenter) {
if (aReplaceCenter) if (aWorld.getBlock(aX, aY, aZ)
.getCollisionBoundingBoxFromPool(aWorld, aX, aY, aZ) == null) aWorld.setBlock(aX, aY, aZ, Blocks.fire);
if (aWorld.getBlock(aX + 1, aY, aZ)
.getCollisionBoundingBoxFromPool(aWorld, aX + 1, aY, aZ) == null)
aWorld.setBlock(aX + 1, aY, aZ, Blocks.fire);
if (aWorld.getBlock(aX - 1, aY, aZ)
.getCollisionBoundingBoxFromPool(aWorld, aX - 1, aY, aZ) == null)
aWorld.setBlock(aX - 1, aY, aZ, Blocks.fire);
if (aWorld.getBlock(aX, aY + 1, aZ)
.getCollisionBoundingBoxFromPool(aWorld, aX, aY + 1, aZ) == null)
aWorld.setBlock(aX, aY + 1, aZ, Blocks.fire);
if (aWorld.getBlock(aX, aY - 1, aZ)
.getCollisionBoundingBoxFromPool(aWorld, aX, aY - 1, aZ) == null)
aWorld.setBlock(aX, aY - 1, aZ, Blocks.fire);
if (aWorld.getBlock(aX, aY, aZ + 1)
.getCollisionBoundingBoxFromPool(aWorld, aX, aY, aZ + 1) == null)
aWorld.setBlock(aX, aY, aZ + 1, Blocks.fire);
if (aWorld.getBlock(aX, aY, aZ - 1)
.getCollisionBoundingBoxFromPool(aWorld, aX, aY, aZ - 1) == null)
aWorld.setBlock(aX, aY, aZ - 1, Blocks.fire);
}
public static ItemStack getProjectile(SubTag aProjectileType, IInventory aInventory) {
if (aInventory != null) for (int i = 0, j = aInventory.getSizeInventory(); i < j; i++) {
ItemStack rStack = aInventory.getStackInSlot(i);
if (isStackValid(rStack) && rStack.getItem() instanceof IProjectileItem
&& ((IProjectileItem) rStack.getItem()).hasProjectile(aProjectileType, rStack))
return updateItemStack(rStack);
}
return null;
}
public static void removeNullStacksFromInventory(IInventory aInventory) {
if (aInventory != null) for (int i = 0, j = aInventory.getSizeInventory(); i < j; i++) {
ItemStack tStack = aInventory.getStackInSlot(i);
if (tStack != null && (tStack.stackSize == 0 || tStack.getItem() == null))
aInventory.setInventorySlotContents(i, null);
}
}
/**
* Initializes new empty texture page for casings page 0 is old CASING_BLOCKS
*
* Then casings should be registered like this: for (byte i = MIN_USED_META; i < MAX_USED_META; i = (byte) (i + 1))
* { Textures.BlockIcons.casingTexturePages[PAGE][i+START_INDEX] = new GT_CopiedBlockTexture(this, 6, i); }
*
* @param page 0 to 127
* @return true if it made empty page, false if one already existed...
*/
public static boolean addTexturePage(byte page) {
if (Textures.BlockIcons.casingTexturePages[page] == null) {
Textures.BlockIcons.casingTexturePages[page] = new ITexture[128];
return true;
}
return false;
}
/**
* Return texture id from page and index, for use when determining hatches, but can also be precomputed from:
* (page<<7)+index
*
* @param page 0 to 127 page
* @param index 0 to 127 texture index
* @return casing texture 0 to 16383
*/
public static int getTextureId(byte page, byte index) {
if (page >= 0 && index >= 0) {
return (page << 7) + index;
}
throw new RuntimeException("Index out of range: [" + page + "][" + index + "]");
}
/**
* Return texture id from page and index, for use when determining hatches, but can also be precomputed from:
* (page<<7)+index
*
* @param page 0 to 127 page
* @param startIndex 0 to 127 start texture index
* @param blockMeta meta of the block
* @return casing texture 0 to 16383
*/
public static int getTextureId(byte page, byte startIndex, byte blockMeta) {
if (page >= 0 && startIndex >= 0 && blockMeta >= 0 && (startIndex + blockMeta) <= 127) {
return (page << 7) + (startIndex + blockMeta);
}
throw new RuntimeException(
"Index out of range: [" + page
+ "]["
+ startIndex
+ "+"
+ blockMeta
+ "="
+ (startIndex + blockMeta)
+ "]");
}
/**
* Return texture id from item stack, unoptimized but readable?
*
* @return casing texture 0 to 16383
*/
public static int getTextureId(Block blockFromBlock, byte metaFromBlock) {
for (int page = 0; page < Textures.BlockIcons.casingTexturePages.length; page++) {
ITexture[] casingTexturePage = Textures.BlockIcons.casingTexturePages[page];
if (casingTexturePage != null) {
for (int index = 0; index < casingTexturePage.length; index++) {
ITexture iTexture = casingTexturePage[index];
if (iTexture instanceof IBlockContainer) {
Block block = ((IBlockContainer) iTexture).getBlock();
byte meta = ((IBlockContainer) iTexture).getMeta();
if (meta == metaFromBlock && blockFromBlock == block) {
return (page << 7) + index;
}
}
}
}
}
throw new RuntimeException(
"Probably missing mapping or different texture class used for: " + blockFromBlock.getUnlocalizedName()
+ " meta:"
+ metaFromBlock);
}
/**
* Converts a Number to a String
*/
public static String parseNumberToString(int aNumber) {
boolean temp = true, negative = false;
if (aNumber < 0) {
aNumber *= -1;
negative = true;
}
StringBuilder tStringB = new StringBuilder();
for (int i = 1000000000; i > 0; i /= 10) {
int tDigit = (aNumber / i) % 10;
if (temp && tDigit != 0) temp = false;
if (!temp) {
tStringB.append(tDigit);
if (i != 1) for (int j = i; j > 0; j /= 1000) if (j == 1) tStringB.append(",");
}
}
String tString = tStringB.toString();
if (tString.equals(E)) tString = "0";
return negative ? "-" + tString : tString;
}
public static NBTTagCompound getNBTContainingBoolean(NBTTagCompound aNBT, Object aTag, boolean aValue) {
if (aNBT == null) aNBT = new NBTTagCompound();
aNBT.setBoolean(aTag.toString(), aValue);
return aNBT;
}
public static NBTTagCompound getNBTContainingByte(NBTTagCompound aNBT, Object aTag, byte aValue) {
if (aNBT == null) aNBT = new NBTTagCompound();
aNBT.setByte(aTag.toString(), aValue);
return aNBT;
}
public static NBTTagCompound getNBTContainingShort(NBTTagCompound aNBT, Object aTag, short aValue) {
if (aNBT == null) aNBT = new NBTTagCompound();
aNBT.setShort(aTag.toString(), aValue);
return aNBT;
}
public static NBTTagCompound getNBTContainingInteger(NBTTagCompound aNBT, Object aTag, int aValue) {
if (aNBT == null) aNBT = new NBTTagCompound();
aNBT.setInteger(aTag.toString(), aValue);
return aNBT;
}
public static NBTTagCompound getNBTContainingFloat(NBTTagCompound aNBT, Object aTag, float aValue) {
if (aNBT == null) aNBT = new NBTTagCompound();
aNBT.setFloat(aTag.toString(), aValue);
return aNBT;
}
public static NBTTagCompound getNBTContainingDouble(NBTTagCompound aNBT, Object aTag, double aValue) {
if (aNBT == null) aNBT = new NBTTagCompound();
aNBT.setDouble(aTag.toString(), aValue);
return aNBT;
}
public static NBTTagCompound getNBTContainingString(NBTTagCompound aNBT, Object aTag, Object aValue) {
if (aNBT == null) aNBT = new NBTTagCompound();
if (aValue == null) return aNBT;
aNBT.setString(aTag.toString(), aValue.toString());
return aNBT;
}
public static boolean isWearingFullFrostHazmat(EntityLivingBase aEntity) {
for (byte i = 1; i < 5; i++) {
ItemStack tStack = aEntity.getEquipmentInSlot(i);
if (!isStackInList(tStack, GregTechAPI.sFrostHazmatList) && !hasHazmatEnchant(tStack)) {
return false;
}
}
return true;
}
public static boolean isWearingFullHeatHazmat(EntityLivingBase aEntity) {
for (byte i = 1; i < 5; i++) {
ItemStack tStack = aEntity.getEquipmentInSlot(i);
if (!isStackInList(tStack, GregTechAPI.sHeatHazmatList) && !hasHazmatEnchant(tStack)) {
return false;
}
}
return true;
}
public static boolean isWearingFullBioHazmat(EntityLivingBase aEntity) {
for (byte i = 1; i < 5; i++) {
ItemStack tStack = aEntity.getEquipmentInSlot(i);
if (!isStackInList(tStack, GregTechAPI.sBioHazmatList) && !hasHazmatEnchant(tStack)) {
return false;
}
}
return true;
}
public static boolean isWearingFullRadioHazmat(EntityLivingBase aEntity) {
for (byte i = 1; i < 5; i++) {
ItemStack tStack = aEntity.getEquipmentInSlot(i);
if (!isStackInList(tStack, GregTechAPI.sRadioHazmatList) && !hasHazmatEnchant(tStack)) {
return false;
}
}
return true;
}
public static boolean isWearingFullElectroHazmat(EntityLivingBase aEntity) {
for (byte i = 1; i < 5; i++) {
ItemStack tStack = aEntity.getEquipmentInSlot(i);
if (!isStackInList(tStack, GregTechAPI.sElectroHazmatList) && !hasHazmatEnchant(tStack)) {
return false;
}
}
return true;
}
public static boolean isWearingFullGasHazmat(EntityLivingBase aEntity) {
for (byte i = 1; i < 5; i++) {
ItemStack tStack = aEntity.getEquipmentInSlot(i);
if (!isStackInList(tStack, GregTechAPI.sGasHazmatList) && !hasHazmatEnchant(tStack)) {
return false;
}
}
return true;
}
public static boolean hasHazmatEnchant(ItemStack aStack) {
if (aStack == null) return false;
Map tEnchantments = EnchantmentHelper.getEnchantments(aStack);
Integer tLevel = tEnchantments.get(EnchantmentHazmat.INSTANCE.effectId);
return tLevel != null && tLevel >= 1;
}
public static float getHeatDamageFromItem(ItemStack aStack) {
ItemData tData = GTOreDictUnificator.getItemData(aStack);
return tData == null ? 0
: (tData.mPrefix == null ? 0 : tData.mPrefix.mHeatDamage)
+ (tData.hasValidMaterialData() ? tData.mMaterial.mMaterial.mHeatDamage : 0);
}
public static int getRadioactivityLevel(ItemStack aStack) {
ItemData tData = GTOreDictUnificator.getItemData(aStack);
if (tData != null && tData.hasValidMaterialData()) {
if (tData.mMaterial.mMaterial.mEnchantmentArmors instanceof EnchantmentRadioactivity)
return tData.mMaterial.mMaterial.mEnchantmentArmorsLevel;
if (tData.mMaterial.mMaterial.mEnchantmentTools instanceof EnchantmentRadioactivity)
return tData.mMaterial.mMaterial.mEnchantmentToolsLevel;
}
return EnchantmentHelper.getEnchantmentLevel(EnchantmentRadioactivity.INSTANCE.effectId, aStack);
}
public static boolean isImmuneToBreathingGasses(EntityLivingBase aEntity) {
return isWearingFullGasHazmat(aEntity);
}
public static boolean applyHeatDamage(EntityLivingBase entity, float damage) {
return applyHeatDamage(entity, damage, GTDamageSources.getHeatDamage());
}
public static boolean applyHeatDamageFromItem(EntityLivingBase entity, float damage, ItemStack item) {
return applyHeatDamage(entity, damage, new DamageSourceHotItem(item));
}
private static boolean applyHeatDamage(EntityLivingBase aEntity, float aDamage, DamageSource source) {
if (aDamage > 0 && aEntity != null && !isWearingFullHeatHazmat(aEntity)) {
return aEntity.attackEntityFrom(source, aDamage);
}
return false;
}
public static boolean applyFrostDamage(EntityLivingBase aEntity, float aDamage) {
if (aDamage > 0 && aEntity != null && !isWearingFullFrostHazmat(aEntity)) {
return aEntity.attackEntityFrom(GTDamageSources.getFrostDamage(), aDamage);
}
return false;
}
public static boolean applyElectricityDamage(EntityLivingBase aEntity, long aVoltage, long aAmperage) {
long aDamage = getTier(aVoltage) * aAmperage * 4;
if (aDamage > 0 && aEntity != null && !isWearingFullElectroHazmat(aEntity)) {
return aEntity.attackEntityFrom(GTDamageSources.getElectricDamage(), aDamage);
}
return false;
}
public static boolean applyRadioactivity(EntityLivingBase aEntity, int aLevel, int aAmountOfItems) {
if (aLevel > 0 && aEntity != null
&& aEntity.getCreatureAttribute() != EnumCreatureAttribute.UNDEAD
&& aEntity.getCreatureAttribute() != EnumCreatureAttribute.ARTHROPOD
&& !isWearingFullRadioHazmat(aEntity)) {
PotionEffect tEffect = null;
aEntity.addPotionEffect(
new PotionEffect(
Potion.moveSlowdown.id,
aLevel * 140 * aAmountOfItems + Math.max(
0,
((tEffect = aEntity.getActivePotionEffect(Potion.moveSlowdown)) == null ? 0
: tEffect.getDuration())),
Math.max(0, (5 * aLevel) / 7)));
aEntity.addPotionEffect(
new PotionEffect(
Potion.digSlowdown.id,
aLevel * 150 * aAmountOfItems + Math.max(
0,
((tEffect = aEntity.getActivePotionEffect(Potion.digSlowdown)) == null ? 0
: tEffect.getDuration())),
Math.max(0, (5 * aLevel) / 7)));
aEntity.addPotionEffect(
new PotionEffect(
Potion.confusion.id,
aLevel * 130 * aAmountOfItems + Math.max(
0,
((tEffect = aEntity.getActivePotionEffect(Potion.confusion)) == null ? 0
: tEffect.getDuration())),
Math.max(0, (5 * aLevel) / 7)));
aEntity.addPotionEffect(
new PotionEffect(
Potion.weakness.id,
aLevel * 150 * aAmountOfItems + Math.max(
0,
((tEffect = aEntity.getActivePotionEffect(Potion.weakness)) == null ? 0
: tEffect.getDuration())),
Math.max(0, (5 * aLevel) / 7)));
aEntity.addPotionEffect(
new PotionEffect(
Potion.hunger.id,
aLevel * 130 * aAmountOfItems + Math.max(
0,
((tEffect = aEntity.getActivePotionEffect(Potion.hunger)) == null ? 0 : tEffect.getDuration())),
Math.max(0, (5 * aLevel) / 7)));
aEntity.addPotionEffect(
new PotionEffect(
24 /* IC2 Radiation */,
aLevel * 180 * aAmountOfItems + Math.max(
0,
((tEffect = aEntity.getActivePotionEffect(Potion.potionTypes[24])) == null ? 0
: tEffect.getDuration())),
Math.max(0, (5 * aLevel) / 7)));
return true;
}
return false;
}
public static ItemStack setStack(ItemStack aSetStack, ItemStack aToStack) {
if (isStackInvalid(aSetStack) || isStackInvalid(aToStack)) return null;
aSetStack.func_150996_a(aToStack.getItem());
aSetStack.stackSize = aToStack.stackSize;
Items.feather.setDamage(aSetStack, Items.feather.getDamage(aToStack));
aSetStack.setTagCompound(aToStack.getTagCompound());
return aSetStack;
}
public static FluidStack[] copyFluidArray(FluidStack... aStacks) {
if (aStacks == null) return null;
FluidStack[] rStacks = new FluidStack[aStacks.length];
for (int i = 0; i < aStacks.length; i++) if (aStacks[i] != null) rStacks[i] = aStacks[i].copy();
return rStacks;
}
public static ItemStack[] copyItemArray(ItemStack... aStacks) {
if (aStacks == null) return null;
ItemStack[] rStacks = new ItemStack[aStacks.length];
for (int i = 0; i < aStacks.length; i++) rStacks[i] = copy(aStacks[i]);
return rStacks;
}
/**
* @deprecated use {@link #copy(ItemStack)} instead
*/
@Deprecated
public static ItemStack copy(Object... aStacks) {
for (Object tStack : aStacks) if (isStackValid(tStack)) return ((ItemStack) tStack).copy();
return null;
}
public static ItemStack copy(ItemStack aStack) {
if (isStackValid(aStack)) return aStack.copy();
return null;
}
@Deprecated
private static ItemStack firstStackOrNull(Object... aStacks) {
for (Object tStack : aStacks) if (tStack instanceof ItemStack stack) return stack;
return null;
}
@Nullable
public static ItemStack copyOrNull(@Nullable ItemStack stack) {
if (isStackValid(stack)) return stack.copy();
return null;
}
public static FluidStack copyAmount(int aAmount, FluidStack aStack) {
if (aStack == null) return null;
FluidStack rStack = aStack.copy();
rStack.amount = aAmount;
return rStack;
}
/**
* @deprecated use {@link #copyAmount(int, ItemStack)} instead
*/
@Deprecated
public static ItemStack copyAmount(long aAmount, Object... aStacks) {
return copyAmount(aAmount, firstStackOrNull(aStacks));
}
/**
* @deprecated use {@link #copyAmount(int, ItemStack)} instead
*/
@Deprecated
public static ItemStack copyAmount(long aAmount, ItemStack aStack) {
return copyAmount((int) aAmount, aStack);
}
public static ItemStack copyAmount(int aAmount, ItemStack aStack) {
ItemStack rStack = copy(aStack);
if (isStackInvalid(rStack)) return null;
if (aAmount > 64) aAmount = 64;
else if (aAmount == -1) aAmount = 111;
else if (aAmount < 0) aAmount = 0;
rStack.stackSize = (byte) aAmount;
return rStack;
}
public static ItemStack multiplyStack(int aMultiplier, ItemStack aStack) {
ItemStack rStack = copy(aStack);
if (isStackInvalid(rStack)) return null;
int tAmount = rStack.stackSize * aMultiplier;
if (tAmount > 64) tAmount = 64;
else if (tAmount == -1) tAmount = 111;
else if (tAmount < 0) tAmount = 0;
rStack.stackSize = (byte) tAmount;
return rStack;
}
/**
* Unlike {@link #copyAmount(int, ItemStack)}, this method does not restrict stack size by 64.
*/
public static ItemStack copyAmountUnsafe(int aAmount, ItemStack aStack) {
ItemStack rStack = copy(aStack);
if (isStackInvalid(rStack)) return null;
else if (aAmount < 0) aAmount = 0;
rStack.stackSize = aAmount;
return rStack;
}
public static ItemStack copyMetaData(int aMetaData, ItemStack aStack) {
ItemStack rStack = copy(aStack);
if (isStackInvalid(rStack)) return null;
Items.feather.setDamage(rStack, aMetaData);
return rStack;
}
/**
* @deprecated use {@link #copyAmountAndMetaData(int, int, ItemStack)} instead
*/
@Deprecated
public static ItemStack copyAmountAndMetaData(long aAmount, long aMetaData, ItemStack aStack) {
return copyAmountAndMetaData((int) aAmount, (int) aMetaData, aStack);
}
public static ItemStack copyAmountAndMetaData(int aAmount, int aMetaData, ItemStack aStack) {
ItemStack rStack = copyAmount(aAmount, aStack);
if (isStackInvalid(rStack)) return null;
Items.feather.setDamage(rStack, aMetaData);
return rStack;
}
/**
* returns a copy of an ItemStack with its Stacksize being multiplied by aMultiplier
*/
public static ItemStack mul(int aMultiplier, ItemStack aStack) {
ItemStack rStack = copy(aStack);
if (rStack == null) return null;
rStack.stackSize *= aMultiplier;
return rStack;
}
/**
* Loads an ItemStack properly.
*/
public static ItemStack loadItem(NBTTagCompound aNBT, String aTagName) {
return loadItem(aNBT.getCompoundTag(aTagName));
}
public static FluidStack loadFluid(NBTTagCompound aNBT, String aTagName) {
return loadFluid(aNBT.getCompoundTag(aTagName));
}
/**
* Loads an ItemStack properly.
*/
public static ItemStack loadItem(NBTTagCompound aNBT) {
if (aNBT == null) return null;
ItemStack tRawStack = ItemStack.loadItemStackFromNBT(aNBT);
int tRealStackSize = 0;
if (tRawStack != null && aNBT.hasKey("Count", Constants.NBT.TAG_INT)) {
tRealStackSize = aNBT.getInteger("Count");
tRawStack.stackSize = tRealStackSize;
} else if (tRawStack != null) {
tRealStackSize = tRawStack.stackSize;
}
ItemStack tRet = GTOreDictUnificator.get(true, tRawStack);
if (tRet != null) tRet.stackSize = tRealStackSize;
return tRet;
}
public static void saveItem(NBTTagCompound aParentTag, String aTagName, ItemStack aStack) {
if (aStack != null) aParentTag.setTag(aTagName, saveItem(aStack));
}
public static NBTTagCompound saveItem(ItemStack aStack) {
if (aStack == null) return new NBTTagCompound();
NBTTagCompound t = new NBTTagCompound();
aStack.writeToNBT(t);
if (aStack.stackSize > Byte.MAX_VALUE) t.setInteger("Count", aStack.stackSize);
return t;
}
/**
* Loads an FluidStack properly.
*/
public static FluidStack loadFluid(NBTTagCompound aNBT) {
if (aNBT == null) return null;
return FluidStack.loadFluidStackFromNBT(aNBT);
}
public static E selectItemInList(int aIndex, E aReplacement, List aList) {
if (aList == null || aList.isEmpty()) return aReplacement;
if (aList.size() <= aIndex) return aList.get(aList.size() - 1);
if (aIndex < 0) return aList.get(0);
return aList.get(aIndex);
}
@SafeVarargs
public static E selectItemInList(int aIndex, E aReplacement, E... aList) {
if (aList == null || aList.length == 0) return aReplacement;
if (aList.length <= aIndex) return aList[aList.length - 1];
if (aIndex < 0) return aList[0];
return aList[aIndex];
}
public static boolean isStackInStackSet(ItemStack aStack, Set aSet) {
if (aStack == null) return false;
if (aSet.contains(aStack)) return true;
return aSet.contains(GTItemStack.internalCopyStack(aStack, true));
}
public static boolean isStackInList(ItemStack aStack, Collection aList) {
if (aStack == null) {
return false;
}
return isStackInList(new GTItemStack(aStack), aList);
}
public static boolean isStackInList(ItemStack aStack, Set aList) {
if (aStack == null) {
return false;
}
return isStackInList(new GTItemStack2(aStack), aList);
}
public static boolean isStackInList(GTItemStack aStack, Collection aList) {
return aStack != null
&& (aList.contains(aStack) || aList.contains(new GTItemStack(aStack.mItem, aStack.mStackSize, W)));
}
public static boolean isStackInList(GTItemStack2 aStack, Set aList) {
return aStack != null
&& (aList.contains(aStack) || aList.contains(new GTItemStack2(aStack.mItem, aStack.mStackSize, W)));
}
/**
* re-maps all Keys of a Map after the Keys were weakened.
*/
public static Map reMap(Map aMap) {
Map tMap = null;
// We try to clone the Map first (most Maps are Cloneable) in order to retain as much state of the Map as
// possible when rehashing. For example, "Custom" HashMaps from fastutil may have a custom hash function which
// would not be used to rehash if we just create a new HashMap.
if (aMap instanceof Cloneable) {
try {
tMap = (Map) aMap.getClass()
.getMethod("clone")
.invoke(aMap);
} catch (Throwable e) {
GTLog.err.println("Failed to clone Map of type " + aMap.getClass());
e.printStackTrace(GTLog.err);
}
}
if (tMap == null) {
tMap = new HashMap<>(aMap);
}
aMap.clear();
aMap.putAll(tMap);
return aMap;
}
/**
* re-maps all Keys of a Map after the Keys were weakened.
*/
public static SetMultimap reMap(SetMultimap aMap) {
@SuppressWarnings("unchecked")
Map.Entry[] entries = aMap.entries()
.toArray(new Map.Entry[0]);
aMap.clear();
for (Map.Entry entry : entries) {
aMap.put(entry.getKey(), entry.getValue());
}
return aMap;
}
public static > LinkedHashMap sortMapByValuesAcending(Map map) {
return map.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue())
.collect(CollectorUtils.entriesToMap(LinkedHashMap::new));
}
/**
* Why the fuck do neither Java nor Guava have a Function to do this?
*/
public static > LinkedHashMap sortMapByValuesDescending(Map aMap) {
List> tEntrySet = new LinkedList<>(aMap.entrySet());
tEntrySet.sort((aValue1, aValue2) -> {
return aValue2.getValue()
.compareTo(aValue1.getValue()); // FB: RV - RV_NEGATING_RESULT_OF_COMPARETO
});
LinkedHashMap rMap = new LinkedHashMap<>();
for (Map.Entry tEntry : tEntrySet) rMap.put(tEntry.getKey(), tEntry.getValue());
return rMap;
}
/**
* Translates a Material Amount into an Amount of Fluid in Fluid Material Units.
*/
public static long translateMaterialToFluidAmount(long aMaterialAmount, boolean aRoundUp) {
return translateMaterialToAmount(aMaterialAmount, L, aRoundUp);
}
/**
* Translates a Material Amount into an Amount of Fluid. Second Parameter for things like Bucket Amounts (1000) and
* similar
*/
public static long translateMaterialToAmount(long aMaterialAmount, long aAmountPerUnit, boolean aRoundUp) {
return Math.max(
0,
((aMaterialAmount * aAmountPerUnit) / M)
+ (aRoundUp && (aMaterialAmount * aAmountPerUnit) % M > 0 ? 1 : 0));
}
/**
* This checks if the Dimension is really a Dimension and not another Planet or something. Used for my Teleporter.
*/
public static boolean isRealDimension(int aDimensionID) {
if (aDimensionID <= 1 && aDimensionID >= -1 && !GregTechAPI.sDimensionalList.contains(aDimensionID))
return true;
return !GregTechAPI.sDimensionalList.contains(aDimensionID)
&& DimensionManager.isDimensionRegistered(aDimensionID);
}
public static boolean moveEntityToDimensionAtCoords(Entity entity, int aDimension, double aX, double aY,
double aZ) {
// Credit goes to BrandonCore Author :!:
if (entity == null || entity.worldObj.isRemote) return false;
if (entity.ridingEntity != null) entity.mountEntity(null);
if (entity.riddenByEntity != null) entity.riddenByEntity.mountEntity(null);
World startWorld = entity.worldObj;
WorldServer destinationWorld = FMLCommonHandler.instance()
.getMinecraftServerInstance()
.worldServerForDimension(aDimension);
if (destinationWorld == null) {
return false;
}
boolean interDimensional = startWorld.provider.dimensionId != destinationWorld.provider.dimensionId;
if (!interDimensional) return false;
startWorld.updateEntityWithOptionalForce(entity, false); // added
if (entity instanceof EntityPlayerMP player) {
player.closeScreen(); // added
player.dimension = aDimension;
player.playerNetServerHandler.sendPacket(
new S07PacketRespawn(
player.dimension,
player.worldObj.difficultySetting,
destinationWorld.getWorldInfo()
.getTerrainType(),
player.theItemInWorldManager.getGameType()));
((WorldServer) startWorld).getPlayerManager()
.removePlayer(player);
startWorld.playerEntities.remove(player);
startWorld.updateAllPlayersSleepingFlag();
int i = entity.chunkCoordX;
int j = entity.chunkCoordZ;
if ((entity.addedToChunk) && (startWorld.getChunkProvider()
.chunkExists(i, j))) {
startWorld.getChunkFromChunkCoords(i, j)
.removeEntity(entity);
startWorld.getChunkFromChunkCoords(i, j).isModified = true;
}
startWorld.loadedEntityList.remove(entity);
startWorld.onEntityRemoved(entity);
}
entity.setLocationAndAngles(aX, aY, aZ, entity.rotationYaw, entity.rotationPitch);
destinationWorld.theChunkProviderServer.loadChunk((int) aX >> 4, (int) aZ >> 4);
destinationWorld.theProfiler.startSection("placing");
if (!(entity instanceof EntityPlayer)) {
NBTTagCompound entityNBT = new NBTTagCompound();
entity.isDead = false;
entityNBT.setString("id", EntityList.getEntityString(entity));
entity.writeToNBT(entityNBT);
entity.isDead = true;
entity = EntityList.createEntityFromNBT(entityNBT, destinationWorld);
if (entity == null) {
return false;
}
entity.dimension = destinationWorld.provider.dimensionId;
}
destinationWorld.spawnEntityInWorld(entity);
entity.setWorld(destinationWorld);
entity.setLocationAndAngles(aX, aY, aZ, entity.rotationYaw, entity.rotationPitch);
destinationWorld.updateEntityWithOptionalForce(entity, false);
entity.setLocationAndAngles(aX, aY, aZ, entity.rotationYaw, entity.rotationPitch);
if ((entity instanceof EntityPlayerMP player)) {
player.mcServer.getConfigurationManager()
.func_72375_a(player, destinationWorld);
player.playerNetServerHandler.setPlayerLocation(aX, aY, aZ, player.rotationYaw, player.rotationPitch);
}
destinationWorld.updateEntityWithOptionalForce(entity, false);
if (entity instanceof EntityPlayerMP player) {
player.theItemInWorldManager.setWorld(destinationWorld);
player.mcServer.getConfigurationManager()
.updateTimeAndWeatherForPlayer(player, destinationWorld);
player.mcServer.getConfigurationManager()
.syncPlayerInventory(player);
for (PotionEffect potionEffect : player.getActivePotionEffects()) {
player.playerNetServerHandler.sendPacket(new S1DPacketEntityEffect(player.getEntityId(), potionEffect));
}
player.playerNetServerHandler.sendPacket(
new S1FPacketSetExperience(player.experience, player.experienceTotal, player.experienceLevel));
FMLCommonHandler.instance()
.firePlayerChangedDimensionEvent(
player,
startWorld.provider.dimensionId,
destinationWorld.provider.dimensionId);
}
entity.setLocationAndAngles(aX, aY, aZ, entity.rotationYaw, entity.rotationPitch);
destinationWorld.theProfiler.endSection();
entity.fallDistance = 0;
return true;
}
public static int getScaleCoordinates(double aValue, int aScale) {
return (int) Math.floor(aValue / aScale);
}
public static int getCoordinateScan(ArrayList aList, EntityPlayer aPlayer, World aWorld, int aScanLevel,
int aX, int aY, int aZ, ForgeDirection side, float aClickX, float aClickY, float aClickZ) {
if (aList == null) return 0;
ArrayList tList = new ArrayList<>();
int rEUAmount = 0;
TileEntity tTileEntity = aWorld.getTileEntity(aX, aY, aZ);
final Block tBlock = aWorld.getBlock(aX, aY, aZ);
addBaseInfo(aPlayer, aWorld, aX, aY, aZ, tList, tTileEntity, tBlock);
if (tTileEntity != null) {
rEUAmount += addFluidHandlerInfo(side, tList, tTileEntity);
try {
if (tTileEntity instanceof ic2.api.reactor.IReactorChamber chamber) {
rEUAmount += 500;
// Redirect the rest of the scans to the reactor itself
tTileEntity = (TileEntity) chamber.getReactor();
}
} catch (Throwable e) {
if (D1) e.printStackTrace(GTLog.err);
}
rEUAmount += addReactorInfo(tList, tTileEntity);
rEUAmount += addAlignmentInfo(tList, tTileEntity);
rEUAmount += addIC2WrenchableInfo(aPlayer, tList, tTileEntity);
rEUAmount += addIC2EnergyConductorInfo(tList, tTileEntity);
rEUAmount += addIC2EnergyStorageInfo(tList, tTileEntity);
rEUAmount += addUpgradableMachineInfo(tList, tTileEntity);
rEUAmount += addMachineProgressInfo(tList, tTileEntity);
rEUAmount += addCoverableInfo(side, tList, tTileEntity);
addEnergyContainerInfo(tList, tTileEntity);
addOwnerInfo(tList, tTileEntity);
addDeviceInfo(tList, tTileEntity);
rEUAmount += addIC2CropInfo(tList, tTileEntity);
rEUAmount += addForestryLeavesInfo(tList, tTileEntity);
}
final Chunk currentChunk = aWorld.getChunkFromBlockCoords(aX, aZ);
addUndergroundFluidInfo(aPlayer, tList, currentChunk);
addPollutionInfo(tList, currentChunk);
rEUAmount += addDebuggableBlockInfo(aPlayer, aX, aY, aZ, tList, tBlock);
final BlockScanningEvent tEvent = new BlockScanningEvent(
aWorld,
aPlayer,
aX,
aY,
aZ,
side,
aScanLevel,
tBlock,
tTileEntity,
tList,
aClickX,
aClickY,
aClickZ);
tEvent.mEUCost = rEUAmount;
MinecraftForge.EVENT_BUS.post(tEvent);
if (!tEvent.isCanceled()) aList.addAll(tList);
return tEvent.mEUCost;
}
private static void addBaseInfo(EntityPlayer aPlayer, World aWorld, int aX, int aY, int aZ, ArrayList tList,
TileEntity tTileEntity, Block tBlock) {
tList.add(
EnumChatFormatting.STRIKETHROUGH + "-----"
+ EnumChatFormatting.RESET
+ " X: "
+ EnumChatFormatting.AQUA
+ formatNumbers(aX)
+ EnumChatFormatting.RESET
+ " Y: "
+ EnumChatFormatting.AQUA
+ formatNumbers(aY)
+ EnumChatFormatting.RESET
+ " Z: "
+ EnumChatFormatting.AQUA
+ formatNumbers(aZ)
+ EnumChatFormatting.RESET
+ " D: "
+ EnumChatFormatting.AQUA
+ aWorld.provider.dimensionId
+ EnumChatFormatting.RESET
+ " "
+ EnumChatFormatting.STRIKETHROUGH
+ "-----");
try {
tList.add(
GTUtility.trans("162", "Name: ") + EnumChatFormatting.BLUE
+ ((tTileEntity instanceof IInventory inv) ? inv.getInventoryName() : tBlock.getUnlocalizedName())
+ EnumChatFormatting.RESET
+ GTUtility.trans("163", " MetaData: ")
+ EnumChatFormatting.AQUA
+ aWorld.getBlockMetadata(aX, aY, aZ)
+ EnumChatFormatting.RESET);
tList.add(
GTUtility.trans("164", "Hardness: ") + EnumChatFormatting.YELLOW
+ tBlock.getBlockHardness(aWorld, aX, aY, aZ)
+ EnumChatFormatting.RESET
+ GTUtility.trans("165", " Blast Resistance: ")
+ EnumChatFormatting.YELLOW
+ tBlock
.getExplosionResistance(aPlayer, aWorld, aX, aY, aZ, aPlayer.posX, aPlayer.posY, aPlayer.posZ)
+ EnumChatFormatting.RESET);
if (tBlock.isBeaconBase(aWorld, aX, aY, aZ, aX, aY + 1, aZ)) tList.add(
EnumChatFormatting.GOLD + GTUtility.trans("166", "Is valid Beacon Pyramid Material")
+ EnumChatFormatting.RESET);
} catch (Throwable e) {
tList.add("§cAn exception was thrown while fetching this block's info.§r");
if (D1) e.printStackTrace(GTLog.err);
}
}
private static int addFluidHandlerInfo(ForgeDirection side, ArrayList tList, TileEntity tTileEntity) {
int rEUAmount = 0;
try {
if (tTileEntity instanceof IFluidHandler fluidHandler) {
rEUAmount += 500;
final FluidTankInfo[] tTanks = fluidHandler.getTankInfo(side);
if (tTanks != null) for (byte i = 0; i < tTanks.length; i++) {
tList.add(
GTUtility.trans("167", "Tank ") + i
+ ": "
+ EnumChatFormatting.GREEN
+ formatNumbers((tTanks[i].fluid == null ? 0 : tTanks[i].fluid.amount))
+ EnumChatFormatting.RESET
+ " L / "
+ EnumChatFormatting.YELLOW
+ formatNumbers(tTanks[i].capacity)
+ EnumChatFormatting.RESET
+ " L "
+ EnumChatFormatting.GOLD
+ getFluidName(tTanks[i].fluid, true)
+ EnumChatFormatting.RESET);
}
}
} catch (Throwable e) {
tList.add("§cAn exception was thrown while fetching this tile's fluid tank info.§r");
if (D1) e.printStackTrace(GTLog.err);
}
return rEUAmount;
}
private static int addDebuggableBlockInfo(EntityPlayer aPlayer, int aX, int aY, int aZ, ArrayList tList,
Block tBlock) {
int rEUAmount = 0;
try {
if (tBlock instanceof IDebugableBlock debugableBlock) {
rEUAmount += 500;
final ArrayList temp = debugableBlock.getDebugInfo(aPlayer, aX, aY, aZ, 3);
if (temp != null) tList.addAll(temp);
}
} catch (Throwable e) {
tList.add("§cAn exception was thrown while fetching this block's debug info.§r");
if (D1) e.printStackTrace(GTLog.err);
}
return rEUAmount;
}
private static void addPollutionInfo(ArrayList tList, Chunk currentChunk) {
if (Pollution.hasPollution(currentChunk)) {
tList.add(
GTUtility.trans("202", "Pollution in Chunk: ") + EnumChatFormatting.RED
+ formatNumbers(Pollution.getPollution(currentChunk))
+ EnumChatFormatting.RESET
+ GTUtility.trans("203", " gibbl"));
} else {
tList.add(
EnumChatFormatting.GREEN + GTUtility.trans("204", "No Pollution in Chunk! HAYO!")
+ EnumChatFormatting.RESET);
}
}
private static void addUndergroundFluidInfo(EntityPlayer aPlayer, ArrayList tList, Chunk currentChunk) {
if (aPlayer.capabilities.isCreativeMode) {
final FluidStack tFluid = undergroundOilReadInformation(currentChunk); // -# to only read
if (tFluid != null) tList.add(
EnumChatFormatting.GOLD + tFluid.getLocalizedName()
+ EnumChatFormatting.RESET
+ ": "
+ EnumChatFormatting.YELLOW
+ formatNumbers(tFluid.amount)
+ EnumChatFormatting.RESET
+ " L");
else tList.add(
EnumChatFormatting.GOLD + GTUtility.trans("201", "Nothing")
+ EnumChatFormatting.RESET
+ ": "
+ EnumChatFormatting.YELLOW
+ '0'
+ EnumChatFormatting.RESET
+ " L");
}
}
private static int addForestryLeavesInfo(ArrayList tList, TileEntity tTileEntity) {
int rEUAmount = 0;
try {
if (Mods.Forestry.isModLoaded()
&& tTileEntity instanceof forestry.arboriculture.tiles.TileLeaves tileLeaves) {
final forestry.api.arboriculture.ITree tree = tileLeaves.getTree();
if (tree != null) {
rEUAmount += 1000;
if (!tree.isAnalyzed()) tree.analyze();
tree.addTooltip(tList);
}
}
} catch (Throwable e) {
tList.add("§cAn exception was thrown while fetching this leaves' info.§r");
if (D1) e.printStackTrace(GTLog.err);
}
return rEUAmount;
}
private static int addIC2CropInfo(ArrayList tList, TileEntity tTileEntity) {
int rEUAmount = 0;
try {
if (tTileEntity instanceof ic2.api.crops.ICropTile crop) {
rEUAmount += 1000;
if (crop.getScanLevel() < 4) crop.setScanLevel((byte) 4);
if (crop.getCrop() != null) {
tList.add(
GTUtility.trans("187", "Type -- Crop-Name: ") + crop.getCrop()
.name()
+ GTUtility.trans("188", " Growth: ")
+ crop.getGrowth()
+ GTUtility.trans("189", " Gain: ")
+ crop.getGain()
+ GTUtility.trans("190", " Resistance: ")
+ crop.getResistance());
}
tList.add(
GTUtility.trans("191", "Plant -- Fertilizer: ") + crop.getNutrientStorage()
+ GTUtility.trans("192", " Water: ")
+ crop.getHydrationStorage()
+ GTUtility.trans("193", " Weed-Ex: ")
+ crop.getWeedExStorage()
+ GTUtility.trans("194", " Scan-Level: ")
+ crop.getScanLevel());
tList.add(
GTUtility.trans("195", "Environment -- Nutrients: ") + crop.getNutrients()
+ GTUtility.trans("196", " Humidity: ")
+ crop.getHumidity()
+ GTUtility.trans("197", " Air-Quality: ")
+ crop.getAirQuality());
if (crop.getCrop() != null) {
final StringBuilder tStringB = new StringBuilder();
for (final String tAttribute : crop.getCrop()
.attributes()) {
tStringB.append(", ")
.append(tAttribute);
}
final String tString = tStringB.toString();
tList.add(GTUtility.trans("198", "Attributes:") + tString.replaceFirst(",", E));
tList.add(
GTUtility.trans("199", "Discovered by: ") + crop.getCrop()
.discoveredBy());
}
}
} catch (Throwable e) {
tList.add("§cAn exception was thrown while fetching this crop's info.§r");
if (D1) e.printStackTrace(GTLog.err);
}
return rEUAmount;
}
private static void addDeviceInfo(ArrayList tList, TileEntity tTileEntity) {
try {
if (tTileEntity instanceof IGregTechDeviceInformation info && info.isGivingInformation()) {
tList.addAll(Arrays.asList(info.getInfoData()));
}
} catch (Throwable e) {
tList.add("§cAn exception was thrown while fetching this device's info.§r");
if (D1) e.printStackTrace(GTLog.err);
}
}
private static void addOwnerInfo(ArrayList tList, TileEntity tTileEntity) {
try {
if (tTileEntity instanceof IGregTechTileEntity gtTE) {
tList.add(
GTUtility.trans("186", "Owned by: ") + EnumChatFormatting.BLUE
+ gtTE.getOwnerName()
+ EnumChatFormatting.RESET);
}
} catch (Throwable e) {
tList.add("§cAn exception was thrown while fetching this device's owner.§r");
if (D1) e.printStackTrace(GTLog.err);
}
}
private static void addEnergyContainerInfo(ArrayList tList, TileEntity tTileEntity) {
try {
if (tTileEntity instanceof IBasicEnergyContainer energyContainer && energyContainer.getEUCapacity() > 0) {
tList.add(
GTUtility.trans("179", "Max IN: ") + EnumChatFormatting.RED
+ formatNumbers(energyContainer.getInputVoltage())
+ " ("
+ GTValues.VN[getTier(energyContainer.getInputVoltage())]
+ ") "
+ EnumChatFormatting.RESET
+ GTUtility.trans("182", " EU at ")
+ EnumChatFormatting.RED
+ formatNumbers(energyContainer.getInputAmperage())
+ EnumChatFormatting.RESET
+ GTUtility.trans("183", " A"));
tList.add(
GTUtility.trans("181", "Max OUT: ") + EnumChatFormatting.RED
+ formatNumbers(energyContainer.getOutputVoltage())
+ " ("
+ GTValues.VN[getTier(energyContainer.getOutputVoltage())]
+ ") "
+ EnumChatFormatting.RESET
+ GTUtility.trans("182", " EU at ")
+ EnumChatFormatting.RED
+ formatNumbers(energyContainer.getOutputAmperage())
+ EnumChatFormatting.RESET
+ GTUtility.trans("183", " A"));
tList.add(
GTUtility.trans("184", "Energy: ") + EnumChatFormatting.GREEN
+ formatNumbers(energyContainer.getStoredEU())
+ EnumChatFormatting.RESET
+ " EU / "
+ EnumChatFormatting.YELLOW
+ formatNumbers(energyContainer.getEUCapacity())
+ EnumChatFormatting.RESET
+ " EU");
}
} catch (Throwable e) {
tList.add("§cAn exception was thrown while fetching this device's energy info.§r");
if (D1) e.printStackTrace(GTLog.err);
}
}
private static int addCoverableInfo(ForgeDirection side, ArrayList tList, TileEntity tTileEntity) {
int rEUAmount = 0;
try {
if (tTileEntity instanceof ICoverable coverable) {
rEUAmount += 300;
final String tString = coverable.getCoverInfoAtSide(side)
.getBehaviorDescription();
if (tString != null && !tString.equals(E)) tList.add(tString);
}
} catch (Throwable e) {
tList.add("§cAn exception was thrown while fetching this device's covers.§r");
if (D1) e.printStackTrace(GTLog.err);
}
return rEUAmount;
}
private static int addMachineProgressInfo(ArrayList tList, TileEntity tTileEntity) {
int rEUAmount = 0;
try {
if (tTileEntity instanceof IMachineProgress progress) {
if (progress.isAllowedToWork() && !progress.hasThingsToDo()) {
tList.add(EnumChatFormatting.RED + "Disabled." + EnumChatFormatting.RESET);
}
if (progress.wasShutdown() && isStringValid(
progress.getLastShutDownReason()
.getDisplayString())) {
tList.add(
progress.getLastShutDownReason()
.getDisplayString());
}
rEUAmount += 400;
int tValue = 0;
if (0 < (tValue = progress.getMaxProgress())) tList.add(
GTUtility.trans("178", "Progress/Load: ") + EnumChatFormatting.GREEN
+ formatNumbers(progress.getProgress())
+ EnumChatFormatting.RESET
+ " / "
+ EnumChatFormatting.YELLOW
+ formatNumbers(tValue)
+ EnumChatFormatting.RESET);
}
} catch (Throwable e) {
tList.add("§cAn exception was thrown while fetching this device's progress.§r");
if (D1) e.printStackTrace(GTLog.err);
}
return rEUAmount;
}
private static int addUpgradableMachineInfo(ArrayList tList, TileEntity tTileEntity) {
int rEUAmount = 0;
try {
if (tTileEntity instanceof IUpgradableMachine upgradableMachine) {
rEUAmount += 500;
if (upgradableMachine.hasMufflerUpgrade()) tList.add(
EnumChatFormatting.GREEN + GTUtility.trans("177", "Has Muffler Upgrade")
+ EnumChatFormatting.RESET);
}
} catch (Throwable e) {
tList.add("§cAn exception was thrown while fetching this device's upgrades.§r");
if (D1) e.printStackTrace(GTLog.err);
}
return rEUAmount;
}
private static int addIC2EnergyStorageInfo(ArrayList tList, TileEntity tTileEntity) {
int rEUAmount = 0;
try {
if (tTileEntity instanceof ic2.api.tile.IEnergyStorage storage) {
rEUAmount += 200;
tList.add(
GTUtility.trans("176", "Contained Energy: ") + EnumChatFormatting.YELLOW
+ formatNumbers(storage.getStored())
+ EnumChatFormatting.RESET
+ " EU / "
+ EnumChatFormatting.YELLOW
+ formatNumbers(storage.getCapacity())
+ EnumChatFormatting.RESET
+ " EU");
}
} catch (Throwable e) {
tList.add("§cAn exception was thrown while fetching this device's IC2 energy info.§r");
if (D1) e.printStackTrace(GTLog.err);
}
return rEUAmount;
}
private static int addIC2EnergyConductorInfo(ArrayList tList, TileEntity tTileEntity) {
int rEUAmount = 0;
try {
if (tTileEntity instanceof ic2.api.energy.tile.IEnergyConductor conductor) {
rEUAmount += 200;
tList.add(
GTUtility.trans("175", "Conduction Loss: ") + EnumChatFormatting.YELLOW
+ conductor.getConductionLoss()
+ EnumChatFormatting.RESET);
}
} catch (Throwable e) {
tList.add("§cAn exception was thrown while fetching this device's EU conduction info.§r");
if (D1) e.printStackTrace(GTLog.err);
}
return rEUAmount;
}
private static int addIC2WrenchableInfo(EntityPlayer aPlayer, ArrayList tList, TileEntity tTileEntity) {
int rEUAmount = 0;
try {
if (tTileEntity instanceof ic2.api.tile.IWrenchable wrenchable) {
rEUAmount += 100;
tList.add(
GTUtility.trans("171", "Facing: ") + EnumChatFormatting.GREEN
+ wrenchable.getFacing()
+ EnumChatFormatting.RESET
+ GTUtility.trans("172", " / Chance: ")
+ EnumChatFormatting.YELLOW
+ (wrenchable.getWrenchDropRate() * 100)
+ EnumChatFormatting.RESET
+ "%");
tList.add(
wrenchable.wrenchCanRemove(aPlayer)
? EnumChatFormatting.GREEN + GTUtility.trans("173", "You can remove this with a Wrench")
+ EnumChatFormatting.RESET
: EnumChatFormatting.RED + GTUtility.trans("174", "You can NOT remove this with a Wrench")
+ EnumChatFormatting.RESET);
}
} catch (Throwable e) {
tList.add("§cAn exception was thrown while fetching this device's IC@ wrenchability.§r");
if (D1) e.printStackTrace(GTLog.err);
}
return rEUAmount;
}
private static int addAlignmentInfo(ArrayList tList, TileEntity tTileEntity) {
int rEUAmount = 0;
try {
if (tTileEntity instanceof IAlignmentProvider alignmentProvider) {
final IAlignment tAlignment = alignmentProvider.getAlignment();
if (tAlignment != null) {
rEUAmount += 100;
tList.add(
GTUtility.trans("219", "Extended Facing: ") + EnumChatFormatting.GREEN
+ tAlignment.getExtendedFacing()
+ EnumChatFormatting.RESET);
}
}
} catch (Throwable e) {
tList.add("§cAn exception was thrown while fetching this device's alignment info.§r");
if (D1) e.printStackTrace(GTLog.err);
}
return rEUAmount;
}
private static int addReactorInfo(ArrayList tList, TileEntity tTileEntity) {
int rEUAmount = 0;
try {
if (tTileEntity instanceof ic2.api.reactor.IReactor reactor) {
rEUAmount += 500;
tList.add(
GTUtility.trans("168", "Heat: ") + EnumChatFormatting.GREEN
+ formatNumbers(reactor.getHeat())
+ EnumChatFormatting.RESET
+ " / "
+ EnumChatFormatting.YELLOW
+ formatNumbers(reactor.getMaxHeat())
+ EnumChatFormatting.RESET);
tList.add(
GTUtility.trans("169", "HEM: ") + EnumChatFormatting.YELLOW
+ reactor.getHeatEffectModifier()
+ EnumChatFormatting.RESET);
}
} catch (Throwable e) {
tList.add("§cAn exception was thrown while fetching this reactor's info.§r");
if (D1) e.printStackTrace(GTLog.err);
}
return rEUAmount;
}
public static String trans(String aKey, String aEnglish) {
return GTLanguageManager.addStringLocalization("Interaction_DESCRIPTION_Index_" + aKey, aEnglish);
}
public static String getTrans(String aKey) {
return GTLanguageManager.getTranslation("Interaction_DESCRIPTION_Index_" + aKey);
}
/**
* @return an Array containing the X and the Y Coordinate of the clicked Point, with the top left Corner as Origin,
* like on the Texture Sheet. return values should always be between [0.0F and 0.99F].
*/
// TODO: use clamp()
public static float[] getClickedFacingCoords(ForgeDirection side, float aX, float aY, float aZ) {
return switch (side) {
case DOWN -> new float[] { Math.min(0.99F, Math.max(0, 1 - aX)), Math.min(0.99F, Math.max(0, aZ)) };
case UP -> new float[] { Math.min(0.99F, Math.max(0, aX)), Math.min(0.99F, Math.max(0, aZ)) };
case NORTH -> new float[] { Math.min(0.99F, Math.max(0, 1 - aX)), Math.min(0.99F, Math.max(0, 1 - aY)) };
case SOUTH -> new float[] { Math.min(0.99F, Math.max(0, aX)), Math.min(0.99F, Math.max(0, 1 - aY)) };
case WEST -> new float[] { Math.min(0.99F, Math.max(0, aZ)), Math.min(0.99F, Math.max(0, 1 - aY)) };
case EAST -> new float[] { Math.min(0.99F, Math.max(0, 1 - aZ)), Math.min(0.99F, Math.max(0, 1 - aY)) };
default -> new float[] { 0.5F, 0.5F };
};
}
/**
* This Function determines the direction a Block gets when being Wrenched. returns -1 if invalid. Even though that
* could never happen.
*/
public static ForgeDirection determineWrenchingSide(ForgeDirection side, float aX, float aY, float aZ) {
ForgeDirection tBack = side.getOpposite();
switch (side) {
case DOWN, UP -> {
if (aX < 0.25) {
if (aZ < 0.25) return tBack;
if (aZ > 0.75) return tBack;
return WEST;
}
if (aX > 0.75) {
if (aZ < 0.25) return tBack;
if (aZ > 0.75) return tBack;
return EAST;
}
if (aZ < 0.25) return NORTH;
if (aZ > 0.75) return SOUTH;
return side;
}
case NORTH, SOUTH -> {
if (aX < 0.25) {
if (aY < 0.25) return tBack;
if (aY > 0.75) return tBack;
return WEST;
}
if (aX > 0.75) {
if (aY < 0.25) return tBack;
if (aY > 0.75) return tBack;
return EAST;
}
if (aY < 0.25) return DOWN;
if (aY > 0.75) return UP;
return side;
}
case WEST, EAST -> {
if (aZ < 0.25) {
if (aY < 0.25) return tBack;
if (aY > 0.75) return tBack;
return NORTH;
}
if (aZ > 0.75) {
if (aY < 0.25) return tBack;
if (aY > 0.75) return tBack;
return SOUTH;
}
if (aY < 0.25) return DOWN;
if (aY > 0.75) return UP;
return side;
}
}
return UNKNOWN;
}
private static DecimalFormat getDecimalFormat() {
return decimalFormatters.computeIfAbsent(Locale.getDefault(Locale.Category.FORMAT), locale -> {
DecimalFormat numberFormat = new DecimalFormat(); // uses the necessary locale inside anyway
numberFormat.setGroupingUsed(true);
numberFormat.setMaximumFractionDigits(2);
numberFormat.setRoundingMode(RoundingMode.HALF_UP);
DecimalFormatSymbols decimalFormatSymbols = numberFormat.getDecimalFormatSymbols();
decimalFormatSymbols.setGroupingSeparator(','); // Use sensible separator for best clarity.
numberFormat.setDecimalFormatSymbols(decimalFormatSymbols);
return numberFormat;
});
}
public static String formatNumbers(BigInteger aNumber) {
return getDecimalFormat().format(aNumber);
}
public static String formatNumbers(long aNumber) {
return getDecimalFormat().format(aNumber);
}
public static String formatNumbers(double aNumber) {
return getDecimalFormat().format(aNumber);
}
/*
* Check if stack has enough items of given type and subtract from stack, if there's no creative or 111 stack.
*/
public static boolean consumeItems(EntityPlayer player, ItemStack stack, Item item, int count) {
if (stack != null && stack.getItem() == item && stack.stackSize >= count) {
if ((!player.capabilities.isCreativeMode) && (stack.stackSize != 111)) stack.stackSize -= count;
return true;
}
return false;
}
/*
* Check if stack has enough items of given gregtech material (will be oredicted) and subtract from stack, if
* there's no creative or 111 stack.
*/
public static boolean consumeItems(EntityPlayer player, ItemStack stack, gregtech.api.enums.Materials mat,
int count) {
if (stack != null && GTOreDictUnificator.getItemData(stack).mMaterial.mMaterial == mat
&& stack.stackSize >= count) {
if ((!player.capabilities.isCreativeMode) && (stack.stackSize != 111)) stack.stackSize -= count;
return true;
}
return false;
}
public static ArrayList sortByValueToList(Map map) {
List> list = new LinkedList<>(map.entrySet());
list.sort((o1, o2) -> o2.getValue() - o1.getValue());
ArrayList result = new ArrayList<>();
for (Map.Entry e : list) result.add(e.getKey());
return result;
}
public static String joinListToString(List list) {
StringBuilder result = new StringBuilder(32);
for (String s : list) result.append(result.length() == 0 ? s : '|' + s);
return result.toString();
}
public static ItemStack getIntegratedCircuit(int config) {
return ItemList.Circuit_Integrated.getWithDamage(0, config);
}
public static float getBlockHardnessAt(World aWorld, int aX, int aY, int aZ) {
return aWorld.getBlock(aX, aY, aZ)
.getBlockHardness(aWorld, aX, aY, aZ);
}
public static FakePlayer getFakePlayer(IGregTechTileEntity aBaseMetaTileEntity) {
if (aBaseMetaTileEntity.getWorld() instanceof WorldServer) {
return FakePlayerFactory.get(
(WorldServer) aBaseMetaTileEntity.getWorld(),
new GameProfile(aBaseMetaTileEntity.getOwnerUuid(), aBaseMetaTileEntity.getOwnerName()));
}
return null;
}
public static boolean eraseBlockByFakePlayer(FakePlayer aPlayer, int aX, int aY, int aZ, boolean isSimulate) {
if (aPlayer == null) return false;
World aWorld = aPlayer.worldObj;
BlockEvent.BreakEvent event = new BlockEvent.BreakEvent(
aX,
aY,
aZ,
aWorld,
aWorld.getBlock(aX, aY, aZ),
aWorld.getBlockMetadata(aX, aY, aZ),
aPlayer);
MinecraftForge.EVENT_BUS.post(event);
if (!event.isCanceled()) {
if (!isSimulate) return aWorld.setBlockToAir(aX, aY, aZ);
return true;
}
return false;
}
public static boolean setBlockByFakePlayer(FakePlayer aPlayer, int aX, int aY, int aZ, Block aBlock, int aMeta,
boolean isSimulate) {
if (aPlayer == null) return false;
World aWorld = aPlayer.worldObj;
BlockEvent.PlaceEvent event = ForgeEventFactory
.onPlayerBlockPlace(aPlayer, new BlockSnapshot(aWorld, aX, aY, aZ, aBlock, aMeta), UNKNOWN);
if (!event.isCanceled()) {
if (!isSimulate) return aWorld.setBlock(aX, aY, aZ, aBlock, aMeta, 3);
return true;
}
return false;
}
public static int findMatchingStackInList(List aStacks, ItemStack aStack) {
if (isStackInvalid(aStack)) return -1;
for (int i = 0, aStacksSize = aStacks.size(); i < aStacksSize; i++) {
ItemStack tStack = aStacks.get(i);
if (areStacksEqual(aStack, tStack)) return i;
}
return -1;
}
public static Map convertItemListToMap(Collection itemStacks) {
Map result = new Object2LongOpenHashMap<>();
for (ItemStack itemStack : itemStacks) {
if (itemStack != null && itemStack.stackSize > 0) {
GTUtility.ItemId itemId = GTUtility.ItemId.createNoCopy(itemStack);
result.merge(itemId, (long) itemStack.stackSize, Long::sum);
}
}
return result;
}
public static Map convertFluidListToMap(Collection fluidStacks) {
Map result = new Reference2LongOpenHashMap<>();
for (FluidStack fluidStack : fluidStacks) {
if (fluidStack != null && fluidStack.amount > 0) {
result.merge(fluidStack.getFluid(), (long) fluidStack.amount, Long::sum);
}
}
return result;
}
/**
* @return Supplied collection that doesn't contain invalid MetaTileEntities.
*/
public static , E extends MetaTileEntity> T filterValidMTEs(T metaTileEntities) {
metaTileEntities.removeIf(mte -> mte == null || !mte.isValid());
return metaTileEntities;
}
/**
* @return Supplied collection that removes invalid MTEs from the collection while it is being iterated
*/
public static , E extends MetaTileEntity> ValidMTEList validMTEList(
T metaTileEntities) {
return new ValidMTEList<>(metaTileEntities);
}
public static ForgeDirection getSideFromPlayerFacing(Entity player) {
if (player == null) return ForgeDirection.UNKNOWN;
if (player.rotationPitch >= 65) return ForgeDirection.UP;
if (player.rotationPitch <= -65) return ForgeDirection.DOWN;
final byte facing = COMPASS_DIRECTIONS[MathHelper.floor_double(0.5D + 4.0F * player.rotationYaw / 360.0F)
& 0x3];
return ForgeDirection.getOrientation(facing);
}
public static class ItemNBT {
public static void setNBT(ItemStack aStack, NBTTagCompound aNBT) {
if (aNBT == null) {
aStack.setTagCompound(null);
return;
}
ArrayList tTagsToRemove = new ArrayList<>();
for (String tKey : aNBT.func_150296_c()) {
NBTBase tValue = aNBT.getTag(tKey);
if (tValue == null || (tValue instanceof NBTPrimitive && ((NBTPrimitive) tValue).func_150291_c() == 0)
|| (tValue instanceof NBTTagString && isStringInvalid(((NBTTagString) tValue).func_150285_a_())))
tTagsToRemove.add(tKey);
}
for (String tKey : tTagsToRemove) aNBT.removeTag(tKey);
aStack.setTagCompound(aNBT.hasNoTags() ? null : aNBT);
}
public static NBTTagCompound getNBT(ItemStack aStack) {
NBTTagCompound rNBT = aStack.getTagCompound();
return rNBT == null ? new NBTTagCompound() : rNBT;
}
public static void setPunchCardData(ItemStack aStack, String aPunchCardData) {
NBTTagCompound tNBT = getNBT(aStack);
tNBT.setString("GT.PunchCardData", aPunchCardData);
setNBT(aStack, tNBT);
}
public static String getPunchCardData(ItemStack aStack) {
NBTTagCompound tNBT = getNBT(aStack);
return tNBT.getString("GT.PunchCardData");
}
public static void setLighterFuel(ItemStack aStack, long aFuel) {
NBTTagCompound tNBT = getNBT(aStack);
tNBT.setLong("GT.LighterFuel", aFuel);
setNBT(aStack, tNBT);
}
public static long getLighterFuel(ItemStack aStack) {
NBTTagCompound tNBT = getNBT(aStack);
return tNBT.getLong("GT.LighterFuel");
}
public static void setMapID(ItemStack aStack, short aMapID) {
NBTTagCompound tNBT = getNBT(aStack);
tNBT.setShort("map_id", aMapID);
setNBT(aStack, tNBT);
}
public static short getMapID(ItemStack aStack) {
NBTTagCompound tNBT = getNBT(aStack);
if (!tNBT.hasKey("map_id")) return -1;
return tNBT.getShort("map_id");
}
public static void setBookTitle(ItemStack aStack, String aTitle) {
NBTTagCompound tNBT = getNBT(aStack);
tNBT.setString("title", aTitle);
setNBT(aStack, tNBT);
}
public static String getBookTitle(ItemStack aStack) {
NBTTagCompound tNBT = getNBT(aStack);
return tNBT.getString("title");
}
public static void setBookAuthor(ItemStack aStack, String aAuthor) {
NBTTagCompound tNBT = getNBT(aStack);
tNBT.setString("author", aAuthor);
setNBT(aStack, tNBT);
}
public static String getBookAuthor(ItemStack aStack) {
NBTTagCompound tNBT = getNBT(aStack);
return tNBT.getString("author");
}
public static void setProspectionData(ItemStack aStack, int aX, int aY, int aZ, int aDim, FluidStack aFluid,
String... aOres) {
NBTTagCompound tNBT = getNBT(aStack);
StringBuilder tData = new StringBuilder(aX + "," + aY + "," + aZ + "," + aDim + ",");
if (aFluid != null) tData.append(aFluid.amount)
.append(",")
.append(aFluid.getLocalizedName())
.append(","); // TODO
// CHECK
// IF
// THAT
// /5000
// is
// needed
// (Not
// needed)
for (String tString : aOres) {
tData.append(tString)
.append(",");
}
tNBT.setString("prospection", tData.toString());
setNBT(aStack, tNBT);
}
public static void setAdvancedProspectionData(byte aTier, ItemStack aStack, int aX, short aY, int aZ, int aDim,
ArrayList aOils, ArrayList aOres, int aRadius) {
setBookTitle(aStack, "Raw Prospection Data");
NBTTagCompound tNBT = getNBT(aStack);
tNBT.setByte("prospection_tier", aTier);
tNBT.setString("prospection_pos", "Dim: " + aDim + "\nX: " + aX + " Y: " + aY + " Z: " + aZ);
// ores
Collections.sort(aOres);
tNBT.setString("prospection_ores", joinListToString(aOres));
// oils
ArrayList tOilsTransformed = new ArrayList<>(aOils.size());
for (String aStr : aOils) {
String[] aStats = aStr.split(",");
tOilsTransformed.add(aStats[0] + ": " + aStats[1] + "L " + aStats[2]);
}
tNBT.setString("prospection_oils", joinListToString(tOilsTransformed));
String tOilsPosStr = "X: " + Math.floorDiv(aX, 16 * 8) * 16 * 8
+ " Z: "
+ Math.floorDiv(aZ, 16 * 8) * 16 * 8
+ "\n";
int xOff = aX - Math.floorDiv(aX, 16 * 8) * 16 * 8;
xOff = xOff / 16;
int xOffRemain = 7 - xOff;
int zOff = aZ - Math.floorDiv(aZ, 16 * 8) * 16 * 8;
zOff = zOff / 16;
int zOffRemain = 7 - zOff;
for (; zOff > 0; zOff--) {
tOilsPosStr = tOilsPosStr.concat("--------\n");
}
for (; xOff > 0; xOff--) {
tOilsPosStr = tOilsPosStr.concat("-");
}
tOilsPosStr = tOilsPosStr.concat("P");
for (; xOffRemain > 0; xOffRemain--) {
tOilsPosStr = tOilsPosStr.concat("-");
}
tOilsPosStr = tOilsPosStr.concat("\n");
for (; zOffRemain > 0; zOffRemain--) {
tOilsPosStr = tOilsPosStr.concat("--------\n");
}
tOilsPosStr = tOilsPosStr.concat(
" X: " + (Math.floorDiv(aX, 16 * 8) + 1) * 16 * 8
+ " Z: "
+ (Math.floorDiv(aZ, 16 * 8) + 1) * 16 * 8); // +1 oilfied to find bottomright of [5]
tNBT.setString("prospection_oils_pos", tOilsPosStr);
tNBT.setString("prospection_radius", String.valueOf(aRadius));
setNBT(aStack, tNBT);
}
public static void convertProspectionData(ItemStack aStack) {
NBTTagCompound tNBT = getNBT(aStack);
byte tTier = tNBT.getByte("prospection_tier");
if (tTier == 0) { // basic prospection data
String tData = tNBT.getString("prospection");
String[] tDataArray = tData.split(",");
if (tDataArray.length > 6) {
tNBT.setString(
"author",
" Dim: " + tDataArray[3]
+ "X: "
+ tDataArray[0]
+ " Y: "
+ tDataArray[1]
+ " Z: "
+ tDataArray[2]);
NBTTagList tNBTList = new NBTTagList();
StringBuilder tOres = new StringBuilder(" Prospected Ores: ");
for (int i = 6; tDataArray.length > i; i++) {
tOres.append(tDataArray[i])
.append(" ");
}
tNBTList.appendTag(
new NBTTagString(
"Tier " + tTier
+ " Prospecting Data From: X"
+ tDataArray[0]
+ " Z:"
+ tDataArray[2]
+ " Dim:"
+ tDataArray[3]
+ " Produces "
+ tDataArray[4]
+ "L "
+ tDataArray[5]
+ " "
+ tOres));
tNBT.setTag("pages", tNBTList);
}
} else { // advanced prospection data
String tPos = tNBT.getString("prospection_pos");
String tRadius = tNBT.getString("prospection_radius");
String tOresStr = tNBT.getString("prospection_ores");
String tOilsStr = tNBT.getString("prospection_oils");
String tOilsPosStr = tNBT.getString("prospection_oils_pos");
String[] tOres = tOresStr.isEmpty() ? null : tOresStr.split("\\|");
String[] tOils = tOilsStr.isEmpty() ? null : tOilsStr.split("\\|");
NBTTagList tNBTList = new NBTTagList();
String tPageText = "Prospector report\n" + tPos
+ "\n\n"
+ "Oils: "
+ (tOils != null ? tOils.length : 0)
+ "\n\n"
+ "Ores within "
+ tRadius
+ " blocks\n\n"
+ "Location is center of orevein\n\n"
+ "Check NEI to confirm orevein type";
tNBTList.appendTag(new NBTTagString(tPageText));
if (tOres != null) fillBookWithList(tNBTList, "Ores Found %s\n\n", "\n", 7, tOres);
if (tOils != null) fillBookWithList(tNBTList, "Oils%s\n\n", "\n", 9, tOils);
tPageText = """
Oil notes
Prospects from NW to SE 576 chunks(9 8x8 oilfields)
around and gives min-max amount
[1][2][3]
[4][5][6]
[7][8][9]
[5] - Prospector in this 8x8 area""";
tNBTList.appendTag(new NBTTagString(tPageText));
tPageText = "Corners of [5] are \n" + tOilsPosStr + "\n" + "P - Prospector in 8x8 field";
tNBTList.appendTag(new NBTTagString(tPageText));
tNBT.setString("author", tPos.replace("\n", " "));
tNBT.setTag("pages", tNBTList);
}
setNBT(aStack, tNBT);
}
public static void fillBookWithList(NBTTagList aBook, String aPageHeader, String aListDelimiter,
int aItemsPerPage, String[] list) {
String aPageFormatter = " %d/%d";
int tTotalPages = list.length / aItemsPerPage + (list.length % aItemsPerPage > 0 ? 1 : 0);
int tPage = 0;
StringBuilder tPageText;
do {
tPageText = new StringBuilder();
for (int i = tPage * aItemsPerPage; i < (tPage + 1) * aItemsPerPage && i < list.length; i += 1)
tPageText.append((tPageText.length() == 0) ? "" : aListDelimiter)
.append(list[i]);
if (tPageText.length() != 0) {
String tPageCounter = tTotalPages > 1 ? String.format(aPageFormatter, tPage + 1, tTotalPages) : "";
NBTTagString tPageTag = new NBTTagString(String.format(aPageHeader, tPageCounter) + tPageText);
aBook.appendTag(tPageTag);
}
++tPage;
} while (tPageText.length() != 0);
}
public static void addEnchantment(ItemStack aStack, Enchantment aEnchantment, int aLevel) {
NBTTagCompound tNBT = getNBT(aStack), tEnchantmentTag;
if (!tNBT.hasKey("ench", 9)) tNBT.setTag("ench", new NBTTagList());
NBTTagList tList = tNBT.getTagList("ench", 10);
boolean temp = true;
for (int i = 0; i < tList.tagCount(); i++) {
tEnchantmentTag = tList.getCompoundTagAt(i);
if (tEnchantmentTag.getShort("id") == aEnchantment.effectId) {
tEnchantmentTag.setShort("id", (short) aEnchantment.effectId);
tEnchantmentTag.setShort("lvl", (byte) aLevel);
temp = false;
break;
}
}
if (temp) {
tEnchantmentTag = new NBTTagCompound();
tEnchantmentTag.setShort("id", (short) aEnchantment.effectId);
tEnchantmentTag.setShort("lvl", (byte) aLevel);
tList.appendTag(tEnchantmentTag);
}
aStack.setTagCompound(tNBT);
}
}
public static String toSubscript(long no) {
char[] chars = Long.toString(no)
.toCharArray();
for (int i = 0; i < chars.length; i++) {
chars[i] += 8272;
}
return new String(chars);
}
public static boolean isPartOfMaterials(ItemStack aStack, Materials aMaterials) {
return GTOreDictUnificator.getAssociation(aStack) != null
&& GTOreDictUnificator.getAssociation(aStack).mMaterial.mMaterial.equals(aMaterials);
}
public static boolean isPartOfOrePrefix(ItemStack aStack, OrePrefixes aPrefix) {
return GTOreDictUnificator.getAssociation(aStack) != null
&& GTOreDictUnificator.getAssociation(aStack).mPrefix.equals(aPrefix);
}
public static final ImmutableSet ORE_BLOCK_CLASSES = ImmutableSet.of(
"bartworks.system.material.BWMetaGeneratedOres",
"bartworks.system.material.BWMetaGeneratedSmallOres",
"gtPlusPlus.core.block.base.BlockBaseOre");
public static boolean isOre(Block aBlock, int aMeta) {
return (aBlock instanceof BlockOresAbstract) || isOre(new ItemStack(aBlock, 1, aMeta))
|| ORE_BLOCK_CLASSES.contains(
aBlock.getClass()
.getName());
}
public static boolean isOre(ItemStack aStack) {
int tItem = GTUtility.stackToInt(aStack);
if (sOreTable.containsKey(tItem)) {
return sOreTable.get(tItem);
}
for (int id : OreDictionary.getOreIDs(aStack)) {
if (OreDictionary.getOreName(id)
.startsWith("ore")) {
sOreTable.put(tItem, true);
return true;
}
}
sOreTable.put(tItem, false);
return false;
}
/**
* Do NOT mutate the returned {@code ItemStack}! We return {@code ItemStack} instead of {@code Block} so that
* we can include metadata.
*/
public static ItemStack getCobbleForOre(Block ore, short metaData) {
// We need to convert small ores to regular ores because small ores don't have associated ItemData.
// We take the modulus of the metadata by 16000 because that is the magic number to convert small ores to
// regular ores.
// See: GT_TileEntity_Ores.java
ItemData association = GTOreDictUnificator
.getAssociation(new ItemStack(Item.getItemFromBlock(ore), 1, metaData % 16000));
if (association != null) {
Supplier supplier = sOreToCobble.get(association.mPrefix);
if (supplier != null) {
return supplier.get();
}
}
return new ItemStack(Blocks.cobblestone);
}
public static Optional reverseShapelessRecipe(ItemStack output, Object... aRecipe) {
if (output == null) {
return Optional.empty();
}
List inputs = new ArrayList<>();
for (Object o : aRecipe) {
if (o instanceof ItemStack) {
ItemStack toAdd = ((ItemStack) o).copy();
inputs.add(toAdd);
} else if (o instanceof String) {
ItemStack stack = GTOreDictUnificator.get(o, 1);
if (stack == null) {
Optional oStack = OreDictionary.getOres((String) o)
.stream()
.findAny();
if (oStack.isPresent()) {
ItemStack copy = oStack.get()
.copy();
inputs.add(copy);
}
} else {
ItemStack copy = stack.copy();
inputs.add(copy);
}
} else if (o instanceof Item) inputs.add(new ItemStack((Item) o));
else if (o instanceof Block) inputs.add(new ItemStack((Block) o));
else throw new IllegalStateException("A Recipe contains an invalid input! Output: " + output);
}
inputs.removeIf(x -> x.getItem() instanceof MetaGeneratedTool);
return Optional.of(
new GTRecipe(
false,
new ItemStack[] { output },
inputs.toArray(new ItemStack[0]),
null,
null,
null,
null,
300,
30,
0));
}
public static Optional reverseShapedRecipe(ItemStack output, Object... aRecipe) {
if (output == null) {
return Optional.empty();
}
Map