diff --git a/src/main/java/reobf/proghatches/ae/DummyCluster.java b/src/main/java/reobf/proghatches/ae/DummyCluster.java new file mode 100644 index 0000000..7d65dff --- /dev/null +++ b/src/main/java/reobf/proghatches/ae/DummyCluster.java @@ -0,0 +1,1291 @@ +/* + * This file is part of Applied Energistics 2. Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved. Applied + * Energistics 2 is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General + * Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any + * later version. Applied Energistics 2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General + * Public License for more details. You should have received a copy of the GNU Lesser General Public License along with + * Applied Energistics 2. If not, see . + */ + +package reobf.proghatches.ae; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.stream.IntStream; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.IChatComponent; +import net.minecraft.util.StatCollector; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; + +import appeng.api.AEApi; +import appeng.api.config.Actionable; +import appeng.api.config.FuzzyMode; +import appeng.api.config.PowerMultiplier; +import appeng.api.config.Upgrades; +import appeng.api.implementations.ICraftingPatternItem; +import appeng.api.networking.IGrid; +import appeng.api.networking.IGridHost; +import appeng.api.networking.IGridNode; +import appeng.api.networking.crafting.CraftingItemList; +import appeng.api.networking.crafting.ICraftingCPU; +import appeng.api.networking.crafting.ICraftingGrid; +import appeng.api.networking.crafting.ICraftingJob; +import appeng.api.networking.crafting.ICraftingLink; +import appeng.api.networking.crafting.ICraftingMedium; +import appeng.api.networking.crafting.ICraftingPatternDetails; +import appeng.api.networking.crafting.ICraftingProvider; +import appeng.api.networking.crafting.ICraftingRequester; +import appeng.api.networking.energy.IEnergyGrid; +import appeng.api.networking.events.MENetworkCraftingCpuChange; +import appeng.api.networking.security.BaseActionSource; +import appeng.api.networking.security.MachineSource; +import appeng.api.networking.security.PlayerSource; +import appeng.api.networking.storage.IStorageGrid; +import appeng.api.storage.IMEInventory; +import appeng.api.storage.IMEMonitorHandlerReceiver; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.storage.data.IAEStack; +import appeng.api.storage.data.IItemList; +import appeng.api.util.DimensionalCoord; +import appeng.api.util.IInterfaceViewable; +import appeng.api.util.WorldCoord; +import appeng.container.ContainerNull; +import appeng.core.AELog; +import appeng.core.localization.PlayerMessages; +import appeng.crafting.CraftBranchFailure; +import appeng.crafting.CraftingLink; +import appeng.crafting.CraftingWatcher; +import appeng.crafting.MECraftingInventory; +import appeng.helpers.DualityInterface; +import appeng.me.cache.CraftingGridCache; +import appeng.me.cluster.IAECluster; +import appeng.tile.AEBaseTile; +import appeng.tile.crafting.TileCraftingMonitorTile; +import appeng.tile.crafting.TileCraftingTile; +import appeng.util.Platform; +import appeng.util.item.AEItemStack; +import cpw.mods.fml.common.FMLCommonHandler; + +public final class DummyCluster implements IAECluster, ICraftingCPU { + + private static final String LOG_MARK_AS_COMPLETE = "Completed job for %s."; + + private final WorldCoord min; + private final WorldCoord max; + private final int[] usedOps = new int[3]; + private final Map tasks = new HashMap<>(); + private Map workableTasks = new HashMap<>(); + private HashSet knownBusyMediums = new HashSet<>(); + // INSTANCE sate + private final LinkedList tiles = new LinkedList<>(); + private final LinkedList storage = new LinkedList<>(); + private final LinkedList status = new LinkedList<>(); + private final HashMap, Object> listeners = new HashMap<>(); + private final HashMap> providers = new HashMap<>(); + private ICraftingLink myLastLink; + private String myName = ""; + private boolean isDestroyed = false; + /** + * crafting job info + */ + private MECraftingInventory inventory = new MECraftingInventory(); + + private IAEItemStack finalOutput; + private boolean waiting = false; + private IItemList waitingFor = AEApi.instance().storage().createItemList(); + private long availableStorage = 0; + private MachineSource machineSrc = null; + private int accelerator = 0; + private boolean isComplete = true; + private int remainingOperations; + private boolean somethingChanged; + + private long lastTime; + private long elapsedTime; + private long startItemCount; + private long remainingItemCount; + + public DummyCluster(final WorldCoord min, final WorldCoord max) { + this.min = min; + this.max = max; + } + + @Override + public IAEItemStack getFinalOutput() { + return finalOutput; + } + + public boolean isDestroyed() { + return this.isDestroyed; + } + + public ICraftingLink getLastCraftingLink() { + return this.myLastLink; + } + + /** + * add a new Listener to the monitor, be sure to properly remove yourself when your done. + */ + @Override + public void addListener(final IMEMonitorHandlerReceiver l, final Object verificationToken) { + this.listeners.put(l, verificationToken); + } + + /** + * remove a Listener to the monitor. + */ + @Override + public void removeListener(final IMEMonitorHandlerReceiver l) { + this.listeners.remove(l); + } + + public IMEInventory getInventory() { + return this.inventory; + } + + @Override + public void updateStatus(final boolean updateGrid) { + for (final TileCraftingTile r : this.tiles) { + r.updateMeta(true); + } + } + + @Override + public void destroy() { + if (this.isDestroyed) { + return; + } + this.isDestroyed = true; + + boolean posted = false; + + for (final TileCraftingTile r : this.tiles) { + final IGridNode n = r.getActionableNode(); + if (n != null && !posted) { + final IGrid g = n.getGrid(); + if (g != null) { + g.postEvent(new MENetworkCraftingCpuChange(n)); + posted = true; + } + } + + r.updateStatus(null); + } + } + + @Override + public Iterator getTiles() { + return (Iterator) this.tiles.iterator(); + } + + void addTile(final TileCraftingTile te) { + if (this.machineSrc == null || te.isCoreBlock()) { + this.machineSrc = new MachineSource(te); + } + + te.setCoreBlock(false); + te.markDirty(); + this.tiles.push(te); + + if (te.isStorage()) { + long additionalStorage = te.getStorageBytes(); + if (Long.MAX_VALUE - additionalStorage >= this.availableStorage) { + // Safe to add as it does not cause overflow + this.availableStorage += additionalStorage; + this.storage.add(te); + } else { + // Prevent form CPU if storage overflowed + this.tiles.remove(te); + } + } else if (te.isStatus()) { + this.status.add((TileCraftingMonitorTile) te); + } else if (te.isAccelerator()) { + this.accelerator += te.acceleratorValue(); + } + } + + public boolean canAccept(final IAEStack input) { + if (input instanceof IAEItemStack) { + final IAEItemStack is = this.waitingFor.findPrecise((IAEItemStack) input); + if (is != null && is.getStackSize() > 0) { + return true; + } + } + return false; + } + + public IAEStack injectItems(final IAEStack input, final Actionable type, final BaseActionSource src) { + if (!(input instanceof IAEItemStack)) { + return input; + } + + final IAEItemStack what = (IAEItemStack) input.copy(); + final IAEItemStack is = this.waitingFor.findPrecise(what); + + if (type == Actionable.SIMULATE) // causes crafting to lock up? + { + if (is != null && is.getStackSize() > 0) { + if (is.getStackSize() >= what.getStackSize()) { + if (Objects.equals(this.finalOutput, what)) { + if (this.myLastLink != null) { + return ((CraftingLink) this.myLastLink).injectItems(what.copy(), type); + } + + return what; // ignore it. + } + + return null; + } + + final IAEItemStack leftOver = what.copy(); + leftOver.decStackSize(is.getStackSize()); + + final IAEItemStack used = what.copy(); + used.setStackSize(is.getStackSize()); + + if (Objects.equals(finalOutput, what)) { + if (this.myLastLink != null) { + leftOver.add(((CraftingLink) this.myLastLink).injectItems(used.copy(), type)); + return leftOver; + } + + return what; // ignore it. + } + + return leftOver; + } + } else if (type == Actionable.MODULATE) { + if (is != null && is.getStackSize() > 0) { + this.waiting = false; + + this.postChange(what, src); + + if (is.getStackSize() >= what.getStackSize()) { + is.decStackSize(what.getStackSize()); + + this.updateElapsedTime(what); + this.markDirty(); + this.postCraftingStatusChange(is); + + if (Objects.equals(finalOutput, what)) { + IAEStack leftover = what; + + this.finalOutput.decStackSize(what.getStackSize()); + + if (this.myLastLink != null) { + leftover = ((CraftingLink) this.myLastLink).injectItems(what, type); + } + + if (this.finalOutput.getStackSize() <= 0) { + this.completeJob(); + } + + this.updateCPU(); + + return leftover; // ignore it. + } + + // 2000 + return this.inventory.injectItems(what, type, src); + } + + final IAEItemStack insert = what.copy(); + insert.setStackSize(is.getStackSize()); + what.decStackSize(is.getStackSize()); + + is.setStackSize(0); + + if (Objects.equals(finalOutput, insert)) { + IAEStack leftover = input; + + this.finalOutput.decStackSize(insert.getStackSize()); + + if (this.myLastLink != null) { + what.add(((CraftingLink) this.myLastLink).injectItems(insert.copy(), type)); + leftover = what; + } + + if (this.finalOutput.getStackSize() <= 0) { + this.completeJob(); + } + + this.updateCPU(); + this.markDirty(); + + return leftover; // ignore it. + } + + this.inventory.injectItems(insert, type, src); + this.markDirty(); + + return what; + } + } + + return input; + } + + private void postChange(final IAEItemStack diff, final BaseActionSource src) { + final Iterator, Object>> i = this.getListeners(); + + // protect integrity + if (i.hasNext()) { + final ImmutableList single = ImmutableList.of(diff.copy()); + + while (i.hasNext()) { + final Entry, Object> o = i.next(); + final IMEMonitorHandlerReceiver receiver = o.getKey(); + + if (receiver.isValid(o.getValue())) { + receiver.postChange(null, single, src); + } else { + i.remove(); + } + } + } + } + + private void markDirty() { + this.getCore().markDirty(); + } + + private void postCraftingStatusChange(final IAEItemStack diff) { + if (this.getGrid() == null) { + return; + } + + final CraftingGridCache sg = this.getGrid().getCache(ICraftingGrid.class); + + if (sg.getInterestManager().containsKey(diff)) { + final Collection list = sg.getInterestManager().get(diff); + + if (!list.isEmpty()) { + for (final CraftingWatcher iw : list) { + + iw.getHost().onRequestChange(sg, diff); + } + } + } + } + + private void completeJob() { + if (this.myLastLink != null) { + ((CraftingLink) this.myLastLink).markDone(); + } + + if (AELog.isCraftingLogEnabled()) { + final IAEItemStack logStack = this.finalOutput.copy(); + logStack.setStackSize(this.startItemCount); + AELog.crafting(LOG_MARK_AS_COMPLETE, logStack); + } + + this.remainingItemCount = 0; + this.startItemCount = 0; + this.lastTime = 0; + this.elapsedTime = 0; + this.isComplete = true; + } + + private void updateCPU() { + IAEItemStack send = this.finalOutput; + + if (this.finalOutput != null && this.finalOutput.getStackSize() <= 0) { + send = null; + } + + for (final TileCraftingMonitorTile t : this.status) { + t.setJob(send); + } + } + + private Iterator, Object>> getListeners() { + return this.listeners.entrySet().iterator(); + } + + private TileCraftingTile getCore() { + return (TileCraftingTile) this.machineSrc.via; + } + + private IGrid getGrid() { + for (final TileCraftingTile r : this.tiles) { + final IGridNode gn = r.getActionableNode(); + if (gn != null) { + final IGrid g = gn.getGrid(); + if (g != null) { + return r.getActionableNode().getGrid(); + } + } + } + + return null; + } + + private ArrayList getExtractItems(IAEItemStack ingredient, ICraftingPatternDetails patternDetails) { + ArrayList list = new ArrayList<>(); + if (patternDetails.canSubstitute()) { + for (IAEItemStack fuzz : this.inventory.getItemList().findFuzzy(ingredient, FuzzyMode.IGNORE_ALL)) { + if (!patternDetails.isCraftable() && fuzz.getStackSize() <= 0) continue; + if (patternDetails.isCraftable()) { + final IAEItemStack[] inputSlots = patternDetails.getInputs(); + final IAEItemStack finalIngredient = ingredient; // have to copy because of Java lambda capture + // rules here + final int matchingSlot = IntStream.range(0, inputSlots.length) + .filter(idx -> inputSlots[idx] != null && Objects.equals(inputSlots[idx], finalIngredient)) + .findFirst().orElse(-1); + if (matchingSlot < 0) { + continue; + } + if (!patternDetails.isValidItemForSlot(matchingSlot, fuzz.getItemStack(), getWorld())) { + // Skip invalid fuzzy matches + continue; + } + } + fuzz = fuzz.copy(); + fuzz.setStackSize(ingredient.getStackSize()); + final IAEItemStack ais = this.inventory.extractItems(fuzz, Actionable.SIMULATE, this.machineSrc); + final ItemStack is = ais == null ? null : ais.getItemStack(); + + if (is != null && is.stackSize == ingredient.getStackSize()) { + list.add(ais); + return list; + } else if (is != null && patternDetails.isCraftable()) { + ingredient = ingredient.copy(); + ingredient.decStackSize(is.stackSize); + list.add(ais); + } + } + } else { + final IAEItemStack extractItems = this.inventory + .extractItems(ingredient, Actionable.SIMULATE, this.machineSrc); + final ItemStack is = extractItems == null ? null : extractItems.getItemStack(); + if (is != null && is.stackSize == ingredient.getStackSize()) { + list.add(extractItems); + return list; + } + } + return list; + } + + private boolean canCraft(final ICraftingPatternDetails details, final IAEItemStack[] condensedInputs) { + for (IAEItemStack g : condensedInputs) { + if (getExtractItems(g, details).isEmpty()) { + return false; + } + } + return true; + } + + public void cancel() { + if (this.myLastLink != null) { + this.myLastLink.cancel(); + } + + final IItemList list; + this.getListOfItem(list = AEApi.instance().storage().createItemList(), CraftingItemList.ALL); + for (final IAEItemStack is : list) { + this.postChange(is, this.machineSrc); + } + + this.isComplete = true; + this.myLastLink = null; + this.tasks.clear(); + this.providers.clear(); + final ImmutableSet items = ImmutableSet.copyOf(this.waitingFor); + + this.waitingFor.resetStatus(); + + for (final IAEItemStack is : items) { + this.postCraftingStatusChange(is); + } + + this.finalOutput = null; + this.updateCPU(); + + this.storeItems(); // marks dirty + } + + public void updateCraftingLogic(final IGrid grid, final IEnergyGrid eg, final CraftingGridCache cc) { + if (!this.getCore().isActive()) { + return; + } + + if (this.myLastLink != null) { + if (this.myLastLink.isCanceled()) { + this.myLastLink = null; + this.cancel(); + } + } + + if (this.isComplete) { + if (this.inventory.getItemList().isEmpty()) { + return; + } + + this.storeItems(); + return; + } + + this.waiting = false; + if (this.waiting || this.tasks.isEmpty()) // nothing to do here... + { + return; + } + + this.remainingOperations = this.accelerator + 1 - (this.usedOps[0] + this.usedOps[1] + this.usedOps[2]); + final int started = this.remainingOperations; + + // Shallow copy tasks so we may remove them after visiting + this.workableTasks = new HashMap<>(this.tasks); + this.knownBusyMediums.clear(); + if (this.remainingOperations > 0) { + do { + this.somethingChanged = false; + this.executeCrafting(eg, cc); + } while (this.somethingChanged && this.remainingOperations > 0); + } + this.usedOps[2] = this.usedOps[1]; + this.usedOps[1] = this.usedOps[0]; + this.usedOps[0] = started - this.remainingOperations; + + this.workableTasks.clear(); + this.knownBusyMediums.clear(); + + if (this.remainingOperations > 0 && !this.somethingChanged) { + this.waiting = true; + } + } + + private void executeCrafting(final IEnergyGrid eg, final CraftingGridCache cc) { + final Iterator> i = this.workableTasks.entrySet().iterator(); + + while (i.hasNext()) { + final Entry e = i.next(); + + if (e.getValue().value <= 0) { + this.tasks.remove(e.getKey()); + i.remove(); + continue; + } + + final ICraftingPatternDetails details = e.getKey(); + if (!this.canCraft(details, details.getCondensedInputs())) { + i.remove(); // No need to revisit this task on next executeCrafting this tick + continue; + } + + InventoryCrafting ic = null; + boolean pushedPattern = false; + + for (final ICraftingMedium m : cc.getMediums(e.getKey())) { + if (e.getValue().value <= 0 || knownBusyMediums.contains(m)) { + continue; + } + + if (m.isBusy()) { + knownBusyMediums.add(m); + continue; + } + + double sum = 0; + if (ic == null) { + final IAEItemStack[] input = details.getInputs(); + + for (final IAEItemStack anInput : input) { + if (anInput != null) { + sum += anInput.getStackSize(); + } + } + // upgraded interface uses more power + if (m instanceof DualityInterface) + sum *= Math.pow(4.0, ((DualityInterface) m).getInstalledUpgrades(Upgrades.PATTERN_CAPACITY)); + + // check if there is enough power + if (eg.extractAEPower(sum, Actionable.SIMULATE, PowerMultiplier.CONFIG) < sum - 0.01) continue; + + ic = details.isCraftable() ? new InventoryCrafting(new ContainerNull(), 3, 3) + : new InventoryCrafting(new ContainerNull(), details.getInputs().length, 1); + + boolean found = false; + for (int x = 0; x < input.length; x++) { + if (input[x] != null) { + found = false; + for (IAEItemStack ias : getExtractItems(input[x], details)) { + if (details.isCraftable() + && !details.isValidItemForSlot(x, ias.getItemStack(), this.getWorld())) { + continue; + } + final IAEItemStack ais = this.inventory + .extractItems(ias, Actionable.MODULATE, this.machineSrc); + final ItemStack is = ais == null ? null : ais.getItemStack(); + if (is == null) continue; + found = true; + ic.setInventorySlotContents(x, is); + if (!details.canBeSubstitute() && is.stackSize == input[x].getStackSize()) { + this.postChange(input[x], this.machineSrc); + break; + } else { + this.postChange(AEItemStack.create(is), this.machineSrc); + } + } + if (!found) { + break; + } + } + } + + if (!found) { + // put stuff back.. + for (int x = 0; x < ic.getSizeInventory(); x++) { + final ItemStack is = ic.getStackInSlot(x); + if (is != null) { + this.inventory + .injectItems(AEItemStack.create(is), Actionable.MODULATE, this.machineSrc); + } + } + ic = null; + break; + } + } + + if (m.pushPattern(details, ic)) { + eg.extractAEPower(sum, Actionable.MODULATE, PowerMultiplier.CONFIG); + this.somethingChanged = true; + this.remainingOperations--; + pushedPattern = true; + + for (final IAEItemStack out : details.getCondensedOutputs()) { + this.postChange(out, this.machineSrc); + this.waitingFor.add(out.copy()); + this.postCraftingStatusChange(out.copy()); + providers.computeIfAbsent(out, k -> new ArrayList<>()); + List list = providers.get(out); + if (m instanceof ICraftingProvider) { + TileEntity tile = this.getTile(m); + if (tile == null) continue; + DimensionalCoord tileDimensionalCoord = new DimensionalCoord(tile); + boolean isAdded = false; + for (DimensionalCoord dimensionalCoord : list) { + if (dimensionalCoord.isEqual(tileDimensionalCoord)) { + isAdded = true; + break; + } + } + if (!isAdded) { + list.add(tileDimensionalCoord); + } + } + } + + if (details.isCraftable()) { + FMLCommonHandler.instance().firePlayerCraftingEvent( + Platform.getPlayer((WorldServer) this.getWorld()), + details.getOutput(ic, this.getWorld()), + ic); + + for (int x = 0; x < ic.getSizeInventory(); x++) { + final ItemStack output = Platform.getContainerItem(ic.getStackInSlot(x)); + if (output != null) { + final IAEItemStack cItem = AEItemStack.create(output); + this.postChange(cItem, this.machineSrc); + this.waitingFor.add(cItem); + this.postCraftingStatusChange(cItem); + } + } + } + + ic = null; // hand off complete! + this.markDirty(); + + e.getValue().value--; + if (e.getValue().value <= 0) { + continue; + } + + if (this.remainingOperations == 0) { + return; + } + } + } + + if (!pushedPattern) { + // No need to revisit this task on next executeCrafting this tick + i.remove(); + } + + if (ic != null) { + // put stuff back.. + for (int x = 0; x < ic.getSizeInventory(); x++) { + final ItemStack is = ic.getStackInSlot(x); + if (is != null) { + this.inventory.injectItems(AEItemStack.create(is), Actionable.MODULATE, this.machineSrc); + } + } + } + } + } + + private void storeItems() { + final IGrid g = this.getGrid(); + + if (g == null) { + return; + } + + final IStorageGrid sg = g.getCache(IStorageGrid.class); + final IMEInventory ii = sg.getItemInventory(); + + for (IAEItemStack is : this.inventory.getItemList()) { + is = this.inventory.extractItems(is.copy(), Actionable.MODULATE, this.machineSrc); + + if (is != null) { + this.postChange(is, this.machineSrc); + is = ii.injectItems(is, Actionable.MODULATE, this.machineSrc); + } + + if (is != null) { + this.inventory.injectItems(is, Actionable.MODULATE, this.machineSrc); + } + } + + if (this.inventory.getItemList().isEmpty()) { + this.inventory = new MECraftingInventory(); + } + + this.markDirty(); + } + + public ICraftingLink submitJob(final IGrid g, final ICraftingJob job, final BaseActionSource src, + final ICraftingRequester requestingMachine) { + if (!this.tasks.isEmpty() || !this.waitingFor.isEmpty()) { + return null; + } + + if (this.isBusy() || !this.isActive() || this.availableStorage < job.getByteTotal()) { + return null; + } + + if (!job.supportsCPUCluster(this)) { + return null; + } + this.providers.clear(); + final IStorageGrid sg = g.getCache(IStorageGrid.class); + final IMEInventory storage = sg.getItemInventory(); + final MECraftingInventory ci = new MECraftingInventory(storage, true, false, false); + + try { + this.waitingFor.resetStatus(); + job.startCrafting(ci, this, src); + if (ci.commit(src)) { + if (job.getOutput() != null) { + this.finalOutput = job.getOutput(); + this.waiting = false; + this.isComplete = false; + this.markDirty(); + + this.updateCPU(); + final String craftID = this.generateCraftingID(); + + this.myLastLink = new CraftingLink( + this.generateLinkData(craftID, requestingMachine == null, false), + this); + + this.prepareElapsedTime(); + + if (requestingMachine == null) { + return this.myLastLink; + } + + final ICraftingLink whatLink = new CraftingLink( + this.generateLinkData(craftID, false, true), + requestingMachine); + + this.submitLink(this.myLastLink); + this.submitLink(whatLink); + + final IItemList list = AEApi.instance().storage().createItemList(); + this.getListOfItem(list, CraftingItemList.ALL); + for (final IAEItemStack ge : list) { + this.postChange(ge, this.machineSrc); + } + + return whatLink; + } + } else { + this.tasks.clear(); + this.providers.clear(); + this.inventory.getItemList().resetStatus(); + } + } catch (final CraftBranchFailure e) { + + if (src instanceof PlayerSource) { + try { + EntityPlayer player = ((PlayerSource) src).player; + if (player != null) { + final IAEItemStack missingStack = e.getMissing(); + String missingName = "?"; + IChatComponent missingDisplayName = new ChatComponentText("?"); + long missingCount = -1; + if (missingStack != null && missingStack.getItem() != null) { + missingName = missingStack.getItemStack().getUnlocalizedName(); + if (StatCollector.canTranslate(missingName + ".name") + && StatCollector.translateToLocal(missingName + ".name") + .equals(missingStack.getItemStack().getDisplayName())) + missingDisplayName = new ChatComponentTranslation(missingName + ".name"); + else missingDisplayName = new ChatComponentText( + missingStack.getItemStack().getDisplayName()); + missingCount = missingStack.getStackSize(); + } + player.addChatMessage( + new ChatComponentTranslation( + PlayerMessages.CraftingItemsWentMissing.getName(), + missingCount, + missingName).appendText(" (").appendSibling(missingDisplayName) + .appendText(")")); + } + } catch (Exception ex) { + AELog.error(ex, "Could not notify player of crafting failure"); + } + } + + this.tasks.clear(); + this.providers.clear(); + this.inventory.getItemList().resetStatus(); + // AELog.error( e ); + } + + return null; + } + + @Override + public boolean isBusy() { + + this.tasks.entrySet().removeIf( + iCraftingPatternDetailsTaskProgressEntry -> iCraftingPatternDetailsTaskProgressEntry.getValue().value + <= 0); + + return !this.tasks.isEmpty() || !this.waitingFor.isEmpty(); + } + + @Override + public BaseActionSource getActionSource() { + return this.machineSrc; + } + + @Override + public long getAvailableStorage() { + return this.availableStorage; + } + + @Override + public int getCoProcessors() { + return this.accelerator; + } + + @Override + public String getName() { + return this.myName; + } + + public boolean isActive() { + final TileCraftingTile core = this.getCore(); + + if (core == null) { + return false; + } + + final IGridNode node = core.getActionableNode(); + if (node == null) { + return false; + } + + return node.isActive(); + } + + private String generateCraftingID() { + final long now = System.currentTimeMillis(); + final int hash = System.identityHashCode(this); + final int hmm = this.finalOutput == null ? 0 : this.finalOutput.hashCode(); + + return Long.toString(now, Character.MAX_RADIX) + '-' + + Integer.toString(hash, Character.MAX_RADIX) + + '-' + + Integer.toString(hmm, Character.MAX_RADIX); + } + + private NBTTagCompound generateLinkData(final String craftingID, final boolean standalone, final boolean req) { + final NBTTagCompound tag = new NBTTagCompound(); + + tag.setString("CraftID", craftingID); + tag.setBoolean("canceled", false); + tag.setBoolean("done", false); + tag.setBoolean("standalone", standalone); + tag.setBoolean("req", req); + + return tag; + } + + private void submitLink(final ICraftingLink myLastLink2) { + if (this.getGrid() != null) { + final CraftingGridCache cc = this.getGrid().getCache(ICraftingGrid.class); + cc.addLink((CraftingLink) myLastLink2); + } + } + + public void getListOfItem(final IItemList list, final CraftingItemList whichList) { + switch (whichList) { + case ACTIVE : { + for (final IAEItemStack ais : this.waitingFor) { + list.add(ais); + } + }break; + case PENDING : { + for (final Entry t : this.tasks.entrySet()) { + for (IAEItemStack ais : t.getKey().getCondensedOutputs()) { + ais = ais.copy(); + ais.setStackSize(ais.getStackSize() * t.getValue().value); + list.add(ais); + } + } + }break; + case STORAGE : this.inventory.getAvailableItems(list); + default : { + this.inventory.getAvailableItems(list); + for (final IAEItemStack ais : this.waitingFor) { + list.add(ais); + } + for (final Entry t : this.tasks.entrySet()) { + for (IAEItemStack ais : t.getKey().getCondensedOutputs()) { + ais = ais.copy(); + ais.setStackSize(ais.getStackSize() * t.getValue().value); + list.add(ais); + } + } + }break; + } + } + + public void addStorage(final IAEItemStack extractItems) { + this.inventory.injectItems(extractItems, Actionable.MODULATE, null); + } + + public void addEmitable(final IAEItemStack i) { + this.waitingFor.add(i); + this.postCraftingStatusChange(i); + } + + public void addCrafting(final ICraftingPatternDetails details, final long crafts) { + TaskProgress i = this.tasks.get(details); + + if (i == null) { + this.tasks.put(details, i = new TaskProgress()); + } + + i.value += crafts; + } + + public IAEItemStack getItemStack(final IAEItemStack what, final CraftingItemList storage2) { + IAEItemStack is; + switch (storage2) { + case STORAGE : is = this.inventory.getItemList().findPrecise(what);break; + case ACTIVE : is = this.waitingFor.findPrecise(what);break; + case PENDING : { + CraftingGridCache cache = null; + if (this.getGrid() != null) { + cache = this.getGrid().getCache(ICraftingGrid.class); + } + is = what.copy(); + is.setStackSize(0); + for (final Entry t : this.tasks.entrySet()) { + for (final IAEItemStack ais : t.getKey().getCondensedOutputs()) { + if (Objects.equals(ais, is)) { + is.setStackSize(is.getStackSize() + ais.getStackSize() * t.getValue().value); + if (cache != null) { + List craftingProviders = cache.getMediums(t.getKey()); + List dimensionalCoords = new ArrayList<>(); + for (ICraftingMedium craftingProvider : craftingProviders) { + final TileEntity tile = this.getTile(craftingProvider); + if (tile != null) dimensionalCoords.add(new DimensionalCoord(tile)); + } + this.providers.put(is, dimensionalCoords); + } + } + } + } + }break; + default : throw new IllegalStateException("Invalid Operation"); + } + + if (is != null) { + return is.copy(); + } + + is = what.copy(); + is.setStackSize(0); + return is; + } + + public void writeToNBT(final NBTTagCompound data) { + data.setTag("finalOutput", this.writeItem(this.finalOutput)); + data.setTag("inventory", this.writeList(this.inventory.getItemList())); + data.setBoolean("waiting", this.waiting); + data.setBoolean("isComplete", this.isComplete); + + if (this.myLastLink != null) { + final NBTTagCompound link = new NBTTagCompound(); + this.myLastLink.writeToNBT(link); + data.setTag("link", link); + } + + NBTTagList list = new NBTTagList(); + for (final Entry e : this.tasks.entrySet()) { + final NBTTagCompound item = this.writeItem(AEItemStack.create(e.getKey().getPattern())); + item.setLong("craftingProgress", e.getValue().value); + list.appendTag(item); + } + data.setTag("tasks", list); + + data.setTag("waitingFor", this.writeList(this.waitingFor)); + + data.setLong("elapsedTime", this.getElapsedTime()); + data.setLong("startItemCount", this.getStartItemCount()); + data.setLong("remainingItemCount", this.getRemainingItemCount()); + + list = new NBTTagList(); + for (final Entry> e : this.providers.entrySet()) { + NBTTagCompound tmp = new NBTTagCompound(); + tmp.setTag("item", this.writeItem(e.getKey())); + DimensionalCoord.writeListToNBT(tmp, e.getValue()); + list.appendTag(tmp); + } + data.setTag("providers", list); + } + + private NBTTagCompound writeItem(final IAEItemStack finalOutput2) { + final NBTTagCompound out = new NBTTagCompound(); + + if (finalOutput2 != null) { + finalOutput2.writeToNBT(out); + } + + return out; + } + + private NBTTagList writeList(final IItemList myList) { + final NBTTagList out = new NBTTagList(); + + for (final IAEItemStack ais : myList) { + out.appendTag(this.writeItem(ais)); + } + + return out; + } + + void done() { + final TileCraftingTile core = this.getCore(); + + core.setCoreBlock(true); + + if (core.getPreviousState() != null) { + this.readFromNBT(core.getPreviousState()); + core.setPreviousState(null); + } + + this.updateCPU(); + this.updateName(); + } + + public void readFromNBT(final NBTTagCompound data) { + this.finalOutput = AEItemStack.loadItemStackFromNBT((NBTTagCompound) data.getTag("finalOutput")); + for (final IAEItemStack ais : this.readList((NBTTagList) data.getTag("inventory"))) { + this.inventory.injectItems(ais, Actionable.MODULATE, this.machineSrc); + } + + this.waiting = data.getBoolean("waiting"); + this.isComplete = data.getBoolean("isComplete"); + + if (data.hasKey("link")) { + final NBTTagCompound link = data.getCompoundTag("link"); + this.myLastLink = new CraftingLink(link, this); + this.submitLink(this.myLastLink); + } + + NBTTagList list = data.getTagList("tasks", 10); + for (int x = 0; x < list.tagCount(); x++) { + final NBTTagCompound item = list.getCompoundTagAt(x); + final IAEItemStack pattern = AEItemStack.loadItemStackFromNBT(item); + if (pattern != null && pattern.getItem() instanceof ICraftingPatternItem ) { + ICraftingPatternItem cpi= (ICraftingPatternItem) pattern.getItem(); + final ICraftingPatternDetails details = cpi.getPatternForItem(pattern.getItemStack(), this.getWorld()); + if (details != null) { + final TaskProgress tp = new TaskProgress(); + tp.value = item.getLong("craftingProgress"); + this.tasks.put(details, tp); + } + } + } + + this.waitingFor = this.readList((NBTTagList) data.getTag("waitingFor")); + for (final IAEItemStack is : this.waitingFor) { + this.postCraftingStatusChange(is.copy()); + } + + this.lastTime = System.nanoTime(); + this.elapsedTime = data.getLong("elapsedTime"); + this.startItemCount = data.getLong("startItemCount"); + this.remainingItemCount = data.getLong("remainingItemCount"); + + list = data.getTagList("providers", 10); + for (int x = 0; x < list.tagCount(); x++) { + final NBTTagCompound pro = list.getCompoundTagAt(x); + this.providers.put( + AEItemStack.loadItemStackFromNBT(pro.getCompoundTag("item")), + DimensionalCoord.readAsListFromNBT(pro)); + } + } + + public void updateName() { + this.myName = ""; + for (final TileCraftingTile te : this.tiles) { + + if (te.hasCustomName()) { + if (this.myName.length() > 0) { + this.myName += ' ' + te.getCustomName(); + } else { + this.myName = te.getCustomName(); + } + } + } + } + + private IItemList readList(final NBTTagList tag) { + final IItemList out = AEApi.instance().storage().createItemList(); + + if (tag == null) { + return out; + } + + for (int x = 0; x < tag.tagCount(); x++) { + final IAEItemStack ais = AEItemStack.loadItemStackFromNBT(tag.getCompoundTagAt(x)); + if (ais != null) { + out.add(ais); + } + } + + return out; + } + + private World getWorld() { + return this.getCore().getWorldObj(); + } + + public boolean isMaking(final IAEItemStack what) { + final IAEItemStack wat = this.waitingFor.findPrecise(what); + return wat != null && wat.getStackSize() > 0; + } + + public void breakCluster() { + final TileCraftingTile t = this.getCore(); + + if (t != null) { + t.breakCluster(); + } + } + + private void prepareElapsedTime() { + this.lastTime = System.nanoTime(); + this.elapsedTime = 0; + + final IItemList list = AEApi.instance().storage().createItemList(); + + this.getListOfItem(list, CraftingItemList.ACTIVE); + this.getListOfItem(list, CraftingItemList.PENDING); + + long itemCount = 0; + for (final IAEItemStack ge : list) { + itemCount += ge.getStackSize(); + } + + this.startItemCount = itemCount; + this.remainingItemCount = itemCount; + } + + private void updateElapsedTime(final IAEItemStack is) { + final long nextStartTime = System.nanoTime(); + this.elapsedTime = this.getElapsedTime() + nextStartTime - this.lastTime; + this.lastTime = nextStartTime; + this.remainingItemCount = this.getRemainingItemCount() - is.getStackSize(); + } + + public long getElapsedTime() { + return this.elapsedTime; + } + + @Override + public long getRemainingItemCount() { + return this.remainingItemCount; + } + + @Override + public long getStartItemCount() { + return this.startItemCount; + } + + @SuppressWarnings("unchecked") + public List getProviders(IAEItemStack is) { + return this.providers.getOrDefault(is, Collections.EMPTY_LIST); + } + + private TileEntity getTile(ICraftingMedium craftingProvider) { + if (craftingProvider instanceof DualityInterface) { + return ((DualityInterface) craftingProvider).getHost().getTile(); + } else if (craftingProvider instanceof AEBaseTile) { + return ((AEBaseTile) craftingProvider).getTile(); + } else if (craftingProvider instanceof IInterfaceViewable ) { + IInterfaceViewable interfaceViewable =(IInterfaceViewable) craftingProvider; + return interfaceViewable.getTileEntity(); + } + try { + Method method = craftingProvider.getClass().getMethod("getTile"); + return (TileEntity) method.invoke(craftingProvider); + } catch (Exception ignored) { + return null; + } + + } + + public int getRemainingOperations() { + if (this.isComplete) { + return 0; + } else { + return this.remainingOperations; + } + } + + private static class TaskProgress { + + private long value; + } +} diff --git a/src/main/java/reobf/proghatches/block/BlockIOHub.java b/src/main/java/reobf/proghatches/block/BlockIOHub.java index b6d3837..943b174 100644 --- a/src/main/java/reobf/proghatches/block/BlockIOHub.java +++ b/src/main/java/reobf/proghatches/block/BlockIOHub.java @@ -22,6 +22,7 @@ import net.minecraftforge.event.ForgeEventFactory; public class BlockIOHub extends BlockContainer { + private IIcon inv_me_slave; public BlockIOHub() { super(new GT_Material_Machines()); @@ -49,6 +50,7 @@ public void registerBlockIcons(IIconRegister reg) { provider_active_overlay = reg.registerIcon("proghatches:provider_active"); provider_in_overlay = reg.registerIcon("proghatches:provider_in"); provider_in_active_overlay = reg.registerIcon("proghatches:provider_in_active"); + inv_me_slave = reg.registerIcon("proghatches:inv_me_slave"); super.registerBlockIcons(reg); } @@ -100,7 +102,7 @@ public boolean onBlockActivated(World worldIn, int x, int y, int z, EntityPlayer static public int magicNO_provider_active_overlay = 0x7d; static public int magicNO_provider_in_overlay = 0x7c; static public int magicNO_provider_in_active_overlay = 0x7b; - + static public int magicNO_inv_me_slave = 0x7a; @SideOnly(value = Side.CLIENT) @Override public IIcon getIcon(int side, int meta) { @@ -110,6 +112,7 @@ public IIcon getIcon(int side, int meta) { if(meta==0x7d)return provider_active_overlay; if(meta==0x7c)return provider_in_overlay; if(meta==0x7b)return provider_in_active_overlay; + if(meta==0x7a)return inv_me_slave; //spotless:on return super.getIcon(side, meta); } diff --git a/src/main/java/reobf/proghatches/gt/metatileentity/BufferedDualInputHatch.java b/src/main/java/reobf/proghatches/gt/metatileentity/BufferedDualInputHatch.java index 1ec6703..f978bee 100644 --- a/src/main/java/reobf/proghatches/gt/metatileentity/BufferedDualInputHatch.java +++ b/src/main/java/reobf/proghatches/gt/metatileentity/BufferedDualInputHatch.java @@ -1148,6 +1148,7 @@ public void detectAndSendChanges(boolean init) { // flush changes to client // sometimes vanilla detection will fail so sync it manually // System.out.println(last-getBaseMetaTileEntity().getTimer()); + if(getBaseMetaTileEntity()!=null) if (last >= getBaseMetaTileEntity().getTimer()) getWindow().getContext().getContainer().inventorySlots.forEach(s -> ((Slot) s).onSlotChanged()); @@ -1670,4 +1671,5 @@ public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlaye return super.onRightclick(aBaseMetaTileEntity, aPlayer, side, aX, aY, aZ); } + } diff --git a/src/main/java/reobf/proghatches/gt/metatileentity/DualInputHatch.java b/src/main/java/reobf/proghatches/gt/metatileentity/DualInputHatch.java index f90be38..5076c53 100644 --- a/src/main/java/reobf/proghatches/gt/metatileentity/DualInputHatch.java +++ b/src/main/java/reobf/proghatches/gt/metatileentity/DualInputHatch.java @@ -126,6 +126,7 @@ import reobf.proghatches.gt.metatileentity.util.IMultiCircuitSupport; import reobf.proghatches.gt.metatileentity.util.IProgrammingCoverBlacklisted; import reobf.proghatches.gt.metatileentity.util.IRecipeProcessingAwareDualHatch; +import reobf.proghatches.gt.metatileentity.util.ISkipStackSizeCheck; import reobf.proghatches.gt.metatileentity.util.InventoryItemHandler; import reobf.proghatches.gt.metatileentity.util.ListeningFluidTank; import reobf.proghatches.item.ItemProgrammingCircuit; @@ -136,7 +137,7 @@ public class DualInputHatch extends GT_MetaTileEntity_Hatch_InputBus implements IConfigurationCircuitSupport, IAddGregtechLogo, IAddUIWidgets, IDualInputHatch, - IProgrammingCoverBlacklisted, IRecipeProcessingAwareDualHatch/*,IMultiCircuitSupport*/ { + IProgrammingCoverBlacklisted, IRecipeProcessingAwareDualHatch,ISkipStackSizeCheck/*,IMultiCircuitSupport*/ { static java.text.DecimalFormat format = new java.text.DecimalFormat("#,###"); public boolean mMultiFluid; @@ -270,7 +271,7 @@ public DualInputHatch(String aName, int aTier, int aSlots, String[] aDescription public NBTTagCompound writeToNBT(ItemStack is, NBTTagCompound tag) { is.writeToNBT(tag); tag.setInteger("ICount", is.stackSize); - + return tag; } diff --git a/src/main/java/reobf/proghatches/gt/metatileentity/DualInputHatchInventoryMappingSlave.java b/src/main/java/reobf/proghatches/gt/metatileentity/DualInputHatchInventoryMappingSlave.java new file mode 100644 index 0000000..3787870 --- /dev/null +++ b/src/main/java/reobf/proghatches/gt/metatileentity/DualInputHatchInventoryMappingSlave.java @@ -0,0 +1,450 @@ +package reobf.proghatches.gt.metatileentity; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPE_IN; + +import java.util.List; + +import com.google.common.collect.ImmutableMap; +import com.gtnewhorizons.modularui.api.forge.ItemStackHandler; + +import appeng.api.networking.crafting.ICraftingMedium; +import appeng.helpers.ICustomNameObject; +import gregtech.api.GregTech_API; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Textures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_InputBus; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_TieredMachineBlock; +import gregtech.api.render.TextureFactory; +import gregtech.common.tileentities.machines.IDualInputHatch; +import mcp.mobius.waila.api.IWailaConfigHandler; +import mcp.mobius.waila.api.IWailaDataAccessor; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTankInfo; +import reobf.proghatches.block.BlockIOHub; +import reobf.proghatches.gt.metatileentity.DualInputHatch.Net; +import reobf.proghatches.gt.metatileentity.util.ISkipStackSizeCheck; +import reobf.proghatches.main.Config; +import reobf.proghatches.main.MyMod; +import reobf.proghatches.main.registration.Registration; + +public class DualInputHatchInventoryMappingSlave +extends GT_MetaTileEntity_TieredMachineBlock implements ISkipStackSizeCheck{ + private T master; // use getMaster() to access + private int masterX, masterY, masterZ; + private boolean masterSet = false; // indicate if values of masterX, + // masterY, masterZ are valid + public DualInputHatchInventoryMappingSlave(int aID, String aName, String aNameRegional, int aTier + ) { + super(aID, aName, aNameRegional, aTier, 0, + + + + Config.get("DIHIMS", ImmutableMap.of())); + Registration.items.add(new ItemStack(GregTech_API.sBlockMachines, 1, aID)); + } + public DualInputHatchInventoryMappingSlave(String aName, int aTier, int aInvSlotCount, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aInvSlotCount, aDescription, aTextures); + + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + + return new DualInputHatchInventoryMappingSlave<>(mName, mTier, 0, mDescriptionArray, mTextures); + } + @Override + public void saveNBTData(NBTTagCompound aNBT) { + aNBT.setBoolean("allowAllSides",allowAllSides); + if (masterSet) { + NBTTagCompound masterNBT = new NBTTagCompound(); + masterNBT.setInteger("x", masterX); + masterNBT.setInteger("y", masterY); + masterNBT.setInteger("z", masterZ); + aNBT.setTag("master", masterNBT); + } + + } + @Override + public void loadNBTData(NBTTagCompound aNBT) { + + + allowAllSides=aNBT.getBoolean("allowAllSides"); + if (aNBT.hasKey("master")) { + NBTTagCompound masterNBT = aNBT.getCompoundTag("master"); + masterX = masterNBT.getInteger("x"); + masterY = masterNBT.getInteger("y"); + masterZ = masterNBT.getInteger("z"); + masterSet = true; + } + } + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + if(!passSideCheck(side)){return false;} + T master; + if((master=getMaster())!=null){ + return master.allowPullStack(aBaseMetaTileEntity, aIndex, getMasterFront(), aStack); + }; + return false; + } + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + if(!passSideCheck(side)){return false;} + T master; + if((master=getMaster())!=null){ + return master.allowPutStack(aBaseMetaTileEntity, aIndex, getMasterFront(), aStack); + }; + return false; + } + @Override + public boolean canDrain(ForgeDirection side, Fluid aFluid) { + T master; + if((master=getMaster())!=null){ + return master.canDrain(getMasterFront(), aFluid); + }; + return false; + } + @Override + public boolean canFill(ForgeDirection side, Fluid aFluid) { + if(!passSideCheck(side)){return false;} + T master; + if((master=getMaster())!=null){ + return master.canFill(getMasterFront(), aFluid); + }; + return false; + } + @Override + public boolean canExtractItem(int aIndex, ItemStack aStack, int ordinalSide) { + if(!passSideCheck(ordinalSide)){return false;} + T master; + if((master=getMaster())!=null){ + return master.canExtractItem(aIndex, aStack, getMasterFront().ordinal()); + }; + return false; + } + @Override + public boolean canInsertItem(int aIndex, ItemStack aStack, int ordinalSide) { + if(!passSideCheck(ordinalSide)){return false;} + if((master=getMaster())!=null){ + return master.canInsertItem(aIndex, aStack, getMasterFront().ordinal()); + }; + return false; + } + @Override + public ItemStackHandler getInventoryHandler() { + if((master=getMaster())!=null){ + return master.getInventoryHandler(); + }; + return super.getInventoryHandler(); + } + + @Override + public int fill(FluidStack resource, boolean doFill) { + if((master=getMaster())!=null){ + return master.fill(resource, doFill); + }; + return 0; + } + @Override + public int fill(ForgeDirection side, FluidStack aFluid, boolean doFill) { + if(!passSideCheck(side)){return 0;} + if((master=getMaster())!=null){ + return master.fill( getMasterFront(), aFluid, doFill); + }; + return 0; + } + @Override + public FluidStack drain(ForgeDirection side, FluidStack aFluid, boolean doDrain) { + if(!passSideCheck(side)){return null;} + if((master=getMaster())!=null){ + return master.drain( getMasterFront(), aFluid, doDrain); + }; + return null; + } + @Override + public FluidStack drain(ForgeDirection side, int maxDrain, boolean doDrain) { + if((master=getMaster())!=null){ + return master.drain( getMasterFront(), maxDrain, doDrain); + }; + return null; + } + @Override + public FluidStack drain(int maxDrain, boolean doDrain) { + if((master=getMaster())!=null){ + return master.drain(maxDrain, doDrain); + }; + return null; + } + + @Override + public ItemStack decrStackSize(int aIndex, int aAmount) { + if((master=getMaster())!=null){ + return master.decrStackSize(aIndex, aAmount); + }; + return null; + } + @Override + public boolean isItemValidForSlot(int aIndex, ItemStack aStack) { + if((master=getMaster())!=null){ + return master.isItemValidForSlot(aIndex, aStack); + }; + return false; + } + @Override + public void setInventorySlotContents(int aIndex, ItemStack aStack) { + if((master=getMaster())!=null){ + master.setInventorySlotContents(aIndex, aStack); + }; + + } + @Override + public ItemStack getStackInSlot(int aIndex) { + if((master=getMaster())!=null){ + return master.getStackInSlot(aIndex); + }; + return null; + } + @Override + public int getInventoryStackLimit() { + if((master=getMaster())!=null){ + return master.getInventoryStackLimit(); + }; + return 0; + } + @Override + public int getSizeInventory() { + if((master=getMaster())!=null){ + return master.getSizeInventory(); + }; + return 0; + } + @Override + public FluidStack getFluid() { + if((master=getMaster())!=null){ + return master.getFluid(); + }; + return null; + } + @Override + public int getFluidAmount() { + if((master=getMaster())!=null){ + return master.getFluidAmount(); + }; + return 0; + } + + + @Override + public boolean shouldDropItemAt(int index) { + return false; + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + + return true; + } + @Override + public ITexture[] getTexture(IGregTechTileEntity baseMetaTileEntity, ForgeDirection side, ForgeDirection facing, + int colorIndex, boolean active, boolean redstoneLevel) { + + + if (side != facing) + + return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][colorIndex + 1] }; + else return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][colorIndex + 1], TextureFactory.of(MyMod.iohub, BlockIOHub.magicNO_inv_me_slave), TextureFactory.of(OVERLAY_PIPE_IN) }; + + } + @Override + public ITexture[][][] getTextureSet(ITexture[] aTextures) { + + return new ITexture[0][0][0]; + } + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTimer) { + super.onPostTick(aBaseMetaTileEntity, aTimer); + if (aTimer % 100 == 0 && masterSet && getMaster() == null) { + trySetMasterFromCoord(masterX, masterY, masterZ); + } + } + @SuppressWarnings("unchecked") + public IDualInputHatch trySetMasterFromCoord(int x, int y, int z) { + TileEntity tileEntity = getBaseMetaTileEntity().getWorld().getTileEntity(x, y, z); + if (tileEntity == null) + return null; + if (!(tileEntity instanceof IGregTechTileEntity)) + return null; + IMetaTileEntity metaTileEntity = ((IGregTechTileEntity) tileEntity).getMetaTileEntity(); + if (!(metaTileEntity instanceof IDualInputHatch)) + return null; + + if (!(metaTileEntity instanceof reobf.proghatches.gt.metatileentity.DualInputHatch)) + return null; + + masterX = x; + masterY = y; + masterZ = z; + masterSet = true; + master = (T) metaTileEntity; + return master; + } + + private boolean tryLinkDataStick(EntityPlayer aPlayer) { + ItemStack dataStick = aPlayer.inventory.getCurrentItem(); + + if (!ItemList.Tool_DataStick.isStackEqual(dataStick, false, true)) { + return false; + } + if (dataStick.hasTagCompound()&&dataStick.stackTagCompound.getString("type") + .equals("CraftingInputBuffer")) { + aPlayer.addChatMessage(new ChatComponentTranslation("programmable_hatches.gt.slave.compat")); + return false; + } + if (!dataStick.hasTagCompound() + || !dataStick.stackTagCompound.getString("type").equals("ProgHatchesDualInput")) { + return false; + } + + NBTTagCompound nbt = dataStick.stackTagCompound; + int x = nbt.getInteger("x"); + int y = nbt.getInteger("y"); + int z = nbt.getInteger("z"); + if (trySetMasterFromCoord(x, y, z) != null) { + aPlayer.addChatMessage(new ChatComponentText("Link successful")); + return true; + } + aPlayer.addChatMessage(new ChatComponentText("Link failed")); + return true; + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + if (!(aPlayer instanceof EntityPlayerMP)) { + return false; + } + if (tryLinkDataStick(aPlayer)) { + return true; + } + IDualInputHatch master = getMaster(); + if (master != null) { + return ((MetaTileEntity) master).onRightclick(((IMetaTileEntity) master).getBaseMetaTileEntity(), aPlayer); + } + return false; + } + public T getMaster() { + if (master == null) + return null; + if (((IMetaTileEntity) master).getBaseMetaTileEntity() == null) { // master + // disappeared + master = null; + } + return master; + } + + public ForgeDirection getMasterFront() { + if (master == null) + return this.getBaseMetaTileEntity().getFrontFacing();//throw new RuntimeExcpetion()? + //do not check master, becasue it's always called after getMaster() + return master.getBaseMetaTileEntity().getFrontFacing(); + }@Override + public void getWailaBody(ItemStack itemStack, List currenttip, IWailaDataAccessor accessor, + IWailaConfigHandler config) { + NBTTagCompound tag = accessor.getNBTData(); + currenttip.add((tag.getBoolean("linked") ? "Linked" : "Not linked")); + + if (tag.hasKey("masterX")) { + currenttip.add("Bound to " + tag.getInteger("masterX") + ", " + tag.getInteger("masterY") + ", " + + tag.getInteger("masterZ")); + } + + + if (tag.hasKey("masterName")) { + currenttip.add(EnumChatFormatting.GOLD + tag.getString("masterName") + + EnumChatFormatting.RESET); } + + + super.getWailaBody(itemStack, currenttip, accessor, config); + }@Override + public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompound tag, World world, int x, int y, + int z) { + + tag.setBoolean("linked", getMaster() != null); + if (masterSet) { + tag.setInteger("masterX", masterX); + tag.setInteger("masterY", masterY); + tag.setInteger("masterZ", masterZ); + } + if (getMaster() != null) tag.setString("masterName", getNameOf(getMaster())); + /* + * if (getMaster() != null) tag.setString("masterName", + * getMaster().getnam); + */ + + super.getWailaNBTData(player, tile, tag, world, x, y, z); + } public String getNameOf(T tg) { + + if(tg instanceof ICustomNameObject){ + ICustomNameObject iv=(ICustomNameObject) tg; + if(iv.hasCustomName()) + return iv.getCustomName(); + + } + + StringBuilder name = new StringBuilder(); + if (tg instanceof ICraftingMedium &&((ICraftingMedium)tg).getCrafterIcon() != null) { + name.append(((ICraftingMedium)tg).getCrafterIcon().getDisplayName()); + } else { + name.append(tg.getLocalName()); + } + + + return name.toString(); + } + @Override + public boolean isFacingValid(ForgeDirection facing) { + + return true; + } + boolean allowAllSides; + public boolean passSideCheck(ForgeDirection dir){ + if(allowAllSides)return true; + return this.getBaseMetaTileEntity().getFrontFacing()==dir; + } + public boolean passSideCheck(int dir){ + return passSideCheck(ForgeDirection.values()[dir]); + } + @Override + public boolean onWireCutterRightClick(ForgeDirection side, ForgeDirection wrenchingSide, EntityPlayer aPlayer, + float aX, float aY, float aZ) { + allowAllSides = !allowAllSides; + + aPlayer.addChatComponentMessage( + new ChatComponentTranslation("GT5U.hatch.additionalConnection." + allowAllSides)); + return true; + } + @Override + public FluidTankInfo[] getTankInfo(ForgeDirection side) { + if(!passSideCheck(side)){return null;} + if((master=getMaster())!=null){ + return master.getTankInfo(side); + }; + return super.getTankInfo(side); + } +} diff --git a/src/main/java/reobf/proghatches/gt/metatileentity/PatternDualInputHatch.java b/src/main/java/reobf/proghatches/gt/metatileentity/PatternDualInputHatch.java index 571bc1e..4809844 100644 --- a/src/main/java/reobf/proghatches/gt/metatileentity/PatternDualInputHatch.java +++ b/src/main/java/reobf/proghatches/gt/metatileentity/PatternDualInputHatch.java @@ -559,12 +559,12 @@ public int getInventoryStackLimit() { return Integer.MAX_VALUE; } - + public boolean skipActiveCheck; @Override public boolean pushPattern(ICraftingPatternDetails patternDetails, InventoryCrafting table) { - if (!isActive()) + if (!isActive()&&!skipActiveCheck) return false; if (!isEmpty()) return false; @@ -881,8 +881,7 @@ public boolean allowsPatternOptimization() { } - - + diff --git a/src/main/java/reobf/proghatches/gt/metatileentity/PatternDualInputHatchInventoryMappingSlave.java b/src/main/java/reobf/proghatches/gt/metatileentity/PatternDualInputHatchInventoryMappingSlave.java new file mode 100644 index 0000000..154582b --- /dev/null +++ b/src/main/java/reobf/proghatches/gt/metatileentity/PatternDualInputHatchInventoryMappingSlave.java @@ -0,0 +1,956 @@ +package reobf.proghatches.gt.metatileentity; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPE_IN; + +import java.io.IOException; +import java.util.EnumSet; +import java.util.List; +import java.util.Optional; + +import com.glodblock.github.common.item.ItemFluidPacket; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.gtnewhorizons.modularui.api.forge.ItemStackHandler; +import com.gtnewhorizons.modularui.api.math.Pos2d; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.api.widget.Widget; +import com.gtnewhorizons.modularui.api.screen.ModularWindow.Builder; +import com.gtnewhorizons.modularui.common.internal.wrapper.BaseSlot; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; +import com.gtnewhorizons.modularui.common.widget.SlotWidget; +import com.gtnewhorizons.modularui.common.widget.SyncedWidget; +import com.gtnewhorizons.modularui.common.widget.TextWidget; + +import appeng.api.implementations.ICraftingPatternItem; +import appeng.api.implementations.IPowerChannelState; +import appeng.api.networking.GridFlags; +import appeng.api.networking.IGridNode; +import appeng.api.networking.crafting.ICraftingMedium; +import appeng.api.networking.crafting.ICraftingPatternDetails; +import appeng.api.networking.crafting.ICraftingProvider; +import appeng.api.networking.crafting.ICraftingProviderHelper; +import appeng.api.networking.events.MENetworkCraftingPatternChange; +import appeng.api.networking.security.IActionHost; +import appeng.api.util.AECableType; +import appeng.api.util.DimensionalCoord; +import appeng.api.util.IInterfaceViewable; +import appeng.core.AppEng; +import appeng.core.sync.GuiBridge; +import appeng.helpers.ICustomNameObject; +import appeng.items.misc.ItemEncodedPattern; +import appeng.items.tools.quartz.ToolQuartzCuttingKnife; +import appeng.me.GridAccessException; +import appeng.me.helpers.AENetworkProxy; +import appeng.me.helpers.IGridProxyable; +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Textures; +import gregtech.api.gui.modularui.GT_UIInfos; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.IConfigurationCircuitSupport; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.modularui.IAddUIWidgets; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.interfaces.tileentity.IHasWorldObjectAndCoords; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_InputBus; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_TieredMachineBlock; +import gregtech.api.render.TextureFactory; +import gregtech.common.tileentities.machines.IDualInputHatch; +import mcp.mobius.waila.api.IWailaConfigHandler; +import mcp.mobius.waila.api.IWailaDataAccessor; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; +import net.minecraft.network.play.server.S35PacketUpdateTileEntity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.event.ForgeEventFactory; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTank; +import reobf.proghatches.block.BlockIOHub; +import reobf.proghatches.gt.metatileentity.DualInputHatch.Net; +import reobf.proghatches.gt.metatileentity.util.ISkipStackSizeCheck; +import reobf.proghatches.gt.metatileentity.util.MappingItemHandler; +import reobf.proghatches.lang.LangManager; +import reobf.proghatches.main.Config; +import reobf.proghatches.main.MyMod; +import reobf.proghatches.main.registration.Registration; +import reobf.proghatches.net.MasterSetMessage; +import reobf.proghatches.net.UpgradesMessage; + +public class PatternDualInputHatchInventoryMappingSlave + extends GT_MetaTileEntity_TieredMachineBlock implements IAddUIWidgets, ICraftingMedium, ICustomNameObject, + IGridProxyable, IInterfaceViewable, IPowerChannelState, IActionHost, ICraftingProvider { + private T master; // use getMaster() to access + public int masterX, masterY, masterZ; + public boolean masterSet = false; // indicate if values of masterX, + // masterY, masterZ are valid + + public PatternDualInputHatchInventoryMappingSlave(int aID, String aName, String aNameRegional, int aTier) { + super(aID, aName, aNameRegional, aTier, 0, + + Config.get("DIHIMS", ImmutableMap.of())); + Registration.items.add(new ItemStack(GregTech_API.sBlockMachines, 1, aID)); + } + + public PatternDualInputHatchInventoryMappingSlave(String aName, int aTier, int aInvSlotCount, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aInvSlotCount, aDescription, aTextures); + + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + + return new PatternDualInputHatchInventoryMappingSlave<>(mName, mTier, 0, mDescriptionArray, mTextures); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + aNBT.setBoolean("additionalConnection", additionalConnection); + NBTTagCompound tag = new NBTTagCompound();// aNBT.getCompoundTag("patternSlots"); + + for (int i = 0; i < pattern.length; i++) { + final int ii = i; + Optional.ofNullable(pattern[i]).map(s -> s.writeToNBT(new NBTTagCompound())) + .ifPresent(s -> tag.setTag("i" + ii, s)); + } + aNBT.setTag("patternSlots", tag); + Optional.ofNullable(customName).ifPresent(s -> aNBT.setString("customName", s)); + getProxy().writeToNBT(aNBT); + + if (masterSet) { + NBTTagCompound masterNBT = new NBTTagCompound(); + masterNBT.setInteger("x", masterX); + masterNBT.setInteger("y", masterY); + masterNBT.setInteger("z", masterZ); + aNBT.setTag("master", masterNBT); + } + + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + additionalConnection = aNBT.getBoolean("additionalConnection"); + NBTTagCompound tag = aNBT.getCompoundTag("patternSlots"); + if (tag != null) + for (int i = 0; i < pattern.length; i++) { + pattern[i] = Optional.ofNullable(tag.getCompoundTag("i" + i)).map(ItemStack::loadItemStackFromNBT) + .orElse(null); + } + customName = aNBT.getString("customName"); + + getProxy().readFromNBT(aNBT); + + updateValidGridProxySides(); + + if (aNBT.hasKey("master")) { + NBTTagCompound masterNBT = aNBT.getCompoundTag("master"); + masterX = masterNBT.getInteger("x"); + masterY = masterNBT.getInteger("y"); + masterZ = masterNBT.getInteger("z"); + masterSet = true; + } + } + + @Override + public boolean shouldDropItemAt(int index) { + return false; + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + + return true; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity baseMetaTileEntity, ForgeDirection side, ForgeDirection facing, + int colorIndex, boolean active, boolean redstoneLevel) { + + if (side != facing) + + return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][colorIndex + 1] }; + else + return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][colorIndex + 1], + TextureFactory.of(MyMod.iohub, BlockIOHub.magicNO_inv_me_slave) }; + + } + + @Override + public ITexture[][][] getTextureSet(ITexture[] aTextures) { + + return new ITexture[0][0][0]; + } + long lastSync; + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTimer) { + super.onPostTick(aBaseMetaTileEntity, aTimer); + if (aTimer % 100 == 0 && masterSet && getMaster() == null) { + trySetMasterFromCoord(masterX, masterY, masterZ); + } + if (getBaseMetaTileEntity().isServerSide()) { + if (needPatternSync && aTimer > lastSync + 100) { + needPatternSync = !postMEPatternChange(); + lastSync = aTimer; + } + if (aTimer % 20 == 0) { + getBaseMetaTileEntity().setActive(isActive()); + } + } + + } + + @SuppressWarnings("unchecked") + public IDualInputHatch trySetMasterFromCoord(int x, int y, int z) { + TileEntity tileEntity = getBaseMetaTileEntity().getWorld().getTileEntity(x, y, z); + if (tileEntity == null) + return null; + if (!(tileEntity instanceof IGregTechTileEntity)) + return null; + IMetaTileEntity metaTileEntity = ((IGregTechTileEntity) tileEntity).getMetaTileEntity(); + if (!(metaTileEntity instanceof IDualInputHatch)) + return null; + + if (!(metaTileEntity instanceof reobf.proghatches.gt.metatileentity.DualInputHatch)) + return null; + + masterX = x; + masterY = y; + masterZ = z; + masterSet = true; + master = (T) metaTileEntity; + return master; + } + + private boolean tryLinkDataStick(EntityPlayer aPlayer) { + ItemStack dataStick = aPlayer.inventory.getCurrentItem(); + + if (!ItemList.Tool_DataStick.isStackEqual(dataStick, false, true)) { + return false; + } + if (dataStick.hasTagCompound() && dataStick.stackTagCompound.getString("type").equals("CraftingInputBuffer")) { + aPlayer.addChatMessage(new ChatComponentTranslation("programmable_hatches.gt.slave.compat")); + return false; + } + if (!dataStick.hasTagCompound() + || !dataStick.stackTagCompound.getString("type").equals("ProgHatchesDualInput")) { + return false; + } + + NBTTagCompound nbt = dataStick.stackTagCompound; + int x = nbt.getInteger("x"); + int y = nbt.getInteger("y"); + int z = nbt.getInteger("z"); + if (trySetMasterFromCoord(x, y, z) != null) { + aPlayer.addChatMessage(new ChatComponentText("Link successful")); + return true; + } + aPlayer.addChatMessage(new ChatComponentText("Link failed")); + return true; + } + + /* + * (non-Javadoc) + * + * @see + * gregtech.api.metatileentity.MetaTileEntity#onRightclick(gregtech.api. + * interfaces.tileentity.IGregTechTileEntity, + * net.minecraft.entity.player.EntityPlayer, + * net.minecraftforge.common.util.ForgeDirection, float, float, float) + */ + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer, ForgeDirection side, + float aX, float aY, float aZ) { + if (!(aPlayer instanceof EntityPlayerMP)) { + return false; + } + final ItemStack is = aPlayer.inventory.getCurrentItem(); + if (is != null && is.getItem() instanceof ToolQuartzCuttingKnife) { + if (ForgeEventFactory.onItemUseStart(aPlayer, is, 1) <= 0) + return false; + IGregTechTileEntity te = getBaseMetaTileEntity(); + aPlayer.openGui(AppEng.instance(), GuiBridge.GUI_RENAMER.ordinal() << 5 | (side.ordinal()), te.getWorld(), + te.getXCoord(), te.getYCoord(), te.getZCoord()); + return true; + } + if (tryLinkDataStick(aPlayer)) { + return true; + } + + if (getMaster() != null) { + if (!aBaseMetaTileEntity.isClientSide()) { + /* + * TileEntity m= (TileEntity) + * getMaster().getBaseMetaTileEntity(); NBTTagCompound + * nbttagcompound = new NBTTagCompound(); + * m.writeToNBT(nbttagcompound); S35PacketUpdateTileEntity pa= + * new S35PacketUpdateTileEntity(m.xCoord, m.yCoord, m.zCoord, + * m.getBlockMetadata() , nbttagcompound); + * + * ((EntityPlayerMP) + * aPlayer).playerNetServerHandler.sendPacket(pa); + */ + + MyMod.net.sendTo(new MasterSetMessage(aBaseMetaTileEntity.getXCoord(), aBaseMetaTileEntity.getYCoord(), + aBaseMetaTileEntity.getZCoord(), this), (EntityPlayerMP) aPlayer); + + } + GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); + return true; + } else { + + GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); + } + return false; + + } + + public T getMaster() { + if (master == null) + return null; + if (((IMetaTileEntity) master).getBaseMetaTileEntity() == null) { // master + // disappeared + master = null; + } + return master; + } + + public ForgeDirection getMasterFront() { + if (master == null) + return this.getBaseMetaTileEntity().getFrontFacing();// throw new + // RuntimeExcpetion()? + // do not check master, becasue it's always called after getMaster() + return master.getBaseMetaTileEntity().getFrontFacing(); + } + + @Override + public void getWailaBody(ItemStack itemStack, List currenttip, IWailaDataAccessor accessor, + IWailaConfigHandler config) { + NBTTagCompound tag = accessor.getNBTData(); + currenttip.add((tag.getBoolean("linked") ? "Linked" : "Not linked")); + + if (tag.hasKey("masterX")) { + currenttip.add("Bound to " + tag.getInteger("masterX") + ", " + tag.getInteger("masterY") + ", " + + tag.getInteger("masterZ")); + } + + if (tag.hasKey("masterName")) { + currenttip.add(EnumChatFormatting.GOLD + tag.getString("masterName") + EnumChatFormatting.RESET); + } + + super.getWailaBody(itemStack, currenttip, accessor, config); + } + + @Override + public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompound tag, World world, int x, int y, + int z) { + + tag.setBoolean("linked", getMaster() != null); + if (masterSet) { + tag.setInteger("masterX", masterX); + tag.setInteger("masterY", masterY); + tag.setInteger("masterZ", masterZ); + } + if (getMaster() != null) + tag.setString("masterName", getNameOf(getMaster())); + /* + * if (getMaster() != null) tag.setString("masterName", + * getMaster().getnam); + */ + + super.getWailaNBTData(player, tile, tag, world, x, y, z); + } + + public String getNameOf(T tg) { + + if (tg instanceof ICustomNameObject) { + ICustomNameObject iv = (ICustomNameObject) tg; + if (iv.hasCustomName()) + return iv.getCustomName(); + + } + + StringBuilder name = new StringBuilder(); + if (tg instanceof ICraftingMedium && ((ICraftingMedium) tg).getCrafterIcon() != null) { + name.append(((ICraftingMedium) tg).getCrafterIcon().getDisplayName()); + } else { + name.append(tg.getLocalName()); + } + + return name.toString(); + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + + return true; + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + + return false; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + + return false; + } + + @Override + public void addUIWidgets(Builder builder, UIBuildContext buildContext) { + if (masterSet) + trySetMasterFromCoord(masterX, masterY, masterZ); + if (getMaster() instanceof IAddUIWidgets) { + builder.widget(new SyncedWidget() { + @Override + public void detectAndSendChanges(boolean init) { + if (getMaster() == null || getMaster().getBaseMetaTileEntity() == null || !getMaster().isValid()) { + buildContext.getPlayer().closeScreen(); + } + } + + @Override + public void readOnClient(int id, PacketBuffer buf) throws IOException { + + } + + @Override + public void readOnServer(int id, PacketBuffer buf) throws IOException { + + } + + }); + ((IAddUIWidgets) getMaster()).addUIWidgets(builder, buildContext); + buildContext.addSyncedWindow(989898, this::createPatternWindow); + + builder.widget(new ButtonWidget().setOnClick((clickData, widget) -> { + if (widget.getContext().isClient() == false) + widget.getContext().openSyncedWindow(989898); + }).setPlayClickSound(true) + .setBackground(GT_UITextures.BUTTON_STANDARD, GT_UITextures.OVERLAY_BUTTON_PLUS_LARGE) + .addTooltips(ImmutableList + .of(LangManager.translateToLocalFormatted("programmable_hatches.gt.pattern.mapping"))) + .setSize(16, 16) + // .setPos(10 + 16 * 9, 3 + 16 * 2) + .setPos(new Pos2d(getGUIWidth() - 18 - 3, 5 + 16 + 2 + 16 + 2 + 18 + 24))); + + } else if (getMaster() == null) { + builder.widget(TextWidget.localised("hatch.dualinput.slave.inv.mapping.me.missing").setPos(5, 5) + + ); + buildContext.addSyncedWindow(989898, this::createPatternWindow); + + builder.widget(new ButtonWidget().setOnClick((clickData, widget) -> { + if (widget.getContext().isClient() == false) + widget.getContext().openSyncedWindow(989898); + }).setPlayClickSound(true) + .setBackground(GT_UITextures.BUTTON_STANDARD, GT_UITextures.OVERLAY_BUTTON_PLUS_LARGE) + .addTooltips(ImmutableList + .of(LangManager.translateToLocalFormatted("programmable_hatches.gt.pattern.mapping"))) + .setSize(16, 16) + // .setPos(10 + 16 * 9, 3 + 16 * 2) + .setPos(new Pos2d(getGUIWidth() - 18 - 3, 5 + 16 + 2 + 16 + 2 + 18 + 24))); + } + + } + + @Override + public boolean useModularUI() { + + return true; + } + + private AENetworkProxy gridProxy; + + @Override + public AENetworkProxy getProxy() { + if (gridProxy == null) { + gridProxy = new AENetworkProxy(this, "proxy", + new ItemStack(GregTech_API.sBlockMachines, 1, this.getBaseMetaTileEntity().getMetaTileID()), true); + gridProxy.setFlags(GridFlags.REQUIRE_CHANNEL); + updateValidGridProxySides(); + if (getBaseMetaTileEntity().getWorld() != null) + gridProxy.setOwner(getBaseMetaTileEntity().getWorld() + .getPlayerEntityByName(getBaseMetaTileEntity().getOwnerName())); + } + + return this.gridProxy; + } + + @Override + public IGridNode getGridNode(ForgeDirection dir) { + return getProxy().getNode(); + } + + @Override + public void securityBreak() { + + } + + @Override + public DimensionalCoord getLocation() { + + return new DimensionalCoord(getTileEntity()); + } + + boolean additionalConnection; + + private void updateValidGridProxySides() { + if (additionalConnection) { + getProxy().setValidSides(EnumSet.complementOf(EnumSet.of(ForgeDirection.UNKNOWN))); + } else { + getProxy().setValidSides(EnumSet.of(getBaseMetaTileEntity().getFrontFacing())); + } + // getProxy().setValidSides(EnumSet.of(getBaseMetaTileEntity().getFrontFacing())); + + } + + @Override + public IGridNode getActionableNode() { + + return this.getGridNode(ForgeDirection.UP); + } + + @Override + public boolean isPowered() { + return getProxy() != null && getProxy().isPowered(); + } + + @Override + public boolean isActive() { + return getProxy() != null && getProxy().isActive(); + } + + @Override + public int rows() { + return 4; + } + + @Override + public int rowSize() { + return 9; + } + + @Override + public IInventory getPatterns() { + + return patternMapper; + } + + @Override + public String getName() { + if (hasCustomName()) { + return getCustomName(); + } + StringBuilder name = new StringBuilder(); + if (getCrafterIcon() != null) { + name.append(getCrafterIcon().getDisplayName()); + } else { + name.append(getInventoryName()); + } + + /* + * if (mInventory[SLOT_CIRCUIT] != null) { name.append(" - "); + * name.append(mInventory[SLOT_CIRCUIT].getItemDamage()); } if + * (mInventory[SLOT_MANUAL_START] != null) { name.append(" - "); + * name.append(mInventory[SLOT_MANUAL_START].getDisplayName()); } + */// TODO + return name.toString(); + } + + @Override + public TileEntity getTileEntity() { + return (TileEntity) getBaseMetaTileEntity(); + } + + @Override + public boolean shouldDisplay() { + + return true; + } + + ItemStack[] pattern = new ItemStack[36]; + IInventory patternMapper = new IInventory() { + + @Override + public int getSizeInventory() { + + return pattern.length; + } + + @Override + public ItemStack getStackInSlot(int slotIn) { + + return pattern[slotIn]; + } + + @Override + public ItemStack decrStackSize(int index, int count) { + + try { + if (pattern[index] != null) { + ItemStack itemstack; + + if (pattern[index].stackSize <= count) { + itemstack = pattern[index]; + pattern[index] = null; + this.markDirty(); + return itemstack; + } else { + itemstack = pattern[index].splitStack(count); + + if (pattern[index].stackSize == 0) { + pattern[index] = null; + } + + this.markDirty(); + return itemstack; + } + } else { + return null; + } + } finally { + + onPatternChange(); + } + } + + @Override + public ItemStack getStackInSlotOnClosing(int index) { + + return null; + } + + @Override + public void setInventorySlotContents(int index, ItemStack stack) { + pattern[index] = stack; + onPatternChange(); + } + + @Override + public String getInventoryName() { + + return ""; + } + + @Override + public boolean hasCustomInventoryName() { + + return false; + } + + // @Override + // public int stack + + @Override + public void markDirty() { + + } + + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + + return true; + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + @Override + public boolean isItemValidForSlot(int index, ItemStack stack) { + + return true; + } + + @Override + public int getInventoryStackLimit() { + + return 1; + } + }; + boolean needPatternSync; + private String customName; + + private void onPatternChange() { + if (!getBaseMetaTileEntity().isServerSide()) + return; + + needPatternSync = true; + } + + @Override + public void gridChanged() { + needPatternSync = true; + } + + @Override + public String getCustomName() { + + return customName; + } + + @Override + public void setCustomName(String name) { + customName = name; + + } + + @Override + public boolean hasCustomName() { + + return customName != null && (!customName.equals("")); + } + + public boolean isInputEmpty(T master) { + + for (FluidTank f : master.mStoredFluid) { + if (f.getFluidAmount() > 0) { + return false; + } + } + for (ItemStack i : master.mInventory) { + + if (i != null && i.stackSize > 0) { + return false; + } + } + return true; + } + + public void clearInv(T master) { + + for (FluidTank f : master.mStoredFluid) { + f.setFluid(null); + } + for (int i = 0; i < master.mInventory.length; i++) { + + if (master.isValidSlot(i)) { + mInventory[i] = null; + } + } + + } + + @Override + public boolean pushPattern(ICraftingPatternDetails patternDetails, InventoryCrafting table) { + T master = getMaster(); + if (getMaster() instanceof PatternDualInputHatch) { + PatternDualInputHatch dih = ((PatternDualInputHatch) getMaster()); + try{ + dih.skipActiveCheck=true; + return dih.pushPattern(patternDetails, table); + }finally{dih.skipActiveCheck=false;} + } + if (master != null) { + if (!isInputEmpty(master)) { + return false; + } + + int i = 0; + int f = 0; + int ilimit = master.getInventoryStackLimit(); + int flimit = master.getInventoryFluidLimit(); + boolean isplit = master.disableLimited; + boolean fsplit = !master.fluidLimit; + for (int index = 0; index < table.getSizeInventory(); index++) { + ItemStack is = (table.getStackInSlot(index)); + if (is == null) + continue; + is = is.copy(); + if (is.getItem() instanceof ItemFluidPacket) { + FluidStack fs = ItemFluidPacket.getFluidStack(is); + if (fs == null) { + continue; + } + while (fs.amount > 0) { + if (f >= master.mStoredFluid.length) { + clearInv(master); + return false; + } + int tosplit = Math.min(fs.amount, flimit); + fs.amount -= tosplit; + if ((!fsplit) && fs.amount > 0) { + clearInv(master); + return false; + } + FluidStack splitted = new FluidStack(fs.getFluid(), tosplit); + master.mStoredFluid[index].setFluid(splitted); + f++; + } + + } else { + while (is.stackSize > 0) { + if (master.isValidSlot(i) == false) { + clearInv(master); + return false; + } + ItemStack splitted = is.splitStack(Math.min(is.stackSize, ilimit)); + if ((!isplit) && is.stackSize > 0) { + clearInv(master); + return false; + } + master.mInventory[index] = splitted; + i++; + } + } + + } + + return true;// hoo ray + } + + return false; + } + + @Override + public boolean isBusy() { + T master = getMaster(); + if (master instanceof PatternDualInputHatch) { + return ((PatternDualInputHatch) getMaster()).isBusy(); + } + if (master != null) { + + if (!isInputEmpty(master)) { + return true; + } + + } + + return false; + } + private boolean postMEPatternChange() { + // don't post until it's active + if (!getProxy().isActive()) + return false; + try { + getProxy().getGrid().postEvent(new MENetworkCraftingPatternChange(this, getProxy().getNode())); + } catch (GridAccessException ignored) { + return false; + } + return true; + } + @Override + public void provideCrafting(ICraftingProviderHelper craftingTracker) { + + if (!isActive()) + return; + + for (ItemStack slot : pattern) { + if (slot == null) + continue; + ICraftingPatternDetails details = null; + try { + details = ((ICraftingPatternItem) slot.getItem()).getPatternForItem(slot, + this.getBaseMetaTileEntity().getWorld()); + + } catch (Exception e) { + + } + if (details == null) { + GT_Mod.GT_FML_LOGGER.warn("Found an invalid pattern at " + getBaseMetaTileEntity().getCoords() + + " in dim " + getBaseMetaTileEntity().getWorld().provider.dimensionId); + continue; + } + craftingTracker.addCraftingOption(this, details); + } + } + + protected ModularWindow createPatternWindow(final EntityPlayer player) { + final int WIDTH = 18 * 4 + 6; + final int HEIGHT = 18 * 9 + 6; + final int PARENT_WIDTH = getGUIWidth(); + final int PARENT_HEIGHT = getGUIHeight(); + + ModularWindow.Builder builder = ModularWindow.builder(WIDTH, HEIGHT); + builder.setBackground(GT_UITextures.BACKGROUND_SINGLEBLOCK_DEFAULT); + builder.setGuiTint(getGUIColorization()); + builder.setDraggable(true); + builder.setPos((a, b) -> new Pos2d(PARENT_WIDTH + b.getPos().getX(), PARENT_HEIGHT * 0 + b.getPos().getY())); + MappingItemHandler shared_handler = new MappingItemHandler(pattern, 0, 36); + // use shared handler + // or shift clicking a pattern in pattern slot will just transfer it to + // another pattern slot + // instead of player inventory! + for (int i = 0; i < 36; i++) { + + BaseSlot bs; + + builder.widget(new SlotWidget(bs = new BaseSlot(shared_handler, i) + + ) { + + @Override + protected ItemStack getItemStackForRendering(Slot slotIn) { + ItemStack stack = slotIn.getStack(); + if (stack == null || !(stack.getItem() instanceof ItemEncodedPattern)) { + return stack; + } + ItemStack output = ((ItemEncodedPattern) stack.getItem()).getOutput(stack); + return output != null ? output : stack; + + } + }.setShiftClickPriority(-1).setFilter(itemStack -> itemStack.getItem() instanceof ICraftingPatternItem) + .setChangeListener(() -> { + onPatternChange(); + }).setPos((i % 4) * 18 + 3, (i / 4) * 18 + 3) + .setBackground(getGUITextureSet().getItemSlot(), GT_UITextures.OVERLAY_SLOT_PATTERN_ME)); + + } + + return builder.build(); + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + super.onFirstTick(aBaseMetaTileEntity); + getProxy().onReady(); + } + + @Override + public AECableType getCableConnectionType(ForgeDirection forgeDirection) { + return isOutputFacing(forgeDirection) ? AECableType.SMART : AECableType.NONE; + } + + @Override + public void onFacingChange() { + updateValidGridProxySides(); + } + + @Override + public ItemStack getCrafterIcon() { + ItemStack is = this.getMachineCraftingIcon(); + return is == null ? new ItemStack(GregTech_API.sBlockMachines, 1, getBaseMetaTileEntity().getMetaTileID()) : is; + } + + @Override + public int getGUIHeight() { + + return super.getGUIHeight() + 20; + } + + +} diff --git a/src/main/java/reobf/proghatches/gt/metatileentity/util/ISkipStackSizeCheck.java b/src/main/java/reobf/proghatches/gt/metatileentity/util/ISkipStackSizeCheck.java new file mode 100644 index 0000000..148937f --- /dev/null +++ b/src/main/java/reobf/proghatches/gt/metatileentity/util/ISkipStackSizeCheck.java @@ -0,0 +1,5 @@ +package reobf.proghatches.gt.metatileentity.util; + +public interface ISkipStackSizeCheck { + +} diff --git a/src/main/java/reobf/proghatches/main/MyMod.java b/src/main/java/reobf/proghatches/main/MyMod.java index 235a0e9..73863fc 100644 --- a/src/main/java/reobf/proghatches/main/MyMod.java +++ b/src/main/java/reobf/proghatches/main/MyMod.java @@ -120,6 +120,7 @@ import reobf.proghatches.eucrafting.TileFluidInterface_EU; import reobf.proghatches.gt.metatileentity.PatternDualInputHatch; +import reobf.proghatches.gt.metatileentity.PatternDualInputHatchInventoryMappingSlave; import reobf.proghatches.gt.metatileentity.ProgrammingCircuitProvider; import reobf.proghatches.gt.metatileentity.ProgrammingCircuitProviderPrefabricated; import reobf.proghatches.gt.metatileentity.multi.LargeProgrammingCircuitProvider; @@ -127,6 +128,7 @@ import reobf.proghatches.item.ItemProgrammingCircuit; import reobf.proghatches.lang.LangManager; import reobf.proghatches.main.mixin.mixins.MixinFixPipeCoverBug; +import reobf.proghatches.net.MasterSetMessage; import reobf.proghatches.net.OpenPartGuiMessage; import reobf.proghatches.net.PriorityMessage; import reobf.proghatches.net.RenameMessage; @@ -216,6 +218,7 @@ public void preInit(FMLPreInitializationEvent event) { net.registerMessage(new PriorityMessage.Handler(), PriorityMessage.class, 1, Side.SERVER); net.registerMessage(new RenameMessage.Handler(), RenameMessage.class, 2, Side.SERVER); net.registerMessage(new UpgradesMessage.Handler(), UpgradesMessage.class, 3, Side.CLIENT); + net.registerMessage(new MasterSetMessage.Handler(), MasterSetMessage.class, 4, Side.CLIENT); proxy.preInit(event); } @@ -309,7 +312,7 @@ public void postInit(FMLPostInitializationEvent event) { InterfaceTerminalRegistry.instance().register(PartFluidP2PInterface.class); InterfaceTerminalRegistry.instance().register(TileFluidInterface_EU.class); InterfaceTerminalRegistry.instance().register(PatternDualInputHatch.Inst.class); - + InterfaceTerminalRegistry.instance().register(PatternDualInputHatchInventoryMappingSlave.class); //InterfaceTerminalRegistry.instance().register(ProgrammingCircuitProvider.class); //InterfaceTerminalRegistry.instance().register(LargeProgrammingCircuitProvider.class); diff --git a/src/main/java/reobf/proghatches/main/mixin/mixins/MixinAE2FCCompat.java b/src/main/java/reobf/proghatches/main/mixin/mixins/MixinAE2FCCompat.java index 3102b74..9769177 100644 --- a/src/main/java/reobf/proghatches/main/mixin/mixins/MixinAE2FCCompat.java +++ b/src/main/java/reobf/proghatches/main/mixin/mixins/MixinAE2FCCompat.java @@ -48,16 +48,24 @@ private static void wrap(TileEntity capProvider, ForgeDirection face, boolean iscover = check(capProvider, face); boolean ispart = false; if (iscover == false) { - /* TileEntity inter = capProvider.getWorldObj().getTileEntity(capProvider.xCoord + face.offsetX, - capProvider.yCoord + face.offsetY, capProvider.zCoord + face.offsetZ); - */ + ispart = Util.getPart(inter, face.getOpposite()) instanceof PartEUP2PInterface; } if (iscover || ispart) { BlockPos pos = new BlockPos(capProvider.xCoord + face.offsetX, capProvider.yCoord + face.offsetY, - capProvider.zCoord + face.offsetZ); + capProvider.zCoord + face.offsetZ){ + @Override + public TileEntity getTileEntity() { + return null; + //attached TE is never a interface! + + } + }; + + + InventoryAdaptor item = InventoryAdaptor.getAdaptor(capProvider, face); IFluidHandler fluid = capProvider instanceof IFluidHandler ? (IFluidHandler) capProvider : null; diff --git a/src/main/java/reobf/proghatches/main/mixin/mixins/MixinAEAdaptorSkipStackSizeCheck.java b/src/main/java/reobf/proghatches/main/mixin/mixins/MixinAEAdaptorSkipStackSizeCheck.java index b4858d3..88d0d8b 100644 --- a/src/main/java/reobf/proghatches/main/mixin/mixins/MixinAEAdaptorSkipStackSizeCheck.java +++ b/src/main/java/reobf/proghatches/main/mixin/mixins/MixinAEAdaptorSkipStackSizeCheck.java @@ -16,6 +16,7 @@ import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import net.minecraft.inventory.IInventory; import reobf.proghatches.gt.metatileentity.DualInputHatch; +import reobf.proghatches.gt.metatileentity.util.ISkipStackSizeCheck; @Mixin(value = AdaptorIInventory.class, remap = false) @@ -68,7 +69,7 @@ public void constructor(IInventory s,CallbackInfo a) { public boolean check(Object s){ if(s!=null&&s instanceof IGregTechTileEntity){ return Optional.ofNullable(((IGregTechTileEntity)s).getMetaTileEntity()) - .map(ss->ss instanceof DualInputHatch?(DualInputHatch)ss:null) + .map(ss->ss instanceof ISkipStackSizeCheck?(ISkipStackSizeCheck)ss:null) .isPresent();}return false;} } diff --git a/src/main/java/reobf/proghatches/main/registration/Registration.java b/src/main/java/reobf/proghatches/main/registration/Registration.java index 4cf169c..8976f9c 100644 --- a/src/main/java/reobf/proghatches/main/registration/Registration.java +++ b/src/main/java/reobf/proghatches/main/registration/Registration.java @@ -34,11 +34,13 @@ import reobf.proghatches.gt.metatileentity.DataHatchME; import reobf.proghatches.gt.metatileentity.DualInputHachOC; import reobf.proghatches.gt.metatileentity.DualInputHatch; +import reobf.proghatches.gt.metatileentity.DualInputHatchInventoryMappingSlave; import reobf.proghatches.gt.metatileentity.DualInputHatchSlave; import reobf.proghatches.gt.metatileentity.FilterOutputBus; import reobf.proghatches.gt.metatileentity.IngredientBuffer; import reobf.proghatches.gt.metatileentity.MultiCircuitInputBus; import reobf.proghatches.gt.metatileentity.PatternDualInputHatch; +import reobf.proghatches.gt.metatileentity.PatternDualInputHatchInventoryMappingSlave; import reobf.proghatches.gt.metatileentity.ProgrammingCircuitProvider; import reobf.proghatches.gt.metatileentity.ProgrammingCircuitProviderPrefabricated; import reobf.proghatches.gt.metatileentity.ProviderChainer; @@ -61,7 +63,7 @@ public class Registration implements Runnable { public static ArrayList items_eucrafting = new ArrayList(); public final static int DualInputHatchOffset = 0;// -15 public final static int QuadDualInputHatchOffset = 16;// -31 - public final static int BufferedQuadDualInputHatchOffset = 100;//-115 + public final static int BufferedDualInputHatchOffset = 32;// -47 public final static int CircuitProviderOffset = 48; public final static int SlaveOffset = 49; @@ -74,6 +76,8 @@ public class Registration implements Runnable { public final static int FilterOffset = 74;// -77 private static final int RecipeCheckResultDetectorOffset = 78; public final static int IngBufferOffset = 79;// -80 + + public final static int BufferedQuadDualInputHatchOffset = 100;//-115 public final static int LargeProviderOffset = 116; public final static int ChainerOffset = 117; public final static int CircuitProviderOffsetT0 = 118; @@ -89,7 +93,8 @@ public class Registration implements Runnable { public static final int RestrictedHatchME = 163; public static final int RestrictedBusME=164; public final static int DualInputHatchOCOffset = 165; - + public final static int MappingSlaveOffset=166; + public final static int PatternMappingSlaveOffset=167; @SuppressWarnings("deprecation") @Override @@ -410,8 +415,14 @@ public void run() { ); + new DualInputHatchInventoryMappingSlave<>( + Config.metaTileEntityOffset + MappingSlaveOffset, + "hatch.dualinput.slave.inv.mapping", + LangManager.translateToLocal("hatch.dualinput.slave.inv.mapping.name"), 6); - + new PatternDualInputHatchInventoryMappingSlave<>( + Config.metaTileEntityOffset + PatternMappingSlaveOffset, "hatch.dualinput.slave.inv.mapping.me", + LangManager.translateToLocal("hatch.dualinput.slave.inv.mapping.me.name"), 6); /*for (int i = 0; i < 4; i++) { new DualInputHatch( diff --git a/src/main/java/reobf/proghatches/net/MasterSetMessage.java b/src/main/java/reobf/proghatches/net/MasterSetMessage.java new file mode 100644 index 0000000..4789c8e --- /dev/null +++ b/src/main/java/reobf/proghatches/net/MasterSetMessage.java @@ -0,0 +1,82 @@ +package reobf.proghatches.net; + +import java.io.IOException; + +import cpw.mods.fml.common.network.ByteBufUtils; +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; +import cpw.mods.fml.common.network.simpleimpl.MessageContext; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import io.netty.buffer.ByteBuf; +import net.bdew.lib.network.NBTTagCompoundSerialize; +import net.minecraft.client.Minecraft; +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTSizeTracker; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.util.ForgeDirection; +import reobf.proghatches.gt.metatileentity.DualInputHatch; +import reobf.proghatches.gt.metatileentity.PatternDualInputHatchInventoryMappingSlave; + +public class MasterSetMessage implements IMessage { + private int mx; + private int my; + private int mz; + private boolean set; + public MasterSetMessage(){} + public MasterSetMessage(int x, int y, int z, PatternDualInputHatchInventoryMappingSlave te) { + this.x = x; + this.y = y; + this.z = z; + this.mx=te.masterX; + this.my=te.masterY; + this.mz=te.masterZ; + this.set=te.masterSet; + + } + public static class Handler implements IMessageHandler { + + @Override + public MasterSetMessage onMessage(MasterSetMessage message, MessageContext ctx) { + + try{ + + PatternDualInputHatchInventoryMappingSlave te=((PatternDualInputHatchInventoryMappingSlave) + ( + (IGregTechTileEntity) + Minecraft.getMinecraft().thePlayer.getEntityWorld() + .getTileEntity(message.x, message.y, message.z)).getMetaTileEntity() + ); + + te.masterSet=message.set; + te.masterX=message.mx; + te.masterY=message.my; + te.masterZ=message.mz; + + ;}catch(Exception w){w.printStackTrace();} + + + return null; + } +} +int x,y,z; + @Override + public void fromBytes(ByteBuf buf) { + x=buf.readInt(); + y=buf.readInt(); + z=buf.readInt(); + mx=buf.readInt(); + my=buf.readInt(); + mz=buf.readInt(); + set=buf.readBoolean(); + } + + @Override + public void toBytes(ByteBuf buf) { + buf.writeInt(x); + buf.writeInt(y); + buf.writeInt(z); + buf.writeInt(mx); + buf.writeInt(my); + buf.writeInt(mz); + buf.writeBoolean(set); + }} \ No newline at end of file diff --git a/src/main/resources/assets/proghatches/lang/en_US.lang b/src/main/resources/assets/proghatches/lang/en_US.lang index 54fdfd7..2302240 100644 --- a/src/main/resources/assets/proghatches/lang/en_US.lang +++ b/src/main/resources/assets/proghatches/lang/en_US.lang @@ -546,3 +546,7 @@ tile.reactor_syncer.tooltip.2=Note that vanilla redstone update every 2 ticks! tile.reactor_syncer.tooltip.3=Better use Redstone P2P, Redstone Conduit or Redalloy Wire instead. tile.reactor_syncer.tooltip=4 tile.proghatch.reactor_syncer.name=Reactor Update Synchronizer +hatch.dualinput.slave.inv.mapping.name=Dual Inventory Mapping Slave +hatch.dualinput.slave.inv.mapping.me.name=Dual Inventory Mapping Slave(ME) +programmable_hatches.gt.pattern.mapping=Insert Pattern(ME Mapping Slave) +hatch.dualinput.slave.inv.mapping.me.missing=Not Linked diff --git a/src/main/resources/assets/proghatches/lang/en_US/DIHIMS.lang b/src/main/resources/assets/proghatches/lang/en_US/DIHIMS.lang new file mode 100644 index 0000000..85b5f89 --- /dev/null +++ b/src/main/resources/assets/proghatches/lang/en_US/DIHIMS.lang @@ -0,0 +1,4 @@ +Not a hatch, is not a part of Multiblock +Link with Crafting Input Buffer using Data Stick to share input area inventory +Can be used to extend Interfaces attached to master hatch +Use wirecutter to allow inputting from any side \ No newline at end of file diff --git a/src/main/resources/assets/proghatches/lang/zh_CN.lang b/src/main/resources/assets/proghatches/lang/zh_CN.lang index 29dea3d..8988f76 100644 --- a/src/main/resources/assets/proghatches/lang/zh_CN.lang +++ b/src/main/resources/assets/proghatches/lang/zh_CN.lang @@ -545,3 +545,7 @@ tile.reactor_syncer.tooltip.1=有助于不停机情况下直接操作反应堆 tile.reactor_syncer.tooltip.2=注意:原版红石每2tick更新 最好使用红石P2P,红石导管和红色合金导线 tile.reactor_syncer.tooltip=3 tile.proghatch.reactor_syncer.name=反应堆更新同步器 +hatch.dualinput.slave.inv.mapping.name=二合一输入区映射镜像 +hatch.dualinput.slave.inv.mapping.me.name=二合一输入区映射镜像(ME) +programmable_hatches.gt.pattern.mapping=添加样板(ME映射镜像) +hatch.dualinput.slave.inv.mapping.me.missing=未连接 diff --git a/src/main/resources/assets/proghatches/lang/zh_CN/DIHIMS.lang b/src/main/resources/assets/proghatches/lang/zh_CN/DIHIMS.lang new file mode 100644 index 0000000..9fe552b --- /dev/null +++ b/src/main/resources/assets/proghatches/lang/zh_CN/DIHIMS.lang @@ -0,0 +1,4 @@ +不是多方块机器的一部分 +使用闪存链接二合一输入仓以共享其输入区 +从而拓展连接的接口数量以及样板数量 +使用剪线钳允许从任何面输入 \ No newline at end of file diff --git a/src/main/resources/assets/proghatches/textures/blocks/inv_me_slave.png b/src/main/resources/assets/proghatches/textures/blocks/inv_me_slave.png new file mode 100644 index 0000000..3db9d63 Binary files /dev/null and b/src/main/resources/assets/proghatches/textures/blocks/inv_me_slave.png differ