add Super ME Replenisher (#1294)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Martin Robertz <dream-master@gmx.net>
Co-authored-by: GitHub GTNH Actions <2970688+Dream-Master@users.noreply.github.com>
Co-authored-by: Kogepan229 <73163994+Kogepan229@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2026-06-26 20:46:28 +02:00
1 parent e586bd33db
commit 9a73e263b2
25 files changed
+1173 -26

No files matched your search

@@ -46,4 +46,6 @@ public interface ITickManager extends IGridCache {
* @return if the call was successful.
*/
boolean wakeDevice(IGridNode node);
default void updateTickRate(final IGridNode node) {}
}
@@ -184,7 +184,16 @@ public interface IMEInventory<StackType extends IAEStack> {
* @deprecated Use {@link IMEInventory#getStackType()} instead
*/
@Deprecated
StorageChannel getChannel();
default StorageChannel getChannel() {
final IAEStackType<?> type = this.getStackType();
if (type == ITEM_STACK_TYPE) {
return StorageChannel.ITEMS;
} else if (type == FLUID_STACK_TYPE) {
return StorageChannel.FLUIDS;
} else {
return null;
}
}
/**
* @return stack type your handler should be part of
@@ -34,12 +34,16 @@ public interface IStorageMonitorable {
/**
* Access the item inventory for the monitorable storage.
*/
IMEMonitor<IAEItemStack> getItemInventory();
default IMEMonitor<IAEItemStack> getItemInventory() {
return (IMEMonitor<IAEItemStack>) this.getMEMonitor(ITEM_STACK_TYPE);
}
/**
* Access the fluid inventory for the monitorable storage.
*/
IMEMonitor<IAEFluidStack> getFluidInventory();
default IMEMonitor<IAEFluidStack> getFluidInventory() {
return (IMEMonitor<IAEFluidStack>) this.getMEMonitor(FLUID_STACK_TYPE);
}
@Nullable
default IMEMonitor<?> getMEMonitor(@Nonnull IAEStackType<?> type) {
@@ -0,0 +1,74 @@
package appeng.block.misc;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import net.minecraft.block.material.Material;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.IIcon;
import net.minecraft.util.StatCollector;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
import appeng.block.AEBaseTileBlock;
import appeng.client.texture.ExtraBlockTextures;
import appeng.core.features.AEFeature;
import appeng.core.sync.GuiBridge;
import appeng.tile.misc.TileSuperMEReplenisher;
import appeng.util.Platform;
public class BlockSuperMEReplenisher extends AEBaseTileBlock {
public BlockSuperMEReplenisher() {
super(Material.iron);
this.setTileEntity(TileSuperMEReplenisher.class);
this.setFeature(EnumSet.of(AEFeature.Core));
this.setHardness(2.2f);
}
@Override
public boolean onActivated(final World w, final int x, final int y, final int z, final EntityPlayer p,
final int side, final float hitX, final float hitY, final float hitZ) {
if (p.isSneaking()) {
return false;
}
final TileSuperMEReplenisher tile = this.getTileEntity(w, x, y, z);
if (tile != null) {
if (Platform.isClient()) {
return true;
}
Platform.openGUI(p, tile, ForgeDirection.getOrientation(side), GuiBridge.GUI_SUPER_ME_REPLENISHER);
return true;
}
return false;
}
@Override
public IIcon getIcon(IBlockAccess w, int x, int y, int z, int s) {
final TileSuperMEReplenisher tile = this.getTileEntity(w, x, y, z);
if (tile != null) {
return switch (tile.getStatus()) {
case 1 -> ExtraBlockTextures.BlockSuperMEReplenisherDraw.getIcon();
case -1 -> ExtraBlockTextures.BlockSuperMEReplenisherExt.getIcon();
default -> super.getIcon(w, x, y, z, s);
};
}
return super.getIcon(w, x, y, z, s);
}
@Override
public void addInformation(ItemStack is, EntityPlayer player, List<String> lines, boolean advancedItemTooltips) {
super.addInformation(is, player, lines, advancedItemTooltips);
lines.addAll(
Arrays.asList(
StatCollector.translateToLocal("gui.tooltips.appliedenergistics2.BlockSuperMEReplenisher")
.split("\\\\n")));
}
}
@@ -1,12 +1,12 @@
package appeng.client.gui.implementations;
import static appeng.util.Platform.fmt;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.entity.player.InventoryPlayer;
import org.lwjgl.input.Keyboard;
import com.gtnewhorizon.gtnhlib.util.numberformatting.NumberFormatUtil;
import appeng.client.gui.GuiSub;
import appeng.client.gui.widgets.GuiAeButton;
import appeng.client.gui.widgets.MEGuiTextField;
@@ -161,10 +161,6 @@ public class GuiCellRestriction extends GuiSub {
super.keyTyped(character, key);
}
private static String fmt(double v) {
return NumberFormatUtil.formatNumber(v);
}
private CellRestrictionData filterCellRestriction() {
final byte types = (byte) this.getTypes();
return new CellRestrictionData(types, this.getAmount(types));
@@ -3,7 +3,6 @@ package appeng.client.gui.implementations;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.entity.player.InventoryPlayer;
import appeng.api.storage.ITerminalHost;
import appeng.client.gui.slots.VirtualMESlotSingle;
import appeng.container.implementations.ContainerPatternValueAmount;
import appeng.core.localization.ColorUtils;
@@ -18,7 +17,7 @@ public class GuiPatternValueAmount extends GuiAmount {
private final VirtualMESlotSingle slot;
@Reflected
public GuiPatternValueAmount(final InventoryPlayer inventoryPlayer, final ITerminalHost te) {
public GuiPatternValueAmount(final InventoryPlayer inventoryPlayer, final Object te) {
super(new ContainerPatternValueAmount(inventoryPlayer, te));
this.container = (ContainerPatternValueAmount) this.inventorySlots;
@@ -1,5 +1,7 @@
package appeng.client.gui.implementations;
import static appeng.util.Platform.fmt;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -21,8 +23,6 @@ import org.jetbrains.annotations.NotNull;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
import com.gtnewhorizon.gtnhlib.util.numberformatting.NumberFormatUtil;
import appeng.api.config.ActionItems;
import appeng.api.config.HealthSortOrder;
import appeng.api.config.ReshufflePhase;
@@ -944,10 +944,6 @@ public class GuiStorageReshuffle extends AEBaseGui {
return sb.toString();
}
private static String fmt(double v) {
return NumberFormatUtil.formatNumber(v);
}
private static String diffColor(double delta) {
if (delta > 0) return POSITIVE;
if (delta < 0) return NEGATIVE;
@@ -0,0 +1,178 @@
package appeng.client.gui.implementations;
import static appeng.util.Platform.fmt;
import net.minecraft.entity.player.InventoryPlayer;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.input.Keyboard;
import appeng.api.storage.data.IAEStack;
import appeng.api.storage.data.IAEStackType;
import appeng.client.gui.AEBaseGui;
import appeng.client.gui.slots.VirtualMEPhantomSlot;
import appeng.client.gui.slots.VirtualMEPhantomSlotPrecise;
import appeng.client.gui.slots.VirtualMESlot;
import appeng.client.gui.widgets.MEGuiTextField;
import appeng.container.implementations.ContainerSuperMEReplenisher;
import appeng.core.localization.ColorUtils;
import appeng.core.localization.GuiText;
import appeng.tile.misc.TileSuperMEReplenisher;
public class GuiSuperMEReplenisher extends AEBaseGui {
private final ContainerSuperMEReplenisher containerSuperMEReplenisher;
private final MEGuiTextField tickRateField;
private final MEGuiTextField thresholdField;
public GuiSuperMEReplenisher(final InventoryPlayer inventoryPlayer, final TileSuperMEReplenisher te) {
super(new ContainerSuperMEReplenisher(inventoryPlayer, te));
this.containerSuperMEReplenisher = (ContainerSuperMEReplenisher) inventorySlots;
this.ySize = 246;
this.xSize = 220;
this.thresholdField = new MEGuiTextField(28, 12);
this.thresholdField.setMaxStringLength(3);
this.tickRateField = new MEGuiTextField(34, 12);
this.tickRateField.setMaxStringLength(4);
}
@Override
public void initGui() {
super.initGui();
this.initVirtualSlots();
this.tickRateField.x = this.guiLeft + 29;
this.thresholdField.x = this.guiLeft + 101;
this.tickRateField.y = this.guiTop + 133;
this.thresholdField.y = this.tickRateField.y;
}
@Override
public void drawFG(int offsetX, int offsetY, int mouseX, int mouseY) {
if (this.containerSuperMEReplenisher.needUpdate) {
this.containerSuperMEReplenisher.needUpdate = false;
this.tickRateField.setText(String.valueOf(this.containerSuperMEReplenisher.tickRate.get()));
this.thresholdField.setText(String.valueOf(this.containerSuperMEReplenisher.threshold.get()));
}
final VirtualMESlot slot = this.getVirtualMESlotUnderMouse();
final int color = ColorUtils.guiTextColorGray.getColor();
if (slot != null) {
final IAEStack<?> config = slot.getAEStack();
if (config != null) {
final IAEStackType<?> type = config.getStackType();
final IAEStack<?> stored = this.containerSuperMEReplenisher.storedData.get().list.findPrecise(config);
final long storedSize = stored == null ? 0 : stored.getStackSize();
this.fontRendererObj.drawString(
GuiText.SuperMEReplenisherTarget.getLocal(fmt(config.getStackSize())),
29,
65,
color);
this.fontRendererObj
.drawString(GuiText.SuperMEReplenisherStored.getLocal(fmt(storedSize)), 29, 75, color);
this.fontRendererObj.drawString(
GuiText.SuperMEReplenisherBytesUsed
.getLocal(fmt((long) Math.ceil((double) storedSize / type.getAmountPerByte()))),
29,
85,
color);
}
}
// Status
final long totalBytes = this.containerSuperMEReplenisher.getTotalBytes();
final boolean unlimited = totalBytes >= Long.MAX_VALUE / 16;
this.fontRendererObj.drawString(
GuiText.SuperMEReplenisherBytesTotal
.getLocal(unlimited ? GuiText.SuperMEReplenisherBytesUnlimited.getLocal() : fmt(totalBytes)),
29,
104,
color);
this.fontRendererObj.drawString(
GuiText.SuperMEReplenisherBytesUsed.getLocal(fmt(this.containerSuperMEReplenisher.getUsedBytes())),
29,
114,
color);
// Settings
this.fontRendererObj.drawString(GuiText.SuperMEReplenisherTickRate.getLocal(), 29, 124, color);
this.fontRendererObj.drawString(GuiText.SuperMEReplenisherThreshold.getLocal(), 100, 124, color);
this.fontRendererObj.drawString("%", 100 + 31, 136, color);
this.fontRendererObj.drawString(GuiText.inventory.getLocal(), 29, this.ySize - 99, color);
}
@Override
public void drawBG(int offsetX, int offsetY, int mouseX, int mouseY) {
this.bindTexture("guis/superMEReplenisher.png");
this.drawTexturedModalRect(offsetX, offsetY, 0, 0, this.xSize, this.ySize);
this.tickRateField.drawTextBox();
this.thresholdField.drawTextBox();
}
private void initVirtualSlots() {
final int xo = 30;
final int yo = -154;
for (int y = 0; y < 3; y++) {
for (int x = 0; x < 9; x++) {
this.registerVirtualSlots(
new VirtualMEPhantomSlotPrecise(
xo + x * 18,
yo + y * 18 + 9 * 18,
this.containerSuperMEReplenisher.config,
x + y * 9,
this::acceptType) {
@Override
protected void setAEStack(@Nullable IAEStack<?> stack) {
if (this.getAEStack() != null)
containerSuperMEReplenisher.slotReset.send(this.slotIndex);
else super.setAEStack(stack);
}
});
}
}
}
@Override
protected void mouseClicked(final int xCoord, final int yCoord, final int btn) {
this.tickRateField.mouseClicked(xCoord, yCoord, btn);
this.thresholdField.mouseClicked(xCoord, yCoord, btn);
super.mouseClicked(xCoord, yCoord, btn);
}
@Override
protected void keyTyped(final char character, final int key) {
if (key == Keyboard.KEY_RETURN || key == Keyboard.KEY_NUMPADENTER) {
this.containerSuperMEReplenisher.tickRate.set(this.getInt(this.tickRateField, 10_000));
this.containerSuperMEReplenisher.threshold.set(this.getInt(this.thresholdField, 100));
this.tickRateField.setFocused(false);
this.thresholdField.setFocused(false);
} else if (!(this.tickRateField.textboxKeyTyped(character, key)
|| this.thresholdField.textboxKeyTyped(character, key)))
super.keyTyped(character, key);
}
private int getInt(final MEGuiTextField field, final int maxValue) {
try {
return Math.min(Math.max(1, Integer.parseInt(field.getText())), maxValue);
} catch (Exception ignored) {
return 1;
}
}
private boolean acceptType(VirtualMEPhantomSlot slot, IAEStackType<?> type, int mouseButton) {
return true;
}
}
@@ -170,7 +170,8 @@ public enum ExtraBlockTextures {
BlockSpatialNetworkRelayConnected("BlockSpatialNetworkRelayConnected"),
BlockSpatialLinkChamberFrontFull("BlockSpatialLinkChamberFrontFull"),
;
BlockSuperMEReplenisherDraw("BlockSuperMEReplenisherDraw"),
BlockSuperMEReplenisherExt("BlockSuperMEReplenisherExt"),;
private final String name;
private IIcon IIcon;
@@ -6,7 +6,6 @@ import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.ICrafting;
import appeng.api.storage.ITerminalHost;
import appeng.api.storage.StorageName;
import appeng.api.storage.data.IAEStack;
import appeng.client.gui.implementations.GuiPatternItemRenamer;
@@ -23,7 +22,7 @@ public class ContainerPatternValueAmount extends ContainerSubGui implements IVir
private IAEStack<?> aes;
private int slotIndex;
public ContainerPatternValueAmount(final InventoryPlayer ip, final ITerminalHost te) {
public ContainerPatternValueAmount(final InventoryPlayer ip, final Object te) {
super(ip, te);
}
@@ -0,0 +1,192 @@
package appeng.container.implementations;
import static appeng.util.Platform.isServer;
import java.util.Objects;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.item.ItemStack;
import appeng.api.config.SecurityPermissions;
import appeng.api.implementations.items.IStorageCell;
import appeng.api.storage.StorageName;
import appeng.api.storage.data.IAEStack;
import appeng.container.AEBaseContainer;
import appeng.container.guisync.IGuiPacketWritable;
import appeng.container.interfaces.IVirtualSlotSource;
import appeng.container.slot.SlotRestrictedInput;
import appeng.container.sync.ActionHandler;
import appeng.container.sync.StreamCodecs;
import appeng.container.sync.SyncCodecs;
import appeng.container.sync.SyncRegistrar;
import appeng.container.sync.handlers.AEStackInventorySyncHandler;
import appeng.container.sync.handlers.IntSyncHandler;
import appeng.container.sync.handlers.LongSyncHandler;
import appeng.container.sync.handlers.ObjectSyncHandler;
import appeng.tile.inventory.AppEngInternalInventory;
import appeng.tile.inventory.IAEStackInventory;
import appeng.tile.misc.TileSuperMEReplenisher;
import appeng.util.Platform;
import appeng.util.item.IAEStackList;
import io.netty.buffer.ByteBuf;
public class ContainerSuperMEReplenisher extends AEBaseContainer implements IVirtualSlotSource {
public static class Stored implements IGuiPacketWritable {
public final IAEStackList list;
public Stored(final IAEStackList list) {
this.list = list;
}
public Stored(ByteBuf buf) {
this.list = new IAEStackList(true);
final int itemListSize = buf.readInt();
for (int i = 0; i < itemListSize; i++) this.list.add(Platform.readStackByte(buf));
}
public static Stored copy(final Stored s) {
final IAEStackList newList = new IAEStackList(true);
s.list.forEach(aes -> newList.add(aes.copy()));
return new Stored(newList);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Stored subject)) return false;
if (this == obj) return true;
if (subject.list.size() != this.list.size()) return false;
for (final IAEStack<?> aes : this.list)
if (!Platform.isStacksIdentical(aes, subject.list.findPrecise(aes))) return false;
return true;
}
@Override
public void writeToPacket(ByteBuf buf) {
buf.writeInt(this.list.size());
this.list.forEach(o -> Platform.writeStackByte(o, buf));
}
}
private final TileSuperMEReplenisher tile;
private final LongSyncHandler totalBytes;
private final LongSyncHandler usedBytes;
public final IntSyncHandler tickRate;
public final IntSyncHandler threshold;
public final ActionHandler<Integer> slotReset;
public final AEStackInventorySyncHandler config;
public final ObjectSyncHandler<Stored> storedData;
public boolean needUpdate = false;
public ContainerSuperMEReplenisher(final InventoryPlayer ip, final TileSuperMEReplenisher te) {
super(ip, te);
this.tile = te;
final SyncRegistrar sync = this.syncRegistrar();
this.totalBytes = sync.longS2C("totalBytes");
this.usedBytes = sync.longS2C("usedBytes");
this.tickRate = sync.intSync("tickRate").onClientChange((oldValue, newValue) -> this.needUpdate = true)
.onServerChange((oldValue, newValue) -> this.tile.setTickRate(newValue));
this.threshold = sync.intSync("threshold").onClientChange((oldValue, newValue) -> this.needUpdate = true)
.onServerChange((oldValue, newValue) -> this.tile.setThreshold((double) newValue / 100));
this.slotReset = sync.actionC2S("reset", StreamCodecs.intValue()).onServerAction(this::resetSlot);
this.config = sync.aeStackInventory("config", this.getConfig());
this.storedData = sync.object(
"storedData",
SyncCodecs.packetWritable(Stored.class, Stored::new, Stored::copy, Objects::equals),
this.tile.getStorage());
final AppEngInternalInventory cells = this.tile.getCellInventory();
for (int i = 0; i < 3; i++) {
this.addSlotToContainer(
new SlotRestrictedInput(
SlotRestrictedInput.PlacableItemType.WORKBENCH_CELL,
cells,
i,
8,
8 + i * 18,
this.getInventoryPlayer()));
this.addSlotToContainer(
new SlotRestrictedInput(
SlotRestrictedInput.PlacableItemType.WORKBENCH_CELL,
cells,
3 + i,
196,
8 + i * 18,
this.getInventoryPlayer()));
}
bindPlayerInventory(ip, 22, 158);
}
private void resetSlot(final int slot) {
this.tile.getAEInventoryByName(StorageName.CONFIG).putAEStackInSlot(slot, null);
}
@Override
public ItemStack slotClick(int slotId, int clickedButton, int mode, EntityPlayer player) {
if (slotId >= 0 && slotId < 6) {
final ItemStack current = this.tile.getCellInventory().getStackInSlot(slotId);
if (current != null) {
if (current.getItem() instanceof IStorageCell currentCell) {
final long currentBytes = currentCell.getBytesLong(current);
if (!(this.totalBytes.get() - this.usedBytes.get() >= currentBytes)) {
final ItemStack hand = player.inventory.getItemStack();
if (hand != null && hand.getItem() instanceof IStorageCell handCell) {
if (!((this.totalBytes.get() + handCell.getBytesLong(hand) - this.usedBytes.get()
>= currentBytes))) {
return null;
}
} else return null;
}
}
}
}
return super.slotClick(slotId, clickedButton, mode, player);
}
@Override
public void detectAndSendChanges() {
this.verifyPermissions(SecurityPermissions.BUILD, false);
if (isServer()) {
this.totalBytes.set(this.tile.getTotalBytes());
this.usedBytes.set(this.tile.getUsedBytes());
this.tickRate.set(this.tile.getTickRate());
this.threshold.set((int) (this.tile.getThreshold() * 100));
this.storedData.set(this.tile.getStorage());
}
super.detectAndSendChanges();
}
@Override
public void updateVirtualSlot(StorageName invName, int slotId, IAEStack<?> aes) {
final IAEStackInventory config = this.tile.getAEInventoryByName(invName);
config.putAEStackInSlot(slotId, aes);
}
public IAEStackInventory getConfig() {
return this.tile.getAEInventoryByName(StorageName.CONFIG);
}
public long getTotalBytes() {
return this.totalBytes.get();
}
public long getUsedBytes() {
return this.usedBytes.get();
}
}
@@ -44,6 +44,7 @@ import appeng.block.misc.BlockQuartzTorch;
import appeng.block.misc.BlockSecurity;
import appeng.block.misc.BlockSkyCompass;
import appeng.block.misc.BlockStorageReshuffle;
import appeng.block.misc.BlockSuperMEReplenisher;
import appeng.block.misc.BlockTinyTNT;
import appeng.block.misc.BlockVibrationChamber;
import appeng.block.networking.BlockCableBus;
@@ -182,6 +183,7 @@ public final class ApiBlocks implements IBlocks {
private final IBlockDefinition chunkLoader;
private final IBlockDefinition phantomNode;
private final IBlockDefinition cubeGenerator;
private final IBlockDefinition superMEReplenisher;
private final Set<IOrientableBlock> orientables;
@@ -342,6 +344,7 @@ public final class ApiBlocks implements IBlocks {
this.chunkLoader = constructor.registerBlockDefinition(new BlockChunkloader());
this.phantomNode = constructor.registerBlockDefinition(new BlockPhantomNode());
this.cubeGenerator = constructor.registerBlockDefinition(new BlockCubeGenerator());
this.superMEReplenisher = constructor.registerBlockDefinition(new BlockSuperMEReplenisher());
this.wirelessConnector = constructor.registerTileDefinition(new BlockWirelessConnector());
this.wirelessHub = constructor.registerTileDefinition(new BlockWirelessHub());
this.crystalGrowthChamber = constructor.registerTileDefinition(new BlockCrystalGrowthChamber());
@@ -406,6 +406,14 @@ public enum GuiText implements Localization {
GuiDimensionalCoordNoDim,
GuiDimensionalCoordShortNoDim,
SuperMEReplenisherBytesTotal,
SuperMEReplenisherBytesUnlimited,
SuperMEReplenisherBytesUsed,
SuperMEReplenisherTickRate,
SuperMEReplenisherThreshold,
SuperMEReplenisherTarget,
SuperMEReplenisherStored,
itemMEStackPacketDesc1,
itemMEStackPacketDesc2,
@@ -101,6 +101,7 @@ import appeng.container.implementations.ContainerSpatialIOPort;
import appeng.container.implementations.ContainerSpatialLinkChamber;
import appeng.container.implementations.ContainerStorageBus;
import appeng.container.implementations.ContainerStorageReshuffle;
import appeng.container.implementations.ContainerSuperMEReplenisher;
import appeng.container.implementations.ContainerVibrationChamber;
import appeng.container.implementations.ContainerWireless;
import appeng.container.implementations.ContainerWirelessKit;
@@ -126,6 +127,7 @@ import appeng.tile.misc.TileCrystalGrowthChamber;
import appeng.tile.misc.TileInscriber;
import appeng.tile.misc.TileSecurity;
import appeng.tile.misc.TileStorageReshuffle;
import appeng.tile.misc.TileSuperMEReplenisher;
import appeng.tile.misc.TileVibrationChamber;
import appeng.tile.networking.TileWireless;
import appeng.tile.qnb.TileQuantumBridge;
@@ -231,7 +233,7 @@ public enum GuiBridge implements IGuiHandler {
GUI_CRAFTING_AMOUNT(ContainerCraftAmount.class, ITerminalHost.class, GuiHostType.ITEM_OR_WORLD,
SecurityPermissions.CRAFT),
GUI_PATTERN_VALUE_AMOUNT(ContainerPatternValueAmount.class, ITerminalHost.class, GuiHostType.ITEM_OR_WORLD, null),
GUI_PATTERN_VALUE_AMOUNT(ContainerPatternValueAmount.class, Object.class, GuiHostType.ITEM_OR_WORLD, null),
GUI_PATTERN_MULTI(ContainerPatternMulti.class, ITerminalHost.class, GuiHostType.ITEM_OR_WORLD, null),
@@ -259,7 +261,10 @@ public enum GuiBridge implements IGuiHandler {
GUI_SUPER_WIRELESS_KIT(ContainerWirelessKit.class, IGuiItemObject.class, GuiHostType.ITEM, null),
GUI_WIRELESS_NETWORK_MANAGER(ContainerWirelessNetworkManager.class, IGuiItemObject.class, GuiHostType.ITEM, null);
GUI_WIRELESS_NETWORK_MANAGER(ContainerWirelessNetworkManager.class, IGuiItemObject.class, GuiHostType.ITEM, null),
GUI_SUPER_ME_REPLENISHER(ContainerSuperMEReplenisher.class, TileSuperMEReplenisher.class, GuiHostType.WORLD,
SecurityPermissions.BUILD);
private final Class tileClass;
private final Class containerClass;
+19
View File
@@ -218,4 +218,23 @@ public class TickManagerCache implements ITickManager {
return false;
}
@Override
public void updateTickRate(IGridNode gridNode) {
final IGridHost machine = gridNode.getMachine();
if (machine instanceof IGridTickable) {
final TickingRequest tr = ((IGridTickable) machine).getTickingRequest(gridNode);
if (tr != null) {
final TickTracker tt = new TickTracker(tr, gridNode, (IGridTickable) machine, this.currentTick, this);
this.alertable.replace(gridNode, tt);
this.sleeping.replace(gridNode, tt);
final TickTracker awakeTT = this.awake.get(gridNode);
if (awakeTT != null) {
this.upcomingTicks.remove(awakeTT);
this.upcomingTicks.add(tt);
}
this.awake.replace(gridNode, tt);
}
}
}
}
@@ -22,6 +22,7 @@ import appeng.api.storage.IExternalStorageHandler;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.data.IAEStackType;
import appeng.tile.misc.TileCondenser;
import appeng.tile.misc.TileSuperMEReplenisher;
public class AEExternalHandler implements IExternalStorageHandler {
@@ -29,6 +30,7 @@ public class AEExternalHandler implements IExternalStorageHandler {
public boolean canHandle(TileEntity te, ForgeDirection d, IAEStackType<?> type, BaseActionSource mySrc) {
if (te instanceof ITileStorageMonitorable)
return ((ITileStorageMonitorable) te).getMonitorable(d, mySrc) != null;
else if (te instanceof TileSuperMEReplenisher) return true;
else return te instanceof TileCondenser && (type == ITEM_STACK_TYPE || type == FLUID_STACK_TYPE);
}
@@ -43,7 +45,7 @@ public class AEExternalHandler implements IExternalStorageHandler {
if (te instanceof ITileStorageMonitorable iface) {
return iface.getMonitorable(d, src).getMEMonitor(type);
}
} else if (te instanceof TileSuperMEReplenisher tSMR) return new MEInventoryWrapper(tSMR, type);
return null;
}
@@ -0,0 +1,39 @@
package appeng.me.storage;
import appeng.api.config.Actionable;
import appeng.api.networking.security.BaseActionSource;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.data.IAEStack;
import appeng.api.storage.data.IAEStackType;
import appeng.api.storage.data.IItemList;
public class MEInventoryWrapper<T extends IAEStack<T>> implements IMEInventory<T> {
private final IMEInventory<T> delegate;
private final IAEStackType<T> type;
public MEInventoryWrapper(IMEInventory<T> delegate, IAEStackType<T> type) {
this.delegate = delegate;
this.type = type;
}
@Override
public T injectItems(T input, Actionable type, BaseActionSource src) {
return this.delegate.injectItems(input, type, src);
}
@Override
public T extractItems(T request, Actionable mode, BaseActionSource src) {
return this.delegate.extractItems(request, mode, src);
}
@Override
public IItemList<T> getAvailableItems(IItemList<T> out, int iteration) {
return this.delegate.getAvailableItems(out, iteration);
}
@Override
public IAEStackType<?> getStackType() {
return this.type;
}
}
@@ -0,0 +1,587 @@
package appeng.tile.misc;
import java.util.List;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.common.util.ForgeDirection;
import com.gtnewhorizon.gtnhlib.item.ItemStackNBT;
import appeng.api.AEApi;
import appeng.api.config.Actionable;
import appeng.api.config.PowerMultiplier;
import appeng.api.implementations.IPowerChannelState;
import appeng.api.implementations.items.IStorageCell;
import appeng.api.networking.GridFlags;
import appeng.api.networking.IGridNode;
import appeng.api.networking.events.MENetworkBootingStatusChange;
import appeng.api.networking.events.MENetworkEventSubscribe;
import appeng.api.networking.events.MENetworkPowerStatusChange;
import appeng.api.networking.security.BaseActionSource;
import appeng.api.networking.security.MachineSource;
import appeng.api.networking.storage.IStorageGrid;
import appeng.api.networking.ticking.IGridTickable;
import appeng.api.networking.ticking.TickRateModulation;
import appeng.api.networking.ticking.TickingRequest;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.StorageName;
import appeng.api.storage.data.AEStackTypeRegistry;
import appeng.api.storage.data.IAEStack;
import appeng.api.storage.data.IAEStackType;
import appeng.api.storage.data.IItemList;
import appeng.container.implementations.ContainerSuperMEReplenisher;
import appeng.me.GridAccessException;
import appeng.tile.TileEvent;
import appeng.tile.events.TileEventType;
import appeng.tile.grid.AENetworkTile;
import appeng.tile.inventory.AppEngInternalInventory;
import appeng.tile.inventory.IAEStackInventory;
import appeng.tile.inventory.IIAEStackInventory;
import appeng.util.Platform;
import appeng.util.item.IAEStackList;
import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
public class TileSuperMEReplenisher extends AENetworkTile
implements IMEInventory<IAEStack<?>>, IIAEStackInventory, IPowerChannelState, IGridTickable {
private final IAEStackList storage = new IAEStackList(true);
private final IAEStackList out = new IAEStackList(true);
private final IAEStackInventory config = new IAEStackInventory(this, 3 * 9, StorageName.CONFIG) {
@Override
public void putAEStackInSlot(int n, IAEStack<?> aes) {
if (haveSame(n, aes)) return;
if (Platform.isServer() && TileSuperMEReplenisher.this.onConfigChange(n, aes)) return;
super.putAEStackInSlot(n, aes);
}
};
private final Object2IntOpenHashMap<IAEStackType<?>> unusedCount = new Object2IntOpenHashMap<>();
private long totalBytes = 0;
private long usedBytes = 0;
private int tickRate = 120;
private double threshold = 0.5;
private boolean unlimited = false;
private boolean isPowered = false;
private int status = 0;
private final BaseActionSource src = new MachineSource(this);
private final AppEngInternalInventory cells = new AppEngInternalInventory(null, 6) {
@Override
public ItemStack decrStackSize(int slot, int qty) {
TileSuperMEReplenisher.this.removeCell(this.getStackInSlot(slot));
return super.decrStackSize(slot, qty);
}
@Override
public void setInventorySlotContents(int slot, ItemStack newItemStack) {
TileSuperMEReplenisher.this.removeCell(this.getStackInSlot(slot));
TileSuperMEReplenisher.this.addCell(newItemStack);
super.setInventorySlotContents(slot, newItemStack);
}
@Override
public void markDirty() {
TileSuperMEReplenisher.this.markDirty();
}
};
public TileSuperMEReplenisher() {
this.getProxy().setFlags(GridFlags.REQUIRE_CHANNEL);
this.getProxy().setIdlePowerUsage(4.0);
}
@Override
public TickingRequest getTickingRequest(IGridNode node) {
return new TickingRequest(this.tickRate, this.tickRate, false, false);
}
@Override
public TickRateModulation tickingRequest(IGridNode node, int TicksSinceLastCall) {
try {
if (this.getProxy().isActive()) return this.doWork(this.getProxy().getStorage());
} catch (final GridAccessException ignored) {}
return TickRateModulation.SAME;
}
private void updateTickRate() {
try {
this.getProxy().getTick().updateTickRate(this.getGridNode(ForgeDirection.UNKNOWN));
} catch (Exception ignored) {}
}
@TileEvent(TileEventType.TICK)
public void tick() {
if (Platform.isServer() && this.status != 0) {
this.status = 0;
this.markForUpdate();
}
}
@TileEvent(TileEventType.NETWORK_READ)
public boolean readFromStream_TileSuperMEReplenisher(final ByteBuf data) {
final boolean oldPower = this.isPowered;
final int oldStatus = this.status;
this.isPowered = data.readBoolean();
this.status = data.readInt();
return this.isPowered != oldPower || this.status != oldStatus;
}
@TileEvent(TileEventType.NETWORK_WRITE)
public void writeToStream_TileSuperMEReplenisher(final ByteBuf data) {
data.writeBoolean(isActive());
data.writeInt(this.status);
}
@TileEvent(TileEventType.WORLD_NBT_READ)
public void readFromNBTEvent(NBTTagCompound data) {
this.config.readFromNBT(data, "config");
this.cells.readFromNBT(data, "cells");
if (data.hasKey("threshold")) this.threshold = data.getDouble("threshold");
if (data.hasKey("tickRate")) this.setTickRate(data.getInteger("tickRate"));
Platform.readAEStackListNBT(this.storage, data.getTagList("storage", Constants.NBT.TAG_COMPOUND));
Platform.readAEStackListNBT(this.out, data.getTagList("out", Constants.NBT.TAG_COMPOUND));
this.countBytes();
this.countUsedBytes();
}
@TileEvent(TileEventType.WORLD_NBT_WRITE)
public NBTTagCompound writeToNBTEvent(NBTTagCompound data) {
this.config.writeToNBT(data, "config");
this.cells.writeToNBT(data, "cells");
data.setDouble("threshold", this.threshold);
data.setInteger("tickRate", this.tickRate);
data.setTag("storage", Platform.writeAEStackListNBT(this.storage));
data.setTag("out", Platform.writeAEStackListNBT(this.out));
return data;
}
@MENetworkEventSubscribe
public void stateChange(final MENetworkPowerStatusChange p) {
this.updatePowerState();
}
@MENetworkEventSubscribe
public final void bootingRender(final MENetworkBootingStatusChange c) {
this.updatePowerState();
}
private TickRateModulation doWork(final IStorageGrid storage) {
for (int i = 0; i < this.config.getSizeInventory(); i++) {
final IAEStack<?> config = this.config.getAEStackInSlot(i);
if (config == null) continue;
final IAEStackType<?> type = config.getStackType();
final IAEStack<?> stored = this.storage.findPrecise(config);
final long configSize = config.getStackSize();
final long storedSize = stored == null ? 0 : stored.getStackSize();
if (((double) storedSize / configSize) < this.threshold) {
final IAEStack<?> toRequest = config.copy();
toRequest.setStackSize(configSize - storedSize);
toRequest(toRequest, storage);
} else if (storedSize > configSize) {
final IAEStack<?> toReturn = config.copy();
toReturn.setStackSize(storedSize - configSize);
toReturn(toReturn, storage, this.storage);
}
}
this.refund(this.out);
return TickRateModulation.SAME;
}
private boolean haveSame(final int n, final IAEStack<?> aes) {
for (int i = 0; i < this.config.getSizeInventory(); i++) {
if (i == n) continue;
final IAEStack<?> config = this.config.getAEStackInSlot(i);
if (config == null) continue;
if (config.equals(aes)) return true;
}
return false;
}
private boolean onConfigChange(final int slots, final IAEStack<?> newStack) {
try {
final IStorageGrid storage = this.getProxy().getStorage();
final IAEStack<?> currentConfig = this.config.getAEStackInSlot(slots);
if (currentConfig == null) return false;
if (currentConfig.equals(newStack)) {
final long currentConfigSize = currentConfig.getStackSize();
final long newConfigSize = newStack.getStackSize();
if (currentConfigSize > newConfigSize) {
final IAEStack<?> stored = this.get(currentConfig);
if (stored == null) return false;
final long storedSize = stored.getStackSize();
if (storedSize > newConfigSize) {
final long newSize = storedSize - newConfigSize;
final IAEStack<?> tempStack = stored.copy();
tempStack.setStackSize(newSize);
this.toReturn(tempStack, storage, this.storage);
return stored.getStackSize() > newConfigSize;
}
return false;
} else {
this.doWork(storage);
return false;
}
} else {
this.toReturn(currentConfig, storage, this.storage);
final IAEStack<?> stored = this.get(currentConfig);
return !(stored == null || stored.getStackSize() == 0);
}
} catch (final GridAccessException ignored) {}
return true;
}
private IAEStack<?> get(final IAEStack<?> aes) {
return this.storage.findPrecise(aes);
}
private void toRequest(final IAEStack<?> aes, final IStorageGrid storage) {
final IMEMonitor monitor = storage.getMEMonitor(aes.getStackType());
if (monitor == null) return;
final IAEStack<?> notAllowed = this.injectItems(aes, Actionable.SIMULATE, this.storage);
if (notAllowed != null) {
final long requestSize = aes.getStackSize();
final long notAllowedSize = notAllowed.getStackSize();
aes.setStackSize(requestSize - notAllowedSize);
}
final IAEStack<?> extracted = monitor.extractItems(aes, Actionable.MODULATE, this.src);
this.injectItems(extracted, Actionable.MODULATE, this.storage);
}
private void toReturn(final IAEStack<?> aes, final IStorageGrid storage, final IAEStackList target) {
final IMEMonitor monitor = storage.getMEMonitor(aes.getStackType());
if (monitor == null) return;
final IAEStack<?> allowed = this.extractItems(aes, Actionable.MODULATE, target);
if (allowed == null) return;
final IAEStack<?> notInjected = monitor.injectItems(allowed, Actionable.MODULATE, this.src);
this.injectItems(notInjected, Actionable.MODULATE, target);
}
private void refund(final IAEStackList fList) {
try {
final IStorageGrid storage = this.getProxy().getStorage();
fList.forEach(listItem -> {
final IMEMonitor monitor = storage.getMEMonitor(listItem.getStackType());
if (monitor != null) {
final IAEStack<?> leftOver = monitor.injectItems(
this.extractItems(listItem, Actionable.MODULATE, fList),
Actionable.MODULATE,
this.src);
if (leftOver != null) this.injectItems(leftOver, Actionable.MODULATE, fList);
}
});
} catch (final GridAccessException ignored) {}
}
public void fullRefund() {
this.refund(this.storage);
this.refund(this.out);
}
private long getCellBytes(final ItemStack is) {
if (is != null && is.getItem() instanceof IStorageCell baseCell) {
return baseCell.getBytesLong(is);
}
return 0;
}
private void removeCell(final ItemStack is) {
final long newBytes = this.getCellBytes(is);
this.totalBytes -= newBytes;
if (this.totalBytes < Long.MAX_VALUE / 16) {
this.unlimited = false;
this.countUsedBytes();
}
this.updatePowerDraw();
}
private void addCell(final ItemStack is) {
final long newBytes = this.getCellBytes(is);
this.totalBytes += newBytes;
if (this.totalBytes >= Long.MAX_VALUE / 16) this.unlimited = true;
this.updatePowerDraw();
}
private void updatePowerDraw() {
final double powerDraw;
if (this.unlimited) powerDraw = 1;
else powerDraw = Math.sqrt(Math.pow(this.totalBytes, 0.576D));
this.getProxy().setIdlePowerUsage(powerDraw);
}
private void updatePowerState() {
boolean newState = false;
try {
newState = this.getProxy().isActive()
&& this.getProxy().getEnergy().extractAEPower(1, Actionable.SIMULATE, PowerMultiplier.CONFIG)
> 0.0001;
} catch (final GridAccessException ignored) {}
if (newState != this.isPowered) {
this.isPowered = newState;
this.markForUpdate();
}
}
@Override
public IItemList<IAEStack<?>> getAvailableItems(IItemList<IAEStack<?>> out, int iteration) {
final IAEStackType<?> outStackType = out.getStackType();
this.storage.forEach(aes -> { if (aes.getStackType().equals(outStackType)) out.add(aes); });
return out;
}
@Override
public IAEStack<?> injectItems(IAEStack<?> input, Actionable type, BaseActionSource src) {
return this.injectItems(input, type, this.out);
}
private IAEStack<?> injectItems(final IAEStack<?> input, final Actionable type, final IAEStackList target) {
if (input == null) return null;
final long freeBytes = this.totalBytes - this.usedBytes;
final IAEStackType<?> stackType = input.getStackType();
final int typeWeight = stackType.getAmountPerByte();
final long stackSize = input.getStackSize();
final int unusedCount = this.unusedCount.getOrDefault(stackType, 0);
if (freeBytes == 0 && unusedCount == 0) return input;
final int freeUnusedCount = unusedCount == 0 ? 0 : typeWeight - unusedCount;
final long needBytes;
final int newUnusedCount;
if (stackSize > freeUnusedCount) {
final long toCountSize = stackSize - freeUnusedCount;
needBytes = (long) Math.ceil((double) toCountSize / typeWeight);
newUnusedCount = (int) toCountSize % typeWeight;
} else {
needBytes = 0;
newUnusedCount = (int) ((unusedCount + stackSize) % typeWeight);
}
if (type == Actionable.SIMULATE) {
if (freeBytes >= needBytes) return null;
else {
final IAEStack<?> notAllowed = input.copy();
notAllowed.setStackSize(input.getStackSize() - ((freeBytes * typeWeight) + freeUnusedCount));
return notAllowed;
}
} else {
this.status = 1;
this.markForUpdate();
if (freeBytes >= needBytes) {
if (!this.unlimited) {
this.unusedCount.put(stackType, newUnusedCount);
this.usedBytes += needBytes;
}
target.add(input);
return null;
} else {
final IAEStack<?> notAllowed = input.copy();
final IAEStack<?> allowed = input.copy();
if (!this.unlimited) {
final long newNeedBytes = freeBytes * typeWeight;
notAllowed.setStackSize(input.getStackSize() - (newNeedBytes + freeUnusedCount));
allowed.setStackSize(input.getStackSize() - notAllowed.getStackSize());
this.usedBytes += freeBytes;
this.unusedCount.put(stackType, 0);
}
target.add(allowed);
return notAllowed;
}
}
}
@Override
public IAEStack<?> extractItems(IAEStack<?> request, Actionable mode, BaseActionSource src) {
return this.extractItems(request, mode, this.storage);
}
private IAEStack<?> extractItems(final IAEStack<?> request, final Actionable mode, final IAEStackList target) {
if (request == null) return null;
final IAEStackType<?> stackType = request.getStackType();
final IAEStack<?> stack = target.findPrecise(request);
if (stack == null) return null;
final long stackSize = stack.getStackSize();
if (stackSize <= 0) return null;
long requestSize = request.getStackSize();
final IAEStack<?> ret = request.copy();
if (stackSize < requestSize) {
ret.setStackSize(stackSize);
requestSize = stackSize;
}
if (mode == Actionable.MODULATE) {
this.status = -1;
this.markForUpdate();
stack.decStackSize(requestSize);
if (!this.unlimited) {
final int typeWeight = stackType.getAmountPerByte();
final int unusedCount = this.unusedCount.getOrDefault(stackType, 0);
final int freeInPartialByte = unusedCount == 0 ? 0 : typeWeight - unusedCount;
final long freedBytes = (freeInPartialByte + requestSize) / typeWeight;
final int newFreeInPartialByte = (int) ((freeInPartialByte + requestSize) % typeWeight);
final int newUnusedCount = newFreeInPartialByte == 0 ? 0 : typeWeight - newFreeInPartialByte;
this.usedBytes -= freedBytes;
this.unusedCount.put(stackType, newUnusedCount);
}
}
return ret;
}
private void countUsedBytes() {
this.usedBytes = 0;
final Object2DoubleOpenHashMap<IAEStackType<?>> unusedCount = new Object2DoubleOpenHashMap<>();
this.storage.forEach(aes -> {
final IAEStackType<?> stackType = aes.getStackType();
unusedCount.put(stackType, unusedCount.getOrDefault(stackType, 0) + aes.getStackSize());
});
this.out.forEach(aes -> {
final IAEStackType<?> stackType = aes.getStackType();
unusedCount.put(stackType, unusedCount.getOrDefault(stackType, 0) + aes.getStackSize());
});
for (IAEStackType<?> stackType : AEStackTypeRegistry.getAllTypes()) {
final int typeWeight = stackType.getAmountPerByte();
final double count = unusedCount.getOrDefault(stackType, 0);
this.unusedCount.put(stackType, (int) count % typeWeight);
this.usedBytes += (long) Math.ceil(count / typeWeight);
}
}
private void countBytes() {
this.totalBytes = 0;
for (int i = 0; i < this.cells.getSizeInventory(); i++) {
this.totalBytes += this.getCellBytes(this.cells.getStackInSlot(i));
}
if (this.totalBytes >= Long.MAX_VALUE / 16) this.unlimited = true;
}
@Override
public void saveAEStackInv() {
this.markDirty();
}
@Override
public void getDrops(World w, int x, int y, int z, List<ItemStack> drops) {
this.fullRefund();
for (int i = 0; i < this.cells.getSizeInventory(); i++) {
final ItemStack cell = this.cells.getStackInSlot(i);
if (cell != null) drops.add(cell);
}
this.zeroVoid(drops);
}
private void zeroVoid(final IAEStackList fList, final List<ItemStack> drops) {
final ItemStack container = AEApi.instance().definitions().items().itemMEStackPacket().maybeStack(1).get();
fList.forEach(listItem -> {
final ItemStack is = container.copy();
Platform.writeStackNBT(listItem, ItemStackNBT.get(is));
drops.add(is);
});
}
public void zeroVoid(final List<ItemStack> drops) {
this.zeroVoid(this.storage, drops);
this.zeroVoid(this.out, drops);
}
@Override
public boolean isPowered() {
return this.isPowered;
}
@Override
public boolean isActive() {
return this.isPowered;
}
@Override
public IAEStackInventory getAEInventoryByName(StorageName name) {
if (name == StorageName.CONFIG) return this.config;
return null;
}
public ContainerSuperMEReplenisher.Stored getStorage() {
return new ContainerSuperMEReplenisher.Stored(this.storage);
}
public AppEngInternalInventory getCellInventory() {
return this.cells;
}
public long getTotalBytes() {
return this.totalBytes;
}
public long getUsedBytes() {
if (this.unlimited) this.countUsedBytes();
return this.usedBytes;
}
public int getStatus() {
return this.status;
}
public void setTickRate(final int tickRate) {
this.tickRate = tickRate;
this.updateTickRate();
}
public int getTickRate() {
return this.tickRate;
}
public void setThreshold(final double threshold) {
this.threshold = threshold;
}
public double getThreshold() {
return this.threshold;
}
}
+15 -1
View File
@@ -75,6 +75,7 @@ import org.jetbrains.annotations.NotNull;
import com.glodblock.github.common.item.ItemFluidDrop;
import com.glodblock.github.common.item.ItemFluidPacket;
import com.gtnewhorizon.gtnhlib.item.ItemStackNBT;
import com.gtnewhorizon.gtnhlib.util.numberformatting.NumberFormatUtil;
import com.mojang.authlib.GameProfile;
import appeng.api.AEApi;
@@ -2064,7 +2065,16 @@ public class Platform {
}
public static IItemList<IAEStack<?>> readAEStackListNBT(final NBTTagList tag, boolean convert) {
final IItemList<IAEStack<?>> out = AEApi.instance().storage().createAEStackList();
return readAEStackListNBT(null, tag, convert);
}
public static IItemList<IAEStack<?>> readAEStackListNBT(final IItemList<IAEStack<?>> out, final NBTTagList tag) {
return readAEStackListNBT(out, tag, false);
}
public static IItemList<IAEStack<?>> readAEStackListNBT(IItemList<IAEStack<?>> out, final NBTTagList tag,
boolean convert) {
if (out == null) out = AEApi.instance().storage().createAEStackList();
if (tag != null) {
for (int x = 0; x < tag.tagCount(); x++) {
@@ -2168,6 +2178,10 @@ public class Platform {
}
}
public static String fmt(double v) {
return NumberFormatUtil.formatNumber(v);
}
@NotNull
@Contract("_ -> new")
public static ItemStack copyStackWithSizeOne(@NotNull ItemStack itemStack) {
@@ -21,8 +21,18 @@ public final class IAEStackList implements IItemList<IAEStack<?>> {
private final Map<IAEStackType<?>, IItemList> lists = new IdentityHashMap<>();
public IAEStackList() {
for (IAEStackType<?> type : AEStackTypeRegistry.getAllTypes()) {
this.lists.put(type, type.createList());
this(false);
}
public IAEStackList(final boolean primitive) {
if (primitive) {
for (IAEStackType<?> type : AEStackTypeRegistry.getAllTypes()) {
this.lists.put(type, type.createPrimitiveList());
}
} else {
for (IAEStackType<?> type : AEStackTypeRegistry.getAllTypes()) {
this.lists.put(type, type.createList());
}
}
}
@@ -72,6 +72,7 @@ tile.appliedenergistics2.BlockSingularityCraftingStorage.name=Singularity Crafti
tile.appliedenergistics2.BlockPaint.name=Paint
tile.appliedenergistics2.BlockSpatialLinkChamber.name=Spatial Link Chamber
tile.appliedenergistics2.BlockSpatialNetworkRelay.name=Spatial Network Relay
tile.appliedenergistics2.BlockSuperMEReplenisher.name=Super ME Replenisher
tile.appliedenergistics2.BlockWirelessConnector.name=Wireless Connector
tile.appliedenergistics2.BlockWirelessHub.name=Wireless Hub
tile.appliedenergistics2.BlockCrystalGrowthChamber.name=Crystal Growth Chamber
@@ -251,6 +252,14 @@ gui.appliedenergistics2.ReshuffleReportTextColorNegative=§4
gui.appliedenergistics2.ReshuffleReportTextColorNeutral=§8
gui.appliedenergistics2.ReshuffleReportTextColorWarning=§6
gui.appliedenergistics2.SuperMEReplenisherBytesTotal=Bytes total: §6%s
gui.appliedenergistics2.SuperMEReplenisherBytesUnlimited=Unlimited
gui.appliedenergistics2.SuperMEReplenisherBytesUsed=Bytes used: §c%s
gui.appliedenergistics2.SuperMEReplenisherTickRate=Tick Rate
gui.appliedenergistics2.SuperMEReplenisherThreshold=Threshold
gui.appliedenergistics2.SuperMEReplenisherTarget=Target: §5%s
gui.appliedenergistics2.SuperMEReplenisherStored=Stored: §5%s
gui.appliedenergistics2.Efficiency=Efficiency
gui.appliedenergistics2.RequiredPower=Required Power
gui.appliedenergistics2.StoredPower=Stored Power
@@ -830,6 +839,7 @@ gui.tooltips.appliedenergistics2.BlockCreativeEnergyCell=§dInfinite Energy
gui.tooltips.appliedenergistics2.PartCreativeEnergy=§dInfinite Energy
gui.tooltips.appliedenergistics2.BlockCreativeEnergyController=§dInfinite Energy
gui.tooltips.appliedenergistics2.PreconfiguredPriority=Preconfigured storage priority: §f%s
gui.tooltips.appliedenergistics2.BlockSuperMEReplenisher=Only for network usage!\nEverything injected will be cached\nThen flashed in local network on Tick Rate!
# Units
gui.appliedenergistics2.units.appliedenergistics=AE
Binary file not shown.

After

Width:  |  Height:  |  Size: 614 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 610 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 610 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 805 B