From c3ce9d9542a1a7057ac0c52022d11947abe1dd15 Mon Sep 17 00:00:00 2001 From: yueh Date: Fri, 10 Jul 2015 02:55:03 +0200 Subject: [PATCH] Adds a round robin and random mode to export buses. Resolves #85 --- .../appeng/api/config/SchedulingMode.java | 30 +++ src/api/java/appeng/api/config/Settings.java | 6 +- .../gui/implementations/GuiUpgradeable.java | 19 ++ .../client/gui/widgets/GuiImgButton.java | 5 + .../implementations/ContainerUpgradeable.java | 4 + .../core/localization/ButtonToolTips.java | 4 +- .../parts/automation/PartExportBus.java | 211 ++++++++++-------- .../parts/automation/PartImportBus.java | 51 ++--- .../parts/automation/PartSharedItemBus.java | 123 ++++++---- .../appliedenergistics2/lang/en_US.lang | 4 + .../textures/guis/states.png | Bin 11915 -> 12259 bytes 11 files changed, 278 insertions(+), 179 deletions(-) create mode 100644 src/api/java/appeng/api/config/SchedulingMode.java diff --git a/src/api/java/appeng/api/config/SchedulingMode.java b/src/api/java/appeng/api/config/SchedulingMode.java new file mode 100644 index 000000000..395bf1ece --- /dev/null +++ b/src/api/java/appeng/api/config/SchedulingMode.java @@ -0,0 +1,30 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2013 AlgorithmX2 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package appeng.api.config; + + +public enum SchedulingMode +{ + DEFAULT, ROUNDROBIN, RANDOM +} diff --git a/src/api/java/appeng/api/config/Settings.java b/src/api/java/appeng/api/config/Settings.java index 97796dc28..b199c023c 100644 --- a/src/api/java/appeng/api/config/Settings.java +++ b/src/api/java/appeng/api/config/Settings.java @@ -54,13 +54,15 @@ public enum Settings INTERFACE_TERMINAL( EnumSet.of( YesNo.YES, YesNo.NO ) ), CRAFT_VIA_REDSTONE( EnumSet.of( YesNo.YES, YesNo.NO ) ), - STORAGE_FILTER( EnumSet.allOf( StorageFilter.class ) ), PLACE_BLOCK( EnumSet.of( YesNo.YES, YesNo.NO ) ); + STORAGE_FILTER( EnumSet.allOf( StorageFilter.class ) ), PLACE_BLOCK( EnumSet.of( YesNo.YES, YesNo.NO ) ), + + SCHEDULING_MODE( EnumSet.allOf( SchedulingMode.class ) ); private final EnumSet> values; Settings( @Nonnull EnumSet> possibleOptions ) { - if ( possibleOptions.isEmpty() ) + if( possibleOptions.isEmpty() ) { throw new IllegalArgumentException( "Tried to instantiate an empty setting." ); } diff --git a/src/main/java/appeng/client/gui/implementations/GuiUpgradeable.java b/src/main/java/appeng/client/gui/implementations/GuiUpgradeable.java index b4f278168..e5dcad7d1 100644 --- a/src/main/java/appeng/client/gui/implementations/GuiUpgradeable.java +++ b/src/main/java/appeng/client/gui/implementations/GuiUpgradeable.java @@ -26,6 +26,7 @@ import net.minecraft.entity.player.InventoryPlayer; import appeng.api.config.FuzzyMode; import appeng.api.config.RedstoneMode; +import appeng.api.config.SchedulingMode; import appeng.api.config.Settings; import appeng.api.config.Upgrades; import appeng.api.config.YesNo; @@ -36,6 +37,7 @@ import appeng.container.implementations.ContainerUpgradeable; import appeng.core.localization.GuiText; import appeng.core.sync.network.NetworkHandler; import appeng.core.sync.packets.PacketConfigButton; +import appeng.parts.automation.PartExportBus; import appeng.parts.automation.PartImportBus; @@ -48,6 +50,7 @@ public class GuiUpgradeable extends AEBaseGui GuiImgButton redstoneMode; GuiImgButton fuzzyMode; GuiImgButton craftMode; + GuiImgButton schedulingMode; public GuiUpgradeable( InventoryPlayer inventoryPlayer, IUpgradeableHost te ) { @@ -81,10 +84,12 @@ public class GuiUpgradeable extends AEBaseGui this.redstoneMode = new GuiImgButton( this.guiLeft - 18, this.guiTop + 8, Settings.REDSTONE_CONTROLLED, RedstoneMode.IGNORE ); this.fuzzyMode = new GuiImgButton( this.guiLeft - 18, this.guiTop + 28, Settings.FUZZY_MODE, FuzzyMode.IGNORE_ALL ); this.craftMode = new GuiImgButton( this.guiLeft - 18, this.guiTop + 48, Settings.CRAFT_ONLY, YesNo.NO ); + this.schedulingMode = new GuiImgButton( this.guiLeft - 18, this.guiTop + 68, Settings.SCHEDULING_MODE, SchedulingMode.DEFAULT ); this.buttonList.add( this.craftMode ); this.buttonList.add( this.redstoneMode ); this.buttonList.add( this.fuzzyMode ); + this.buttonList.add( this.schedulingMode ); } @Override @@ -107,6 +112,11 @@ public class GuiUpgradeable extends AEBaseGui { this.craftMode.set( this.cvb.cMode ); } + + if( this.schedulingMode != null ) + { + this.schedulingMode.set( this.cvb.schedulingMode ); + } } @Override @@ -140,6 +150,10 @@ public class GuiUpgradeable extends AEBaseGui { this.craftMode.setVisibility( this.bc.getInstalledUpgrades( Upgrades.CRAFTING ) > 0 ); } + if( this.schedulingMode != null ) + { + this.schedulingMode.setVisibility(this.bc.getInstalledUpgrades( Upgrades.CAPACITY ) > 0 && this.bc instanceof PartExportBus ); + } } protected String getBackground() @@ -178,5 +192,10 @@ public class GuiUpgradeable extends AEBaseGui { NetworkHandler.instance.sendToServer( new PacketConfigButton( this.fuzzyMode.getSetting(), backwards ) ); } + + if( btn == this.schedulingMode ) + { + NetworkHandler.instance.sendToServer( new PacketConfigButton( this.schedulingMode.getSetting(), backwards ) ); + } } } diff --git a/src/main/java/appeng/client/gui/widgets/GuiImgButton.java b/src/main/java/appeng/client/gui/widgets/GuiImgButton.java index d154c8d3a..2747b96d8 100644 --- a/src/main/java/appeng/client/gui/widgets/GuiImgButton.java +++ b/src/main/java/appeng/client/gui/widgets/GuiImgButton.java @@ -39,6 +39,7 @@ import appeng.api.config.OperationMode; import appeng.api.config.PowerUnits; import appeng.api.config.RedstoneMode; import appeng.api.config.RelativeDirection; +import appeng.api.config.SchedulingMode; import appeng.api.config.SearchBoxMode; import appeng.api.config.Settings; import appeng.api.config.SortDir; @@ -158,6 +159,10 @@ public class GuiImgButton extends GuiButton implements ITooltip this.registerApp( 16 * 14, Settings.PLACE_BLOCK, YesNo.YES, ButtonToolTips.BlockPlacement, ButtonToolTips.BlockPlacementYes ); this.registerApp( 16 * 14 + 1, Settings.PLACE_BLOCK, YesNo.NO, ButtonToolTips.BlockPlacement, ButtonToolTips.BlockPlacementNo ); + + this.registerApp( 16 * 15, Settings.SCHEDULING_MODE, SchedulingMode.DEFAULT, ButtonToolTips.SchedulingMode, ButtonToolTips.SchedulingModeDefault ); + this.registerApp( 16 * 15 + 1, Settings.SCHEDULING_MODE, SchedulingMode.ROUNDROBIN, ButtonToolTips.SchedulingMode, ButtonToolTips.SchedulingModeRoundRobin ); + this.registerApp( 16 * 15 + 2, Settings.SCHEDULING_MODE, SchedulingMode.RANDOM, ButtonToolTips.SchedulingMode, ButtonToolTips.SchedulingModeRandom ); } } diff --git a/src/main/java/appeng/container/implementations/ContainerUpgradeable.java b/src/main/java/appeng/container/implementations/ContainerUpgradeable.java index 9ff79a6ff..b710b0fcd 100644 --- a/src/main/java/appeng/container/implementations/ContainerUpgradeable.java +++ b/src/main/java/appeng/container/implementations/ContainerUpgradeable.java @@ -27,6 +27,7 @@ import net.minecraft.world.World; import appeng.api.config.FuzzyMode; import appeng.api.config.RedstoneMode; +import appeng.api.config.SchedulingMode; import appeng.api.config.SecurityPermissions; import appeng.api.config.Settings; import appeng.api.config.Upgrades; @@ -58,6 +59,8 @@ public class ContainerUpgradeable extends AEBaseContainer implements IOptionalSl public FuzzyMode fzMode = FuzzyMode.IGNORE_ALL; @GuiSync( 5 ) public YesNo cMode = YesNo.NO; + @GuiSync( 6 ) + public SchedulingMode schedulingMode = SchedulingMode.DEFAULT; int tbSlot; NetworkToolViewer tbInventory; @@ -217,6 +220,7 @@ public class ContainerUpgradeable extends AEBaseContainer implements IOptionalSl if( this.upgradeable instanceof PartExportBus ) { this.cMode = (YesNo) cm.getSetting( Settings.CRAFT_ONLY ); + this.schedulingMode = (SchedulingMode) cm.getSetting( Settings.SCHEDULING_MODE ); } } diff --git a/src/main/java/appeng/core/localization/ButtonToolTips.java b/src/main/java/appeng/core/localization/ButtonToolTips.java index 82da570d7..86a58836b 100644 --- a/src/main/java/appeng/core/localization/ButtonToolTips.java +++ b/src/main/java/appeng/core/localization/ButtonToolTips.java @@ -61,7 +61,9 @@ public enum ButtonToolTips BlockPlacement, BlockPlacementYes, BlockPlacementNo, // Used in the tooltips of the items in the terminal, when moused over - ItemsStored, ItemsRequestable; + ItemsStored, ItemsRequestable, + + SchedulingMode, SchedulingModeDefault, SchedulingModeRoundRobin, SchedulingModeRandom; final String root; diff --git a/src/main/java/appeng/parts/automation/PartExportBus.java b/src/main/java/appeng/parts/automation/PartExportBus.java index ef005cd3f..e6ee49769 100644 --- a/src/main/java/appeng/parts/automation/PartExportBus.java +++ b/src/main/java/appeng/parts/automation/PartExportBus.java @@ -35,6 +35,7 @@ import appeng.api.config.Actionable; import appeng.api.config.FuzzyMode; import appeng.api.config.PowerMultiplier; import appeng.api.config.RedstoneMode; +import appeng.api.config.SchedulingMode; import appeng.api.config.Settings; import appeng.api.config.Upgrades; import appeng.api.config.YesNo; @@ -66,10 +67,11 @@ import appeng.util.item.AEItemStack; public class PartExportBus extends PartSharedItemBus implements ICraftingRequester { - final MultiCraftingTracker cratingTracker = new MultiCraftingTracker( this, 9 ); - final BaseActionSource mySrc; - long itemToSend = 1; - boolean didSomething = false; + private final MultiCraftingTracker craftingTracker = new MultiCraftingTracker( this, 9 ); + private final BaseActionSource mySrc; + private long itemToSend = 1; + private boolean didSomething = false; + private int nextSlot = 0; @Reflected public PartExportBus( ItemStack is ) @@ -79,6 +81,7 @@ public class PartExportBus extends PartSharedItemBus implements ICraftingRequest this.getConfigManager().registerSetting( Settings.REDSTONE_CONTROLLED, RedstoneMode.IGNORE ); this.getConfigManager().registerSetting( Settings.FUZZY_MODE, FuzzyMode.IGNORE_ALL ); this.getConfigManager().registerSetting( Settings.CRAFT_ONLY, YesNo.NO ); + this.getConfigManager().registerSetting( Settings.SCHEDULING_MODE, SchedulingMode.DEFAULT ); this.mySrc = new MachineSource( this ); } @@ -86,76 +89,64 @@ public class PartExportBus extends PartSharedItemBus implements ICraftingRequest public void readFromNBT( NBTTagCompound extra ) { super.readFromNBT( extra ); - this.cratingTracker.readFromNBT( extra ); + this.craftingTracker.readFromNBT( extra ); + this.nextSlot = extra.getInteger( "nextSlot" ); } @Override public void writeToNBT( NBTTagCompound extra ) { super.writeToNBT( extra ); - this.cratingTracker.writeToNBT( extra ); + this.craftingTracker.writeToNBT( extra ); + extra.setInteger( "nextSlot", this.nextSlot ); } @Override - TickRateModulation doBusWork() + protected TickRateModulation doBusWork() { - if( !this.proxy.isActive() ) + if( !this.proxy.isActive() || !this.canDoBusWork() ) { return TickRateModulation.IDLE; } - this.itemToSend = 1; + this.itemToSend = this.calculateItemsToSend(); this.didSomething = false; - switch( this.getInstalledUpgrades( Upgrades.SPEED ) ) - { - default: - case 0: - this.itemToSend = 1; - break; - case 1: - this.itemToSend = 8; - break; - case 2: - this.itemToSend = 32; - break; - case 3: - this.itemToSend = 64; - break; - case 4: - this.itemToSend = 96; - break; - } - try { - InventoryAdaptor d = this.getHandler(); - IMEMonitor inv = this.proxy.getStorage().getItemInventory(); - IEnergyGrid energy = this.proxy.getEnergy(); - ICraftingGrid cg = this.proxy.getCrafting(); - FuzzyMode fzMode = (FuzzyMode) this.getConfigManager().getSetting( Settings.FUZZY_MODE ); + final InventoryAdaptor destination = this.getHandler(); + final IMEMonitor inv = this.proxy.getStorage().getItemInventory(); + final IEnergyGrid energy = this.proxy.getEnergy(); + final ICraftingGrid cg = this.proxy.getCrafting(); + final FuzzyMode fzMode = (FuzzyMode) this.getConfigManager().getSetting( Settings.FUZZY_MODE ); + final SchedulingMode schedulingMode = (SchedulingMode) this.getConfigManager().getSetting( Settings.SCHEDULING_MODE ); - if( d != null ) + if( destination != null ) { - for( int x = 0; x < this.availableSlots() && this.itemToSend > 0; x++ ) + int x = 0; + + for( x = 0; x < this.availableSlots() && this.itemToSend > 0; x++ ) { - IAEItemStack ais = this.config.getAEStackInSlot( x ); + int slotToExport = this.getStartingSlot( schedulingMode, x ); + + final IAEItemStack ais = this.config.getAEStackInSlot( slotToExport ); + if( ais == null || this.itemToSend <= 0 || this.craftOnly() ) { if( this.isCraftingEnabled() ) { - this.didSomething = this.cratingTracker.handleCrafting( x, this.itemToSend, ais, d, this.getTile().getWorldObj(), this.proxy.getGrid(), cg, this.mySrc ) || this.didSomething; + this.didSomething = this.craftingTracker.handleCrafting( slotToExport, this.itemToSend, ais, destination, this.getTile().getWorldObj(), this.proxy.getGrid(), cg, this.mySrc ) || this.didSomething; } continue; } - long before = this.itemToSend; + final long before = this.itemToSend; if( this.getInstalledUpgrades( Upgrades.FUZZY ) > 0 ) { for( IAEItemStack o : ImmutableList.copyOf( inv.getStorageList().findFuzzy( ais, fzMode ) ) ) { - this.pushItemIntoTarget( d, energy, inv, o ); + this.pushItemIntoTarget( destination, energy, inv, o ); if( this.itemToSend <= 0 ) { break; @@ -164,14 +155,20 @@ public class PartExportBus extends PartSharedItemBus implements ICraftingRequest } else { - this.pushItemIntoTarget( d, energy, inv, ais ); + this.pushItemIntoTarget( destination, energy, inv, ais ); } if( this.itemToSend == before && this.isCraftingEnabled() ) { - this.didSomething = this.cratingTracker.handleCrafting( x, this.itemToSend, ais, d, this.getTile().getWorldObj(), this.proxy.getGrid(), cg, this.mySrc ) || this.didSomething; + this.didSomething = this.craftingTracker.handleCrafting( slotToExport, this.itemToSend, ais, destination, this.getTile().getWorldObj(), this.proxy.getGrid(), cg, this.mySrc ) || this.didSomething; } } + + this.updateSchedulingMode( schedulingMode, x ); + } + else + { + return TickRateModulation.SLEEP; } } catch( GridAccessException e ) @@ -195,7 +192,6 @@ public class PartExportBus extends PartSharedItemBus implements ICraftingRequest @SideOnly( Side.CLIENT ) public void renderInventory( IPartRenderHelper rh, RenderBlocks renderer ) { - rh.setTexture( CableBusTextures.PartExportSides.getIcon(), CableBusTextures.PartExportSides.getIcon(), CableBusTextures.PartMonitorBack.getIcon(), this.is.getIconIndex(), CableBusTextures.PartExportSides.getIcon(), CableBusTextures.PartExportSides.getIcon() ); rh.setBounds( 4, 4, 12, 12, 12, 14 ); @@ -261,12 +257,6 @@ public class PartExportBus extends PartSharedItemBus implements ICraftingRequest return new TickingRequest( TickRates.ExportBus.min, TickRates.ExportBus.max, this.isSleeping(), false ); } - @Override - protected boolean isSleeping() - { - return this.getHandler() == null || super.isSleeping(); - } - @Override public RedstoneMode getRSMode() { @@ -279,66 +269,24 @@ public class PartExportBus extends PartSharedItemBus implements ICraftingRequest return this.doBusWork(); } - private boolean craftOnly() - { - return this.getConfigManager().getSetting( Settings.CRAFT_ONLY ) == YesNo.YES; - } - - private boolean isCraftingEnabled() - { - return this.getInstalledUpgrades( Upgrades.CRAFTING ) > 0; - } - - private void pushItemIntoTarget( InventoryAdaptor d, IEnergyGrid energy, IMEInventory inv, IAEItemStack ais ) - { - ItemStack is = ais.getItemStack(); - is.stackSize = (int) this.itemToSend; - - ItemStack o = d.simulateAdd( is ); - long canFit = o == null ? this.itemToSend : this.itemToSend - o.stackSize; - - if( canFit > 0 ) - { - ais = ais.copy(); - ais.setStackSize( canFit ); - IAEItemStack itemsToAdd = Platform.poweredExtraction( energy, inv, ais, this.mySrc ); - - if( itemsToAdd != null ) - { - this.itemToSend -= itemsToAdd.getStackSize(); - - ItemStack failed = d.addItems( itemsToAdd.getItemStack() ); - if( failed != null ) - { - ais.setStackSize( failed.stackSize ); - inv.injectItems( ais, Actionable.MODULATE, this.mySrc ); - } - else - { - this.didSomething = true; - } - } - } - } - @Override public ImmutableSet getRequestedJobs() { - return this.cratingTracker.getRequestedJobs(); + return this.craftingTracker.getRequestedJobs(); } @Override public IAEItemStack injectCraftedItems( ICraftingLink link, IAEItemStack items, Actionable mode ) { - InventoryAdaptor d = this.getHandler(); + final InventoryAdaptor d = this.getHandler(); try { if( d != null && this.proxy.isActive() ) { - IEnergyGrid energy = this.proxy.getEnergy(); + final IEnergyGrid energy = this.proxy.getEnergy(); + final double power = items.getStackSize(); - double power = items.getStackSize(); if( energy.extractAEPower( power, mode, PowerMultiplier.CONFIG ) > power - 0.01 ) { if( mode == Actionable.MODULATE ) @@ -360,6 +308,77 @@ public class PartExportBus extends PartSharedItemBus implements ICraftingRequest @Override public void jobStateChange( ICraftingLink link ) { - this.cratingTracker.jobStateChange( link ); + this.craftingTracker.jobStateChange( link ); + } + + @Override + protected boolean isSleeping() + { + return this.getHandler() == null || super.isSleeping(); + } + + private boolean craftOnly() + { + return this.getConfigManager().getSetting( Settings.CRAFT_ONLY ) == YesNo.YES; + } + + private boolean isCraftingEnabled() + { + return this.getInstalledUpgrades( Upgrades.CRAFTING ) > 0; + } + + private void pushItemIntoTarget( InventoryAdaptor d, IEnergyGrid energy, IMEInventory inv, IAEItemStack ais ) + { + final ItemStack is = ais.getItemStack(); + is.stackSize = (int) this.itemToSend; + + final ItemStack o = d.simulateAdd( is ); + long canFit = o == null ? this.itemToSend : this.itemToSend - o.stackSize; + + if( canFit > 0 ) + { + ais = ais.copy(); + ais.setStackSize( canFit ); + IAEItemStack itemsToAdd = Platform.poweredExtraction( energy, inv, ais, this.mySrc ); + + if( itemsToAdd != null ) + { + this.itemToSend -= itemsToAdd.getStackSize(); + + final ItemStack failed = d.addItems( itemsToAdd.getItemStack() ); + if( failed != null ) + { + ais.setStackSize( failed.stackSize ); + inv.injectItems( ais, Actionable.MODULATE, this.mySrc ); + } + else + { + this.didSomething = true; + } + } + } + } + + private int getStartingSlot( SchedulingMode schedulingMode, int x ) + { + if( schedulingMode == SchedulingMode.RANDOM ) + { + return Platform.getRandom().nextInt( this.availableSlots() ); + } + + if( schedulingMode == SchedulingMode.ROUNDROBIN ) + { + return ( this.nextSlot + x ) % this.availableSlots(); + } + + return x; + } + + private void updateSchedulingMode( SchedulingMode schedulingMode, int x ) + { + if( schedulingMode == SchedulingMode.ROUNDROBIN ) + { + this.nextSlot = ( this.nextSlot + x ) % this.availableSlots(); + } } } diff --git a/src/main/java/appeng/parts/automation/PartImportBus.java b/src/main/java/appeng/parts/automation/PartImportBus.java index 81200b298..bf02daa79 100644 --- a/src/main/java/appeng/parts/automation/PartImportBus.java +++ b/src/main/java/appeng/parts/automation/PartImportBus.java @@ -59,8 +59,8 @@ import appeng.util.inv.IInventoryDestination; public class PartImportBus extends PartSharedItemBus implements IInventoryDestination { private final BaseActionSource source; - IMEInventory destination = null; - IAEItemStack lastItemChecked = null; + private IMEInventory destination = null; + private IAEItemStack lastItemChecked = null; private int itemToSend; // used in tickingRequest private boolean worked; // used in tickingRequest @@ -82,7 +82,7 @@ public class PartImportBus extends PartSharedItemBus implements IInventoryDestin return false; } - IAEItemStack out = this.destination.injectItems( this.lastItemChecked = AEApi.instance().storage().createItemStack( stack ), Actionable.SIMULATE, this.source ); + final IAEItemStack out = this.destination.injectItems( this.lastItemChecked = AEApi.instance().storage().createItemStack( stack ), Actionable.SIMULATE, this.source ); if( out == null ) { return true; @@ -173,50 +173,32 @@ public class PartImportBus extends PartSharedItemBus implements IInventoryDestin } @Override - TickRateModulation doBusWork() + protected TickRateModulation doBusWork() { - if( !this.proxy.isActive() ) + if( !this.proxy.isActive() || !this.canDoBusWork() ) { return TickRateModulation.IDLE; } this.worked = false; - InventoryAdaptor myAdaptor = this.getHandler(); - FuzzyMode fzMode = (FuzzyMode) this.getConfigManager().getSetting( Settings.FUZZY_MODE ); + final InventoryAdaptor myAdaptor = this.getHandler(); + final FuzzyMode fzMode = (FuzzyMode) this.getConfigManager().getSetting( Settings.FUZZY_MODE ); if( myAdaptor != null ) { try { - switch( this.getInstalledUpgrades( Upgrades.SPEED ) ) - { - default: - case 0: - this.itemToSend = 1; - break; - case 1: - this.itemToSend = 8; - break; - case 2: - this.itemToSend = 32; - break; - case 3: - this.itemToSend = 64; - break; - case 4: - this.itemToSend = 96; - break; - } - + this.itemToSend = this.calculateItemsToSend(); this.itemToSend = Math.min( this.itemToSend, (int) ( 0.01 + this.proxy.getEnergy().extractAEPower( this.itemToSend, Actionable.SIMULATE, PowerMultiplier.CONFIG ) ) ); - IMEMonitor inv = this.proxy.getStorage().getItemInventory(); - IEnergyGrid energy = this.proxy.getEnergy(); + + final IMEMonitor inv = this.proxy.getStorage().getItemInventory(); + final IEnergyGrid energy = this.proxy.getEnergy(); boolean Configured = false; for( int x = 0; x < this.availableSlots(); x++ ) { - IAEItemStack ais = this.config.getAEStackInSlot( x ); + final IAEItemStack ais = this.config.getAEStackInSlot( x ); if( ais != null && this.itemToSend > 0 ) { Configured = true; @@ -256,14 +238,9 @@ public class PartImportBus extends PartSharedItemBus implements IInventoryDestin private boolean importStuff( InventoryAdaptor myAdaptor, IAEItemStack whatToImport, IMEMonitor inv, IEnergySource energy, FuzzyMode fzMode ) { - int toSend = this.itemToSend; - - if( toSend > 64 ) - { - toSend = 64; - } - + final int toSend = Math.min( this.itemToSend, 64 ); ItemStack newItems; + if( this.getInstalledUpgrades( Upgrades.FUZZY ) > 0 ) { newItems = myAdaptor.removeSimilarItems( toSend, whatToImport == null ? null : whatToImport.getItemStack(), fzMode, this.configDestination( inv ) ); diff --git a/src/main/java/appeng/parts/automation/PartSharedItemBus.java b/src/main/java/appeng/parts/automation/PartSharedItemBus.java index 01d4ca075..6cfe11ae1 100644 --- a/src/main/java/appeng/parts/automation/PartSharedItemBus.java +++ b/src/main/java/appeng/parts/automation/PartSharedItemBus.java @@ -37,21 +37,16 @@ import appeng.util.Platform; public abstract class PartSharedItemBus extends PartUpgradeable implements IGridTickable { - final AppEngInternalAEInventory config = new AppEngInternalAEInventory( this, 9 ); - int adaptorHash = 0; - InventoryAdaptor adaptor; - boolean lastRedstone = false; + protected final AppEngInternalAEInventory config = new AppEngInternalAEInventory( this, 9 ); + private int adaptorHash = 0; + private InventoryAdaptor adaptor; + private boolean lastRedstone = false; public PartSharedItemBus( ItemStack is ) { super( is ); } - protected int availableSlots() - { - return Math.min( 1 + this.getInstalledUpgrades( Upgrades.CAPACITY ) * 4, this.config.getSizeInventory() ); - } - @Override public void upgradesChanged() { @@ -83,6 +78,80 @@ public abstract class PartSharedItemBus extends PartUpgradeable implements IGrid return super.getInventoryByName( name ); } + @Override + public void onNeighborChanged() + { + this.updateState(); + if( this.lastRedstone != this.host.hasRedstone( this.side ) ) + { + this.lastRedstone = !this.lastRedstone; + if( this.lastRedstone && this.getRSMode() == RedstoneMode.SIGNAL_PULSE ) + { + this.doBusWork(); + } + } + } + + protected InventoryAdaptor getHandler() + { + final TileEntity self = this.getHost().getTile(); + final TileEntity target = this.getTileEntity( self, self.xCoord + this.side.offsetX, self.yCoord + this.side.offsetY, self.zCoord + this.side.offsetZ ); + + final int newAdaptorHash = Platform.generateTileHash( target ); + + if( this.adaptorHash == newAdaptorHash && newAdaptorHash != 0 ) + { + return this.adaptor; + } + + this.adaptorHash = newAdaptorHash; + this.adaptor = InventoryAdaptor.getAdaptor( target, this.side.getOpposite() ); + + return this.adaptor; + } + + protected int availableSlots() + { + return Math.min( 1 + this.getInstalledUpgrades( Upgrades.CAPACITY ) * 4, this.config.getSizeInventory() ); + } + + protected int calculateItemsToSend() + { + switch( this.getInstalledUpgrades( Upgrades.SPEED ) ) + { + default: + case 0: + return 1; + case 1: + return 8; + case 2: + return 32; + case 3: + return 64; + case 4: + return 96; + } + } + + /** + * Checks if the bus can actually do something. + * + * Currently this tests if the chunk for the target is actually loaded. + * + * @return true, if the the bus should do its work. + */ + protected boolean canDoBusWork() + { + final TileEntity self = this.getHost().getTile(); + final TileEntity target = this.getTileEntity( self, self.xCoord + this.side.offsetX, self.yCoord + this.side.offsetY, self.zCoord + this.side.offsetZ ); + + final World world = target.getWorldObj(); + final int xCoordinate = target.xCoord; + final int zCoordinate = target.zCoord; + + return world != null && world.getChunkProvider().chunkExists( xCoordinate >> 4, zCoordinate >> 4 ); + } + private void updateState() { try @@ -102,27 +171,9 @@ public abstract class PartSharedItemBus extends PartUpgradeable implements IGrid } } - InventoryAdaptor getHandler() - { - TileEntity self = this.getHost().getTile(); - TileEntity target = this.getTileEntity( self, self.xCoord + this.side.offsetX, self.yCoord + this.side.offsetY, self.zCoord + this.side.offsetZ ); - - int newAdaptorHash = Platform.generateTileHash( target ); - - if( this.adaptorHash == newAdaptorHash && newAdaptorHash != 0 ) - { - return this.adaptor; - } - - this.adaptorHash = newAdaptorHash; - this.adaptor = InventoryAdaptor.getAdaptor( target, this.side.getOpposite() ); - - return this.adaptor; - } - private TileEntity getTileEntity( TileEntity self, int x, int y, int z ) { - World w = self.getWorldObj(); + final World w = self.getWorldObj(); if( w.getChunkProvider().chunkExists( x >> 4, z >> 4 ) ) { @@ -132,19 +183,5 @@ public abstract class PartSharedItemBus extends PartUpgradeable implements IGrid return null; } - @Override - public void onNeighborChanged() - { - this.updateState(); - if( this.lastRedstone != this.host.hasRedstone( this.side ) ) - { - this.lastRedstone = !this.lastRedstone; - if( this.lastRedstone && this.getRSMode() == RedstoneMode.SIGNAL_PULSE ) - { - this.doBusWork(); - } - } - } - - abstract TickRateModulation doBusWork(); + protected abstract TickRateModulation doBusWork(); } diff --git a/src/main/resources/assets/appliedenergistics2/lang/en_US.lang b/src/main/resources/assets/appliedenergistics2/lang/en_US.lang index cc68cd06a..b70a5ddc0 100644 --- a/src/main/resources/assets/appliedenergistics2/lang/en_US.lang +++ b/src/main/resources/assets/appliedenergistics2/lang/en_US.lang @@ -313,6 +313,10 @@ gui.tooltips.appliedenergistics2.ReportInaccessibleItemsNo=No: Only extractable gui.tooltips.appliedenergistics2.BlockPlacement=Block Placement gui.tooltips.appliedenergistics2.BlockPlacementYes=Blocks will be placed as block. gui.tooltips.appliedenergistics2.BlockPlacementNo=Blocks will be dropped as item. +gui.tooltips.appliedenergistics2.SchedulingMode=Scheduling Mode +gui.tooltips.appliedenergistics2.SchedulingModeDefault=Export the first item until the network is empty, then try the next ones. +gui.tooltips.appliedenergistics2.SchedulingModeRoundRobin=Export using round robin mode. +gui.tooltips.appliedenergistics2.SchedulingModeRandom=Export items in random mode. gui.tooltips.appliedenergistics2.ItemsStored=Items Stored: %s gui.tooltips.appliedenergistics2.ItemsRequestable=Items Requestable: %s diff --git a/src/main/resources/assets/appliedenergistics2/textures/guis/states.png b/src/main/resources/assets/appliedenergistics2/textures/guis/states.png index c72f864a66cb9f2c7585196446b15faabfe04756..8e692d7a8c5b48d0830b39aeb399b46acfa3b925 100644 GIT binary patch delta 10964 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 t*!rU)PW79{|C<6lngQu&X%Q~loCIFv}!vX*R delta 10619 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 GGywoz-$