Merge remote-tracking branch 'origin/master' into fabric/master

# Conflicts:
#	src/main/java/appeng/client/gui/AEBaseScreen.java
#	src/main/java/appeng/client/gui/widgets/CustomSlotWidget.java
#	src/main/java/appeng/client/gui/widgets/ITooltip.java
#	src/main/java/appeng/client/gui/widgets/IconButton.java
#	src/main/java/appeng/client/gui/widgets/ProgressBar.java
#	src/main/java/appeng/client/gui/widgets/SettingToggleButton.java
#	src/main/java/appeng/client/gui/widgets/ToggleButton.java
#	src/main/java/appeng/container/slot/PlayerInvSlot.java
#	src/main/java/appeng/fluids/client/gui/widgets/FluidSlotWidget.java
#	src/main/java/appeng/fluids/client/gui/widgets/FluidTankWidget.java
#	src/main/java/appeng/fluids/client/gui/widgets/OptionalFluidSlotWidget.java
#	src/main/java/appeng/fluids/parts/FluidAnnihilationPlanePart.java
#	src/main/java/appeng/parts/automation/AbstractFormationPlanePart.java
#	src/main/java/appeng/parts/automation/AnnihilationPlanePart.java
#	src/main/java/appeng/parts/automation/FormationPlanePart.java
#	src/main/java/appeng/parts/automation/IdentityAnnihilationPlanePart.java
#	src/main/java/appeng/parts/p2p/FluidP2PTunnelPart.java
This commit is contained in:
Sebastian Hartte
2020-08-05 23:40:58 +02:00
21 changed files with 591 additions and 580 deletions
@@ -168,14 +168,14 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends HandledScr
protected void drawGuiSlot(MatrixStack matrices, CustomSlotWidget slot, int mouseX, int mouseY,
float partialTicks) {
if (slot.isSlotEnabled()) {
final int left = slot.xPos();
final int top = slot.yPos();
final int right = left + slot.getWidth();
final int bottom = top + slot.getHeight();
final int left = slot.getTooltipAreaX();
final int top = slot.getTooltipAreaY();
final int right = left + slot.getTooltipAreaWidth();
final int bottom = top + slot.getTooltipAreaHeight();
slot.drawContent(getClient(), mouseX, mouseY, partialTicks);
if (this.isPointWithinBounds(left, top, slot.getWidth(), slot.getHeight(), mouseX, mouseY)
if (this.isPointWithinBounds(left, top, slot.getTooltipAreaWidth(), slot.getTooltipAreaHeight(), mouseX, mouseY)
&& slot.canClick(getPlayer())) {
RenderSystem.colorMask(true, true, true, false);
this.fillGradient(matrices, left, top, right, bottom, -2130706433, -2130706433);
@@ -185,27 +185,28 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends HandledScr
}
private void drawTooltip(MatrixStack matrices, ITooltip tooltip, int mouseX, int mouseY) {
final int x = tooltip.xPos();
int y = tooltip.yPos();
final int x = tooltip.getTooltipAreaX();
int y = tooltip.getTooltipAreaY();
if (x < mouseX && x + tooltip.getWidth() > mouseX && tooltip.isVisible()) {
if (y < mouseY && y + tooltip.getHeight() > mouseY) {
if (x < mouseX && x + tooltip.getTooltipAreaWidth() > mouseX && tooltip.isTooltipAreaVisible()) {
if (y < mouseY && y + tooltip.getTooltipAreaHeight() > mouseY) {
if (y < 15) {
y = 15;
}
final Text msg = tooltip.getMessage();
if (msg != null && !msg.getString().isEmpty()) {
this.drawTooltip(matrices, x + 11, y + 4, msg);
}
final Text msg = tooltip.getTooltipMessage();
this.drawTooltip(matrices, x + 11, y + 4, msg);
}
}
}
protected void drawTooltip(MatrixStack matrices, int x, int y, Text message) {
String[] lines = message.getString().split("\n"); // FIXME FABRIC
List<Text> textLines = Arrays.stream(lines).map(LiteralText::new).collect(Collectors.toList());
this.drawTooltip(matrices, x, y, textLines);
String tooltipText = message.getString();
if (!tooltipText.isEmpty()) {
String[] lines = tooltipText.split("\n"); // FIXME FABRIC
List<Text> textLines = Arrays.stream(lines).map(LiteralText::new).collect(Collectors.toList());
this.drawTooltip(matrices, x, y, textLines);}
}
// FIXME FABRIC: move out to json (?)
@@ -290,8 +291,8 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends HandledScr
}
for (CustomSlotWidget slot : this.guiSlots) {
if (this.isPointWithinBounds(slot.xPos(), slot.yPos(), slot.getWidth(), slot.getHeight(), xCoord, yCoord)
&& slot.canClick(getPlayer())) {
if (this.isPointWithinBounds(slot.getTooltipAreaX(), slot.getTooltipAreaY(), slot.getTooltipAreaWidth(),
slot.getTooltipAreaHeight(), xCoord, yCoord) && slot.canClick(getPlayer())) {
slot.slotClicked(getPlayer().inventory.getCursorStack(), btn);
}
}
@@ -27,7 +27,7 @@ import net.minecraft.text.Text;
import appeng.api.config.ActionItems;
import appeng.core.localization.ButtonToolTips;
public class ActionButton extends IconButton implements ITooltip {
public class ActionButton extends IconButton {
private static final Pattern PATTERN_NEW_LINE = Pattern.compile("\\n", Pattern.LITERAL);
private final int iconIndex;
@@ -6,6 +6,7 @@ import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
public abstract class CustomSlotWidget extends DrawableHelper implements ITooltip {
@@ -37,32 +38,32 @@ public abstract class CustomSlotWidget extends DrawableHelper implements IToolti
}
@Override
public Text getMessage() {
return null;
public Text getTooltipMessage() {
return LiteralText.EMPTY;
}
@Override
public int xPos() {
public int getTooltipAreaX() {
return this.x;
}
@Override
public int yPos() {
public int getTooltipAreaY() {
return this.y;
}
@Override
public int getWidth() {
public int getTooltipAreaWidth() {
return 16;
}
@Override
public int getHeight() {
public int getTooltipAreaHeight() {
return 16;
}
@Override
public boolean isVisible() {
public boolean isTooltipAreaVisible() {
return false;
}
@@ -20,48 +20,53 @@ package appeng.client.gui.widgets;
import net.minecraft.text.Text;
import javax.annotation.Nonnull;
/**
* AEBaseGui controlled Tooltip Interface.
*/
public interface ITooltip {
/**
* returns the tooltip message.
* Returns the tooltip message.
*
* Should use {@link net.minecraft.text.LiteralText#EMPTY} for no tooltip
*
* @return tooltip message
*/
Text getMessage();
@Nonnull
Text getTooltipMessage();
/**
* x Location for the object that triggers the tooltip.
*
* @return xPosition
*/
int xPos();
int getTooltipAreaX();
/**
* y Location for the object that triggers the tooltip.
*
* @return yPosition
*/
int yPos();
int getTooltipAreaY();
/**
* Width of the object that triggers the tooltip.
*
* @return width
*/
int getWidth();
int getTooltipAreaWidth();
/**
* Height for the object that triggers the tooltip.
*
* @return height
*/
int getHeight();
int getTooltipAreaHeight();
/**
* @return true if button being drawn
*/
boolean isVisible();
boolean isTooltipAreaVisible();
}
@@ -25,6 +25,7 @@ import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.texture.TextureManager;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
public abstract class IconButton extends ButtonWidget implements ITooltip {
@@ -95,27 +96,32 @@ public abstract class IconButton extends ButtonWidget implements ITooltip {
protected abstract int getIconIndex();
@Override
public int xPos() {
public Text getTooltipMessage() {
return getMessage();
}
@Override
public int getTooltipAreaX() {
return this.x;
}
@Override
public int yPos() {
public int getTooltipAreaY() {
return this.y;
}
@Override
public int getWidth() {
public int getTooltipAreaWidth() {
return this.halfSize ? 8 : 16;
}
@Override
public int getHeight() {
public int getTooltipAreaHeight() {
return this.halfSize ? 8 : 16;
}
@Override
public boolean isVisible() {
public boolean isTooltipAreaVisible() {
return this.visible;
}
@@ -77,7 +77,7 @@ public class ProgressBar extends AbstractButtonWidget implements ITooltip {
}
@Override
public Text getMessage() {
public Text getTooltipMessage() {
if (this.fullMsg != null) {
return this.fullMsg;
}
@@ -88,27 +88,27 @@ public class ProgressBar extends AbstractButtonWidget implements ITooltip {
}
@Override
public int xPos() {
public int getTooltipAreaX() {
return this.x - 2;
}
@Override
public int yPos() {
public int getTooltipAreaY() {
return this.y - 2;
}
@Override
public int getWidth() {
public int getTooltipAreaWidth() {
return this.width + 4;
}
@Override
public int getHeight() {
public int getTooltipAreaHeight() {
return this.height + 4;
}
@Override
public boolean isVisible() {
public boolean isTooltipAreaVisible() {
return true;
}
@@ -279,7 +279,7 @@ public class SettingToggleButton<T extends Enum<T>> extends IconButton {
}
@Override
public Text getMessage() {
public Text getTooltipMessage() {
Text displayName = null;
Text displayValue = null;
@@ -93,27 +93,32 @@ public class TabButton extends ButtonWidget implements ITooltip {
}
@Override
public int xPos() {
public ITextComponent getTooltipMessage() {
return getMessage();
}
@Override
public int getTooltipAreaX() {
return this.x;
}
@Override
public int yPos() {
public int getTooltipAreaY() {
return this.y;
}
@Override
public int getWidth() {
public int getTooltipAreaWidth() {
return 22;
}
@Override
public int getHeight() {
public int getTooltipAreaHeight() {
return 22;
}
@Override
public boolean isVisible() {
public boolean isTooltipAreaVisible() {
return this.visible;
}
@@ -74,7 +74,7 @@ public class ToggleButton extends ButtonWidget implements ITooltip {
}
@Override
public Text getMessage() {
public Text getTooltipMessage() {
if (this.displayName != null) {
String name = this.displayName.getString();
String value = this.displayHint.getString();
@@ -96,27 +96,27 @@ public class ToggleButton extends ButtonWidget implements ITooltip {
}
@Override
public int xPos() {
public int getTooltipAreaX() {
return this.x;
}
@Override
public int yPos() {
public int getTooltipAreaY() {
return this.y;
}
@Override
public int getWidth() {
public int getTooltipAreaWidth() {
return 16;
}
@Override
public int getHeight() {
public int getTooltipAreaHeight() {
return 16;
}
@Override
public boolean isVisible() {
public boolean isTooltipAreaVisible() {
return this.visible;
}
}
@@ -53,7 +53,7 @@ public class FormationPlaneContainer extends UpgradeableContainer {
return helper.open(player, locator);
}
@GuiSync(6)
@GuiSync(7)
public YesNo placeMode;
public FormationPlaneContainer(int id, final PlayerInventory ip, final FormationPlanePart te) {
+1 -1
View File
@@ -49,7 +49,7 @@ public class FacadePart implements IFacadePart {
@Override
public void getBoxes(final IPartCollisionHelper ch, boolean livingEntity) {
if (livingEntity) {
if (livingEntity || !ch.isBBCollision()) {
// prevent weird snag behavior
ch.addBox(0.0, 0.0, 14, 16.0, 16.0, 16.0);
} else {
@@ -7,6 +7,7 @@ import java.util.Set;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import alexiil.mc.lib.attributes.fluid.FluidAttributes;
@@ -35,7 +36,12 @@ public class FluidSlotWidget extends CustomSlotWidget {
public void drawContent(final MinecraftClient mc, final int mouseX, final int mouseY, final float partialTicks) {
final IAEFluidStack fs = this.getFluidStack();
if (fs != null) {
fs.getFluidStack().renderGuiRect(xPos(), yPos(), xPos() + getWidth(), yPos() + getHeight());
// The tooltip area coincides with the area of the slot
int x = getTooltipAreaX();
int y = getTooltipAreaY();
int width = getTooltipAreaX();
int height = getTooltipAreaY();
fs.getFluidStack().renderGuiRect(x, y, x + width, y + height);
}
}
@@ -61,16 +67,16 @@ public class FluidSlotWidget extends CustomSlotWidget {
}
@Override
public Text getMessage() {
public Text getTooltipMessage() {
final IAEFluidStack fluid = this.getFluidStack();
if (fluid != null) {
return fluid.getFluidStack().getName();
}
return null;
return LiteralText.EMPTY;
}
@Override
public boolean isVisible() {
public boolean isTooltipAreaVisible() {
return true;
}
@@ -83,7 +83,7 @@ public class FluidTankWidget extends AbstractButtonWidget implements ITooltip {
}
@Override
public Text getMessage() {
public Text getTooltipMessage() {
final IAEFluidStack fluid = this.tank.getFluidInSlot(this.slot);
if (fluid != null && fluid.getStackSize() > 0) {
Text desc = fluid.getFluidStack().getName();
@@ -95,27 +95,27 @@ public class FluidTankWidget extends AbstractButtonWidget implements ITooltip {
}
@Override
public int xPos() {
public int getTooltipAreaX() {
return this.x - 2;
}
@Override
public int yPos() {
public int getTooltipAreaY() {
return this.y - 2;
}
@Override
public int getWidth() {
public int getTooltipAreaWidth() {
return this.width + 4;
}
@Override
public int getHeight() {
public int getTooltipAreaHeight() {
return this.height + 4;
}
@Override
public boolean isVisible() {
public boolean isTooltipAreaVisible() {
return true;
}
@@ -50,8 +50,8 @@ public class OptionalFluidSlotWidget extends FluidSlotWidget {
}
int oldZOffset = getZOffset();
setZOffset(currentZIndex);
drawTexture(matrices, guileft + this.xPos() - 1, guitop + this.yPos() - 1, this.srcX - 1, this.srcY - 1,
this.getWidth() + 2, this.getHeight() + 2);
drawTexture(matrices, guileft + this.getTooltipAreaX() - 1, guitop + this.getTooltipAreaY() - 1, this.srcX - 1, this.srcY - 1,
this.getTooltipAreaWidth() + 2, this.getTooltipAreaHeight() + 2);
setZOffset(oldZOffset);
}
}
@@ -38,15 +38,12 @@ 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.Api;
import appeng.core.AppEng;
import appeng.core.settings.TickRates;
@@ -56,6 +53,7 @@ import appeng.items.parts.PartModels;
import appeng.me.GridAccessException;
import appeng.me.helpers.MachineSource;
import appeng.parts.BasicStatePart;
import appeng.parts.automation.PlaneConnectionHelper;
import appeng.parts.automation.PlaneConnections;
import appeng.parts.automation.PlaneModels;
import appeng.util.Platform;
@@ -75,115 +73,27 @@ public class FluidAnnihilationPlanePart extends BasicStatePart implements IGridT
private final IActionSource mySrc = new MachineSource(this);
private final PlaneConnectionHelper connectionHelper = new PlaneConnectionHelper(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);
connectionHelper.getBoxes(bch);
}
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);
return connectionHelper.getConnections();
}
@Override
public void onneighborUpdate(BlockView w, BlockPos pos, BlockPos neighbor) {
if (pos.offset(this.getSide().getFacing()).equals(neighbor)) {
this.refresh();
} else {
connectionHelper.updateConnections();
}
}
@@ -192,14 +102,6 @@ public class FluidAnnihilationPlanePart extends BasicStatePart implements IGridT
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());
@@ -11,9 +11,7 @@ import net.minecraft.world.BlockView;
import appeng.api.config.Actionable;
import appeng.api.config.Settings;
import appeng.api.networking.security.IActionSource;
import appeng.api.parts.IPart;
import appeng.api.parts.IPartCollisionHelper;
import appeng.api.parts.IPartHost;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.cells.ICellContainer;
import appeng.api.storage.cells.ICellInventory;
@@ -30,6 +28,7 @@ public abstract class AbstractFormationPlanePart<T extends IAEStack<T>> extends
private boolean wasActive = false;
private int priority = 0;
protected boolean blocked = false;
private final PlaneConnectionHelper connectionHelper = new PlaneConnectionHelper(this);
public AbstractFormationPlanePart(ItemStack is) {
super(is);
@@ -64,103 +63,11 @@ public abstract class AbstractFormationPlanePart<T extends IAEStack<T>> extends
@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.isTransitionPlane(te.getWorld().getBlockEntity(pos.offset(e.getOpposite())), this.getSide())) {
minX = 0;
}
if (this.isTransitionPlane(te.getWorld().getBlockEntity(pos.offset(e)), this.getSide())) {
maxX = 16;
}
if (this.isTransitionPlane(te.getWorld().getBlockEntity(pos.offset(u.getOpposite())), this.getSide())) {
minY = 0;
}
if (this.isTransitionPlane(te.getWorld().getBlockEntity(pos.offset(u)), this.getSide())) {
maxY = 16;
}
}
bch.addBox(5, 5, 14, 11, 11, 15);
bch.addBox(minX, minY, 15, maxX, maxY, 16);
connectionHelper.getBoxes(bch);
}
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.isTransitionPlane(te.getWorld().getBlockEntity(pos.offset(facingRight.getOpposite())),
this.getSide())) {
left = true;
}
if (this.isTransitionPlane(te.getWorld().getBlockEntity(pos.offset(facingRight)), this.getSide())) {
right = true;
}
if (this.isTransitionPlane(te.getWorld().getBlockEntity(pos.offset(facingUp.getOpposite())),
this.getSide())) {
down = true;
}
if (this.isTransitionPlane(te.getWorld().getBlockEntity(pos.offset(facingUp)), this.getSide())) {
up = true;
}
}
return PlaneConnections.of(up, right, down, left);
return connectionHelper.getConnections();
}
@Override
@@ -172,6 +79,8 @@ public abstract class AbstractFormationPlanePart<T extends IAEStack<T>> extends
final BlockPos tePos = te.getPos().offset(side.getFacing());
this.blocked = isBlocking(w, tePos);
} else {
connectionHelper.updateConnections();
}
}
@@ -184,14 +93,6 @@ public abstract class AbstractFormationPlanePart<T extends IAEStack<T>> extends
return 1;
}
protected boolean isTransitionPlane(final BlockEntity blockTileEntity, final AEPartLocation side) {
if (blockTileEntity instanceof IPartHost) {
final IPart p = ((IPartHost) blockTileEntity).getPart(side);
return p != null && this.getClass() == p.getClass();
}
return false;
}
@Override
public T extractItems(final T request, final Actionable mode, final IActionSource src) {
return null;
@@ -60,9 +60,7 @@ 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.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack;
@@ -98,53 +96,31 @@ public class AnnihilationPlanePart extends BasicStatePart implements IGridTickab
private boolean isAccepting = true;
private boolean breaking = false;
private final PlaneConnectionHelper connectionHelper = new PlaneConnectionHelper(this);
public AnnihilationPlanePart(final ItemStack is) {
super(is);
}
@Override
public TickRateModulation call(final World world) throws Exception {
public TickRateModulation call(final World world) {
this.breaking = false;
return this.breakBlock(true);
}
@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;
}
// For collision, we're using a simplified bounding box
if (bch.isBBCollision()) {
// The smaller collision hitbox here is needed to allow for the entity collision
// event
bch.addBox(0, 0, 14, 16, 16, 15.5);
return;
}
bch.addBox(5, 5, 14, 11, 11, 15);
// The smaller collision hitbox here is needed to allow for the entity collision
// event
bch.addBox(minX, minY, 15, maxX, maxY, bch.isBBCollision() ? 15 : 16);
connectionHelper.getBoxes(bch);
}
/**
@@ -152,73 +128,15 @@ public class AnnihilationPlanePart extends BasicStatePart implements IGridTickab
* visually.
*/
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);
return connectionHelper.getConnections();
}
@Override
public void onneighborUpdate(BlockView w, BlockPos pos, BlockPos neighbor) {
if (pos.offset(this.getSide().getFacing()).equals(neighbor)) {
this.refresh();
} else {
connectionHelper.updateConnections();
}
}
@@ -363,14 +281,6 @@ public class AnnihilationPlanePart extends BasicStatePart implements IGridTickab
return changed;
}
protected 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;
}
@Override
@MENetworkEventSubscribe
public void chanRender(final MENetworkChannelsChanged c) {
@@ -21,11 +21,13 @@ package appeng.parts.automation;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.annotation.Nullable;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.*;
@@ -49,7 +51,6 @@ 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.IPartItem;
import appeng.api.parts.IPartModel;
import appeng.api.storage.IMEInventoryHandler;
import appeng.api.storage.IStorageChannel;
@@ -76,6 +77,7 @@ import appeng.util.prioritylist.PrecisePriorityList;
public class FormationPlanePart extends AbstractFormationPlanePart<IAEItemStack> {
private static final PlaneModels MODELS = new PlaneModels("part/formation_plane", "part/formation_plane_on");
private static final Random RANDOM_OFFSET = new Random();
@PartModels
public static List<IPartModel> getModels() {
@@ -214,12 +216,12 @@ public class FormationPlanePart extends AbstractFormationPlanePart<IAEItemStack>
final BlockPos placePos = te.getPos().offset(side.getFacing());
if (w.getBlockState(placePos).getMaterial().isReplaceable()) {
if (placeBlock == YesNo.YES && (i instanceof BlockItem || i instanceof FireworkChargeItem
|| i instanceof FireworkItem || i instanceof IPartItem)) {
if (placeBlock == YesNo.YES) {
final PlayerEntity player = FakePlayer.getOrCreate(serverWorld);
Platform.configurePlayer(player, side, this.getTile());
Hand hand = player.getActiveHand();
player.setStackInHand(hand, is);
// Seems to work without...
// Hand hand = player.getActiveHand();
// player.setStackInHand(hand, is);
maxStorage = is.getCount();
worked = true;
@@ -227,83 +229,33 @@ public class FormationPlanePart extends AbstractFormationPlanePart<IAEItemStack>
// The side the plane is attached to will be considered the look direction
// in terms of placing an item
Direction lookDirection = side.getFacing();
PlaneDirectionalPlaceContext context = new PlaneDirectionalPlaceContext(w, player, placePos,
lookDirection, is, lookDirection.getOpposite());
// FIXME No idea what any of this is _supposed_ to do, comment badly needed
if (i instanceof WallStandingBlockItem) {
boolean Worked = false;
i.onItemUse(context);
maxStorage -= is.getCount();
// Up or Down, Attempt 1??
if (side.xOffset == 0 && side.zOffset == 0) {
Worked = i
.useOnBlock(new AutomaticItemPlacementContext(w, placePos.offset(side.getFacing()),
lookDirection, is, side.getFacing())) == ActionResult.SUCCESS;
}
// Up or Down, Attempt 2??
if (!Worked && side.xOffset == 0 && side.zOffset == 0) {
Worked = i.useOnBlock(new AutomaticItemPlacementContext(w,
placePos.offset(side.getFacing().getOpposite()), lookDirection, is,
side.getFacing().getOpposite())) == ActionResult.SUCCESS;
}
// Horizontal, attempt 1??
if (!Worked && side.yOffset == 0) {
Worked = i.useOnBlock(new AutomaticItemPlacementContext(w, placePos.offset(Direction.DOWN),
lookDirection, is, Direction.DOWN)) == ActionResult.SUCCESS;
}
if (!Worked) {
i.useOnBlock(new AutomaticItemPlacementContext(w, placePos, lookDirection, is,
lookDirection.getOpposite()));
}
maxStorage -= is.getCount();
} else {
i.useOnBlock(new AutomaticItemPlacementContext(w, placePos, lookDirection, is,
lookDirection.getOpposite()));
maxStorage -= is.getCount();
}
} else {
maxStorage = 1;
}
// Safe keeping
player.setStackInHand(hand, ItemStack.EMPTY);
// Seems to work without... Safe keeping
// player.setStackInHand(hand, ItemStack.EMPTY);
} else {
worked = true;
final int sum = this.countEntitesAround(w, placePos);
// Disable spawning once there is a certain amount of entities in an area.
if (sum < AEConfig.instance().getFormationPlaneEntityLimit()) {
worked = true;
if (type == Actionable.MODULATE) {
is.setCount((int) maxStorage);
final double x = (side.xOffset != 0 ? 0 : .7 * (Platform.getRandomFloat() - .5)) + side.xOffset
+ .5 + te.getPos().getX();
final double y = (side.yOffset != 0 ? 0 : .7 * (Platform.getRandomFloat() - .5)) + side.yOffset
+ .5 + te.getPos().getY();
final double z = (side.zOffset != 0 ? 0 : .7 * (Platform.getRandomFloat() - .5)) + side.zOffset
+ .5 + te.getPos().getZ();
final ItemEntity ei = new ItemEntity(w, x, y, z, is.copy());
ei.setVelocity(side.xOffset * 0.2, side.yOffset * 0.2, side.zOffset * 0.2);
Entity result;
if (is.getItem() instanceof AECustomEntityItem) {
result = ((AECustomEntityItem) is.getItem()).replaceItemEntity(serverWorld, ei, is);
if (result != ei) {
ei.remove();
}
} else {
result = ei;
}
if (!w.spawnEntity(result)) {
result.remove();
if (!spawnItemEntity(serverWorld, te, side, is)) {
// revert in case something prevents spawning.
worked = false;
}
}
} else {
worked = false;
}
}
}
@@ -322,6 +274,56 @@ public class FormationPlanePart extends AbstractFormationPlanePart<IAEItemStack>
return input;
}
private static boolean spawnItemEntity(ServerWorld w, BlockEntity te, AEPartLocation side, ItemStack is) {
// the item offset based on the entity height plus some offset
final double itemOffset = .55 + EntityType.ITEM.getHeight();
// The center of the block the plane is located in
final double centerX = te.getPos().getX() + .5;
final double centerY = te.getPos().getY() + .5;
final double centerZ = te.getPos().getZ() + .5;
// When spawning downwards, we have to take the item height of 0.25 into account
// Otherwise it will get stuck and be spit out in a random direction as
// minecraft spawns it at its feet position and not center
final double additionalYOffset = side.yOffset == -1 ? -.3 : 0;
// Calculate the offsets to spawn it into the adjacent block, taking the sign
// into account.
// Spawn it 0.8 blocks away from the center pos when facing in this direction
// Every other direction will select a position in a .5 block area around the
// block center.
final double offsetX = (side.xOffset == 0) ? ((RANDOM_OFFSET.nextFloat() / 2) - .25)
: (side.xOffset * itemOffset);
final double offsetY = (side.yOffset == 0) ? ((RANDOM_OFFSET.nextFloat() / 2) - .25)
: ((side.yOffset * itemOffset) + additionalYOffset);
final double offsetZ = (side.zOffset == 0) ? ((RANDOM_OFFSET.nextFloat() / 2) - .25)
: (side.zOffset * itemOffset);
final double absoluteX = centerX + offsetX;
final double absoluteY = centerY + offsetY;
final double absoluteZ = centerZ + offsetZ;
final ItemEntity ei = new ItemEntity(w, absoluteX, absoluteY, absoluteZ, is.copy());
ei.setVelocity(side.xOffset * .1, side.yOffset * 0.1, side.zOffset * 0.1);
Entity result;
if (is.getItem() instanceof AECustomEntityItem) {
result = ((AECustomEntityItem) is.getItem()).replaceItemEntity(w, ei, is);
if (result != ei) {
ei.remove();
}
} else {
result = ei;
}
if (!w.spawnEntity(result)) {
result.remove();
return false;
}
return true;
}
@Override
public IStorageChannel<IAEItemStack> getChannel() {
return Api.instance().storage().getStorageChannel(IItemStorageChannel.class);
@@ -354,11 +356,76 @@ public class FormationPlanePart extends AbstractFormationPlanePart<IAEItemStack>
return list.size();
}
private class ForcedItemUseContext extends ItemUsageContext {
protected ForcedItemUseContext(World worldIn, @Nullable PlayerEntity player, Hand handIn, ItemStack heldItem,
BlockHitResult rayTraceResultIn) {
super(worldIn, player, handIn, heldItem, rayTraceResultIn);
/**
* A custom {@link DirectionalPlaceContext} which also accepts a player needed
* various blocks like seeds.
* <p>
* Also removed {@link DirectionalPlaceContext#replacingClickedOnBlock} as this
* can cause a {@link StackOverflowError} for certain replaceable blocks.
*/
private static class PlaneDirectionalPlaceContext extends BlockItemUseContext {
private final Direction lookDirection;
public PlaneDirectionalPlaceContext(World world, PlayerEntity player, BlockPos pos, Direction lookDirection,
ItemStack itemStack, Direction facing) {
super(world, player, Hand.MAIN_HAND, itemStack,
new BlockRayTraceResult(Vector3d.copyCenteredHorizontally(pos), facing, pos, false));
this.lookDirection = lookDirection;
}
@Override
public BlockPos getPos() {
return this.rayTraceResult.getPos();
}
@Override
public boolean canPlace() {
return this.world.getBlockState(this.rayTraceResult.getPos()).isReplaceable(this);
}
@Override
public Direction getNearestLookingDirection() {
return Direction.DOWN;
}
@Override
public Direction[] getNearestLookingDirections() {
switch (this.lookDirection) {
case DOWN:
default:
return new Direction[] { Direction.DOWN, Direction.NORTH, Direction.EAST, Direction.SOUTH,
Direction.WEST, Direction.UP };
case UP:
return new Direction[] { Direction.DOWN, Direction.UP, Direction.NORTH, Direction.EAST,
Direction.SOUTH, Direction.WEST };
case NORTH:
return new Direction[] { Direction.DOWN, Direction.NORTH, Direction.EAST, Direction.WEST,
Direction.UP, Direction.SOUTH };
case SOUTH:
return new Direction[] { Direction.DOWN, Direction.SOUTH, Direction.EAST, Direction.WEST,
Direction.UP, Direction.NORTH };
case WEST:
return new Direction[] { Direction.DOWN, Direction.WEST, Direction.SOUTH, Direction.UP,
Direction.NORTH, Direction.EAST };
case EAST:
return new Direction[] { Direction.DOWN, Direction.EAST, Direction.SOUTH, Direction.UP,
Direction.NORTH, Direction.WEST };
}
}
@Override
public Direction getPlacementHorizontalFacing() {
return this.lookDirection.getAxis() == Axis.Y ? Direction.NORTH : this.lookDirection;
}
@Override
public boolean func_225518_g_() {
return false;
}
@Override
public float getPlacementYaw() {
return (float) (this.lookDirection.getHorizontalIndex() * 90);
}
}
}
@@ -54,15 +54,6 @@ public class IdentityAnnihilationPlanePart extends AnnihilationPlanePart {
super(is);
}
@Override
protected 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;
}
@Override
protected float calculateEnergyUsage(final ServerWorld w, final BlockPos pos, final List<ItemStack> items) {
final float requiredEnergy = super.calculateEnergyUsage(w, pos, items);
@@ -0,0 +1,160 @@
package appeng.parts.automation;
import javax.annotation.Nullable;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import appeng.api.parts.IPart;
import appeng.api.parts.IPartCollisionHelper;
import appeng.api.parts.IPartHost;
import appeng.api.util.AEPartLocation;
import appeng.parts.AEBasePart;
/**
* Helps plane parts (annihilation, formation) with determining and checking for
* connections to adjacent plane parts of the same type to form a visually
* larger plane.
*/
public final class PlaneConnectionHelper {
private final AEBasePart part;
public PlaneConnectionHelper(AEBasePart part) {
this.part = part;
}
/**
* Gets on which sides this part has adjacent planes that it visually connects
* to
*/
public PlaneConnections getConnections() {
TileEntity hostTileEntity = getHostTileEntity();
AEPartLocation side = part.getSide();
final Direction facingRight, facingUp;
switch (side) {
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;
if (hostTileEntity != null) {
World world = hostTileEntity.getWorld();
BlockPos pos = hostTileEntity.getPos();
if (isCompatiblePlaneAdjacent(world.getTileEntity(pos.offset(facingRight.getOpposite())))) {
left = true;
}
if (isCompatiblePlaneAdjacent(world.getTileEntity(pos.offset(facingRight)))) {
right = true;
}
if (isCompatiblePlaneAdjacent(world.getTileEntity(pos.offset(facingUp.getOpposite())))) {
down = true;
}
if (isCompatiblePlaneAdjacent(world.getTileEntity(pos.offset(facingUp)))) {
up = true;
}
}
return PlaneConnections.of(up, right, down, left);
}
/**
* Get the bounding boxes of this plane parts components.
*/
public void getBoxes(IPartCollisionHelper bch) {
int minX = 1;
int minY = 1;
int maxX = 15;
int maxY = 15;
TileEntity hostTile = getHostTileEntity();
if (hostTile != null) {
World world = hostTile.getWorld();
final BlockPos pos = hostTile.getPos();
final Direction e = bch.getWorldX();
final Direction u = bch.getWorldY();
if (isCompatiblePlaneAdjacent(world.getTileEntity(pos.offset(e.getOpposite())))) {
minX = 0;
}
if (isCompatiblePlaneAdjacent(world.getTileEntity(pos.offset(e)))) {
maxX = 16;
}
if (isCompatiblePlaneAdjacent(world.getTileEntity(pos.offset(u.getOpposite())))) {
minY = 0;
}
if (isCompatiblePlaneAdjacent(world.getTileEntity(pos.offset(u)))) {
maxY = 16;
}
}
bch.addBox(5, 5, 14, 11, 11, 15);
bch.addBox(minX, minY, 15, maxX, maxY, 16);
}
/**
* Call this when an adjacent block has changed since the connections need to be
* recalculated.
*/
public void updateConnections() {
TileEntity hostTile = getHostTileEntity();
if (hostTile != null) {
hostTile.requestModelDataUpdate();
}
}
private boolean isCompatiblePlaneAdjacent(@Nullable TileEntity adjacentTileEntity) {
if (adjacentTileEntity instanceof IPartHost) {
final IPart p = ((IPartHost) adjacentTileEntity).getPart(part.getSide());
return p != null && p.getClass() == part.getClass();
}
return false;
}
private TileEntity getHostTileEntity() {
IPartHost host = part.getHost();
if (host != null) {
return host.getTile();
}
return null;
}
}
@@ -18,32 +18,32 @@
package appeng.parts.p2p;
import java.util.*;
import java.util.List;
import javax.annotation.Nonnull;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockView;
import alexiil.mc.lib.attributes.AttributeList;
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.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.world.IBlockReader;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
import appeng.api.config.PowerUnits;
import appeng.api.parts.IPartModel;
import appeng.items.parts.PartModels;
import appeng.me.GridAccessException;
public class FluidP2PTunnelPart extends P2PTunnelPart<FluidP2PTunnelPart> implements FluidInsertable {
public class FluidP2PTunnelPart extends P2PTunnelPart<FluidP2PTunnelPart> {
private static final P2PModels MODELS = new P2PModels("part/p2p/p2p_tunnel_fluids");
private static final IFluidHandler NULL_FLUID_HANDLER = new NullFluidHandler();
private static final ThreadLocal<Deque<FluidP2PTunnelPart>> DEPTH = new ThreadLocal<>();;
private FluidInsertable cachedTank;
private final IFluidHandler inputHandler = new InputFluidHandler();
private final IFluidHandler outputHandler = new OutputFluidHandler();
public FluidP2PTunnelPart(final ItemStack is) {
super(is);
@@ -60,13 +60,10 @@ public class FluidP2PTunnelPart extends P2PTunnelPart<FluidP2PTunnelPart> implem
@Override
public void onTunnelNetworkChange() {
this.cachedTank = null;
}
@Override
public void onneighborUpdate(BlockView w, BlockPos pos, BlockPos neighbor) {
this.cachedTank = null;
public void onNeighborChanged(IBlockReader w, BlockPos pos, BlockPos neighbor) {
if (this.isOutput()) {
final FluidP2PTunnelPart in = this.getInput();
if (in != null) {
@@ -75,9 +72,17 @@ public class FluidP2PTunnelPart extends P2PTunnelPart<FluidP2PTunnelPart> implem
}
}
@SuppressWarnings("unchecked")
@Override
public void addAllAttributes(AttributeList<?> to) {
to.offer(this);
public <T> LazyOptional<T> getCapability(Capability<T> capabilityClass) {
if (capabilityClass == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) {
if (this.isOutput()) {
return (LazyOptional<T>) LazyOptional.of(() -> this.outputHandler);
}
return (LazyOptional<T>) LazyOptional.of(() -> this.inputHandler);
}
return super.getCapability(capabilityClass);
}
@Override
@@ -85,122 +90,173 @@ public class FluidP2PTunnelPart extends P2PTunnelPart<FluidP2PTunnelPart> implem
return MODELS.getModel(this.isPowered(), this.isActive());
}
@Override
public FluidVolume attemptInsertion(FluidVolume fluid, Simulation simulation) {
private IFluidHandler getAttachedFluidHandler() {
LazyOptional<IFluidHandler> fluidHandler = LazyOptional.empty();
if (this.isActive()) {
final TileEntity self = this.getTile();
final TileEntity te = self.getWorld().getTileEntity(self.getPos().offset(this.getSide().getFacing()));
final Deque<FluidP2PTunnelPart> stack = this.getDepth();
for (final FluidP2PTunnelPart t : stack) {
if (t == this) {
return fluid;
if (te != null) {
fluidHandler = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY,
this.getSide().getOpposite().getFacing());
}
}
stack.push(this);
final List<FluidP2PTunnelPart> list = this.getOutputs(fluid.getFluidKey());
FluidAmount requestTotal = FluidAmount.ZERO;
Iterator<FluidP2PTunnelPart> i = list.iterator();
while (i.hasNext()) {
final FluidP2PTunnelPart l = i.next();
final FluidInsertable tank = l.getTarget();
FluidAmount inserted;
if (tank != null) {
inserted = fluid.amount().sub(tank.attemptInsertion(fluid.copy(), Simulation.SIMULATE).amount());
} else {
inserted = FluidAmount.ZERO;
}
if (inserted.isZero()) {
i.remove();
} else {
requestTotal = requestTotal.add(inserted);
}
}
if (requestTotal.isZero()) {
if (stack.pop() != this) {
throw new IllegalStateException("Invalid Recursion detected.");
}
return fluid;
}
if (simulation != Simulation.ACTION) {
if (stack.pop() != this) {
throw new IllegalStateException("Invalid Recursion detected.");
}
return fluid.copy().split(fluid.amount().min(requestTotal));
}
FluidAmount remaining = fluid.amount();
i = list.iterator();
while (i.hasNext() && !remaining.isZero()) {
final FluidP2PTunnelPart l = i.next();
FluidVolume insert = fluid.withAmount(fluid.amount().div(list.size()));
if (insert.amount().isGreaterThan(remaining)) {
insert = insert.withAmount(remaining);
}
FluidInsertable tank = l.getTarget();
if (tank != null) {
remaining = remaining
.sub(insert.amount().sub(tank.attemptInsertion(insert, Simulation.ACTION).amount()));
}
}
if (stack.pop() != this) {
throw new IllegalStateException("Invalid Recursion detected.");
}
return remaining.isZero() ? FluidVolumeUtil.EMPTY : fluid.withAmount(remaining);
return fluidHandler.orElse(NULL_FLUID_HANDLER);
}
private Deque<FluidP2PTunnelPart> getDepth() {
Deque<FluidP2PTunnelPart> s = DEPTH.get();
private class InputFluidHandler implements IFluidHandler {
if (s == null) {
DEPTH.set(s = new ArrayDeque<>());
@Override
public int getTanks() {
return 1;
}
return s;
}
@Override
@Nonnull
public FluidStack getFluidInTank(int tank) {
return FluidStack.EMPTY;
}
private List<FluidP2PTunnelPart> getOutputs(final FluidKey input) {
final List<FluidP2PTunnelPart> outs = new ArrayList<>();
@Override
public int getTankCapacity(int tank) {
return Integer.MAX_VALUE;
}
try {
for (final FluidP2PTunnelPart l : this.getOutputs()) {
final FluidInsertable handler = l.getTarget();
@Override
public boolean isFluidValid(int tank, @Nonnull FluidStack stack) {
return true;
}
if (handler != null) {
outs.add(l);
@Override
public int fill(FluidStack resource, FluidAction action) {
int total = 0;
try {
final int outputTunnels = FluidP2PTunnelPart.this.getOutputs().size();
final int amount = resource.getAmount();
if (outputTunnels == 0 || amount == 0) {
return 0;
}
final int amountPerOutput = Math.max(1, amount / outputTunnels);
int overflow = amountPerOutput == 0 ? amount : amount % amountPerOutput;
for (FluidP2PTunnelPart target : FluidP2PTunnelPart.this.getOutputs()) {
final IFluidHandler output = target.getAttachedFluidHandler();
final int toSend = amountPerOutput + overflow;
final FluidStack fillWithFluidStack = resource.copy();
fillWithFluidStack.setAmount(toSend);
final int received = output.fill(fillWithFluidStack, action);
overflow = toSend - received;
total += received;
}
if (action == FluidAction.EXECUTE) {
FluidP2PTunnelPart.this.queueTunnelDrain(PowerUnits.RF, total);
}
} catch (GridAccessException ignored) {
}
} catch (final GridAccessException e) {
// :P
return total;
}
@Override
@Nonnull
public FluidStack drain(FluidStack resource, FluidAction action) {
return FluidStack.EMPTY;
}
@Override
@Nonnull
public FluidStack drain(int maxDrain, FluidAction action) {
return FluidStack.EMPTY;
}
return outs;
}
private FluidInsertable getTarget() {
if (!this.getProxy().isActive()) {
return null;
private class OutputFluidHandler implements IFluidHandler {
@Override
public int getTanks() {
return FluidP2PTunnelPart.this.getAttachedFluidHandler().getTanks();
}
if (this.cachedTank != null) {
return this.cachedTank;
@Override
@Nonnull
public FluidStack getFluidInTank(int tank) {
return FluidP2PTunnelPart.this.getAttachedFluidHandler().getFluidInTank(tank);
}
return this.cachedTank = FluidAttributes.INSERTABLE.getFirstOrNullFromNeighbour(this.getTile(),
this.getSide().getFacing());
@Override
public int getTankCapacity(int tank) {
return FluidP2PTunnelPart.this.getAttachedFluidHandler().getTankCapacity(tank);
}
@Override
public boolean isFluidValid(int tank, @Nonnull FluidStack stack) {
return FluidP2PTunnelPart.this.getAttachedFluidHandler().isFluidValid(tank, stack);
}
@Override
public int fill(FluidStack resource, FluidAction action) {
return 0;
}
@Override
@Nonnull
public FluidStack drain(FluidStack resource, FluidAction action) {
return FluidP2PTunnelPart.this.getAttachedFluidHandler().drain(resource, action);
}
@Override
@Nonnull
public FluidStack drain(int maxDrain, FluidAction action) {
return FluidP2PTunnelPart.this.getAttachedFluidHandler().drain(maxDrain, action);
}
}
private static class NullFluidHandler implements IFluidHandler {
@Override
public int getTanks() {
return 0;
}
@Override
@Nonnull
public FluidStack getFluidInTank(int tank) {
return FluidStack.EMPTY;
}
@Override
public int getTankCapacity(int tank) {
return 0;
}
@Override
public boolean isFluidValid(int tank, @Nonnull FluidStack stack) {
return false;
}
@Override
public int fill(FluidStack resource, FluidAction action) {
return 0;
}
@Override
@Nonnull
public FluidStack drain(FluidStack resource, FluidAction action) {
return FluidStack.EMPTY;
}
@Override
@Nonnull
public FluidStack drain(int maxDrain, FluidAction action) {
return FluidStack.EMPTY;
}
}
}