Files
Applied-Energistics-2/src/main/java/appeng/fluids/parts/FluidAnnihilationPlanePart.java
T
2020-07-01 21:27:37 +02:00

321 lines
11 KiB
Java

package appeng.fluids.parts;
import java.util.List;
import javax.annotation.Nonnull;
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
import net.minecraft.block.BlockState;
import net.minecraft.block.IBucketPickupHandler;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.Fluids;
import net.minecraft.fluid.IFluidState;
import net.minecraft.item.ItemStack;
import net.minecraft.tag.FluidTags;
import net.minecraft.tag.Tag;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import net.minecraftforge.fluids.FluidAttributes;
import appeng.api.AEApi;
import appeng.api.config.Actionable;
import appeng.api.config.PowerMultiplier;
import appeng.api.networking.IGridNode;
import appeng.api.networking.energy.IEnergyGrid;
import appeng.api.networking.events.MENetworkChannelsChanged;
import appeng.api.networking.events.MENetworkEventSubscribe;
import appeng.api.networking.events.MENetworkPowerStatusChange;
import appeng.api.networking.security.IActionSource;
import appeng.api.networking.storage.IStorageGrid;
import appeng.api.networking.ticking.IGridTickable;
import appeng.api.networking.ticking.TickRateModulation;
import appeng.api.networking.ticking.TickingRequest;
import appeng.api.parts.IPart;
import appeng.api.parts.IPartCollisionHelper;
import appeng.api.parts.IPartHost;
import appeng.api.parts.IPartModel;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.channels.IFluidStorageChannel;
import appeng.api.storage.data.IAEFluidStack;
import appeng.api.util.AECableType;
import appeng.api.util.AEPartLocation;
import appeng.core.AppEng;
import appeng.core.settings.TickRates;
import appeng.core.sync.packets.BlockTransitionEffectPacket;
import appeng.fluids.util.AEFluidStack;
import appeng.items.parts.PartModels;
import appeng.me.GridAccessException;
import appeng.me.helpers.MachineSource;
import appeng.parts.BasicStatePart;
import appeng.parts.automation.PlaneConnections;
import appeng.parts.automation.PlaneModelData;
import appeng.parts.automation.PlaneModels;
import appeng.util.Platform;
public class FluidAnnihilationPlanePart extends BasicStatePart implements IGridTickable {
public static final Identifier TAG_BLACKLIST = new Identifier(AppEng.MOD_ID,
"blacklisted/fluid_annihilation_plane");
private static final PlaneModels MODELS = new PlaneModels("part/fluid_annihilation_plane",
"part/fluid_annihilation_plane_on");
@PartModels
public static List<IPartModel> getModels() {
return MODELS.getModels();
}
private final IActionSource mySrc = new MachineSource(this);
public FluidAnnihilationPlanePart(final ItemStack is) {
super(is);
}
@Override
public void getBoxes(final IPartCollisionHelper bch) {
int minX = 1;
int minY = 1;
int maxX = 15;
int maxY = 15;
final IPartHost host = this.getHost();
if (host != null) {
final BlockEntity te = host.getTile();
final BlockPos pos = te.getPos();
final Direction e = bch.getWorldX();
final Direction u = bch.getWorldY();
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(e.getOpposite())), this.getSide())) {
minX = 0;
}
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(e)), this.getSide())) {
maxX = 16;
}
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(u.getOpposite())), this.getSide())) {
minY = 0;
}
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(e)), this.getSide())) {
maxY = 16;
}
}
bch.addBox(5, 5, 14, 11, 11, 15);
bch.addBox(minX, minY, 15, maxX, maxY, 16);
}
public PlaneConnections getConnections() {
final Direction facingRight, facingUp;
AEPartLocation location = this.getSide();
switch (location) {
case UP:
facingRight = Direction.EAST;
facingUp = Direction.NORTH;
break;
case DOWN:
facingRight = Direction.WEST;
facingUp = Direction.NORTH;
break;
case NORTH:
facingRight = Direction.WEST;
facingUp = Direction.UP;
break;
case SOUTH:
facingRight = Direction.EAST;
facingUp = Direction.UP;
break;
case WEST:
facingRight = Direction.SOUTH;
facingUp = Direction.UP;
break;
case EAST:
facingRight = Direction.NORTH;
facingUp = Direction.UP;
break;
default:
case INTERNAL:
return PlaneConnections.of(false, false, false, false);
}
boolean left = false, right = false, down = false, up = false;
final IPartHost host = this.getHost();
if (host != null) {
final BlockEntity te = host.getTile();
final BlockPos pos = te.getPos();
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(facingRight.getOpposite())),
this.getSide())) {
left = true;
}
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(facingRight)), this.getSide())) {
right = true;
}
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(facingUp.getOpposite())),
this.getSide())) {
down = true;
}
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(facingUp)), this.getSide())) {
up = true;
}
}
return PlaneConnections.of(up, right, down, left);
}
@Override
public void onneighborUpdate(BlockView w, BlockPos pos, BlockPos neighbor) {
if (pos.offset(this.getSide().getFacing()).equals(neighbor)) {
this.refresh();
}
}
@Override
public float getCableConnectionLength(AECableType cable) {
return 1;
}
private boolean isAnnihilationPlane(final BlockEntity blockTileEntity, final AEPartLocation side) {
if (blockTileEntity instanceof IPartHost) {
final IPart p = ((IPartHost) blockTileEntity).getPart(side);
return p != null && p.getClass() == this.getClass();
}
return false;
}
private void refresh() {
try {
this.getProxy().getTick().alertDevice(this.getProxy().getNode());
} catch (final GridAccessException e) {
// :P
}
}
@Override
@MENetworkEventSubscribe
public void chanRender(final MENetworkChannelsChanged c) {
this.refresh();
this.getHost().markForUpdate();
}
@Override
@MENetworkEventSubscribe
public void powerRender(final MENetworkPowerStatusChange c) {
this.refresh();
this.getHost().markForUpdate();
}
private TickRateModulation pickupFluid() {
if (!this.getProxy().isActive()) {
return TickRateModulation.SLEEP;
}
final BlockEntity te = this.getTile();
final World w = te.getWorld();
final BlockPos pos = te.getPos().offset(this.getSide().getFacing());
BlockState blockstate = w.getBlockState(pos);
if (blockstate.getBlock() instanceof IBucketPickupHandler) {
IFluidState fluidState = blockstate.getFluidState();
Fluid fluid = fluidState.getFluid();
if (isFluidBlacklisted(fluid)) {
return TickRateModulation.SLEEP;
}
if (fluid != Fluids.EMPTY && fluidState.isSource()) {
// Attempt to store the fluid in the network
final IAEFluidStack blockFluid = AEFluidStack
.fromFluidStack(new FluidVolume(fluidState.getFluid(), FluidAttributes.BUCKET_VOLUME));
if (this.storeFluid(blockFluid, false)) {
// If that would succeed, actually slurp up the liquid as if we were using a
// bucket
// This _MIGHT_ change the liquid, and if it does, and we dont have enough
// space, tough luck. you loose the source block.
fluid = ((IBucketPickupHandler) blockstate.getBlock()).pickupFluid(w, pos, blockstate);
this.storeFluid(AEFluidStack.fromFluidStack(new FluidVolume(fluid, FluidAttributes.BUCKET_VOLUME)),
true);
AppEng.instance().sendToAllNearExcept(null, pos.getX(), pos.getY(), pos.getZ(), 64, w,
new BlockTransitionEffectPacket(pos, blockstate, this.getSide().getOpposite(),
BlockTransitionEffectPacket.SoundMode.FLUID));
return TickRateModulation.URGENT;
}
return TickRateModulation.IDLE;
}
}
// nothing to do here :)
return TickRateModulation.SLEEP;
}
@Override
public TickingRequest getTickingRequest(final IGridNode node) {
return new TickingRequest(TickRates.AnnihilationPlane.getMin(), TickRates.AnnihilationPlane.getMax(), false,
true);
}
@Override
public TickRateModulation tickingRequest(final IGridNode node, final int ticksSinceLastCall) {
return this.pickupFluid();
}
private boolean storeFluid(IAEFluidStack stack, boolean modulate) {
try {
final IStorageGrid storage = this.getProxy().getStorage();
final IMEInventory<IAEFluidStack> inv = storage
.getInventory(AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class));
if (modulate) {
final IEnergyGrid energy = this.getProxy().getEnergy();
return Platform.poweredInsert(energy, inv, stack, this.mySrc) == null;
} else {
final float requiredPower = stack.getStackSize() / Math.min(1.0f, stack.getChannel().transferFactor());
final IEnergyGrid energy = this.getProxy().getEnergy();
if (energy.extractAEPower(requiredPower, Actionable.SIMULATE, PowerMultiplier.CONFIG) < requiredPower) {
return false;
}
final IAEFluidStack leftOver = inv.injectItems(stack, Actionable.SIMULATE, this.mySrc);
return leftOver == null || leftOver.getStackSize() == 0;
}
} catch (final GridAccessException e) {
// :P
}
return false;
}
@Override
public IPartModel getStaticModels() {
return MODELS.getModel(this.isPowered(), this.isActive());
}
@Nonnull
@Override
public IModelData getModelData() {
return new PlaneModelData(getConnections());
}
private boolean isFluidBlacklisted(Fluid fluid) {
Tag<Fluid> tag = FluidTags.getCollection().getOrCreate(TAG_BLACKLIST);
return fluid.isIn(tag);
}
}