ME Chest
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.block.storage;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Material;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.state.property.EnumProperty;
|
||||
import net.minecraft.state.StateManager;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.Util;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import appeng.block.AEBaseTileBlock;
|
||||
import appeng.core.localization.PlayerMessages;
|
||||
import appeng.tile.storage.ChestBlockEntity;
|
||||
|
||||
public class ChestBlock extends AEBaseTileBlock<ChestBlockEntity> {
|
||||
|
||||
private final static EnumProperty<DriveSlotState> SLOT_STATE = EnumProperty.of("slot_state",
|
||||
DriveSlotState.class);
|
||||
|
||||
public ChestBlock() {
|
||||
super(defaultProps(Material.METAL));
|
||||
this.setDefaultState(this.getDefaultState().with(SLOT_STATE, DriveSlotState.EMPTY));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||
super.appendProperties(builder);
|
||||
builder.add(SLOT_STATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BlockState updateBlockStateFromTileEntity(BlockState currentState, ChestBlockEntity te) {
|
||||
DriveSlotState slotState = DriveSlotState.EMPTY;
|
||||
|
||||
if (te.getCellCount() >= 1) {
|
||||
slotState = DriveSlotState.fromCellStatus(te.getCellStatus(0));
|
||||
}
|
||||
// Power-state has to be checked separately
|
||||
if (!te.isPowered() && slotState != DriveSlotState.EMPTY) {
|
||||
slotState = DriveSlotState.OFFLINE;
|
||||
}
|
||||
|
||||
return currentState.with(SLOT_STATE, slotState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult onActivated(final World w, final BlockPos pos, final PlayerEntity p, final Hand hand,
|
||||
final @Nullable ItemStack heldItem, final BlockHitResult hit) {
|
||||
final ChestBlockEntity tg = this.getBlockEntity(w, pos);
|
||||
if (tg != null && !p.isInSneakingPose()) {
|
||||
if (w.isClient()) {
|
||||
return ActionResult.SUCCESS;
|
||||
}
|
||||
|
||||
if (hit.getSide() == tg.getUp()) {
|
||||
if (!tg.openGui(p)) {
|
||||
p.sendSystemMessage(PlayerMessages.ChestCannotReadStorageCell.get(), Util.NIL_UUID);
|
||||
}
|
||||
} else {
|
||||
// FIXME FABRIC ContainerOpener.openContainer(ChestContainer.TYPE, p,
|
||||
// FIXME FABRIC ContainerLocator.forTileEntitySide(tg, hit.getSide()));
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
return ActionResult.SUCCESS;
|
||||
}
|
||||
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.block.storage;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
|
||||
import appeng.api.util.AEColor;
|
||||
import appeng.bootstrap.BlockRenderingCustomizer;
|
||||
import appeng.bootstrap.IBlockRendering;
|
||||
import appeng.bootstrap.IItemRendering;
|
||||
import appeng.client.render.ColorableTileBlockColor;
|
||||
import appeng.client.render.StaticItemColor;
|
||||
|
||||
public class ChestRendering extends BlockRenderingCustomizer {
|
||||
|
||||
@Override
|
||||
@Environment(EnvType.CLIENT)
|
||||
public void customize(IBlockRendering rendering, IItemRendering itemRendering) {
|
||||
rendering.renderType(RenderLayer.getCutout());
|
||||
|
||||
// I checked, the ME chest doesn't keep its color in item form
|
||||
itemRendering.color(new StaticItemColor(AEColor.TRANSPARENT));
|
||||
rendering.blockColor(new ColorableTileBlockColor());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.block.storage;
|
||||
|
||||
import net.minecraft.util.StringIdentifiable;
|
||||
|
||||
import appeng.api.storage.cells.CellState;
|
||||
|
||||
/**
|
||||
* Describes the different states a single slot of a BlockDrive can be in in
|
||||
* terms of rendering.
|
||||
*/
|
||||
public enum DriveSlotState implements StringIdentifiable {
|
||||
|
||||
// No cell in slot
|
||||
EMPTY("empty"),
|
||||
|
||||
// Cell in slot, but unpowered
|
||||
OFFLINE("offline"),
|
||||
|
||||
// Online and free space
|
||||
ONLINE("online"),
|
||||
|
||||
// Online and not space
|
||||
NOT_EMPTY("not_empty"),
|
||||
|
||||
// Types full, space left
|
||||
TYPES_FULL("types_full"),
|
||||
|
||||
// Completely full
|
||||
FULL("full");
|
||||
|
||||
private final String name;
|
||||
|
||||
DriveSlotState(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asString() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public static DriveSlotState fromCellStatus(CellState cellStatus) {
|
||||
switch (cellStatus) {
|
||||
default:
|
||||
case ABSENT:
|
||||
return DriveSlotState.EMPTY;
|
||||
case EMPTY:
|
||||
return DriveSlotState.ONLINE;
|
||||
case NOT_EMPTY:
|
||||
return DriveSlotState.NOT_EMPTY;
|
||||
case TYPES_FULL:
|
||||
return DriveSlotState.TYPES_FULL;
|
||||
case FULL:
|
||||
return DriveSlotState.FULL;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.client.render;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.client.color.block.BlockColorProvider;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
|
||||
import appeng.api.implementations.tiles.IColorableTile;
|
||||
import appeng.api.util.AEColor;
|
||||
|
||||
/**
|
||||
* Automatically exposes the color of a colorable tile using tint indices 0-2
|
||||
*/
|
||||
public class ColorableTileBlockColor implements BlockColorProvider {
|
||||
|
||||
public static final ColorableTileBlockColor INSTANCE = new ColorableTileBlockColor();
|
||||
|
||||
@Override
|
||||
public int getColor(BlockState state, @Nullable BlockRenderView worldIn, @Nullable BlockPos pos, int tintIndex) {
|
||||
AEColor color = AEColor.TRANSPARENT; // Default to a neutral color
|
||||
|
||||
if (worldIn != null && pos != null) {
|
||||
BlockEntity te = worldIn.getBlockEntity(pos);
|
||||
if (te instanceof IColorableTile) {
|
||||
color = ((IColorableTile) te).getColor();
|
||||
}
|
||||
}
|
||||
|
||||
return color.getVariantByTintIndex(tintIndex);
|
||||
}
|
||||
}
|
||||
@@ -18,14 +18,13 @@
|
||||
|
||||
package appeng.core.api;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import alexiil.mc.lib.attributes.Attributes;
|
||||
import alexiil.mc.lib.attributes.Simulation;
|
||||
import alexiil.mc.lib.attributes.fluid.FluidAttributes;
|
||||
import alexiil.mc.lib.attributes.fluid.FluidExtractable;
|
||||
import alexiil.mc.lib.attributes.fluid.FluidVolumeUtil;
|
||||
import alexiil.mc.lib.attributes.fluid.amount.FluidAmount;
|
||||
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
|
||||
import appeng.fluids.util.FluidList;
|
||||
@@ -180,17 +179,17 @@ public class ApiStorage implements IStorageHelper {
|
||||
Preconditions.checkNotNull(input);
|
||||
|
||||
if (input instanceof FluidVolume) {
|
||||
return AEFluidStack.fromFluidStack((FluidVolume) input);
|
||||
return AEFluidStack.fromFluidVolume((FluidVolume) input, RoundingMode.DOWN);
|
||||
}
|
||||
if (input instanceof ItemStack) {
|
||||
final ItemStack is = (ItemStack) input;
|
||||
if (is.getItem() instanceof FluidDummyItem) {
|
||||
return AEFluidStack.fromFluidStack(((FluidDummyItem) is.getItem()).getFluidStack(is));
|
||||
return AEFluidStack.fromFluidVolume(((FluidDummyItem) is.getItem()).getFluidStack(is), RoundingMode.DOWN);
|
||||
} else {
|
||||
FluidExtractable fluidExtractable = FluidAttributes.EXTRACTABLE.get(is);
|
||||
FluidVolume fluidVolume = fluidExtractable.attemptAnyExtraction(FluidAmount.MAX_VALUE, Simulation.ACTION);
|
||||
if (!fluidVolume.isEmpty()) {
|
||||
return AEFluidStack.fromFluidStack(fluidVolume);
|
||||
return AEFluidStack.fromFluidVolume(fluidVolume, RoundingMode.DOWN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ import appeng.api.features.AEFeature;
|
||||
import appeng.block.misc.*;
|
||||
import appeng.block.networking.CableBusBlock;
|
||||
import appeng.block.networking.CableBusRendering;
|
||||
import appeng.block.storage.ChestBlock;
|
||||
import appeng.block.storage.ChestRendering;
|
||||
import appeng.block.storage.SkyChestBlock;
|
||||
import appeng.bootstrap.*;
|
||||
import appeng.bootstrap.components.IInitComponent;
|
||||
@@ -39,6 +41,7 @@ import appeng.tile.misc.LightDetectorBlockEntity;
|
||||
import appeng.tile.misc.SkyCompassBlockEntity;
|
||||
import appeng.tile.networking.CableBusBlockEntity;
|
||||
import appeng.tile.networking.CableBusTESR;
|
||||
import appeng.tile.storage.ChestBlockEntity;
|
||||
import appeng.tile.storage.SkyChestBlockEntity;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
@@ -334,9 +337,9 @@ public final class ApiBlocks implements IBlocks {
|
||||
// FIXME }
|
||||
// FIXME }).build())
|
||||
// FIXME .rendering(new DriveRendering()).build();
|
||||
// FIXME this.chest = registry.block("chest", ChestBlock::new).features(AEFeature.STORAGE_CELLS, AEFeature.ME_CHEST)
|
||||
// FIXME .tileEntity(registry.tileEntity("chest", ChestBlockEntity.class, ChestBlockEntity::new).build())
|
||||
// FIXME .rendering(new ChestRendering()).build();
|
||||
this.chest = registry.block("chest", ChestBlock::new).features(AEFeature.STORAGE_CELLS, AEFeature.ME_CHEST)
|
||||
.tileEntity(registry.tileEntity("chest", ChestBlockEntity.class, ChestBlockEntity::new).build())
|
||||
.rendering(new ChestRendering()).build();
|
||||
// FIXME this.iface = registry.block("interface", InterfaceBlock::new).features(AEFeature.INTERFACE)
|
||||
// FIXME .tileEntity(
|
||||
// FIXME registry.tileEntity("interface", InterfaceBlockEntity.class, InterfaceBlockEntity::new).build())
|
||||
|
||||
@@ -41,6 +41,8 @@ import appeng.fluids.items.FluidDummyItem;
|
||||
import appeng.util.Platform;
|
||||
import appeng.util.item.AEStack;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
|
||||
public final class AEFluidStack extends AEStack<IAEFluidStack> implements IAEFluidStack, Comparable<AEFluidStack> {
|
||||
private static final String NBT_STACKSIZE = "cnt";
|
||||
private static final String NBT_REQUESTABLE = "req";
|
||||
@@ -72,7 +74,7 @@ public final class AEFluidStack extends AEStack<IAEFluidStack> implements IAEFlu
|
||||
this.tagCompound = tag;
|
||||
}
|
||||
|
||||
public static AEFluidStack fromFluidStack(final FluidVolume input) {
|
||||
public static AEFluidStack fromFluidVolume(final FluidVolume input, RoundingMode roundingMode) {
|
||||
if (input.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
@@ -87,8 +89,7 @@ public final class AEFluidStack extends AEStack<IAEFluidStack> implements IAEFlu
|
||||
tag = null;
|
||||
}
|
||||
|
||||
// FIXME FABRIC NOPE NO FRACTIONS YOU FREAKS THIS IS NOT FROG FRACTIONS
|
||||
long amount = (long)(input.amount().asInexactDouble() * 1000.0);
|
||||
long amount = input.amount().asLong(1000, roundingMode);
|
||||
|
||||
return new AEFluidStack(fluid, amount, tag);
|
||||
}
|
||||
@@ -218,6 +219,11 @@ public final class AEFluidStack extends AEStack<IAEFluidStack> implements IAEFlu
|
||||
return this.fluid.readVolume(tagCompound).withAmount(amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidAmount getAmount() {
|
||||
return FluidAmount.of(getStackSize(), 1000);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidKey getFluid() {
|
||||
return this.fluid;
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.tile.grid;
|
||||
|
||||
import alexiil.mc.lib.attributes.AttributeList;
|
||||
import alexiil.mc.lib.attributes.AttributeProvider;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.security.IActionHost;
|
||||
import appeng.api.util.AECableType;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.api.util.DimensionalCoord;
|
||||
import appeng.me.helpers.AENetworkProxy;
|
||||
import appeng.me.helpers.IGridProxyable;
|
||||
import appeng.tile.powersink.AEBasePoweredBlockEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public abstract class AENetworkPowerBlockEntity extends AEBasePoweredBlockEntity implements IActionHost, IGridProxyable {
|
||||
|
||||
private final AENetworkProxy gridProxy = new AENetworkProxy(this, "proxy", this.getItemFromTile(this), true);
|
||||
|
||||
public AENetworkPowerBlockEntity(BlockEntityType<?> tileEntityTypeIn) {
|
||||
super(tileEntityTypeIn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromTag(BlockState state, final CompoundTag data) {
|
||||
super.fromTag(state, data);
|
||||
this.getProxy().readFromNBT(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag toTag(final CompoundTag data) {
|
||||
super.toTag(data);
|
||||
this.getProxy().writeToNBT(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AENetworkProxy getProxy() {
|
||||
return this.gridProxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DimensionalCoord getLocation() {
|
||||
return new DimensionalCoord(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gridChanged() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridNode getGridNode(final AEPartLocation dir) {
|
||||
return this.getProxy().getNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AECableType getCableConnectionType(final AEPartLocation dir) {
|
||||
return AECableType.SMART;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelRemoval() {
|
||||
super.cancelRemoval();
|
||||
this.getProxy().validate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markRemoved() {
|
||||
super.markRemoved();
|
||||
this.getProxy().remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChunkUnloaded() {
|
||||
super.onChunkUnloaded();
|
||||
this.getProxy().onChunkUnloaded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReady() {
|
||||
super.onReady();
|
||||
this.getProxy().onReady();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridNode getActionableNode() {
|
||||
return this.getProxy().getNode();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.tile.powersink;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import alexiil.mc.lib.attributes.AttributeList;
|
||||
import alexiil.mc.lib.attributes.AttributeProvider;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
import appeng.api.config.AccessRestriction;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.config.PowerMultiplier;
|
||||
import appeng.api.config.PowerUnits;
|
||||
import appeng.api.networking.energy.IAEPowerStorage;
|
||||
import appeng.api.networking.events.MENetworkPowerStorage.PowerEventType;
|
||||
import appeng.tile.AEBaseInvBlockEntity;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public abstract class AEBasePoweredBlockEntity extends AEBaseInvBlockEntity
|
||||
implements IAEPowerStorage, IExternalPowerSink, AttributeProvider {
|
||||
|
||||
// values that determine general function, are set by inheriting classes if
|
||||
// needed. These should generally remain static.
|
||||
private double internalMaxPower = 10000;
|
||||
private boolean internalPublicPowerStorage = false;
|
||||
private AccessRestriction internalPowerFlow = AccessRestriction.READ_WRITE;
|
||||
// the current power buffer.
|
||||
private double internalCurrentPower = 0;
|
||||
private static final Set<Direction> ALL_SIDES = ImmutableSet.copyOf(EnumSet.allOf(Direction.class));
|
||||
private Set<Direction> internalPowerSides = ALL_SIDES;
|
||||
|
||||
// IC2 private IC2PowerSink ic2Sink;
|
||||
|
||||
public AEBasePoweredBlockEntity(BlockEntityType<?> tileEntityTypeIn) {
|
||||
super(tileEntityTypeIn);
|
||||
// IC2 this.ic2Sink = Integrations.ic2().createPowerSink( this, this );
|
||||
// IC2 this.ic2Sink.setValidFaces( this.internalPowerSides );
|
||||
}
|
||||
|
||||
protected final Set<Direction> getPowerSides() {
|
||||
return this.internalPowerSides;
|
||||
}
|
||||
|
||||
protected void setPowerSides(final Set<Direction> sides) {
|
||||
this.internalPowerSides = ImmutableSet.copyOf(sides);
|
||||
// IC2 this.ic2Sink.setValidFaces( sides );
|
||||
// trigger re-calc!
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag toTag(final CompoundTag data) {
|
||||
super.toTag(data);
|
||||
data.putDouble("internalCurrentPower", this.getInternalCurrentPower());
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromTag(BlockState state, final CompoundTag data) {
|
||||
super.fromTag(state, data);
|
||||
this.setInternalCurrentPower(data.getDouble("internalCurrentPower"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final double getExternalPowerDemand(final PowerUnits externalUnit, final double maxPowerRequired) {
|
||||
return PowerUnits.AE.convertTo(externalUnit,
|
||||
Math.max(0.0, this.getFunnelPowerDemand(externalUnit.convertTo(PowerUnits.AE, maxPowerRequired))));
|
||||
}
|
||||
|
||||
protected double getFunnelPowerDemand(final double maxRequired) {
|
||||
return this.getInternalMaxPower() - this.getInternalCurrentPower();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final double injectExternalPower(final PowerUnits input, final double amt, Actionable mode) {
|
||||
return PowerUnits.AE.convertTo(input, this.funnelPowerIntoStorage(input.convertTo(PowerUnits.AE, amt), mode));
|
||||
}
|
||||
|
||||
protected double funnelPowerIntoStorage(final double power, final Actionable mode) {
|
||||
return this.injectAEPower(power, mode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final double injectAEPower(double amt, final Actionable mode) {
|
||||
if (amt < 0.000001) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
final double required = this.getAEMaxPower() - this.getAECurrentPower();
|
||||
final double insertable = Math.min(required, amt);
|
||||
|
||||
if (mode == Actionable.MODULATE) {
|
||||
if (this.getInternalCurrentPower() < 0.01 && insertable > 0.01) {
|
||||
this.PowerEvent(PowerEventType.PROVIDE_POWER);
|
||||
}
|
||||
|
||||
this.setInternalCurrentPower(this.getInternalCurrentPower() + insertable);
|
||||
}
|
||||
|
||||
return amt - insertable;
|
||||
}
|
||||
|
||||
protected void PowerEvent(final PowerEventType x) {
|
||||
// nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public final double getAEMaxPower() {
|
||||
return this.getInternalMaxPower();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final double getAECurrentPower() {
|
||||
return this.getInternalCurrentPower();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isAEPublicPowerStorage() {
|
||||
return this.isInternalPublicPowerStorage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AccessRestriction getPowerFlow() {
|
||||
return this.getInternalPowerFlow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final double extractAEPower(final double amt, final Actionable mode, final PowerMultiplier multiplier) {
|
||||
return multiplier.divide(this.extractAEPower(multiplier.multiply(amt), mode));
|
||||
}
|
||||
|
||||
protected double extractAEPower(double amt, final Actionable mode) {
|
||||
if (mode == Actionable.SIMULATE) {
|
||||
if (this.getInternalCurrentPower() > amt) {
|
||||
return amt;
|
||||
}
|
||||
return this.getInternalCurrentPower();
|
||||
}
|
||||
|
||||
final boolean wasFull = this.getInternalCurrentPower() >= this.getInternalMaxPower() - 0.001;
|
||||
if (wasFull && amt > 0.001) {
|
||||
this.PowerEvent(PowerEventType.REQUEST_POWER);
|
||||
}
|
||||
|
||||
if (this.getInternalCurrentPower() > amt) {
|
||||
this.setInternalCurrentPower(this.getInternalCurrentPower() - amt);
|
||||
return amt;
|
||||
}
|
||||
|
||||
amt = this.getInternalCurrentPower();
|
||||
this.setInternalCurrentPower(0);
|
||||
return amt;
|
||||
}
|
||||
|
||||
public double getInternalCurrentPower() {
|
||||
return this.internalCurrentPower;
|
||||
}
|
||||
|
||||
public void setInternalCurrentPower(final double internalCurrentPower) {
|
||||
this.internalCurrentPower = internalCurrentPower;
|
||||
}
|
||||
|
||||
public double getInternalMaxPower() {
|
||||
return this.internalMaxPower;
|
||||
}
|
||||
|
||||
public void setInternalMaxPower(final double internalMaxPower) {
|
||||
this.internalMaxPower = internalMaxPower;
|
||||
}
|
||||
|
||||
private boolean isInternalPublicPowerStorage() {
|
||||
return this.internalPublicPowerStorage;
|
||||
}
|
||||
|
||||
public void setInternalPublicPowerStorage(final boolean internalPublicPowerStorage) {
|
||||
this.internalPublicPowerStorage = internalPublicPowerStorage;
|
||||
}
|
||||
|
||||
private AccessRestriction getInternalPowerFlow() {
|
||||
return this.internalPowerFlow;
|
||||
}
|
||||
|
||||
public void setInternalPowerFlow(final AccessRestriction internalPowerFlow) {
|
||||
this.internalPowerFlow = internalPowerFlow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReady() {
|
||||
super.onReady();
|
||||
|
||||
// IC2 this.ic2Sink.onLoad();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChunkUnloaded() {
|
||||
super.onChunkUnloaded();
|
||||
|
||||
// IC2 this.ic2Sink.onChunkUnloaded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markRemoved() {
|
||||
super.markRemoved();
|
||||
|
||||
// IC2 this.ic2Sink.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAllAttributes(World world, BlockPos pos, BlockState state, AttributeList<?> to) {
|
||||
super.addAllAttributes(world, pos, state, to);
|
||||
|
||||
// FIXME FABRIC: Offer energy attributes
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.tile.powersink;
|
||||
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.config.PowerUnits;
|
||||
import appeng.api.networking.energy.IAEPowerStorage;
|
||||
|
||||
public interface IExternalPowerSink extends IAEPowerStorage {
|
||||
|
||||
/**
|
||||
* Inject power into the network
|
||||
*
|
||||
* @param externalUnit The {@link PowerUnits} used by the input
|
||||
* @param amount The amount offered to the sink.
|
||||
* @param mode Modulate or simulate the operation.
|
||||
* @return The unused amount, which could not be inserted into the sink.
|
||||
*/
|
||||
double injectExternalPower(PowerUnits externalUnit, double amount, Actionable mode);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param externalUnit The {@link PowerUnits} used by the input
|
||||
* @param maxPowerRequired Limit the demand to this upper bound.
|
||||
* @return The amount of power demanded by the sink.
|
||||
*/
|
||||
double getExternalPowerDemand(PowerUnits externalUnit, double maxPowerRequired);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,771 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.tile.storage;
|
||||
|
||||
import alexiil.mc.lib.attributes.AttributeList;
|
||||
import alexiil.mc.lib.attributes.Simulation;
|
||||
import alexiil.mc.lib.attributes.fluid.FluidInsertable;
|
||||
import alexiil.mc.lib.attributes.fluid.amount.FluidAmount;
|
||||
import alexiil.mc.lib.attributes.fluid.filter.ConstantFluidFilter;
|
||||
import alexiil.mc.lib.attributes.fluid.filter.FluidFilter;
|
||||
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
|
||||
import alexiil.mc.lib.attributes.item.FixedItemInv;
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.config.*;
|
||||
import appeng.api.implementations.tiles.IColorableTile;
|
||||
import appeng.api.implementations.tiles.IMEChest;
|
||||
import appeng.api.networking.GridFlags;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.energy.IEnergyGrid;
|
||||
import appeng.api.networking.events.*;
|
||||
import appeng.api.networking.events.MENetworkPowerStorage.PowerEventType;
|
||||
import appeng.api.networking.security.IActionHost;
|
||||
import appeng.api.networking.security.IActionSource;
|
||||
import appeng.api.networking.security.ISecurityGrid;
|
||||
import appeng.api.networking.storage.IBaseMonitor;
|
||||
import appeng.api.networking.storage.IStorageGrid;
|
||||
import appeng.api.storage.*;
|
||||
import appeng.api.storage.cells.*;
|
||||
import appeng.api.storage.channels.IFluidStorageChannel;
|
||||
import appeng.api.storage.channels.IItemStorageChannel;
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.api.storage.data.IAEItemStack;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.api.util.AEColor;
|
||||
import appeng.api.util.IConfigManager;
|
||||
import appeng.fluids.util.AEFluidStack;
|
||||
import appeng.helpers.IPriorityHost;
|
||||
import appeng.me.GridAccessException;
|
||||
import appeng.me.helpers.MEMonitorHandler;
|
||||
import appeng.me.helpers.MachineSource;
|
||||
import appeng.me.storage.MEInventoryHandler;
|
||||
import appeng.tile.grid.AENetworkPowerBlockEntity;
|
||||
import appeng.tile.inventory.AppEngInternalInventory;
|
||||
import appeng.util.ConfigManager;
|
||||
import appeng.util.IConfigManagerHost;
|
||||
import appeng.util.Platform;
|
||||
import appeng.util.helpers.ItemHandlerUtil;
|
||||
import appeng.util.inv.InvOperation;
|
||||
import appeng.util.inv.WrapperChainedItemHandler;
|
||||
import appeng.util.inv.filter.IAEItemFilter;
|
||||
import appeng.util.item.AEItemStack;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.screen.ScreenHandlerType;
|
||||
import net.minecraft.util.Tickable;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class ChestBlockEntity extends AENetworkPowerBlockEntity
|
||||
implements IMEChest, ITerminalHost, IPriorityHost, IConfigManagerHost, IColorableTile, Tickable {
|
||||
|
||||
private static final int BIT_POWER_MASK = Byte.MIN_VALUE;
|
||||
private static final int BIT_STATE_MASK = 0b111;
|
||||
|
||||
private static final int BIT_CELL_STATE_MASK = 0b111;
|
||||
private static final int BIT_CELL_STATE_BITS = 3;
|
||||
private final AppEngInternalInventory inputInventory = new AppEngInternalInventory(this, 1);
|
||||
private final AppEngInternalInventory cellInventory = new AppEngInternalInventory(this, 1);
|
||||
private final FixedItemInv internalInventory = new WrapperChainedItemHandler(this.inputInventory,
|
||||
this.cellInventory);
|
||||
|
||||
private final IActionSource mySrc = new MachineSource(this);
|
||||
private final IConfigManager config = new ConfigManager(this);
|
||||
private long lastStateChange = 0;
|
||||
private int priority = 0;
|
||||
private int state = 0;
|
||||
private boolean wasActive = false;
|
||||
private AEColor paintedColor = AEColor.TRANSPARENT;
|
||||
private boolean isCached = false;
|
||||
private ChestMonitorHandler cellHandler;
|
||||
private Accessor accessor;
|
||||
private FluidInsertable fluidInsertable;
|
||||
|
||||
public ChestBlockEntity(BlockEntityType<?> tileEntityTypeIn) {
|
||||
super(tileEntityTypeIn);
|
||||
this.setInternalMaxPower(PowerMultiplier.CONFIG.multiply(40));
|
||||
this.getProxy().setFlags(GridFlags.REQUIRE_CHANNEL);
|
||||
this.config.registerSetting(Settings.SORT_BY, SortOrder.NAME);
|
||||
this.config.registerSetting(Settings.VIEW_MODE, ViewItems.ALL);
|
||||
this.config.registerSetting(Settings.SORT_DIRECTION, SortDir.ASCENDING);
|
||||
|
||||
this.setInternalPublicPowerStorage(true);
|
||||
this.setInternalPowerFlow(AccessRestriction.WRITE);
|
||||
|
||||
this.inputInventory.setFilter(new InputInventoryFilter());
|
||||
this.cellInventory.setFilter(new CellInventoryFilter());
|
||||
}
|
||||
|
||||
public ItemStack getCell() {
|
||||
return this.cellInventory.getInvStack(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void PowerEvent(final PowerEventType x) {
|
||||
if (x == PowerEventType.REQUEST_POWER) {
|
||||
try {
|
||||
this.getProxy().getGrid().postEvent(new MENetworkPowerStorage(this, PowerEventType.REQUEST_POWER));
|
||||
} catch (final GridAccessException e) {
|
||||
// :(
|
||||
}
|
||||
} else {
|
||||
this.recalculateDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
private void recalculateDisplay() {
|
||||
final int oldState = this.state;
|
||||
|
||||
for (int x = 0; x < this.getCellCount(); x++) {
|
||||
this.state |= (this.getCellStatus(x).ordinal() << (BIT_CELL_STATE_BITS * x));
|
||||
}
|
||||
|
||||
if (this.isPowered()) {
|
||||
this.state |= BIT_POWER_MASK;
|
||||
} else {
|
||||
this.state &= ~BIT_POWER_MASK;
|
||||
}
|
||||
|
||||
final boolean currentActive = this.getProxy().isActive();
|
||||
if (this.wasActive != currentActive) {
|
||||
this.wasActive = currentActive;
|
||||
try {
|
||||
this.getProxy().getGrid().postEvent(new MENetworkCellArrayUpdate());
|
||||
} catch (final GridAccessException e) {
|
||||
// :P
|
||||
}
|
||||
}
|
||||
|
||||
if (oldState != this.state) {
|
||||
this.markForUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCellCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void updateHandler() {
|
||||
if (!this.isCached) {
|
||||
this.cellHandler = null;
|
||||
this.accessor = null;
|
||||
this.fluidInsertable = null;
|
||||
|
||||
final ItemStack is = this.getCell();
|
||||
if (!is.isEmpty()) {
|
||||
this.isCached = true;
|
||||
ICellHandler cellHandler = AEApi.instance().registries().cell().getHandler(is);
|
||||
if (cellHandler != null) {
|
||||
double power = 1.0;
|
||||
|
||||
for (IStorageChannel channel : AEApi.instance().storage().storageChannels()) {
|
||||
final ICellInventoryHandler<IAEItemStack> newCell = cellHandler.getCellInventory(is, this,
|
||||
channel);
|
||||
if (newCell != null) {
|
||||
power += cellHandler.cellIdleDrain(is, newCell);
|
||||
this.cellHandler = this.wrap(newCell);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.getProxy().setIdlePowerUsage(power);
|
||||
this.accessor = new Accessor();
|
||||
|
||||
if (this.cellHandler != null && this.cellHandler.getChannel() == AEApi.instance().storage()
|
||||
.getStorageChannel(IFluidStorageChannel.class)) {
|
||||
this.fluidInsertable = new FluidHandler();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends IAEStack<T>> ChestMonitorHandler<T> wrap(final IMEInventoryHandler<T> h) {
|
||||
if (h == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final MEInventoryHandler<T> ih = new MEInventoryHandler<T>(h, h.getChannel());
|
||||
ih.setPriority(this.priority);
|
||||
|
||||
final ChestMonitorHandler<T> g = new ChestMonitorHandler<T>(ih);
|
||||
g.addListener(new ChestNetNotifier<T>(h.getChannel()), g);
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CellState getCellStatus(final int slot) {
|
||||
if (isClient()) {
|
||||
return CellState.values()[(this.state >> (slot * BIT_CELL_STATE_BITS)) & BIT_CELL_STATE_MASK];
|
||||
}
|
||||
|
||||
this.updateHandler();
|
||||
|
||||
final ItemStack cell = this.getCell();
|
||||
final ICellHandler ch = AEApi.instance().registries().cell().getHandler(cell);
|
||||
|
||||
if (this.cellHandler != null && ch != null) {
|
||||
return ch.getStatusForCell(cell, this.cellHandler.getInternalHandler());
|
||||
}
|
||||
|
||||
return CellState.ABSENT;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Item getCellItem(int slot) {
|
||||
if (slot != 0) {
|
||||
return null;
|
||||
}
|
||||
ItemStack cell = getCell();
|
||||
return cell.isEmpty() ? null : cell.getItem();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPowered() {
|
||||
if (isClient()) {
|
||||
return (this.state & BIT_POWER_MASK) == BIT_POWER_MASK;
|
||||
}
|
||||
|
||||
boolean gridPowered = this.getAECurrentPower() > 64;
|
||||
|
||||
if (!gridPowered) {
|
||||
try {
|
||||
gridPowered = this.getProxy().getEnergy().isNetworkPowered();
|
||||
} catch (final GridAccessException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
return super.getAECurrentPower() > 1 || gridPowered;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCellBlinking(final int slot) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double extractAEPower(final double amt, final Actionable mode) {
|
||||
double stash = 0.0;
|
||||
|
||||
try {
|
||||
final IEnergyGrid eg = this.getProxy().getEnergy();
|
||||
stash = eg.extractAEPower(amt, mode, PowerMultiplier.ONE);
|
||||
if (stash >= amt) {
|
||||
return stash;
|
||||
}
|
||||
} catch (final GridAccessException e) {
|
||||
// no grid :(
|
||||
}
|
||||
|
||||
// local battery!
|
||||
return super.extractAEPower(amt - stash, mode) + stash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (this.world.isClient) {
|
||||
return;
|
||||
}
|
||||
|
||||
final double idleUsage = this.getProxy().getIdlePowerUsage();
|
||||
|
||||
try {
|
||||
if (!this.getProxy().getEnergy().isNetworkPowered()) {
|
||||
final double powerUsed = this.extractAEPower(idleUsage, Actionable.MODULATE, PowerMultiplier.CONFIG); // drain
|
||||
if (powerUsed + 0.1 >= idleUsage != (this.state & BIT_POWER_MASK) > 0) {
|
||||
this.recalculateDisplay();
|
||||
}
|
||||
}
|
||||
} catch (final GridAccessException e) {
|
||||
final double powerUsed = this.extractAEPower(this.getProxy().getIdlePowerUsage(), Actionable.MODULATE,
|
||||
PowerMultiplier.CONFIG); // drain
|
||||
if (powerUsed + 0.1 >= idleUsage != (this.state & BIT_POWER_MASK) > 0) {
|
||||
this.recalculateDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
if (!ItemHandlerUtil.isEmpty(this.inputInventory)) {
|
||||
this.tryToStoreContents();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeToStream(final PacketByteBuf data) throws IOException {
|
||||
super.writeToStream(data);
|
||||
|
||||
this.state = 0;
|
||||
|
||||
for (int x = 0; x < this.getCellCount(); x++) {
|
||||
this.state |= (this.getCellStatus(x).ordinal() << (3 * x));
|
||||
}
|
||||
|
||||
if (this.isPowered()) {
|
||||
this.state |= BIT_POWER_MASK;
|
||||
} else {
|
||||
this.state &= ~BIT_POWER_MASK;
|
||||
}
|
||||
|
||||
data.writeByte(this.state);
|
||||
data.writeByte(this.paintedColor.ordinal());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean readFromStream(final PacketByteBuf data) throws IOException {
|
||||
final boolean c = super.readFromStream(data);
|
||||
|
||||
final int oldState = this.state;
|
||||
|
||||
this.state = data.readByte();
|
||||
final AEColor oldPaintedColor = this.paintedColor;
|
||||
this.paintedColor = AEColor.values()[data.readByte()];
|
||||
|
||||
this.lastStateChange = this.world.getTime();
|
||||
|
||||
return oldPaintedColor != this.paintedColor || (this.state & 0xDB6DB6DB) != (oldState & 0xDB6DB6DB) || c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromTag(BlockState state, final CompoundTag data) {
|
||||
super.fromTag(state, data);
|
||||
this.config.readFromNBT(data);
|
||||
this.priority = data.getInt("priority");
|
||||
if (data.contains("paintedColor")) {
|
||||
this.paintedColor = AEColor.values()[data.getByte("paintedColor")];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag toTag(final CompoundTag data) {
|
||||
super.toTag(data);
|
||||
this.config.writeToNBT(data);
|
||||
data.putInt("priority", this.priority);
|
||||
data.putByte("paintedColor", (byte) this.paintedColor.ordinal());
|
||||
return data;
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void powerRender(final MENetworkPowerStatusChange c) {
|
||||
this.recalculateDisplay();
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void channelRender(final MENetworkChannelsChanged c) {
|
||||
this.recalculateDisplay();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends IAEStack<T>> IMEMonitor<T> getInventory(IStorageChannel<T> channel) {
|
||||
this.updateHandler();
|
||||
|
||||
if (this.cellHandler != null && this.cellHandler.getChannel() == channel) {
|
||||
return this.cellHandler;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FixedItemInv getInternalInventory() {
|
||||
return this.internalInventory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChangeInventory(final FixedItemInv inv, final int slot, final InvOperation mc,
|
||||
final ItemStack removed, final ItemStack added) {
|
||||
if (inv == this.cellInventory) {
|
||||
this.cellHandler = null;
|
||||
this.isCached = false; // recalculate the storage cell.
|
||||
|
||||
try {
|
||||
this.getProxy().getGrid().postEvent(new MENetworkCellArrayUpdate());
|
||||
final IStorageGrid gs = this.getProxy().getStorage();
|
||||
Platform.postChanges(gs, removed, added, this.mySrc);
|
||||
} catch (final GridAccessException ignored) {
|
||||
|
||||
}
|
||||
|
||||
// update the neighbors
|
||||
if (this.world != null) {
|
||||
Platform.notifyBlocksOfNeighbors(this.world, this.pos);
|
||||
this.markForUpdate();
|
||||
}
|
||||
}
|
||||
if (inv == this.inputInventory && mc == InvOperation.INSERT) {
|
||||
this.tryToStoreContents();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FixedItemInv getItemHandlerForSide(@Nonnull Direction side) {
|
||||
if (side == this.getForward()) {
|
||||
return this.cellInventory;
|
||||
} else {
|
||||
return this.inputInventory;
|
||||
}
|
||||
}
|
||||
|
||||
private void tryToStoreContents() {
|
||||
if (!ItemHandlerUtil.isEmpty(this.inputInventory)) {
|
||||
this.updateHandler();
|
||||
|
||||
if (this.cellHandler != null && this.cellHandler.getChannel() == AEApi.instance().storage()
|
||||
.getStorageChannel(IItemStorageChannel.class)) {
|
||||
final IAEItemStack returns = Platform.poweredInsert(this, this.cellHandler,
|
||||
AEItemStack.fromItemStack(this.inputInventory.getInvStack(0)), this.mySrc);
|
||||
|
||||
if (returns == null) {
|
||||
this.inputInventory.forceSetInvStack(0, ItemStack.EMPTY);
|
||||
} else {
|
||||
this.inputInventory.forceSetInvStack(0, returns.createItemStack());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IMEInventoryHandler> getCellArray(final IStorageChannel channel) {
|
||||
if (this.getProxy().isActive()) {
|
||||
this.updateHandler();
|
||||
|
||||
if (this.cellHandler != null && this.cellHandler.getChannel() == channel) {
|
||||
return Collections.singletonList(this.cellHandler);
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority() {
|
||||
return this.priority;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPriority(final int newValue) {
|
||||
this.priority = newValue;
|
||||
this.cellHandler = null;
|
||||
this.isCached = false; // recalculate the storage cell.
|
||||
|
||||
try {
|
||||
this.getProxy().getGrid().postEvent(new MENetworkCellArrayUpdate());
|
||||
} catch (final GridAccessException e) {
|
||||
// :P
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void blinkCell(final int slot) {
|
||||
final long now = this.world.getTime();
|
||||
if (now - this.lastStateChange > 8) {
|
||||
this.state = 0;
|
||||
}
|
||||
this.lastStateChange = now;
|
||||
|
||||
this.state |= 1 << (slot * BIT_CELL_STATE_BITS + 2);
|
||||
|
||||
this.recalculateDisplay();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IConfigManager getConfigManager() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSetting(final IConfigManager manager, final Settings settingName, final Enum<?> newValue) {
|
||||
|
||||
}
|
||||
|
||||
public boolean openGui(final PlayerEntity p) {
|
||||
this.updateHandler();
|
||||
if (this.cellHandler != null) {
|
||||
final ICellHandler ch = AEApi.instance().registries().cell().getHandler(this.getCell());
|
||||
|
||||
if (ch != null) {
|
||||
final ICellGuiHandler chg = AEApi.instance().registries().cell()
|
||||
.getGuiHandler(this.cellHandler.getChannel(), this.getCell());
|
||||
if (chg != null) {
|
||||
chg.openChestGui(p, this, ch, this.cellHandler, this.getCell(), this.cellHandler.getChannel());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AEColor getColor() {
|
||||
return this.paintedColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean recolourBlock(final Direction side, final AEColor newPaintedColor, final PlayerEntity who) {
|
||||
if (this.paintedColor == newPaintedColor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.paintedColor = newPaintedColor;
|
||||
this.saveChanges();
|
||||
this.markForUpdate();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveChanges(final ICellInventory<?> cellInventory) {
|
||||
if (cellInventory != null) {
|
||||
cellInventory.persist();
|
||||
}
|
||||
this.world.markDirty(this.pos, this);
|
||||
}
|
||||
|
||||
private class ChestNetNotifier<T extends IAEStack<T>> implements IMEMonitorHandlerReceiver<T> {
|
||||
|
||||
private final IStorageChannel<T> chan;
|
||||
|
||||
public ChestNetNotifier(final IStorageChannel<T> chan) {
|
||||
this.chan = chan;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(final Object verificationToken) {
|
||||
ChestBlockEntity.this.updateHandler();
|
||||
if (ChestBlockEntity.this.cellHandler != null
|
||||
&& this.chan == ChestBlockEntity.this.cellHandler.getChannel()) {
|
||||
return verificationToken == ChestBlockEntity.this.cellHandler;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postChange(final IBaseMonitor<T> monitor, final Iterable<T> change, final IActionSource source) {
|
||||
if (source == ChestBlockEntity.this.mySrc
|
||||
|| source.machine().map(machine -> machine == ChestBlockEntity.this).orElse(false)) {
|
||||
try {
|
||||
if (ChestBlockEntity.this.getProxy().isActive()) {
|
||||
ChestBlockEntity.this.getProxy().getStorage().postAlterationOfStoredItems(this.chan, change,
|
||||
ChestBlockEntity.this.mySrc);
|
||||
}
|
||||
} catch (final GridAccessException e) {
|
||||
// :(
|
||||
}
|
||||
}
|
||||
|
||||
ChestBlockEntity.this.blinkCell(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onListUpdate() {
|
||||
// not used here
|
||||
}
|
||||
}
|
||||
|
||||
private class ChestMonitorHandler<T extends IAEStack<T>> extends MEMonitorHandler<T> {
|
||||
|
||||
public ChestMonitorHandler(final IMEInventoryHandler<T> t) {
|
||||
super(t);
|
||||
}
|
||||
|
||||
private ICellInventoryHandler<T> getInternalHandler() {
|
||||
final IMEInventoryHandler<T> h = this.getHandler();
|
||||
if (h instanceof MEInventoryHandler) {
|
||||
return (ICellInventoryHandler<T>) ((MEInventoryHandler<T>) h).getInternal();
|
||||
}
|
||||
return (ICellInventoryHandler<T>) this.getHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T injectItems(final T input, final Actionable mode, final IActionSource src) {
|
||||
if (src.player().map(player -> !this.securityCheck(player, SecurityPermissions.INJECT)).orElse(false)) {
|
||||
return input;
|
||||
}
|
||||
return super.injectItems(input, mode, src);
|
||||
}
|
||||
|
||||
private boolean securityCheck(final PlayerEntity player, final SecurityPermissions requiredPermission) {
|
||||
if (ChestBlockEntity.this.getTile() instanceof IActionHost && requiredPermission != null) {
|
||||
|
||||
final IGridNode gn = ((IActionHost) ChestBlockEntity.this.getTile()).getActionableNode();
|
||||
if (gn != null) {
|
||||
final IGrid g = gn.getGrid();
|
||||
if (g != null) {
|
||||
final boolean requirePower = false;
|
||||
if (requirePower) {
|
||||
final IEnergyGrid eg = g.getCache(IEnergyGrid.class);
|
||||
if (!eg.isNetworkPowered()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final ISecurityGrid sg = g.getCache(ISecurityGrid.class);
|
||||
if (sg.hasPermission(player, requiredPermission)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T extractItems(final T request, final Actionable mode, final IActionSource src) {
|
||||
if (src.player().map(player -> !this.securityCheck(player, SecurityPermissions.EXTRACT)).orElse(false)) {
|
||||
return null;
|
||||
}
|
||||
return super.extractItems(request, mode, src);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAllAttributes(World world, BlockPos pos, BlockState state, AttributeList<?> to) {
|
||||
super.addAllAttributes(world, pos, state, to);
|
||||
|
||||
if (fluidInsertable != null && to.getSearchDirection() != getForward()) {
|
||||
to.offer(fluidInsertable);
|
||||
}
|
||||
|
||||
// FIXME FABRIC: STORAGE_MONITORABLE_ACCESSOR
|
||||
}
|
||||
|
||||
private class Accessor implements IStorageMonitorableAccessor {
|
||||
@Nullable
|
||||
@Override
|
||||
public IStorageMonitorable getInventory(IActionSource src) {
|
||||
if (Platform.canAccess(ChestBlockEntity.this.getProxy(), src)) {
|
||||
return ChestBlockEntity.this;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private class FluidHandler implements FluidInsertable {
|
||||
|
||||
private boolean canAcceptLiquids() {
|
||||
return ChestBlockEntity.this.cellHandler != null && ChestBlockEntity.this.cellHandler.getChannel() == AEApi
|
||||
.instance().storage().getStorageChannel(IFluidStorageChannel.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidVolume attemptInsertion(FluidVolume fluidVolume, Simulation simulation) {
|
||||
ChestBlockEntity.this.updateHandler();
|
||||
if (!canAcceptLiquids()) {
|
||||
return fluidVolume;
|
||||
}
|
||||
|
||||
// Rounds down to representable amount of fluid
|
||||
AEFluidStack toInsert = AEFluidStack.fromFluidVolume(fluidVolume, RoundingMode.DOWN);
|
||||
|
||||
if (toInsert == null) {
|
||||
return fluidVolume;
|
||||
}
|
||||
|
||||
IAEFluidStack remaining = Platform.poweredInsert(ChestBlockEntity.this,
|
||||
ChestBlockEntity.this.cellHandler,
|
||||
toInsert,
|
||||
ChestBlockEntity.this.mySrc,
|
||||
simulation == Simulation.ACTION ? Actionable.MODULATE : Actionable.SIMULATE);
|
||||
|
||||
FluidAmount filledAmt = remaining != null ? remaining.getAmount() : toInsert.getAmount();
|
||||
FluidAmount remainingAmt = fluidVolume.amount().roundedSub(filledAmt, RoundingMode.DOWN);
|
||||
return fluidVolume.withAmount(remainingAmt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidFilter getInsertionFilter() {
|
||||
ChestBlockEntity.this.updateHandler();
|
||||
return canAcceptLiquids() ? ConstantFluidFilter.ANYTHING : ConstantFluidFilter.NOTHING;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class InputInventoryFilter implements IAEItemFilter {
|
||||
@Override
|
||||
public boolean allowExtract(FixedItemInv inv, int slot, int amount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowInsert(FixedItemInv inv, int slot, ItemStack stack) {
|
||||
if (ChestBlockEntity.this.isPowered()) {
|
||||
ChestBlockEntity.this.updateHandler();
|
||||
return ChestBlockEntity.this.cellHandler != null && ChestBlockEntity.this.cellHandler
|
||||
.getChannel() == AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static class CellInventoryFilter implements IAEItemFilter {
|
||||
|
||||
@Override
|
||||
public boolean allowExtract(FixedItemInv inv, int slot, int amount) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowInsert(FixedItemInv inv, int slot, ItemStack stack) {
|
||||
return AEApi.instance().registries().cell().getHandler(stack) != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemStackRepresentation() {
|
||||
return AEApi.instance().definitions().blocks().chest().maybeStack(1).orElse(ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScreenHandlerType<?> getContainerType() {
|
||||
this.updateHandler();
|
||||
if (this.cellHandler != null) {
|
||||
if (this.cellHandler.getChannel() == AEApi.instance().storage()
|
||||
.getStorageChannel(IItemStorageChannel.class)) {
|
||||
throw new IllegalStateException();
|
||||
// FIXME FABRIC return MEMonitorableContainer.TYPE;
|
||||
}
|
||||
if (this.cellHandler.getChannel() == AEApi.instance().storage()
|
||||
.getStorageChannel(IFluidStorageChannel.class)) {
|
||||
throw new IllegalStateException();
|
||||
// FIXME FABRIC return FluidTerminalContainer.TYPE;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -51,6 +51,7 @@ import appeng.fluids.util.AEFluidStack;
|
||||
import appeng.hooks.TickHandler;
|
||||
import appeng.me.GridAccessException;
|
||||
import appeng.me.GridNode;
|
||||
import appeng.me.helpers.AENetworkProxy;
|
||||
import appeng.util.helpers.ItemComparisonHelper;
|
||||
import appeng.util.helpers.P2PHelper;
|
||||
import appeng.util.item.AEItemStack;
|
||||
@@ -781,6 +782,9 @@ public class Platform {
|
||||
return poweredInsert(energy, cell, input, src, Actionable.MODULATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The remainder (non-inserted) _or_ null if everything was inserted.
|
||||
*/
|
||||
public static <T extends IAEStack<T>> T poweredInsert(final IEnergySource energy, final IMEInventory<T> cell,
|
||||
final T input, final IActionSource src, final Actionable mode) {
|
||||
Preconditions.checkNotNull(energy);
|
||||
@@ -983,26 +987,26 @@ public class Platform {
|
||||
yaw, pitch);
|
||||
}
|
||||
|
||||
// FIXME public static boolean canAccess(final AENetworkProxy gridProxy, final IActionSource src) {
|
||||
// FIXME try {
|
||||
// FIXME if (src.player().isPresent()) {
|
||||
// FIXME return gridProxy.getSecurity().hasPermission(src.player().get(), SecurityPermissions.BUILD);
|
||||
// FIXME } else if (src.machine().isPresent()) {
|
||||
// FIXME final IActionHost te = src.machine().get();
|
||||
// FIXME final IGridNode n = te.getActionableNode();
|
||||
// FIXME if (n == null) {
|
||||
// FIXME return false;
|
||||
// FIXME }
|
||||
// FIXME
|
||||
// FIXME final int playerID = n.getPlayerID();
|
||||
// FIXME return gridProxy.getSecurity().hasPermission(playerID, SecurityPermissions.BUILD);
|
||||
// FIXME } else {
|
||||
// FIXME return false;
|
||||
// FIXME }
|
||||
// FIXME } catch (final GridAccessException gae) {
|
||||
// FIXME return false;
|
||||
// FIXME }
|
||||
// FIXME }
|
||||
public static boolean canAccess(final AENetworkProxy gridProxy, final IActionSource src) {
|
||||
try {
|
||||
if (src.player().isPresent()) {
|
||||
return gridProxy.getSecurity().hasPermission(src.player().get(), SecurityPermissions.BUILD);
|
||||
} else if (src.machine().isPresent()) {
|
||||
final IActionHost te = src.machine().get();
|
||||
final IGridNode n = te.getActionableNode();
|
||||
if (n == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int playerID = n.getPlayerID();
|
||||
return gridProxy.getSecurity().hasPermission(playerID, SecurityPermissions.BUILD);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (final GridAccessException gae) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static ItemStack extractItemsByRecipe(final IEnergySource energySrc, final IActionSource mySrc,
|
||||
final IMEMonitor<IAEItemStack> src, final World w, final Recipe<CraftingInventory> r,
|
||||
|
||||
Reference in New Issue
Block a user