Lots more moved
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, 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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.fluids.block;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.block.Material;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import appeng.block.AEBaseTileBlock;
|
||||
import appeng.container.ContainerLocator;
|
||||
import appeng.container.ContainerOpener;
|
||||
import appeng.fluids.container.FluidInterfaceContainer;
|
||||
import appeng.fluids.tile.FluidInterfaceBlockEntity;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public class FluidInterfaceBlock extends AEBaseTileBlock<FluidInterfaceBlockEntity> {
|
||||
public FluidInterfaceBlock() {
|
||||
super(defaultProps(Material.METAL));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult onActivated(final World w, final BlockPos pos, final PlayerEntity p, final Hand hand,
|
||||
final @Nullable ItemStack heldItem, final BlockHitResult hit) {
|
||||
if (p.isInSneakingPose()) {
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
|
||||
final BlockEntity tg = this.getBlockEntity(w, pos);
|
||||
if (tg != null) {
|
||||
if (Platform.isServer()) {
|
||||
ContainerOpener.openContainer(FluidInterfaceContainer.TYPE, p,
|
||||
ContainerLocator.forTileEntitySide(tg, hit.getSide()));
|
||||
}
|
||||
return ActionResult.SUCCESS;
|
||||
}
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, 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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.fluids.client.gui;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.screen.slot.Slot;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.screen.slot.SlotActionType;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
|
||||
import appeng.api.config.Settings;
|
||||
import appeng.api.config.SortDir;
|
||||
import appeng.api.config.SortOrder;
|
||||
import appeng.api.config.ViewItems;
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.api.util.IConfigManager;
|
||||
import appeng.client.ActionKey;
|
||||
import appeng.client.gui.AEBaseMEScreen;
|
||||
import appeng.client.gui.widgets.AETextField;
|
||||
import appeng.client.gui.widgets.ISortSource;
|
||||
import appeng.client.gui.widgets.Scrollbar;
|
||||
import appeng.client.gui.widgets.SettingToggleButton;
|
||||
import appeng.client.me.FluidRepo;
|
||||
import appeng.client.me.InternalFluidSlotME;
|
||||
import appeng.client.me.SlotFluidME;
|
||||
import appeng.core.AELog;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.core.localization.GuiText;
|
||||
import appeng.core.sync.network.NetworkHandler;
|
||||
import appeng.core.sync.packets.ConfigValuePacket;
|
||||
import appeng.core.sync.packets.InventoryActionPacket;
|
||||
import appeng.fluids.container.FluidTerminalContainer;
|
||||
import appeng.fluids.container.slots.IMEFluidSlot;
|
||||
import appeng.helpers.InventoryAction;
|
||||
import appeng.util.IConfigManagerHost;
|
||||
import appeng.util.Platform;
|
||||
|
||||
/**
|
||||
* @author BrockWS
|
||||
* @version rv6 - 12/05/2018
|
||||
* @since rv6 12/05/2018
|
||||
*/
|
||||
public class FluidTerminalScreen extends AEBaseMEScreen<FluidTerminalContainer>
|
||||
implements ISortSource, IConfigManagerHost {
|
||||
private final List<SlotFluidME> meFluidSlots = new LinkedList<>();
|
||||
private final FluidRepo repo;
|
||||
private final IConfigManager configSrc;
|
||||
|
||||
private static final int GRID_OFFSET_X = 9;
|
||||
private static final int GRID_OFFSET_Y = 18;
|
||||
private static final int ROWS = 6;
|
||||
private static final int COLS = 9;
|
||||
|
||||
private AETextField searchField;
|
||||
private SettingToggleButton<SortOrder> sortByBox;
|
||||
private SettingToggleButton<SortDir> sortDirBox;
|
||||
|
||||
public FluidTerminalScreen(FluidTerminalContainer container, PlayerInventory playerInventory,
|
||||
Text title) {
|
||||
super(container, playerInventory, title);
|
||||
this.backgroundWidth = 185;
|
||||
this.backgroundHeight = 222;
|
||||
final Scrollbar scrollbar = new Scrollbar();
|
||||
this.setScrollBar(scrollbar);
|
||||
this.repo = new FluidRepo(scrollbar, this);
|
||||
this.configSrc = container.getConfigManager();
|
||||
this.handler.setGui(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
this.x = (this.width - this.backgroundWidth) / 2;
|
||||
this.y = (this.height - this.backgroundHeight) / 2;
|
||||
|
||||
this.searchField = new AETextField(this.textRenderer, this.x + 80, this.y + 4, 90, 12);
|
||||
this.searchField.setHasBorder(false);
|
||||
this.searchField.setMaxLength(25);
|
||||
this.searchField.setEditableColor(0xFFFFFF);
|
||||
this.searchField.setSelectionColor(0xFF99FF99);
|
||||
this.searchField.setVisible(true);
|
||||
|
||||
int offset = this.y;
|
||||
|
||||
this.sortByBox = this.addButton(new SettingToggleButton<>(this.x - 18, offset, Settings.SORT_BY,
|
||||
getSortBy(), Platform::isSortOrderAvailable, this::toggleServerSetting));
|
||||
offset += 20;
|
||||
|
||||
this.sortDirBox = this.addButton(new SettingToggleButton<>(this.x - 18, offset, Settings.SORT_DIRECTION,
|
||||
getSortDir(), this::toggleServerSetting));
|
||||
|
||||
for (int y = 0; y < ROWS; y++) {
|
||||
for (int x = 0; x < COLS; x++) {
|
||||
SlotFluidME slot = new SlotFluidME(new InternalFluidSlotME(this.repo, x + y * COLS,
|
||||
GRID_OFFSET_X + x * 18, GRID_OFFSET_Y + y * 18));
|
||||
this.getMeFluidSlots().add(slot);
|
||||
this.handler.slots.add(slot);
|
||||
}
|
||||
}
|
||||
this.setScrollBar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawFG(MatrixStack matrices, int offsetX, int offsetY, int mouseX, int mouseY) {
|
||||
this.textRenderer.draw(matrices, this.getGuiDisplayName("Fluid Terminal"), 8, 6, 4210752);
|
||||
this.textRenderer.draw(matrices, GuiText.inventory.getLocal(), 8, this.backgroundHeight - 96 + 3, 4210752);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawBG(MatrixStack matrices, int offsetX, int offsetY, int mouseX, int mouseY, float partialTicks) {
|
||||
this.bindTexture(this.getBackground());
|
||||
final int x_width = 197;
|
||||
drawTexture(matrices, offsetX, offsetY, 0, 0, x_width, 18);
|
||||
|
||||
for (int x = 0; x < 6; x++) {
|
||||
drawTexture(matrices, offsetX, offsetY + 18 + x * 18, 0, 18, x_width, 18);
|
||||
}
|
||||
|
||||
drawTexture(matrices, offsetX, offsetY + 16 + 6 * 18, 0, 106 - 18 - 18, x_width, 99 + 77);
|
||||
|
||||
if (this.searchField != null) {
|
||||
this.searchField.render(matrices, mouseX, mouseY, partialTicks);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
this.repo.setPower(this.handler.isPowered());
|
||||
super.tick();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawMouseoverTooltip(MatrixStack matrices, int mouseX, int mouseY) {
|
||||
final Slot slot = this.getSlot(mouseX, mouseY);
|
||||
|
||||
if (slot instanceof IMEFluidSlot && slot.doDrawHoveringEffect()) {
|
||||
final IMEFluidSlot fluidSlot = (IMEFluidSlot) slot;
|
||||
|
||||
if (fluidSlot.getAEFluidStack() != null && fluidSlot.shouldRenderAsFluid()) {
|
||||
final IAEFluidStack fluidStack = fluidSlot.getAEFluidStack();
|
||||
final String formattedAmount = NumberFormat.getNumberInstance(Locale.US)
|
||||
.format(fluidStack.getStackSize() / 1000.0) + " B";
|
||||
|
||||
final String modName = Platform.getModName(Platform.getModId(fluidStack));
|
||||
|
||||
final List<Text> list = new ArrayList<>();
|
||||
list.add(fluidStack.getFluidStack().getName());
|
||||
list.add(new LiteralText(formattedAmount));
|
||||
list.add(new LiteralText(modName));
|
||||
|
||||
this.renderTooltip(matrices, list, mouseX, mouseY);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.drawMouseoverTooltip(matrices, mouseX, mouseY);
|
||||
}
|
||||
|
||||
private <S extends Enum<S>> void toggleServerSetting(SettingToggleButton<S> btn, boolean backwards) {
|
||||
S next = btn.getNextValue(backwards);
|
||||
NetworkHandler.instance().sendToServer(new ConfigValuePacket(btn.getSetting().name(), next.name()));
|
||||
btn.set(next);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMouseClick(Slot slot, int slotIdx, int mouseButton, SlotActionType clickType) {
|
||||
if (slot instanceof SlotFluidME) {
|
||||
final SlotFluidME meSlot = (SlotFluidME) slot;
|
||||
|
||||
if (clickType == SlotActionType.PICKUP) {
|
||||
// TODO: Allow more options
|
||||
if (mouseButton == 0 && meSlot.hasStack()) {
|
||||
this.handler.setTargetStack(meSlot.getAEFluidStack());
|
||||
AELog.debug("mouse0 GUI STACK SIZE %s", meSlot.getAEFluidStack().getStackSize());
|
||||
NetworkHandler.instance()
|
||||
.sendToServer(new InventoryActionPacket(InventoryAction.FILL_ITEM, slot.id, 0));
|
||||
} else {
|
||||
this.handler.setTargetStack(meSlot.getAEFluidStack());
|
||||
if (meSlot.getAEFluidStack() != null) {
|
||||
AELog.debug("mouse1 GUI STACK SIZE %s", meSlot.getAEFluidStack().getStackSize());
|
||||
}
|
||||
NetworkHandler.instance()
|
||||
.sendToServer(new InventoryActionPacket(InventoryAction.EMPTY_ITEM, slot.id, 0));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
super.onMouseClick(slot, slotIdx, mouseButton, clickType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean charTyped(char character, int p_charTyped_2_) {
|
||||
if (character == ' ' && this.searchField.getText().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.searchField.isFocused() && this.searchField.charTyped(character, p_charTyped_2_)) {
|
||||
this.repo.setSearchString(this.searchField.getText());
|
||||
this.repo.updateView();
|
||||
this.setScrollBar();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyPressed(int keyCode, int scanCode, int p_keyPressed_3_) {
|
||||
|
||||
if (keyCode != GLFW.GLFW_KEY_ESCAPE && !this.checkHotbarKeys(keyCode, scanCode)) {
|
||||
if (AppEng.instance().isActionKey(ActionKey.TOGGLE_FOCUS, keyCode, scanCode)) {
|
||||
this.searchField.setFocused(!this.searchField.isFocused());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.searchField.isFocused()) {
|
||||
if (keyCode == GLFW.GLFW_KEY_ENTER) {
|
||||
this.searchField.setFocused(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.searchField.keyPressed(keyCode, scanCode, p_keyPressed_3_)) {
|
||||
this.repo.setSearchString(this.searchField.getText());
|
||||
this.repo.updateView();
|
||||
this.setScrollBar();
|
||||
}
|
||||
|
||||
// We need to swallow key presses if the field is focused because typing 'e'
|
||||
// would otherwise close
|
||||
// the screen
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return super.keyPressed(keyCode, scanCode, p_keyPressed_3_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(final double xCoord, final double yCoord, final int btn) {
|
||||
if (this.searchField.mouseClicked(xCoord, yCoord, btn)) {
|
||||
if (btn == 1 && this.searchField.isMouseOver(xCoord, yCoord)) {
|
||||
this.searchField.setText("");
|
||||
this.repo.setSearchString("");
|
||||
this.repo.updateView();
|
||||
this.setScrollBar();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.mouseClicked(xCoord, yCoord, btn);
|
||||
}
|
||||
|
||||
public void postUpdate(final List<IAEFluidStack> list) {
|
||||
for (final IAEFluidStack is : list) {
|
||||
this.repo.postUpdate(is);
|
||||
}
|
||||
|
||||
this.repo.updateView();
|
||||
this.setScrollBar();
|
||||
}
|
||||
|
||||
private void setScrollBar() {
|
||||
this.getScrollBar().setTop(18).setLeft(175).setHeight(ROWS * 18 - 2);
|
||||
this.getScrollBar().setRange(0, (this.repo.size() + COLS - 1) / COLS - ROWS, ROWS / 6);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortOrder getSortBy() {
|
||||
return (SortOrder) this.configSrc.getSetting(Settings.SORT_BY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortDir getSortDir() {
|
||||
return (SortDir) this.configSrc.getSetting(Settings.SORT_DIRECTION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewItems getSortDisplay() {
|
||||
return (ViewItems) this.configSrc.getSetting(Settings.VIEW_MODE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSetting(IConfigManager manager, Settings settingName, Enum<?> newValue) {
|
||||
if (this.sortByBox != null) {
|
||||
this.sortByBox.set(getSortBy());
|
||||
}
|
||||
|
||||
if (this.sortDirBox != null) {
|
||||
this.sortDirBox.set(getSortDir());
|
||||
}
|
||||
|
||||
this.repo.updateView();
|
||||
}
|
||||
|
||||
protected List<SlotFluidME> getMeFluidSlots() {
|
||||
return this.meFluidSlots;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isPowered() {
|
||||
return this.repo.hasPower();
|
||||
}
|
||||
|
||||
protected String getBackground() {
|
||||
return "guis/terminal.png";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.fluids.client.render;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
|
||||
import net.minecraft.client.font.TextRenderer;
|
||||
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.client.render.StackSizeRenderer;
|
||||
import appeng.core.AEConfig;
|
||||
import appeng.util.ISlimReadableNumberConverter;
|
||||
import appeng.util.IWideReadableNumberConverter;
|
||||
import appeng.util.ReadableNumberConverter;
|
||||
|
||||
/**
|
||||
* @author AlgorithmX2
|
||||
* @author thatsIch
|
||||
* @author yueh
|
||||
* @version rv6
|
||||
* @since rv6
|
||||
*/
|
||||
public class FluidStackSizeRenderer {
|
||||
|
||||
private static final String[] NUMBER_FORMATS = new String[] { "#.000", "#.00", "#.0", "#" };
|
||||
|
||||
private static final ISlimReadableNumberConverter SLIM_CONVERTER = ReadableNumberConverter.INSTANCE;
|
||||
private static final IWideReadableNumberConverter WIDE_CONVERTER = ReadableNumberConverter.INSTANCE;
|
||||
|
||||
public void renderStackSize(TextRenderer fontRenderer, IAEFluidStack aeStack, int xPos, int yPos) {
|
||||
if (aeStack != null && aeStack.getStackSize() > 0) {
|
||||
final String stackSize = this.getToBeRenderedStackSize(aeStack.getStackSize());
|
||||
StackSizeRenderer.renderSizeLabel(fontRenderer, xPos, yPos, stackSize);
|
||||
}
|
||||
}
|
||||
|
||||
private String getToBeRenderedStackSize(final long originalSize) {
|
||||
// Handle any value below 100 (large font) or 1000 (small font) Buckets with a
|
||||
// custom formatter,
|
||||
// otherwise pass it to the normal number converter
|
||||
if (originalSize < 1000 * 100 && AEConfig.instance().isUseLargeFonts()) {
|
||||
return this.getSlimRenderedStacksize(originalSize);
|
||||
} else if (originalSize < 1000 * 1000 && !AEConfig.instance().isUseLargeFonts()) {
|
||||
return this.getWideRenderedStacksize(originalSize);
|
||||
}
|
||||
|
||||
if (AEConfig.instance().isUseLargeFonts()) {
|
||||
return SLIM_CONVERTER.toSlimReadableForm(originalSize / 1000);
|
||||
} else {
|
||||
return WIDE_CONVERTER.toWideReadableForm(originalSize / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
private String getSlimRenderedStacksize(final long originalSize) {
|
||||
final int log = 1 + (int) Math.floor(Math.log10(originalSize)) / 2;
|
||||
|
||||
return this.getRenderedFluidStackSize(originalSize, log);
|
||||
}
|
||||
|
||||
private String getWideRenderedStacksize(final long originalSize) {
|
||||
final int log = (int) Math.floor(Math.log10(originalSize)) / 2;
|
||||
|
||||
return this.getRenderedFluidStackSize(originalSize, log);
|
||||
}
|
||||
|
||||
private String getRenderedFluidStackSize(final long originalSize, final int log) {
|
||||
final int index = Math.max(0, Math.min(3, log));
|
||||
|
||||
final DecimalFormatSymbols symbols = new DecimalFormatSymbols();
|
||||
symbols.setDecimalSeparator('.');
|
||||
final DecimalFormat format = new DecimalFormat(NUMBER_FORMATS[index]);
|
||||
format.setDecimalFormatSymbols(symbols);
|
||||
format.setRoundingMode(RoundingMode.DOWN);
|
||||
|
||||
return format.format(originalSize / 1000d);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
|
||||
package appeng.fluids.container;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import alexiil.mc.lib.attributes.Simulation;
|
||||
import alexiil.mc.lib.attributes.fluid.FluidAttributes;
|
||||
import alexiil.mc.lib.attributes.fluid.amount.FluidAmount;
|
||||
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.screen.ScreenHandlerType;
|
||||
import net.minecraft.screen.ScreenHandlerListener;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import appeng.api.config.Upgrades;
|
||||
import appeng.api.implementations.IUpgradeableHost;
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.container.implementations.UpgradeableContainer;
|
||||
import appeng.fluids.helper.FluidSyncHelper;
|
||||
import appeng.fluids.util.AEFluidStack;
|
||||
import appeng.fluids.util.IAEFluidTank;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public abstract class FluidConfigurableContainer extends UpgradeableContainer implements IFluidSyncContainer {
|
||||
private FluidSyncHelper sync = null;
|
||||
|
||||
public FluidConfigurableContainer(ScreenHandlerType<?> containerType, int id, PlayerInventory ip, IUpgradeableHost te) {
|
||||
super(containerType, id, ip, te);
|
||||
}
|
||||
|
||||
public abstract IAEFluidTank getFluidConfigInventory();
|
||||
|
||||
private FluidSyncHelper getSyncHelper() {
|
||||
if (this.sync == null) {
|
||||
this.sync = new FluidSyncHelper(this.getFluidConfigInventory(), 0);
|
||||
}
|
||||
return this.sync;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemStack transferStackToContainer(ItemStack input) {
|
||||
FluidVolume fluid = FluidAttributes.EXTRACTABLE.get(input)
|
||||
.attemptAnyExtraction(FluidAmount.MAX_VALUE, Simulation.ACTION);
|
||||
|
||||
if (!fluid.isEmpty()) {
|
||||
final IAEFluidTank t = this.getFluidConfigInventory();
|
||||
final IAEFluidStack stack = AEFluidStack.fromFluidVolume(fluid, RoundingMode.DOWN);
|
||||
for (int i = 0; i < t.getSlots(); ++i) {
|
||||
if (t.getFluidInSlot(i) == null && this.isValidForConfig(i, stack)) {
|
||||
t.setFluidInSlot(i, stack);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
protected boolean isValidForConfig(int slot, IAEFluidStack fs) {
|
||||
if (this.supportCapacity()) {
|
||||
// assumes 4 slots per upgrade
|
||||
final int upgrades = this.getUpgradeable().getInstalledUpgrades(Upgrades.CAPACITY);
|
||||
|
||||
if (slot > 0 && upgrades < 1) {
|
||||
return false;
|
||||
}
|
||||
if (slot > 4 && upgrades < 2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void standardDetectAndSendChanges() {
|
||||
if (Platform.isServer()) {
|
||||
this.getSyncHelper().sendDiff(this.getListeners());
|
||||
|
||||
// clear out config items that are no longer valid (eg capacity upgrade removed)
|
||||
final IAEFluidTank t = this.getFluidConfigInventory();
|
||||
for (int i = 0; i < t.getSlots(); ++i) {
|
||||
if (t.getFluidInSlot(i) != null && !this.isValidForConfig(i, t.getFluidInSlot(i))) {
|
||||
t.setFluidInSlot(i, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
super.standardDetectAndSendChanges();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(ScreenHandlerListener listener) {
|
||||
super.addListener(listener);
|
||||
this.getSyncHelper().sendFull(Collections.singleton(listener));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveFluidSlots(Map<Integer, IAEFluidStack> fluids) {
|
||||
this.getSyncHelper().readPacket(fluids);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
|
||||
package appeng.fluids.container;
|
||||
|
||||
import alexiil.mc.lib.attributes.item.FixedItemInv;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.screen.ScreenHandlerType;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
|
||||
import appeng.api.config.SecurityPermissions;
|
||||
import appeng.api.config.Upgrades;
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.container.ContainerLocator;
|
||||
import appeng.container.implementations.ContainerHelper;
|
||||
import appeng.container.slot.RestrictedInputSlot;
|
||||
import appeng.fluids.parts.FluidFormationPlanePart;
|
||||
import appeng.fluids.util.IAEFluidTank;
|
||||
|
||||
public class FluidFormationPlaneContainer extends FluidConfigurableContainer {
|
||||
|
||||
public static ScreenHandlerType<FluidFormationPlaneContainer> TYPE;
|
||||
|
||||
private static final ContainerHelper<FluidFormationPlaneContainer, FluidFormationPlanePart> helper = new ContainerHelper<>(
|
||||
FluidFormationPlaneContainer::new, FluidFormationPlanePart.class, SecurityPermissions.BUILD);
|
||||
|
||||
public static FluidFormationPlaneContainer fromNetwork(int windowId, PlayerInventory inv, PacketByteBuf buf) {
|
||||
return helper.fromNetwork(windowId, inv, buf);
|
||||
}
|
||||
|
||||
public static boolean open(PlayerEntity player, ContainerLocator locator) {
|
||||
return helper.open(player, locator);
|
||||
}
|
||||
|
||||
private final FluidFormationPlanePart plane;
|
||||
|
||||
public FluidFormationPlaneContainer(int id, final PlayerInventory ip, final FluidFormationPlanePart te) {
|
||||
super(TYPE, id, ip, te);
|
||||
this.plane = te;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getHeight() {
|
||||
return 251;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEFluidTank getFluidConfigInventory() {
|
||||
return this.plane.getConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupConfig() {
|
||||
final FixedItemInv upgrades = this.getUpgradeable().getInventoryByName("upgrades");
|
||||
this.addSlot((new RestrictedInputSlot(RestrictedInputSlot.PlacableItemType.UPGRADES, upgrades, 0, 187, 8,
|
||||
this.getPlayerInventory())).setNotDraggable());
|
||||
this.addSlot((new RestrictedInputSlot(RestrictedInputSlot.PlacableItemType.UPGRADES, upgrades, 1, 187, 8 + 18,
|
||||
this.getPlayerInventory())).setNotDraggable());
|
||||
this.addSlot((new RestrictedInputSlot(RestrictedInputSlot.PlacableItemType.UPGRADES, upgrades, 2, 187,
|
||||
8 + 18 * 2, this.getPlayerInventory())).setNotDraggable());
|
||||
this.addSlot((new RestrictedInputSlot(RestrictedInputSlot.PlacableItemType.UPGRADES, upgrades, 3, 187,
|
||||
8 + 18 * 3, this.getPlayerInventory())).setNotDraggable());
|
||||
this.addSlot((new RestrictedInputSlot(RestrictedInputSlot.PlacableItemType.UPGRADES, upgrades, 4, 187,
|
||||
8 + 18 * 4, this.getPlayerInventory())).setNotDraggable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendContentUpdates() {
|
||||
this.verifyPermissions(SecurityPermissions.BUILD, false);
|
||||
this.checkToolbox();
|
||||
this.standardDetectAndSendChanges();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isValidForConfig(int slot, IAEFluidStack fs) {
|
||||
if (this.supportCapacity()) {
|
||||
final int upgrades = this.getUpgradeable().getInstalledUpgrades(Upgrades.CAPACITY);
|
||||
|
||||
final int y = slot / 9;
|
||||
|
||||
if (y >= upgrades + 2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSlotEnabled(final int idx) {
|
||||
final int upgrades = this.getUpgradeable().getInstalledUpgrades(Upgrades.CAPACITY);
|
||||
|
||||
return upgrades > idx;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supportCapacity() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int availableUpgrades() {
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, 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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.fluids.container;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.screen.ScreenHandlerType;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
|
||||
import appeng.api.config.SecurityPermissions;
|
||||
import appeng.container.ContainerLocator;
|
||||
import appeng.container.implementations.ContainerHelper;
|
||||
import appeng.fluids.parts.SharedFluidBusPart;
|
||||
import appeng.fluids.util.IAEFluidTank;
|
||||
|
||||
/**
|
||||
* @author BrockWS
|
||||
* @version rv5 - 1/05/2018
|
||||
* @since rv5 1/05/2018
|
||||
*/
|
||||
public class FluidIOContainer extends FluidConfigurableContainer {
|
||||
|
||||
public static ScreenHandlerType<FluidIOContainer> TYPE;
|
||||
|
||||
private static final ContainerHelper<FluidIOContainer, SharedFluidBusPart> helper = new ContainerHelper<>(
|
||||
FluidIOContainer::new, SharedFluidBusPart.class, SecurityPermissions.BUILD);
|
||||
|
||||
public static FluidIOContainer fromNetwork(int windowId, PlayerInventory inv, PacketByteBuf buf) {
|
||||
return helper.fromNetwork(windowId, inv, buf);
|
||||
}
|
||||
|
||||
public static boolean open(PlayerEntity player, ContainerLocator locator) {
|
||||
return helper.open(player, locator);
|
||||
}
|
||||
|
||||
private final SharedFluidBusPart bus;
|
||||
|
||||
public FluidIOContainer(int id, PlayerInventory ip, SharedFluidBusPart te) {
|
||||
super(TYPE, id, ip, te);
|
||||
this.bus = te;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEFluidTank getFluidConfigInventory() {
|
||||
return this.bus.getConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupConfig() {
|
||||
this.setupUpgrades();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, 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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.fluids.container;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.screen.ScreenHandlerListener;
|
||||
import net.minecraft.screen.ScreenHandlerType;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
|
||||
import appeng.api.config.SecurityPermissions;
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.api.util.IConfigManager;
|
||||
import appeng.container.ContainerLocator;
|
||||
import appeng.container.implementations.ContainerHelper;
|
||||
import appeng.fluids.helper.DualityFluidInterface;
|
||||
import appeng.fluids.helper.FluidSyncHelper;
|
||||
import appeng.fluids.helper.IFluidInterfaceHost;
|
||||
import appeng.fluids.util.IAEFluidTank;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public class FluidInterfaceContainer extends FluidConfigurableContainer {
|
||||
|
||||
public static ScreenHandlerType<FluidInterfaceContainer> TYPE;
|
||||
|
||||
private static final ContainerHelper<FluidInterfaceContainer, IFluidInterfaceHost> helper = new ContainerHelper<>(
|
||||
FluidInterfaceContainer::new, IFluidInterfaceHost.class, SecurityPermissions.BUILD);
|
||||
|
||||
public static FluidInterfaceContainer fromNetwork(int windowId, PlayerInventory inv, PacketByteBuf buf) {
|
||||
return helper.fromNetwork(windowId, inv, buf);
|
||||
}
|
||||
|
||||
public static boolean open(PlayerEntity player, ContainerLocator locator) {
|
||||
return helper.open(player, locator);
|
||||
}
|
||||
|
||||
private final DualityFluidInterface myDuality;
|
||||
private final FluidSyncHelper tankSync;
|
||||
|
||||
public FluidInterfaceContainer(int id, final PlayerInventory ip, final IFluidInterfaceHost te) {
|
||||
super(TYPE, id, ip, te.getDualityFluidInterface().getHost());
|
||||
|
||||
this.myDuality = te.getDualityFluidInterface();
|
||||
this.tankSync = new FluidSyncHelper(this.myDuality.getTanks(), DualityFluidInterface.NUMBER_OF_TANKS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getHeight() {
|
||||
return 231;
|
||||
}
|
||||
|
||||
public IAEFluidTank getTanks() {
|
||||
return myDuality.getTanks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEFluidTank getFluidConfigInventory() {
|
||||
return this.myDuality.getConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendContentUpdates() {
|
||||
this.verifyPermissions(SecurityPermissions.BUILD, false);
|
||||
|
||||
if (Platform.isServer()) {
|
||||
this.tankSync.sendDiff(this.getListeners());
|
||||
}
|
||||
|
||||
super.sendContentUpdates();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupConfig() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadSettingsFromHost(final IConfigManager cm) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(ScreenHandlerListener listener) {
|
||||
super.addListener(listener);
|
||||
this.tankSync.sendFull(Collections.singleton(listener));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveFluidSlots(Map<Integer, IAEFluidStack> fluids) {
|
||||
super.receiveFluidSlots(fluids);
|
||||
this.tankSync.readPacket(fluids);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supportCapacity() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int availableUpgrades() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasToolbox() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package appeng.fluids.container;
|
||||
|
||||
import net.minecraft.client.gui.widget.TextFieldWidget;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.screen.ScreenHandlerType;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
|
||||
import appeng.api.config.RedstoneMode;
|
||||
import appeng.api.config.SecurityPermissions;
|
||||
import appeng.api.config.Settings;
|
||||
import appeng.container.ContainerLocator;
|
||||
import appeng.container.guisync.GuiSync;
|
||||
import appeng.container.implementations.ContainerHelper;
|
||||
import appeng.fluids.parts.FluidLevelEmitterPart;
|
||||
import appeng.fluids.util.IAEFluidTank;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public class FluidLevelEmitterContainer extends FluidConfigurableContainer {
|
||||
public static ScreenHandlerType<FluidLevelEmitterContainer> TYPE;
|
||||
|
||||
private static final ContainerHelper<FluidLevelEmitterContainer, FluidLevelEmitterPart> helper = new ContainerHelper<>(
|
||||
FluidLevelEmitterContainer::new, FluidLevelEmitterPart.class, SecurityPermissions.BUILD);
|
||||
|
||||
public static FluidLevelEmitterContainer fromNetwork(int windowId, PlayerInventory inv, PacketByteBuf buf) {
|
||||
return helper.fromNetwork(windowId, inv, buf);
|
||||
}
|
||||
|
||||
public static boolean open(PlayerEntity player, ContainerLocator locator) {
|
||||
return helper.open(player, locator);
|
||||
}
|
||||
|
||||
private final FluidLevelEmitterPart lvlEmitter;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
private TextFieldWidget textField;
|
||||
@GuiSync(3)
|
||||
public long EmitterValue = -1;
|
||||
|
||||
public FluidLevelEmitterContainer(int id, final PlayerInventory ip, final FluidLevelEmitterPart te) {
|
||||
super(TYPE, id, ip, te);
|
||||
this.lvlEmitter = te;
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public void setTextField(final TextFieldWidget level) {
|
||||
this.textField = level;
|
||||
this.textField.setText(String.valueOf(this.EmitterValue));
|
||||
}
|
||||
|
||||
public void setLevel(final long l, final PlayerEntity player) {
|
||||
this.lvlEmitter.setReportingValue(l);
|
||||
this.EmitterValue = l;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupConfig() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supportCapacity() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int availableUpgrades() {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendContentUpdates() {
|
||||
this.verifyPermissions(SecurityPermissions.BUILD, false);
|
||||
|
||||
if (Platform.isServer()) {
|
||||
this.EmitterValue = this.lvlEmitter.getReportingValue();
|
||||
this.setRedStoneMode(
|
||||
(RedstoneMode) this.getUpgradeable().getConfigManager().getSetting(Settings.REDSTONE_EMITTER));
|
||||
}
|
||||
|
||||
this.standardDetectAndSendChanges();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(final String field, final Object oldValue, final Object newValue) {
|
||||
if (field.equals("EmitterValue")) {
|
||||
if (this.textField != null) {
|
||||
this.textField.setText(String.valueOf(this.EmitterValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEFluidTank getFluidConfigInventory() {
|
||||
return this.lvlEmitter.getConfig();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, 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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.fluids.container;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.screen.ScreenHandlerType;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import alexiil.mc.lib.attributes.item.FixedItemInv;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.config.AccessRestriction;
|
||||
import appeng.api.config.FuzzyMode;
|
||||
import appeng.api.config.SecurityPermissions;
|
||||
import appeng.api.config.Settings;
|
||||
import appeng.api.config.StorageFilter;
|
||||
import appeng.api.config.Upgrades;
|
||||
import appeng.api.storage.IMEInventory;
|
||||
import appeng.api.storage.channels.IFluidStorageChannel;
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.container.ContainerLocator;
|
||||
import appeng.container.guisync.GuiSync;
|
||||
import appeng.container.implementations.ContainerHelper;
|
||||
import appeng.container.slot.RestrictedInputSlot;
|
||||
import appeng.fluids.parts.FluidStorageBusPart;
|
||||
import appeng.fluids.util.IAEFluidTank;
|
||||
import appeng.util.Platform;
|
||||
import appeng.util.iterators.NullIterator;
|
||||
|
||||
/**
|
||||
* @author BrockWS
|
||||
* @version rv6 - 22/05/2018
|
||||
* @since rv6 22/05/2018
|
||||
*/
|
||||
public class FluidStorageBusContainer extends FluidConfigurableContainer {
|
||||
|
||||
public static ScreenHandlerType<FluidStorageBusContainer> TYPE;
|
||||
|
||||
private static final ContainerHelper<FluidStorageBusContainer, FluidStorageBusPart> helper = new ContainerHelper<>(
|
||||
FluidStorageBusContainer::new, FluidStorageBusPart.class);
|
||||
|
||||
public static FluidStorageBusContainer fromNetwork(int windowId, PlayerInventory inv, PacketByteBuf buf) {
|
||||
return helper.fromNetwork(windowId, inv, buf);
|
||||
}
|
||||
|
||||
public static boolean open(PlayerEntity player, ContainerLocator locator) {
|
||||
return helper.open(player, locator);
|
||||
}
|
||||
|
||||
private final FluidStorageBusPart storageBus;
|
||||
|
||||
@GuiSync(3)
|
||||
public AccessRestriction rwMode = AccessRestriction.READ_WRITE;
|
||||
|
||||
@GuiSync(4)
|
||||
public StorageFilter storageFilter = StorageFilter.EXTRACTABLE_ONLY;
|
||||
|
||||
public FluidStorageBusContainer(int id, PlayerInventory ip, FluidStorageBusPart te) {
|
||||
super(TYPE, id, ip, te);
|
||||
this.storageBus = te;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getHeight() {
|
||||
return 251;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupConfig() {
|
||||
final FixedItemInv upgrades = this.getUpgradeable().getInventoryByName("upgrades");
|
||||
this.addSlot((new RestrictedInputSlot(RestrictedInputSlot.PlacableItemType.UPGRADES, upgrades, 0, 187, 8,
|
||||
this.getPlayerInventory())).setNotDraggable());
|
||||
this.addSlot((new RestrictedInputSlot(RestrictedInputSlot.PlacableItemType.UPGRADES, upgrades, 1, 187, 8 + 18,
|
||||
this.getPlayerInventory())).setNotDraggable());
|
||||
this.addSlot((new RestrictedInputSlot(RestrictedInputSlot.PlacableItemType.UPGRADES, upgrades, 2, 187,
|
||||
8 + 18 * 2, this.getPlayerInventory())).setNotDraggable());
|
||||
this.addSlot((new RestrictedInputSlot(RestrictedInputSlot.PlacableItemType.UPGRADES, upgrades, 3, 187,
|
||||
8 + 18 * 3, this.getPlayerInventory())).setNotDraggable());
|
||||
this.addSlot((new RestrictedInputSlot(RestrictedInputSlot.PlacableItemType.UPGRADES, upgrades, 4, 187,
|
||||
8 + 18 * 4, this.getPlayerInventory())).setNotDraggable());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isValidForConfig(int slot, IAEFluidStack fs) {
|
||||
if (this.supportCapacity()) {
|
||||
final int upgrades = this.getUpgradeable().getInstalledUpgrades(Upgrades.CAPACITY);
|
||||
|
||||
final int y = slot / 9;
|
||||
|
||||
if (y >= upgrades + 2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supportCapacity() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int availableUpgrades() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendContentUpdates() {
|
||||
this.verifyPermissions(SecurityPermissions.BUILD, false);
|
||||
|
||||
if (Platform.isServer()) {
|
||||
this.setFuzzyMode((FuzzyMode) this.getUpgradeable().getConfigManager().getSetting(Settings.FUZZY_MODE));
|
||||
this.setReadWriteMode(
|
||||
(AccessRestriction) this.getUpgradeable().getConfigManager().getSetting(Settings.ACCESS));
|
||||
this.setStorageFilter(
|
||||
(StorageFilter) this.getUpgradeable().getConfigManager().getSetting(Settings.STORAGE_FILTER));
|
||||
}
|
||||
|
||||
this.standardDetectAndSendChanges();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSlotEnabled(final int idx) {
|
||||
final int upgrades = this.getUpgradeable().getInstalledUpgrades(Upgrades.CAPACITY);
|
||||
|
||||
return upgrades > idx;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
IAEFluidTank h = this.storageBus.getConfig();
|
||||
for (int i = 0; i < h.getSlots(); ++i) {
|
||||
h.setFluidInSlot(i, null);
|
||||
}
|
||||
this.sendContentUpdates();
|
||||
}
|
||||
|
||||
public void partition() {
|
||||
IAEFluidTank h = this.storageBus.getConfig();
|
||||
|
||||
final IMEInventory<IAEFluidStack> cellInv = this.storageBus.getInternalHandler();
|
||||
|
||||
Iterator<IAEFluidStack> i = new NullIterator<>();
|
||||
if (cellInv != null) {
|
||||
final IItemList<IAEFluidStack> list = cellInv.getAvailableItems(
|
||||
AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class).createList());
|
||||
i = list.iterator();
|
||||
}
|
||||
|
||||
for (int x = 0; x < h.getSlots(); x++) {
|
||||
if (i.hasNext() && this.isSlotEnabled((x / 9) - 2)) {
|
||||
h.setFluidInSlot(x, i.next());
|
||||
} else {
|
||||
h.setFluidInSlot(x, null);
|
||||
}
|
||||
}
|
||||
this.sendContentUpdates();
|
||||
}
|
||||
|
||||
public AccessRestriction getReadWriteMode() {
|
||||
return this.rwMode;
|
||||
}
|
||||
|
||||
private void setReadWriteMode(final AccessRestriction rwMode) {
|
||||
this.rwMode = rwMode;
|
||||
}
|
||||
|
||||
public StorageFilter getStorageFilter() {
|
||||
return this.storageFilter;
|
||||
}
|
||||
|
||||
private void setStorageFilter(final StorageFilter storageFilter) {
|
||||
this.storageFilter = storageFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEFluidTank getFluidConfigInventory() {
|
||||
return this.storageBus.getConfig();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,449 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, 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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.fluids.container;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.RoundingMode;
|
||||
import java.nio.BufferOverflowException;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import alexiil.mc.lib.attributes.Simulation;
|
||||
import alexiil.mc.lib.attributes.fluid.FluidAttributes;
|
||||
import alexiil.mc.lib.attributes.fluid.FluidExtractable;
|
||||
import alexiil.mc.lib.attributes.fluid.FluidInsertable;
|
||||
import alexiil.mc.lib.attributes.fluid.amount.FluidAmount;
|
||||
import alexiil.mc.lib.attributes.fluid.filter.ExactFluidFilter;
|
||||
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
|
||||
import alexiil.mc.lib.attributes.misc.Ref;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.screen.ScreenHandlerListener;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.screen.ScreenHandlerType;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.config.PowerMultiplier;
|
||||
import appeng.api.config.SecurityPermissions;
|
||||
import appeng.api.config.Settings;
|
||||
import appeng.api.config.SortDir;
|
||||
import appeng.api.config.SortOrder;
|
||||
import appeng.api.config.ViewItems;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.energy.IEnergyGrid;
|
||||
import appeng.api.networking.energy.IEnergySource;
|
||||
import appeng.api.networking.security.IActionHost;
|
||||
import appeng.api.networking.security.IActionSource;
|
||||
import appeng.api.networking.storage.IBaseMonitor;
|
||||
import appeng.api.storage.IMEMonitor;
|
||||
import appeng.api.storage.IMEMonitorHandlerReceiver;
|
||||
import appeng.api.storage.ITerminalHost;
|
||||
import appeng.api.storage.channels.IFluidStorageChannel;
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.api.util.IConfigManager;
|
||||
import appeng.api.util.IConfigurableObject;
|
||||
import appeng.container.AEBaseContainer;
|
||||
import appeng.container.ContainerLocator;
|
||||
import appeng.container.guisync.GuiSync;
|
||||
import appeng.container.implementations.ContainerHelper;
|
||||
import appeng.core.AELog;
|
||||
import appeng.core.sync.network.NetworkHandler;
|
||||
import appeng.core.sync.packets.ConfigValuePacket;
|
||||
import appeng.core.sync.packets.MEFluidInventoryUpdatePacket;
|
||||
import appeng.core.sync.packets.TargetFluidStackPacket;
|
||||
import appeng.fluids.util.AEFluidStack;
|
||||
import appeng.helpers.InventoryAction;
|
||||
import appeng.me.helpers.ChannelPowerSrc;
|
||||
import appeng.util.ConfigManager;
|
||||
import appeng.util.IConfigManagerHost;
|
||||
import appeng.util.Platform;
|
||||
|
||||
/**
|
||||
* @author BrockWS
|
||||
* @version rv6 - 12/05/2018
|
||||
* @since rv6 12/05/2018
|
||||
*/
|
||||
public class FluidTerminalContainer extends AEBaseContainer
|
||||
implements IConfigManagerHost, IConfigurableObject, IMEMonitorHandlerReceiver<IAEFluidStack> {
|
||||
|
||||
public static ScreenHandlerType<FluidTerminalContainer> TYPE;
|
||||
|
||||
private static final ContainerHelper<FluidTerminalContainer, ITerminalHost> helper = new ContainerHelper<>(
|
||||
FluidTerminalContainer::new, ITerminalHost.class, SecurityPermissions.BUILD);
|
||||
|
||||
public static FluidTerminalContainer fromNetwork(int windowId, PlayerInventory inv, PacketByteBuf buf) {
|
||||
return helper.fromNetwork(windowId, inv, buf);
|
||||
}
|
||||
|
||||
public static boolean open(PlayerEntity player, ContainerLocator locator) {
|
||||
return helper.open(player, locator);
|
||||
}
|
||||
|
||||
private final IConfigManager clientCM;
|
||||
private final IMEMonitor<IAEFluidStack> monitor;
|
||||
private final IItemList<IAEFluidStack> fluids = AEApi.instance().storage()
|
||||
.getStorageChannel(IFluidStorageChannel.class).createList();
|
||||
@GuiSync(99)
|
||||
public boolean hasPower = false;
|
||||
private ITerminalHost terminal;
|
||||
private IConfigManager serverCM;
|
||||
private IConfigManagerHost gui;
|
||||
private IGridNode networkNode;
|
||||
// Holds the fluid the client wishes to extract, or null for insert
|
||||
private IAEFluidStack clientRequestedTargetFluid = null;
|
||||
|
||||
public FluidTerminalContainer(int id, PlayerInventory ip, ITerminalHost terminal) {
|
||||
super(TYPE, id, ip, terminal);
|
||||
this.terminal = terminal;
|
||||
this.clientCM = new ConfigManager(this);
|
||||
|
||||
this.clientCM.registerSetting(Settings.SORT_BY, SortOrder.NAME);
|
||||
this.clientCM.registerSetting(Settings.SORT_DIRECTION, SortDir.ASCENDING);
|
||||
this.clientCM.registerSetting(Settings.VIEW_MODE, ViewItems.ALL);
|
||||
if (Platform.isServer()) {
|
||||
this.serverCM = terminal.getConfigManager();
|
||||
this.monitor = terminal
|
||||
.getInventory(AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class));
|
||||
|
||||
if (this.monitor != null) {
|
||||
this.monitor.addListener(this, null);
|
||||
|
||||
if (terminal instanceof IEnergySource) {
|
||||
this.setPowerSource((IEnergySource) terminal);
|
||||
} else if (terminal instanceof IGridHost || terminal instanceof IActionHost) {
|
||||
final IGridNode node;
|
||||
if (terminal instanceof IGridHost) {
|
||||
node = ((IGridHost) terminal).getGridNode(AEPartLocation.INTERNAL);
|
||||
} else if (terminal instanceof IActionHost) {
|
||||
node = ((IActionHost) terminal).getActionableNode();
|
||||
} else {
|
||||
node = null;
|
||||
}
|
||||
|
||||
if (node != null) {
|
||||
this.networkNode = node;
|
||||
final IGrid g = node.getGrid();
|
||||
if (g != null) {
|
||||
this.setPowerSource(new ChannelPowerSrc(this.networkNode,
|
||||
(IEnergySource) g.getCache(IEnergyGrid.class)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.monitor = null;
|
||||
}
|
||||
this.bindPlayerInventory(ip, 0, 222 - 82);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(Object verificationToken) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postChange(IBaseMonitor<IAEFluidStack> monitor, Iterable<IAEFluidStack> change,
|
||||
IActionSource actionSource) {
|
||||
for (final IAEFluidStack is : change) {
|
||||
this.fluids.add(is);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onListUpdate() {
|
||||
for (final ScreenHandlerListener c : this.getListeners()) {
|
||||
this.queueInventory(c);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(ScreenHandlerListener listener) {
|
||||
super.addListener(listener);
|
||||
|
||||
this.queueInventory(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(final PlayerEntity player) {
|
||||
super.close(player);
|
||||
if (this.monitor != null) {
|
||||
this.monitor.removeListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void queueInventory(final ScreenHandlerListener c) {
|
||||
if (Platform.isServer() && c instanceof PlayerEntity && this.monitor != null) {
|
||||
try {
|
||||
MEFluidInventoryUpdatePacket piu = new MEFluidInventoryUpdatePacket();
|
||||
final IItemList<IAEFluidStack> monitorCache = this.monitor.getStorageList();
|
||||
|
||||
for (final IAEFluidStack send : monitorCache) {
|
||||
try {
|
||||
piu.appendFluid(send);
|
||||
} catch (final BufferOverflowException boe) {
|
||||
NetworkHandler.instance().sendTo(piu, (ServerPlayerEntity) c);
|
||||
|
||||
piu = new MEFluidInventoryUpdatePacket();
|
||||
piu.appendFluid(send);
|
||||
}
|
||||
}
|
||||
|
||||
NetworkHandler.instance().sendTo(piu, (ServerPlayerEntity) c);
|
||||
} catch (final IOException e) {
|
||||
AELog.debug(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IConfigManager getConfigManager() {
|
||||
if (Platform.isServer()) {
|
||||
return this.serverCM;
|
||||
}
|
||||
return this.clientCM;
|
||||
}
|
||||
|
||||
public void setTargetStack(final IAEFluidStack stack) {
|
||||
if (Platform.isClient()) {
|
||||
if (stack == null && this.clientRequestedTargetFluid == null) {
|
||||
return;
|
||||
}
|
||||
if (stack != null && this.clientRequestedTargetFluid != null
|
||||
&& FluidVolume.areEqualExceptAmounts(stack.getFluidStack(), this.clientRequestedTargetFluid.getFluidStack())) {
|
||||
return;
|
||||
}
|
||||
NetworkHandler.instance().sendToServer(new TargetFluidStackPacket((AEFluidStack) stack));
|
||||
}
|
||||
|
||||
this.clientRequestedTargetFluid = stack == null ? null : stack.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSetting(IConfigManager manager, Settings settingName, Enum<?> newValue) {
|
||||
if (this.getGui() != null) {
|
||||
this.getGui().updateSetting(manager, settingName, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendContentUpdates() {
|
||||
if (Platform.isServer()) {
|
||||
if (this.monitor != this.terminal
|
||||
.getInventory(AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class))) {
|
||||
this.setValidContainer(false);
|
||||
}
|
||||
|
||||
for (final Settings set : this.serverCM.getSettings()) {
|
||||
final Enum<?> sideLocal = this.serverCM.getSetting(set);
|
||||
final Enum<?> sideRemote = this.clientCM.getSetting(set);
|
||||
|
||||
if (sideLocal != sideRemote) {
|
||||
this.clientCM.putSetting(set, sideLocal);
|
||||
for (final ScreenHandlerListener crafter : this.getListeners()) {
|
||||
if (crafter instanceof ServerPlayerEntity) {
|
||||
NetworkHandler.instance().sendTo(new ConfigValuePacket(set.name(), sideLocal.name()),
|
||||
(ServerPlayerEntity) crafter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.fluids.isEmpty()) {
|
||||
try {
|
||||
final IItemList<IAEFluidStack> monitorCache = this.monitor.getStorageList();
|
||||
|
||||
final MEFluidInventoryUpdatePacket piu = new MEFluidInventoryUpdatePacket();
|
||||
|
||||
for (final IAEFluidStack is : this.fluids) {
|
||||
final IAEFluidStack send = monitorCache.findPrecise(is);
|
||||
if (send == null) {
|
||||
is.setStackSize(0);
|
||||
piu.appendFluid(is);
|
||||
} else {
|
||||
piu.appendFluid(send);
|
||||
}
|
||||
}
|
||||
|
||||
if (!piu.isEmpty()) {
|
||||
this.fluids.resetStatus();
|
||||
|
||||
for (final Object c : this.getListeners()) {
|
||||
if (c instanceof PlayerEntity) {
|
||||
NetworkHandler.instance().sendTo(piu, (ServerPlayerEntity) c);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
AELog.debug(e);
|
||||
}
|
||||
}
|
||||
this.updatePowerStatus();
|
||||
|
||||
super.sendContentUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAction(ServerPlayerEntity player, InventoryAction action, int slot, long id) {
|
||||
if (action != InventoryAction.FILL_ITEM && action != InventoryAction.EMPTY_ITEM) {
|
||||
super.doAction(player, action, slot, id);
|
||||
return;
|
||||
}
|
||||
|
||||
final ItemStack held = player.inventory.getCursorStack();
|
||||
if (held.getCount() != 1) {
|
||||
// only support stacksize 1 for now
|
||||
return;
|
||||
}
|
||||
|
||||
if (action == InventoryAction.FILL_ITEM && this.clientRequestedTargetFluid != null) {
|
||||
Ref<ItemStack> container = new Ref<>(held);
|
||||
FluidInsertable insertable = FluidAttributes.INSERTABLE.getFirstOrNull(container);
|
||||
if (insertable == null) {
|
||||
return; // Not a fillable item.
|
||||
}
|
||||
|
||||
// Check how much we can store in the item
|
||||
FluidVolume volumeAllowed = insertable.attemptInsertion(this.clientRequestedTargetFluid.getFluidStack().withAmount(FluidAmount.MAX_VALUE), Simulation.SIMULATE);
|
||||
|
||||
final IAEFluidStack stack = AEFluidStack.fromFluidVolume(this.clientRequestedTargetFluid.getFluidStack().withAmount(volumeAllowed.amount()), RoundingMode.DOWN);
|
||||
if (stack == null) {
|
||||
return; // Might be nothing allowed...
|
||||
}
|
||||
|
||||
// Check if we can pull out of the system
|
||||
final IAEFluidStack canPull = Platform.poweredExtraction(this.getPowerSource(), this.monitor, stack,
|
||||
this.getActionSource(), Actionable.SIMULATE);
|
||||
if (canPull == null || canPull.getStackSize() < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// How much could fit into the container
|
||||
volumeAllowed = insertable.attemptInsertion(canPull.getFluidStack(), Simulation.SIMULATE);
|
||||
if (volumeAllowed.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Now actually pull out of the system
|
||||
stack.setStackSize(volumeAllowed.amount().asLong(1000, RoundingMode.DOWN));
|
||||
final IAEFluidStack pulled = Platform.poweredExtraction(this.getPowerSource(), this.monitor, stack,
|
||||
this.getActionSource());
|
||||
if (pulled == null || pulled.getStackSize() < 1) {
|
||||
// Something went wrong
|
||||
AELog.error("Unable to pull fluid out of the ME system even though the simulation said yes ");
|
||||
return;
|
||||
}
|
||||
|
||||
// Actually fill
|
||||
final FluidVolume reallyFilled = insertable.attemptInsertion(pulled.getFluidStack(), Simulation.ACTION);
|
||||
|
||||
if (!reallyFilled.amount().equals(volumeAllowed.amount())) {
|
||||
AELog.error("Fluid item [%s] reported a different possible amount than it actually accepted.",
|
||||
held.getName());
|
||||
}
|
||||
|
||||
player.inventory.setCursorStack(container.get());
|
||||
this.updateHeld(player);
|
||||
} else if (action == InventoryAction.EMPTY_ITEM) {
|
||||
Ref<ItemStack> container = new Ref<>(held);
|
||||
FluidExtractable extractable = FluidAttributes.EXTRACTABLE.getFirstOrNull(container);
|
||||
if (extractable == null) {
|
||||
return; // Not a drainable item.
|
||||
}
|
||||
|
||||
// See how much we can drain from the item
|
||||
FluidVolume extract = extractable.attemptAnyExtraction(FluidAmount.MAX_VALUE, Simulation.SIMULATE);
|
||||
AEFluidStack aeStack = AEFluidStack.fromFluidVolume(extract, RoundingMode.DOWN);
|
||||
if (aeStack == null || aeStack.getStackSize() == 0) {
|
||||
return; // Not enough liquid in the container
|
||||
}
|
||||
|
||||
// Check if we can push into the system
|
||||
final IAEFluidStack notStorable = Platform.poweredInsert(this.getPowerSource(), this.monitor,
|
||||
aeStack, this.getActionSource(), Actionable.SIMULATE);
|
||||
|
||||
// Adjust the amount if needed
|
||||
if (notStorable != null && notStorable.getStackSize() > 0) {
|
||||
final FluidAmount toStore = aeStack.getAmount().sub(notStorable.getAmount());
|
||||
extract = extractable.attemptExtraction(new ExactFluidFilter(aeStack.getFluid()), toStore, Simulation.SIMULATE);
|
||||
|
||||
if (extract.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Actually drain
|
||||
FluidVolume drained = extractable.extract(extract.getFluidKey(), extract.amount());
|
||||
aeStack = AEFluidStack.fromFluidVolume(drained, RoundingMode.DOWN);
|
||||
if (aeStack == null) {
|
||||
// TODO WARN
|
||||
return; // I guess the extractable decided to return a different amount upon execution
|
||||
}
|
||||
|
||||
final IAEFluidStack notInserted = Platform.poweredInsert(this.getPowerSource(), this.monitor,
|
||||
aeStack, this.getActionSource());
|
||||
|
||||
if (notInserted != null && notInserted.getStackSize() > 0) {
|
||||
AELog.error("Fluid item [%s] reported a different possible amount to drain than it actually provided.",
|
||||
held.getName());
|
||||
}
|
||||
|
||||
player.inventory.setCursorStack(container.get());
|
||||
this.updateHeld(player);
|
||||
}
|
||||
}
|
||||
|
||||
protected void updatePowerStatus() {
|
||||
try {
|
||||
if (this.networkNode != null) {
|
||||
this.setPowered(this.networkNode.isActive());
|
||||
} else if (this.getPowerSource() instanceof IEnergyGrid) {
|
||||
this.setPowered(((IEnergyGrid) this.getPowerSource()).isNetworkPowered());
|
||||
} else {
|
||||
this.setPowered(
|
||||
this.getPowerSource().extractAEPower(1, Actionable.SIMULATE, PowerMultiplier.CONFIG) > 0.8);
|
||||
}
|
||||
} catch (final Exception ignore) {
|
||||
// :P
|
||||
}
|
||||
}
|
||||
|
||||
private IConfigManagerHost getGui() {
|
||||
return this.gui;
|
||||
}
|
||||
|
||||
public void setGui(@Nonnull final IConfigManagerHost gui) {
|
||||
this.gui = gui;
|
||||
}
|
||||
|
||||
public boolean isPowered() {
|
||||
return this.hasPower;
|
||||
}
|
||||
|
||||
private void setPowered(final boolean isPowered) {
|
||||
this.hasPower = isPowered;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
package appeng.fluids.container;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
|
||||
public interface IFluidSyncContainer {
|
||||
void receiveFluidSlots(final Map<Integer, IAEFluidStack> fluids);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, 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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.fluids.container.slots;
|
||||
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
|
||||
/**
|
||||
* @author yueh
|
||||
* @version rv6
|
||||
* @since rv6
|
||||
*/
|
||||
public interface IMEFluidSlot {
|
||||
IAEFluidStack getAEFluidStack();
|
||||
|
||||
default boolean shouldRenderAsFluid() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,502 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, 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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.fluids.helper;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import alexiil.mc.lib.attributes.AttributeList;
|
||||
import alexiil.mc.lib.attributes.item.FixedItemInv;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.config.Settings;
|
||||
import appeng.api.config.Upgrades;
|
||||
import appeng.api.implementations.IUpgradeableHost;
|
||||
import appeng.api.networking.GridFlags;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.energy.IEnergySource;
|
||||
import appeng.api.networking.security.IActionHost;
|
||||
import appeng.api.networking.security.IActionSource;
|
||||
import appeng.api.networking.ticking.IGridTickable;
|
||||
import appeng.api.networking.ticking.TickRateModulation;
|
||||
import appeng.api.networking.ticking.TickingRequest;
|
||||
import appeng.api.storage.IMEInventory;
|
||||
import appeng.api.storage.IMEMonitor;
|
||||
import appeng.api.storage.IStorageChannel;
|
||||
import appeng.api.storage.IStorageMonitorable;
|
||||
import appeng.api.storage.IStorageMonitorableAccessor;
|
||||
import appeng.api.storage.channels.IFluidStorageChannel;
|
||||
import appeng.api.storage.channels.IItemStorageChannel;
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.api.storage.data.IAEItemStack;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.api.util.AECableType;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.api.util.DimensionalCoord;
|
||||
import appeng.api.util.IConfigManager;
|
||||
import appeng.core.settings.TickRates;
|
||||
import appeng.fluids.util.AEFluidInventory;
|
||||
import appeng.fluids.util.IAEFluidInventory;
|
||||
import appeng.fluids.util.IAEFluidTank;
|
||||
import appeng.me.GridAccessException;
|
||||
import appeng.me.helpers.AENetworkProxy;
|
||||
import appeng.me.helpers.MachineSource;
|
||||
import appeng.me.storage.MEMonitorIFluidHandler;
|
||||
import appeng.me.storage.MEMonitorPassThrough;
|
||||
import appeng.me.storage.NullInventory;
|
||||
import appeng.util.ConfigManager;
|
||||
import appeng.util.IConfigManagerHost;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public class DualityFluidInterface
|
||||
implements IGridTickable, IStorageMonitorable, IAEFluidInventory, IUpgradeableHost, IConfigManagerHost {
|
||||
public static final int NUMBER_OF_TANKS = 6;
|
||||
public static final int TANK_CAPACITY = 1000 * 4;
|
||||
|
||||
private final ConfigManager cm = new ConfigManager(this);
|
||||
private final AENetworkProxy gridProxy;
|
||||
private final IFluidInterfaceHost iHost;
|
||||
private final IActionSource mySource;
|
||||
private final IActionSource interfaceRequestSource;
|
||||
private boolean hasConfig = false;
|
||||
private final IStorageMonitorableAccessor accessor = this::getMonitorable;
|
||||
private final AEFluidInventory tanks = new AEFluidInventory(this, NUMBER_OF_TANKS, TANK_CAPACITY);
|
||||
private final AEFluidInventory config = new AEFluidInventory(this, NUMBER_OF_TANKS);
|
||||
private final IAEFluidStack[] requireWork;
|
||||
private int isWorking = -1;
|
||||
private int priority;
|
||||
|
||||
private final MEMonitorPassThrough<IAEItemStack> items = new MEMonitorPassThrough<>(
|
||||
new NullInventory<IAEItemStack>(), AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class));
|
||||
private final MEMonitorPassThrough<IAEFluidStack> fluids = new MEMonitorPassThrough<>(
|
||||
new NullInventory<IAEFluidStack>(),
|
||||
AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class));
|
||||
|
||||
public DualityFluidInterface(final AENetworkProxy networkProxy, final IFluidInterfaceHost ih) {
|
||||
this.gridProxy = networkProxy;
|
||||
this.gridProxy.setFlags(GridFlags.REQUIRE_CHANNEL);
|
||||
this.iHost = ih;
|
||||
|
||||
this.mySource = new MachineSource(this.iHost);
|
||||
this.interfaceRequestSource = new InterfaceRequestSource(this.iHost);
|
||||
|
||||
this.fluids.setChangeSource(this.mySource);
|
||||
this.items.setChangeSource(this.mySource);
|
||||
|
||||
this.requireWork = new IAEFluidStack[NUMBER_OF_TANKS];
|
||||
for (int i = 0; i < NUMBER_OF_TANKS; ++i) {
|
||||
this.requireWork[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
public IUpgradeableHost getHost() {
|
||||
if (this.iHost instanceof IUpgradeableHost) {
|
||||
return this.iHost;
|
||||
}
|
||||
if (this.iHost instanceof IUpgradeableHost) {
|
||||
return this.iHost;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IAEStack<T>> IMEMonitor<T> getInventory(IStorageChannel<T> channel) {
|
||||
if (channel == AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class)) {
|
||||
if (this.hasConfig()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (IMEMonitor<T>) this.items;
|
||||
} else if (channel == AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class)) {
|
||||
if (this.hasConfig()) {
|
||||
return (IMEMonitor<T>) new InterfaceInventory(this);
|
||||
}
|
||||
|
||||
return (IMEMonitor<T>) this.fluids;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public IStorageMonitorable getMonitorable(final IActionSource src) {
|
||||
if (Platform.canAccess(this.gridProxy, src)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickingRequest getTickingRequest(final IGridNode node) {
|
||||
return new TickingRequest(TickRates.Interface.getMin(), TickRates.Interface.getMax(), !this.hasWorkToDo(),
|
||||
true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickRateModulation tickingRequest(final IGridNode node, final int ticksSinceLastCall) {
|
||||
if (!this.gridProxy.isActive()) {
|
||||
return TickRateModulation.SLEEP;
|
||||
}
|
||||
|
||||
final boolean couldDoWork = this.updateStorage();
|
||||
return this.hasWorkToDo() ? (couldDoWork ? TickRateModulation.URGENT : TickRateModulation.SLOWER)
|
||||
: TickRateModulation.SLEEP;
|
||||
}
|
||||
|
||||
public void notifyNeighbors() {
|
||||
if (this.gridProxy.isActive()) {
|
||||
try {
|
||||
this.gridProxy.getTick().wakeDevice(this.gridProxy.getNode());
|
||||
} catch (final GridAccessException e) {
|
||||
// :P
|
||||
}
|
||||
}
|
||||
|
||||
final BlockEntity te = this.iHost.getBlockEntity();
|
||||
if (te != null && te.getWorld() != null) {
|
||||
Platform.notifyBlocksOfNeighbors(te.getWorld(), te.getPos());
|
||||
}
|
||||
}
|
||||
|
||||
public void gridChanged() {
|
||||
try {
|
||||
this.items.setInternal(this.gridProxy.getStorage()
|
||||
.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class)));
|
||||
this.fluids.setInternal(this.gridProxy.getStorage()
|
||||
.getInventory(AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class)));
|
||||
} catch (final GridAccessException gae) {
|
||||
this.items.setInternal(new NullInventory<IAEItemStack>());
|
||||
this.fluids.setInternal(new NullInventory<IAEFluidStack>());
|
||||
}
|
||||
|
||||
this.notifyNeighbors();
|
||||
}
|
||||
|
||||
public AECableType getCableConnectionType(final AEPartLocation dir) {
|
||||
return AECableType.SMART;
|
||||
}
|
||||
|
||||
public DimensionalCoord getLocation() {
|
||||
return new DimensionalCoord(this.iHost.getBlockEntity());
|
||||
}
|
||||
|
||||
private boolean hasConfig() {
|
||||
return this.hasConfig;
|
||||
}
|
||||
|
||||
private void readConfig() {
|
||||
this.hasConfig = false;
|
||||
|
||||
for (int i = 0; i < this.config.getSlots(); i++) {
|
||||
if (this.config.getFluidInSlot(i) != null) {
|
||||
this.hasConfig = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
final boolean had = this.hasWorkToDo();
|
||||
|
||||
for (int x = 0; x < NUMBER_OF_TANKS; x++) {
|
||||
this.updatePlan(x);
|
||||
}
|
||||
|
||||
final boolean has = this.hasWorkToDo();
|
||||
|
||||
if (had != has) {
|
||||
try {
|
||||
if (has) {
|
||||
this.gridProxy.getTick().alertDevice(this.gridProxy.getNode());
|
||||
} else {
|
||||
this.gridProxy.getTick().sleepDevice(this.gridProxy.getNode());
|
||||
}
|
||||
} catch (final GridAccessException e) {
|
||||
// :P
|
||||
}
|
||||
}
|
||||
|
||||
this.notifyNeighbors();
|
||||
}
|
||||
|
||||
private boolean updateStorage() {
|
||||
boolean didSomething = false;
|
||||
for (int x = 0; x < NUMBER_OF_TANKS; x++) {
|
||||
if (this.requireWork[x] != null) {
|
||||
didSomething = this.usePlan(x) || didSomething;
|
||||
}
|
||||
}
|
||||
return didSomething;
|
||||
}
|
||||
|
||||
private boolean hasWorkToDo() {
|
||||
for (final IAEFluidStack requiredWork : this.requireWork) {
|
||||
if (requiredWork != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void updatePlan(final int slot) {
|
||||
final IAEFluidStack req = this.config.getFluidInSlot(slot);
|
||||
final IAEFluidStack stored = this.tanks.getFluidInSlot(slot);
|
||||
|
||||
if (req == null && (stored != null && stored.getStackSize() > 0)) {
|
||||
final IAEFluidStack work = stored.copy();
|
||||
this.requireWork[slot] = work.setStackSize(-work.getStackSize());
|
||||
return;
|
||||
} else if (req != null) {
|
||||
if (stored == null || stored.getStackSize() == 0) // need to add stuff!
|
||||
{
|
||||
this.requireWork[slot] = req.copy();
|
||||
this.requireWork[slot].setStackSize(TANK_CAPACITY);
|
||||
return;
|
||||
} else if (req.equals(stored)) // same type ( qty different? )!
|
||||
{
|
||||
if (stored.getStackSize() < TANK_CAPACITY) {
|
||||
this.requireWork[slot] = req.copy();
|
||||
this.requireWork[slot].setStackSize(TANK_CAPACITY - stored.getStackSize());
|
||||
return;
|
||||
}
|
||||
} else
|
||||
// Stored != null; dispose!
|
||||
{
|
||||
final IAEFluidStack work = stored.copy();
|
||||
this.requireWork[slot] = work.setStackSize(-work.getStackSize());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.requireWork[slot] = null;
|
||||
}
|
||||
|
||||
private boolean usePlan(final int slot) {
|
||||
IAEFluidStack work = this.requireWork[slot];
|
||||
this.isWorking = slot;
|
||||
|
||||
boolean changed = false;
|
||||
try {
|
||||
final IMEInventory<IAEFluidStack> dest = this.gridProxy.getStorage()
|
||||
.getInventory(AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class));
|
||||
final IEnergySource src = this.gridProxy.getEnergy();
|
||||
|
||||
if (work.getStackSize() > 0) {
|
||||
// make sure strange things didn't happen...
|
||||
if (this.tanks.fill(slot, work.getFluidStack(), false) != work.getStackSize()) {
|
||||
changed = true;
|
||||
} else {
|
||||
final IAEFluidStack acquired = Platform.poweredExtraction(src, dest, work,
|
||||
this.interfaceRequestSource);
|
||||
if (acquired != null) {
|
||||
changed = true;
|
||||
final int filled = this.tanks.fill(slot, acquired.getFluidStack(), true);
|
||||
if (filled != acquired.getStackSize()) {
|
||||
throw new IllegalStateException("bad attempt at managing tanks. ( fill )");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (work.getStackSize() < 0) {
|
||||
IAEFluidStack toStore = work.copy();
|
||||
toStore.setStackSize(-toStore.getStackSize());
|
||||
|
||||
// make sure strange things didn't happen...
|
||||
final FluidVolume canExtract = this.tanks.drain(slot, toStore.getFluidStack(), false);
|
||||
if (canExtract.isEmpty() || canExtract.getAmount() != toStore.getStackSize()) {
|
||||
changed = true;
|
||||
} else {
|
||||
IAEFluidStack notStored = Platform.poweredInsert(src, dest, toStore, this.interfaceRequestSource);
|
||||
toStore.setStackSize(toStore.getStackSize() - (notStored == null ? 0 : notStored.getStackSize()));
|
||||
|
||||
if (toStore.getStackSize() > 0) {
|
||||
// extract items!
|
||||
changed = true;
|
||||
final FluidVolume removed = this.tanks.drain(slot, toStore.getFluidStack(), true);
|
||||
if (removed.isEmpty() || toStore.getStackSize() != removed.getAmount()) {
|
||||
throw new IllegalStateException("bad attempt at managing tanks. ( drain )");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final GridAccessException e) {
|
||||
// :P
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
this.updatePlan(slot);
|
||||
}
|
||||
|
||||
this.isWorking = -1;
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFluidInventoryChanged(final IAEFluidTank inventory, final int slot) {
|
||||
if (this.isWorking == slot) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (inventory == this.config) {
|
||||
this.readConfig();
|
||||
} else if (inventory == this.tanks) {
|
||||
this.saveChanges();
|
||||
|
||||
final boolean had = this.hasWorkToDo();
|
||||
|
||||
this.updatePlan(slot);
|
||||
|
||||
final boolean now = this.hasWorkToDo();
|
||||
|
||||
if (had != now) {
|
||||
try {
|
||||
if (now) {
|
||||
this.gridProxy.getTick().alertDevice(this.gridProxy.getNode());
|
||||
} else {
|
||||
this.gridProxy.getTick().sleepDevice(this.gridProxy.getNode());
|
||||
}
|
||||
} catch (final GridAccessException e) {
|
||||
// :P
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getPriority() {
|
||||
return this.priority;
|
||||
}
|
||||
|
||||
public void setPriority(final int newValue) {
|
||||
this.priority = newValue;
|
||||
}
|
||||
|
||||
public void writeToNBT(final CompoundTag data) {
|
||||
data.putInt("priority", this.priority);
|
||||
this.tanks.writeToNBT(data, "storage");
|
||||
this.config.writeToNBT(data, "config");
|
||||
}
|
||||
|
||||
public void readFromNBT(final CompoundTag data) {
|
||||
this.config.readFromNBT(data, "config");
|
||||
this.tanks.readFromNBT(data, "storage");
|
||||
this.priority = data.getInt("priority");
|
||||
this.readConfig();
|
||||
}
|
||||
|
||||
public IAEFluidTank getConfig() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
public IAEFluidTank getTanks() {
|
||||
return this.tanks;
|
||||
}
|
||||
|
||||
private class InterfaceRequestSource extends MachineSource {
|
||||
private final InterfaceRequestContext context;
|
||||
|
||||
InterfaceRequestSource(IActionHost v) {
|
||||
super(v);
|
||||
this.context = new InterfaceRequestContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Optional<T> context(Class<T> key) {
|
||||
if (key == InterfaceRequestContext.class) {
|
||||
return (Optional<T>) Optional.of(this.context);
|
||||
}
|
||||
|
||||
return super.context(key);
|
||||
}
|
||||
}
|
||||
|
||||
private class InterfaceRequestContext implements Comparable<Integer> {
|
||||
@Override
|
||||
public int compareTo(Integer o) {
|
||||
return Integer.compare(DualityFluidInterface.this.priority, o);
|
||||
}
|
||||
}
|
||||
|
||||
private class InterfaceInventory extends MEMonitorIFluidHandler {
|
||||
|
||||
InterfaceInventory(final DualityFluidInterface tileInterface) {
|
||||
super(tileInterface.tanks.getGroupedInv());
|
||||
this.setActionSource(new MachineSource(tileInterface.iHost));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEFluidStack injectItems(final IAEFluidStack input, final Actionable type, final IActionSource src) {
|
||||
final Optional<InterfaceRequestContext> context = src.context(InterfaceRequestContext.class);
|
||||
final boolean isInterface = context.isPresent();
|
||||
|
||||
if (isInterface) {
|
||||
return input;
|
||||
}
|
||||
|
||||
return super.injectItems(input, type, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEFluidStack extractItems(final IAEFluidStack request, final Actionable type, final IActionSource src) {
|
||||
final Optional<InterfaceRequestContext> context = src.context(InterfaceRequestContext.class);
|
||||
final boolean hasLowerOrEqualPriority = context
|
||||
.map(c -> c.compareTo(DualityFluidInterface.this.priority) <= 0).orElse(false);
|
||||
|
||||
if (hasLowerOrEqualPriority) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return super.extractItems(request, type, src);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveChanges() {
|
||||
this.iHost.saveChanges();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IConfigManager getConfigManager() {
|
||||
return this.cm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FixedItemInv getInventoryByName(String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInstalledUpgrades(Upgrades u) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockEntity getTile() {
|
||||
return (BlockEntity) (this.iHost instanceof BlockEntity ? this.iHost : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSetting(IConfigManager manager, Settings settingName, Enum<?> newValue) {
|
||||
}
|
||||
|
||||
public void addAllAttributes(AttributeList<?> to) {
|
||||
to.offer(this.tanks);
|
||||
to.offer(this.accessor);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, 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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.fluids.helper;
|
||||
|
||||
import alexiil.mc.lib.attributes.Simulation;
|
||||
import alexiil.mc.lib.attributes.fluid.FluidAttributes;
|
||||
import alexiil.mc.lib.attributes.fluid.FluidExtractable;
|
||||
import alexiil.mc.lib.attributes.fluid.amount.FluidAmount;
|
||||
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
|
||||
import alexiil.mc.lib.attributes.item.filter.ItemFilter;
|
||||
import appeng.api.AEApi;
|
||||
import appeng.fluids.items.FluidDummyItem;
|
||||
import appeng.items.contents.CellConfig;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
/**
|
||||
* @author DrummerMC
|
||||
* @version rv6 - 2018-01-22
|
||||
* @since rv6 2018-01-22
|
||||
*/
|
||||
public class FluidCellConfig extends CellConfig {
|
||||
public FluidCellConfig(ItemStack is) {
|
||||
super(is);
|
||||
}
|
||||
|
||||
private static ItemStack tryConvertToFluidDummy(ItemStack stack) {
|
||||
if (stack.isEmpty() || stack.getItem() instanceof FluidDummyItem) {
|
||||
return stack;
|
||||
}
|
||||
|
||||
// Try to auto-convert any fluid-containing item into a dummy item before insertion
|
||||
FluidExtractable fluidExtractable = FluidAttributes.EXTRACTABLE.getFirstOrNull(stack);
|
||||
if (fluidExtractable == null) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
FluidVolume fluid = fluidExtractable.attemptAnyExtraction(FluidAmount.MAX_VALUE, Simulation.SIMULATE);
|
||||
if (fluid.isEmpty()) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
fluid = fluid.withAmount(FluidAmount.BUCKET);
|
||||
|
||||
ItemStack is = AEApi.instance().definitions().items().dummyFluidItem().stack(1);
|
||||
FluidDummyItem item = (FluidDummyItem) is.getItem();
|
||||
item.setFluidStack(is, fluid);
|
||||
return is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack attemptInsertion(ItemStack stack, Simulation simulation) {
|
||||
stack = tryConvertToFluidDummy(stack);
|
||||
return super.attemptInsertion(stack, simulation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setInvStack(int slot, ItemStack to, Simulation simulation) {
|
||||
to = tryConvertToFluidDummy(to);
|
||||
return super.setInvStack(slot, to, simulation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemFilter getFilterForSlot(int slot) {
|
||||
return stack -> !tryConvertToFluidDummy(stack).isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemValidForSlot(int slot, ItemStack stack) {
|
||||
return !tryConvertToFluidDummy(stack).isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
|
||||
package appeng.fluids.helper;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import net.minecraft.screen.ScreenHandlerListener;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.core.sync.network.NetworkHandler;
|
||||
import appeng.core.sync.packets.FluidSlotPacket;
|
||||
import appeng.fluids.util.AEFluidInventory;
|
||||
import appeng.fluids.util.IAEFluidTank;
|
||||
|
||||
public class FluidSyncHelper {
|
||||
private final IAEFluidTank inv;
|
||||
private final IAEFluidTank cache;
|
||||
private final int idOffset;
|
||||
|
||||
public FluidSyncHelper(final IAEFluidTank inv, final int idOffset) {
|
||||
this.inv = inv;
|
||||
this.cache = new AEFluidInventory(null, inv.getSlots());
|
||||
this.idOffset = idOffset;
|
||||
}
|
||||
|
||||
public void sendFull(final Iterable<ScreenHandlerListener> listeners) {
|
||||
this.sendDiffMap(this.createDiffMap(true), listeners);
|
||||
}
|
||||
|
||||
public void sendDiff(final Iterable<ScreenHandlerListener> listeners) {
|
||||
this.sendDiffMap(this.createDiffMap(false), listeners);
|
||||
}
|
||||
|
||||
public void readPacket(final Map<Integer, IAEFluidStack> data) {
|
||||
for (int i = 0; i < this.inv.getSlots(); ++i) {
|
||||
if (data.containsKey(i + this.idOffset)) {
|
||||
this.inv.setFluidInSlot(i, data.get(i + this.idOffset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendDiffMap(final Map<Integer, IAEFluidStack> data, final Iterable<ScreenHandlerListener> listeners) {
|
||||
if (data.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final ScreenHandlerListener l : listeners) {
|
||||
if (l instanceof ServerPlayerEntity) {
|
||||
NetworkHandler.instance().sendTo(new FluidSlotPacket(data), (ServerPlayerEntity) l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<Integer, IAEFluidStack> createDiffMap(final boolean full) {
|
||||
final Map<Integer, IAEFluidStack> ret = new HashMap<>();
|
||||
for (int i = 0; i < this.inv.getSlots(); ++i) {
|
||||
if (full || !this.equalsSlot(i)) {
|
||||
ret.put(i + this.idOffset, this.inv.getFluidInSlot(i));
|
||||
}
|
||||
if (!full) {
|
||||
this.cache.setFluidInSlot(i, this.inv.getFluidInSlot(i));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private final boolean equalsSlot(int slot) {
|
||||
final IAEFluidStack stackA = this.inv.getFluidInSlot(slot);
|
||||
final IAEFluidStack stackB = this.cache.getFluidInSlot(slot);
|
||||
|
||||
if (!Objects.equals(stackA, stackB)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return stackA == null || stackA.getStackSize() == stackB.getStackSize();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package appeng.fluids.helper;
|
||||
|
||||
import alexiil.mc.lib.attributes.fluid.GroupedFluidInv;
|
||||
import alexiil.mc.lib.attributes.fluid.amount.FluidAmount;
|
||||
import alexiil.mc.lib.attributes.fluid.volume.FluidKey;
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.fluids.util.AEFluidStack;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
import java.util.*;
|
||||
|
||||
public class GroupedFluidInvCache {
|
||||
|
||||
private final GroupedFluidInv inventory;
|
||||
|
||||
private final Map<FluidKey, IAEFluidStack> memory = new HashMap<>();
|
||||
|
||||
public GroupedFluidInvCache(GroupedFluidInv inventory) {
|
||||
this.inventory = inventory;
|
||||
}
|
||||
|
||||
public IItemList<IAEFluidStack> getAvailable(IItemList<IAEFluidStack> out) {
|
||||
for (Map.Entry<FluidKey, IAEFluidStack> entry : memory.entrySet()) {
|
||||
out.add(entry.getValue());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
public List<IAEFluidStack> detectChanges() {
|
||||
final List<IAEFluidStack> changes = new ArrayList<>();
|
||||
|
||||
Set<FluidKey> storedFluids = inventory.getStoredFluids();
|
||||
for (FluidKey storedFluid : storedFluids) {
|
||||
IAEFluidStack old = this.memory.get(storedFluid);
|
||||
|
||||
FluidAmount newAmount = inventory.getAmount_F(storedFluid);
|
||||
FluidAmount oldAmount = old == null ? FluidAmount.ZERO : old.getAmount();
|
||||
|
||||
if (!newAmount.equals(oldAmount)) {
|
||||
AEFluidStack newStack = AEFluidStack.fromFluidVolume(storedFluid.withAmount(newAmount), RoundingMode.DOWN);
|
||||
|
||||
if (old != null) {
|
||||
old = old.copy();
|
||||
old.setStackSize(-old.getStackSize());
|
||||
changes.add(old);
|
||||
}
|
||||
|
||||
if (newStack != null) {
|
||||
this.memory.put(storedFluid, newStack);
|
||||
changes.add(newStack);
|
||||
} else {
|
||||
this.memory.remove(storedFluid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// detect dropped items; should fix non IISided Inventory Changes.
|
||||
Set<FluidKey> toRemove = null;
|
||||
for (final Map.Entry<FluidKey, IAEFluidStack> entry : memory.entrySet()) {
|
||||
if (storedFluids.contains(entry.getKey())) {
|
||||
continue; // Still stored
|
||||
}
|
||||
|
||||
if (toRemove == null) {
|
||||
toRemove = new HashSet<>();
|
||||
}
|
||||
toRemove.add(entry.getKey());
|
||||
|
||||
final IAEFluidStack a = entry.getValue().copy();
|
||||
a.setStackSize(-a.getStackSize());
|
||||
changes.add(a);
|
||||
}
|
||||
// Now clean up if any removed entries were found
|
||||
if (toRemove != null) {
|
||||
for (FluidKey fluidKey : toRemove) {
|
||||
memory.remove(fluidKey);
|
||||
}
|
||||
}
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, 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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.fluids.helper;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
import appeng.api.implementations.IUpgradeableHost;
|
||||
import appeng.api.networking.security.IActionHost;
|
||||
import appeng.me.helpers.IGridProxyable;
|
||||
|
||||
public interface IFluidInterfaceHost extends IActionHost, IGridProxyable, IUpgradeableHost {
|
||||
DualityFluidInterface getDualityFluidInterface();
|
||||
|
||||
EnumSet<Direction> getTargets();
|
||||
|
||||
BlockEntity getBlockEntity();
|
||||
|
||||
void saveChanges();
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, 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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.fluids.items;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import alexiil.mc.lib.attributes.item.FixedItemInv;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.storage.IStorageChannel;
|
||||
import appeng.api.storage.channels.IFluidStorageChannel;
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.fluids.helper.FluidCellConfig;
|
||||
import appeng.items.materials.MaterialType;
|
||||
import appeng.items.storage.AbstractStorageCell;
|
||||
import appeng.util.InventoryAdaptor;
|
||||
|
||||
/**
|
||||
* @author DrummerMC
|
||||
* @version rv6 - 2018-01-17
|
||||
* @since rv6 2018-01-17
|
||||
*/
|
||||
public final class BasicFluidStorageCell extends AbstractStorageCell<IAEFluidStack> {
|
||||
|
||||
private final int perType;
|
||||
private final double idleDrain;
|
||||
|
||||
public BasicFluidStorageCell(Settings props, final MaterialType whichCell, final int kilobytes) {
|
||||
super(props, whichCell, kilobytes);
|
||||
switch (whichCell) {
|
||||
case FLUID_1K_CELL_COMPONENT:
|
||||
this.idleDrain = 0.5;
|
||||
this.perType = 8;
|
||||
break;
|
||||
case FLUID_4K_CELL_COMPONENT:
|
||||
this.idleDrain = 1.0;
|
||||
this.perType = 32;
|
||||
break;
|
||||
case FLUID_16K_CELL_COMPONENT:
|
||||
this.idleDrain = 1.5;
|
||||
this.perType = 128;
|
||||
break;
|
||||
case FLUID_64K_CELL_COMPONENT:
|
||||
this.idleDrain = 2.0;
|
||||
this.perType = 512;
|
||||
break;
|
||||
default:
|
||||
this.idleDrain = 0.0;
|
||||
this.perType = 8;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBytesPerType(ItemStack cellItem) {
|
||||
return this.perType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getIdleDrain() {
|
||||
return this.idleDrain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IStorageChannel<IAEFluidStack> getChannel() {
|
||||
return AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTotalTypes(final ItemStack cellItem) {
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FixedItemInv getConfigInventory(final ItemStack is) {
|
||||
return new FluidCellConfig(is);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dropEmptyStorageCellCase(final InventoryAdaptor ia, final PlayerEntity player) {
|
||||
AEApi.instance().definitions().materials().emptyStorageCell().maybeStack(1).ifPresent(is -> {
|
||||
final ItemStack extraA = ia.addItems(is);
|
||||
if (!extraA.isEmpty()) {
|
||||
player.dropItem(extraA, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package appeng.fluids.items;
|
||||
|
||||
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.color.item.ItemColorProvider;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class FluidDummyItemColor implements ItemColorProvider {
|
||||
|
||||
@Override
|
||||
public int getColor(ItemStack stack, int tintIndex) {
|
||||
|
||||
Item item = stack.getItem();
|
||||
if (!(item instanceof FluidDummyItem)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
FluidDummyItem fluidItem = (FluidDummyItem) item;
|
||||
FluidVolume fluidStack = fluidItem.getFluidStack(stack);
|
||||
|
||||
return fluidStack.getRenderColor();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,321 @@
|
||||
|
||||
package appeng.fluids.parts;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import alexiil.mc.lib.attributes.fluid.FluidAttributes;
|
||||
import alexiil.mc.lib.attributes.fluid.amount.FluidAmount;
|
||||
import alexiil.mc.lib.attributes.fluid.volume.FluidKeys;
|
||||
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.FluidDrainable;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.fluid.Fluid;
|
||||
import net.minecraft.fluid.Fluids;
|
||||
import net.minecraft.fluid.FluidState;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tag.FluidTags;
|
||||
import net.minecraft.tag.Tag;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.BlockView;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.config.PowerMultiplier;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.energy.IEnergyGrid;
|
||||
import appeng.api.networking.events.MENetworkChannelsChanged;
|
||||
import appeng.api.networking.events.MENetworkEventSubscribe;
|
||||
import appeng.api.networking.events.MENetworkPowerStatusChange;
|
||||
import appeng.api.networking.security.IActionSource;
|
||||
import appeng.api.networking.storage.IStorageGrid;
|
||||
import appeng.api.networking.ticking.IGridTickable;
|
||||
import appeng.api.networking.ticking.TickRateModulation;
|
||||
import appeng.api.networking.ticking.TickingRequest;
|
||||
import appeng.api.parts.IPart;
|
||||
import appeng.api.parts.IPartCollisionHelper;
|
||||
import appeng.api.parts.IPartHost;
|
||||
import appeng.api.parts.IPartModel;
|
||||
import appeng.api.storage.IMEInventory;
|
||||
import appeng.api.storage.channels.IFluidStorageChannel;
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.api.util.AECableType;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.core.settings.TickRates;
|
||||
import appeng.core.sync.packets.BlockTransitionEffectPacket;
|
||||
import appeng.fluids.util.AEFluidStack;
|
||||
import appeng.items.parts.PartModels;
|
||||
import appeng.me.GridAccessException;
|
||||
import appeng.me.helpers.MachineSource;
|
||||
import appeng.parts.BasicStatePart;
|
||||
import appeng.parts.automation.PlaneConnections;
|
||||
import appeng.parts.automation.PlaneModels;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public class FluidAnnihilationPlanePart extends BasicStatePart implements IGridTickable {
|
||||
|
||||
public static final Identifier TAG_BLACKLIST = new Identifier(AppEng.MOD_ID,
|
||||
"blacklisted/fluid_annihilation_plane");
|
||||
|
||||
private static final PlaneModels MODELS = new PlaneModels("part/fluid_annihilation_plane",
|
||||
"part/fluid_annihilation_plane_on");
|
||||
|
||||
@PartModels
|
||||
public static List<IPartModel> getModels() {
|
||||
return MODELS.getModels();
|
||||
}
|
||||
|
||||
private final IActionSource mySrc = new MachineSource(this);
|
||||
|
||||
public FluidAnnihilationPlanePart(final ItemStack is) {
|
||||
super(is);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getBoxes(final IPartCollisionHelper bch) {
|
||||
int minX = 1;
|
||||
int minY = 1;
|
||||
int maxX = 15;
|
||||
int maxY = 15;
|
||||
|
||||
final IPartHost host = this.getHost();
|
||||
if (host != null) {
|
||||
final BlockEntity te = host.getTile();
|
||||
|
||||
final BlockPos pos = te.getPos();
|
||||
|
||||
final Direction e = bch.getWorldX();
|
||||
final Direction u = bch.getWorldY();
|
||||
|
||||
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(e.getOpposite())), this.getSide())) {
|
||||
minX = 0;
|
||||
}
|
||||
|
||||
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(e)), this.getSide())) {
|
||||
maxX = 16;
|
||||
}
|
||||
|
||||
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(u.getOpposite())), this.getSide())) {
|
||||
minY = 0;
|
||||
}
|
||||
|
||||
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(e)), this.getSide())) {
|
||||
maxY = 16;
|
||||
}
|
||||
}
|
||||
|
||||
bch.addBox(5, 5, 14, 11, 11, 15);
|
||||
bch.addBox(minX, minY, 15, maxX, maxY, 16);
|
||||
}
|
||||
|
||||
public PlaneConnections getConnections() {
|
||||
|
||||
final Direction facingRight, facingUp;
|
||||
AEPartLocation location = this.getSide();
|
||||
switch (location) {
|
||||
case UP:
|
||||
facingRight = Direction.EAST;
|
||||
facingUp = Direction.NORTH;
|
||||
break;
|
||||
case DOWN:
|
||||
facingRight = Direction.WEST;
|
||||
facingUp = Direction.NORTH;
|
||||
break;
|
||||
case NORTH:
|
||||
facingRight = Direction.WEST;
|
||||
facingUp = Direction.UP;
|
||||
break;
|
||||
case SOUTH:
|
||||
facingRight = Direction.EAST;
|
||||
facingUp = Direction.UP;
|
||||
break;
|
||||
case WEST:
|
||||
facingRight = Direction.SOUTH;
|
||||
facingUp = Direction.UP;
|
||||
break;
|
||||
case EAST:
|
||||
facingRight = Direction.NORTH;
|
||||
facingUp = Direction.UP;
|
||||
break;
|
||||
default:
|
||||
case INTERNAL:
|
||||
return PlaneConnections.of(false, false, false, false);
|
||||
}
|
||||
|
||||
boolean left = false, right = false, down = false, up = false;
|
||||
|
||||
final IPartHost host = this.getHost();
|
||||
if (host != null) {
|
||||
final BlockEntity te = host.getTile();
|
||||
|
||||
final BlockPos pos = te.getPos();
|
||||
|
||||
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(facingRight.getOpposite())),
|
||||
this.getSide())) {
|
||||
left = true;
|
||||
}
|
||||
|
||||
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(facingRight)), this.getSide())) {
|
||||
right = true;
|
||||
}
|
||||
|
||||
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(facingUp.getOpposite())),
|
||||
this.getSide())) {
|
||||
down = true;
|
||||
}
|
||||
|
||||
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(facingUp)), this.getSide())) {
|
||||
up = true;
|
||||
}
|
||||
}
|
||||
|
||||
return PlaneConnections.of(up, right, down, left);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onneighborUpdate(BlockView w, BlockPos pos, BlockPos neighbor) {
|
||||
if (pos.offset(this.getSide().getFacing()).equals(neighbor)) {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCableConnectionLength(AECableType cable) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
private boolean isAnnihilationPlane(final BlockEntity blockTileEntity, final AEPartLocation side) {
|
||||
if (blockTileEntity instanceof IPartHost) {
|
||||
final IPart p = ((IPartHost) blockTileEntity).getPart(side);
|
||||
return p != null && p.getClass() == this.getClass();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void refresh() {
|
||||
try {
|
||||
this.getProxy().getTick().alertDevice(this.getProxy().getNode());
|
||||
} catch (final GridAccessException e) {
|
||||
// :P
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@MENetworkEventSubscribe
|
||||
public void chanRender(final MENetworkChannelsChanged c) {
|
||||
this.refresh();
|
||||
this.getHost().markForUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
@MENetworkEventSubscribe
|
||||
public void powerRender(final MENetworkPowerStatusChange c) {
|
||||
this.refresh();
|
||||
this.getHost().markForUpdate();
|
||||
}
|
||||
|
||||
private TickRateModulation tryDrainFluid() {
|
||||
if (!this.getProxy().isActive()) {
|
||||
return TickRateModulation.SLEEP;
|
||||
}
|
||||
|
||||
final BlockEntity te = this.getTile();
|
||||
final World w = te.getWorld();
|
||||
final BlockPos pos = te.getPos().offset(this.getSide().getFacing());
|
||||
|
||||
BlockState blockstate = w.getBlockState(pos);
|
||||
if (blockstate.getBlock() instanceof FluidDrainable) {
|
||||
FluidState fluidState = blockstate.getFluidState();
|
||||
|
||||
Fluid fluid = fluidState.getFluid();
|
||||
if (isFluidBlacklisted(fluid)) {
|
||||
return TickRateModulation.SLEEP;
|
||||
}
|
||||
|
||||
if (fluid != Fluids.EMPTY && fluidState.isStill()) {
|
||||
// Attempt to store the fluid in the network
|
||||
final IAEFluidStack blockFluid = AEFluidStack
|
||||
.fromFluidVolume(FluidKeys.get(fluid).withAmount(FluidAmount.ONE), RoundingMode.DOWN);
|
||||
if (this.storeFluid(blockFluid, false)) {
|
||||
// If that would succeed, actually slurp up the liquid as if we were using a
|
||||
// bucket
|
||||
// This _MIGHT_ change the liquid, and if it does, and we dont have enough
|
||||
// space, tough luck. you loose the source block.
|
||||
fluid = ((FluidDrainable) blockstate.getBlock()).tryDrainFluid(w, pos, blockstate);
|
||||
this.storeFluid(AEFluidStack.fromFluidVolume(FluidKeys.get(fluid).withAmount(FluidAmount.ONE), RoundingMode.DOWN),
|
||||
true);
|
||||
|
||||
AppEng.instance().sendToAllNearExcept(null, pos.getX(), pos.getY(), pos.getZ(), 64, w,
|
||||
new BlockTransitionEffectPacket(pos, blockstate, this.getSide().getOpposite(),
|
||||
BlockTransitionEffectPacket.SoundMode.FLUID));
|
||||
|
||||
return TickRateModulation.URGENT;
|
||||
}
|
||||
return TickRateModulation.IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
// nothing to do here :)
|
||||
return TickRateModulation.SLEEP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickingRequest getTickingRequest(final IGridNode node) {
|
||||
return new TickingRequest(TickRates.AnnihilationPlane.getMin(), TickRates.AnnihilationPlane.getMax(), false,
|
||||
true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickRateModulation tickingRequest(final IGridNode node, final int ticksSinceLastCall) {
|
||||
return this.tryDrainFluid();
|
||||
}
|
||||
|
||||
private boolean storeFluid(IAEFluidStack stack, boolean modulate) {
|
||||
try {
|
||||
final IStorageGrid storage = this.getProxy().getStorage();
|
||||
final IMEInventory<IAEFluidStack> inv = storage
|
||||
.getInventory(AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class));
|
||||
|
||||
if (modulate) {
|
||||
final IEnergyGrid energy = this.getProxy().getEnergy();
|
||||
return Platform.poweredInsert(energy, inv, stack, this.mySrc) == null;
|
||||
} else {
|
||||
final float requiredPower = stack.getStackSize() / Math.min(1.0f, stack.getChannel().transferFactor());
|
||||
final IEnergyGrid energy = this.getProxy().getEnergy();
|
||||
|
||||
if (energy.extractAEPower(requiredPower, Actionable.SIMULATE, PowerMultiplier.CONFIG) < requiredPower) {
|
||||
return false;
|
||||
}
|
||||
final IAEFluidStack leftOver = inv.injectItems(stack, Actionable.SIMULATE, this.mySrc);
|
||||
return leftOver == null || leftOver.getStackSize() == 0;
|
||||
}
|
||||
} catch (final GridAccessException e) {
|
||||
// :P
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPartModel getStaticModels() {
|
||||
return MODELS.getModel(this.isPowered(), this.isActive());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Object getModelData() {
|
||||
return getConnections();
|
||||
}
|
||||
|
||||
private boolean isFluidBlacklisted(Fluid fluid) {
|
||||
Tag<Fluid> tag = FluidTags.getContainer().getOrCreate(TAG_BLACKLIST);
|
||||
return fluid.isIn(tag);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, 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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.fluids.parts;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import alexiil.mc.lib.attributes.Simulation;
|
||||
import alexiil.mc.lib.attributes.fluid.FluidAttributes;
|
||||
import alexiil.mc.lib.attributes.fluid.FluidInsertable;
|
||||
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
|
||||
import appeng.attributes.MEAttributes;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.config.FuzzyMode;
|
||||
import appeng.api.config.RedstoneMode;
|
||||
import appeng.api.config.SchedulingMode;
|
||||
import appeng.api.config.Settings;
|
||||
import appeng.api.config.YesNo;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.security.IActionSource;
|
||||
import appeng.api.networking.ticking.TickRateModulation;
|
||||
import appeng.api.networking.ticking.TickingRequest;
|
||||
import appeng.api.parts.IPartCollisionHelper;
|
||||
import appeng.api.parts.IPartModel;
|
||||
import appeng.api.storage.IMEMonitor;
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.core.settings.TickRates;
|
||||
import appeng.items.parts.PartModels;
|
||||
import appeng.me.GridAccessException;
|
||||
import appeng.me.helpers.MachineSource;
|
||||
import appeng.parts.PartModel;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
|
||||
/**
|
||||
* @author BrockWS
|
||||
* @version rv6 - 30/04/2018
|
||||
* @since rv6 30/04/2018
|
||||
*/
|
||||
public class FluidExportBusPart extends SharedFluidBusPart {
|
||||
public static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "part/fluid_export_bus_base");
|
||||
@PartModels
|
||||
public static final IPartModel MODELS_OFF = new PartModel(MODEL_BASE,
|
||||
new Identifier(AppEng.MOD_ID, "part/fluid_export_bus_off"));
|
||||
@PartModels
|
||||
public static final IPartModel MODELS_ON = new PartModel(MODEL_BASE,
|
||||
new Identifier(AppEng.MOD_ID, "part/fluid_export_bus_on"));
|
||||
@PartModels
|
||||
public static final IPartModel MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE,
|
||||
new Identifier(AppEng.MOD_ID, "part/fluid_export_bus_has_channel"));
|
||||
|
||||
private final IActionSource source;
|
||||
|
||||
public FluidExportBusPart(ItemStack is) {
|
||||
super(is);
|
||||
this.getConfigManager().registerSetting(Settings.REDSTONE_CONTROLLED, RedstoneMode.IGNORE);
|
||||
this.getConfigManager().registerSetting(Settings.FUZZY_MODE, FuzzyMode.IGNORE_ALL);
|
||||
this.getConfigManager().registerSetting(Settings.CRAFT_ONLY, YesNo.NO);
|
||||
this.getConfigManager().registerSetting(Settings.SCHEDULING_MODE, SchedulingMode.DEFAULT);
|
||||
this.source = new MachineSource(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickingRequest getTickingRequest(IGridNode node) {
|
||||
return new TickingRequest(TickRates.FluidExportBus.getMin(), TickRates.FluidExportBus.getMax(),
|
||||
this.isSleeping(), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickRateModulation tickingRequest(IGridNode node, int ticksSinceLastCall) {
|
||||
return this.canDoBusWork() ? this.doBusWork() : TickRateModulation.IDLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canDoBusWork() {
|
||||
return this.getProxy().isActive();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TickRateModulation doBusWork() {
|
||||
if (!this.canDoBusWork()) {
|
||||
return TickRateModulation.IDLE;
|
||||
}
|
||||
|
||||
FluidInsertable insertable = MEAttributes.getAttributeInFrontOfPart(FluidAttributes.INSERTABLE, this);
|
||||
|
||||
if (insertable != null) {
|
||||
try {
|
||||
final IMEMonitor<IAEFluidStack> inv = this.getProxy().getStorage().getInventory(this.getChannel());
|
||||
|
||||
for (int i = 0; i < this.getConfig().getSlots(); i++) {
|
||||
IAEFluidStack fluid = this.getConfig().getFluidInSlot(i);
|
||||
if (fluid != null) {
|
||||
final IAEFluidStack toExtract = fluid.copy();
|
||||
|
||||
toExtract.setStackSize(this.calculateAmountToSend());
|
||||
|
||||
final IAEFluidStack out = inv.extractItems(toExtract, Actionable.SIMULATE, this.source);
|
||||
|
||||
if (out != null) {
|
||||
FluidVolume toInsert = out.getFluidStack();
|
||||
FluidVolume remainder = insertable.attemptInsertion(toInsert, Simulation.ACTION);
|
||||
|
||||
if (remainder.getAmount_F().isLessThan(toInsert.getAmount_F())) {
|
||||
// This will loose some liquid if the target accepts 1/1001'th bucket of fluid,
|
||||
// we'll deduct 1/1000th from storage.
|
||||
long remainderMillibuckets = remainder.getAmount_F().asInt(1000, RoundingMode.DOWN);
|
||||
|
||||
toExtract.setStackSize(remainderMillibuckets);
|
||||
inv.extractItems(toExtract, Actionable.MODULATE, this.source);
|
||||
|
||||
return TickRateModulation.FASTER;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TickRateModulation.SLOWER;
|
||||
} catch (GridAccessException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
return TickRateModulation.SLEEP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getBoxes(final IPartCollisionHelper bch) {
|
||||
bch.addBox(4, 4, 12, 12, 12, 14);
|
||||
bch.addBox(5, 5, 14, 11, 11, 15);
|
||||
bch.addBox(6, 6, 15, 10, 10, 16);
|
||||
bch.addBox(6, 6, 11, 10, 10, 12);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RedstoneMode getRSMode() {
|
||||
return (RedstoneMode) this.getConfigManager().getSetting(Settings.REDSTONE_CONTROLLED);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public IPartModel getStaticModels() {
|
||||
if (this.isActive() && this.isPowered()) {
|
||||
return MODELS_HAS_CHANNEL;
|
||||
} else if (this.isPowered()) {
|
||||
return MODELS_ON;
|
||||
} else {
|
||||
return MODELS_OFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
|
||||
package appeng.fluids.parts;
|
||||
|
||||
import alexiil.mc.lib.attributes.Simulation;
|
||||
import alexiil.mc.lib.attributes.fluid.amount.FluidAmount;
|
||||
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.config.AccessRestriction;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.config.IncludeExclude;
|
||||
import appeng.api.config.Upgrades;
|
||||
import appeng.api.networking.events.MENetworkCellArrayUpdate;
|
||||
import appeng.api.networking.events.MENetworkChannelsChanged;
|
||||
import appeng.api.networking.events.MENetworkEventSubscribe;
|
||||
import appeng.api.networking.events.MENetworkPowerStatusChange;
|
||||
import appeng.api.networking.security.IActionSource;
|
||||
import appeng.api.parts.IPartModel;
|
||||
import appeng.api.storage.IMEInventoryHandler;
|
||||
import appeng.api.storage.IStorageChannel;
|
||||
import appeng.api.storage.channels.IFluidStorageChannel;
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.container.ContainerLocator;
|
||||
import appeng.container.ContainerOpener;
|
||||
import appeng.fluids.container.FluidFormationPlaneContainer;
|
||||
import appeng.fluids.util.AEFluidInventory;
|
||||
import appeng.fluids.util.AEFluidStack;
|
||||
import appeng.fluids.util.IAEFluidInventory;
|
||||
import appeng.fluids.util.IAEFluidTank;
|
||||
import appeng.items.parts.PartModels;
|
||||
import appeng.me.GridAccessException;
|
||||
import appeng.me.storage.MEInventoryHandler;
|
||||
import appeng.parts.automation.AbstractFormationPlanePart;
|
||||
import appeng.parts.automation.PlaneModels;
|
||||
import appeng.util.Platform;
|
||||
import appeng.util.prioritylist.PrecisePriorityList;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.FluidBlock;
|
||||
import net.minecraft.block.FluidFillable;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.fluid.Fluid;
|
||||
import net.minecraft.fluid.FluidState;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.screen.ScreenHandlerType;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldAccess;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class FluidFormationPlanePart extends AbstractFormationPlanePart<IAEFluidStack> implements IAEFluidInventory {
|
||||
private static final PlaneModels MODELS = new PlaneModels("part/fluid_formation_plane",
|
||||
"part/fluid_formation_plane_on");
|
||||
|
||||
@PartModels
|
||||
public static List<IPartModel> getModels() {
|
||||
return MODELS.getModels();
|
||||
}
|
||||
|
||||
private final MEInventoryHandler<IAEFluidStack> myHandler = new MEInventoryHandler<>(this,
|
||||
AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class));
|
||||
private final AEFluidInventory config = new AEFluidInventory(this, 63);
|
||||
|
||||
public FluidFormationPlanePart(final ItemStack is) {
|
||||
super(is);
|
||||
this.updateHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateHandler() {
|
||||
this.myHandler.setBaseAccess(AccessRestriction.WRITE);
|
||||
this.myHandler.setWhitelist(
|
||||
this.getInstalledUpgrades(Upgrades.INVERTER) > 0 ? IncludeExclude.BLACKLIST : IncludeExclude.WHITELIST);
|
||||
this.myHandler.setPriority(this.getPriority());
|
||||
|
||||
final IItemList<IAEFluidStack> priorityList = AEApi.instance().storage()
|
||||
.getStorageChannel(IFluidStorageChannel.class).createList();
|
||||
|
||||
final int slotsToUse = 18 + this.getInstalledUpgrades(Upgrades.CAPACITY) * 9;
|
||||
for (int x = 0; x < this.config.getSlots() && x < slotsToUse; x++) {
|
||||
final IAEFluidStack is = this.config.getFluidInSlot(x);
|
||||
if (is != null) {
|
||||
priorityList.add(is);
|
||||
}
|
||||
}
|
||||
this.myHandler.setPartitionList(new PrecisePriorityList<>(priorityList));
|
||||
|
||||
try {
|
||||
this.getProxy().getGrid().postEvent(new MENetworkCellArrayUpdate());
|
||||
} catch (final GridAccessException e) {
|
||||
// :P
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEFluidStack injectItems(IAEFluidStack input, Actionable type, IActionSource src) {
|
||||
if (this.blocked || input == null || input.getAmount().isLessThan(FluidAmount.BUCKET)) {
|
||||
// need a full bucket
|
||||
return input;
|
||||
}
|
||||
|
||||
final BlockEntity te = this.getHost().getTile();
|
||||
final World w = te.getWorld();
|
||||
final AEPartLocation side = this.getSide();
|
||||
final BlockPos pos = te.getPos().offset(side.getFacing());
|
||||
|
||||
FluidVolume volume = input.getFluidStack();
|
||||
FluidVolume remainder = fill(w, pos, volume, type == Actionable.MODULATE ? Simulation.ACTION : Simulation.SIMULATE);
|
||||
if (remainder.getAmount_F().isLessThan(volume.getAmount_F())) {
|
||||
// calculate the effective amount consumed
|
||||
// round UP here because we might otherwise duplicate fluids
|
||||
if (remainder.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return AEFluidStack.fromFluidVolume(remainder, RoundingMode.DOWN);
|
||||
}
|
||||
} else {
|
||||
// Filling failed
|
||||
this.blocked = true;
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME https://github.com/AlexIIL/LibBlockAttributes/pull/21
|
||||
/**
|
||||
* Attempts to fill the given block with a bucket's worth of fluid
|
||||
* @return The remainder of the given fluid volume after placing a bucket
|
||||
*/
|
||||
public static FluidVolume fill(WorldAccess world, BlockPos pos, FluidVolume volume, Simulation simulation) {
|
||||
|
||||
if (volume.getAmount_F().isLessThan(FluidAmount.BUCKET)) {
|
||||
return volume; // Need at least a buckets worth
|
||||
}
|
||||
|
||||
Fluid fluid = volume.getRawFluid();
|
||||
if (fluid == null) {
|
||||
return volume; // Can't be placed if it doesn't have an associated vanilla fluid
|
||||
}
|
||||
|
||||
// This code assumes that placing a fluid in the world will always consume a bucket's worth
|
||||
boolean success = false;
|
||||
|
||||
BlockState state = world.getBlockState(pos);
|
||||
Block block = state.getBlock();
|
||||
if (state.isAir()) {
|
||||
// The easiest case, probably
|
||||
if (simulation == Simulation.ACTION) {
|
||||
BlockState fluidStillState = fluid.getDefaultState().getBlockState();
|
||||
world.setBlockState(pos, fluidStillState, 3);
|
||||
}
|
||||
success = true;
|
||||
|
||||
} else if (block instanceof FluidFillable) {
|
||||
// FluidFillable includes waterloggable blocks, but not cauldrons, etc.
|
||||
FluidFillable fillable = (FluidFillable) block;
|
||||
if (simulation == Simulation.SIMULATE) {
|
||||
success = fillable.canFillWithFluid(world, pos, state, fluid);
|
||||
} else {
|
||||
success = fillable.tryFillWithFluid(world, pos, state, fluid.getDefaultState());
|
||||
}
|
||||
} else if (block instanceof FluidBlock) {
|
||||
FluidState fluidState = world.getFluidState(pos);
|
||||
// Top up a non-still fluid block, but this consumes a full bucket regardless of the level
|
||||
if (!fluidState.isStill() && fluidState.getFluid() == fluid) {
|
||||
if (simulation == Simulation.ACTION) {
|
||||
world.setBlockState(pos, fluid.getDefaultState().getBlockState(), 3);
|
||||
}
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
// Reduce by one bucket
|
||||
return volume.copy().withAmount(volume.getAmount_F().roundedSub(FluidAmount.ONE, RoundingMode.DOWN));
|
||||
} else {
|
||||
return volume;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFluidInventoryChanged(IAEFluidTank inv, int slot) {
|
||||
if (inv == this.config) {
|
||||
this.updateHandler();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromNBT(final CompoundTag data) {
|
||||
super.readFromNBT(data);
|
||||
this.config.readFromNBT(data, "config");
|
||||
this.updateHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToNBT(final CompoundTag data) {
|
||||
super.writeToNBT(data);
|
||||
this.config.writeToNBT(data, "config");
|
||||
}
|
||||
|
||||
@Override
|
||||
@MENetworkEventSubscribe
|
||||
public void powerRender(final MENetworkPowerStatusChange c) {
|
||||
this.stateChanged();
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void updateChannels(final MENetworkChannelsChanged changedChannels) {
|
||||
this.stateChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPartActivate(final PlayerEntity player, final Hand hand, final Vec3d pos) {
|
||||
if (Platform.isServer()) {
|
||||
ContainerOpener.openContainer(FluidFormationPlaneContainer.TYPE, player, ContainerLocator.forPart(this));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IStorageChannel<IAEFluidStack> getChannel() {
|
||||
return AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IMEInventoryHandler> getCellArray(final IStorageChannel channel) {
|
||||
if (this.getProxy().isActive()
|
||||
&& channel == AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class)) {
|
||||
final List<IMEInventoryHandler> handler = new ArrayList<>(1);
|
||||
handler.add(this.myHandler);
|
||||
return handler;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPartModel getStaticModels() {
|
||||
return MODELS.getModel(this.isPowered(), this.isActive());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Object getModelData() {
|
||||
return getConnections();
|
||||
}
|
||||
|
||||
public IAEFluidTank getConfig() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemStackRepresentation() {
|
||||
return AEApi.instance().definitions().parts().fluidFormationnPlane().maybeStack(1).orElse(ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScreenHandlerType<?> getContainerType() {
|
||||
return FluidFormationPlaneContainer.TYPE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, 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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.fluids.parts;
|
||||
|
||||
import alexiil.mc.lib.attributes.Simulation;
|
||||
import alexiil.mc.lib.attributes.fluid.GroupedFluidInv;
|
||||
import alexiil.mc.lib.attributes.fluid.filter.ExactFluidFilter;
|
||||
import alexiil.mc.lib.attributes.fluid.filter.FluidFilter;
|
||||
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.networking.security.IActionSource;
|
||||
import appeng.api.networking.storage.IBaseMonitor;
|
||||
import appeng.api.networking.ticking.TickRateModulation;
|
||||
import appeng.api.storage.IMEInventory;
|
||||
import appeng.api.storage.IMEMonitorHandlerReceiver;
|
||||
import appeng.api.storage.IStorageChannel;
|
||||
import appeng.api.storage.channels.IFluidStorageChannel;
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.fluids.helper.GroupedFluidInvCache;
|
||||
import appeng.fluids.util.AEFluidStack;
|
||||
import appeng.me.GridAccessException;
|
||||
import appeng.me.helpers.IGridProxyable;
|
||||
import appeng.me.storage.ITickingMonitor;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Wraps an Fluid Handler in such a way that it can be used as an IMEInventory
|
||||
* for fluids.
|
||||
*
|
||||
* @author BrockWS
|
||||
* @version rv6 - 22/05/2018
|
||||
* @since rv6 22/05/2018
|
||||
*/
|
||||
public class FluidHandlerAdapter implements IMEInventory<IAEFluidStack>, IBaseMonitor<IAEFluidStack>, ITickingMonitor {
|
||||
private final Map<IMEMonitorHandlerReceiver<IAEFluidStack>, Object> listeners = new HashMap<>();
|
||||
private IActionSource source;
|
||||
private final GroupedFluidInv fluidHandler;
|
||||
private final IGridProxyable proxyable;
|
||||
private final GroupedFluidInvCache cache;
|
||||
|
||||
FluidHandlerAdapter(GroupedFluidInv fluidHandler, IGridProxyable proxy) {
|
||||
this.fluidHandler = fluidHandler;
|
||||
this.proxyable = proxy;
|
||||
this.cache = new GroupedFluidInvCache(this.fluidHandler);
|
||||
}
|
||||
|
||||
private Simulation getFluidAction(Actionable actionable) {
|
||||
return actionable == Actionable.MODULATE ? Simulation.ACTION : Simulation.SIMULATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEFluidStack injectItems(IAEFluidStack input, Actionable type, IActionSource src) {
|
||||
FluidVolume fluidStack = input.getFluidStack();
|
||||
|
||||
// Insert
|
||||
FluidVolume excess = this.fluidHandler.attemptInsertion(fluidStack, getFluidAction(type));
|
||||
if (excess.amount().equals(fluidStack.amount())) {
|
||||
// The stack was unmodified, target tank is full
|
||||
return input;
|
||||
}
|
||||
|
||||
if (type == Actionable.MODULATE) {
|
||||
try {
|
||||
this.proxyable.getProxy().getTick().alertDevice(this.proxyable.getProxy().getNode());
|
||||
} catch (GridAccessException ignore) {
|
||||
// meh
|
||||
}
|
||||
}
|
||||
|
||||
return AEFluidStack.fromFluidVolume(excess, RoundingMode.DOWN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEFluidStack extractItems(IAEFluidStack request, Actionable mode, IActionSource src) {
|
||||
FluidFilter filter = new ExactFluidFilter(request.getFluid());
|
||||
|
||||
// Drain the fluid from the tank
|
||||
FluidVolume gathered = this.fluidHandler.attemptExtraction(filter, request.getAmount(), getFluidAction(mode));
|
||||
if (gathered.isEmpty()) {
|
||||
// If nothing was pulled from the tank, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
if (mode == Actionable.MODULATE) {
|
||||
try {
|
||||
this.proxyable.getProxy().getTick().alertDevice(this.proxyable.getProxy().getNode());
|
||||
} catch (GridAccessException ignore) {
|
||||
// meh
|
||||
}
|
||||
}
|
||||
return AEFluidStack.fromFluidVolume(gathered, RoundingMode.DOWN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickRateModulation onTick() {
|
||||
List<IAEFluidStack> changes = this.cache.detectChanges();
|
||||
if (!changes.isEmpty()) {
|
||||
this.postDifference(changes);
|
||||
return TickRateModulation.URGENT;
|
||||
} else {
|
||||
return TickRateModulation.SLOWER;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<IAEFluidStack> getAvailableItems(IItemList<IAEFluidStack> out) {
|
||||
return this.cache.getAvailable(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IStorageChannel<IAEFluidStack> getChannel() {
|
||||
return AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActionSource(IActionSource source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(final IMEMonitorHandlerReceiver<IAEFluidStack> l, final Object verificationToken) {
|
||||
this.listeners.put(l, verificationToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(final IMEMonitorHandlerReceiver<IAEFluidStack> l) {
|
||||
this.listeners.remove(l);
|
||||
}
|
||||
|
||||
private void postDifference(Iterable<IAEFluidStack> a) {
|
||||
final Iterator<Map.Entry<IMEMonitorHandlerReceiver<IAEFluidStack>, Object>> i = this.listeners.entrySet()
|
||||
.iterator();
|
||||
while (i.hasNext()) {
|
||||
final Map.Entry<IMEMonitorHandlerReceiver<IAEFluidStack>, Object> l = i.next();
|
||||
final IMEMonitorHandlerReceiver<IAEFluidStack> key = l.getKey();
|
||||
if (key.isValid(l.getValue())) {
|
||||
key.postChange(this, a, this.source);
|
||||
} else {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, 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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.fluids.parts;
|
||||
|
||||
import alexiil.mc.lib.attributes.Simulation;
|
||||
import alexiil.mc.lib.attributes.fluid.FluidAttributes;
|
||||
import alexiil.mc.lib.attributes.fluid.FluidExtractable;
|
||||
import alexiil.mc.lib.attributes.fluid.amount.FluidAmount;
|
||||
import alexiil.mc.lib.attributes.fluid.filter.ConstantFluidFilter;
|
||||
import alexiil.mc.lib.attributes.fluid.filter.FluidFilter;
|
||||
import alexiil.mc.lib.attributes.fluid.volume.FluidKey;
|
||||
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
|
||||
import appeng.api.config.*;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.security.IActionSource;
|
||||
import appeng.api.networking.ticking.TickRateModulation;
|
||||
import appeng.api.networking.ticking.TickingRequest;
|
||||
import appeng.api.parts.IPartModel;
|
||||
import appeng.api.storage.IMEMonitor;
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.attributes.MEAttributes;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.core.settings.TickRates;
|
||||
import appeng.fluids.util.AEFluidStack;
|
||||
import appeng.items.parts.PartModels;
|
||||
import appeng.me.GridAccessException;
|
||||
import appeng.me.helpers.MachineSource;
|
||||
import appeng.parts.PartModel;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author BrockWS
|
||||
* @version rv6 - 30/04/2018
|
||||
* @since rv6 30/04/2018
|
||||
*/
|
||||
public class FluidImportBusPart extends SharedFluidBusPart {
|
||||
public static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "part/fluid_import_bus_base");
|
||||
@PartModels
|
||||
public static final IPartModel MODELS_OFF = new PartModel(MODEL_BASE,
|
||||
new Identifier(AppEng.MOD_ID, "part/fluid_import_bus_off"));
|
||||
@PartModels
|
||||
public static final IPartModel MODELS_ON = new PartModel(MODEL_BASE,
|
||||
new Identifier(AppEng.MOD_ID, "part/fluid_import_bus_on"));
|
||||
@PartModels
|
||||
public static final IPartModel MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE,
|
||||
new Identifier(AppEng.MOD_ID, "part/fluid_import_bus_has_channel"));
|
||||
|
||||
private final IActionSource source;
|
||||
|
||||
public FluidImportBusPart(ItemStack is) {
|
||||
super(is);
|
||||
this.getConfigManager().registerSetting(Settings.REDSTONE_CONTROLLED, RedstoneMode.IGNORE);
|
||||
this.getConfigManager().registerSetting(Settings.FUZZY_MODE, FuzzyMode.IGNORE_ALL);
|
||||
this.getConfigManager().registerSetting(Settings.CRAFT_ONLY, YesNo.NO);
|
||||
this.getConfigManager().registerSetting(Settings.SCHEDULING_MODE, SchedulingMode.DEFAULT);
|
||||
this.source = new MachineSource(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickingRequest getTickingRequest(IGridNode node) {
|
||||
return new TickingRequest(TickRates.FluidImportBus.getMin(), TickRates.FluidImportBus.getMax(),
|
||||
this.isSleeping(), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickRateModulation tickingRequest(IGridNode node, int ticksSinceLastCall) {
|
||||
return this.canDoBusWork() ? this.doBusWork() : TickRateModulation.IDLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TickRateModulation doBusWork() {
|
||||
if (!this.canDoBusWork()) {
|
||||
return TickRateModulation.IDLE;
|
||||
}
|
||||
|
||||
FluidExtractable extractable = MEAttributes.getAttributeInFrontOfPart(FluidAttributes.EXTRACTABLE, this);
|
||||
if (extractable != null) {
|
||||
try {
|
||||
IMEMonitor<IAEFluidStack> inv = this.getProxy().getStorage().getInventory(this.getChannel());
|
||||
|
||||
// Ask the target for fluid matching our filter
|
||||
FluidFilter filter = getFilter();
|
||||
FluidVolume extractableVolume = extractable.attemptExtraction(filter,
|
||||
FluidAmount.of(this.calculateAmountToSend(), 1000), Simulation.SIMULATE);
|
||||
|
||||
// Also double check that it's valid w.r.t. our filter
|
||||
if (extractableVolume.isEmpty() || !filter.matches(extractableVolume.fluidKey)) {
|
||||
return TickRateModulation.SLOWER;
|
||||
}
|
||||
|
||||
// Round down when inserting fluids into the system to avoid duplication
|
||||
final AEFluidStack aeFluidStack = AEFluidStack.fromFluidVolume(extractableVolume, RoundingMode.DOWN);
|
||||
|
||||
if (aeFluidStack != null) {
|
||||
final IAEFluidStack notInserted = inv.injectItems(aeFluidStack, Actionable.MODULATE,
|
||||
this.source);
|
||||
|
||||
if (notInserted != null && notInserted.getStackSize() > 0) {
|
||||
aeFluidStack.decStackSize(notInserted.getStackSize());
|
||||
}
|
||||
|
||||
// Now we need to actually drain the fluid, and use the actual amount we just inserted
|
||||
extractable.extract(filter, aeFluidStack.getAmount()); // FIXME: If there's a mismatch here, log?
|
||||
|
||||
return TickRateModulation.FASTER;
|
||||
}
|
||||
|
||||
return TickRateModulation.IDLE;
|
||||
} catch (GridAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return TickRateModulation.SLEEP;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canDoBusWork() {
|
||||
return this.getProxy().isActive();
|
||||
}
|
||||
|
||||
// Returns a filter for fluid extraction based on the configured filter for this bus
|
||||
private FluidFilter getFilter() {
|
||||
Set<FluidKey> allowedFluids = null;
|
||||
|
||||
for (int i = 0; i < this.getConfig().getSlots(); i++) {
|
||||
final IAEFluidStack stack = this.getConfig().getFluidInSlot(i);
|
||||
if (stack != null) {
|
||||
if (allowedFluids == null) {
|
||||
allowedFluids = new HashSet<>();
|
||||
}
|
||||
allowedFluids.add(stack.getFluid());
|
||||
}
|
||||
}
|
||||
return allowedFluids == null ? ConstantFluidFilter.ANYTHING : allowedFluids::contains;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RedstoneMode getRSMode() {
|
||||
return (RedstoneMode) this.getConfigManager().getSetting(Settings.REDSTONE_CONTROLLED);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public IPartModel getStaticModels() {
|
||||
if (this.isActive() && this.isPowered()) {
|
||||
return MODELS_HAS_CHANNEL;
|
||||
} else if (this.isPowered()) {
|
||||
return MODELS_ON;
|
||||
} else {
|
||||
return MODELS_OFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, 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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.fluids.parts;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import alexiil.mc.lib.attributes.AttributeList;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.screen.ScreenHandlerType;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import alexiil.mc.lib.attributes.item.FixedItemInv;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.config.Upgrades;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.events.MENetworkChannelsChanged;
|
||||
import appeng.api.networking.events.MENetworkEventSubscribe;
|
||||
import appeng.api.networking.events.MENetworkPowerStatusChange;
|
||||
import appeng.api.networking.ticking.IGridTickable;
|
||||
import appeng.api.networking.ticking.TickRateModulation;
|
||||
import appeng.api.networking.ticking.TickingRequest;
|
||||
import appeng.api.parts.IPartCollisionHelper;
|
||||
import appeng.api.parts.IPartModel;
|
||||
import appeng.api.storage.IMEMonitor;
|
||||
import appeng.api.storage.IStorageChannel;
|
||||
import appeng.api.storage.IStorageMonitorable;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.api.util.AECableType;
|
||||
import appeng.api.util.IConfigManager;
|
||||
import appeng.container.ContainerLocator;
|
||||
import appeng.container.ContainerOpener;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.fluids.container.FluidInterfaceContainer;
|
||||
import appeng.fluids.helper.DualityFluidInterface;
|
||||
import appeng.fluids.helper.IFluidInterfaceHost;
|
||||
import appeng.helpers.IPriorityHost;
|
||||
|
||||
import appeng.items.parts.PartModels;
|
||||
import appeng.parts.BasicStatePart;
|
||||
import appeng.parts.PartModel;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public class FluidInterfacePart extends BasicStatePart
|
||||
implements IGridTickable, IStorageMonitorable, IFluidInterfaceHost, IPriorityHost {
|
||||
public static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "part/fluid_interface_base");
|
||||
|
||||
@PartModels
|
||||
public static final PartModel MODELS_OFF = new PartModel(MODEL_BASE,
|
||||
new Identifier(AppEng.MOD_ID, "part/fluid_interface_off"));
|
||||
|
||||
@PartModels
|
||||
public static final PartModel MODELS_ON = new PartModel(MODEL_BASE,
|
||||
new Identifier(AppEng.MOD_ID, "part/fluid_interface_on"));
|
||||
|
||||
@PartModels
|
||||
public static final PartModel MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE,
|
||||
new Identifier(AppEng.MOD_ID, "part/fluid_interface_has_channel"));
|
||||
|
||||
private final DualityFluidInterface duality = new DualityFluidInterface(this.getProxy(), this);
|
||||
|
||||
public FluidInterfacePart(final ItemStack is) {
|
||||
super(is);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DualityFluidInterface getDualityFluidInterface() {
|
||||
return this.duality;
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void stateChange(final MENetworkChannelsChanged c) {
|
||||
this.duality.notifyNeighbors();
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void stateChange(final MENetworkPowerStatusChange c) {
|
||||
this.duality.notifyNeighbors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getBoxes(final IPartCollisionHelper bch) {
|
||||
bch.addBox(2, 2, 14, 14, 14, 16);
|
||||
bch.addBox(5, 5, 12, 11, 11, 14);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gridChanged() {
|
||||
this.duality.gridChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromNBT(final CompoundTag data) {
|
||||
super.readFromNBT(data);
|
||||
this.duality.readFromNBT(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToNBT(final CompoundTag data) {
|
||||
super.writeToNBT(data);
|
||||
this.duality.writeToNBT(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCableConnectionLength(AECableType cable) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPartActivate(final PlayerEntity p, final Hand hand, final Vec3d pos) {
|
||||
if (Platform.isServer()) {
|
||||
ContainerOpener.openContainer(FluidInterfaceContainer.TYPE, p, ContainerLocator.forPart(this));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IAEStack<T>> IMEMonitor<T> getInventory(IStorageChannel<T> channel) {
|
||||
return this.duality.getInventory(channel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickingRequest getTickingRequest(final IGridNode node) {
|
||||
return this.duality.getTickingRequest(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickRateModulation tickingRequest(final IGridNode node, final int ticksSinceLastCall) {
|
||||
return this.duality.tickingRequest(node, ticksSinceLastCall);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<Direction> getTargets() {
|
||||
return EnumSet.of(this.getSide().getFacing());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockEntity getBlockEntity() {
|
||||
return super.getHost().getTile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPartModel getStaticModels() {
|
||||
if (this.isActive() && this.isPowered()) {
|
||||
return MODELS_HAS_CHANNEL;
|
||||
} else if (this.isPowered()) {
|
||||
return MODELS_ON;
|
||||
} else {
|
||||
return MODELS_OFF;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority() {
|
||||
return this.duality.getPriority();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPriority(final int newValue) {
|
||||
this.duality.setPriority(newValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAllAttributes(AttributeList<?> to) {
|
||||
super.addAllAttributes(to);
|
||||
this.duality.addAllAttributes(to);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInstalledUpgrades(Upgrades u) {
|
||||
return this.duality.getInstalledUpgrades(u);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IConfigManager getConfigManager() {
|
||||
return this.duality.getConfigManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FixedItemInv getInventoryByName(String name) {
|
||||
return this.duality.getInventoryByName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemStackRepresentation() {
|
||||
return AEApi.instance().definitions().parts().fluidIface().maybeStack(1).orElse(ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScreenHandlerType<?> getContainerType() {
|
||||
return FluidInterfaceContainer.TYPE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
|
||||
package appeng.fluids.parts;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.particle.DustParticleEffect;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.config.RedstoneMode;
|
||||
import appeng.api.config.Settings;
|
||||
import appeng.api.networking.events.MENetworkChannelsChanged;
|
||||
import appeng.api.networking.events.MENetworkEventSubscribe;
|
||||
import appeng.api.networking.events.MENetworkPowerStatusChange;
|
||||
import appeng.api.networking.security.IActionSource;
|
||||
import appeng.api.networking.storage.IBaseMonitor;
|
||||
import appeng.api.networking.storage.IStackWatcher;
|
||||
import appeng.api.networking.storage.IStackWatcherHost;
|
||||
import appeng.api.parts.IPartCollisionHelper;
|
||||
import appeng.api.parts.IPartModel;
|
||||
import appeng.api.storage.IMEMonitor;
|
||||
import appeng.api.storage.IMEMonitorHandlerReceiver;
|
||||
import appeng.api.storage.IStorageChannel;
|
||||
import appeng.api.storage.channels.IFluidStorageChannel;
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.api.util.AECableType;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.api.util.IConfigManager;
|
||||
import appeng.container.ContainerLocator;
|
||||
import appeng.container.ContainerOpener;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.fluids.container.FluidLevelEmitterContainer;
|
||||
import appeng.fluids.util.AEFluidInventory;
|
||||
import appeng.fluids.util.IAEFluidInventory;
|
||||
import appeng.fluids.util.IAEFluidTank;
|
||||
import appeng.items.parts.PartModels;
|
||||
import appeng.me.GridAccessException;
|
||||
import appeng.parts.PartModel;
|
||||
import appeng.parts.automation.UpgradeablePart;
|
||||
import appeng.util.IConfigManagerHost;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public class FluidLevelEmitterPart extends UpgradeablePart
|
||||
implements IStackWatcherHost, IConfigManagerHost, IAEFluidInventory, IMEMonitorHandlerReceiver<IAEFluidStack> {
|
||||
@PartModels
|
||||
public static final Identifier MODEL_BASE_OFF = new Identifier(AppEng.MOD_ID,
|
||||
"part/level_emitter_base_off");
|
||||
@PartModels
|
||||
public static final Identifier MODEL_BASE_ON = new Identifier(AppEng.MOD_ID,
|
||||
"part/level_emitter_base_on");
|
||||
@PartModels
|
||||
public static final Identifier MODEL_STATUS_OFF = new Identifier(AppEng.MOD_ID,
|
||||
"part/level_emitter_status_off");
|
||||
@PartModels
|
||||
public static final Identifier MODEL_STATUS_ON = new Identifier(AppEng.MOD_ID,
|
||||
"part/level_emitter_status_on");
|
||||
@PartModels
|
||||
public static final Identifier MODEL_STATUS_HAS_CHANNEL = new Identifier(AppEng.MOD_ID,
|
||||
"part/level_emitter_status_has_channel");
|
||||
|
||||
public static final PartModel MODEL_OFF_OFF = new PartModel(MODEL_BASE_OFF, MODEL_STATUS_OFF);
|
||||
public static final PartModel MODEL_OFF_ON = new PartModel(MODEL_BASE_OFF, MODEL_STATUS_ON);
|
||||
public static final PartModel MODEL_OFF_HAS_CHANNEL = new PartModel(MODEL_BASE_OFF, MODEL_STATUS_HAS_CHANNEL);
|
||||
public static final PartModel MODEL_ON_OFF = new PartModel(MODEL_BASE_ON, MODEL_STATUS_OFF);
|
||||
public static final PartModel MODEL_ON_ON = new PartModel(MODEL_BASE_ON, MODEL_STATUS_ON);
|
||||
public static final PartModel MODEL_ON_HAS_CHANNEL = new PartModel(MODEL_BASE_ON, MODEL_STATUS_HAS_CHANNEL);
|
||||
|
||||
private static final int FLAG_ON = 4;
|
||||
|
||||
private boolean prevState = false;
|
||||
private long lastReportedValue = 0;
|
||||
private long reportingValue = 0;
|
||||
private IStackWatcher stackWatcher = null;
|
||||
private final AEFluidInventory config = new AEFluidInventory(this, 1);
|
||||
|
||||
public FluidLevelEmitterPart(ItemStack is) {
|
||||
super(is);
|
||||
|
||||
this.getConfigManager().registerSetting(Settings.REDSTONE_EMITTER, RedstoneMode.HIGH_SIGNAL);
|
||||
}
|
||||
|
||||
public long getReportingValue() {
|
||||
return this.reportingValue;
|
||||
}
|
||||
|
||||
public void setReportingValue(final long v) {
|
||||
this.reportingValue = v;
|
||||
this.updateState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSetting(IConfigManager manager, Settings settingName, Enum<?> newValue) {
|
||||
this.configureWatchers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateWatcher(IStackWatcher newWatcher) {
|
||||
this.stackWatcher = newWatcher;
|
||||
this.configureWatchers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStackChange(IItemList<?> o, IAEStack<?> fullStack, IAEStack<?> diffStack, IActionSource src,
|
||||
IStorageChannel<?> chan) {
|
||||
if (chan == AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class)
|
||||
&& fullStack.equals(this.config.getFluidInSlot(0))) {
|
||||
this.lastReportedValue = fullStack.getStackSize();
|
||||
this.updateState();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFluidInventoryChanged(IAEFluidTank inv, int slot) {
|
||||
this.configureWatchers();
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void channelChanged(final MENetworkChannelsChanged c) {
|
||||
this.updateState();
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void powerChanged(final MENetworkPowerStatusChange c) {
|
||||
this.updateState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int isProvidingStrongPower() {
|
||||
return this.prevState ? 15 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int isProvidingWeakPower() {
|
||||
return this.prevState ? 15 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int populateFlags(final int cf) {
|
||||
return cf | (this.prevState ? FLAG_ON : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(final Object effectiveGrid) {
|
||||
try {
|
||||
return this.getProxy().getGrid() == effectiveGrid;
|
||||
} catch (final GridAccessException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postChange(final IBaseMonitor<IAEFluidStack> monitor, final Iterable<IAEFluidStack> change,
|
||||
final IActionSource actionSource) {
|
||||
this.updateReportingValue((IMEMonitor<IAEFluidStack>) monitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onListUpdate() {
|
||||
try {
|
||||
final IStorageChannel<IAEFluidStack> channel = AEApi.instance().storage()
|
||||
.getStorageChannel(IFluidStorageChannel.class);
|
||||
final IMEMonitor<IAEFluidStack> inventory = this.getProxy().getStorage().getInventory(channel);
|
||||
|
||||
this.updateReportingValue(inventory);
|
||||
} catch (final GridAccessException e) {
|
||||
// ;P
|
||||
}
|
||||
}
|
||||
|
||||
private void updateState() {
|
||||
final boolean isOn = this.isLevelEmitterOn();
|
||||
if (this.prevState != isOn) {
|
||||
this.getHost().markForUpdate();
|
||||
final BlockEntity te = this.getHost().getTile();
|
||||
this.prevState = isOn;
|
||||
Platform.notifyBlocksOfNeighbors(te.getWorld(), te.getPos());
|
||||
Platform.notifyBlocksOfNeighbors(te.getWorld(), te.getPos().offset(this.getSide().getFacing()));
|
||||
}
|
||||
}
|
||||
|
||||
private void configureWatchers() {
|
||||
final IFluidStorageChannel channel = AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class);
|
||||
|
||||
if (this.stackWatcher != null) {
|
||||
this.stackWatcher.reset();
|
||||
|
||||
final IAEFluidStack myStack = this.config.getFluidInSlot(0);
|
||||
|
||||
try {
|
||||
if (myStack != null) {
|
||||
this.getProxy().getStorage().getInventory(channel).removeListener(this);
|
||||
this.stackWatcher.add(myStack);
|
||||
} else {
|
||||
this.getProxy().getStorage().getInventory(channel).addListener(this, this.getProxy().getGrid());
|
||||
}
|
||||
|
||||
final IMEMonitor<IAEFluidStack> inventory = this.getProxy().getStorage().getInventory(channel);
|
||||
|
||||
this.updateReportingValue(inventory);
|
||||
} catch (GridAccessException e) {
|
||||
// NOP
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateReportingValue(final IMEMonitor<IAEFluidStack> monitor) {
|
||||
final IAEFluidStack myStack = this.config.getFluidInSlot(0);
|
||||
|
||||
if (myStack == null) {
|
||||
this.lastReportedValue = 0;
|
||||
for (final IAEFluidStack st : monitor.getStorageList()) {
|
||||
this.lastReportedValue += st.getStackSize();
|
||||
}
|
||||
} else {
|
||||
final IAEFluidStack r = monitor.getStorageList().findPrecise(myStack);
|
||||
if (r == null) {
|
||||
this.lastReportedValue = 0;
|
||||
} else {
|
||||
this.lastReportedValue = r.getStackSize();
|
||||
}
|
||||
}
|
||||
this.updateState();
|
||||
}
|
||||
|
||||
private boolean isLevelEmitterOn() {
|
||||
if (Platform.isClient()) {
|
||||
return (this.getClientFlags() & FLAG_ON) == FLAG_ON;
|
||||
}
|
||||
|
||||
if (!this.getProxy().isActive()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final boolean flipState = this.getConfigManager()
|
||||
.getSetting(Settings.REDSTONE_EMITTER) == RedstoneMode.LOW_SIGNAL;
|
||||
return flipState ? this.reportingValue > this.lastReportedValue : this.reportingValue <= this.lastReportedValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AECableType getCableConnectionType(final AEPartLocation dir) {
|
||||
return AECableType.SMART;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCableConnectionLength(AECableType cable) {
|
||||
return 16;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canConnectRedstone() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getBoxes(final IPartCollisionHelper bch) {
|
||||
bch.addBox(7, 7, 11, 9, 9, 16);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void randomDisplayTick(final World world, final BlockPos pos, final Random r) {
|
||||
if (this.isLevelEmitterOn()) {
|
||||
final AEPartLocation d = this.getSide();
|
||||
|
||||
final double d0 = d.xOffset * 0.45F + (r.nextFloat() - 0.5F) * 0.2D;
|
||||
final double d1 = d.yOffset * 0.45F + (r.nextFloat() - 0.5F) * 0.2D;
|
||||
final double d2 = d.zOffset * 0.45F + (r.nextFloat() - 0.5F) * 0.2D;
|
||||
|
||||
world.addParticle(DustParticleEffect.RED, 0.5 + pos.getX() + d0, 0.5 + pos.getY() + d1,
|
||||
0.5 + pos.getZ() + d2, 0.0D, 0.0D, 0.0D);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPartActivate(final PlayerEntity player, final Hand hand, final Vec3d pos) {
|
||||
if (Platform.isServer()) {
|
||||
ContainerOpener.openContainer(FluidLevelEmitterContainer.TYPE, player, ContainerLocator.forPart(this));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPartModel getStaticModels() {
|
||||
if (this.isActive() && this.isPowered()) {
|
||||
return this.isLevelEmitterOn() ? MODEL_ON_HAS_CHANNEL : MODEL_OFF_HAS_CHANNEL;
|
||||
} else if (this.isPowered()) {
|
||||
return this.isLevelEmitterOn() ? MODEL_ON_ON : MODEL_OFF_ON;
|
||||
} else {
|
||||
return this.isLevelEmitterOn() ? MODEL_ON_OFF : MODEL_OFF_OFF;
|
||||
}
|
||||
}
|
||||
|
||||
public IAEFluidTank getConfig() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromNBT(final CompoundTag data) {
|
||||
super.readFromNBT(data);
|
||||
this.lastReportedValue = data.getLong("lastReportedValue");
|
||||
this.reportingValue = data.getLong("reportingValue");
|
||||
this.prevState = data.getBoolean("prevState");
|
||||
this.config.readFromNBT(data, "config");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToNBT(final CompoundTag data) {
|
||||
super.writeToNBT(data);
|
||||
data.putLong("lastReportedValue", this.lastReportedValue);
|
||||
data.putLong("reportingValue", this.reportingValue);
|
||||
data.putBoolean("prevState", this.prevState);
|
||||
this.config.writeToNBT(data, "config");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,438 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, 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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.fluids.parts;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import alexiil.mc.lib.attributes.fluid.FluidAttributes;
|
||||
import alexiil.mc.lib.attributes.fluid.GroupedFluidInv;
|
||||
import alexiil.mc.lib.attributes.fluid.GroupedFluidInvView;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.screen.ScreenHandlerType;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.config.AccessRestriction;
|
||||
import appeng.api.config.FuzzyMode;
|
||||
import appeng.api.config.IncludeExclude;
|
||||
import appeng.api.config.Settings;
|
||||
import appeng.api.config.StorageFilter;
|
||||
import appeng.api.config.Upgrades;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.events.MENetworkCellArrayUpdate;
|
||||
import appeng.api.networking.security.IActionSource;
|
||||
import appeng.api.networking.storage.IBaseMonitor;
|
||||
import appeng.api.networking.ticking.ITickManager;
|
||||
import appeng.api.networking.ticking.TickRateModulation;
|
||||
import appeng.api.networking.ticking.TickingRequest;
|
||||
import appeng.api.parts.IPartHost;
|
||||
import appeng.api.parts.IPartModel;
|
||||
import appeng.api.storage.IMEInventory;
|
||||
import appeng.api.storage.IMEInventoryHandler;
|
||||
import appeng.api.storage.IMEMonitorHandlerReceiver;
|
||||
import appeng.api.storage.IStorageChannel;
|
||||
import appeng.api.storage.IStorageMonitorable;
|
||||
import appeng.api.storage.IStorageMonitorableAccessor;
|
||||
import appeng.api.storage.channels.IFluidStorageChannel;
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.attributes.MEAttributes;
|
||||
import appeng.container.ContainerLocator;
|
||||
import appeng.container.ContainerOpener;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.core.settings.TickRates;
|
||||
import appeng.fluids.container.FluidStorageBusContainer;
|
||||
import appeng.fluids.util.AEFluidInventory;
|
||||
import appeng.fluids.util.IAEFluidInventory;
|
||||
import appeng.fluids.util.IAEFluidTank;
|
||||
import appeng.helpers.IInterfaceHost;
|
||||
import appeng.items.parts.PartModels;
|
||||
import appeng.me.GridAccessException;
|
||||
import appeng.me.helpers.MachineSource;
|
||||
import appeng.me.storage.ITickingMonitor;
|
||||
import appeng.me.storage.MEInventoryHandler;
|
||||
import appeng.parts.PartModel;
|
||||
import appeng.parts.misc.SharedStorageBusPart;
|
||||
import appeng.util.Platform;
|
||||
import appeng.util.prioritylist.FuzzyPriorityList;
|
||||
import appeng.util.prioritylist.PrecisePriorityList;
|
||||
|
||||
/**
|
||||
* @author BrockWS
|
||||
* @version rv6 - 22/05/2018
|
||||
* @since rv6 22/05/2018
|
||||
*/
|
||||
public class FluidStorageBusPart extends SharedStorageBusPart
|
||||
implements IMEMonitorHandlerReceiver<IAEFluidStack>, IAEFluidInventory {
|
||||
public static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID,
|
||||
"part/fluid_storage_bus_base");
|
||||
@PartModels
|
||||
public static final IPartModel MODELS_OFF = new PartModel(MODEL_BASE,
|
||||
new Identifier(AppEng.MOD_ID, "part/fluid_storage_bus_off"));
|
||||
@PartModels
|
||||
public static final IPartModel MODELS_ON = new PartModel(MODEL_BASE,
|
||||
new Identifier(AppEng.MOD_ID, "part/fluid_storage_bus_on"));
|
||||
@PartModels
|
||||
public static final IPartModel MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE,
|
||||
new Identifier(AppEng.MOD_ID, "part/fluid_storage_bus_has_channel"));
|
||||
|
||||
private final IActionSource source;
|
||||
private final AEFluidInventory config = new AEFluidInventory(this, 63);
|
||||
private boolean cached = false;
|
||||
private ITickingMonitor monitor = null;
|
||||
private MEInventoryHandler<IAEFluidStack> handler = null;
|
||||
private int handlerHash = 0;
|
||||
private byte resetCacheLogic = 0;
|
||||
|
||||
public FluidStorageBusPart(ItemStack is) {
|
||||
super(is);
|
||||
this.getConfigManager().registerSetting(Settings.ACCESS, AccessRestriction.READ_WRITE);
|
||||
this.getConfigManager().registerSetting(Settings.FUZZY_MODE, FuzzyMode.IGNORE_ALL);
|
||||
this.getConfigManager().registerSetting(Settings.STORAGE_FILTER, StorageFilter.EXTRACTABLE_ONLY);
|
||||
this.source = new MachineSource(this);
|
||||
}
|
||||
|
||||
private IMEInventory<IAEFluidStack> getInventoryWrapper(BlockEntity target) {
|
||||
// Prioritize a handler to directly link to another ME network
|
||||
IStorageMonitorableAccessor accessor = MEAttributes.getAttributeInFrontOfPart(MEAttributes.STORAGE_MONITORABLE_ACCESSOR, this);
|
||||
if (accessor != null) {
|
||||
IStorageMonitorable inventory = accessor.getInventory(this.source);
|
||||
if (inventory != null) {
|
||||
return inventory.getInventory(AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class));
|
||||
}
|
||||
|
||||
// So this could / can be a design decision. If the tile does support our custom
|
||||
// capability,
|
||||
// but it does not return an inventory for the action source, we do NOT fall
|
||||
// back to using
|
||||
// IItemHandler's, as that might circumvent the security setings, and might also
|
||||
// cause
|
||||
// performance issues.
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check via cap for IItemHandler
|
||||
GroupedFluidInv handlerExt = MEAttributes.getAttributeInFrontOfPart(FluidAttributes.GROUPED_INV, this);
|
||||
if (handlerExt != null) {
|
||||
return new FluidHandlerAdapter(handlerExt, this);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickRateModulation tickingRequest(IGridNode node, int ticksSinceLastCall) {
|
||||
if (this.resetCacheLogic != 0) {
|
||||
this.resetCache();
|
||||
}
|
||||
|
||||
if (this.monitor != null) {
|
||||
return this.monitor.onTick();
|
||||
}
|
||||
|
||||
return TickRateModulation.SLEEP;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetCache() {
|
||||
final boolean fullReset = this.resetCacheLogic == 2;
|
||||
this.resetCacheLogic = 0;
|
||||
|
||||
final IMEInventory<IAEFluidStack> in = this.getInternalHandler();
|
||||
IItemList<IAEFluidStack> before = AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class)
|
||||
.createList();
|
||||
if (in != null) {
|
||||
before = in.getAvailableItems(before);
|
||||
}
|
||||
|
||||
this.cached = false;
|
||||
if (fullReset) {
|
||||
this.handlerHash = 0;
|
||||
}
|
||||
|
||||
final IMEInventory<IAEFluidStack> out = this.getInternalHandler();
|
||||
|
||||
if (in != out) {
|
||||
IItemList<IAEFluidStack> after = AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class)
|
||||
.createList();
|
||||
if (out != null) {
|
||||
after = out.getAvailableItems(after);
|
||||
}
|
||||
Platform.postListChanges(before, after, this, this.source);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetCache(final boolean fullReset) {
|
||||
if (this.getHost() == null || this.getHost().getTile() == null || this.getHost().getTile().getWorld() == null
|
||||
|| this.getHost().getTile().getWorld().isClient) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fullReset) {
|
||||
this.resetCacheLogic = 2;
|
||||
} else {
|
||||
this.resetCacheLogic = 1;
|
||||
}
|
||||
|
||||
try {
|
||||
this.getProxy().getTick().alertDevice(this.getProxy().getNode());
|
||||
} catch (final GridAccessException e) {
|
||||
// :P
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPartActivate(final PlayerEntity player, final Hand hand, final Vec3d pos) {
|
||||
if (Platform.isServer()) {
|
||||
ContainerOpener.openContainer(FluidStorageBusContainer.TYPE, player, ContainerLocator.forPart(this));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFluidInventoryChanged(IAEFluidTank inv, int slot) {
|
||||
if (inv == this.config) {
|
||||
this.resetCache(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromNBT(final CompoundTag data) {
|
||||
super.readFromNBT(data);
|
||||
this.config.readFromNBT(data, "config");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToNBT(final CompoundTag data) {
|
||||
super.writeToNBT(data);
|
||||
this.config.writeToNBT(data, "config");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(final Object verificationToken) {
|
||||
return this.handler == verificationToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postChange(final IBaseMonitor<IAEFluidStack> monitor, final Iterable<IAEFluidStack> change,
|
||||
final IActionSource source) {
|
||||
try {
|
||||
if (this.getProxy().isActive()) {
|
||||
this.getProxy().getStorage().postAlterationOfStoredItems(
|
||||
AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class), change, this.source);
|
||||
}
|
||||
} catch (final GridAccessException e) {
|
||||
// :(
|
||||
}
|
||||
}
|
||||
|
||||
public MEInventoryHandler<IAEFluidStack> getInternalHandler() {
|
||||
if (this.cached) {
|
||||
return this.handler;
|
||||
}
|
||||
|
||||
final boolean wasSleeping = this.monitor == null;
|
||||
|
||||
this.cached = true;
|
||||
final BlockEntity self = this.getHost().getTile();
|
||||
final BlockEntity target = self.getWorld().getBlockEntity(self.getPos().offset(this.getSide().getFacing()));
|
||||
final int newHandlerHash = this.createHandlerHash(target);
|
||||
|
||||
if (newHandlerHash != 0 && newHandlerHash == this.handlerHash) {
|
||||
return this.handler;
|
||||
}
|
||||
|
||||
this.handlerHash = newHandlerHash;
|
||||
this.handler = null;
|
||||
this.monitor = null;
|
||||
if (target != null) {
|
||||
IMEInventory<IAEFluidStack> inv = this.getInventoryWrapper(target);
|
||||
if (inv instanceof ITickingMonitor) {
|
||||
this.monitor = (ITickingMonitor) inv;
|
||||
this.monitor.setActionSource(new MachineSource(this));
|
||||
}
|
||||
|
||||
if (inv != null) {
|
||||
this.checkInterfaceVsStorageBus(target, this.getSide().getOpposite());
|
||||
|
||||
this.handler = new MEInventoryHandler<>(inv,
|
||||
AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class));
|
||||
|
||||
this.handler.setBaseAccess((AccessRestriction) this.getConfigManager().getSetting(Settings.ACCESS));
|
||||
this.handler.setWhitelist(this.getInstalledUpgrades(Upgrades.INVERTER) > 0 ? IncludeExclude.BLACKLIST
|
||||
: IncludeExclude.WHITELIST);
|
||||
this.handler.setPriority(this.getPriority());
|
||||
|
||||
final IItemList<IAEFluidStack> priorityList = AEApi.instance().storage()
|
||||
.getStorageChannel(IFluidStorageChannel.class).createList();
|
||||
|
||||
final int slotsToUse = 18 + this.getInstalledUpgrades(Upgrades.CAPACITY) * 9;
|
||||
for (int x = 0; x < this.config.getSlots() && x < slotsToUse; x++) {
|
||||
final IAEFluidStack is = this.config.getFluidInSlot(x);
|
||||
if (is != null) {
|
||||
priorityList.add(is);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.getInstalledUpgrades(Upgrades.FUZZY) > 0) {
|
||||
this.handler.setPartitionList(new FuzzyPriorityList<IAEFluidStack>(priorityList,
|
||||
(FuzzyMode) this.getConfigManager().getSetting(Settings.FUZZY_MODE)));
|
||||
} else {
|
||||
this.handler.setPartitionList(new PrecisePriorityList<IAEFluidStack>(priorityList));
|
||||
}
|
||||
|
||||
if (inv instanceof IBaseMonitor) {
|
||||
((IBaseMonitor<IAEFluidStack>) inv).addListener(this, this.handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update sleep state...
|
||||
if (wasSleeping != (this.monitor == null)) {
|
||||
try {
|
||||
final ITickManager tm = this.getProxy().getTick();
|
||||
if (this.monitor == null) {
|
||||
tm.sleepDevice(this.getProxy().getNode());
|
||||
} else {
|
||||
tm.wakeDevice(this.getProxy().getNode());
|
||||
}
|
||||
} catch (final GridAccessException ignore) {
|
||||
// :(
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// force grid to update handlers...
|
||||
this.getProxy().getGrid().postEvent(new MENetworkCellArrayUpdate());
|
||||
} catch (final GridAccessException ignore) {
|
||||
// :3
|
||||
}
|
||||
|
||||
return this.handler;
|
||||
}
|
||||
|
||||
private void checkInterfaceVsStorageBus(final BlockEntity target, final AEPartLocation side) {
|
||||
IInterfaceHost achievement = null;
|
||||
|
||||
if (target instanceof IInterfaceHost) {
|
||||
achievement = (IInterfaceHost) target;
|
||||
}
|
||||
|
||||
if (target instanceof IPartHost) {
|
||||
final Object part = ((IPartHost) target).getPart(side);
|
||||
if (part instanceof IInterfaceHost) {
|
||||
achievement = (IInterfaceHost) part;
|
||||
}
|
||||
}
|
||||
|
||||
if (achievement != null && achievement.getActionableNode() != null) {
|
||||
// Platform.increaseStat( achievement.getActionableNode().getPlayerID(),
|
||||
// Achievements.Recursive.getAchievement()
|
||||
// );
|
||||
// Platform.increaseStat( getActionableNode().getPlayerID(),
|
||||
// Achievements.Recursive.getAchievement() );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IMEInventoryHandler> getCellArray(final IStorageChannel channel) {
|
||||
if (channel == this.getStorageChannel()) {
|
||||
final IMEInventoryHandler<IAEFluidStack> out = this.getProxy().isActive() ? this.getInternalHandler()
|
||||
: null;
|
||||
if (out != null) {
|
||||
return Collections.singletonList(out);
|
||||
}
|
||||
}
|
||||
return super.getCellArray(channel);
|
||||
}
|
||||
|
||||
private int createHandlerHash(BlockEntity target) {
|
||||
if (target == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
IStorageMonitorableAccessor accessor = MEAttributes.getAttributeInFrontOfPart(
|
||||
MEAttributes.STORAGE_MONITORABLE_ACCESSOR, this);
|
||||
if (accessor != null) {
|
||||
return Objects.hash(target, accessor);
|
||||
}
|
||||
|
||||
final GroupedFluidInv groupedInv = MEAttributes.getAttributeInFrontOfPart(
|
||||
FluidAttributes.GROUPED_INV, this);
|
||||
if (groupedInv != null) {
|
||||
return Objects.hash(target, groupedInv);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickingRequest getTickingRequest(IGridNode node) {
|
||||
return new TickingRequest(TickRates.FluidStorageBus.getMin(), TickRates.FluidStorageBus.getMax(),
|
||||
this.isSleeping(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onListUpdate() {
|
||||
// not used here.
|
||||
}
|
||||
|
||||
@Override
|
||||
public IStorageChannel getStorageChannel() {
|
||||
return AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class);
|
||||
}
|
||||
|
||||
public IAEFluidTank getConfig() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public IPartModel getStaticModels() {
|
||||
if (this.isActive() && this.isPowered()) {
|
||||
return MODELS_HAS_CHANNEL;
|
||||
} else if (this.isPowered()) {
|
||||
return MODELS_ON;
|
||||
} else {
|
||||
return MODELS_OFF;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemStackRepresentation() {
|
||||
return AEApi.instance().definitions().parts().fluidStorageBus().maybeStack(1).orElse(ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScreenHandlerType<?> getContainerType() {
|
||||
return FluidStorageBusContainer.TYPE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, 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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.fluids.parts;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.screen.ScreenHandlerType;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import appeng.api.parts.IPartModel;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.fluids.container.FluidTerminalContainer;
|
||||
import appeng.items.parts.PartModels;
|
||||
import appeng.parts.PartModel;
|
||||
import appeng.parts.reporting.AbstractTerminalPart;
|
||||
|
||||
/**
|
||||
* @author BrockWS
|
||||
* @version rv6 - 12/05/2018
|
||||
* @since rv6 12/05/2018
|
||||
*/
|
||||
public class FluidTerminalPart extends AbstractTerminalPart {
|
||||
|
||||
@PartModels
|
||||
public static final Identifier MODEL_OFF = new Identifier(AppEng.MOD_ID, "part/fluid_terminal_off");
|
||||
@PartModels
|
||||
public static final Identifier MODEL_ON = new Identifier(AppEng.MOD_ID, "part/fluid_terminal_on");
|
||||
|
||||
public static final IPartModel MODELS_OFF = new PartModel(MODEL_BASE, MODEL_OFF, MODEL_STATUS_OFF);
|
||||
public static final IPartModel MODELS_ON = new PartModel(MODEL_BASE, MODEL_ON, MODEL_STATUS_ON);
|
||||
public static final IPartModel MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE, MODEL_ON, MODEL_STATUS_HAS_CHANNEL);
|
||||
|
||||
public FluidTerminalPart(ItemStack is) {
|
||||
super(is);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScreenHandlerType<?> getContainerType(PlayerEntity player) {
|
||||
return FluidTerminalContainer.TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPartModel getStaticModels() {
|
||||
return this.selectModel(MODELS_OFF, MODELS_ON, MODELS_HAS_CHANNEL);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, 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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.fluids.parts;
|
||||
|
||||
import alexiil.mc.lib.attributes.Attribute;
|
||||
import alexiil.mc.lib.attributes.SearchOptions;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.*;
|
||||
import net.minecraft.world.BlockView;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.config.RedstoneMode;
|
||||
import appeng.api.config.Upgrades;
|
||||
import appeng.api.networking.ticking.IGridTickable;
|
||||
import appeng.api.networking.ticking.TickRateModulation;
|
||||
import appeng.api.parts.IPartCollisionHelper;
|
||||
import appeng.api.storage.channels.IFluidStorageChannel;
|
||||
import appeng.api.util.AECableType;
|
||||
import appeng.container.ContainerLocator;
|
||||
import appeng.container.ContainerOpener;
|
||||
import appeng.fluids.container.FluidIOContainer;
|
||||
import appeng.fluids.util.AEFluidInventory;
|
||||
import appeng.fluids.util.IAEFluidTank;
|
||||
import appeng.me.GridAccessException;
|
||||
import appeng.parts.automation.UpgradeablePart;
|
||||
import appeng.util.Platform;
|
||||
|
||||
/**
|
||||
* @author BrockWS
|
||||
* @version rv6 - 30/04/2018
|
||||
* @since rv6 30/04/2018
|
||||
*/
|
||||
public abstract class SharedFluidBusPart extends UpgradeablePart implements IGridTickable {
|
||||
|
||||
private final AEFluidInventory config = new AEFluidInventory(null, 9);
|
||||
private boolean lastRedstone;
|
||||
|
||||
public SharedFluidBusPart(ItemStack is) {
|
||||
super(is);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upgradesChanged() {
|
||||
this.updateState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onneighborUpdate(BlockView w, BlockPos pos, BlockPos neighbor) {
|
||||
this.updateState();
|
||||
if (this.lastRedstone != this.getHost().hasRedstone(this.getSide())) {
|
||||
this.lastRedstone = !this.lastRedstone;
|
||||
if (this.lastRedstone && this.getRSMode() == RedstoneMode.SIGNAL_PULSE) {
|
||||
this.doBusWork();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateState() {
|
||||
try {
|
||||
if (!this.isSleeping()) {
|
||||
this.getProxy().getTick().wakeDevice(this.getProxy().getNode());
|
||||
} else {
|
||||
this.getProxy().getTick().sleepDevice(this.getProxy().getNode());
|
||||
}
|
||||
} catch (final GridAccessException e) {
|
||||
// :P
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPartActivate(final PlayerEntity player, final Hand hand, final Vec3d pos) {
|
||||
if (Platform.isServer()) {
|
||||
ContainerOpener.openContainer(FluidIOContainer.TYPE, player, ContainerLocator.forPart(this));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getBoxes(IPartCollisionHelper bch) {
|
||||
bch.addBox(6, 6, 11, 10, 10, 13);
|
||||
bch.addBox(5, 5, 13, 11, 11, 14);
|
||||
bch.addBox(4, 4, 14, 12, 12, 16);
|
||||
}
|
||||
|
||||
protected int calculateAmountToSend() {
|
||||
double amount = this.getChannel().transferFactor();
|
||||
switch (this.getInstalledUpgrades(Upgrades.SPEED)) {
|
||||
case 4:
|
||||
amount = amount * 1.5;
|
||||
case 3:
|
||||
amount = amount * 2;
|
||||
case 2:
|
||||
amount = amount * 4;
|
||||
case 1:
|
||||
amount = amount * 8;
|
||||
case 0:
|
||||
default:
|
||||
return MathHelper.floor(amount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromNBT(CompoundTag extra) {
|
||||
super.readFromNBT(extra);
|
||||
this.config.readFromNBT(extra, "config");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToNBT(CompoundTag extra) {
|
||||
super.writeToNBT(extra);
|
||||
this.config.writeToNBT(extra, "config");
|
||||
}
|
||||
|
||||
public IAEFluidTank getConfig() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
protected IFluidStorageChannel getChannel() {
|
||||
return AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCableConnectionLength(AECableType cable) {
|
||||
return 5;
|
||||
}
|
||||
|
||||
protected abstract TickRateModulation doBusWork();
|
||||
|
||||
protected abstract boolean canDoBusWork();
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2015, 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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.fluids.registries;
|
||||
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.implementations.tiles.IChestOrDrive;
|
||||
import appeng.api.storage.IMEInventoryHandler;
|
||||
import appeng.api.storage.IStorageChannel;
|
||||
import appeng.api.storage.cells.ICellGuiHandler;
|
||||
import appeng.api.storage.cells.ICellHandler;
|
||||
import appeng.api.storage.channels.IFluidStorageChannel;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.container.ContainerLocator;
|
||||
import appeng.container.ContainerOpener;
|
||||
import appeng.fluids.container.FluidTerminalContainer;
|
||||
|
||||
public class BasicFluidCellGuiHandler implements ICellGuiHandler {
|
||||
|
||||
@Override
|
||||
public <T extends IAEStack<T>> boolean isHandlerFor(final IStorageChannel<T> channel) {
|
||||
return channel == AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openChestGui(final PlayerEntity player, final IChestOrDrive chest, final ICellHandler cellHandler,
|
||||
final IMEInventoryHandler inv, final ItemStack is, final IStorageChannel chan) {
|
||||
ContainerOpener.openContainer(FluidTerminalContainer.TYPE, player,
|
||||
ContainerLocator.forTileEntitySide((BlockEntity) chest, chest.getUp()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, 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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.fluids.tile;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import alexiil.mc.lib.attributes.AttributeList;
|
||||
import alexiil.mc.lib.attributes.item.FixedItemInv;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.screen.ScreenHandlerType;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.config.Upgrades;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.events.MENetworkChannelsChanged;
|
||||
import appeng.api.networking.events.MENetworkEventSubscribe;
|
||||
import appeng.api.networking.events.MENetworkPowerStatusChange;
|
||||
import appeng.api.networking.ticking.IGridTickable;
|
||||
import appeng.api.networking.ticking.TickRateModulation;
|
||||
import appeng.api.networking.ticking.TickingRequest;
|
||||
import appeng.api.util.AECableType;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.api.util.DimensionalCoord;
|
||||
import appeng.api.util.IConfigManager;
|
||||
import appeng.fluids.container.FluidInterfaceContainer;
|
||||
import appeng.fluids.helper.DualityFluidInterface;
|
||||
import appeng.fluids.helper.IFluidInterfaceHost;
|
||||
import appeng.helpers.IPriorityHost;
|
||||
import appeng.tile.grid.AENetworkBlockEntity;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class FluidInterfaceBlockEntity extends AENetworkBlockEntity
|
||||
implements IGridTickable, IFluidInterfaceHost, IPriorityHost {
|
||||
private final DualityFluidInterface duality = new DualityFluidInterface(this.getProxy(), this);
|
||||
|
||||
public FluidInterfaceBlockEntity(BlockEntityType<?> tileEntityTypeIn) {
|
||||
super(tileEntityTypeIn);
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void stateChange(final MENetworkChannelsChanged c) {
|
||||
this.duality.notifyNeighbors();
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void stateChange(final MENetworkPowerStatusChange c) {
|
||||
this.duality.notifyNeighbors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickingRequest getTickingRequest(IGridNode node) {
|
||||
return this.duality.getTickingRequest(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickRateModulation tickingRequest(IGridNode node, int ticksSinceLastCall) {
|
||||
return this.duality.tickingRequest(node, ticksSinceLastCall);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DualityFluidInterface getDualityFluidInterface() {
|
||||
return this.duality;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockEntity getBlockEntity() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gridChanged() {
|
||||
this.duality.gridChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag toTag(final CompoundTag data) {
|
||||
super.toTag(data);
|
||||
this.duality.writeToNBT(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromTag(BlockState state, final CompoundTag data) {
|
||||
super.fromTag(state, data);
|
||||
this.duality.readFromNBT(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AECableType getCableConnectionType(final AEPartLocation dir) {
|
||||
return this.duality.getCableConnectionType(dir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DimensionalCoord getLocation() {
|
||||
return this.duality.getLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<Direction> getTargets() {
|
||||
return EnumSet.allOf(Direction.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority() {
|
||||
return this.duality.getPriority();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPriority(final int newValue) {
|
||||
this.duality.setPriority(newValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAllAttributes(World world, BlockPos pos, BlockState state, AttributeList<?> to) {
|
||||
super.addAllAttributes(world, pos, state, to);
|
||||
duality.addAllAttributes(to);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInstalledUpgrades(Upgrades u) {
|
||||
return this.duality.getInstalledUpgrades(u);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IConfigManager getConfigManager() {
|
||||
return this.duality.getConfigManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FixedItemInv getInventoryByName(String name) {
|
||||
return this.duality.getInventoryByName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemStackRepresentation() {
|
||||
return AEApi.instance().definitions().blocks().fluidIface().maybeStack(1).orElse(ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScreenHandlerType<?> getContainerType() {
|
||||
return FluidInterfaceContainer.TYPE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
|
||||
package appeng.fluids.util;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Objects;
|
||||
|
||||
import alexiil.mc.lib.attributes.ListenerRemovalToken;
|
||||
import alexiil.mc.lib.attributes.ListenerToken;
|
||||
import alexiil.mc.lib.attributes.Simulation;
|
||||
import alexiil.mc.lib.attributes.fluid.FluidInvTankChangeListener;
|
||||
import alexiil.mc.lib.attributes.fluid.FluidVolumeUtil;
|
||||
import alexiil.mc.lib.attributes.fluid.amount.FluidAmount;
|
||||
import alexiil.mc.lib.attributes.fluid.volume.FluidKey;
|
||||
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.core.AELog;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public class AEFluidInventory implements IAEFluidTank {
|
||||
private final IAEFluidStack[] fluids;
|
||||
private final IAEFluidInventory handler;
|
||||
private final int capacity;
|
||||
|
||||
public AEFluidInventory(final IAEFluidInventory handler, final int slots, final int capacity) {
|
||||
this.fluids = new IAEFluidStack[slots];
|
||||
this.handler = handler;
|
||||
this.capacity = capacity;
|
||||
}
|
||||
|
||||
public AEFluidInventory(final IAEFluidInventory handler, final int slots) {
|
||||
this(handler, slots, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setInvFluid(int tank, FluidVolume to, Simulation simulation) {
|
||||
if (tank >= 0 && tank < this.getSlots()) {
|
||||
if (simulation == Simulation.ACTION) {
|
||||
setFluidInSlot(tank, AEFluidStack.fromFluidVolume(to, RoundingMode.DOWN));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFluidInSlot(final int slot, final IAEFluidStack fluid) {
|
||||
if (slot >= 0 && slot < this.getSlots()) {
|
||||
if (Objects.equals(this.fluids[slot], fluid)) {
|
||||
if (fluid != null && fluid.getStackSize() != this.fluids[slot].getStackSize()) {
|
||||
this.fluids[slot].setStackSize(Math.min(fluid.getStackSize(), this.capacity));
|
||||
this.onContentChanged(slot);
|
||||
}
|
||||
} else {
|
||||
if (fluid == null) {
|
||||
this.fluids[slot] = null;
|
||||
} else {
|
||||
this.fluids[slot] = fluid.copy();
|
||||
this.fluids[slot].setStackSize(Math.min(fluid.getStackSize(), this.capacity));
|
||||
}
|
||||
|
||||
this.onContentChanged(slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onContentChanged(final int slot) {
|
||||
if (this.handler != null && Platform.isServer()) {
|
||||
this.handler.onFluidInventoryChanged(this, slot);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEFluidStack getFluidInSlot(final int slot) {
|
||||
if (slot >= 0 && slot < this.getSlots()) {
|
||||
return this.fluids[slot];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlots() {
|
||||
return this.fluids.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTankCount() {
|
||||
return this.fluids.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidAmount getMaxAmount_F(int tank) {
|
||||
return FluidAmount.of(Math.min(this.capacity, Integer.MAX_VALUE), 1000);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidVolume getInvFluid(int tank) {
|
||||
if (tank < 0 || tank >= fluids.length) {
|
||||
return FluidVolumeUtil.EMPTY;
|
||||
}
|
||||
return fluids[tank] == null ? FluidVolumeUtil.EMPTY : fluids[tank].getFluidStack();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFluidValidForTank(int tank, FluidKey fluid) {
|
||||
return !fluid.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenerToken addListener(FluidInvTankChangeListener listener, ListenerRemovalToken removalToken) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int fill(final int slot, final FluidVolume resource, final boolean doFill) {
|
||||
if (resource.isEmpty() || resource.getAmount() <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
final IAEFluidStack fluid = this.fluids[slot];
|
||||
|
||||
if (fluid != null && !fluid.getFluidStack().equals(resource)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amountToStore = this.capacity;
|
||||
|
||||
if (fluid != null) {
|
||||
amountToStore -= fluid.getStackSize();
|
||||
}
|
||||
|
||||
amountToStore = Math.min(amountToStore, (int) resource.getAmount_F().asLong(1000, RoundingMode.DOWN));
|
||||
|
||||
if (doFill) {
|
||||
if (fluid == null) {
|
||||
this.setFluidInSlot(slot, AEFluidStack.fromFluidVolume(resource, RoundingMode.DOWN));
|
||||
} else {
|
||||
fluid.setStackSize(fluid.getStackSize() + amountToStore);
|
||||
this.onContentChanged(slot);
|
||||
}
|
||||
}
|
||||
|
||||
return amountToStore;
|
||||
}
|
||||
|
||||
public FluidVolume drain(final int slot, final FluidVolume resource, final boolean doDrain) {
|
||||
final IAEFluidStack fluid = this.fluids[slot];
|
||||
if (resource.isEmpty() || fluid == null || !fluid.getFluidStack().equals(resource)) {
|
||||
return null;
|
||||
}
|
||||
int toDrain = (int) resource.getAmount_F().asLong(1000, RoundingMode.DOWN);
|
||||
return this.drain(slot, toDrain, doDrain);
|
||||
}
|
||||
|
||||
public FluidVolume drain(final int slot, final int maxDrain, boolean doDrain) {
|
||||
final IAEFluidStack fluid = this.fluids[slot];
|
||||
if (fluid == null || maxDrain <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int drained = maxDrain;
|
||||
if (fluid.getStackSize() < drained) {
|
||||
drained = (int) fluid.getStackSize();
|
||||
}
|
||||
|
||||
FluidVolume stack = fluid.getFluidStack().withAmount(FluidAmount.of(drained, 1000));
|
||||
if (doDrain) {
|
||||
fluid.setStackSize(fluid.getStackSize() - drained);
|
||||
if (fluid.getStackSize() <= 0) {
|
||||
this.fluids[slot] = null;
|
||||
}
|
||||
this.onContentChanged(slot);
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
|
||||
public void writeToNBT(final CompoundTag data, final String name) {
|
||||
final CompoundTag c = new CompoundTag();
|
||||
this.writeToNBT(c);
|
||||
data.put(name, c);
|
||||
}
|
||||
|
||||
private void writeToNBT(final CompoundTag target) {
|
||||
for (int x = 0; x < this.fluids.length; x++) {
|
||||
try {
|
||||
final CompoundTag c = new CompoundTag();
|
||||
|
||||
if (this.fluids[x] != null) {
|
||||
this.fluids[x].writeToNBT(c);
|
||||
}
|
||||
|
||||
target.put("#" + x, c);
|
||||
} catch (final Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void readFromNBT(final CompoundTag data, final String name) {
|
||||
final CompoundTag c = data.getCompound(name);
|
||||
if (!c.isEmpty()) {
|
||||
this.readFromNBT(c);
|
||||
}
|
||||
}
|
||||
|
||||
private void readFromNBT(final CompoundTag target) {
|
||||
for (int x = 0; x < this.fluids.length; x++) {
|
||||
try {
|
||||
final CompoundTag c = target.getCompound("#" + x);
|
||||
|
||||
if (!c.isEmpty()) {
|
||||
this.fluids[x] = AEFluidStack.fromNBT(c);
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
AELog.debug(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, 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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.fluids.util;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import appeng.api.config.SortDir;
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.util.Platform;
|
||||
|
||||
/**
|
||||
* @author BrockWS
|
||||
* @version rv6 - 22/05/2018
|
||||
* @since rv6 22/05/2018
|
||||
*/
|
||||
public class FluidSorters {
|
||||
private static SortDir Direction = SortDir.ASCENDING;
|
||||
|
||||
public static final Comparator<IAEFluidStack> CONFIG_BASED_SORT_BY_NAME = (o1, o2) -> {
|
||||
// FIXME: Calling .getString() to compare two untranslated strings is a problem,
|
||||
// we need to investigate how to do this better
|
||||
if (getDirection() == SortDir.ASCENDING) {
|
||||
return Platform.getFluidDisplayName(o1).getString()
|
||||
.compareToIgnoreCase(Platform.getFluidDisplayName(o2).getString());
|
||||
}
|
||||
return Platform.getFluidDisplayName(o2).getString()
|
||||
.compareToIgnoreCase(Platform.getFluidDisplayName(o1).getString());
|
||||
};
|
||||
|
||||
public static final Comparator<IAEFluidStack> CONFIG_BASED_SORT_BY_MOD = new Comparator<IAEFluidStack>() {
|
||||
|
||||
@Override
|
||||
public int compare(final IAEFluidStack o1, final IAEFluidStack o2) {
|
||||
final AEFluidStack op1 = (AEFluidStack) o1;
|
||||
final AEFluidStack op2 = (AEFluidStack) o2;
|
||||
|
||||
if (getDirection() == SortDir.ASCENDING) {
|
||||
return this.secondarySort(Platform.getModId(op1).compareToIgnoreCase(Platform.getModId(op2)), o2, o1);
|
||||
}
|
||||
return this.secondarySort(Platform.getModId(op2).compareToIgnoreCase(Platform.getModId(op1)), o1, o2);
|
||||
}
|
||||
|
||||
private int secondarySort(final int compareToIgnoreCase, final IAEFluidStack o1, final IAEFluidStack o2) {
|
||||
if (compareToIgnoreCase == 0) {
|
||||
// FIXME: Calling .getString() to compare two untranslated strings is a problem,
|
||||
// we need to investigate how to do this better
|
||||
return Platform.getFluidDisplayName(o2).getString()
|
||||
.compareToIgnoreCase(Platform.getFluidDisplayName(o1).getString());
|
||||
}
|
||||
|
||||
return compareToIgnoreCase;
|
||||
}
|
||||
};
|
||||
|
||||
public static final Comparator<IAEFluidStack> CONFIG_BASED_SORT_BY_SIZE = (o1, o2) -> {
|
||||
if (getDirection() == SortDir.ASCENDING) {
|
||||
return Long.compare(o2.getStackSize(), o1.getStackSize());
|
||||
}
|
||||
return Long.compare(o1.getStackSize(), o2.getStackSize());
|
||||
};
|
||||
|
||||
private static SortDir getDirection() {
|
||||
return Direction;
|
||||
}
|
||||
|
||||
public static void setDirection(final SortDir direction) {
|
||||
Direction = direction;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, 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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.fluids.util;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface IAEFluidInventory {
|
||||
void onFluidInventoryChanged(final IAEFluidTank inv, final int slot);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
package appeng.fluids.util;
|
||||
|
||||
import alexiil.mc.lib.attributes.fluid.FixedFluidInv;
|
||||
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
|
||||
public interface IAEFluidTank extends FixedFluidInv {
|
||||
void setFluidInSlot(final int slot, final IAEFluidStack fluid);
|
||||
|
||||
IAEFluidStack getFluidInSlot(final int slot);
|
||||
|
||||
int getSlots();
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user