From 244e7fb4f8707a4c3458b572ae3a6cc16633b5dc Mon Sep 17 00:00:00 2001 From: asdflj <854865755@qq.com> Date: Fri, 11 Nov 2022 13:47:43 +0800 Subject: [PATCH] Level Maintainer add control button Level Maintainer add oc support fix Level Maintainer render error --- .../github/client/gui/GuiFCImgButton.java | 59 +++-- .../github/client/gui/GuiLevelMaintainer.java | 189 ++++++++++------ .../container/ContainerLevelMaintainer.java | 9 - .../render/RenderBlockLevelMaintainer.java | 36 +++ .../client/textures/FCPartsTexture.java | 2 +- .../common/block/BlockLevelMaintainer.java | 9 + .../common/tile/TileLevelMaintainer.java | 129 ++++++++++- .../opencomputers/DriverLevelMaintainer.java | 212 ++++++++++++++++++ .../crossmod/opencomputers/OCDriverInit.java | 2 + .../network/CPacketLevelMaintainer.java | 77 +++++-- .../resources/assets/ae2fc/lang/en_US.lang | 5 +- .../resources/assets/ae2fc/lang/zh_CN.lang | 5 +- ...Active.png => level_maintainer_active.png} | Bin .../assets/ae2fc/textures/gui/states.png | Bin 1106 -> 1695 bytes 14 files changed, 592 insertions(+), 142 deletions(-) create mode 100644 src/main/java/com/glodblock/github/client/render/RenderBlockLevelMaintainer.java create mode 100644 src/main/java/com/glodblock/github/crossmod/opencomputers/DriverLevelMaintainer.java rename src/main/resources/assets/ae2fc/textures/blocks/{level_maintainerActive.png => level_maintainer_active.png} (100%) diff --git a/src/main/java/com/glodblock/github/client/gui/GuiFCImgButton.java b/src/main/java/com/glodblock/github/client/gui/GuiFCImgButton.java index c5038af9..60bbca6d 100644 --- a/src/main/java/com/glodblock/github/client/gui/GuiFCImgButton.java +++ b/src/main/java/com/glodblock/github/client/gui/GuiFCImgButton.java @@ -40,16 +40,21 @@ public class GuiFCImgButton extends GuiButton implements ITooltip { this.registerApp(2, "FORCE_PRIO", "DO_PRIO", "prio"); this.registerApp(3, "NOT_PRIO", "DONT_PRIO", "not_prio"); this.registerApp(4, "SUBMIT", "SUBMIT", "submit"); + this.registerApp(6, "DISABLE", "DISABLE", "disable"); + this.registerApp(7, "ENABLE", "ENABLE", "enable"); } } - private void registerApp(final int iconIndex, final String setting, final String val, final String title ) - { + private void registerApp(final int iconIndex, final String setting, final String val, final String title ) { final ButtonAppearance a = new ButtonAppearance(); a.displayName = StatCollector.translateToLocal(prefix + title); - a.displayValue = StatCollector.translateToLocal(prefix + title + ".hint"); + if (StatCollector.translateToLocal(prefix + title + ".hint").equals(prefix + title + ".hint")) { + a.displayValue = null; + } else { + a.displayValue = StatCollector.translateToLocal(prefix + title + ".hint"); + } a.index = iconIndex; - appearances.put( new EnumPair( setting, val ), a ); + appearances.put(new EnumPair(setting, val), a); } public void setVisibility( final boolean vis ) @@ -157,39 +162,31 @@ public class GuiFCImgButton extends GuiButton implements ITooltip { displayValue = buttonAppearance.displayValue; } - if( displayName != null ) - { - String name = StatCollector.translateToLocal( displayName ); - String value = StatCollector.translateToLocal( displayValue ); - - if( name == null || name.isEmpty() ) - { + if( displayName != null ) { + String name = StatCollector.translateToLocal(displayName); + if (name == null || name.isEmpty()) { name = displayName; } - if( value == null || value.isEmpty() ) - { - value = displayValue; - } + if (displayValue != null) { + String value = StatCollector.translateToLocal(displayValue); - if( this.fillVar != null ) - { - value = COMPILE.matcher( value ).replaceFirst( this.fillVar ); - } + if (this.fillVar != null) { + value = COMPILE.matcher(value).replaceFirst(this.fillVar); + } - value = PATTERN_NEW_LINE.matcher( value ).replaceAll( "\n" ); - final StringBuilder sb = new StringBuilder( value ); + value = PATTERN_NEW_LINE.matcher(value).replaceAll("\n"); + final StringBuilder sb = new StringBuilder(value); - int i = sb.lastIndexOf( "\n" ); - if( i <= 0 ) - { - i = 0; + int i = sb.lastIndexOf("\n"); + if (i <= 0) { + i = 0; + } + while (i + 30 < sb.length() && (i = sb.lastIndexOf(" ", i + 30)) != -1) { + sb.replace(i, i + 1, "\n"); + } + return name + '\n' + sb; } - while( i + 30 < sb.length() && ( i = sb.lastIndexOf( " ", i + 30 ) ) != -1 ) - { - sb.replace( i, i + 1, "\n" ); - } - - return name + '\n' + sb; + return name; } return null; } diff --git a/src/main/java/com/glodblock/github/client/gui/GuiLevelMaintainer.java b/src/main/java/com/glodblock/github/client/gui/GuiLevelMaintainer.java index b7f4468c..ff6cbefd 100644 --- a/src/main/java/com/glodblock/github/client/gui/GuiLevelMaintainer.java +++ b/src/main/java/com/glodblock/github/client/gui/GuiLevelMaintainer.java @@ -37,8 +37,7 @@ public class GuiLevelMaintainer extends AEBaseGui implements INEIGuiHandler { private static final ResourceLocation TEX_BG = FluidCraft.resource("textures/gui/level_maintainer.png"); private final ContainerLevelMaintainer cont; - private final Widget[] qtyInputs = new Widget[TileLevelMaintainer.REQ_COUNT]; - private final Widget[] batchInputs = new Widget[TileLevelMaintainer.REQ_COUNT]; + private final Component[] component = new Component[TileLevelMaintainer.REQ_COUNT]; private final MouseRegionManager mouseRegions = new MouseRegionManager(this); private final AppEngRenderItem stackSizeRenderer = Ae2ReflectClient.getStackSizeRenderer(this); private TileLevelMaintainer tile; @@ -56,19 +55,19 @@ public class GuiLevelMaintainer extends AEBaseGui implements INEIGuiHandler { for (IAEItemStack is : list) { long size = is.getItemStack().getTagCompound().getLong("Batch"); int i = is.getItemStack().getTagCompound().getInteger("Index"); - qtyInputs[i].textField.setText(String.valueOf(is.getStackSize())); - batchInputs[i].textField.setText(String.valueOf(size)); + boolean isEnable = is.getItemStack().getTagCompound().getBoolean("Enable"); + component[i].getQty().textField.setText(String.valueOf(is.getStackSize())); + component[i].getBatch().textField.setText(String.valueOf(size)); + component[i].setEnable(isEnable); } } public void drawScreen(final int mouseX, final int mouseY, final float btn) { super.drawScreen(mouseX, mouseY, btn); if (ModAndClassUtil.isSearchBar) { - for (Widget i : qtyInputs) { - handleTooltip(mouseX, mouseY, i.textField.new TooltipProvider()); - } - for (Widget i : batchInputs) { - handleTooltip(mouseX, mouseY, i.textField.new TooltipProvider()); + for (Component com : this.component) { + handleTooltip(mouseX, mouseY, com.getQty().textField.new TooltipProvider()); + handleTooltip(mouseX, mouseY, com.getBatch().textField.new TooltipProvider()); } } } @@ -76,19 +75,21 @@ public class GuiLevelMaintainer extends AEBaseGui implements INEIGuiHandler { public void initGui() { super.initGui(); for (int i = 0; i < TileLevelMaintainer.REQ_COUNT; i++) { - qtyInputs[i] = new Widget( - new FCGuiTextField(this.fontRendererObj, guiLeft + 37, guiTop + 21 + 20 * i, 52, 16), - new GuiFCImgButton(guiLeft + 37 + 47, guiTop + 20 + 20 * i, "SUBMIT", "SUBMIT"), I18n.format(NameConst.TT_REQUEST_SIZE), - i, 0); - this.buttonList.add(qtyInputs[i].btn()); - batchInputs[i] = new Widget( - new FCGuiTextField(this.fontRendererObj, guiLeft + 100, guiTop + 21 + 20 * i, 52, 16), - new GuiFCImgButton(guiLeft + 100 + 47, guiTop + 20 + 20 * i, "SUBMIT", "SUBMIT"), I18n.format(NameConst.TT_BATCH_SIZE), - i, 1 + component[i] = new Component( + new Widget( + new FCGuiTextField(this.fontRendererObj, guiLeft + 37, guiTop + 21 + 20 * i, 52, 16), + new GuiFCImgButton(guiLeft + 37 + 47, guiTop + 20 + 20 * i, "SUBMIT", "SUBMIT"), I18n.format(NameConst.TT_REQUEST_SIZE), + i, "TileLevelMaintainer.Quantity"), + new Widget( + new FCGuiTextField(this.fontRendererObj, guiLeft + 100, guiTop + 21 + 20 * i, 52, 16), + new GuiFCImgButton(guiLeft + 100 + 47, guiTop + 20 + 20 * i, "SUBMIT", "SUBMIT"), I18n.format(NameConst.TT_BATCH_SIZE), + i, "TileLevelMaintainer.Batch"), + new GuiFCImgButton(guiLeft + 4, guiTop + 23 + 20 * i, "ENABLE", "ENABLE"), + new GuiFCImgButton(guiLeft + 4, guiTop + 23 + 20 * i, "DISABLE", "DISABLE"), + this.buttonList ); - this.buttonList.add(batchInputs[i].btn()); } - FluidCraft.proxy.netHandler.sendToServer(new CPacketLevelMaintainer(-1)); + FluidCraft.proxy.netHandler.sendToServer(new CPacketLevelMaintainer("TileLevelMaintainer.refresh")); } @Override @@ -96,8 +97,7 @@ public class GuiLevelMaintainer extends AEBaseGui implements INEIGuiHandler { mc.getTextureManager().bindTexture(TEX_BG); drawTexturedModalRect(offsetX, offsetY, 0, 0, 176, ySize); for (int i = 0; i < TileLevelMaintainer.REQ_COUNT; i++) { - qtyInputs[i].draw(); - batchInputs[i].draw(); + this.component[i].draw(); } } @@ -119,8 +119,8 @@ public class GuiLevelMaintainer extends AEBaseGui implements INEIGuiHandler { super.func_146977_a(new SlotSingleItem(slot)); if (stack == null) return true; IAEItemStack fake = stack.copy(); - if (this.qtyInputs[slot.getSlotIndex()].textField.getText().matches("[0-9]+")) { - fake.setStackSize(Long.parseLong(this.qtyInputs[slot.getSlotIndex()].textField.getText())); + if (this.component[slot.getSlotIndex()].getQty().textField.getText().matches("[0-9]+")) { + fake.setStackSize(Long.parseLong(this.component[slot.getSlotIndex()].getQty().textField.getText())); } else { fake.setStackSize(0); } @@ -137,18 +137,11 @@ public class GuiLevelMaintainer extends AEBaseGui implements INEIGuiHandler { if (input != null) { input.setFocused(false); } - for (Widget i : qtyInputs) { - if (i.textField.isMouseIn(xCoord, yCoord)) { - i.textField.setFocused(true); - this.input = i.textField; - super.mouseClicked(xCoord, yCoord, btn); - return; - } - } - for (Widget i : batchInputs) { - if (i.textField.isMouseIn(xCoord, yCoord)) { - i.textField.setFocused(true); - this.input = i.textField; + for (Component com : this.component) { + FCGuiTextField textField = com.isMouseIn(xCoord, yCoord); + if (textField != null) { + textField.setFocused(true); + this.input = textField; super.mouseClicked(xCoord, yCoord, btn); return; } @@ -169,7 +162,7 @@ public class GuiLevelMaintainer extends AEBaseGui implements INEIGuiHandler { this.input.textboxKeyTyped(character, key); } super.keyTyped(character, key); - if (!this.input.getText().matches("[0-9]+")) { + if (!this.input.getText().matches("^[0-9]+")) { this.input.setTextColor(0xFF0000); } else { this.input.setTextColor(0xFFFFFF); @@ -184,44 +177,23 @@ public class GuiLevelMaintainer extends AEBaseGui implements INEIGuiHandler { @Override protected void handleMouseClick(final Slot slot, final int slotIdx, final int ctrlDown, final int mouseButton) { if (slot instanceof ContainerLevelMaintainer.FakeSlot && this.cont.getPlayerInv().getItemStack() != null) { - this.qtyInputs[slot.getSlotIndex()].textField.setText(String.valueOf(this.cont.getPlayerInv().getItemStack().stackSize)); + this.component[slot.getSlotIndex()].getQty().textField.setText(String.valueOf(this.cont.getPlayerInv().getItemStack().stackSize)); return; } super.handleMouseClick(slot, slotIdx, ctrlDown, mouseButton); } public void updateAmount(int idx, int stackSize) { - this.qtyInputs[idx].textField.setText(String.valueOf(stackSize)); + this.component[idx].getQty().textField.setText(String.valueOf(stackSize)); } - private boolean sendToServer(Widget widget) { - if (((ContainerLevelMaintainer.FakeSlot) cont.inventorySlots.get(widget.idx)).getHasStack()) { - if (!widget.textField.getText().isEmpty() && widget.textField.getText().matches("[0-9]+")) { - widget.textField.setText(widget.textField.getText().replaceAll("^(0+)", "")); - FluidCraft.proxy.netHandler.sendToServer(new CPacketLevelMaintainer(widget.action, widget.idx, widget.textField.getText())); - widget.textField.setTextColor(0xFFFFFF); - return true; - } else { - widget.textField.setTextColor(0xFF0000); - return false; - } - } - return false; - } @Override protected void actionPerformed(final GuiButton btn) { super.actionPerformed(btn); - for (Widget widget : qtyInputs) { - if (widget.button == btn) { - sendToServer(widget); - return; - } - } - for (Widget widget : batchInputs) { - if (widget.button == btn) { - sendToServer(widget); - return; + for (Component com : this.component) { + if (com.sendToServer(btn)) { + break; } } } @@ -269,13 +241,100 @@ public class GuiLevelMaintainer extends AEBaseGui implements INEIGuiHandler { return false; } + private class Component { + public boolean isEnable = true; + private Widget qty; + private Widget batch; + private GuiFCImgButton disable; + private GuiFCImgButton enable; + + public Component(Widget qtyInput, Widget batchInput, GuiFCImgButton enableBtn, GuiFCImgButton disableBtn, List buttonList) { + this.qty = qtyInput; + this.batch = batchInput; + this.enable = enableBtn; + this.disable = disableBtn; + this.enable.setHalfSize(true); + this.disable.setHalfSize(true); + buttonList.add(this.qty.button); + buttonList.add(this.batch.button); + buttonList.add(this.enable); + buttonList.add(this.disable); + } + + public int getIndex() { + return this.getQty().idx; + } + + public void setEnable(boolean enable) { + this.isEnable = enable; + } + + private boolean send(Widget widget) { + if (((ContainerLevelMaintainer.FakeSlot) cont.inventorySlots.get(widget.idx)).getHasStack()) { + if (!widget.textField.getText().isEmpty() && widget.textField.getText().matches("^[0-9]+")) { + String str = widget.textField.getText().replaceAll("^(0+)", ""); + widget.textField.setText(str.isEmpty() ? "0" : str); + FluidCraft.proxy.netHandler.sendToServer(new CPacketLevelMaintainer(widget.action, widget.idx, widget.textField.getText())); + widget.textField.setTextColor(0xFFFFFF); + return true; + } else { + widget.textField.setTextColor(0xFF0000); + return false; + } + } + return false; + } + + protected boolean sendToServer(GuiButton btn) { + if (this.getQty().button == btn) { + return this.send(this.getQty()); + } + if (this.getBatch().button == btn) { + return this.send(this.getBatch()); + } + if (this.enable == btn) { + FluidCraft.proxy.netHandler.sendToServer(new CPacketLevelMaintainer("TileLevelMaintainer.Enable", this.getIndex())); + } else if (this.disable == btn) { + FluidCraft.proxy.netHandler.sendToServer(new CPacketLevelMaintainer("TileLevelMaintainer.Disable", this.getIndex())); + } + return false; + } + + public FCGuiTextField isMouseIn(final int xCoord, final int yCoord) { + if (this.getQty().textField.isMouseIn(xCoord, yCoord)) return this.getQty().textField; + if (this.getBatch().textField.isMouseIn(xCoord, yCoord)) return this.getBatch().textField; + return null; + } + + public Widget getQty() { + return this.qty; + } + + public Widget getBatch() { + return this.batch; + } + + public void draw() { + this.getQty().draw(); + this.getBatch().draw(); + if (this.isEnable) { + this.enable.visible = true; + this.disable.visible = false; + } else { + this.enable.visible = false; + this.disable.visible = true; + } + } + + } + private class Widget { public final int idx; - public final int action; + public final String action; private FCGuiTextField textField; private GuiFCImgButton button; - public Widget(FCGuiTextField textField, GuiFCImgButton button, String tooltip, int idx, int action) { + public Widget(FCGuiTextField textField, GuiFCImgButton button, String tooltip, int idx, String action) { this.textField = textField; this.textField.setMessage(tooltip); this.textField.setEnableBackgroundDrawing(false); diff --git a/src/main/java/com/glodblock/github/client/gui/container/ContainerLevelMaintainer.java b/src/main/java/com/glodblock/github/client/gui/container/ContainerLevelMaintainer.java index 71337aef..3be49d0c 100644 --- a/src/main/java/com/glodblock/github/client/gui/container/ContainerLevelMaintainer.java +++ b/src/main/java/com/glodblock/github/client/gui/container/ContainerLevelMaintainer.java @@ -46,15 +46,6 @@ public class ContainerLevelMaintainer extends AEBaseContainer { return null; } - - public void handleClientInteraction(int action, int idx, long size) { - if (action == 0) { - tile.updateQuantity(idx, size); - } else if (action == 1) { - tile.updateBatchSize(idx, size); - } - } - public static class FakeSlot extends ContainerFluidPatternEncoder.SlotFluidConvertingFake { public FakeSlot(AeItemStackHandler inv, int idx, int x, int y) { diff --git a/src/main/java/com/glodblock/github/client/render/RenderBlockLevelMaintainer.java b/src/main/java/com/glodblock/github/client/render/RenderBlockLevelMaintainer.java new file mode 100644 index 00000000..24d23c78 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/render/RenderBlockLevelMaintainer.java @@ -0,0 +1,36 @@ +package com.glodblock.github.client.render; + +import appeng.client.render.BaseBlockRender; +import appeng.client.render.BlockRenderInfo; +import com.glodblock.github.client.textures.FCPartsTexture; +import com.glodblock.github.common.block.BlockLevelMaintainer; +import com.glodblock.github.common.tile.TileLevelMaintainer; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; + +public class RenderBlockLevelMaintainer extends BaseBlockRender { + + public RenderBlockLevelMaintainer() { + super(false, 20); + } + + + @Override + public boolean renderInWorld(final BlockLevelMaintainer block, final IBlockAccess world, final int x, final int y, final int z, final RenderBlocks renderer) { + final TileLevelMaintainer ti = block.getTileEntity(world, x, y, z); + final BlockRenderInfo info = block.getRendererInstance(); + + if (ti != null && ti.isActive()) { + final IIcon activeIcon = FCPartsTexture.BlockLevelMaintainer_Active.getIcon(); + final IIcon side = FCPartsTexture.BlockLevelMaintainer.getIcon(); + info.setTemporaryRenderIcons(side, side, activeIcon, side, side, side); + } + + final boolean fz = super.renderInWorld(block, world, x, y, z, renderer); + + info.setTemporaryRenderIcon(null); + + return fz; + } +} diff --git a/src/main/java/com/glodblock/github/client/textures/FCPartsTexture.java b/src/main/java/com/glodblock/github/client/textures/FCPartsTexture.java index db2f9d6b..5be5b3eb 100644 --- a/src/main/java/com/glodblock/github/client/textures/FCPartsTexture.java +++ b/src/main/java/com/glodblock/github/client/textures/FCPartsTexture.java @@ -14,7 +14,7 @@ public enum FCPartsTexture { PartFluidPatternTerminal_Colored("pattern_terminal_medium"), PartTerminalBroad("terminal_broad"), PartFluidImportBus("fluid_import_face"), PartFluidExportBus("fluid_export_face"), BlockFluidInterfaceAlternate_Arrow("fluid_interface_arrow"), BlockInterfaceAlternate("fluid_interface_a"), - BlockInterface_Face("fluid_interface"), BlockLevelMaintainer("level_maintainer"); + BlockInterface_Face("fluid_interface"), BlockLevelMaintainer("level_maintainer"), BlockLevelMaintainer_Active("level_maintainer_active"); private final String name; public net.minecraft.util.IIcon IIcon; diff --git a/src/main/java/com/glodblock/github/common/block/BlockLevelMaintainer.java b/src/main/java/com/glodblock/github/common/block/BlockLevelMaintainer.java index c853bf9d..8f726bac 100644 --- a/src/main/java/com/glodblock/github/common/block/BlockLevelMaintainer.java +++ b/src/main/java/com/glodblock/github/common/block/BlockLevelMaintainer.java @@ -1,6 +1,7 @@ package com.glodblock.github.common.block; import appeng.block.AEBaseItemBlock; +import com.glodblock.github.client.render.RenderBlockLevelMaintainer; import com.glodblock.github.common.tabs.FluidCraftingTabs; import com.glodblock.github.common.tile.TileLevelMaintainer; import com.glodblock.github.inventory.InventoryHandler; @@ -8,6 +9,8 @@ import com.glodblock.github.inventory.gui.GuiType; import com.glodblock.github.util.BlockPos; import com.glodblock.github.util.NameConst; import cpw.mods.fml.common.registry.GameRegistry; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; import net.minecraft.block.material.Material; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; @@ -30,6 +33,12 @@ public class BlockLevelMaintainer extends FCBaseBlock { return this; } + @Override + @SideOnly(Side.CLIENT) + protected RenderBlockLevelMaintainer getRenderer() { + return new RenderBlockLevelMaintainer(); + } + @Override public boolean onActivated(World world, int x, int y, int z, EntityPlayer player, int facing, float hitX, float hitY, float hitZ) { if (player.isSneaking()) { diff --git a/src/main/java/com/glodblock/github/common/tile/TileLevelMaintainer.java b/src/main/java/com/glodblock/github/common/tile/TileLevelMaintainer.java index ee19d286..bdfbe672 100644 --- a/src/main/java/com/glodblock/github/common/tile/TileLevelMaintainer.java +++ b/src/main/java/com/glodblock/github/common/tile/TileLevelMaintainer.java @@ -3,6 +3,7 @@ package com.glodblock.github.common.tile; import appeng.api.AEApi; import appeng.api.config.Actionable; import appeng.api.config.PowerMultiplier; +import appeng.api.implementations.IPowerChannelState; import appeng.api.networking.GridFlags; import appeng.api.networking.IGrid; import appeng.api.networking.IGridNode; @@ -11,6 +12,9 @@ import appeng.api.networking.crafting.ICraftingJob; import appeng.api.networking.crafting.ICraftingLink; import appeng.api.networking.crafting.ICraftingRequester; import appeng.api.networking.energy.IEnergyGrid; +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.ticking.IGridTickable; @@ -29,22 +33,26 @@ import appeng.tile.events.TileEventType; import appeng.tile.grid.AENetworkTile; import appeng.tile.inventory.IAEAppEngInventory; import appeng.tile.inventory.InvOperation; +import appeng.util.item.AEItemStack; import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.inventory.AeItemStackHandler; import com.glodblock.github.inventory.AeStackInventory; import com.glodblock.github.inventory.AeStackInventoryImpl; import com.google.common.collect.ImmutableSet; +import io.netty.buffer.ByteBuf; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import java.util.concurrent.Future; -public class TileLevelMaintainer extends AENetworkTile implements IAEAppEngInventory, IGridTickable, ICraftingRequester { +public class TileLevelMaintainer extends AENetworkTile implements IAEAppEngInventory, IGridTickable, ICraftingRequester, IPowerChannelState { public static final int REQ_COUNT = 5; public final InventoryRequest requests = new InventoryRequest(this); private final BaseActionSource source; - + private final IInventory inv = new AeItemStackHandler(requests.getRequestStacks()); + private boolean isPowered = false; public TileLevelMaintainer() { getProxy().setIdlePowerUsage(1D); @@ -103,6 +111,7 @@ public class TileLevelMaintainer extends AENetworkTile implements IAEAppEngInven public TickRateModulation tickingRequest(IGridNode node, int TicksSinceLastCall) { return this.canDoBusWork() ? this.doWork() : TickRateModulation.IDLE; } + private TickRateModulation doWork() { if (!this.getProxy().isActive() || !this.canDoBusWork()) { return TickRateModulation.IDLE; @@ -113,7 +122,7 @@ public class TileLevelMaintainer extends AENetworkTile implements IAEAppEngInven IGrid grid = this.getProxy().getGrid(); final IItemList inv = this.getProxy().getStorage().getItemInventory().getStorageList(); for (int i = 0; i < REQ_COUNT; i++) { - IAEItemStack is = requests.getQuantity(i); + IAEItemStack is = requests.getRequestQtyStack(i); if (is != null && requests.getBatchSize(i) > 0) { IAEItemStack craftItem = requests.getCraftItem(i); if (cg.canEmitFor(craftItem) || cg.isRequesting(craftItem) || @@ -165,12 +174,27 @@ public class TileLevelMaintainer extends AENetworkTile implements IAEAppEngInven return this.getProxy().isActive(); } + @Override + public void gridChanged() { + + } + + @Override + public boolean isPowered() { + return this.isPowered; + } + + @Override + public boolean isActive() { + return this.isPowered; + } + public InventoryRequest getRequestInventory() { return this.requests; } public IInventory getInventory() { - return (IInventory) this.requests.getRequestStacks(); + return inv; } public void updateQuantity(int idx, long size) { @@ -181,6 +205,10 @@ public class TileLevelMaintainer extends AENetworkTile implements IAEAppEngInven this.requests.updateBatchSize(idx, size); } + public void setRequestStatus(int idx, boolean enable) { + this.requests.setEnable(idx, enable); + } + private void readLinkFromNBT(NBTTagCompound data) { try { for (int i = 0; i < this.requests.getLinks().length; i++) { @@ -224,6 +252,45 @@ public class TileLevelMaintainer extends AENetworkTile implements IAEAppEngInven this.readLinkFromNBT(data); } + @TileEvent(TileEventType.NETWORK_READ) + public boolean readFromStream(final ByteBuf data) { + final boolean oldPower = this.isPowered; + this.isPowered = data.readBoolean(); + return this.isPowered != oldPower; + } + + @TileEvent(TileEventType.NETWORK_WRITE) + public void writeToStream(final ByteBuf data) { + data.writeBoolean(this.isActive()); + } + + @MENetworkEventSubscribe + public void stateChange(final MENetworkPowerStatusChange p) { + this.updatePowerState(); + } + + @MENetworkEventSubscribe + public final void bootingRender(final MENetworkBootingStatusChange c) { + this.updatePowerState(); + } + + 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(); + } + } + public static class InventoryRequest { private final AeStackInventoryImpl requestStacks; private final AeStackInventoryImpl requestBatches; @@ -239,6 +306,35 @@ public class TileLevelMaintainer extends AENetworkTile implements IAEAppEngInven this.links = new ICraftingLink[REQ_COUNT]; } + public void setEnable(int idx, boolean enable) { + IAEItemStack ias = this.getRequestStacks().getStack(idx); + IAEItemStack ias1 = this.getRequestBatches().getStack(idx); + if (ias != null && ias1 != null) { + ItemStack is = ias1.getItemStack(); + NBTTagCompound data = new NBTTagCompound(); + data.setBoolean("Enable", enable); + is.setTagCompound(data); + IAEItemStack i = AEItemStack.create(is); + i.setStackSize(ias1.getStackSize()); + this.getRequestBatches().setStack(idx, i); + } + } + + public boolean isEnable(int idx) { + IAEItemStack ias = this.getRequestBatches().getStack(idx); + if (ias != null) { + ItemStack is = ias.getItemStack(); + try { + return is.getTagCompound().getBoolean("Enable"); + } catch (NullPointerException e) { + // support old version + return true; + } + } else { + return true; + } + } + public boolean isDone(int index) { if (this.getLinks()[index] != null) { return this.getLinks()[index].isDone() || this.getLinks()[index].isCanceled(); @@ -276,15 +372,19 @@ public class TileLevelMaintainer extends AENetworkTile implements IAEAppEngInven } public void updateBatchSize(int idx, long size) { - IAEItemStack is = this.getRequestStacks().getStack(idx); - if (is != null) { - IAEItemStack i = is.copy(); + IAEItemStack ias = this.getRequestStacks().getStack(idx); + if (ias != null) { + ItemStack is = ias.copy().getItemStack(); + NBTTagCompound data = new NBTTagCompound(); + data.setBoolean("Enable", true); + is.setTagCompound(data); + IAEItemStack i = AEItemStack.create(is); i.setStackSize(size); this.getRequestBatches().setStack(idx, i); } } - public IAEItemStack getQuantity(int idx) { + public IAEItemStack getRequestQtyStack(int idx) { IAEItemStack is = this.getRequestStacks().getStack(idx); if (is == null) return null; IAEItemStack qis = this.getRequestQtys().getStack(idx); @@ -292,17 +392,26 @@ public class TileLevelMaintainer extends AENetworkTile implements IAEAppEngInven return this.getRequestQtys().getStack(idx); } + public long getQuantity(int idx) { + IAEItemStack ias = this.getRequestQtyStack(idx); + if (ias == null) { + return 0; + } + return ias.getStackSize(); + } + public long getBatchSize(int idx) { + if (!this.isEnable(idx)) return 0; IAEItemStack is = this.getRequestStacks().getStack(idx); IAEItemStack is1 = this.getRequestBatches().getStack(idx); - if (is != null && is1 != null && is.isSameType(is1)) { + if (is != null && is1 != null) { return is1.getStackSize(); } return 0; } public IAEItemStack getCraftItem(int idx) { - IAEItemStack is = this.getQuantity(idx); + IAEItemStack is = this.getRequestQtyStack(idx); if (is != null) { IAEItemStack ias = is.copy(); ias.setStackSize(this.getBatchSize(idx)); diff --git a/src/main/java/com/glodblock/github/crossmod/opencomputers/DriverLevelMaintainer.java b/src/main/java/com/glodblock/github/crossmod/opencomputers/DriverLevelMaintainer.java new file mode 100644 index 00000000..dc884b49 --- /dev/null +++ b/src/main/java/com/glodblock/github/crossmod/opencomputers/DriverLevelMaintainer.java @@ -0,0 +1,212 @@ +package com.glodblock.github.crossmod.opencomputers; + +import appeng.util.item.AEItemStack; +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.common.tile.TileLevelMaintainer; +import com.glodblock.github.inventory.AeItemStackHandler; +import com.glodblock.github.loader.ItemAndBlockHolder; +import com.glodblock.github.util.NameConst; +import cpw.mods.fml.common.registry.GameRegistry; +import li.cil.oc.api.driver.EnvironmentProvider; +import li.cil.oc.api.driver.NamedBlock; +import li.cil.oc.api.internal.Database; +import li.cil.oc.api.machine.Arguments; +import li.cil.oc.api.machine.Callback; +import li.cil.oc.api.machine.Context; +import li.cil.oc.api.network.Component; +import li.cil.oc.api.network.ManagedEnvironment; +import li.cil.oc.api.network.Node; +import li.cil.oc.api.prefab.DriverSidedTileEntity; +import li.cil.oc.integration.ManagedTileEntityEnvironment; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +import java.util.HashMap; +import java.util.Map; + + +public class DriverLevelMaintainer extends DriverSidedTileEntity { + @Override + public Class getTileEntityClass() { + return TileLevelMaintainer.class; + } + + @Override + public ManagedEnvironment createEnvironment(World world, int x, int y, int z, ForgeDirection forgeDirection) { + return new DriverLevelMaintainer.Environment((TileLevelMaintainer) world.getTileEntity(x, y, z)); + } + + public static class Environment extends ManagedTileEntityEnvironment + implements NamedBlock { + + public Environment(TileLevelMaintainer tileEntity) { + super(tileEntity, NameConst.BLOCK_LEVEL_MAINTAINER); + } + + private int getSlot(Arguments args, IInventory inv, int index, int def) { + if (index >= 0 && index < args.count()) { + int slot = args.checkInteger(index) - 1; + if (slot < 0 || slot >= inv.getSizeInventory()) { + throw new IllegalArgumentException("Invalid slot"); + } + return slot; + } else { + return def; + } + } + + private boolean isDone(Arguments args) { + int slot = args.checkInteger(0) - 1; + if (slot < 0 || slot >= TileLevelMaintainer.REQ_COUNT) { + throw new IllegalArgumentException("Invalid slot"); + } + return tileEntity.requests.isDone(slot); + } + + private boolean isEnable(Arguments args) { + int slot = args.checkInteger(0) - 1; + if (slot < 0 || slot >= TileLevelMaintainer.REQ_COUNT) { + throw new IllegalArgumentException("Invalid slot"); + } + return tileEntity.requests.isEnable(slot); + } + + private boolean setEnable(Arguments args) { + if (args.count() != 2) { + throw new IllegalArgumentException("Invalid args!"); + } else { + int slot = args.checkInteger(0) - 1; + if (slot < 0 || slot >= TileLevelMaintainer.REQ_COUNT) { + throw new IllegalArgumentException("Invalid slot"); + } + boolean enable = args.checkBoolean(1); + tileEntity.requests.setEnable(slot, enable); + return true; + } + } + + private void updateOrder(int slot, int quantity, int batch) { + tileEntity.updateQuantity(slot, quantity); + tileEntity.updateBatchSize(slot, batch); + } + + @Callback(doc = "function([slot:number]):table -- Get the slot status.") + public Object[] getSlot(Context context, Arguments args) { + IInventory config = tileEntity.getInventory(); + int slot = getSlot(args, config, 0, 0); + ItemStack stack = config.getStackInSlot(slot); + if (stack != null) { + Map result = new HashMap<>(); + result.put("damage", stack.getItemDamage()); + result.put("hasTag", stack.hasTagCompound()); + result.put("label", stack.getDisplayName()); + result.put("maxDamage", stack.getMaxDamage()); + result.put("name", GameRegistry.findUniqueIdentifierFor(stack.getItem()).toString()); + result.put("quantity", tileEntity.requests.getQuantity(slot)); + result.put("batch", tileEntity.requests.getBatchSize(slot)); + result.put("isFluid", ItemFluidDrop.isFluidStack(stack)); + if (ItemFluidDrop.isFluidStack(stack)) result.put("fluid", ItemFluidDrop.getFluidStack(stack)); + result.put("isEnable", tileEntity.requests.isEnable(slot)); + result.put("isDone", tileEntity.requests.isDone(slot)); + return new Object[]{result}; + } + return new Object[]{null}; + } + + private void setSlot(int slot, String address, int index) { + Node node = node().network().node(address); + if (node instanceof Component) { + if (node.host() instanceof Database) { + ItemStack dbStack = ((Database) node.host()).getStackInSlot(index); + if (dbStack == null) { + throw new IllegalArgumentException("Invalid slot"); + } + dbStack.stackSize = 1; + ((AeItemStackHandler) tileEntity.getInventory()).getAeInventory().setStack(slot, AEItemStack.create(dbStack)); + } else { + throw new IllegalArgumentException("Not a database"); + } + } else { + throw new IllegalArgumentException("No such component"); + } + } + + @Callback(doc = "function(slot:number[,database:address[,index:number]],quantity:number,batch:number):boolean -- Configuration the slot.") + public Object[] setSlot(Context context, Arguments args) { + int slot; + String address; + int index; + int quantity; + int batch; + slot = args.checkInteger(0) - 1; + + if (slot < 0 || slot >= TileLevelMaintainer.REQ_COUNT) { + throw new IllegalArgumentException("Invalid slot"); + } + if (args.count() == 5) { + address = args.checkString(1); + index = args.checkInteger(2) - 1; + quantity = args.checkInteger(3); + batch = args.checkInteger(4); + setSlot(slot, address, index); + updateOrder(slot, quantity, batch); + } else if (args.count() == 3) { + quantity = args.checkInteger(1); + batch = args.checkInteger(2); + updateOrder(slot, quantity, batch); + } else { + throw new IllegalArgumentException("Invalid args"); + } + return new Object[]{true}; + } + + private boolean isActive() { + return tileEntity.isActive(); + } + + @Callback(doc = "function(slot:number):boolean -- Get the crafting task state.") + public Object[] isDone(Context context, Arguments args) { + return new Object[]{this.isDone(args)}; + } + + @Callback(doc = "function(slot:number):boolean -- Get the crafting state of slot.") + public Object[] isEnable(Context context, Arguments args) { + return new Object[]{this.isEnable(args)}; + } + + @Callback(doc = "function(slot:number,value:boolean):boolean -- Set the crafting state of slot.") + public Object[] setEnable(Context context, Arguments args) { + return new Object[]{this.setEnable(args)}; + } + + @Callback(doc = "function():boolean Get Level Maintainer state") + public Object[] active(Context context, Arguments args) { + return new Object[]{this.isActive()}; + } + + @Override + public String preferredName() { + return NameConst.BLOCK_LEVEL_MAINTAINER; + } + + @Override + public int priority() { + return 6; + } + } + + public static class Provider implements EnvironmentProvider { + Provider() { + } + + @Override + public Class getEnvironment(ItemStack itemStack) { + if (itemStack != null && itemStack.isItemEqual(ItemAndBlockHolder.LEVEL_MAINTAINER.stack())) { + return DriverLevelMaintainer.Environment.class; + } + return null; + } + } +} diff --git a/src/main/java/com/glodblock/github/crossmod/opencomputers/OCDriverInit.java b/src/main/java/com/glodblock/github/crossmod/opencomputers/OCDriverInit.java index 35cd6554..50192001 100644 --- a/src/main/java/com/glodblock/github/crossmod/opencomputers/OCDriverInit.java +++ b/src/main/java/com/glodblock/github/crossmod/opencomputers/OCDriverInit.java @@ -7,6 +7,8 @@ public class OCDriverInit { public static void run() { Driver.add(new DriverOCPatternEditor()); Driver.add(new DriverOCPatternEditor.Provider()); + Driver.add(new DriverLevelMaintainer()); + Driver.add(new DriverLevelMaintainer.Provider()); } } diff --git a/src/main/java/com/glodblock/github/network/CPacketLevelMaintainer.java b/src/main/java/com/glodblock/github/network/CPacketLevelMaintainer.java index a4a37b52..0fa007c3 100644 --- a/src/main/java/com/glodblock/github/network/CPacketLevelMaintainer.java +++ b/src/main/java/com/glodblock/github/network/CPacketLevelMaintainer.java @@ -17,36 +17,43 @@ import javax.annotation.Nullable; public class CPacketLevelMaintainer implements IMessage { - private int action; + private String action; private long size; private int slotIndex; public CPacketLevelMaintainer() { } - public CPacketLevelMaintainer(int action) { + public CPacketLevelMaintainer(String action, int slotIndex) { + this.action = action; + this.size = 0; + this.slotIndex = slotIndex; + } + + public CPacketLevelMaintainer(String action) { this.action = action; this.size = 0; this.slotIndex = 0; } - public CPacketLevelMaintainer(int action, int slotIndex, long size) { + public CPacketLevelMaintainer(String action, int slotIndex, long size) { this.action = action; this.size = size; this.slotIndex = slotIndex; } - public CPacketLevelMaintainer(int action, int slotIndex, String size) { + public CPacketLevelMaintainer(String action, int slotIndex, String size) { this.action = action; this.slotIndex = slotIndex; - this.size = Long.parseLong(size); + this.size = size.isEmpty() ? 0 : Long.parseLong(size); } - public static IAEItemStack setTag(IAEItemStack ias, long batch, int slotIndex) { + public static IAEItemStack setTag(IAEItemStack ias, long batch, int slotIndex, boolean enable) { NBTTagCompound data = new NBTTagCompound(); ItemStack is = ias.getItemStack(); data.setLong("Batch", batch); data.setLong("Index", slotIndex); + data.setBoolean("Enable", enable); is.setTagCompound(data); IAEItemStack iaeItemStack = AEItemStack.create(is); iaeItemStack.setStackSize(ias.getStackSize()); @@ -55,40 +62,66 @@ public class CPacketLevelMaintainer implements IMessage { @Override public void fromBytes(ByteBuf buf) { - this.action = buf.readInt(); + int leAction = buf.readInt(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < leAction; i++) { + sb.append(buf.readChar()); + } + this.action = sb.toString(); this.slotIndex = buf.readInt(); this.size = buf.readLong(); } @Override public void toBytes(ByteBuf buf) { - buf.writeInt(this.action); + buf.writeInt(this.action.length()); + for (int i = 0; i < this.action.length(); i++) { + buf.writeChar(this.action.charAt(i)); + } buf.writeInt(this.slotIndex); buf.writeLong(this.size); } public static class Handler implements IMessageHandler { + private void refresh(ContainerLevelMaintainer cca, EntityPlayerMP player) { + SPacketMEInventoryUpdate piu = new SPacketMEInventoryUpdate(false); + for (int i = 0; i < TileLevelMaintainer.REQ_COUNT; i++) { + IAEItemStack is = cca.getTile().requests.getRequestQtyStack(i); + IAEItemStack is1 = cca.getTile().requests.getRequestBatches().getStack(i); + if (is != null) { + if (is1 != null) { + NBTTagCompound data; + data = is1.getItemStack().getTagCompound(); + piu.appendItem(setTag(is, is1.getStackSize(), i, data.getBoolean("Enable"))); + } else { + piu.appendItem(setTag(is, 0, i, true)); + } + } + } + FluidCraft.proxy.netHandler.sendTo(piu, player); + } @Nullable @Override public IMessage onMessage(CPacketLevelMaintainer message, MessageContext ctx) { - if (ctx.getServerHandler().playerEntity.openContainer instanceof ContainerLevelMaintainer) { + if (message.action.startsWith("TileLevelMaintainer.") && ctx.getServerHandler().playerEntity.openContainer instanceof ContainerLevelMaintainer) { EntityPlayerMP player = ctx.getServerHandler().playerEntity; final ContainerLevelMaintainer cca = (ContainerLevelMaintainer) ctx.getServerHandler().playerEntity.openContainer; - if (message.action == -1) { - SPacketMEInventoryUpdate piu = new SPacketMEInventoryUpdate(false); - for (int i = 0; i < TileLevelMaintainer.REQ_COUNT; i++) { - IAEItemStack is = cca.getTile().requests.getQuantity(i); - IAEItemStack is1 = cca.getTile().requests.getRequestBatches().getStack(i); - if (is != null) { - piu.appendItem(setTag(is, is1 != null ? is1.getStackSize() : 0, i)); - } - } - FluidCraft.proxy.netHandler.sendTo(piu, player); - } else { - cca.handleClientInteraction(message.action, message.slotIndex, message.size); + switch (message.action) { + case "TileLevelMaintainer.Quantity": + cca.getTile().updateQuantity(message.slotIndex, message.size); + break; + case "TileLevelMaintainer.Batch": + cca.getTile().updateBatchSize(message.slotIndex, message.size); + break; + case "TileLevelMaintainer.Enable": + cca.getTile().setRequestStatus(message.slotIndex, false); + break; + case "TileLevelMaintainer.Disable": + cca.getTile().setRequestStatus(message.slotIndex, true); + break; } - + this.refresh(cca, player); } return null; } diff --git a/src/main/resources/assets/ae2fc/lang/en_US.lang b/src/main/resources/assets/ae2fc/lang/en_US.lang index 43fbe7c9..ab8f2e35 100644 --- a/src/main/resources/assets/ae2fc/lang/en_US.lang +++ b/src/main/resources/assets/ae2fc/lang/en_US.lang @@ -49,8 +49,9 @@ ae2fc.tooltip.not_prio=Allow fluids to be placed first ae2fc.tooltip.not_prio.hint=Enabled ae2fc.tooltip.prio=Allow fluids to be placed first ae2fc.tooltip.prio.hint=Disabled -ae2fc.tooltip.submit=Submit Request -ae2fc.tooltip.submit.hint=Submit +ae2fc.tooltip.submit=Submit +ae2fc.tooltip.enable=enable +ae2fc.tooltip.disable=disable ae2fc.gui.part_fluid_pattern_terminal=Fluid Pattern Terminal ae2fc.gui.part_fluid_pattern_terminal_ex=Fluid Processing Pattern Terminal diff --git a/src/main/resources/assets/ae2fc/lang/zh_CN.lang b/src/main/resources/assets/ae2fc/lang/zh_CN.lang index 67137050..3e21bb7d 100644 --- a/src/main/resources/assets/ae2fc/lang/zh_CN.lang +++ b/src/main/resources/assets/ae2fc/lang/zh_CN.lang @@ -49,8 +49,9 @@ ae2fc.tooltip.not_prio=优先放置流体 ae2fc.tooltip.not_prio.hint=启用 ae2fc.tooltip.prio=优先放置流体 ae2fc.tooltip.prio.hint=禁用 -ae2fc.tooltip.submit=提交请求 -ae2fc.tooltip.submit.hint=提交 +ae2fc.tooltip.submit=提交 +ae2fc.tooltip.enable=启用 +ae2fc.tooltip.disable=禁用 ae2fc.gui.part_fluid_pattern_terminal=ME流体样板终端 ae2fc.gui.part_fluid_pattern_terminal_ex=ME增广流体样板终端 diff --git a/src/main/resources/assets/ae2fc/textures/blocks/level_maintainerActive.png b/src/main/resources/assets/ae2fc/textures/blocks/level_maintainer_active.png similarity index 100% rename from src/main/resources/assets/ae2fc/textures/blocks/level_maintainerActive.png rename to src/main/resources/assets/ae2fc/textures/blocks/level_maintainer_active.png diff --git a/src/main/resources/assets/ae2fc/textures/gui/states.png b/src/main/resources/assets/ae2fc/textures/gui/states.png index d0fee811794344a7a17d1f30670c4268986d394b..4f0fe51ddc814bb67c66e5ce42ed3377ee501554 100644 GIT binary patch delta 1690 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