From 62bbc327633542d7dfa0a36e5729c9a3576a06ed Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Mon, 3 Aug 2020 20:31:30 +0200 Subject: [PATCH 01/11] Minor cleanup. --- src/main/java/appeng/container/AEBaseContainer.java | 2 -- src/main/java/appeng/container/slot/PlayerInvSlot.java | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/appeng/container/AEBaseContainer.java b/src/main/java/appeng/container/AEBaseContainer.java index b8c1f32cb..1f71dab58 100644 --- a/src/main/java/appeng/container/AEBaseContainer.java +++ b/src/main/java/appeng/container/AEBaseContainer.java @@ -93,8 +93,6 @@ public abstract class AEBaseContainer extends Container { private boolean sentCustomName; private int ticksSinceCheck = 900; private IAEItemStack clientRequestedTargetItem = null; - // Slots that were created to represent the player inventory - private List playerInventorySlots = null; public AEBaseContainer(ContainerType containerType, int id, final PlayerInventory ip, final TileEntity myTile, final IPart myPart) { diff --git a/src/main/java/appeng/container/slot/PlayerInvSlot.java b/src/main/java/appeng/container/slot/PlayerInvSlot.java index 0f12d82cd..364319f4b 100644 --- a/src/main/java/appeng/container/slot/PlayerInvSlot.java +++ b/src/main/java/appeng/container/slot/PlayerInvSlot.java @@ -24,8 +24,8 @@ import net.minecraftforge.items.IItemHandler; public class PlayerInvSlot extends AppEngSlot { - public PlayerInvSlot(final IItemHandler par1iInventory, final int invSlot, final int x, final int y) { - super(par1iInventory, invSlot, x, y); + public PlayerInvSlot(final IItemHandler inv, final int invSlot, final int x, final int y) { + super(inv, invSlot, x, y); this.setPlayerSide(true); } From 8f0e408772d6ee16d9ebb70bad8325771c9dfc5d Mon Sep 17 00:00:00 2001 From: yueh Date: Mon, 3 Aug 2020 20:57:10 +0200 Subject: [PATCH 02/11] Fixes NPE on empty tooltips (#4546) --- src/main/java/appeng/client/gui/AEBaseScreen.java | 12 ++++++++---- .../appeng/client/gui/widgets/CustomSlotWidget.java | 3 ++- .../java/appeng/client/gui/widgets/ITooltip.java | 8 +++++++- .../fluids/client/gui/widgets/FluidSlotWidget.java | 4 +++- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/main/java/appeng/client/gui/AEBaseScreen.java b/src/main/java/appeng/client/gui/AEBaseScreen.java index ca30c7aa0..34055b47c 100644 --- a/src/main/java/appeng/client/gui/AEBaseScreen.java +++ b/src/main/java/appeng/client/gui/AEBaseScreen.java @@ -191,10 +191,14 @@ public abstract class AEBaseScreen extends ContainerS } protected void drawTooltip(MatrixStack matrices, int x, int y, ITextComponent message) { - String[] lines = message.getString().split("\n"); // FIXME FABRIC - List textLines = Arrays.stream(lines).map(StringTextComponent::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 textLines = Arrays.stream(lines).map(StringTextComponent::new) + .collect(Collectors.toList()); + this.drawTooltip(matrices, x, y, textLines); + } } // FIXME FABRIC: move out to json (?) diff --git a/src/main/java/appeng/client/gui/widgets/CustomSlotWidget.java b/src/main/java/appeng/client/gui/widgets/CustomSlotWidget.java index 8498e3ac1..bb9308ae5 100644 --- a/src/main/java/appeng/client/gui/widgets/CustomSlotWidget.java +++ b/src/main/java/appeng/client/gui/widgets/CustomSlotWidget.java @@ -8,6 +8,7 @@ import net.minecraft.client.gui.AbstractGui; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.StringTextComponent; public abstract class CustomSlotWidget extends AbstractGui implements ITooltip { private final int x; @@ -39,7 +40,7 @@ public abstract class CustomSlotWidget extends AbstractGui implements ITooltip { @Override public ITextComponent getMessage() { - return null; + return StringTextComponent.EMPTY; } @Override diff --git a/src/main/java/appeng/client/gui/widgets/ITooltip.java b/src/main/java/appeng/client/gui/widgets/ITooltip.java index d487dc155..bb0018cb4 100644 --- a/src/main/java/appeng/client/gui/widgets/ITooltip.java +++ b/src/main/java/appeng/client/gui/widgets/ITooltip.java @@ -18,7 +18,10 @@ package appeng.client.gui.widgets; +import javax.annotation.Nonnull; + import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.StringTextComponent; /** * AEBaseGui controlled Tooltip Interface. @@ -26,10 +29,13 @@ import net.minecraft.util.text.ITextComponent; public interface ITooltip { /** - * returns the tooltip message. + * Returns the tooltip message. + * + * Should use {@link StringTextComponent#EMPTY} for no tooltip * * @return tooltip message */ + @Nonnull ITextComponent getMessage(); /** diff --git a/src/main/java/appeng/fluids/client/gui/widgets/FluidSlotWidget.java b/src/main/java/appeng/fluids/client/gui/widgets/FluidSlotWidget.java index 448514b85..75de9a589 100644 --- a/src/main/java/appeng/fluids/client/gui/widgets/FluidSlotWidget.java +++ b/src/main/java/appeng/fluids/client/gui/widgets/FluidSlotWidget.java @@ -1,5 +1,6 @@ package appeng.fluids.client.gui.widgets; +import java.awt.TextComponent; import java.util.Collections; import com.mojang.blaze3d.matrix.MatrixStack; @@ -12,6 +13,7 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.fluid.Fluid; import net.minecraft.item.ItemStack; import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TranslationTextComponent; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.fluids.FluidAttributes; @@ -84,7 +86,7 @@ public class FluidSlotWidget extends CustomSlotWidget { if (fluid != null) { return new TranslationTextComponent(fluid.getFluidStack().getTranslationKey()); } - return null; + return StringTextComponent.EMPTY; } @Override From 22f552217f4c40558242d3f0844c529469eed6e4 Mon Sep 17 00:00:00 2001 From: yueh Date: Mon, 3 Aug 2020 21:39:34 +0200 Subject: [PATCH 03/11] Apply the FE tunnel behaviour to the fluid tunnel (#4545) * Apply the FE tunnel behaviour to the fluid tunnel * Make a second pass to try and get all the requested fill amount sent out to outputs. Co-authored-by: Sebastian Hartte --- .../appeng/parts/p2p/FluidP2PTunnelPart.java | 314 +++++++++--------- 1 file changed, 166 insertions(+), 148 deletions(-) diff --git a/src/main/java/appeng/parts/p2p/FluidP2PTunnelPart.java b/src/main/java/appeng/parts/p2p/FluidP2PTunnelPart.java index 57eb6f5c0..c3ae96e4b 100644 --- a/src/main/java/appeng/parts/p2p/FluidP2PTunnelPart.java +++ b/src/main/java/appeng/parts/p2p/FluidP2PTunnelPart.java @@ -18,15 +18,10 @@ package appeng.parts.p2p; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Deque; -import java.util.Iterator; import java.util.List; import javax.annotation.Nonnull; -import net.minecraft.fluid.Fluid; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; @@ -37,18 +32,18 @@ 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 implements IFluidHandler { +public class FluidP2PTunnelPart extends P2PTunnelPart { 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> DEPTH = new ThreadLocal<>();; - - private LazyOptional cachedTank; - private int tmpUsed; + private final IFluidHandler inputHandler = new InputFluidHandler(); + private final IFluidHandler outputHandler = new OutputFluidHandler(); public FluidP2PTunnelPart(final ItemStack is) { super(is); @@ -65,13 +60,10 @@ public class FluidP2PTunnelPart extends P2PTunnelPart implem @Override public void onTunnelNetworkChange() { - this.cachedTank = null; } @Override public void onNeighborChanged(IBlockReader w, BlockPos pos, BlockPos neighbor) { - this.cachedTank = null; - if (this.isOutput()) { final FluidP2PTunnelPart in = this.getInput(); if (in != null) { @@ -84,7 +76,10 @@ public class FluidP2PTunnelPart extends P2PTunnelPart implem @Override public LazyOptional getCapability(Capability capabilityClass) { if (capabilityClass == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) { - return (LazyOptional) LazyOptional.of(() -> this); + if (this.isOutput()) { + return (LazyOptional) LazyOptional.of(() -> this.outputHandler); + } + return (LazyOptional) LazyOptional.of(() -> this.inputHandler); } return super.getCapability(capabilityClass); @@ -95,168 +90,191 @@ public class FluidP2PTunnelPart extends P2PTunnelPart implem return MODELS.getModel(this.isPowered(), this.isActive()); } - @Override - public int getTanks() { - return 0; - } + private IFluidHandler getAttachedFluidHandler() { + LazyOptional fluidHandler = LazyOptional.empty(); + if (this.isActive()) { + final TileEntity self = this.getTile(); + final TileEntity te = self.getWorld().getTileEntity(self.getPos().offset(this.getSide().getFacing())); - @Override - @Nonnull - public FluidStack getFluidInTank(int tank) { - return FluidStack.EMPTY; - } - - @Override - public int getTankCapacity(int tank) { - return 1000; - } - - @Override - public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { - return false; - } - - @Override - public int fill(FluidStack resource, FluidAction action) { - - final Deque stack = this.getDepth(); - - for (final FluidP2PTunnelPart t : stack) { - if (t == this) { - return 0; + if (te != null) { + fluidHandler = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, + this.getSide().getOpposite().getFacing()); } } + return fluidHandler.orElse(NULL_FLUID_HANDLER); + } - stack.push(this); + private class InputFluidHandler implements IFluidHandler { - final List list = this.getOutputs(resource.getFluid()); - int requestTotal = 0; - - Iterator i = list.iterator(); - - while (i.hasNext()) { - final FluidP2PTunnelPart l = i.next(); - final IFluidHandler tank = l.getTarget().orElse(null); - if (tank != null) { - l.tmpUsed = tank.fill(resource.copy(), FluidAction.SIMULATE); - } else { - l.tmpUsed = 0; - } - - if (l.tmpUsed <= 0) { - i.remove(); - } else { - requestTotal += l.tmpUsed; - } + @Override + public int getTanks() { + return 1; } - if (requestTotal <= 0) { - if (stack.pop() != this) { - throw new IllegalStateException("Invalid Recursion detected."); + @Override + @Nonnull + public FluidStack getFluidInTank(int tank) { + return FluidStack.EMPTY; + } + + @Override + public int getTankCapacity(int tank) { + return Integer.MAX_VALUE; + } + + @Override + public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { + return true; + } + + @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; + } + + // Make a second pass, to distribute any leftover overflow in case + // a later output did not completely consume its allotment + if (overflow > 0) { + for (FluidP2PTunnelPart target : FluidP2PTunnelPart.this.getOutputs()) { + final IFluidHandler output = target.getAttachedFluidHandler(); + final FluidStack fillWithFluidStack = resource.copy(); + fillWithFluidStack.setAmount(overflow); + + final int received = output.fill(fillWithFluidStack, action); + + overflow -= received; + total += received; + if (overflow <= 0) { + break; // don't continue if nothing is left + } + } + } + + if (action == FluidAction.EXECUTE) { + FluidP2PTunnelPart.this.queueTunnelDrain(PowerUnits.RF, total); + } + } catch (GridAccessException ignored) { } + 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; + } + + } + + private class OutputFluidHandler implements IFluidHandler { + + @Override + public int getTanks() { + return FluidP2PTunnelPart.this.getAttachedFluidHandler().getTanks(); + } + + @Override + @Nonnull + public FluidStack getFluidInTank(int tank) { + return FluidP2PTunnelPart.this.getAttachedFluidHandler().getFluidInTank(tank); + } + + @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; } - if (action != FluidAction.EXECUTE) { - if (stack.pop() != this) { - throw new IllegalStateException("Invalid Recursion detected."); - } - - return Math.min(resource.getAmount(), requestTotal); + @Override + @Nonnull + public FluidStack drain(FluidStack resource, FluidAction action) { + return FluidP2PTunnelPart.this.getAttachedFluidHandler().drain(resource, action); } - int available = resource.getAmount(); - - i = list.iterator(); - int used = 0; - - while (i.hasNext() && available > 0) { - final FluidP2PTunnelPart l = i.next(); - - final FluidStack insert = resource.copy(); - insert.setAmount((int) Math.ceil(insert.getAmount() * ((double) l.tmpUsed / (double) requestTotal))); - if (insert.getAmount() > available) { - insert.setAmount(available); - } - - final IFluidHandler tank = l.getTarget().orElse(null); - if (tank != null) { - l.tmpUsed = tank.fill(insert.copy(), action); - } else { - l.tmpUsed = 0; - } - - available -= insert.getAmount(); - used += l.tmpUsed; + @Override + @Nonnull + public FluidStack drain(int maxDrain, FluidAction action) { + return FluidP2PTunnelPart.this.getAttachedFluidHandler().drain(maxDrain, action); } - - if (stack.pop() != this) { - throw new IllegalStateException("Invalid Recursion detected."); - } - - return used; } - @Override - @Nonnull - public FluidStack drain(FluidStack resource, FluidAction action) { - return FluidStack.EMPTY; - } + private static class NullFluidHandler implements IFluidHandler { - @Override - @Nonnull - public FluidStack drain(int maxDrain, FluidAction action) { - return FluidStack.EMPTY; - } - - private Deque getDepth() { - Deque s = DEPTH.get(); - - if (s == null) { - DEPTH.set(s = new ArrayDeque<>()); + @Override + public int getTanks() { + return 0; } - return s; - } - - private List getOutputs(final Fluid input) { - final List outs = new ArrayList<>(); - - try { - for (final FluidP2PTunnelPart l : this.getOutputs()) { - final IFluidHandler handler = l.getTarget().orElse(null); - - if (handler != null) { - outs.add(l); - } - } - } catch (final GridAccessException e) { - // :P + @Override + @Nonnull + public FluidStack getFluidInTank(int tank) { + return FluidStack.EMPTY; } - return outs; - } - - private LazyOptional getTarget() { - if (!this.getProxy().isActive()) { - return null; + @Override + public int getTankCapacity(int tank) { + return 0; } - if (this.cachedTank != null) { - return this.cachedTank; + @Override + public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { + return false; } - final TileEntity te = this.getTile().getWorld() - .getTileEntity(this.getTile().getPos().offset(this.getSide().getFacing())); - - if (te != null && te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, - this.getSide().getFacing().getOpposite()).isPresent()) { - return this.cachedTank = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, - this.getSide().getFacing().getOpposite()); + @Override + public int fill(FluidStack resource, FluidAction action) { + return 0; } - return null; + @Override + @Nonnull + public FluidStack drain(FluidStack resource, FluidAction action) { + return FluidStack.EMPTY; + } + + @Override + @Nonnull + public FluidStack drain(int maxDrain, FluidAction action) { + return FluidStack.EMPTY; + } } } From 39959145a3eeb4319a1b2a6e9a65e5d2eabc654c Mon Sep 17 00:00:00 2001 From: yueh Date: Tue, 4 Aug 2020 08:45:10 +0200 Subject: [PATCH 04/11] Revert "Apply the FE tunnel behaviour to the fluid tunnel (#4545)" (#4549) This reverts commit 22f552217f4c40558242d3f0844c529469eed6e4. --- .../appeng/parts/p2p/FluidP2PTunnelPart.java | 310 +++++++++--------- 1 file changed, 146 insertions(+), 164 deletions(-) diff --git a/src/main/java/appeng/parts/p2p/FluidP2PTunnelPart.java b/src/main/java/appeng/parts/p2p/FluidP2PTunnelPart.java index c3ae96e4b..57eb6f5c0 100644 --- a/src/main/java/appeng/parts/p2p/FluidP2PTunnelPart.java +++ b/src/main/java/appeng/parts/p2p/FluidP2PTunnelPart.java @@ -18,10 +18,15 @@ package appeng.parts.p2p; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.Iterator; import java.util.List; import javax.annotation.Nonnull; +import net.minecraft.fluid.Fluid; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; @@ -32,18 +37,18 @@ 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 { +public class FluidP2PTunnelPart extends P2PTunnelPart implements IFluidHandler { private static final P2PModels MODELS = new P2PModels("part/p2p/p2p_tunnel_fluids"); - private static final IFluidHandler NULL_FLUID_HANDLER = new NullFluidHandler(); - private final IFluidHandler inputHandler = new InputFluidHandler(); - private final IFluidHandler outputHandler = new OutputFluidHandler(); + private static final ThreadLocal> DEPTH = new ThreadLocal<>();; + + private LazyOptional cachedTank; + private int tmpUsed; public FluidP2PTunnelPart(final ItemStack is) { super(is); @@ -60,10 +65,13 @@ public class FluidP2PTunnelPart extends P2PTunnelPart { @Override public void onTunnelNetworkChange() { + this.cachedTank = null; } @Override public void onNeighborChanged(IBlockReader w, BlockPos pos, BlockPos neighbor) { + this.cachedTank = null; + if (this.isOutput()) { final FluidP2PTunnelPart in = this.getInput(); if (in != null) { @@ -76,10 +84,7 @@ public class FluidP2PTunnelPart extends P2PTunnelPart { @Override public LazyOptional getCapability(Capability capabilityClass) { if (capabilityClass == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) { - if (this.isOutput()) { - return (LazyOptional) LazyOptional.of(() -> this.outputHandler); - } - return (LazyOptional) LazyOptional.of(() -> this.inputHandler); + return (LazyOptional) LazyOptional.of(() -> this); } return super.getCapability(capabilityClass); @@ -90,191 +95,168 @@ public class FluidP2PTunnelPart extends P2PTunnelPart { return MODELS.getModel(this.isPowered(), this.isActive()); } - private IFluidHandler getAttachedFluidHandler() { - LazyOptional fluidHandler = LazyOptional.empty(); - if (this.isActive()) { - final TileEntity self = this.getTile(); - final TileEntity te = self.getWorld().getTileEntity(self.getPos().offset(this.getSide().getFacing())); + @Override + public int getTanks() { + return 0; + } - if (te != null) { - fluidHandler = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, - this.getSide().getOpposite().getFacing()); + @Override + @Nonnull + public FluidStack getFluidInTank(int tank) { + return FluidStack.EMPTY; + } + + @Override + public int getTankCapacity(int tank) { + return 1000; + } + + @Override + public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { + return false; + } + + @Override + public int fill(FluidStack resource, FluidAction action) { + + final Deque stack = this.getDepth(); + + for (final FluidP2PTunnelPart t : stack) { + if (t == this) { + return 0; } } - return fluidHandler.orElse(NULL_FLUID_HANDLER); - } - private class InputFluidHandler implements IFluidHandler { + stack.push(this); - @Override - public int getTanks() { - return 1; - } + final List list = this.getOutputs(resource.getFluid()); + int requestTotal = 0; - @Override - @Nonnull - public FluidStack getFluidInTank(int tank) { - return FluidStack.EMPTY; - } + Iterator i = list.iterator(); - @Override - public int getTankCapacity(int tank) { - return Integer.MAX_VALUE; - } - - @Override - public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { - return true; - } - - @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; - } - - // Make a second pass, to distribute any leftover overflow in case - // a later output did not completely consume its allotment - if (overflow > 0) { - for (FluidP2PTunnelPart target : FluidP2PTunnelPart.this.getOutputs()) { - final IFluidHandler output = target.getAttachedFluidHandler(); - final FluidStack fillWithFluidStack = resource.copy(); - fillWithFluidStack.setAmount(overflow); - - final int received = output.fill(fillWithFluidStack, action); - - overflow -= received; - total += received; - if (overflow <= 0) { - break; // don't continue if nothing is left - } - } - } - - if (action == FluidAction.EXECUTE) { - FluidP2PTunnelPart.this.queueTunnelDrain(PowerUnits.RF, total); - } - } catch (GridAccessException ignored) { + while (i.hasNext()) { + final FluidP2PTunnelPart l = i.next(); + final IFluidHandler tank = l.getTarget().orElse(null); + if (tank != null) { + l.tmpUsed = tank.fill(resource.copy(), FluidAction.SIMULATE); + } else { + l.tmpUsed = 0; } - return total; + if (l.tmpUsed <= 0) { + i.remove(); + } else { + requestTotal += l.tmpUsed; + } } - @Override - @Nonnull - public FluidStack drain(FluidStack resource, FluidAction action) { - return FluidStack.EMPTY; + if (requestTotal <= 0) { + if (stack.pop() != this) { + throw new IllegalStateException("Invalid Recursion detected."); + } + + return 0; } - @Override - @Nonnull - public FluidStack drain(int maxDrain, FluidAction action) { - return FluidStack.EMPTY; + if (action != FluidAction.EXECUTE) { + if (stack.pop() != this) { + throw new IllegalStateException("Invalid Recursion detected."); + } + + return Math.min(resource.getAmount(), requestTotal); } + int available = resource.getAmount(); + + i = list.iterator(); + int used = 0; + + while (i.hasNext() && available > 0) { + final FluidP2PTunnelPart l = i.next(); + + final FluidStack insert = resource.copy(); + insert.setAmount((int) Math.ceil(insert.getAmount() * ((double) l.tmpUsed / (double) requestTotal))); + if (insert.getAmount() > available) { + insert.setAmount(available); + } + + final IFluidHandler tank = l.getTarget().orElse(null); + if (tank != null) { + l.tmpUsed = tank.fill(insert.copy(), action); + } else { + l.tmpUsed = 0; + } + + available -= insert.getAmount(); + used += l.tmpUsed; + } + + if (stack.pop() != this) { + throw new IllegalStateException("Invalid Recursion detected."); + } + + return used; } - private class OutputFluidHandler implements IFluidHandler { - - @Override - public int getTanks() { - return FluidP2PTunnelPart.this.getAttachedFluidHandler().getTanks(); - } - - @Override - @Nonnull - public FluidStack getFluidInTank(int tank) { - return FluidP2PTunnelPart.this.getAttachedFluidHandler().getFluidInTank(tank); - } - - @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); - } + @Override + @Nonnull + public FluidStack drain(FluidStack resource, FluidAction action) { + return FluidStack.EMPTY; } - private static class NullFluidHandler implements IFluidHandler { + @Override + @Nonnull + public FluidStack drain(int maxDrain, FluidAction action) { + return FluidStack.EMPTY; + } - @Override - public int getTanks() { - return 0; + private Deque getDepth() { + Deque s = DEPTH.get(); + + if (s == null) { + DEPTH.set(s = new ArrayDeque<>()); } - @Override - @Nonnull - public FluidStack getFluidInTank(int tank) { - return FluidStack.EMPTY; + return s; + } + + private List getOutputs(final Fluid input) { + final List outs = new ArrayList<>(); + + try { + for (final FluidP2PTunnelPart l : this.getOutputs()) { + final IFluidHandler handler = l.getTarget().orElse(null); + + if (handler != null) { + outs.add(l); + } + } + } catch (final GridAccessException e) { + // :P } - @Override - public int getTankCapacity(int tank) { - return 0; + return outs; + } + + private LazyOptional getTarget() { + if (!this.getProxy().isActive()) { + return null; } - @Override - public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { - return false; + if (this.cachedTank != null) { + return this.cachedTank; } - @Override - public int fill(FluidStack resource, FluidAction action) { - return 0; + final TileEntity te = this.getTile().getWorld() + .getTileEntity(this.getTile().getPos().offset(this.getSide().getFacing())); + + if (te != null && te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, + this.getSide().getFacing().getOpposite()).isPresent()) { + return this.cachedTank = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, + this.getSide().getFacing().getOpposite()); } - @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 null; } } From 7ca9405c8b605d69c6c91352e3a6d19c42857024 Mon Sep 17 00:00:00 2001 From: yueh Date: Tue, 4 Aug 2020 17:57:59 +0200 Subject: [PATCH 05/11] Apply the FE tunnel behaviour to the fluid tunnel (#4550) --- .../appeng/parts/p2p/FluidP2PTunnelPart.java | 296 +++++++++--------- 1 file changed, 148 insertions(+), 148 deletions(-) diff --git a/src/main/java/appeng/parts/p2p/FluidP2PTunnelPart.java b/src/main/java/appeng/parts/p2p/FluidP2PTunnelPart.java index 57eb6f5c0..ff530ac21 100644 --- a/src/main/java/appeng/parts/p2p/FluidP2PTunnelPart.java +++ b/src/main/java/appeng/parts/p2p/FluidP2PTunnelPart.java @@ -18,15 +18,10 @@ package appeng.parts.p2p; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Deque; -import java.util.Iterator; import java.util.List; import javax.annotation.Nonnull; -import net.minecraft.fluid.Fluid; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; @@ -37,18 +32,18 @@ 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 implements IFluidHandler { +public class FluidP2PTunnelPart extends P2PTunnelPart { 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> DEPTH = new ThreadLocal<>();; - - private LazyOptional cachedTank; - private int tmpUsed; + private final IFluidHandler inputHandler = new InputFluidHandler(); + private final IFluidHandler outputHandler = new OutputFluidHandler(); public FluidP2PTunnelPart(final ItemStack is) { super(is); @@ -65,13 +60,10 @@ public class FluidP2PTunnelPart extends P2PTunnelPart implem @Override public void onTunnelNetworkChange() { - this.cachedTank = null; } @Override public void onNeighborChanged(IBlockReader w, BlockPos pos, BlockPos neighbor) { - this.cachedTank = null; - if (this.isOutput()) { final FluidP2PTunnelPart in = this.getInput(); if (in != null) { @@ -84,7 +76,10 @@ public class FluidP2PTunnelPart extends P2PTunnelPart implem @Override public LazyOptional getCapability(Capability capabilityClass) { if (capabilityClass == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) { - return (LazyOptional) LazyOptional.of(() -> this); + if (this.isOutput()) { + return (LazyOptional) LazyOptional.of(() -> this.outputHandler); + } + return (LazyOptional) LazyOptional.of(() -> this.inputHandler); } return super.getCapability(capabilityClass); @@ -95,168 +90,173 @@ public class FluidP2PTunnelPart extends P2PTunnelPart implem return MODELS.getModel(this.isPowered(), this.isActive()); } - @Override - public int getTanks() { - return 0; - } + private IFluidHandler getAttachedFluidHandler() { + LazyOptional fluidHandler = LazyOptional.empty(); + if (this.isActive()) { + final TileEntity self = this.getTile(); + final TileEntity te = self.getWorld().getTileEntity(self.getPos().offset(this.getSide().getFacing())); - @Override - @Nonnull - public FluidStack getFluidInTank(int tank) { - return FluidStack.EMPTY; - } - - @Override - public int getTankCapacity(int tank) { - return 1000; - } - - @Override - public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { - return false; - } - - @Override - public int fill(FluidStack resource, FluidAction action) { - - final Deque stack = this.getDepth(); - - for (final FluidP2PTunnelPart t : stack) { - if (t == this) { - return 0; + if (te != null) { + fluidHandler = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, + this.getSide().getOpposite().getFacing()); } } + return fluidHandler.orElse(NULL_FLUID_HANDLER); + } - stack.push(this); + private class InputFluidHandler implements IFluidHandler { - final List list = this.getOutputs(resource.getFluid()); - int requestTotal = 0; - - Iterator i = list.iterator(); - - while (i.hasNext()) { - final FluidP2PTunnelPart l = i.next(); - final IFluidHandler tank = l.getTarget().orElse(null); - if (tank != null) { - l.tmpUsed = tank.fill(resource.copy(), FluidAction.SIMULATE); - } else { - l.tmpUsed = 0; - } - - if (l.tmpUsed <= 0) { - i.remove(); - } else { - requestTotal += l.tmpUsed; - } + @Override + public int getTanks() { + return 1; } - if (requestTotal <= 0) { - if (stack.pop() != this) { - throw new IllegalStateException("Invalid Recursion detected."); + @Override + @Nonnull + public FluidStack getFluidInTank(int tank) { + return FluidStack.EMPTY; + } + + @Override + public int getTankCapacity(int tank) { + return Integer.MAX_VALUE; + } + + @Override + public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { + return true; + } + + @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) { } + 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; + } + + } + + private class OutputFluidHandler implements IFluidHandler { + + @Override + public int getTanks() { + return FluidP2PTunnelPart.this.getAttachedFluidHandler().getTanks(); + } + + @Override + @Nonnull + public FluidStack getFluidInTank(int tank) { + return FluidP2PTunnelPart.this.getAttachedFluidHandler().getFluidInTank(tank); + } + + @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; } - if (action != FluidAction.EXECUTE) { - if (stack.pop() != this) { - throw new IllegalStateException("Invalid Recursion detected."); - } - - return Math.min(resource.getAmount(), requestTotal); + @Override + @Nonnull + public FluidStack drain(FluidStack resource, FluidAction action) { + return FluidP2PTunnelPart.this.getAttachedFluidHandler().drain(resource, action); } - int available = resource.getAmount(); - - i = list.iterator(); - int used = 0; - - while (i.hasNext() && available > 0) { - final FluidP2PTunnelPart l = i.next(); - - final FluidStack insert = resource.copy(); - insert.setAmount((int) Math.ceil(insert.getAmount() * ((double) l.tmpUsed / (double) requestTotal))); - if (insert.getAmount() > available) { - insert.setAmount(available); - } - - final IFluidHandler tank = l.getTarget().orElse(null); - if (tank != null) { - l.tmpUsed = tank.fill(insert.copy(), action); - } else { - l.tmpUsed = 0; - } - - available -= insert.getAmount(); - used += l.tmpUsed; + @Override + @Nonnull + public FluidStack drain(int maxDrain, FluidAction action) { + return FluidP2PTunnelPart.this.getAttachedFluidHandler().drain(maxDrain, action); } - - if (stack.pop() != this) { - throw new IllegalStateException("Invalid Recursion detected."); - } - - return used; } - @Override - @Nonnull - public FluidStack drain(FluidStack resource, FluidAction action) { - return FluidStack.EMPTY; - } + private static class NullFluidHandler implements IFluidHandler { - @Override - @Nonnull - public FluidStack drain(int maxDrain, FluidAction action) { - return FluidStack.EMPTY; - } - - private Deque getDepth() { - Deque s = DEPTH.get(); - - if (s == null) { - DEPTH.set(s = new ArrayDeque<>()); + @Override + public int getTanks() { + return 0; } - return s; - } - - private List getOutputs(final Fluid input) { - final List outs = new ArrayList<>(); - - try { - for (final FluidP2PTunnelPart l : this.getOutputs()) { - final IFluidHandler handler = l.getTarget().orElse(null); - - if (handler != null) { - outs.add(l); - } - } - } catch (final GridAccessException e) { - // :P + @Override + @Nonnull + public FluidStack getFluidInTank(int tank) { + return FluidStack.EMPTY; } - return outs; - } - - private LazyOptional getTarget() { - if (!this.getProxy().isActive()) { - return null; + @Override + public int getTankCapacity(int tank) { + return 0; } - if (this.cachedTank != null) { - return this.cachedTank; + @Override + public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { + return false; } - final TileEntity te = this.getTile().getWorld() - .getTileEntity(this.getTile().getPos().offset(this.getSide().getFacing())); - - if (te != null && te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, - this.getSide().getFacing().getOpposite()).isPresent()) { - return this.cachedTank = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, - this.getSide().getFacing().getOpposite()); + @Override + public int fill(FluidStack resource, FluidAction action) { + return 0; } - return null; + @Override + @Nonnull + public FluidStack drain(FluidStack resource, FluidAction action) { + return FluidStack.EMPTY; + } + + @Override + @Nonnull + public FluidStack drain(int maxDrain, FluidAction action) { + return FluidStack.EMPTY; + } } } From eab6483bd7c10c7f6e1b8a5335a32b4cfb5dd492 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Tue, 4 Aug 2020 19:49:11 +0200 Subject: [PATCH 06/11] Fixes #4551: Bounding box of annihilation planes is too small. --- .../parts/automation/AnnihilationPlanePart.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/appeng/parts/automation/AnnihilationPlanePart.java b/src/main/java/appeng/parts/automation/AnnihilationPlanePart.java index 29071a678..1488b0bff 100644 --- a/src/main/java/appeng/parts/automation/AnnihilationPlanePart.java +++ b/src/main/java/appeng/parts/automation/AnnihilationPlanePart.java @@ -108,6 +108,15 @@ public class AnnihilationPlanePart extends BasicStatePart implements IGridTickab @Override public void getBoxes(final IPartCollisionHelper bch) { + + // 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; + } + int minX = 1; int minY = 1; int maxX = 15; @@ -140,9 +149,7 @@ public class AnnihilationPlanePart extends BasicStatePart implements IGridTickab } 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); + bch.addBox(minX, minY, 15, maxX, maxY, 16); } /** From 9bc844738caaf77604204bc746012f242ec923e9 Mon Sep 17 00:00:00 2001 From: shartte Date: Wed, 5 Aug 2020 16:33:44 +0200 Subject: [PATCH 07/11] Fixes #4547: Name clash between ITooltip#getWidth, ITooltip#getHeight and Vanilla Widget methods leads to missing methods at runtime, since the implementing methods will be remapped to SRG names, while referees of the interface will try to call the renamed methods by their name in the interface, leading to an AbstractMethodError. (#4557) --- .../java/appeng/client/gui/AEBaseScreen.java | 24 +++++++++---------- .../client/gui/widgets/ActionButton.java | 2 +- .../client/gui/widgets/CustomSlotWidget.java | 12 +++++----- .../appeng/client/gui/widgets/ITooltip.java | 12 +++++----- .../appeng/client/gui/widgets/IconButton.java | 16 +++++++++---- .../client/gui/widgets/ProgressBar.java | 12 +++++----- .../gui/widgets/SettingToggleButton.java | 2 +- .../appeng/client/gui/widgets/TabButton.java | 15 ++++++++---- .../client/gui/widgets/ToggleButton.java | 12 +++++----- .../client/gui/widgets/FluidSlotWidget.java | 8 +++---- .../client/gui/widgets/FluidTankWidget.java | 12 +++++----- .../gui/widgets/OptionalFluidSlotWidget.java | 5 ++-- 12 files changed, 72 insertions(+), 60 deletions(-) diff --git a/src/main/java/appeng/client/gui/AEBaseScreen.java b/src/main/java/appeng/client/gui/AEBaseScreen.java index 34055b47c..d0d6e11a9 100644 --- a/src/main/java/appeng/client/gui/AEBaseScreen.java +++ b/src/main/java/appeng/client/gui/AEBaseScreen.java @@ -158,14 +158,14 @@ public abstract class AEBaseScreen extends ContainerS protected void drawGuiSlot(MatrixStack matrixStack, 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(matrixStack, getMinecraft(), mouseX, mouseY, partialTicks); - if (this.isPointInRegion(left, top, slot.getWidth(), slot.getHeight(), mouseX, mouseY) + if (this.isPointInRegion(left, top, slot.getTooltipAreaWidth(), slot.getTooltipAreaHeight(), mouseX, mouseY) && slot.canClick(getPlayer())) { RenderSystem.colorMask(true, true, true, false); this.fillGradient(matrixStack, left, top, right, bottom, -2130706433, -2130706433); @@ -175,16 +175,16 @@ public abstract class AEBaseScreen extends ContainerS } private void drawTooltip(MatrixStack matrixStack, ITooltip tooltip, int mouseX, int mouseY) { - final int x = tooltip.xPos(); // ((GuiImgButton) c).x; - int y = tooltip.yPos(); // ((GuiImgButton) c).y; + 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 ITextComponent msg = tooltip.getMessage(); + final ITextComponent msg = tooltip.getTooltipMessage(); this.drawTooltip(matrixStack, x + 11, y + 4, msg); } } @@ -285,8 +285,8 @@ public abstract class AEBaseScreen extends ContainerS } for (CustomSlotWidget slot : this.guiSlots) { - if (this.isPointInRegion(slot.xPos(), slot.yPos(), slot.getWidth(), slot.getHeight(), xCoord, yCoord) - && slot.canClick(getPlayer())) { + if (this.isPointInRegion(slot.getTooltipAreaX(), slot.getTooltipAreaY(), slot.getTooltipAreaWidth(), + slot.getTooltipAreaHeight(), xCoord, yCoord) && slot.canClick(getPlayer())) { slot.slotClicked(getPlayer().inventory.getItemStack(), btn); } } diff --git a/src/main/java/appeng/client/gui/widgets/ActionButton.java b/src/main/java/appeng/client/gui/widgets/ActionButton.java index 8f011582d..00561bbcb 100644 --- a/src/main/java/appeng/client/gui/widgets/ActionButton.java +++ b/src/main/java/appeng/client/gui/widgets/ActionButton.java @@ -27,7 +27,7 @@ import net.minecraft.util.text.StringTextComponent; 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; diff --git a/src/main/java/appeng/client/gui/widgets/CustomSlotWidget.java b/src/main/java/appeng/client/gui/widgets/CustomSlotWidget.java index bb9308ae5..abece0745 100644 --- a/src/main/java/appeng/client/gui/widgets/CustomSlotWidget.java +++ b/src/main/java/appeng/client/gui/widgets/CustomSlotWidget.java @@ -39,32 +39,32 @@ public abstract class CustomSlotWidget extends AbstractGui implements ITooltip { } @Override - public ITextComponent getMessage() { + public ITextComponent getTooltipMessage() { return StringTextComponent.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; } diff --git a/src/main/java/appeng/client/gui/widgets/ITooltip.java b/src/main/java/appeng/client/gui/widgets/ITooltip.java index bb0018cb4..1f75f19c6 100644 --- a/src/main/java/appeng/client/gui/widgets/ITooltip.java +++ b/src/main/java/appeng/client/gui/widgets/ITooltip.java @@ -36,38 +36,38 @@ public interface ITooltip { * @return tooltip message */ @Nonnull - ITextComponent getMessage(); + ITextComponent 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(); } diff --git a/src/main/java/appeng/client/gui/widgets/IconButton.java b/src/main/java/appeng/client/gui/widgets/IconButton.java index 075c63c3a..fcf88e4bb 100644 --- a/src/main/java/appeng/client/gui/widgets/IconButton.java +++ b/src/main/java/appeng/client/gui/widgets/IconButton.java @@ -25,6 +25,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.widget.button.Button; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.StringTextComponent; import net.minecraftforge.fml.client.gui.GuiUtils; @@ -97,27 +98,32 @@ public abstract class IconButton extends Button implements ITooltip { protected abstract int getIconIndex(); @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 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; } diff --git a/src/main/java/appeng/client/gui/widgets/ProgressBar.java b/src/main/java/appeng/client/gui/widgets/ProgressBar.java index 2fa20b7b6..85f646e5c 100644 --- a/src/main/java/appeng/client/gui/widgets/ProgressBar.java +++ b/src/main/java/appeng/client/gui/widgets/ProgressBar.java @@ -81,7 +81,7 @@ public class ProgressBar extends Widget implements ITooltip { } @Override - public ITextComponent getMessage() { + public ITextComponent getTooltipMessage() { if (this.fullMsg != null) { return this.fullMsg; } @@ -92,27 +92,27 @@ public class ProgressBar extends Widget 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; } diff --git a/src/main/java/appeng/client/gui/widgets/SettingToggleButton.java b/src/main/java/appeng/client/gui/widgets/SettingToggleButton.java index 74ecf64d8..b80b38f35 100644 --- a/src/main/java/appeng/client/gui/widgets/SettingToggleButton.java +++ b/src/main/java/appeng/client/gui/widgets/SettingToggleButton.java @@ -279,7 +279,7 @@ public class SettingToggleButton> extends IconButton { } @Override - public ITextComponent getMessage() { + public ITextComponent getTooltipMessage() { ITextComponent displayName = null; ITextComponent displayValue = null; diff --git a/src/main/java/appeng/client/gui/widgets/TabButton.java b/src/main/java/appeng/client/gui/widgets/TabButton.java index afc8c660e..bd1154065 100644 --- a/src/main/java/appeng/client/gui/widgets/TabButton.java +++ b/src/main/java/appeng/client/gui/widgets/TabButton.java @@ -99,27 +99,32 @@ public class TabButton extends Button 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; } diff --git a/src/main/java/appeng/client/gui/widgets/ToggleButton.java b/src/main/java/appeng/client/gui/widgets/ToggleButton.java index 254cabf14..be6953266 100644 --- a/src/main/java/appeng/client/gui/widgets/ToggleButton.java +++ b/src/main/java/appeng/client/gui/widgets/ToggleButton.java @@ -77,7 +77,7 @@ public class ToggleButton extends Button implements ITooltip { } @Override - public ITextComponent getMessage() { + public ITextComponent getTooltipMessage() { if (this.displayName != null) { String name = I18n.format(this.displayName); String value = I18n.format(this.displayHint); @@ -106,27 +106,27 @@ public class ToggleButton extends Button 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; } } diff --git a/src/main/java/appeng/fluids/client/gui/widgets/FluidSlotWidget.java b/src/main/java/appeng/fluids/client/gui/widgets/FluidSlotWidget.java index 75de9a589..86e825b2e 100644 --- a/src/main/java/appeng/fluids/client/gui/widgets/FluidSlotWidget.java +++ b/src/main/java/appeng/fluids/client/gui/widgets/FluidSlotWidget.java @@ -1,6 +1,5 @@ package appeng.fluids.client.gui.widgets; -import java.awt.TextComponent; import java.util.Collections; import com.mojang.blaze3d.matrix.MatrixStack; @@ -57,7 +56,8 @@ public class FluidSlotWidget extends CustomSlotWidget { final float blue = (attributes.getColor() & 255) / 255.0F; RenderSystem.color3f(red, green, blue); - blit(matrixStack, xPos(), yPos(), this.getBlitOffset(), getWidth(), getHeight(), sprite); + blit(matrixStack, getTooltipAreaX(), getTooltipAreaY(), this.getBlitOffset(), getTooltipAreaWidth(), + getTooltipAreaHeight(), sprite); } } @@ -81,7 +81,7 @@ public class FluidSlotWidget extends CustomSlotWidget { } @Override - public ITextComponent getMessage() { + public ITextComponent getTooltipMessage() { final IAEFluidStack fluid = this.getFluidStack(); if (fluid != null) { return new TranslationTextComponent(fluid.getFluidStack().getTranslationKey()); @@ -90,7 +90,7 @@ public class FluidSlotWidget extends CustomSlotWidget { } @Override - public boolean isVisible() { + public boolean isTooltipAreaVisible() { return true; } diff --git a/src/main/java/appeng/fluids/client/gui/widgets/FluidTankWidget.java b/src/main/java/appeng/fluids/client/gui/widgets/FluidTankWidget.java index 05a4625a9..e0eda6b9b 100644 --- a/src/main/java/appeng/fluids/client/gui/widgets/FluidTankWidget.java +++ b/src/main/java/appeng/fluids/client/gui/widgets/FluidTankWidget.java @@ -89,7 +89,7 @@ public class FluidTankWidget extends Widget implements ITooltip { } @Override - public ITextComponent getMessage() { + public ITextComponent getTooltipMessage() { final IAEFluidStack fluid = this.tank.getFluidInSlot(this.slot); if (fluid != null && fluid.getStackSize() > 0) { return fluid.getFluid().getAttributes().getDisplayName(fluid.getFluidStack()).deepCopy() @@ -99,27 +99,27 @@ public class FluidTankWidget extends Widget 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; } diff --git a/src/main/java/appeng/fluids/client/gui/widgets/OptionalFluidSlotWidget.java b/src/main/java/appeng/fluids/client/gui/widgets/OptionalFluidSlotWidget.java index 882bc8251..b006d2f46 100644 --- a/src/main/java/appeng/fluids/client/gui/widgets/OptionalFluidSlotWidget.java +++ b/src/main/java/appeng/fluids/client/gui/widgets/OptionalFluidSlotWidget.java @@ -48,7 +48,8 @@ public class OptionalFluidSlotWidget extends FluidSlotWidget { } else { RenderSystem.color4f(1.0F, 1.0F, 1.0F, 0.4F); } - GuiUtils.drawTexturedModalRect(guileft + this.xPos() - 1, guitop + this.yPos() - 1, this.srcX - 1, - this.srcY - 1, this.getWidth() + 2, this.getHeight() + 2, currentZIndex); + GuiUtils.drawTexturedModalRect(guileft + this.getTooltipAreaX() - 1, guitop + this.getTooltipAreaY() - 1, + this.srcX - 1, this.srcY - 1, this.getTooltipAreaWidth() + 2, this.getTooltipAreaHeight() + 2, + currentZIndex); } } From 8617dc8340ea1862662926562bc503260689303c Mon Sep 17 00:00:00 2001 From: shartte Date: Wed, 5 Aug 2020 17:45:33 +0200 Subject: [PATCH 08/11] Plane Connection Refactor (#4556) * Refactors all plane parts to use a common helper for calculating connections to adjacent planes. Also fixes problems with updating these connections on neighbor updates. * Fix conflicting GuiSync ID. * Slightly refactor PlaneConnectionHelper, and fix an issue where the bounding box was calculated incorrectly by using the wrong up-direction. --- .../FormationPlaneContainer.java | 2 +- .../parts/FluidAnnihilationPlanePart.java | 113 +------------ .../AbstractFormationPlanePart.java | 110 +----------- .../automation/AnnihilationPlanePart.java | 112 +----------- .../parts/automation/FormationPlanePart.java | 10 -- .../IdentityAnnihilationPlanePart.java | 9 - .../automation/PlaneConnectionHelper.java | 160 ++++++++++++++++++ 7 files changed, 180 insertions(+), 336 deletions(-) create mode 100644 src/main/java/appeng/parts/automation/PlaneConnectionHelper.java diff --git a/src/main/java/appeng/container/implementations/FormationPlaneContainer.java b/src/main/java/appeng/container/implementations/FormationPlaneContainer.java index 21830b75d..3ec08634c 100644 --- a/src/main/java/appeng/container/implementations/FormationPlaneContainer.java +++ b/src/main/java/appeng/container/implementations/FormationPlaneContainer.java @@ -52,7 +52,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) { diff --git a/src/main/java/appeng/fluids/parts/FluidAnnihilationPlanePart.java b/src/main/java/appeng/fluids/parts/FluidAnnihilationPlanePart.java index a1efa33a1..6708c87c8 100644 --- a/src/main/java/appeng/fluids/parts/FluidAnnihilationPlanePart.java +++ b/src/main/java/appeng/fluids/parts/FluidAnnihilationPlanePart.java @@ -14,7 +14,6 @@ import net.minecraft.item.ItemStack; import net.minecraft.tags.FluidTags; import net.minecraft.tags.ITag; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockReader; @@ -35,15 +34,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; @@ -53,6 +49,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.PlaneModelData; import appeng.parts.automation.PlaneModels; @@ -73,115 +70,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 TileEntity te = host.getTile(); - - final BlockPos pos = te.getPos(); - - final Direction e = bch.getWorldX(); - final Direction u = bch.getWorldY(); - - if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(e.getOpposite())), this.getSide())) { - minX = 0; - } - - if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(e)), this.getSide())) { - maxX = 16; - } - - if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(u.getOpposite())), this.getSide())) { - minY = 0; - } - - if (this.isAnnihilationPlane(te.getWorld().getTileEntity(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 TileEntity te = host.getTile(); - - final BlockPos pos = te.getPos(); - - if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(facingRight.getOpposite())), - this.getSide())) { - left = true; - } - - if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(facingRight)), this.getSide())) { - right = true; - } - - if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(facingUp.getOpposite())), - this.getSide())) { - down = true; - } - - if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(facingUp)), this.getSide())) { - up = true; - } - } - - return PlaneConnections.of(up, right, down, left); + return connectionHelper.getConnections(); } @Override public void onNeighborChanged(IBlockReader w, BlockPos pos, BlockPos neighbor) { if (pos.offset(this.getSide().getFacing()).equals(neighbor)) { this.refresh(); + } else { + connectionHelper.updateConnections(); } } @@ -190,14 +99,6 @@ public class FluidAnnihilationPlanePart extends BasicStatePart implements IGridT return 1; } - private boolean isAnnihilationPlane(final TileEntity 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()); diff --git a/src/main/java/appeng/parts/automation/AbstractFormationPlanePart.java b/src/main/java/appeng/parts/automation/AbstractFormationPlanePart.java index ef60254f3..b1953e6bc 100644 --- a/src/main/java/appeng/parts/automation/AbstractFormationPlanePart.java +++ b/src/main/java/appeng/parts/automation/AbstractFormationPlanePart.java @@ -4,16 +4,13 @@ package appeng.parts.automation; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockReader; 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 +27,7 @@ public abstract class AbstractFormationPlanePart> 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 +62,11 @@ public abstract class AbstractFormationPlanePart> 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 TileEntity te = host.getTile(); - - final BlockPos pos = te.getPos(); - - final Direction e = bch.getWorldX(); - final Direction u = bch.getWorldY(); - - if (this.isTransitionPlane(te.getWorld().getTileEntity(pos.offset(e.getOpposite())), this.getSide())) { - minX = 0; - } - - if (this.isTransitionPlane(te.getWorld().getTileEntity(pos.offset(e)), this.getSide())) { - maxX = 16; - } - - if (this.isTransitionPlane(te.getWorld().getTileEntity(pos.offset(u.getOpposite())), this.getSide())) { - minY = 0; - } - - if (this.isTransitionPlane(te.getWorld().getTileEntity(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 TileEntity te = host.getTile(); - - final BlockPos pos = te.getPos(); - - if (this.isTransitionPlane(te.getWorld().getTileEntity(pos.offset(facingRight.getOpposite())), - this.getSide())) { - left = true; - } - - if (this.isTransitionPlane(te.getWorld().getTileEntity(pos.offset(facingRight)), this.getSide())) { - right = true; - } - - if (this.isTransitionPlane(te.getWorld().getTileEntity(pos.offset(facingUp.getOpposite())), - this.getSide())) { - down = true; - } - - if (this.isTransitionPlane(te.getWorld().getTileEntity(pos.offset(facingUp)), this.getSide())) { - up = true; - } - } - - return PlaneConnections.of(up, right, down, left); + return connectionHelper.getConnections(); } @Override @@ -172,6 +78,8 @@ public abstract class AbstractFormationPlanePart> extends final BlockPos tePos = te.getPos().offset(side.getFacing()); this.blocked = !w.getBlockState(tePos).getMaterial().isReplaceable(); + } else { + connectionHelper.updateConnections(); } } @@ -180,14 +88,6 @@ public abstract class AbstractFormationPlanePart> extends return 1; } - protected boolean isTransitionPlane(final TileEntity 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; diff --git a/src/main/java/appeng/parts/automation/AnnihilationPlanePart.java b/src/main/java/appeng/parts/automation/AnnihilationPlanePart.java index 1488b0bff..36e08f294 100644 --- a/src/main/java/appeng/parts/automation/AnnihilationPlanePart.java +++ b/src/main/java/appeng/parts/automation/AnnihilationPlanePart.java @@ -35,7 +35,6 @@ import net.minecraft.tags.BlockTags; import net.minecraft.tags.ITag; import net.minecraft.tags.ItemTags; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; @@ -58,9 +57,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; @@ -96,12 +93,14 @@ 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); } @@ -117,39 +116,8 @@ public class AnnihilationPlanePart extends BasicStatePart implements IGridTickab return; } - int minX = 1; - int minY = 1; - int maxX = 15; - int maxY = 15; + connectionHelper.getBoxes(bch); - final IPartHost host = this.getHost(); - if (host != null) { - final TileEntity te = host.getTile(); - - final BlockPos pos = te.getPos(); - - final Direction e = bch.getWorldX(); - final Direction u = bch.getWorldY(); - - if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(e.getOpposite())), this.getSide())) { - minX = 0; - } - - if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(e)), this.getSide())) { - maxX = 16; - } - - if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(u.getOpposite())), this.getSide())) { - minY = 0; - } - - if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(e)), this.getSide())) { - maxY = 16; - } - } - - bch.addBox(5, 5, 14, 11, 11, 15); - bch.addBox(minX, minY, 15, maxX, maxY, 16); } /** @@ -157,73 +125,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 TileEntity te = host.getTile(); - - final BlockPos pos = te.getPos(); - - if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(facingRight.getOpposite())), - this.getSide())) { - left = true; - } - - if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(facingRight)), this.getSide())) { - right = true; - } - - if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(facingUp.getOpposite())), - this.getSide())) { - down = true; - } - - if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(facingUp)), this.getSide())) { - up = true; - } - } - - return PlaneConnections.of(up, right, down, left); + return connectionHelper.getConnections(); } @Override public void onNeighborChanged(IBlockReader w, BlockPos pos, BlockPos neighbor) { if (pos.offset(this.getSide().getFacing()).equals(neighbor)) { this.refresh(); + } else { + connectionHelper.updateConnections(); } } @@ -369,14 +279,6 @@ public class AnnihilationPlanePart extends BasicStatePart implements IGridTickab return changed; } - protected boolean isAnnihilationPlane(final TileEntity 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) { diff --git a/src/main/java/appeng/parts/automation/FormationPlanePart.java b/src/main/java/appeng/parts/automation/FormationPlanePart.java index 639227a1e..644e7fb2e 100644 --- a/src/main/java/appeng/parts/automation/FormationPlanePart.java +++ b/src/main/java/appeng/parts/automation/FormationPlanePart.java @@ -23,7 +23,6 @@ import java.util.Collections; import java.util.List; import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.entity.Entity; import net.minecraft.entity.item.ItemEntity; @@ -35,7 +34,6 @@ import net.minecraft.item.FireworkRocketItem; import net.minecraft.item.FireworkStarItem; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.item.ItemUseContext; import net.minecraft.item.WallOrFloorItem; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; @@ -44,7 +42,6 @@ import net.minecraft.util.Direction; import net.minecraft.util.Hand; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import net.minecraft.world.server.ServerWorld; @@ -364,11 +361,4 @@ public class FormationPlanePart extends AbstractFormationPlanePart return list.size(); } - private class ForcedItemUseContext extends ItemUseContext { - protected ForcedItemUseContext(World worldIn, @Nullable PlayerEntity player, Hand handIn, ItemStack heldItem, - BlockRayTraceResult rayTraceResultIn) { - super(worldIn, player, handIn, heldItem, rayTraceResultIn); - } - } - } diff --git a/src/main/java/appeng/parts/automation/IdentityAnnihilationPlanePart.java b/src/main/java/appeng/parts/automation/IdentityAnnihilationPlanePart.java index cb187f5e0..27d457465 100644 --- a/src/main/java/appeng/parts/automation/IdentityAnnihilationPlanePart.java +++ b/src/main/java/appeng/parts/automation/IdentityAnnihilationPlanePart.java @@ -55,15 +55,6 @@ public class IdentityAnnihilationPlanePart extends AnnihilationPlanePart { super(is); } - @Override - protected boolean isAnnihilationPlane(final TileEntity 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 items) { final float requiredEnergy = super.calculateEnergyUsage(w, pos, items); diff --git a/src/main/java/appeng/parts/automation/PlaneConnectionHelper.java b/src/main/java/appeng/parts/automation/PlaneConnectionHelper.java new file mode 100644 index 000000000..31d7ee5a8 --- /dev/null +++ b/src/main/java/appeng/parts/automation/PlaneConnectionHelper.java @@ -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; + } + +} From 12e3fa9127cbd0db7c0186811b311a20b2034123 Mon Sep 17 00:00:00 2001 From: yueh Date: Wed, 5 Aug 2020 17:56:42 +0200 Subject: [PATCH 09/11] Makes formation planes a bit more consistent and less violent. (#4553) * Makes formation planes a bit more consistent and less violent. Items will now have a slower speed when spawning as well as a narrower area to avoid having them glitch into a wall and be teleported around * Removed debug output, added clarifying parenthesis and extracted method. * Fixes various other issues with the formation plane Also removed now useless code Co-authored-by: Sebastian Hartte --- .../parts/automation/FormationPlanePart.java | 212 ++++++++++++------ 1 file changed, 138 insertions(+), 74 deletions(-) diff --git a/src/main/java/appeng/parts/automation/FormationPlanePart.java b/src/main/java/appeng/parts/automation/FormationPlanePart.java index 644e7fb2e..c3286a139 100644 --- a/src/main/java/appeng/parts/automation/FormationPlanePart.java +++ b/src/main/java/appeng/parts/automation/FormationPlanePart.java @@ -21,32 +21,31 @@ package appeng.parts.automation; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Random; import javax.annotation.Nonnull; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.inventory.container.ContainerType; -import net.minecraft.item.BlockItem; +import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.DirectionalPlaceContext; -import net.minecraft.item.FireworkRocketItem; -import net.minecraft.item.FireworkStarItem; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.item.WallOrFloorItem; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.ActionResultType; import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; import net.minecraft.util.Hand; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import net.minecraft.world.server.ServerWorld; import net.minecraftforge.client.model.data.IModelData; -import net.minecraftforge.common.IPlantable; import net.minecraftforge.items.IItemHandler; import appeng.api.config.AccessRestriction; @@ -61,7 +60,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; @@ -86,6 +84,7 @@ import appeng.util.prioritylist.PrecisePriorityList; public class FormationPlanePart extends AbstractFormationPlanePart { 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 getModels() { @@ -219,12 +218,12 @@ public class FormationPlanePart extends AbstractFormationPlanePart final BlockPos placePos = te.getPos().offset(side.getFacing()); if (w.getBlockState(placePos).getMaterial().isReplaceable()) { - if (placeBlock == YesNo.YES && (i instanceof BlockItem || i instanceof IPlantable - || i instanceof FireworkStarItem || i instanceof FireworkRocketItem || i instanceof IPartItem)) { + if (placeBlock == YesNo.YES) { final PlayerEntity player = Platform.getPlayer((ServerWorld) w); Platform.configurePlayer(player, side, this.getTile()); - Hand hand = player.getActiveHand(); - player.setHeldItem(hand, is); + // Seems to work without... + // Hand hand = player.getActiveHand(); + // player.setHeldItem(hand, is); maxStorage = is.getCount(); worked = true; @@ -232,84 +231,33 @@ public class FormationPlanePart extends AbstractFormationPlanePart // 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 IPlantable || i instanceof WallOrFloorItem) { - boolean Worked = false; + i.onItemUse(context); + maxStorage -= is.getCount(); - // Up or Down, Attempt 1?? - if (side.xOffset == 0 && side.zOffset == 0) { - Worked = i.onItemUse(new DirectionalPlaceContext(w, placePos.offset(side.getFacing()), - lookDirection, is, side.getFacing())) == ActionResultType.SUCCESS; - } - - // Up or Down, Attempt 2?? - if (!Worked && side.xOffset == 0 && side.zOffset == 0) { - Worked = i.onItemUse(new DirectionalPlaceContext(w, - placePos.offset(side.getFacing().getOpposite()), lookDirection, is, - side.getFacing().getOpposite())) == ActionResultType.SUCCESS; - } - - // Horizontal, attempt 1?? - if (!Worked && side.yOffset == 0) { - Worked = i.onItemUse(new DirectionalPlaceContext(w, placePos.offset(Direction.DOWN), - lookDirection, is, Direction.DOWN)) == ActionResultType.SUCCESS; - } - - if (!Worked) { - i.onItemUse(new DirectionalPlaceContext(w, placePos, lookDirection, is, - lookDirection.getOpposite())); - } - - maxStorage -= is.getCount(); - } else { - i.onItemUse(new DirectionalPlaceContext(w, placePos, lookDirection, is, - lookDirection.getOpposite())); - maxStorage -= is.getCount(); - } } else { maxStorage = 1; } - // Safe keeping - player.setHeldItem(hand, ItemStack.EMPTY); + // Seems to work without... Safe keeping + // player.setHeldItem(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()); - - Entity result = ei; - - ei.setMotion(side.xOffset * 0.2, side.yOffset * 0.2, side.zOffset * 0.2); - - if (is.getItem().hasCustomEntity(is)) { - result = is.getItem().createEntity(w, ei, is); - if (result != null) { - ei.remove(); - } else { - result = ei; - } - } - - if (!w.addEntity(result)) { - result.remove(); + if (!spawnItemEntity(w, te, side, is)) { + // revert in case something prevents spawning. worked = false; } + } - } else { - worked = false; } } } @@ -328,6 +276,57 @@ public class FormationPlanePart extends AbstractFormationPlanePart return input; } + private static boolean spawnItemEntity(World w, TileEntity 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()); + Entity result = ei; + + ei.setMotion(side.xOffset * .1, side.yOffset * 0.1, side.zOffset * 0.1); + + if (is.getItem().hasCustomEntity(is)) { + result = is.getItem().createEntity(w, ei, is); + if (result != null) { + ei.remove(); + } else { + result = ei; + } + } + + if (!w.addEntity(result)) { + result.remove(); + return false; + } + return true; + } + @Override public IStorageChannel getChannel() { return Api.instance().storage().getStorageChannel(IItemStorageChannel.class); @@ -361,4 +360,69 @@ public class FormationPlanePart extends AbstractFormationPlanePart return list.size(); } + /** + * A custom {@link DirectionalPlaceContext} which also accepts a player needed + * various blocks like seeds. + *

+ * 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; + } + + public BlockPos getPos() { + return this.rayTraceResult.getPos(); + } + + public boolean canPlace() { + return this.world.getBlockState(this.rayTraceResult.getPos()).isReplaceable(this); + } + + public Direction getNearestLookingDirection() { + return Direction.DOWN; + } + + 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 }; + } + } + + public Direction getPlacementHorizontalFacing() { + return this.lookDirection.getAxis() == Axis.Y ? Direction.NORTH : this.lookDirection; + } + + public boolean func_225518_g_() { + return false; + } + + public float getPlacementYaw() { + return (float) (this.lookDirection.getHorizontalIndex() * 90); + } + } } From 1404806d3daa1a371aeda27068b158f48d8fc953 Mon Sep 17 00:00:00 2001 From: yueh Date: Wed, 5 Aug 2020 21:52:34 +0200 Subject: [PATCH 10/11] Fixes #4559: Use visual bounding box for overlay (#4561) --- src/main/java/appeng/facade/FacadePart.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/appeng/facade/FacadePart.java b/src/main/java/appeng/facade/FacadePart.java index e010a513d..e59bcc9b0 100644 --- a/src/main/java/appeng/facade/FacadePart.java +++ b/src/main/java/appeng/facade/FacadePart.java @@ -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 { From 822249dda898bba469751a2ee1246d52113f4ca9 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Wed, 5 Aug 2020 22:10:53 +0200 Subject: [PATCH 11/11] Added missing @Override annotations. --- .../java/appeng/parts/automation/FormationPlanePart.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/appeng/parts/automation/FormationPlanePart.java b/src/main/java/appeng/parts/automation/FormationPlanePart.java index c3286a139..f53faf259 100644 --- a/src/main/java/appeng/parts/automation/FormationPlanePart.java +++ b/src/main/java/appeng/parts/automation/FormationPlanePart.java @@ -377,18 +377,22 @@ public class FormationPlanePart extends AbstractFormationPlanePart 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: @@ -413,14 +417,17 @@ public class FormationPlanePart extends AbstractFormationPlanePart } } + @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); }