diff --git a/build.gradle b/build.gradle index d90db129d1c..5e787403a3d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,4 @@ -//version: 1646409286 +//version: 1650343995 /* DO NOT CHANGE THIS FILE! @@ -568,7 +568,7 @@ publishing { artifact source: shadowJar, classifier: "" } if(!noPublishedSources) { - artifact source: sourcesJar, classifier: "src" + artifact source: sourcesJar, classifier: "sources" } artifact source: usesShadowedDependencies.toBoolean() ? shadowDevJar : devJar, classifier: "dev" if (apiPackage) { diff --git a/repositories.gradle b/repositories.gradle index 6ca2cb42f93..140ef1aab63 100644 --- a/repositories.gradle +++ b/repositories.gradle @@ -9,6 +9,7 @@ repositories { maven { name 'ic2' url 'https://maven.ic2.player.to/' + url 'https://maven2.ic2.player.to/' metadataSources { mavenPom() artifact() diff --git a/src/main/java/appeng/api/implementations/items/IStorageCell.java b/src/main/java/appeng/api/implementations/items/IStorageCell.java index 4dd8ceb2b96..c997ebf852f 100644 --- a/src/main/java/appeng/api/implementations/items/IStorageCell.java +++ b/src/main/java/appeng/api/implementations/items/IStorageCell.java @@ -28,6 +28,8 @@ import appeng.api.storage.data.IAEItemStack; import net.minecraft.item.ItemStack; +import javax.annotation.Nullable; + /** * Any item which implements this can be treated as an IMEInventory via @@ -110,7 +112,17 @@ public interface IStorageCell extends ICellWorkbenchItem boolean isStorageCell( ItemStack i ); /** + * @param i item * @return drain in ae/t this storage cell will use. */ - double getIdleDrain(); + default double getIdleDrain( @Nullable ItemStack i ) { + // provided for API backwards compatibility + return getIdleDrain(); + } + + /** + * The old idle drain API that didn't accept an ItemStack. Unused in base AE2. + * @return drain in ae/t this storage cell will use. + */ + double getIdleDrain(); } diff --git a/src/main/java/appeng/api/networking/crafting/ICraftingCPU.java b/src/main/java/appeng/api/networking/crafting/ICraftingCPU.java index 5dbc40e87af..750c2a32a83 100644 --- a/src/main/java/appeng/api/networking/crafting/ICraftingCPU.java +++ b/src/main/java/appeng/api/networking/crafting/ICraftingCPU.java @@ -27,12 +27,15 @@ import appeng.api.networking.security.BaseActionSource; import appeng.api.networking.storage.IBaseMonitor; import appeng.api.storage.data.IAEItemStack; +import appeng.api.util.WorldCoord; + +import javax.annotation.Nullable; public interface ICraftingCPU extends IBaseMonitor { - /** + /** * @return true if the CPU currently has a job. */ boolean isBusy(); @@ -56,4 +59,29 @@ public interface ICraftingCPU extends IBaseMonitor * @return an empty string or the name of the cpu. */ String getName(); + + /** + * @return final output of the current crafting operation, or null if not crafting + */ + @Nullable + default IAEItemStack getFinalOutput() + { + return null; + } + + /** + * @return remaining count of items (or other units of processing) for the current crafting job + */ + default long getRemainingItemCount() + { + return 0; + } + + /** + * @return total count of items (or other units of processing) for the current crafting job + */ + default long getStartItemCount() + { + return 0; + } } diff --git a/src/main/java/appeng/client/gui/implementations/GuiCraftingStatus.java b/src/main/java/appeng/client/gui/implementations/GuiCraftingStatus.java index 4add21585da..f9d96244e1a 100644 --- a/src/main/java/appeng/client/gui/implementations/GuiCraftingStatus.java +++ b/src/main/java/appeng/client/gui/implementations/GuiCraftingStatus.java @@ -27,8 +27,11 @@ import appeng.api.definitions.IDefinitions; import appeng.api.definitions.IParts; import appeng.api.storage.ITerminalHost; +import appeng.api.storage.data.IAEItemStack; +import appeng.client.gui.widgets.GuiScrollbar; import appeng.client.gui.widgets.GuiTabButton; import appeng.container.implementations.ContainerCraftingStatus; +import appeng.container.implementations.CraftingCPUStatus; import appeng.core.AELog; import appeng.core.localization.GuiText; import appeng.core.sync.GuiBridge; @@ -40,23 +43,35 @@ import appeng.parts.reporting.PartPatternTerminal; import appeng.parts.reporting.PartPatternTerminalEx; import appeng.parts.reporting.PartTerminal; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.GuiButton; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.item.ItemStack; import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; import java.io.IOException; +import java.util.List; public class GuiCraftingStatus extends GuiCraftingCPU { + private static final int CPU_TABLE_WIDTH = 94; + private static final int CPU_TABLE_HEIGHT = 164; + private static final int CPU_TABLE_SLOT_XOFF = 100; + private static final int CPU_TABLE_SLOT_YOFF = 0; + private static final int CPU_TABLE_SLOT_WIDTH = 67; + private static final int CPU_TABLE_SLOT_HEIGHT = 23; private final ContainerCraftingStatus status; private GuiButton selectCPU; + private GuiScrollbar cpuScrollbar; private GuiTabButton originalGuiBtn; private GuiBridge originalGui; private ItemStack myIcon = null; + private String selectedCPUName = ""; public GuiCraftingStatus( final InventoryPlayer inventoryPlayer, final ITerminalHost te ) { @@ -120,18 +135,6 @@ protected void actionPerformed( final GuiButton btn ) final boolean backwards = Mouse.isButtonDown( 1 ); - if( btn == this.selectCPU ) - { - try - { - NetworkHandler.instance.sendToServer( new PacketValueConfig( "Terminal.Cpu", backwards ? "Prev" : "Next" ) ); - } - catch( final IOException e ) - { - AELog.debug( e ); - } - } - if( btn == this.originalGuiBtn ) { NetworkHandler.instance.sendToServer( new PacketSwitchGuis( this.originalGui ) ); @@ -144,9 +147,15 @@ public void initGui() super.initGui(); this.selectCPU = new GuiButton( 0, this.guiLeft + 8, this.guiTop + this.ySize - 25, 150, 20, GuiText.CraftingCPU.getLocal() + ": " + GuiText.NoCraftingCPUs ); - // selectCPU.enabled = false; + this.selectCPU.enabled = false; this.buttonList.add( this.selectCPU ); + this.cpuScrollbar = new GuiScrollbar(); + this.cpuScrollbar.setLeft( -16 ); + this.cpuScrollbar.setTop( 19 ); + this.cpuScrollbar.setWidth( 12 ); + this.cpuScrollbar.setHeight( 137 ); + if( this.myIcon != null ) { this.buttonList.add( this.originalGuiBtn = new GuiTabButton( this.guiLeft + 213, this.guiTop - 4, this.myIcon, this.myIcon.getDisplayName(), itemRender ) ); @@ -157,28 +166,283 @@ public void initGui() @Override public void drawScreen( final int mouseX, final int mouseY, final float btn ) { + List cpus = this.status.getCPUs(); + this.selectedCPUName = null; + this.cpuScrollbar.setRange( 0, Integer.max(0, cpus.size() - 6), 1 ); + for (CraftingCPUStatus cpu : cpus) + { + if (cpu.getSerial() == this.status.selectedCpuSerial) + { + this.selectedCPUName = cpu.getName(); + } + } this.updateCPUButtonText(); super.drawScreen( mouseX, mouseY, btn ); } - private void updateCPUButtonText() + @Override + public void drawFG( int offsetX, int offsetY, int mouseX, int mouseY ) + { + super.drawFG( offsetX, offsetY, mouseX, mouseY ); + if (this.cpuScrollbar != null) + { + this.cpuScrollbar.draw( this ); + } + + List cpus = this.status.getCPUs(); + final int firstCpu = this.cpuScrollbar.getCurrentScroll(); + CraftingCPUStatus hoveredCpu = hitCpu( mouseX, mouseY ); + { + FontRenderer font = Minecraft.getMinecraft().fontRenderer; + final int TEXT_COLOR = 0x202020; + for( int i = firstCpu; i < firstCpu + 6; i++ ) + { + if( i < 0 || i >= cpus.size() ) + { + continue; + } + CraftingCPUStatus cpu = cpus.get( i ); + if( cpu == null ) + { + continue; + } + int x = -CPU_TABLE_WIDTH + 9; + int y = 19 + ( i - firstCpu ) * CPU_TABLE_SLOT_HEIGHT; + if( cpu.getSerial() == this.status.selectedCpuSerial ) + { + GL11.glColor4f( 0.0F, 0.8352F, 1.0F, 1.0F ); + } + else if( hoveredCpu != null && hoveredCpu.getSerial() == cpu.getSerial() ) + { + GL11.glColor4f( 0.65F, 0.9F, 1.0F, 1.0F ); + } else + { + GL11.glColor4f( 1.0F, 1.0F, 1.0F, 1.0F ); + } + this.bindTexture( "guis/cpu_selector.png" ); + this.drawTexturedModalRect( x, y, CPU_TABLE_SLOT_XOFF, CPU_TABLE_SLOT_YOFF, CPU_TABLE_SLOT_WIDTH, CPU_TABLE_SLOT_HEIGHT ); + GL11.glColor4f( 1.0F, 1.0F, 1.0F, 1.0F ); + + String name = cpu.getName(); + if( name == null || name.isEmpty() ) + { + name = GuiText.CPUs.getLocal() + " #" + cpu.getSerial(); + } + if( name.length() > 12 ) + { + name = name.substring( 0, 11 ) + ".."; + } + GL11.glPushMatrix(); + GL11.glTranslatef( x + 3, y + 3, 0 ); + GL11.glScalef( 0.8f, 0.8f, 1.0f ); + font.drawString( name, 0, 0, TEXT_COLOR ); + GL11.glPopMatrix(); + + GL11.glPushMatrix(); + GL11.glTranslatef( x + 3, y + 11, 0 ); + final IAEItemStack craftingStack = cpu.getCrafting(); + if( craftingStack != null ) + { + final int iconIndex = 16 * 11 + 2; + this.bindTexture( "guis/states.png" ); + final int uv_y = iconIndex / 16; + final int uv_x = iconIndex - uv_y * 16; + + GL11.glScalef( 0.5f, 0.5f, 1.0f ); + GL11.glColor4f( 1.0F, 1.0F, 1.0F, 1.0F ); + this.drawTexturedModalRect( 0, 0, uv_x * 16, uv_y * 16, 16, 16 ); + GL11.glTranslatef( 18.0f, 2.0f, 0.0f ); + String amount = Long.toString( craftingStack.getStackSize() ); + if( amount.length() > 5 ) + { + amount = amount.substring( 0, 5 ) + ".."; + } + GL11.glScalef( 1.5f, 1.5f, 1.0f ); + font.drawString( amount, 0, 0, 0x009000 ); + GL11.glPopMatrix(); + GL11.glPushMatrix(); + GL11.glTranslatef( x + CPU_TABLE_SLOT_WIDTH - 19, y + 3, 0 ); + this.drawItem( 0, 0, craftingStack.getItemStack() ); + } + else + { + final int iconIndex = 16 * 4 + 3; + this.bindTexture( "guis/states.png" ); + final int uv_y = iconIndex / 16; + final int uv_x = iconIndex - uv_y * 16; + + GL11.glScalef( 0.5f, 0.5f, 1.0f ); + GL11.glColor4f( 1.0F, 1.0F, 1.0F, 1.0F ); + this.drawTexturedModalRect( 0, 0, uv_x * 16, uv_y * 16, 16, 16 ); + GL11.glTranslatef( 18.0f, 2.0f, 0.0f ); + GL11.glScalef( 1.5f, 1.5f, 1.0f ); + font.drawString( cpu.formatStorage(), 0, 0, TEXT_COLOR ); + } + GL11.glPopMatrix(); + } + GL11.glColor4f( 1.0F, 1.0F, 1.0F, 1.0F ); + } + if( hoveredCpu != null ) + { + StringBuilder tooltip = new StringBuilder(); + String name = hoveredCpu.getName(); + if( name != null && !name.isEmpty() ) + { + tooltip.append( name ); + tooltip.append( '\n' ); + } + else + { + tooltip.append ( GuiText.CPUs.getLocal() ); + tooltip.append ( " #" ); + tooltip.append ( hoveredCpu.getSerial() ); + tooltip.append ( '\n' ); + } + IAEItemStack crafting = hoveredCpu.getCrafting(); + if( crafting != null && crafting.getStackSize() > 0 ) + { + tooltip.append( GuiText.Crafting.getLocal() ); + tooltip.append( ": " ); + tooltip.append( crafting.getStackSize() ); + tooltip.append( ' ' ); + tooltip.append( crafting.getItemStack().getDisplayName() ); + tooltip.append( '\n' ); + tooltip.append( hoveredCpu.getRemainingItems() ); + tooltip.append( " / " ); + tooltip.append( hoveredCpu.getTotalItems() ); + tooltip.append( '\n' ); + } + if ( hoveredCpu.getStorage() > 0 ) + { + tooltip.append( GuiText.Bytes.getLocal() ); + tooltip.append( ": " ); + tooltip.append( hoveredCpu.formatStorage() ); + tooltip.append( '\n' ); + } + if ( hoveredCpu.getCoprocessors() > 0 ) + { + tooltip.append( GuiText.CoProcessors.getLocal() ); + tooltip.append( ": " ); + tooltip.append( hoveredCpu.getCoprocessors() ); + tooltip.append( '\n' ); + } + if (tooltip.length() > 0) + { + this.drawTooltip( mouseX - offsetX, mouseY - offsetY, 0, tooltip.toString() ); + } + } + } + + @Override + public void drawBG( int offsetX, int offsetY, int mouseX, int mouseY ) + { + super.drawBG( offsetX, offsetY, mouseX, mouseY ); + this.bindTexture( "guis/cpu_selector.png" ); + this.drawTexturedModalRect( offsetX - CPU_TABLE_WIDTH, offsetY, 0, 0, CPU_TABLE_WIDTH, CPU_TABLE_HEIGHT ); + } + + @Override + protected void mouseClicked( int xCoord, int yCoord, int btn ) + { + super.mouseClicked( xCoord, yCoord, btn ); + if( cpuScrollbar != null ) + { + cpuScrollbar.click( this, xCoord - this.guiLeft, yCoord - this.guiTop ); + } + CraftingCPUStatus hit = hitCpu( xCoord, yCoord ); + if (hit != null) + { + try + { + NetworkHandler.instance.sendToServer( new PacketValueConfig( "Terminal.Cpu.Set", Integer.toString( hit.getSerial() ) ) ); + } + catch( final IOException e ) + { + AELog.debug( e ); + } + } + } + + @Override + protected void mouseClickMove( int x, int y, int c, long d ) + { + super.mouseClickMove( x, y, c, d ); + if( cpuScrollbar != null ) + { + cpuScrollbar.click( this, x - this.guiLeft, y - this.guiTop ); + } + } + + @Override + public void handleMouseInput() + { + int x = Mouse.getEventX() * this.width / this.mc.displayWidth; + int y = this.height - Mouse.getEventY() * this.height / this.mc.displayHeight - 1; + x -= guiLeft - CPU_TABLE_WIDTH; + y -= guiTop; + int dwheel = Mouse.getEventDWheel(); + if (x >= 9 && x < CPU_TABLE_SLOT_WIDTH + 9 && y >= 19 && y < 19 + 6 * CPU_TABLE_SLOT_HEIGHT) + { + if (this.cpuScrollbar != null && dwheel != 0) + { + this.cpuScrollbar.wheel( dwheel ); + return; + } + } + super.handleMouseInput(); + } + + public boolean hideItemPanelSlot( int x, int y, int w, int h ) + { + x -= guiLeft - CPU_TABLE_WIDTH; + y -= guiTop; + boolean xInside = + ( x >= 0 && x < CPU_TABLE_SLOT_WIDTH + 9 ) + || ( x + w >= 0 && x + w < CPU_TABLE_SLOT_WIDTH + 9 ) + || ( x <= 0 && x + w >= CPU_TABLE_SLOT_WIDTH + 9 ); + boolean yInside = + ( y >= 0 && y < 19 + 6 * CPU_TABLE_SLOT_HEIGHT ) + || ( y + h >= 0 && y + h < 19 + 6 * CPU_TABLE_SLOT_HEIGHT ) + || ( y < 0 && y + h >= 19 + 6 * CPU_TABLE_SLOT_HEIGHT ); + if( xInside && yInside ) + { + return true; + } + return false; + } + + private CraftingCPUStatus hitCpu( int x, int y ) + { + x -= guiLeft - CPU_TABLE_WIDTH; + y -= guiTop; + if (!(x >= 9 && x < CPU_TABLE_SLOT_WIDTH + 9 && y >= 19 && y < 19 + 6 * CPU_TABLE_SLOT_HEIGHT)) + { + return null; + } + int scrollOffset = this.cpuScrollbar != null ? this.cpuScrollbar.getCurrentScroll() : 0; + int cpuId = scrollOffset + (y - 19) / CPU_TABLE_SLOT_HEIGHT; + List cpus = this.status.getCPUs(); + return (cpuId >= 0 && cpuId < cpus.size()) ? cpus.get(cpuId) : null; + } + + private void updateCPUButtonText() { String btnTextText = GuiText.NoCraftingJobs.getLocal(); - if( this.status.selectedCpu >= 0 )// && status.selectedCpu < status.cpus.size() ) + if( this.status.selectedCpuSerial >= 0 ) { - if( this.status.myName.length() > 0 ) + if( this.selectedCPUName != null && this.selectedCPUName.length() > 0 ) { - final String name = this.status.myName.substring( 0, Math.min( 20, this.status.myName.length() ) ); + final String name = this.selectedCPUName.substring( 0, Math.min( 20, this.selectedCPUName.length() ) ); btnTextText = GuiText.CPUs.getLocal() + ": " + name; } else { - btnTextText = GuiText.CPUs.getLocal() + ": #" + this.status.selectedCpu; + btnTextText = GuiText.CPUs.getLocal() + ": #" + this.status.selectedCpuSerial; } } - if( this.status.noCPU ) + if( this.status.getCPUs().isEmpty() ) { btnTextText = GuiText.NoCraftingJobs.getLocal(); } @@ -191,4 +455,9 @@ protected String getGuiDisplayName( final String in ) { return in; // the cup name is on the button } + + public void postCPUUpdate( CraftingCPUStatus[] cpus ) + { + this.status.postCPUUpdate(cpus); + } } diff --git a/src/main/java/appeng/container/implementations/ContainerCraftingCPU.java b/src/main/java/appeng/container/implementations/ContainerCraftingCPU.java index d7d9575e37b..320de674378 100644 --- a/src/main/java/appeng/container/implementations/ContainerCraftingCPU.java +++ b/src/main/java/appeng/container/implementations/ContainerCraftingCPU.java @@ -30,6 +30,7 @@ import appeng.api.storage.IMEMonitorHandlerReceiver; import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IItemList; +import appeng.api.util.WorldCoord; import appeng.container.AEBaseContainer; import appeng.container.guisync.GuiSync; import appeng.core.AELog; diff --git a/src/main/java/appeng/container/implementations/ContainerCraftingStatus.java b/src/main/java/appeng/container/implementations/ContainerCraftingStatus.java index 0bea6be6e1a..c46b42e0af7 100644 --- a/src/main/java/appeng/container/implementations/ContainerCraftingStatus.java +++ b/src/main/java/appeng/container/implementations/ContainerCraftingStatus.java @@ -19,29 +19,36 @@ package appeng.container.implementations; +import appeng.api.networking.IGrid; import appeng.api.networking.crafting.ICraftingCPU; import appeng.api.networking.crafting.ICraftingGrid; import appeng.api.storage.ITerminalHost; import appeng.container.guisync.GuiSync; +import appeng.core.AELog; +import appeng.core.sync.network.NetworkHandler; +import appeng.core.sync.packets.PacketCraftingCPUsUpdate; import appeng.util.Platform; +import com.google.common.collect.ImmutableCollection; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.entity.player.InventoryPlayer; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.io.IOException; +import java.util.*; public class ContainerCraftingStatus extends ContainerCraftingCPU { - private final List cpus = new ArrayList(); + private ImmutableSet lastCpuSet = null; + private List cpus = new ArrayList(); + private final WeakHashMap cpuSerialMap = new WeakHashMap<>(); + private int nextCpuSerial = 1; + private int lastUpdate = 0; @GuiSync( 5 ) - public int selectedCpu = -1; - @GuiSync( 6 ) - public boolean noCPU = true; - @GuiSync( 7 ) - public String myName = ""; + public int selectedCpuSerial = -1; public ContainerCraftingStatus( final InventoryPlayer ip, final ITerminalHost te ) { @@ -51,146 +58,134 @@ public ContainerCraftingStatus( final InventoryPlayer ip, final ITerminalHost te @Override public void detectAndSendChanges() { - if( Platform.isServer() && this.getNetwork() != null ) + IGrid network = this.getNetwork(); + if( Platform.isServer() && network != null ) { - final ICraftingGrid cc = this.getNetwork().getCache( ICraftingGrid.class ); + final ICraftingGrid cc = network.getCache( ICraftingGrid.class ); final ImmutableSet cpuSet = cc.getCpus(); - - int matches = 0; - boolean changed = false; - for( final ICraftingCPU c : cpuSet ) - { - boolean found = false; - for( final CraftingCPURecord ccr : this.cpus ) - { - if( ccr.getCpu() == c ) - { - found = true; - } - } - - final boolean matched = this.cpuMatches( c ); - - if( matched ) - { - matches++; - } - - if( found == !matched ) - { - changed = true; - } - } - - if( changed || this.cpus.size() != matches ) - { - this.cpus.clear(); - for( final ICraftingCPU c : cpuSet ) - { - if( this.cpuMatches( c ) ) - { - this.cpus.add( new CraftingCPURecord( c.getAvailableStorage(), c.getCoProcessors(), c ) ); - } - } - - this.sendCPUs(); - } - - this.noCPU = this.cpus.isEmpty(); + // Update at least once a second + ++lastUpdate; + if (!cpuSet.equals( lastCpuSet ) || lastUpdate > 20) { + lastUpdate = 0; + lastCpuSet = cpuSet; + updateCpuList(); + sendCPUs(); + } } + // Clear selection if CPU is no longer in list + if (selectedCpuSerial != -1) { + if (cpus.stream().noneMatch(c -> c.getSerial() == selectedCpuSerial)) { + selectCPU(-1); + } + } + + // Select a suitable CPU if none is selected + if (selectedCpuSerial == -1) { + // Try busy CPUs first + for (CraftingCPUStatus cpu : cpus) { + if (cpu.getRemainingItems() > 0) { + selectCPU(cpu.getSerial()); + break; + } + } + // If we couldn't find a busy one, just select the first + if (selectedCpuSerial == -1 && !cpus.isEmpty()) { + selectCPU(cpus.get(0).getSerial()); + } + } + super.detectAndSendChanges(); } - private boolean cpuMatches( final ICraftingCPU c ) + private static final Comparator CPU_COMPARATOR = Comparator + .comparing((CraftingCPUStatus e) -> e.getName() == null || e.getName().isEmpty()) + .thenComparing(e -> e.getName() != null ? e.getName() : "") + .thenComparingInt(CraftingCPUStatus::getSerial); + + private void updateCpuList() + { + this.cpus.clear(); + for (ICraftingCPU cpu : lastCpuSet) + { + int serial = getOrAssignCpuSerial(cpu); + this.cpus.add( new CraftingCPUStatus( cpu, serial ) ); + } + this.cpus.sort(CPU_COMPARATOR); + } + + private int getOrAssignCpuSerial( ICraftingCPU cpu ) + { + return cpuSerialMap.computeIfAbsent( cpu, unused -> nextCpuSerial++ ); + } + + private boolean cpuMatches( final ICraftingCPU c ) { return c.isBusy(); } - - private void findByName() - { - int index = 0; - for (CraftingCPURecord c: cpus) - { - if (this.myName.equals(c.getName())) - { - this.selectedCpu = index; - break; - } - ++index; - } - } private void sendCPUs() { - Collections.sort( this.cpus ); - - if( this.selectedCpu >= this.cpus.size() ) - this.selectedCpu = -1; - - if( this.selectedCpu == -1 ) - this.myName = ""; - - if( this.myName != "" ) - findByName(); - - if( this.selectedCpu == -1 && this.cpus.size() > 0 ) - { - this.selectedCpu = 0; - } - - if( this.selectedCpu != -1 ) - { - this.myName = this.cpus.get( this.selectedCpu ).getName(); - } - - if( this.selectedCpu != -1 ) - { - if( this.cpus.get( this.selectedCpu ).getCpu() != this.getMonitor() ) - { - this.setCPU( this.cpus.get( this.selectedCpu ).getCpu() ); - } - } - else - { - this.setCPU( null ); - } - } - - public void cycleCpu( final boolean next ) + final PacketCraftingCPUsUpdate update; + for( final Object player : this.crafters ) + { + if( player instanceof EntityPlayerMP ) + { + try + { + NetworkHandler.instance.sendTo( new PacketCraftingCPUsUpdate( this.cpus ), (EntityPlayerMP) player ); + } + catch( IOException e ) + { + AELog.debug( e ); + } + } + } + } + + public void selectCPU( int serial ) { - if( next ) - { - this.selectedCpu++; - } - else - { - this.selectedCpu--; - } - - if( this.selectedCpu < -1 ) - { - this.selectedCpu = this.cpus.size() - 1; - } - else if( this.selectedCpu >= this.cpus.size() ) - { - this.selectedCpu = -1; - } + if (Platform.isServer()) + { + if( serial < -1 ) + { + serial = -1; + } + + final int searchedSerial = serial; + if( serial > -1 && cpus.stream().noneMatch(c -> c.getSerial() == searchedSerial) ) + { + serial = -1; + } + + ICraftingCPU newSelectedCpu = null; + if( serial != -1 ) + { + for( ICraftingCPU cpu : lastCpuSet ) + { + if( cpuSerialMap.getOrDefault( cpu, -1 ) == serial ) + { + newSelectedCpu = cpu; + break; + } + } + } + + if( newSelectedCpu != getMonitor() ) + { + this.selectedCpuSerial = serial; + setCPU( newSelectedCpu ); + } + } + } - if( this.selectedCpu == -1 && this.cpus.size() > 0 ) - { - this.selectedCpu = 0; - } + public List getCPUs() + { + return Collections.unmodifiableList( cpus ); + } - if( this.selectedCpu == -1 ) - { - this.myName = ""; - this.setCPU( null ); - } - else - { - this.myName = this.cpus.get( this.selectedCpu ).getName(); - this.setCPU( this.cpus.get( this.selectedCpu ).getCpu() ); - } - } + public void postCPUUpdate( CraftingCPUStatus[] cpus ) + { + this.cpus = Arrays.asList( cpus ); + } } diff --git a/src/main/java/appeng/container/implementations/CraftingCPUStatus.java b/src/main/java/appeng/container/implementations/CraftingCPUStatus.java new file mode 100644 index 00000000000..22503ba80f0 --- /dev/null +++ b/src/main/java/appeng/container/implementations/CraftingCPUStatus.java @@ -0,0 +1,199 @@ +package appeng.container.implementations; + +import appeng.api.networking.crafting.ICraftingCPU; +import appeng.api.storage.data.IAEItemStack; +import appeng.util.ItemSorters; +import appeng.util.item.AEItemStack; +import io.netty.buffer.ByteBuf; +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTTagCompound; + +import javax.annotation.Nullable; +import java.io.*; + +/** + * Summary status for the crafting CPU selection widget + */ +public class CraftingCPUStatus implements Comparable +{ + @Nullable + private final ICraftingCPU serverCluster; + private final String name; + private final int serial; + private final long storage; + private final long coprocessors; + private final long totalItems; + private final long remainingItems; + private final IAEItemStack crafting; + + public CraftingCPUStatus( ) + { + this.serverCluster = null; + this.name = "ERROR"; + this.serial = 0; + this.storage = 0; + this.coprocessors = 0; + this.totalItems = 0; + this.remainingItems = 0; + this.crafting = null; + } + + public CraftingCPUStatus( ICraftingCPU cluster, int serial ) + { + this.serverCluster = cluster; + this.name = cluster.getName(); + this.serial = serial; + if (cluster.isBusy()) + { + crafting = cluster.getFinalOutput(); + totalItems = cluster.getStartItemCount(); + remainingItems = cluster.getRemainingItemCount(); + } + else + { + crafting = null; + totalItems = 0; + remainingItems = 0; + } + this.storage = cluster.getAvailableStorage(); + this.coprocessors = cluster.getCoProcessors(); + } + + public CraftingCPUStatus( NBTTagCompound i ) + { + this.serverCluster = null; + this.name = i.getString( "name" ); + this.serial = i.getInteger( "serial" ); + this.storage = i.getLong("storage"); + this.coprocessors = i.getLong("coprocessors"); + this.totalItems = i.getLong("totalItems"); + this.remainingItems = i.getLong("remainingItems"); + this.crafting = i.hasKey( "crafting" ) ? AEItemStack.loadItemStackFromNBT( i.getCompoundTag( "crafting" ) ) : null; + } + + public CraftingCPUStatus(ByteBuf packet) throws IOException + { + this(readNBTFromPacket( packet )); + } + + private static NBTTagCompound readNBTFromPacket(ByteBuf packet) throws IOException + { + final int size = packet.readInt(); + final byte[] tagBytes = new byte[size]; + packet.readBytes( tagBytes ); + final ByteArrayInputStream di = new ByteArrayInputStream( tagBytes ); + return CompressedStreamTools.read( new DataInputStream( di )); + } + + public void writeToNBT( NBTTagCompound i ) + { + if (name != null && !name.isEmpty()) + { + i.setString( "name", name ); + } + i.setInteger( "serial", serial ); + i.setLong( "storage", storage ); + i.setLong( "coprocessors", coprocessors ); + i.setLong( "totalItems", totalItems ); + i.setLong( "remainingItems", remainingItems ); + if (crafting != null) + { + NBTTagCompound stack = new NBTTagCompound(); + crafting.writeToNBT( stack ); + i.setTag( "crafting", stack ); + } + } + + public void writeToPacket( ByteBuf i ) throws IOException + { + final ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + final DataOutputStream data = new DataOutputStream( bytes ); + + NBTTagCompound tag = new NBTTagCompound(); + this.writeToNBT( tag ); + CompressedStreamTools.write( tag, data ); + + final byte[] tagBytes = bytes.toByteArray(); + final int size = tagBytes.length; + + i.writeInt( size ); + i.writeBytes( tagBytes ); + } + + @Nullable + public ICraftingCPU getServerCluster() + { + return serverCluster; + } + + public String getName() + { + return name; + } + + public int getSerial() + { + return serial; + } + + public long getStorage() + { + return storage; + } + + public long getCoprocessors() + { + return coprocessors; + } + + public long getTotalItems() + { + return totalItems; + } + + public long getRemainingItems() + { + return remainingItems; + } + + public IAEItemStack getCrafting() + { + return crafting; + } + + @Override + public int compareTo( CraftingCPUStatus o ) + { + final int a = ItemSorters.compareLong( o.getCoprocessors(), this.getCoprocessors() ); + if( a != 0 ) + { + return a; + } + return ItemSorters.compareLong( o.getStorage(), this.getStorage() ); + } + + public String formatStorage() + { + long val = getStorage(); + if (val > 4_000_000_000_000L) + { + return String.format("%dT", val / 1024 / 1024 / 1024 / 1024); + } + else if (val > 4_000_000_000L) + { + return String.format("%dG", val / 1024 / 1024 / 1024); + } + else if (val > 4_000_000L) + { + return String.format("%dM", val / 1024 / 1024); + } + else if (val > 4_000L) + { + return String.format("%dk", val / 1024); + } + else + { + return Long.toString( val ); + } + } +} diff --git a/src/main/java/appeng/core/sync/AppEngPacketHandlerBase.java b/src/main/java/appeng/core/sync/AppEngPacketHandlerBase.java index 3757cbf8f14..aca334855a6 100644 --- a/src/main/java/appeng/core/sync/AppEngPacketHandlerBase.java +++ b/src/main/java/appeng/core/sync/AppEngPacketHandlerBase.java @@ -81,7 +81,9 @@ public enum PacketTypes PACKET_COMPRESSED_NBT( PacketCompressedNBT.class ), - PACKET_PAINTED_ENTITY( PacketPaintedEntity.class ); + PACKET_PAINTED_ENTITY( PacketPaintedEntity.class ), + + PACKET_CRAFTING_CPUS_UPDATE( PacketCraftingCPUsUpdate.class ); private final Class packetClass; private final Constructor packetConstructor; diff --git a/src/main/java/appeng/core/sync/packets/PacketCraftingCPUsUpdate.java b/src/main/java/appeng/core/sync/packets/PacketCraftingCPUsUpdate.java new file mode 100644 index 00000000000..7131e80b8b4 --- /dev/null +++ b/src/main/java/appeng/core/sync/packets/PacketCraftingCPUsUpdate.java @@ -0,0 +1,63 @@ +package appeng.core.sync.packets; + +import appeng.client.gui.implementations.GuiCraftingStatus; +import appeng.container.implementations.CraftingCPUStatus; +import appeng.core.sync.AppEngPacket; +import appeng.core.sync.network.INetworkInfo; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.entity.player.EntityPlayer; + +import java.io.IOException; +import java.util.Collection; + +public class PacketCraftingCPUsUpdate extends AppEngPacket +{ + private final CraftingCPUStatus[] cpus; + + public PacketCraftingCPUsUpdate( final ByteBuf stream ) + { + int count = stream.readInt(); + cpus = new CraftingCPUStatus[count]; + for( int i = 0; i < count; i++ ) + { + try + { + cpus[i] = new CraftingCPUStatus( stream ); + } + catch( IOException e ) + { + cpus[i] = new CraftingCPUStatus( ); + } + } + } + + public PacketCraftingCPUsUpdate( final Collection cpus ) throws IOException + { + this.cpus = cpus.toArray( new CraftingCPUStatus[0] ); + + final ByteBuf data = Unpooled.buffer(); + data.writeInt( this.getPacketID() ); + data.writeInt( this.cpus.length ); + for( CraftingCPUStatus cpu : this.cpus ) + { + cpu.writeToPacket( data ); + } + this.configureWrite( data ); + } + + @Override + public void clientPacketData( final INetworkInfo network, final AppEngPacket packet, final EntityPlayer player ) + { + final GuiScreen gs = Minecraft.getMinecraft().currentScreen; + + if( gs instanceof GuiCraftingStatus ) + { + GuiCraftingStatus gui = (GuiCraftingStatus) gs; + gui.postCPUUpdate( this.cpus ); + } + + } +} diff --git a/src/main/java/appeng/core/sync/packets/PacketValueConfig.java b/src/main/java/appeng/core/sync/packets/PacketValueConfig.java index 1b3dcad0e31..acd276f30d4 100644 --- a/src/main/java/appeng/core/sync/packets/PacketValueConfig.java +++ b/src/main/java/appeng/core/sync/packets/PacketValueConfig.java @@ -87,10 +87,10 @@ public void serverPacketData( final INetworkInfo manager, final AppEngPacket pac final IMouseWheelItem si = (IMouseWheelItem) is.getItem(); si.onWheel( is, this.Value.equals( "WheelUp" ) ); } - else if( this.Name.equals( "Terminal.Cpu" ) && c instanceof ContainerCraftingStatus ) + else if( this.Name.equals( "Terminal.Cpu.Set" ) && c instanceof ContainerCraftingStatus ) { final ContainerCraftingStatus qk = (ContainerCraftingStatus) c; - qk.cycleCpu( this.Value.equals( "Next" ) ); + qk.selectCPU( Integer.parseInt( this.Value ) ); } else if( this.Name.equals( "Terminal.Cpu" ) && c instanceof ContainerCraftConfirm ) { diff --git a/src/main/java/appeng/integration/modules/NEIHelpers/NEIGuiHandler.java b/src/main/java/appeng/integration/modules/NEIHelpers/NEIGuiHandler.java index 9a08589b5fd..e66de50db5e 100644 --- a/src/main/java/appeng/integration/modules/NEIHelpers/NEIGuiHandler.java +++ b/src/main/java/appeng/integration/modules/NEIHelpers/NEIGuiHandler.java @@ -1,5 +1,6 @@ package appeng.integration.modules.NEIHelpers; +import appeng.client.gui.implementations.GuiCraftingStatus; import appeng.client.gui.implementations.GuiMEMonitorable; import codechicken.nei.api.INEIGuiAdapter; import net.minecraft.client.gui.inventory.GuiContainer; @@ -24,4 +25,14 @@ public boolean handleDragNDrop(GuiContainer gui, int mousex, int mousey, ItemSta } return super.handleDragNDrop(gui, mousex, mousey, draggedStack, button); } + + @Override + public boolean hideItemPanelSlot( GuiContainer gui, int x, int y, int w, int h ) + { + if (gui instanceof GuiCraftingStatus ) + { + return ( (GuiCraftingStatus) gui ).hideItemPanelSlot( x, y, w, h ); + } + return false; + } } diff --git a/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java b/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java index 6c6a4283576..0ad508f6375 100644 --- a/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java +++ b/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java @@ -106,6 +106,12 @@ public CraftingCPUCluster( final WorldCoord min, final WorldCoord max ) this.max = max; } + @Override + public IAEItemStack getFinalOutput() + { + return finalOutput; + } + public boolean isDestroyed() { return this.isDestroyed; @@ -1316,11 +1322,13 @@ public long getElapsedTime() return this.elapsedTime; } + @Override public long getRemainingItemCount() { return this.remainingItemCount; } + @Override public long getStartItemCount() { return this.startItemCount; diff --git a/src/main/java/appeng/me/storage/CellInventory.java b/src/main/java/appeng/me/storage/CellInventory.java index 9a00a7c9a7d..794ce636bcd 100644 --- a/src/main/java/appeng/me/storage/CellInventory.java +++ b/src/main/java/appeng/me/storage/CellInventory.java @@ -492,7 +492,7 @@ public ItemStack getItemStack() @Override public double getIdleDrain() { - return this.cellType.getIdleDrain(); + return this.cellType.getIdleDrain(this.cellItem); } @Override diff --git a/src/main/resources/assets/appliedenergistics2/textures/guis/cpu_selector.png b/src/main/resources/assets/appliedenergistics2/textures/guis/cpu_selector.png new file mode 100644 index 00000000000..3c898c43760 Binary files /dev/null and b/src/main/resources/assets/appliedenergistics2/textures/guis/cpu_selector.png differ