Lots more moved

This commit is contained in:
Sebastian Hartte
2020-07-04 21:03:30 +02:00
parent 5982f094ec
commit 1478e4c378
444 changed files with 4693 additions and 5235 deletions
@@ -455,4 +455,5 @@ public abstract class AEBasePart implements IPart, IGridProxyable, IActionHost,
public ItemStack getItemStack() {
return this.is;
}
}
@@ -0,0 +1,234 @@
package appeng.parts.automation;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockView;
import appeng.api.config.Actionable;
import appeng.api.config.Settings;
import appeng.api.networking.security.IActionSource;
import appeng.api.parts.IPart;
import appeng.api.parts.IPartCollisionHelper;
import appeng.api.parts.IPartHost;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.cells.ICellContainer;
import appeng.api.storage.cells.ICellInventory;
import appeng.api.storage.data.IAEStack;
import appeng.api.storage.data.IItemList;
import appeng.api.util.AECableType;
import appeng.api.util.AEPartLocation;
import appeng.api.util.IConfigManager;
import appeng.helpers.IPriorityHost;
public abstract class AbstractFormationPlanePart<T extends IAEStack<T>> extends UpgradeablePart
implements ICellContainer, IPriorityHost, IMEInventory<T> {
private boolean wasActive = false;
private int priority = 0;
protected boolean blocked = false;
public AbstractFormationPlanePart(ItemStack is) {
super(is);
}
protected abstract void updateHandler();
@Override
protected int getUpgradeSlots() {
return 5;
}
@Override
public void upgradesChanged() {
this.updateHandler();
}
@Override
public void updateSetting(final IConfigManager manager, final Settings settingName, final Enum<?> newValue) {
this.updateHandler();
this.getHost().markForSave();
}
public void stateChanged() {
final boolean currentActive = this.getProxy().isActive();
if (this.wasActive != currentActive) {
this.wasActive = currentActive;
this.updateHandler();
this.getHost().markForUpdate();
}
}
@Override
public void getBoxes(final IPartCollisionHelper bch) {
int minX = 1;
int minY = 1;
int maxX = 15;
int maxY = 15;
final IPartHost host = this.getHost();
if (host != null) {
final BlockEntity te = host.getTile();
final BlockPos pos = te.getPos();
final Direction e = bch.getWorldX();
final Direction u = bch.getWorldY();
if (this.isTransitionPlane(te.getWorld().getBlockEntity(pos.offset(e.getOpposite())), this.getSide())) {
minX = 0;
}
if (this.isTransitionPlane(te.getWorld().getBlockEntity(pos.offset(e)), this.getSide())) {
maxX = 16;
}
if (this.isTransitionPlane(te.getWorld().getBlockEntity(pos.offset(u.getOpposite())), this.getSide())) {
minY = 0;
}
if (this.isTransitionPlane(te.getWorld().getBlockEntity(pos.offset(u)), this.getSide())) {
maxY = 16;
}
}
bch.addBox(5, 5, 14, 11, 11, 15);
bch.addBox(minX, minY, 15, maxX, maxY, 16);
}
public PlaneConnections getConnections() {
final Direction facingRight, facingUp;
AEPartLocation location = this.getSide();
switch (location) {
case UP:
facingRight = Direction.EAST;
facingUp = Direction.NORTH;
break;
case DOWN:
facingRight = Direction.WEST;
facingUp = Direction.NORTH;
break;
case NORTH:
facingRight = Direction.WEST;
facingUp = Direction.UP;
break;
case SOUTH:
facingRight = Direction.EAST;
facingUp = Direction.UP;
break;
case WEST:
facingRight = Direction.SOUTH;
facingUp = Direction.UP;
break;
case EAST:
facingRight = Direction.NORTH;
facingUp = Direction.UP;
break;
default:
case INTERNAL:
return PlaneConnections.of(false, false, false, false);
}
boolean left = false, right = false, down = false, up = false;
final IPartHost host = this.getHost();
if (host != null) {
final BlockEntity te = host.getTile();
final BlockPos pos = te.getPos();
if (this.isTransitionPlane(te.getWorld().getBlockEntity(pos.offset(facingRight.getOpposite())),
this.getSide())) {
left = true;
}
if (this.isTransitionPlane(te.getWorld().getBlockEntity(pos.offset(facingRight)), this.getSide())) {
right = true;
}
if (this.isTransitionPlane(te.getWorld().getBlockEntity(pos.offset(facingUp.getOpposite())),
this.getSide())) {
down = true;
}
if (this.isTransitionPlane(te.getWorld().getBlockEntity(pos.offset(facingUp)), this.getSide())) {
up = true;
}
}
return PlaneConnections.of(up, right, down, left);
}
@Override
public void onneighborUpdate(BlockView w, BlockPos pos, BlockPos neighbor) {
if (pos.offset(this.getSide().getFacing()).equals(neighbor)) {
final BlockEntity te = this.getHost().getTile();
final AEPartLocation side = this.getSide();
final BlockPos tePos = te.getPos().offset(side.getFacing());
this.blocked = !w.getBlockState(tePos).getMaterial().isReplaceable();
}
}
@Override
public float getCableConnectionLength(AECableType cable) {
return 1;
}
protected boolean isTransitionPlane(final BlockEntity blockTileEntity, final AEPartLocation side) {
if (blockTileEntity instanceof IPartHost) {
final IPart p = ((IPartHost) blockTileEntity).getPart(side);
return p != null && this.getClass() == p.getClass();
}
return false;
}
@Override
public T extractItems(final T request, final Actionable mode, final IActionSource src) {
return null;
}
@Override
public IItemList<T> getAvailableItems(final IItemList<T> out) {
return out;
}
@Override
public void readFromNBT(final CompoundTag data) {
super.readFromNBT(data);
this.priority = data.getInt("priority");
}
@Override
public void writeToNBT(final CompoundTag data) {
super.writeToNBT(data);
data.putInt("priority", this.getPriority());
}
@Override
public int getPriority() {
return this.priority;
}
@Override
public void setPriority(final int newValue) {
this.priority = newValue;
this.getHost().markForSave();
this.updateHandler();
}
@Override
public void blinkCell(final int slot) {
// :P
}
@Override
public void saveChanges(final ICellInventory<?> cell) {
// nope!
}
}
@@ -0,0 +1,633 @@
/*
* 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.parts.automation;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import appeng.util.FakePlayer;
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Material;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.Entity;
import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.item.ToolMaterials;
import net.minecraft.tag.Tag;
import net.minecraft.tag.BlockTags;
import net.minecraft.tag.ItemTags;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import net.minecraft.server.world.ServerWorld;
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.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack;
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.core.sync.packets.ItemTransitionEffectPacket;
import appeng.hooks.TickHandler;
import appeng.items.parts.PartModels;
import appeng.me.GridAccessException;
import appeng.me.helpers.MachineSource;
import appeng.parts.BasicStatePart;
import appeng.util.IWorldCallable;
import appeng.util.Platform;
import appeng.util.item.AEItemStack;
public class AnnihilationPlanePart extends BasicStatePart implements IGridTickable, IWorldCallable<TickRateModulation> {
public static final Identifier TAG_BLACKLIST = new Identifier(AppEng.MOD_ID,
"blacklisted/annihilation_plane");
private static final PlaneModels MODELS = new PlaneModels("part/annihilation_plane", "part/annihilation_plane_on");
@PartModels
public static List<IPartModel> getModels() {
return MODELS.getModels();
}
private final IActionSource mySrc = new MachineSource(this);
private boolean isAccepting = true;
private boolean breaking = false;
public AnnihilationPlanePart(final ItemStack is) {
super(is);
}
@Override
public TickRateModulation call(final World world) throws Exception {
this.breaking = false;
return this.breakBlock(true);
}
@Override
public void getBoxes(final IPartCollisionHelper bch) {
int minX = 1;
int minY = 1;
int maxX = 15;
int maxY = 15;
final IPartHost host = this.getHost();
if (host != null) {
final BlockEntity te = host.getTile();
final BlockPos pos = te.getPos();
final Direction e = bch.getWorldX();
final Direction u = bch.getWorldY();
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(e.getOpposite())), this.getSide())) {
minX = 0;
}
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(e)), this.getSide())) {
maxX = 16;
}
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(u.getOpposite())), this.getSide())) {
minY = 0;
}
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(e)), this.getSide())) {
maxY = 16;
}
}
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);
}
/**
* @return An object describing which adjacent planes this plane connects to
* visually.
*/
public PlaneConnections getConnections() {
final Direction facingRight, facingUp;
AEPartLocation location = this.getSide();
switch (location) {
case UP:
facingRight = Direction.EAST;
facingUp = Direction.NORTH;
break;
case DOWN:
facingRight = Direction.WEST;
facingUp = Direction.NORTH;
break;
case NORTH:
facingRight = Direction.WEST;
facingUp = Direction.UP;
break;
case SOUTH:
facingRight = Direction.EAST;
facingUp = Direction.UP;
break;
case WEST:
facingRight = Direction.SOUTH;
facingUp = Direction.UP;
break;
case EAST:
facingRight = Direction.NORTH;
facingUp = Direction.UP;
break;
default:
case INTERNAL:
return PlaneConnections.of(false, false, false, false);
}
boolean left = false, right = false, down = false, up = false;
final IPartHost host = this.getHost();
if (host != null) {
final BlockEntity te = host.getTile();
final BlockPos pos = te.getPos();
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(facingRight.getOpposite())),
this.getSide())) {
left = true;
}
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(facingRight)), this.getSide())) {
right = true;
}
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(facingUp.getOpposite())),
this.getSide())) {
down = true;
}
if (this.isAnnihilationPlane(te.getWorld().getBlockEntity(pos.offset(facingUp)), this.getSide())) {
up = true;
}
}
return PlaneConnections.of(up, right, down, left);
}
@Override
public void onneighborUpdate(BlockView w, BlockPos pos, BlockPos neighbor) {
if (pos.offset(this.getSide().getFacing()).equals(neighbor)) {
this.refresh();
}
}
@Override
public void onEntityCollision(final Entity entity) {
if (this.isAccepting && entity instanceof ItemEntity && entity.isAlive() && Platform.isServer()
&& this.getProxy().isActive()) {
ItemEntity itemEntity = (ItemEntity) entity;
if (isItemBlacklisted(itemEntity.getStack().getItem())) {
return;
}
boolean capture = false;
final BlockPos pos = this.getTile().getPos();
// This is the middle point of the entities BB, which is better suited for
// comparisons that don't rely on it
// "touching" the plane
double posYMiddle = (entity.getBoundingBox().minY + entity.getBoundingBox().maxY) / 2.0D;
switch (this.getSide()) {
case DOWN:
case UP:
if (entity.getX() > pos.getX() && entity.getX() < pos.getX() + 1) {
if (entity.getZ() > pos.getZ() && entity.getZ() < pos.getZ() + 1) {
if ((entity.getY() > pos.getY() + 0.9 && this.getSide() == AEPartLocation.UP)
|| (entity.getY() < pos.getY() + 0.1 && this.getSide() == AEPartLocation.DOWN)) {
capture = true;
}
}
}
break;
case SOUTH:
case NORTH:
if (entity.getX() > pos.getX() && entity.getX() < pos.getX() + 1) {
if (posYMiddle > pos.getY() && posYMiddle < pos.getY() + 1) {
if ((entity.getZ() > pos.getZ() + 0.9 && this.getSide() == AEPartLocation.SOUTH)
|| (entity.getZ() < pos.getZ() + 0.1
&& this.getSide() == AEPartLocation.NORTH)) {
capture = true;
}
}
}
break;
case EAST:
case WEST:
if (entity.getZ() > pos.getZ() && entity.getZ() < pos.getZ() + 1) {
if (posYMiddle > pos.getY() && posYMiddle < pos.getY() + 1) {
if ((entity.getX() > pos.getX() + 0.9 && this.getSide() == AEPartLocation.EAST)
|| (entity.getX() < pos.getX() + 0.1 && this.getSide() == AEPartLocation.WEST)) {
capture = true;
}
}
}
break;
default:
// umm?
break;
}
if (capture) {
final boolean changed = this.storeEntityItem(itemEntity);
if (changed) {
AppEng.instance().sendToAllNearExcept(null, pos.getX(), pos.getY(), pos.getZ(), 64,
this.getTile().getWorld(), new ItemTransitionEffectPacket(entity.getX(),
entity.getY(), entity.getZ(), this.getSide().getOpposite()));
}
}
}
}
@Override
public float getCableConnectionLength(AECableType cable) {
return 1;
}
/**
* Stores an {@link ItemEntity} inside the network and either marks it as dead
* or sets it to the leftover stackSize.
*
* @param entityItem {@link ItemEntity} to store
*/
private boolean storeEntityItem(final ItemEntity entityItem) {
if (entityItem.isAlive()) {
final IAEItemStack overflow = this.storeItemStack(entityItem.getStack());
return this.handleOverflow(entityItem, overflow);
}
return false;
}
/**
* Stores an {@link ItemStack} inside the network.
*
* @param item {@link ItemStack} to store
*
* @return the leftover items, which could not be stored inside the network
*/
private IAEItemStack storeItemStack(final ItemStack item) {
final IAEItemStack itemToStore = AEItemStack.fromItemStack(item);
try {
final IStorageGrid storage = this.getProxy().getStorage();
final IEnergyGrid energy = this.getProxy().getEnergy();
final IAEItemStack overflow = Platform.poweredInsert(energy,
storage.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class)),
itemToStore, this.mySrc);
this.isAccepting = overflow == null;
return overflow;
} catch (final GridAccessException e1) {
// :P
}
return null;
}
/**
* Handles a possible overflow or none at all. It will update the entity to
* match the leftover stack size as well as mark it as dead without any leftover
* amount.
*
* @param entityItem the entity to update or destroy
* @param overflow the leftover {@link IAEItemStack}
*
* @return true, if the entity was changed otherwise false.
*/
private boolean handleOverflow(final ItemEntity entityItem, final IAEItemStack overflow) {
if (overflow == null || overflow.getStackSize() == 0) {
entityItem.remove();
return true;
}
final int oldStackSize = entityItem.getStack().getCount();
final int newStackSize = (int) overflow.getStackSize();
final boolean changed = oldStackSize != newStackSize;
entityItem.getStack().setCount(newStackSize);
return changed;
}
protected boolean isAnnihilationPlane(final BlockEntity blockTileEntity, final AEPartLocation side) {
if (blockTileEntity instanceof IPartHost) {
final IPart p = ((IPartHost) blockTileEntity).getPart(side);
return p != null && p.getClass() == this.getClass();
}
return false;
}
@Override
@MENetworkEventSubscribe
public void chanRender(final MENetworkChannelsChanged c) {
this.refresh();
this.getHost().markForUpdate();
}
@Override
@MENetworkEventSubscribe
public void powerRender(final MENetworkPowerStatusChange c) {
this.refresh();
this.getHost().markForUpdate();
}
private TickRateModulation breakBlock(final boolean modulate) {
if (this.isAccepting && this.getProxy().isActive()) {
try {
final BlockEntity te = this.getTile();
final ServerWorld w = (ServerWorld) te.getWorld();
final BlockPos pos = te.getPos().offset(this.getSide().getFacing());
final IEnergyGrid energy = this.getProxy().getEnergy();
final BlockState blockState = w.getBlockState(pos);
if (this.canHandleBlock(w, pos, blockState)) {
// Query the loot-table and get a potential outcome of the loot-table evaluation
final List<ItemStack> items = this.obtainBlockDrops(w, pos);
final float requiredPower = this.calculateEnergyUsage(w, pos, items);
final boolean hasPower = energy.extractAEPower(requiredPower, Actionable.SIMULATE,
PowerMultiplier.CONFIG) > requiredPower - 0.1;
final boolean canStore = this.canStoreItemStacks(items);
if (hasPower && canStore) {
if (modulate) {
performBreakBlock(w, pos, blockState, energy, requiredPower, items);
} else {
this.breaking = true;
TickHandler.INSTANCE.addCallable(this.getTile().getWorld(), this);
}
return TickRateModulation.URGENT;
}
}
} catch (final GridAccessException e1) {
// :P
}
}
// nothing to do here :)
return TickRateModulation.IDLE;
}
private void performBreakBlock(ServerWorld w, BlockPos pos, BlockState blockState, IEnergyGrid energy,
float requiredPower, List<ItemStack> items) {
if (!this.breakBlockAndStoreExtraItems(w, pos)) {
// We failed to actually replace the block with air or it already was the case
return;
}
for (ItemStack item : items) {
IAEItemStack overflow = storeItemStack(item);
// If inserting the item fully was not possible, drop it as an item entity
// instead
// if the storage clears up, we'll pick it up that way
if (overflow != null) {
Platform.spawnDrops(w, pos, Collections.singletonList(overflow.createItemStack()));
}
}
energy.extractAEPower(requiredPower, Actionable.MODULATE, PowerMultiplier.CONFIG);
AppEng.instance().sendToAllNearExcept(null, pos.getX(), pos.getY(), pos.getZ(), 64, w,
new BlockTransitionEffectPacket(pos, blockState, this.getSide().getOpposite(),
BlockTransitionEffectPacket.SoundMode.NONE));
}
@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) {
if (this.breaking) {
return TickRateModulation.URGENT;
}
this.isAccepting = true;
return this.breakBlock(false);
}
/**
* Checks if this plane can handle the block at the specific coordinates.
*/
private boolean canHandleBlock(final ServerWorld w, final BlockPos pos, final BlockState state) {
if (state.isAir()) {
return false;
}
if (isBlockBlacklisted(state.getBlock())) {
return false;
}
final Material material = state.getMaterial();
final float hardness = state.getHardness(w, pos);
final boolean ignoreMaterials = material == Material.AIR || material == Material.LAVA
|| material == Material.WATER || material.isLiquid();
return !ignoreMaterials && hardness >= 0f && w.isChunkLoaded(pos)
&& w.canPlayerModifyAt(FakePlayer.getOrCreate(w), pos);
}
protected List<ItemStack> obtainBlockDrops(final ServerWorld w, final BlockPos pos) {
Entity fakePlayer = FakePlayer.getOrCreate(w);
final BlockState state = w.getBlockState(pos);
ItemStack harvestTool = createHarvestTool(state);
if (harvestTool == null) {
if (!state.isToolRequired()) {
harvestTool = ItemStack.EMPTY;
} else {
// In case the block does NOT allow us to harvest it without a tool, or the
// proper tool, do not return anything.
return Collections.emptyList();
}
}
BlockEntity te = w.getBlockEntity(pos);
return Block.getDroppedStacks(state, w, pos, te, fakePlayer, harvestTool);
}
/**
* Checks if this plane can handle the block at the specific coordinates.
*/
protected float calculateEnergyUsage(final ServerWorld w, final BlockPos pos, final List<ItemStack> items) {
final BlockState state = w.getBlockState(pos);
final float hardness = state.getHardness(w, pos);
float requiredEnergy = 1 + hardness;
for (final ItemStack is : items) {
requiredEnergy += is.getCount();
}
return requiredEnergy;
}
/**
* Checks if the network can store the possible drops.
*
* It also sets isAccepting to false, if the item can not be stored.
*
* @param itemStacks an array of {@link ItemStack} to test
*
* @return true, if the network can store at least a single item of all drops or
* no drops are reported
*/
private boolean canStoreItemStacks(final List<ItemStack> itemStacks) {
boolean canStore = itemStacks.isEmpty();
try {
final IStorageGrid storage = this.getProxy().getStorage();
for (final ItemStack itemStack : itemStacks) {
final IAEItemStack itemToTest = AEItemStack.fromItemStack(itemStack);
final IAEItemStack overflow = storage
.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class))
.injectItems(itemToTest, Actionable.SIMULATE, this.mySrc);
if (overflow == null || itemToTest.getStackSize() > overflow.getStackSize()) {
canStore = true;
}
}
} catch (final GridAccessException e) {
// :P
}
this.isAccepting = canStore;
return canStore;
}
private boolean breakBlockAndStoreExtraItems(final ServerWorld w, final BlockPos pos) {
// Kill the block, but signal no drops
if (!w.breakBlock(pos, false)) {
// The block was no longer there
return false;
}
// This handles items that do not spawn via loot-tables but rather normal block
// breaking
// i.e. our cable-buses do this (bad practice, really)
final Box box = new Box(pos).expand(0.2);
for (final Object ei : w.getEntities(ItemEntity.class, box, null)) {
if (ei instanceof ItemEntity) {
final ItemEntity entityItem = (ItemEntity) ei;
this.storeEntityItem(entityItem);
}
}
return true;
}
private void refresh() {
this.isAccepting = true;
try {
this.getProxy().getTick().alertDevice(this.getProxy().getNode());
} catch (final GridAccessException e) {
// :P
}
}
@Override
public IPartModel getStaticModels() {
return MODELS.getModel(this.isPowered(), this.isActive());
}
@Nullable
@Override
public Object getModelData() {
return getConnections();
}
private static final Item[] SUPPORTED_HARVEST_TOOLS = {
Items.DIAMOND_AXE,
Items.DIAMOND_PICKAXE,
Items.DIAMOND_SHOVEL,
};
/**
* Creates the fake (and temporary) tool that will be used to calculate the loot
* tables of a block this plane wants to break.
*
* @param state The state of the block about to be broken.
*/
protected ItemStack createHarvestTool(BlockState state) {
// Try to use the right tool...
for (Item toolItem : SUPPORTED_HARVEST_TOOLS) {
if (toolItem.isEffectiveOn(state)) {
return new ItemStack(toolItem);
}
}
return null;
}
public static boolean isBlockBlacklisted(Block b) {
Tag<Block> tag = BlockTags.getContainer().getOrCreate(TAG_BLACKLIST);
return b.isIn(tag);
}
public static boolean isItemBlacklisted(Item i) {
Tag<Item> tag = ItemTags.getContainer().getOrCreate(TAG_BLACKLIST);
return i.isIn(tag);
}
}
@@ -0,0 +1,46 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.parts.automation;
import net.minecraft.item.ItemStack;
import appeng.api.config.Upgrades;
import appeng.api.definitions.IItemDefinition;
import appeng.util.inv.IAEAppEngInventory;
public final class DefinitionUpgradeInventory extends UpgradeInventory {
private final IItemDefinition definition;
public DefinitionUpgradeInventory(final IItemDefinition definition, final IAEAppEngInventory parent, final int s) {
super(parent, s);
this.definition = definition;
}
@Override
public int getMaxInstalled(final Upgrades upgrades) {
for (final Upgrades.Supported supported : upgrades.getSupported()) {
if (supported.isSupported(definition.item())) {
return supported.getMaxCount();
}
}
return 0;
}
}
@@ -0,0 +1,321 @@
/*
* 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.parts.automation;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Vec3d;
import appeng.api.AEApi;
import appeng.api.config.Actionable;
import appeng.api.config.FuzzyMode;
import appeng.api.config.PowerMultiplier;
import appeng.api.config.RedstoneMode;
import appeng.api.config.SchedulingMode;
import appeng.api.config.Settings;
import appeng.api.config.Upgrades;
import appeng.api.config.YesNo;
import appeng.api.networking.IGridNode;
import appeng.api.networking.crafting.ICraftingGrid;
import appeng.api.networking.crafting.ICraftingLink;
import appeng.api.networking.crafting.ICraftingRequester;
import appeng.api.networking.energy.IEnergyGrid;
import appeng.api.networking.security.IActionSource;
import appeng.api.networking.ticking.TickRateModulation;
import appeng.api.networking.ticking.TickingRequest;
import appeng.api.parts.IPartCollisionHelper;
import appeng.api.parts.IPartModel;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.util.AECableType;
import appeng.container.ContainerLocator;
import appeng.container.ContainerOpener;
import appeng.container.implementations.UpgradeableContainer;
import appeng.core.AELog;
import appeng.core.AppEng;
import appeng.core.settings.TickRates;
import appeng.helpers.MultiCraftingTracker;
import appeng.items.parts.PartModels;
import appeng.me.GridAccessException;
import appeng.me.helpers.MachineSource;
import appeng.parts.PartModel;
import appeng.util.InventoryAdaptor;
import appeng.util.Platform;
import appeng.util.item.AEItemStack;
public class ExportBusPart extends SharedItemBusPart implements ICraftingRequester {
public static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "part/export_bus_base");
@PartModels
public static final IPartModel MODELS_OFF = new PartModel(MODEL_BASE,
new Identifier(AppEng.MOD_ID, "part/export_bus_off"));
@PartModels
public static final IPartModel MODELS_ON = new PartModel(MODEL_BASE,
new Identifier(AppEng.MOD_ID, "part/export_bus_on"));
@PartModels
public static final IPartModel MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE,
new Identifier(AppEng.MOD_ID, "part/export_bus_has_channel"));
private final MultiCraftingTracker craftingTracker = new MultiCraftingTracker(this, 9);
private final IActionSource mySrc;
private long itemToSend = 1;
private boolean didSomething = false;
private int nextSlot = 0;
public ExportBusPart(final ItemStack is) {
super(is);
this.getConfigManager().registerSetting(Settings.REDSTONE_CONTROLLED, RedstoneMode.IGNORE);
this.getConfigManager().registerSetting(Settings.FUZZY_MODE, FuzzyMode.IGNORE_ALL);
this.getConfigManager().registerSetting(Settings.CRAFT_ONLY, YesNo.NO);
this.getConfigManager().registerSetting(Settings.SCHEDULING_MODE, SchedulingMode.DEFAULT);
this.mySrc = new MachineSource(this);
}
@Override
public void readFromNBT(final CompoundTag extra) {
super.readFromNBT(extra);
this.craftingTracker.readFromNBT(extra);
this.nextSlot = extra.getInt("nextSlot");
}
@Override
public void writeToNBT(final CompoundTag extra) {
super.writeToNBT(extra);
this.craftingTracker.writeToNBT(extra);
extra.putInt("nextSlot", this.nextSlot);
}
@Override
protected TickRateModulation doBusWork() {
if (!this.getProxy().isActive() || !this.canDoBusWork()) {
return TickRateModulation.IDLE;
}
this.itemToSend = this.calculateItemsToSend();
this.didSomething = false;
try {
final InventoryAdaptor destination = this.getHandler();
final IMEMonitor<IAEItemStack> inv = this.getProxy().getStorage()
.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class));
final IEnergyGrid energy = this.getProxy().getEnergy();
final ICraftingGrid cg = this.getProxy().getCrafting();
final FuzzyMode fzMode = (FuzzyMode) this.getConfigManager().getSetting(Settings.FUZZY_MODE);
final SchedulingMode schedulingMode = (SchedulingMode) this.getConfigManager()
.getSetting(Settings.SCHEDULING_MODE);
if (destination != null) {
int x = 0;
for (x = 0; x < this.availableSlots() && this.itemToSend > 0; x++) {
final int slotToExport = this.getStartingSlot(schedulingMode, x);
final IAEItemStack ais = this.getConfig().getAEStackInSlot(slotToExport);
if (ais == null || this.itemToSend <= 0 || this.craftOnly()) {
if (this.isCraftingEnabled()) {
this.didSomething = this.craftingTracker.handleCrafting(slotToExport, this.itemToSend, ais,
destination, this.getTile().getWorld(), this.getProxy().getGrid(), cg, this.mySrc)
|| this.didSomething;
}
continue;
}
final long before = this.itemToSend;
if (this.getInstalledUpgrades(Upgrades.FUZZY) > 0) {
for (final IAEItemStack o : ImmutableList.copyOf(inv.getStorageList().findFuzzy(ais, fzMode))) {
this.pushItemIntoTarget(destination, energy, inv, o);
if (this.itemToSend <= 0) {
break;
}
}
} else {
this.pushItemIntoTarget(destination, energy, inv, ais);
}
if (this.itemToSend == before && this.isCraftingEnabled()) {
this.didSomething = this.craftingTracker.handleCrafting(slotToExport, this.itemToSend, ais,
destination, this.getTile().getWorld(), this.getProxy().getGrid(), cg, this.mySrc)
|| this.didSomething;
}
}
this.updateSchedulingMode(schedulingMode, x);
} else {
return TickRateModulation.SLEEP;
}
} catch (final GridAccessException e) {
// :P
}
return this.didSomething ? TickRateModulation.FASTER : TickRateModulation.SLOWER;
}
@Override
public void getBoxes(final IPartCollisionHelper bch) {
bch.addBox(4, 4, 12, 12, 12, 14);
bch.addBox(5, 5, 14, 11, 11, 15);
bch.addBox(6, 6, 15, 10, 10, 16);
bch.addBox(6, 6, 11, 10, 10, 12);
}
@Override
public float getCableConnectionLength(AECableType cable) {
return 5;
}
@Override
public boolean onPartActivate(final PlayerEntity player, final Hand hand, final Vec3d pos) {
if (Platform.isServer()) {
ContainerOpener.openContainer(UpgradeableContainer.TYPE, player, ContainerLocator.forPart(this));
}
return true;
}
@Override
public TickingRequest getTickingRequest(final IGridNode node) {
return new TickingRequest(TickRates.ExportBus.getMin(), TickRates.ExportBus.getMax(), this.isSleeping(), false);
}
@Override
public RedstoneMode getRSMode() {
return (RedstoneMode) this.getConfigManager().getSetting(Settings.REDSTONE_CONTROLLED);
}
@Override
public TickRateModulation tickingRequest(final IGridNode node, final int ticksSinceLastCall) {
return this.doBusWork();
}
@Override
public ImmutableSet<ICraftingLink> getRequestedJobs() {
return this.craftingTracker.getRequestedJobs();
}
@Override
public IAEItemStack injectCraftedItems(final ICraftingLink link, final IAEItemStack items, final Actionable mode) {
final InventoryAdaptor d = this.getHandler();
try {
if (d != null && this.getProxy().isActive()) {
final IEnergyGrid energy = this.getProxy().getEnergy();
final double power = items.getStackSize();
if (energy.extractAEPower(power, mode, PowerMultiplier.CONFIG) > power - 0.01) {
if (mode == Actionable.MODULATE) {
return AEItemStack.fromItemStack(d.addItems(items.createItemStack()));
}
return AEItemStack.fromItemStack(d.simulateAdd(items.createItemStack()));
}
}
} catch (final GridAccessException e) {
AELog.debug(e);
}
return items;
}
@Override
public void jobStateChange(final ICraftingLink link) {
this.craftingTracker.jobStateChange(link);
}
@Override
protected boolean isSleeping() {
return this.getHandler() == null || super.isSleeping();
}
private boolean craftOnly() {
return this.getConfigManager().getSetting(Settings.CRAFT_ONLY) == YesNo.YES;
}
private boolean isCraftingEnabled() {
return this.getInstalledUpgrades(Upgrades.CRAFTING) > 0;
}
private void pushItemIntoTarget(final InventoryAdaptor d, final IEnergyGrid energy,
final IMEInventory<IAEItemStack> inv, IAEItemStack ais) {
final ItemStack is = ais.createItemStack();
is.setCount((int) this.itemToSend);
final ItemStack o = d.simulateAdd(is);
final long canFit = o.isEmpty() ? this.itemToSend : this.itemToSend - o.getCount();
if (canFit > 0) {
ais = ais.copy();
ais.setStackSize(canFit);
final IAEItemStack itemsToAdd = Platform.poweredExtraction(energy, inv, ais, this.mySrc);
if (itemsToAdd != null) {
this.itemToSend -= itemsToAdd.getStackSize();
final ItemStack failed = d.addItems(itemsToAdd.createItemStack());
if (!failed.isEmpty()) {
ais.setStackSize(failed.getCount());
inv.injectItems(ais, Actionable.MODULATE, this.mySrc);
} else {
this.didSomething = true;
}
}
}
}
private int getStartingSlot(final SchedulingMode schedulingMode, final int x) {
if (schedulingMode == SchedulingMode.RANDOM) {
return Platform.getRandom().nextInt(this.availableSlots());
}
if (schedulingMode == SchedulingMode.ROUNDROBIN) {
return (this.nextSlot + x) % this.availableSlots();
}
return x;
}
private void updateSchedulingMode(final SchedulingMode schedulingMode, final int x) {
if (schedulingMode == SchedulingMode.ROUNDROBIN) {
this.nextSlot = (this.nextSlot + x) % this.availableSlots();
}
}
@Override
public IPartModel getStaticModels() {
if (this.isActive() && this.isPowered()) {
return MODELS_HAS_CHANNEL;
} else if (this.isPowered()) {
return MODELS_ON;
} else {
return MODELS_OFF;
}
}
}
@@ -0,0 +1,357 @@
/*
* 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.parts.automation;
import alexiil.mc.lib.attributes.item.FixedItemInv;
import appeng.api.AEApi;
import appeng.api.config.*;
import appeng.api.networking.events.MENetworkCellArrayUpdate;
import appeng.api.networking.events.MENetworkChannelsChanged;
import appeng.api.networking.events.MENetworkEventSubscribe;
import appeng.api.networking.events.MENetworkPowerStatusChange;
import appeng.api.networking.security.IActionSource;
import appeng.api.parts.IPartItem;
import appeng.api.parts.IPartModel;
import appeng.api.storage.IMEInventoryHandler;
import appeng.api.storage.IStorageChannel;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList;
import appeng.api.util.AEPartLocation;
import appeng.container.ContainerLocator;
import appeng.container.ContainerOpener;
import appeng.container.implementations.FormationPlaneContainer;
import appeng.core.AEConfig;
import appeng.items.parts.PartModels;
import appeng.me.GridAccessException;
import appeng.me.storage.MEInventoryHandler;
import appeng.tile.inventory.AppEngInternalAEInventory;
import appeng.util.FakePlayer;
import appeng.util.Platform;
import appeng.util.inv.InvOperation;
import appeng.util.prioritylist.FuzzyPriorityList;
import appeng.util.prioritylist.PrecisePriorityList;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.Entity;
import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.*;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class FormationPlanePart extends AbstractFormationPlanePart<IAEItemStack> {
private static final PlaneModels MODELS = new PlaneModels("part/formation_plane", "part/formation_plane_on");
@PartModels
public static List<IPartModel> getModels() {
return MODELS.getModels();
}
private final MEInventoryHandler<IAEItemStack> myHandler = new MEInventoryHandler<>(this,
AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class));
private final AppEngInternalAEInventory Config = new AppEngInternalAEInventory(this, 63);
public FormationPlanePart(final ItemStack is) {
super(is);
this.getConfigManager().registerSetting(Settings.FUZZY_MODE, FuzzyMode.IGNORE_ALL);
this.getConfigManager().registerSetting(Settings.PLACE_BLOCK, YesNo.YES);
this.updateHandler();
}
@Override
protected void updateHandler() {
this.myHandler.setBaseAccess(AccessRestriction.WRITE);
this.myHandler.setWhitelist(
this.getInstalledUpgrades(Upgrades.INVERTER) > 0 ? IncludeExclude.BLACKLIST : IncludeExclude.WHITELIST);
this.myHandler.setPriority(this.getPriority());
final IItemList<IAEItemStack> priorityList = AEApi.instance().storage()
.getStorageChannel(IItemStorageChannel.class).createList();
final int slotsToUse = 18 + this.getInstalledUpgrades(Upgrades.CAPACITY) * 9;
for (int x = 0; x < this.Config.getSlotCount() && x < slotsToUse; x++) {
final IAEItemStack is = this.Config.getAEStackInSlot(x);
if (is != null) {
priorityList.add(is);
}
}
if (this.getInstalledUpgrades(Upgrades.FUZZY) > 0) {
this.myHandler.setPartitionList(new FuzzyPriorityList<IAEItemStack>(priorityList,
(FuzzyMode) this.getConfigManager().getSetting(Settings.FUZZY_MODE)));
} else {
this.myHandler.setPartitionList(new PrecisePriorityList<IAEItemStack>(priorityList));
}
try {
this.getProxy().getGrid().postEvent(new MENetworkCellArrayUpdate());
} catch (final GridAccessException e) {
// :P
}
}
@Override
public void onChangeInventory(final FixedItemInv inv, final int slot, final InvOperation mc,
final ItemStack removedStack, final ItemStack newStack) {
super.onChangeInventory(inv, slot, mc, removedStack, newStack);
if (inv == this.Config) {
this.updateHandler();
}
}
@Override
public void readFromNBT(final CompoundTag data) {
super.readFromNBT(data);
this.Config.readFromNBT(data, "config");
this.updateHandler();
}
@Override
public void writeToNBT(final CompoundTag data) {
super.writeToNBT(data);
this.Config.writeToNBT(data, "config");
}
@Override
public FixedItemInv getInventoryByName(final String name) {
if (name.equals("config")) {
return this.Config;
}
return super.getInventoryByName(name);
}
@Override
@MENetworkEventSubscribe
public void powerRender(final MENetworkPowerStatusChange c) {
this.stateChanged();
}
@MENetworkEventSubscribe
public void updateChannels(final MENetworkChannelsChanged changedChannels) {
this.stateChanged();
}
@Override
public boolean onPartActivate(final PlayerEntity player, final Hand hand, final Vec3d pos) {
if (Platform.isServer()) {
ContainerOpener.openContainer(FormationPlaneContainer.TYPE, player, ContainerLocator.forPart(this));
}
return true;
}
@Override
public List<IMEInventoryHandler> getCellArray(final IStorageChannel channel) {
if (this.getProxy().isActive()
&& channel == AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class)) {
final List<IMEInventoryHandler> handler = new ArrayList<>(1);
handler.add(this.myHandler);
return handler;
}
return Collections.emptyList();
}
@Override
public IAEItemStack injectItems(final IAEItemStack input, final Actionable type, final IActionSource src) {
if (this.blocked || input == null || input.getStackSize() <= 0) {
return input;
}
final YesNo placeBlock = (YesNo) this.getConfigManager().getSetting(Settings.PLACE_BLOCK);
final ItemStack is = input.createItemStack();
final Item i = is.getItem();
long maxStorage = Math.min(input.getStackSize(), is.getMaxCount());
boolean worked = false;
final BlockEntity te = this.getHost().getTile();
final World w = te.getWorld();
final AEPartLocation side = this.getSide();
final BlockPos placePos = te.getPos().offset(side.getFacing());
if (w.getBlockState(placePos).getMaterial().isReplaceable()) {
if (placeBlock == YesNo.YES && (i instanceof BlockItem
|| i instanceof FireworkChargeItem || i instanceof FireworkItem || i instanceof IPartItem)) {
final PlayerEntity player = FakePlayer.getOrCreate((ServerWorld) w);
Platform.configurePlayer(player, side, this.getTile());
Hand hand = player.getActiveHand();
player.setStackInHand(hand, is);
maxStorage = is.getCount();
worked = true;
if (type == Actionable.MODULATE) {
// The side the plane is attached to will be considered the look direction
// in terms of placing an item
Direction lookDirection = side.getFacing();
// FIXME No idea what any of this is _supposed_ to do, comment badly needed
if (i instanceof WallStandingBlockItem) {
boolean Worked = false;
// Up or Down, Attempt 1??
if (side.xOffset == 0 && side.zOffset == 0) {
Worked = i.useOnBlock(new AutomaticItemPlacementContext(w, placePos.offset(side.getFacing()),
lookDirection, is, side.getFacing())) == ActionResult.SUCCESS;
}
// Up or Down, Attempt 2??
if (!Worked && side.xOffset == 0 && side.zOffset == 0) {
Worked = i.useOnBlock(new AutomaticItemPlacementContext(w,
placePos.offset(side.getFacing().getOpposite()), lookDirection, is,
side.getFacing().getOpposite())) == ActionResult.SUCCESS;
}
// Horizontal, attempt 1??
if (!Worked && side.yOffset == 0) {
Worked = i.useOnBlock(new AutomaticItemPlacementContext(w, placePos.offset(Direction.DOWN),
lookDirection, is, Direction.DOWN)) == ActionResult.SUCCESS;
}
if (!Worked) {
i.useOnBlock(new AutomaticItemPlacementContext(w, placePos, lookDirection, is,
lookDirection.getOpposite()));
}
maxStorage -= is.getCount();
} else {
i.useOnBlock(new AutomaticItemPlacementContext(w, placePos, lookDirection, is,
lookDirection.getOpposite()));
maxStorage -= is.getCount();
}
} else {
maxStorage = 1;
}
// Safe keeping
player.setStackInHand(hand, ItemStack.EMPTY);
} else {
worked = true;
final int sum = this.countEntitesAround(w, placePos);
if (sum < AEConfig.instance().getFormationPlaneEntityLimit()) {
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.setVelocity(side.xOffset * 0.2, side.yOffset * 0.2, side.zOffset * 0.2);
// FIXME FABRIC No custom item entity support
// FIXME FABRIC if (is.getItem().hasCustomEntity(is)) {
// FIXME FABRIC result = is.getItem().createEntity(w, ei, is);
// FIXME FABRIC if (result != null) {
// FIXME FABRIC ei.remove();
// FIXME FABRIC } else {
// FIXME FABRIC result = ei;
// FIXME FABRIC }
// FIXME FABRIC }
if (!w.spawnEntity(result)) {
result.remove();
worked = false;
}
}
} else {
worked = false;
}
}
}
this.blocked = !w.getBlockState(placePos).getMaterial().isReplaceable();
if (worked) {
final IAEItemStack out = input.copy();
out.decStackSize(maxStorage);
if (out.getStackSize() == 0) {
return null;
}
return out;
}
return input;
}
@Override
public IStorageChannel<IAEItemStack> getChannel() {
return AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class);
}
@Override
public IPartModel getStaticModels() {
return MODELS.getModel(this.isPowered(), this.isActive());
}
@Override
public Object getModelData() {
return getConnections();
}
@Override
public ItemStack getItemStackRepresentation() {
return AEApi.instance().definitions().parts().formationPlane().maybeStack(1).orElse(ItemStack.EMPTY);
}
@Override
public ScreenHandlerType<?> getContainerType() {
return FormationPlaneContainer.TYPE;
}
private int countEntitesAround(World world, BlockPos pos) {
final Box t = new Box(pos).expand(8);
final List<Entity> list = world.getEntities(Entity.class, t, null);
return list.size();
}
private class ForcedItemUseContext extends ItemUsageContext {
protected ForcedItemUseContext(World worldIn, @Nullable PlayerEntity player, Hand handIn, ItemStack heldItem,
BlockHitResult rayTraceResultIn) {
super(worldIn, player, handIn, heldItem, rayTraceResultIn);
}
}
}
@@ -0,0 +1,97 @@
/*
* 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.parts.automation;
import java.util.List;
import javax.annotation.Nonnull;
import com.google.common.collect.ImmutableMap;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.enchantment.Enchantments;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.server.world.ServerWorld;
import appeng.api.parts.IPart;
import appeng.api.parts.IPartHost;
import appeng.api.parts.IPartModel;
import appeng.api.util.AEPartLocation;
import appeng.items.parts.PartModels;
public class IdentityAnnihilationPlanePart extends AnnihilationPlanePart {
private static final PlaneModels MODELS = new PlaneModels("part/identity_annihilation_plane",
"part/identity_annihilation_plane_on");
@PartModels
public static List<IPartModel> getModels() {
return MODELS.getModels();
}
private static final float SILK_TOUCH_FACTOR = 16;
public IdentityAnnihilationPlanePart(final ItemStack is) {
super(is);
}
@Override
protected boolean isAnnihilationPlane(final BlockEntity blockTileEntity, final AEPartLocation side) {
if (blockTileEntity instanceof IPartHost) {
final IPart p = ((IPartHost) blockTileEntity).getPart(side);
return p != null && p.getClass() == this.getClass();
}
return false;
}
@Override
protected float calculateEnergyUsage(final ServerWorld w, final BlockPos pos, final List<ItemStack> items) {
final float requiredEnergy = super.calculateEnergyUsage(w, pos, items);
return requiredEnergy * SILK_TOUCH_FACTOR;
}
@Override
protected ItemStack createHarvestTool(BlockState state) {
ItemStack harvestTool = super.createHarvestTool(state);
// For silk touch purposes, enchant the fake tool
if (harvestTool != null) {
EnchantmentHelper.set(ImmutableMap.of(Enchantments.SILK_TOUCH, 1), harvestTool);
}
return harvestTool;
}
@Override
public IPartModel getStaticModels() {
return MODELS.getModel(this.isPowered(), this.isActive());
}
@Nonnull
@Override
public Object getModelData() {
return getConnections();
}
}
@@ -0,0 +1,276 @@
/*
* 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.parts.automation;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Vec3d;
import appeng.api.AEApi;
import appeng.api.config.Actionable;
import appeng.api.config.FuzzyMode;
import appeng.api.config.RedstoneMode;
import appeng.api.config.Settings;
import appeng.api.config.Upgrades;
import appeng.api.networking.IGridNode;
import appeng.api.networking.energy.IEnergyGrid;
import appeng.api.networking.energy.IEnergySource;
import appeng.api.networking.security.IActionSource;
import appeng.api.networking.ticking.TickRateModulation;
import appeng.api.networking.ticking.TickingRequest;
import appeng.api.parts.IPartCollisionHelper;
import appeng.api.parts.IPartModel;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.util.AECableType;
import appeng.container.ContainerLocator;
import appeng.container.ContainerOpener;
import appeng.container.implementations.UpgradeableContainer;
import appeng.core.AppEng;
import appeng.core.settings.TickRates;
import appeng.items.parts.PartModels;
import appeng.me.GridAccessException;
import appeng.me.helpers.MachineSource;
import appeng.parts.PartModel;
import appeng.util.InventoryAdaptor;
import appeng.util.Platform;
import appeng.util.inv.IInventoryDestination;
import appeng.util.item.AEItemStack;
public class ImportBusPart extends SharedItemBusPart implements IInventoryDestination {
public static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "part/import_bus_base");
@PartModels
public static final IPartModel MODELS_OFF = new PartModel(MODEL_BASE,
new Identifier(AppEng.MOD_ID, "part/import_bus_off"));
@PartModels
public static final IPartModel MODELS_ON = new PartModel(MODEL_BASE,
new Identifier(AppEng.MOD_ID, "part/import_bus_on"));
@PartModels
public static final IPartModel MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE,
new Identifier(AppEng.MOD_ID, "part/import_bus_has_channel"));
private final IActionSource source;
private int itemsToSend; // used in tickingRequest
private boolean worked; // used in tickingRequest
public ImportBusPart(final ItemStack is) {
super(is);
this.getConfigManager().registerSetting(Settings.REDSTONE_CONTROLLED, RedstoneMode.IGNORE);
this.getConfigManager().registerSetting(Settings.FUZZY_MODE, FuzzyMode.IGNORE_ALL);
this.source = new MachineSource(this);
}
@Override
public boolean canInsert(final ItemStack stack) {
if (stack.isEmpty() || stack.getItem() == Items.AIR) {
return false;
}
try {
final IMEMonitor<IAEItemStack> inv = this.getProxy().getStorage()
.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class));
final IAEItemStack out = inv.injectItems(
AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class).createStack(stack),
Actionable.SIMULATE, this.source);
if (out == null) {
return true;
}
return out.getStackSize() != stack.getCount();
} catch (GridAccessException ex) {
return false;
}
}
@Override
public void getBoxes(final IPartCollisionHelper bch) {
bch.addBox(6, 6, 11, 10, 10, 13);
bch.addBox(5, 5, 13, 11, 11, 14);
bch.addBox(4, 4, 14, 12, 12, 16);
}
@Override
public float getCableConnectionLength(AECableType cable) {
return 5;
}
@Override
public boolean onPartActivate(final PlayerEntity player, final Hand hand, final Vec3d pos) {
if (Platform.isServer()) {
ContainerOpener.openContainer(UpgradeableContainer.TYPE, player, ContainerLocator.forPart(this));
}
return true;
}
@Override
public TickingRequest getTickingRequest(final IGridNode node) {
return new TickingRequest(TickRates.ImportBus.getMin(), TickRates.ImportBus.getMax(), this.isSleeping(), false);
}
@Override
public TickRateModulation tickingRequest(final IGridNode node, final int ticksSinceLastCall) {
return this.doBusWork();
}
@Override
protected TickRateModulation doBusWork() {
if (!this.getProxy().isActive() || !this.canDoBusWork()) {
return TickRateModulation.IDLE;
}
this.worked = false;
final InventoryAdaptor myAdaptor = this.getHandler();
final FuzzyMode fzMode = (FuzzyMode) this.getConfigManager().getSetting(Settings.FUZZY_MODE);
if (myAdaptor != null) {
try {
this.itemsToSend = this.calculateItemsToSend();
final IMEMonitor<IAEItemStack> inv = this.getProxy().getStorage()
.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class));
final IEnergyGrid energy = this.getProxy().getEnergy();
boolean Configured = false;
for (int x = 0; x < this.availableSlots(); x++) {
final IAEItemStack ais = this.getConfig().getAEStackInSlot(x);
if (ais != null && this.itemsToSend > 0) {
Configured = true;
while (this.itemsToSend > 0) {
if (this.importStuff(myAdaptor, ais, inv, energy, fzMode)) {
break;
}
}
}
}
if (!Configured) {
while (this.itemsToSend > 0) {
if (this.importStuff(myAdaptor, null, inv, energy, fzMode)) {
break;
}
}
}
} catch (final GridAccessException e) {
// :3
}
} else {
return TickRateModulation.SLEEP;
}
return this.worked ? TickRateModulation.FASTER : TickRateModulation.SLOWER;
}
private boolean importStuff(final InventoryAdaptor myAdaptor, final IAEItemStack whatToImport,
final IMEMonitor<IAEItemStack> inv, final IEnergySource energy, final FuzzyMode fzMode) {
final int toSend = this.calculateMaximumAmountToImport(myAdaptor, whatToImport, inv, fzMode);
final ItemStack newItems;
if (this.getInstalledUpgrades(Upgrades.FUZZY) > 0) {
newItems = myAdaptor.removeSimilarItems(toSend,
whatToImport == null ? ItemStack.EMPTY : whatToImport.getDefinition(), fzMode, this);
} else {
newItems = myAdaptor.removeItems(toSend,
whatToImport == null ? ItemStack.EMPTY : whatToImport.getDefinition(), this);
}
if (!newItems.isEmpty()) {
final IAEItemStack aeStack = AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class)
.createStack(newItems);
final IAEItemStack failed = Platform.poweredInsert(energy, inv, aeStack, this.source);
if (failed != null) {
// try unpowered insert, better be a bit lenient then void items
final IAEItemStack spill = inv.injectItems(failed, Actionable.MODULATE, this.source);
if (spill != null) {
// last resort try to put it back .. lets hope it's a chest type of thing
myAdaptor.addItems(spill.createItemStack());
}
return true;
} else {
this.itemsToSend -= newItems.getCount();
this.worked = true;
}
} else {
return true;
}
return false;
}
private int calculateMaximumAmountToImport(final InventoryAdaptor myAdaptor, final IAEItemStack whatToImport,
final IMEMonitor<IAEItemStack> inv, final FuzzyMode fzMode) {
final int toSend = Math.min(this.itemsToSend, 64);
final ItemStack itemStackToImport;
if (whatToImport == null) {
itemStackToImport = ItemStack.EMPTY;
} else {
itemStackToImport = whatToImport.getDefinition();
}
final IAEItemStack itemAmountNotStorable;
final ItemStack simResult;
if (this.getInstalledUpgrades(Upgrades.FUZZY) > 0) {
simResult = myAdaptor.simulateSimilarRemove(toSend, itemStackToImport, fzMode, this);
itemAmountNotStorable = inv.injectItems(AEItemStack.fromItemStack(simResult), Actionable.SIMULATE,
this.source);
} else {
simResult = myAdaptor.simulateRemove(toSend, itemStackToImport, this);
itemAmountNotStorable = inv.injectItems(AEItemStack.fromItemStack(simResult), Actionable.SIMULATE,
this.source);
}
if (itemAmountNotStorable != null) {
return (int) Math.min(simResult.getCount() - itemAmountNotStorable.getStackSize(), toSend);
}
return toSend;
}
@Override
protected boolean isSleeping() {
return this.getHandler() == null || super.isSleeping();
}
@Override
public RedstoneMode getRSMode() {
return (RedstoneMode) this.getConfigManager().getSetting(Settings.REDSTONE_CONTROLLED);
}
@Override
public IPartModel getStaticModels() {
if (this.isActive() && this.isPowered()) {
return MODELS_HAS_CHANNEL;
} else if (this.isPowered()) {
return MODELS_ON;
} else {
return MODELS_OFF;
}
}
}
@@ -0,0 +1,496 @@
/*
* 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.parts.automation;
import java.util.Collection;
import java.util.Random;
import alexiil.mc.lib.attributes.item.FixedItemInv;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.CraftingInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.particle.DustParticleEffect;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import appeng.api.AEApi;
import appeng.api.config.FuzzyMode;
import appeng.api.config.LevelType;
import appeng.api.config.RedstoneMode;
import appeng.api.config.Settings;
import appeng.api.config.Upgrades;
import appeng.api.config.YesNo;
import appeng.api.networking.crafting.ICraftingGrid;
import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.api.networking.crafting.ICraftingProvider;
import appeng.api.networking.crafting.ICraftingProviderHelper;
import appeng.api.networking.crafting.ICraftingWatcher;
import appeng.api.networking.crafting.ICraftingWatcherHost;
import appeng.api.networking.energy.IEnergyGrid;
import appeng.api.networking.energy.IEnergyWatcher;
import appeng.api.networking.energy.IEnergyWatcherHost;
import appeng.api.networking.events.MENetworkChannelsChanged;
import appeng.api.networking.events.MENetworkCraftingPatternChange;
import appeng.api.networking.events.MENetworkEventSubscribe;
import appeng.api.networking.events.MENetworkPowerStatusChange;
import appeng.api.networking.security.IActionSource;
import appeng.api.networking.storage.IBaseMonitor;
import appeng.api.networking.storage.IStackWatcher;
import appeng.api.networking.storage.IStackWatcherHost;
import appeng.api.parts.IPartCollisionHelper;
import appeng.api.parts.IPartModel;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.IMEMonitorHandlerReceiver;
import appeng.api.storage.IStorageChannel;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IAEStack;
import appeng.api.storage.data.IItemList;
import appeng.api.util.AECableType;
import appeng.api.util.AEPartLocation;
import appeng.api.util.IConfigManager;
import appeng.container.ContainerLocator;
import appeng.container.ContainerOpener;
import appeng.container.implementations.LevelEmitterContainer;
import appeng.core.AppEng;
import appeng.items.parts.PartModels;
import appeng.me.GridAccessException;
import appeng.parts.PartModel;
import appeng.tile.inventory.AppEngInternalAEInventory;
import appeng.util.Platform;
import appeng.util.inv.InvOperation;
public class LevelEmitterPart extends UpgradeablePart implements IEnergyWatcherHost, IStackWatcherHost,
ICraftingWatcherHost, IMEMonitorHandlerReceiver<IAEItemStack>, ICraftingProvider {
@PartModels
public static final Identifier MODEL_BASE_OFF = new Identifier(AppEng.MOD_ID,
"part/level_emitter_base_off");
@PartModels
public static final Identifier MODEL_BASE_ON = new Identifier(AppEng.MOD_ID,
"part/level_emitter_base_on");
@PartModels
public static final Identifier MODEL_STATUS_OFF = new Identifier(AppEng.MOD_ID,
"part/level_emitter_status_off");
@PartModels
public static final Identifier MODEL_STATUS_ON = new Identifier(AppEng.MOD_ID,
"part/level_emitter_status_on");
@PartModels
public static final Identifier MODEL_STATUS_HAS_CHANNEL = new Identifier(AppEng.MOD_ID,
"part/level_emitter_status_has_channel");
public static final PartModel MODEL_OFF_OFF = new PartModel(MODEL_BASE_OFF, MODEL_STATUS_OFF);
public static final PartModel MODEL_OFF_ON = new PartModel(MODEL_BASE_OFF, MODEL_STATUS_ON);
public static final PartModel MODEL_OFF_HAS_CHANNEL = new PartModel(MODEL_BASE_OFF, MODEL_STATUS_HAS_CHANNEL);
public static final PartModel MODEL_ON_OFF = new PartModel(MODEL_BASE_ON, MODEL_STATUS_OFF);
public static final PartModel MODEL_ON_ON = new PartModel(MODEL_BASE_ON, MODEL_STATUS_ON);
public static final PartModel MODEL_ON_HAS_CHANNEL = new PartModel(MODEL_BASE_ON, MODEL_STATUS_HAS_CHANNEL);
private static final int FLAG_ON = 4;
private final AppEngInternalAEInventory config = new AppEngInternalAEInventory(this, 1);
private boolean prevState = false;
private long lastReportedValue = 0;
private long reportingValue = 0;
private IStackWatcher myWatcher;
private IEnergyWatcher myEnergyWatcher;
private ICraftingWatcher myCraftingWatcher;
private double centerX;
private double centerY;
private double centerZ;
public LevelEmitterPart(final ItemStack is) {
super(is);
this.getConfigManager().registerSetting(Settings.REDSTONE_EMITTER, RedstoneMode.HIGH_SIGNAL);
this.getConfigManager().registerSetting(Settings.FUZZY_MODE, FuzzyMode.IGNORE_ALL);
this.getConfigManager().registerSetting(Settings.LEVEL_TYPE, LevelType.ITEM_LEVEL);
this.getConfigManager().registerSetting(Settings.CRAFT_VIA_REDSTONE, YesNo.NO);
}
public long getReportingValue() {
return this.reportingValue;
}
public void setReportingValue(final long v) {
this.reportingValue = v;
if (this.getConfigManager().getSetting(Settings.LEVEL_TYPE) == LevelType.ENERGY_LEVEL) {
this.configureWatchers();
} else {
this.updateState();
}
}
@MENetworkEventSubscribe
public void powerChanged(final MENetworkPowerStatusChange c) {
this.updateState();
}
private void updateState() {
final boolean isOn = this.isLevelEmitterOn();
if (this.prevState != isOn) {
this.getHost().markForUpdate();
final BlockEntity te = this.getHost().getTile();
this.prevState = isOn;
Platform.notifyBlocksOfNeighbors(te.getWorld(), te.getPos());
Platform.notifyBlocksOfNeighbors(te.getWorld(), te.getPos().offset(this.getSide().getFacing()));
}
}
// TODO: Make private again
public boolean isLevelEmitterOn() {
if (Platform.isClient()) {
return (this.getClientFlags() & FLAG_ON) == FLAG_ON;
}
if (!this.getProxy().isActive()) {
return false;
}
if (this.getInstalledUpgrades(Upgrades.CRAFTING) > 0) {
try {
return this.getProxy().getCrafting().isRequesting(this.config.getAEStackInSlot(0));
} catch (final GridAccessException e) {
// :P
}
return this.prevState;
}
final boolean flipState = this.getConfigManager()
.getSetting(Settings.REDSTONE_EMITTER) == RedstoneMode.LOW_SIGNAL;
return flipState ? this.reportingValue >= this.lastReportedValue + 1
: this.reportingValue < this.lastReportedValue + 1;
}
@MENetworkEventSubscribe
public void channelChanged(final MENetworkChannelsChanged c) {
this.updateState();
}
@Override
protected int populateFlags(final int cf) {
return cf | (this.prevState ? FLAG_ON : 0);
}
@Override
public void updateWatcher(final ICraftingWatcher newWatcher) {
this.myCraftingWatcher = newWatcher;
this.configureWatchers();
}
@Override
public void onRequestChange(final ICraftingGrid craftingGrid, final IAEItemStack what) {
this.updateState();
}
// update the system...
private void configureWatchers() {
final IAEItemStack myStack = this.config.getAEStackInSlot(0);
if (this.myWatcher != null) {
this.myWatcher.reset();
}
if (this.myEnergyWatcher != null) {
this.myEnergyWatcher.reset();
}
if (this.myCraftingWatcher != null) {
this.myCraftingWatcher.reset();
}
try {
this.getProxy().getGrid().postEvent(new MENetworkCraftingPatternChange(this, this.getProxy().getNode()));
} catch (final GridAccessException e1) {
// :/
}
if (this.getInstalledUpgrades(Upgrades.CRAFTING) > 0) {
if (this.myCraftingWatcher != null && myStack != null) {
this.myCraftingWatcher.add(myStack);
}
return;
}
if (this.getConfigManager().getSetting(Settings.LEVEL_TYPE) == LevelType.ENERGY_LEVEL) {
if (this.myEnergyWatcher != null) {
this.myEnergyWatcher.add(this.reportingValue);
}
try {
// update to power...
this.lastReportedValue = (long) this.getProxy().getEnergy().getStoredPower();
this.updateState();
// no more item stuff..
this.getProxy().getStorage()
.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class))
.removeListener(this);
} catch (final GridAccessException e) {
// :P
}
return;
}
try {
if (this.getInstalledUpgrades(Upgrades.FUZZY) > 0 || myStack == null) {
this.getProxy().getStorage()
.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class))
.addListener(this, this.getProxy().getGrid());
} else {
this.getProxy().getStorage()
.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class))
.removeListener(this);
if (this.myWatcher != null) {
this.myWatcher.add(myStack);
}
}
this.updateReportingValue(this.getProxy().getStorage()
.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class)));
} catch (final GridAccessException e) {
// >.>
}
}
private void updateReportingValue(final IMEMonitor<IAEItemStack> monitor) {
final IAEItemStack myStack = this.config.getAEStackInSlot(0);
if (myStack == null) {
this.lastReportedValue = 0;
for (final IAEItemStack st : monitor.getStorageList()) {
this.lastReportedValue += st.getStackSize();
}
} else if (this.getInstalledUpgrades(Upgrades.FUZZY) > 0) {
this.lastReportedValue = 0;
final FuzzyMode fzMode = (FuzzyMode) this.getConfigManager().getSetting(Settings.FUZZY_MODE);
final Collection<IAEItemStack> fuzzyList = monitor.getStorageList().findFuzzy(myStack, fzMode);
for (final IAEItemStack st : fuzzyList) {
this.lastReportedValue += st.getStackSize();
}
} else {
final IAEItemStack r = monitor.getStorageList().findPrecise(myStack);
if (r == null) {
this.lastReportedValue = 0;
} else {
this.lastReportedValue = r.getStackSize();
}
}
this.updateState();
}
@Override
public void updateWatcher(final IStackWatcher newWatcher) {
this.myWatcher = newWatcher;
this.configureWatchers();
}
@Override
public void onStackChange(final IItemList o, final IAEStack fullStack, final IAEStack diffStack,
final IActionSource src, final IStorageChannel chan) {
if (chan == AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class)
&& fullStack.equals(this.config.getAEStackInSlot(0))
&& this.getInstalledUpgrades(Upgrades.FUZZY) == 0) {
this.lastReportedValue = fullStack.getStackSize();
this.updateState();
}
}
@Override
public void updateWatcher(final IEnergyWatcher newWatcher) {
this.myEnergyWatcher = newWatcher;
this.configureWatchers();
}
@Override
public void onThresholdPass(final IEnergyGrid energyGrid) {
this.lastReportedValue = (long) energyGrid.getStoredPower();
this.updateState();
}
@Override
public boolean isValid(final Object effectiveGrid) {
try {
return this.getProxy().getGrid() == effectiveGrid;
} catch (final GridAccessException e) {
return false;
}
}
@Override
public void postChange(final IBaseMonitor<IAEItemStack> monitor, final Iterable<IAEItemStack> change,
final IActionSource actionSource) {
this.updateReportingValue((IMEMonitor<IAEItemStack>) monitor);
}
@Override
public void onListUpdate() {
try {
this.updateReportingValue(this.getProxy().getStorage()
.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class)));
} catch (final GridAccessException e) {
// ;P
}
}
@Override
public AECableType getCableConnectionType(final AEPartLocation dir) {
return AECableType.SMART;
}
@Override
public void getBoxes(final IPartCollisionHelper bch) {
bch.addBox(7, 7, 11, 9, 9, 16);
}
@Override
public int isProvidingStrongPower() {
return this.prevState ? 15 : 0;
}
@Override
public int isProvidingWeakPower() {
return this.prevState ? 15 : 0;
}
@Override
public void randomDisplayTick(final World world, final BlockPos pos, final Random r) {
if (this.isLevelEmitterOn()) {
final AEPartLocation d = this.getSide();
final double d0 = d.xOffset * 0.45F + (r.nextFloat() - 0.5F) * 0.2D;
final double d1 = d.yOffset * 0.45F + (r.nextFloat() - 0.5F) * 0.2D;
final double d2 = d.zOffset * 0.45F + (r.nextFloat() - 0.5F) * 0.2D;
world.addParticle(DustParticleEffect.RED, 0.5 + pos.getX() + d0, 0.5 + pos.getY() + d1,
0.5 + pos.getZ() + d2, 0.0D, 0.0D, 0.0D);
}
}
@Override
public float getCableConnectionLength(AECableType cable) {
return 16;
}
@Override
public boolean onPartActivate(final PlayerEntity player, final Hand hand, final Vec3d pos) {
if (Platform.isServer()) {
ContainerOpener.openContainer(LevelEmitterContainer.TYPE, player, ContainerLocator.forPart(this));
}
return true;
}
@Override
public void updateSetting(final IConfigManager manager, final Settings settingName, final Enum<?> newValue) {
this.configureWatchers();
}
@Override
public void onChangeInventory(final FixedItemInv inv, final int slot, final InvOperation mc,
final ItemStack removedStack, final ItemStack newStack) {
if (inv == this.config) {
this.configureWatchers();
}
super.onChangeInventory(inv, slot, mc, removedStack, newStack);
}
@Override
public void upgradesChanged() {
this.configureWatchers();
}
@Override
public boolean canConnectRedstone() {
return true;
}
@Override
public void readFromNBT(final CompoundTag data) {
super.readFromNBT(data);
this.lastReportedValue = data.getLong("lastReportedValue");
this.reportingValue = data.getLong("reportingValue");
this.prevState = data.getBoolean("prevState");
this.config.readFromNBT(data, "config");
}
@Override
public void writeToNBT(final CompoundTag data) {
super.writeToNBT(data);
data.putLong("lastReportedValue", this.lastReportedValue);
data.putLong("reportingValue", this.reportingValue);
data.putBoolean("prevState", this.prevState);
this.config.writeToNBT(data, "config");
}
@Override
public FixedItemInv getInventoryByName(final String name) {
if (name.equals("config")) {
return this.config;
}
return super.getInventoryByName(name);
}
@Override
public boolean pushPattern(final ICraftingPatternDetails patternDetails, final CraftingInventory table) {
return false;
}
@Override
public boolean isBusy() {
return true;
}
@Override
public void provideCrafting(final ICraftingProviderHelper craftingTracker) {
if (this.getInstalledUpgrades(Upgrades.CRAFTING) > 0) {
if (this.getConfigManager().getSetting(Settings.CRAFT_VIA_REDSTONE) == YesNo.YES) {
final IAEItemStack what = this.config.getAEStackInSlot(0);
if (what != null) {
craftingTracker.setEmitable(what);
}
}
}
}
@Override
public IPartModel getStaticModels() {
if (this.isActive() && this.isPowered()) {
return this.isLevelEmitterOn() ? MODEL_ON_HAS_CHANNEL : MODEL_OFF_HAS_CHANNEL;
} else if (this.isPowered()) {
return this.isLevelEmitterOn() ? MODEL_ON_ON : MODEL_OFF_ON;
} else {
return this.isLevelEmitterOn() ? MODEL_ON_OFF : MODEL_OFF_OFF;
}
}
}
@@ -0,0 +1,124 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.parts.automation;
import java.util.ArrayList;
import java.util.List;
import com.google.common.base.Strings;
/**
* Models in which directions - looking at the front face - a plane
* (annihilation, formation, etc.) is connected to other planes of the same
* type.
*/
public final class PlaneConnections {
private final boolean up;
private final boolean right;
private final boolean down;
private final boolean left;
private static final int BITMASK_UP = 8;
private static final int BITMASK_RIGHT = 4;
private static final int BITMASK_DOWN = 2;
private static final int BITMASK_LEFT = 1;
public static final List<PlaneConnections> PERMUTATIONS = generatePermutations();
private static List<PlaneConnections> generatePermutations() {
List<PlaneConnections> connections = new ArrayList<>(16);
for (int i = 0; i < 16; i++) {
boolean up = (i & BITMASK_UP) != 0;
boolean right = (i & BITMASK_RIGHT) != 0;
boolean down = (i & BITMASK_DOWN) != 0;
boolean left = (i & BITMASK_LEFT) != 0;
connections.add(new PlaneConnections(up, right, down, left));
}
return connections;
}
private PlaneConnections(boolean up, boolean right, boolean down, boolean left) {
this.up = up;
this.right = right;
this.down = down;
this.left = left;
}
public static PlaneConnections of(boolean up, boolean right, boolean down, boolean left) {
return PERMUTATIONS.get(getIndex(up, right, down, left));
}
public boolean isUp() {
return this.up;
}
public boolean isRight() {
return this.right;
}
public boolean isDown() {
return this.down;
}
public boolean isLeft() {
return this.left;
}
// The combination of connections expressed as a number ranging from [0,15]
public int getIndex() {
return getIndex(this.up, this.right, this.down, this.left);
}
private static int getIndex(boolean up, boolean right, boolean down, boolean left) {
return (up ? BITMASK_UP : 0) + (right ? BITMASK_RIGHT : 0) + (left ? BITMASK_LEFT : 0)
+ (down ? BITMASK_DOWN : 0);
}
// Returns a suffix that expresses the connection states as a string
public String getFilenameSuffix() {
String suffix = Integer.toBinaryString(this.getIndex());
return Strings.padStart(suffix, 4, '0');
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || this.getClass() != o.getClass()) {
return false;
}
PlaneConnections that = (PlaneConnections) o;
return this.up == that.up && this.right == that.right && this.down == that.down && this.left == that.left;
}
@Override
public int hashCode() {
int result = (this.up ? 1 : 0);
result = 31 * result + (this.right ? 1 : 0);
result = 31 * result + (this.down ? 1 : 0);
result = 31 * result + (this.left ? 1 : 0);
return result;
}
}
@@ -0,0 +1,73 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.parts.automation;
import java.util.List;
import com.google.common.collect.ImmutableList;
import net.minecraft.util.Identifier;
import appeng.api.parts.IPartModel;
import appeng.core.AppEng;
import appeng.parts.PartModel;
/**
* Contains a mapping from a Plane's connections to the models to use for that
* state.
*/
public class PlaneModels {
public static final Identifier MODEL_CHASSIS_OFF = new Identifier(AppEng.MOD_ID,
"part/transition_plane_off");
public static final Identifier MODEL_CHASSIS_ON = new Identifier(AppEng.MOD_ID,
"part/transition_plane_on");
public static final Identifier MODEL_CHASSIS_HAS_CHANNEL = new Identifier(AppEng.MOD_ID,
"part/transition_plane_has_channel");
private final IPartModel modelOff;
private final IPartModel modelOn;
private final IPartModel modelHasChannel;
public PlaneModels(String planeOffLocation, String planeOnLocation) {
Identifier planeOff = new Identifier(AppEng.MOD_ID, planeOffLocation);
Identifier planeOn = new Identifier(AppEng.MOD_ID, planeOnLocation);
this.modelOff = new PartModel(MODEL_CHASSIS_OFF, planeOff);
this.modelOn = new PartModel(MODEL_CHASSIS_ON, planeOff);
this.modelHasChannel = new PartModel(MODEL_CHASSIS_HAS_CHANNEL, planeOn);
}
public IPartModel getModel(boolean hasPower, boolean hasChannel) {
if (hasPower && hasChannel) {
return modelHasChannel;
} else if (hasPower) {
return modelOn;
} else {
return modelOff;
}
}
public List<IPartModel> getModels() {
return ImmutableList.of(modelOff, modelOn, modelHasChannel);
}
}
@@ -0,0 +1,154 @@
/*
* 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.parts.automation;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import alexiil.mc.lib.attributes.item.FixedItemInv;
import appeng.api.config.RedstoneMode;
import appeng.api.config.Upgrades;
import appeng.api.networking.ticking.IGridTickable;
import appeng.api.networking.ticking.TickRateModulation;
import appeng.me.GridAccessException;
import appeng.tile.inventory.AppEngInternalAEInventory;
import appeng.util.InventoryAdaptor;
public abstract class SharedItemBusPart extends UpgradeablePart implements IGridTickable {
private final AppEngInternalAEInventory config = new AppEngInternalAEInventory(this, 9);
private boolean lastRedstone = false;
public SharedItemBusPart(final ItemStack is) {
super(is);
}
@Override
public void upgradesChanged() {
this.updateState();
}
@Override
public void readFromNBT(final net.minecraft.nbt.CompoundTag extra) {
super.readFromNBT(extra);
this.getConfig().readFromNBT(extra, "config");
}
@Override
public void writeToNBT(final net.minecraft.nbt.CompoundTag extra) {
super.writeToNBT(extra);
this.getConfig().writeToNBT(extra, "config");
}
@Override
public FixedItemInv getInventoryByName(final String name) {
if (name.equals("config")) {
return this.getConfig();
}
return super.getInventoryByName(name);
}
@Override
public void onneighborUpdate(BlockView w, BlockPos pos, BlockPos neighbor) {
this.updateState();
if (this.lastRedstone != this.getHost().hasRedstone(this.getSide())) {
this.lastRedstone = !this.lastRedstone;
if (this.lastRedstone && this.getRSMode() == RedstoneMode.SIGNAL_PULSE) {
this.doBusWork();
}
}
}
protected InventoryAdaptor getHandler() {
final BlockEntity self = this.getHost().getTile();
final BlockEntity target = this.getBlockEntity(self, self.getPos().offset(this.getSide().getFacing()));
return InventoryAdaptor.getAdaptor(target, this.getSide().getFacing().getOpposite());
}
private BlockEntity getBlockEntity(final BlockEntity self, final BlockPos pos) {
final World w = self.getWorld();
ChunkPos cp = new ChunkPos(pos);
if (w.getChunkManager().isChunkLoaded(cp.x, cp.z)) {
return w.getBlockEntity(pos);
}
return null;
}
protected int availableSlots() {
return Math.min(1 + this.getInstalledUpgrades(Upgrades.CAPACITY) * 4, this.getConfig().getSlotCount());
}
protected int calculateItemsToSend() {
switch (this.getInstalledUpgrades(Upgrades.SPEED)) {
default:
case 0:
return 1;
case 1:
return 8;
case 2:
return 32;
case 3:
return 64;
case 4:
return 96;
}
}
/**
* Checks if the bus can actually do something.
*
* Currently this tests if the chunk for the target is actually loaded.
*
* @return true, if the the bus should do its work.
*/
protected boolean canDoBusWork() {
final BlockEntity self = this.getHost().getTile();
final BlockPos selfPos = self.getPos().offset(this.getSide().getFacing());
final World world = self.getWorld();
ChunkPos cp = new ChunkPos(selfPos);
return world != null && world.getChunkManager().isChunkLoaded(cp.x, cp.z);
}
private void updateState() {
try {
if (!this.isSleeping()) {
this.getProxy().getTick().wakeDevice(this.getProxy().getNode());
} else {
this.getProxy().getTick().sleepDevice(this.getProxy().getNode());
}
} catch (final GridAccessException e) {
// :P
}
}
protected abstract TickRateModulation doBusWork();
AppEngInternalAEInventory getConfig() {
return this.config;
}
}
@@ -0,0 +1,148 @@
/*
* 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.parts.automation;
import java.util.List;
import net.minecraft.item.ItemStack;
import alexiil.mc.lib.attributes.item.FixedItemInv;
import appeng.api.config.RedstoneMode;
import appeng.api.config.Settings;
import appeng.api.config.Upgrades;
import appeng.api.util.IConfigManager;
import appeng.parts.BasicStatePart;
import appeng.util.ConfigManager;
import appeng.util.IConfigManagerHost;
import appeng.util.inv.IAEAppEngInventory;
import appeng.util.inv.InvOperation;
public abstract class UpgradeablePart extends BasicStatePart implements IAEAppEngInventory, IConfigManagerHost {
private final IConfigManager manager;
private final UpgradeInventory upgrades;
public UpgradeablePart(final ItemStack is) {
super(is);
this.upgrades = new StackUpgradeInventory(this.getItemStack(), this, this.getUpgradeSlots());
this.manager = new ConfigManager(this);
}
protected int getUpgradeSlots() {
return 4;
}
@Override
public void updateSetting(final IConfigManager manager, final Settings settingName, final Enum<?> newValue) {
}
@Override
public void onChangeInventory(final FixedItemInv inv, final int slot, final InvOperation mc,
final ItemStack removedStack, final ItemStack newStack) {
if (inv == this.upgrades) {
this.upgradesChanged();
}
}
public void upgradesChanged() {
}
protected boolean isSleeping() {
if (this.getInstalledUpgrades(Upgrades.REDSTONE) > 0) {
switch (this.getRSMode()) {
case IGNORE:
return false;
case HIGH_SIGNAL:
if (this.getHost().hasRedstone(this.getSide())) {
return false;
}
break;
case LOW_SIGNAL:
if (!this.getHost().hasRedstone(this.getSide())) {
return false;
}
break;
case SIGNAL_PULSE:
default:
break;
}
return true;
}
return false;
}
@Override
public int getInstalledUpgrades(final Upgrades u) {
return this.upgrades.getInstalledUpgrades(u);
}
@Override
public boolean canConnectRedstone() {
return this.upgrades.getMaxInstalled(Upgrades.REDSTONE) > 0;
}
@Override
public void readFromNBT(final net.minecraft.nbt.CompoundTag extra) {
super.readFromNBT(extra);
this.manager.readFromNBT(extra);
this.upgrades.readFromNBT(extra, "upgrades");
}
@Override
public void writeToNBT(final net.minecraft.nbt.CompoundTag extra) {
super.writeToNBT(extra);
this.manager.writeToNBT(extra);
this.upgrades.writeToNBT(extra, "upgrades");
}
@Override
public void getDrops(final List<ItemStack> drops, final boolean wrenched) {
for (final ItemStack is : this.upgrades) {
if (!is.isEmpty()) {
drops.add(is);
}
}
}
@Override
public IConfigManager getConfigManager() {
return this.manager;
}
@Override
public FixedItemInv getInventoryByName(final String name) {
if (name.equals("upgrades")) {
return this.upgrades;
}
return null;
}
public RedstoneMode getRSMode() {
return null;
}
}
@@ -0,0 +1,277 @@
/*
* 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.parts.misc;
import java.util.EnumSet;
import java.util.List;
import alexiil.mc.lib.attributes.AttributeList;
import alexiil.mc.lib.attributes.item.FixedItemInv;
import com.google.common.collect.ImmutableSet;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.CraftingInventory;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.util.math.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Vec3d;
import appeng.api.AEApi;
import appeng.api.config.Actionable;
import appeng.api.config.Upgrades;
import appeng.api.networking.IGridNode;
import appeng.api.networking.crafting.ICraftingLink;
import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.api.networking.crafting.ICraftingProviderHelper;
import appeng.api.networking.events.MENetworkChannelsChanged;
import appeng.api.networking.events.MENetworkEventSubscribe;
import appeng.api.networking.events.MENetworkPowerStatusChange;
import appeng.api.networking.ticking.IGridTickable;
import appeng.api.networking.ticking.TickRateModulation;
import appeng.api.networking.ticking.TickingRequest;
import appeng.api.parts.IPartCollisionHelper;
import appeng.api.parts.IPartModel;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.IStorageChannel;
import appeng.api.storage.IStorageMonitorable;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IAEStack;
import appeng.api.util.AECableType;
import appeng.api.util.IConfigManager;
import appeng.container.ContainerLocator;
import appeng.container.ContainerOpener;
import appeng.container.implementations.InterfaceContainer;
import appeng.core.AppEng;
import appeng.helpers.DualityInterface;
import appeng.helpers.IInterfaceHost;
import appeng.helpers.IPriorityHost;
import appeng.items.parts.PartModels;
import appeng.parts.BasicStatePart;
import appeng.parts.PartModel;
import appeng.util.Platform;
import appeng.util.inv.IAEAppEngInventory;
import appeng.util.inv.IInventoryDestination;
import appeng.util.inv.InvOperation;
public class InterfacePart extends BasicStatePart implements IGridTickable, IStorageMonitorable, IInventoryDestination,
IInterfaceHost, IAEAppEngInventory, IPriorityHost {
public static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "part/interface_base");
@PartModels
public static final PartModel MODELS_OFF = new PartModel(MODEL_BASE,
new Identifier(AppEng.MOD_ID, "part/interface_off"));
@PartModels
public static final PartModel MODELS_ON = new PartModel(MODEL_BASE,
new Identifier(AppEng.MOD_ID, "part/interface_on"));
@PartModels
public static final PartModel MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE,
new Identifier(AppEng.MOD_ID, "part/interface_has_channel"));
private final DualityInterface duality = new DualityInterface(this.getProxy(), this);
public InterfacePart(final ItemStack is) {
super(is);
}
@MENetworkEventSubscribe
public void stateChange(final MENetworkChannelsChanged c) {
this.duality.notifyNeighbors();
}
@MENetworkEventSubscribe
public void stateChange(final MENetworkPowerStatusChange c) {
this.duality.notifyNeighbors();
}
@Override
public void getBoxes(final IPartCollisionHelper bch) {
bch.addBox(2, 2, 14, 14, 14, 16);
bch.addBox(5, 5, 12, 11, 11, 14);
}
@Override
public int getInstalledUpgrades(final Upgrades u) {
return this.duality.getInstalledUpgrades(u);
}
@Override
public void gridChanged() {
this.duality.gridChanged();
}
@Override
public void readFromNBT(final CompoundTag data) {
super.readFromNBT(data);
this.duality.readFromNBT(data);
}
@Override
public void writeToNBT(final CompoundTag data) {
super.writeToNBT(data);
this.duality.writeToNBT(data);
}
@Override
public void addToWorld() {
super.addToWorld();
this.duality.initialize();
}
@Override
public void getDrops(final List<ItemStack> drops, final boolean wrenched) {
this.duality.addDrops(drops);
}
@Override
public float getCableConnectionLength(AECableType cable) {
return 4;
}
@Override
public IConfigManager getConfigManager() {
return this.duality.getConfigManager();
}
@Override
public FixedItemInv getInventoryByName(final String name) {
return this.duality.getInventoryByName(name);
}
@Override
public boolean onPartActivate(final PlayerEntity p, final Hand hand, final Vec3d pos) {
if (Platform.isServer()) {
ContainerOpener.openContainer(InterfaceContainer.TYPE, p, ContainerLocator.forPart(this));
}
return true;
}
@Override
public boolean canInsert(final ItemStack stack) {
return this.duality.canInsert(stack);
}
@Override
public <T extends IAEStack<T>> IMEMonitor<T> getInventory(IStorageChannel<T> channel) {
return this.duality.getInventory(channel);
}
@Override
public TickingRequest getTickingRequest(final IGridNode node) {
return this.duality.getTickingRequest(node);
}
@Override
public TickRateModulation tickingRequest(final IGridNode node, final int ticksSinceLastCall) {
return this.duality.tickingRequest(node, ticksSinceLastCall);
}
@Override
public void onChangeInventory(final FixedItemInv inv, final int slot, final InvOperation mc,
final ItemStack removedStack, final ItemStack newStack) {
this.duality.onChangeInventory(inv, slot, mc, removedStack, newStack);
}
@Override
public DualityInterface getInterfaceDuality() {
return this.duality;
}
@Override
public EnumSet<Direction> getTargets() {
return EnumSet.of(this.getSide().getFacing());
}
@Override
public BlockEntity getBlockEntity() {
return super.getHost().getTile();
}
@Override
public boolean pushPattern(final ICraftingPatternDetails patternDetails, final CraftingInventory table) {
return this.duality.pushPattern(patternDetails, table);
}
@Override
public boolean isBusy() {
return this.duality.isBusy();
}
@Override
public void provideCrafting(final ICraftingProviderHelper craftingTracker) {
this.duality.provideCrafting(craftingTracker);
}
@Override
public ImmutableSet<ICraftingLink> getRequestedJobs() {
return this.duality.getRequestedJobs();
}
@Override
public IAEItemStack injectCraftedItems(final ICraftingLink link, final IAEItemStack items, final Actionable mode) {
return this.duality.injectCraftedItems(link, items, mode);
}
@Override
public void jobStateChange(final ICraftingLink link) {
this.duality.jobStateChange(link);
}
@Override
public int getPriority() {
return this.duality.getPriority();
}
@Override
public void setPriority(final int newValue) {
this.duality.setPriority(newValue);
}
@Override
public IPartModel getStaticModels() {
if (this.isActive() && this.isPowered()) {
return MODELS_HAS_CHANNEL;
} else if (this.isPowered()) {
return MODELS_ON;
} else {
return MODELS_OFF;
}
}
@Override
public void addAllAttributes(AttributeList<?> to) {
this.duality.addAllAttributes(to);
}
@Override
public ItemStack getItemStackRepresentation() {
return AEApi.instance().definitions().parts().iface().maybeStack(1).orElse(ItemStack.EMPTY);
}
@Override
public ScreenHandlerType<?> getContainerType() {
return InterfaceContainer.TYPE;
}
}
@@ -0,0 +1,317 @@
/*
* 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.parts.misc;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import alexiil.mc.lib.attributes.Simulation;
import alexiil.mc.lib.attributes.item.FixedItemInv;
import net.minecraft.item.ItemStack;
import appeng.api.AEApi;
import appeng.api.config.Actionable;
import appeng.api.networking.security.IActionSource;
import appeng.api.networking.storage.IBaseMonitor;
import appeng.api.networking.ticking.TickRateModulation;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.IMEMonitorHandlerReceiver;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList;
import appeng.core.AELog;
import appeng.me.GridAccessException;
import appeng.me.helpers.IGridProxyable;
import appeng.me.storage.ITickingMonitor;
import appeng.util.Platform;
import appeng.util.item.AEItemStack;
/**
* Wraps an Item Handler in such a way that it can be used as an IMEInventory
* for items.
*/
class ItemHandlerAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<IAEItemStack>, ITickingMonitor {
private final Map<IMEMonitorHandlerReceiver<IAEItemStack>, Object> listeners = new HashMap<>();
private IActionSource mySource;
private final FixedItemInv itemHandler;
private final IGridProxyable proxyable;
private final InventoryCache cache;
ItemHandlerAdapter(FixedItemInv itemHandler, IGridProxyable proxy) {
this.itemHandler = itemHandler;
this.proxyable = proxy;
this.cache = new InventoryCache(this.itemHandler);
}
@Override
public IAEItemStack injectItems(IAEItemStack iox, Actionable type, IActionSource src) {
ItemStack orgInput = iox.createItemStack();
ItemStack remaining = orgInput;
int slotCount = this.itemHandler.getSlotCount();
boolean simulate = (type == Actionable.SIMULATE);
// This uses a brute force approach and tries to jam it in every slot the
// inventory exposes.
for (int i = 0; i < slotCount && !remaining.isEmpty(); i++) {
remaining = this.itemHandler.getSlot(i).attemptInsertion(remaining, simulate ? Simulation.SIMULATE : Simulation.ACTION);
}
// At this point, we still have some items left...
if (remaining == orgInput) {
// The stack remained unmodified, target inventory is full
return iox;
}
if (type == Actionable.MODULATE) {
try {
this.proxyable.getProxy().getTick().alertDevice(this.proxyable.getProxy().getNode());
} catch (GridAccessException ex) {
// meh
}
}
return AEItemStack.fromItemStack(remaining);
}
// FIXME FABRIC: this really needs to be rewritten to use the other interface types and not do slot iterations
@Override
public IAEItemStack extractItems(IAEItemStack request, Actionable mode, IActionSource src) {
ItemStack requestedItemStack = request.createItemStack();
int remainingSize = requestedItemStack.getCount();
// Use this to gather the requested items
ItemStack gathered = ItemStack.EMPTY;
final boolean simulate = (mode == Actionable.SIMULATE);
for (int i = 0; i < this.itemHandler.getSlotCount(); i++) {
ItemStack stackInInventorySlot = this.itemHandler.getInvStack(i);
if (!Platform.itemComparisons().isSameItem(stackInInventorySlot, requestedItemStack)) {
continue;
}
ItemStack extracted;
int stackSizeCurrentSlot = stackInInventorySlot.getCount();
int remainingCurrentSlot = Math.min(remainingSize, stackSizeCurrentSlot);
// We have to loop here because according to the docs, the handler shouldn't
// return a stack with size >
// maxSize, even if we request more. So even if it returns a valid stack, it
// might have more stuff.
do {
extracted = this.itemHandler.getSlot(i).attemptAnyExtraction(remainingCurrentSlot, simulate ? Simulation.SIMULATE : Simulation.ACTION);
if (!extracted.isEmpty()) {
if (extracted.getCount() > remainingCurrentSlot) {
// Something broke. It should never return more than we requested...
// We're going to silently eat the remainder
AELog.warn(
"Mod that provided item handler %s is broken. Returned %s items while only requesting %d.",
this.itemHandler.getClass().getName(), extracted.toString(), remainingCurrentSlot);
extracted.setCount(remainingCurrentSlot);
}
// We're just gonna use the first stack we get our hands on as the template for
// the rest.
// In case some stupid itemhandler (aka forge) returns an internal state we have
// to do a second
// expensive copy again.
if (gathered.isEmpty()) {
gathered = extracted.copy();
} else {
gathered.increment(extracted.getCount());
}
remainingCurrentSlot -= extracted.getCount();
}
} while (!extracted.isEmpty() && remainingCurrentSlot > 0);
remainingSize -= stackSizeCurrentSlot - remainingCurrentSlot;
// Done?
if (remainingSize <= 0) {
break;
}
}
if (!gathered.isEmpty()) {
if (mode == Actionable.MODULATE) {
try {
this.proxyable.getProxy().getTick().alertDevice(this.proxyable.getProxy().getNode());
} catch (GridAccessException ex) {
// meh
}
}
return AEItemStack.fromItemStack(gathered);
}
return null;
}
@Override
public TickRateModulation onTick() {
List<IAEItemStack> changes = this.cache.update();
if (!changes.isEmpty()) {
this.postDifference(changes);
return TickRateModulation.URGENT;
} else {
return TickRateModulation.SLOWER;
}
}
@Override
public void setActionSource(final IActionSource mySource) {
this.mySource = mySource;
}
@Override
public IItemList<IAEItemStack> getAvailableItems(IItemList<IAEItemStack> out) {
return this.cache.getAvailableItems(out);
}
@Override
public IItemStorageChannel getChannel() {
return AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class);
}
@Override
public void addListener(final IMEMonitorHandlerReceiver<IAEItemStack> l, final Object verificationToken) {
this.listeners.put(l, verificationToken);
}
@Override
public void removeListener(final IMEMonitorHandlerReceiver<IAEItemStack> l) {
this.listeners.remove(l);
}
private void postDifference(Iterable<IAEItemStack> a) {
final Iterator<Map.Entry<IMEMonitorHandlerReceiver<IAEItemStack>, Object>> i = this.listeners.entrySet()
.iterator();
while (i.hasNext()) {
final Map.Entry<IMEMonitorHandlerReceiver<IAEItemStack>, Object> l = i.next();
final IMEMonitorHandlerReceiver<IAEItemStack> key = l.getKey();
if (key.isValid(l.getValue())) {
key.postChange(this, a, this.mySource);
} else {
i.remove();
}
}
}
private static class InventoryCache {
private IAEItemStack[] cachedAeStacks = new IAEItemStack[0];
private final FixedItemInv itemHandler;
public InventoryCache(FixedItemInv itemHandler) {
this.itemHandler = itemHandler;
}
public IItemList<IAEItemStack> getAvailableItems(IItemList<IAEItemStack> out) {
Arrays.stream(this.cachedAeStacks).forEach(out::add);
return out;
}
public List<IAEItemStack> update() {
final List<IAEItemStack> changes = new ArrayList<>();
final int slots = this.itemHandler.getSlotCount();
// Make room for new slots
if (slots > this.cachedAeStacks.length) {
this.cachedAeStacks = Arrays.copyOf(this.cachedAeStacks, slots);
}
for (int slot = 0; slot < slots; slot++) {
// Save the old stuff
final IAEItemStack oldAeIS = this.cachedAeStacks[slot];
final ItemStack newIS = this.itemHandler.getInvStack(slot);
this.handlePossibleSlotChanges(slot, oldAeIS, newIS, changes);
}
// Handle cases where the number of slots actually is lower now than before
if (slots < this.cachedAeStacks.length) {
for (int slot = slots; slot < this.cachedAeStacks.length; slot++) {
final IAEItemStack aeStack = this.cachedAeStacks[slot];
if (aeStack != null) {
final IAEItemStack a = aeStack.copy();
a.setStackSize(-a.getStackSize());
changes.add(a);
}
}
// Reduce the cache size
this.cachedAeStacks = Arrays.copyOf(this.cachedAeStacks, slots);
}
return changes;
}
private void handlePossibleSlotChanges(int slot, IAEItemStack oldAeIS, ItemStack newIS,
List<IAEItemStack> changes) {
if (oldAeIS != null && oldAeIS.isSameType(newIS)) {
this.handleStackSizeChanged(slot, oldAeIS, newIS, changes);
} else {
this.handleItemChanged(slot, oldAeIS, newIS, changes);
}
}
private void handleStackSizeChanged(int slot, IAEItemStack oldAeIS, ItemStack newIS,
List<IAEItemStack> changes) {
// Still the same item, but amount might have changed
final long diff = newIS.getCount() - oldAeIS.getStackSize();
if (diff != 0) {
final IAEItemStack stack = oldAeIS.copy();
stack.setStackSize(newIS.getCount());
this.cachedAeStacks[slot] = stack;
final IAEItemStack a = stack.copy();
a.setStackSize(diff);
changes.add(a);
}
}
private void handleItemChanged(int slot, IAEItemStack oldAeIS, ItemStack newIS, List<IAEItemStack> changes) {
// Completely different item
this.cachedAeStacks[slot] = AEItemStack.fromItemStack(newIS);
// If we had a stack previously in this slot, notify the network about its
// disappearance
if (oldAeIS != null) {
oldAeIS.setStackSize(-oldAeIS.getStackSize());
changes.add(oldAeIS);
}
// Notify the network about the new stack. Note that this is null if newIS was
// null
if (this.cachedAeStacks[slot] != null) {
changes.add(this.cachedAeStacks[slot]);
}
}
}
}
@@ -0,0 +1,171 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2018, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.parts.misc;
import java.util.Collections;
import java.util.List;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockView;
import appeng.api.AEApi;
import appeng.api.config.Settings;
import appeng.api.networking.events.MENetworkCellArrayUpdate;
import appeng.api.networking.events.MENetworkChannelsChanged;
import appeng.api.networking.events.MENetworkEventSubscribe;
import appeng.api.networking.events.MENetworkPowerStatusChange;
import appeng.api.networking.ticking.IGridTickable;
import appeng.api.parts.IPartCollisionHelper;
import appeng.api.storage.IMEInventoryHandler;
import appeng.api.storage.IStorageChannel;
import appeng.api.storage.cells.ICellContainer;
import appeng.api.storage.cells.ICellInventory;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.util.AECableType;
import appeng.api.util.IConfigManager;
import appeng.helpers.IPriorityHost;
import appeng.me.GridAccessException;
import appeng.parts.automation.UpgradeablePart;
/**
* @author BrockWS
* @version rv6 - 22/05/2018
* @since rv6 22/05/2018
*/
public abstract class SharedStorageBusPart extends UpgradeablePart
implements IGridTickable, ICellContainer, IPriorityHost {
private boolean wasActive = false;
private int priority = 0;
public SharedStorageBusPart(ItemStack is) {
super(is);
}
protected void updateStatus() {
final boolean currentActive = this.getProxy().isActive();
if (this.wasActive != currentActive) {
this.wasActive = currentActive;
try {
this.getProxy().getGrid().postEvent(new MENetworkCellArrayUpdate());
this.getHost().markForUpdate();
} catch (final GridAccessException ignore) {
// :P
}
}
}
@MENetworkEventSubscribe
public void updateChannels(final MENetworkChannelsChanged changedChannels) {
this.updateStatus();
}
/**
* Helper method to get this parts storage channel
*
* @return Storage channel
*/
public IStorageChannel getStorageChannel() {
return AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class);
}
protected abstract void resetCache();
protected abstract void resetCache(boolean fullReset);
@Override
public List<IMEInventoryHandler> getCellArray(final IStorageChannel channel) {
return Collections.emptyList();
}
@Override
public void blinkCell(int slot) {
}
@Override
public void saveChanges(ICellInventory<?> cellInventory) {
}
@Override
public int getPriority() {
return this.priority;
}
@Override
public void setPriority(final int newValue) {
this.priority = newValue;
this.getHost().markForSave();
this.resetCache(true);
}
@Override
@MENetworkEventSubscribe
public void powerRender(final MENetworkPowerStatusChange c) {
this.updateStatus();
}
@Override
public void upgradesChanged() {
super.upgradesChanged();
this.resetCache(true);
}
@Override
public void updateSetting(final IConfigManager manager, final Settings settingName, final Enum<?> newValue) {
this.resetCache(true);
this.getHost().markForSave();
}
@Override
public void onneighborUpdate(BlockView w, BlockPos pos, BlockPos neighbor) {
if (pos.offset(this.getSide().getFacing()).equals(neighbor)) {
this.resetCache(false);
}
}
@Override
public void readFromNBT(final CompoundTag data) {
super.readFromNBT(data);
this.priority = data.getInt("priority");
}
@Override
public void writeToNBT(final CompoundTag data) {
super.writeToNBT(data);
data.putInt("priority", this.priority);
}
@Override
public void getBoxes(final IPartCollisionHelper bch) {
bch.addBox(3, 3, 15, 13, 13, 16);
bch.addBox(2, 2, 14, 14, 14, 15);
bch.addBox(5, 5, 12, 11, 11, 14);
}
@Override
protected int getUpgradeSlots() {
return 5;
}
@Override
public float getCableConnectionLength(AECableType cable) {
return 4;
}
}
@@ -0,0 +1,568 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.parts.misc;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import alexiil.mc.lib.attributes.Attributes;
import alexiil.mc.lib.attributes.item.ItemAttributes;
import appeng.attributes.MEAttributes;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.BlockView;
import alexiil.mc.lib.attributes.item.FixedItemInv;
import appeng.api.AEApi;
import appeng.api.config.AccessRestriction;
import appeng.api.config.FuzzyMode;
import appeng.api.config.IncludeExclude;
import appeng.api.config.Settings;
import appeng.api.config.StorageFilter;
import appeng.api.config.Upgrades;
import appeng.api.networking.IGridNode;
import appeng.api.networking.events.MENetworkCellArrayUpdate;
import appeng.api.networking.events.MENetworkChannelsChanged;
import appeng.api.networking.events.MENetworkEventSubscribe;
import appeng.api.networking.events.MENetworkPowerStatusChange;
import appeng.api.networking.security.IActionSource;
import appeng.api.networking.storage.IBaseMonitor;
import appeng.api.networking.ticking.IGridTickable;
import appeng.api.networking.ticking.ITickManager;
import appeng.api.networking.ticking.TickRateModulation;
import appeng.api.networking.ticking.TickingRequest;
import appeng.api.parts.IPartCollisionHelper;
import appeng.api.parts.IPartHost;
import appeng.api.parts.IPartModel;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.IMEInventoryHandler;
import appeng.api.storage.IMEMonitorHandlerReceiver;
import appeng.api.storage.IStorageChannel;
import appeng.api.storage.IStorageMonitorable;
import appeng.api.storage.IStorageMonitorableAccessor;
import appeng.api.storage.cells.ICellContainer;
import appeng.api.storage.cells.ICellInventory;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList;
import appeng.api.util.AECableType;
import appeng.api.util.AEPartLocation;
import appeng.api.util.IConfigManager;
import appeng.container.ContainerLocator;
import appeng.container.ContainerOpener;
import appeng.container.implementations.StorageBusContainer;
import appeng.core.AppEng;
import appeng.core.settings.TickRates;
import appeng.helpers.IInterfaceHost;
import appeng.helpers.IPriorityHost;
import appeng.items.parts.PartModels;
import appeng.me.GridAccessException;
import appeng.me.helpers.MachineSource;
import appeng.me.storage.ITickingMonitor;
import appeng.me.storage.MEInventoryHandler;
import appeng.me.storage.MEMonitorIInventory;
import appeng.parts.PartModel;
import appeng.parts.automation.UpgradeablePart;
import appeng.tile.inventory.AppEngInternalAEInventory;
import appeng.util.Platform;
import appeng.util.inv.InvOperation;
import appeng.util.prioritylist.FuzzyPriorityList;
import appeng.util.prioritylist.PrecisePriorityList;
public class StorageBusPart extends UpgradeablePart
implements IGridTickable, ICellContainer, IMEMonitorHandlerReceiver<IAEItemStack>, IPriorityHost {
public static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "part/storage_bus_base");
@PartModels
public static final IPartModel MODELS_OFF = new PartModel(MODEL_BASE,
new Identifier(AppEng.MOD_ID, "part/storage_bus_off"));
@PartModels
public static final IPartModel MODELS_ON = new PartModel(MODEL_BASE,
new Identifier(AppEng.MOD_ID, "part/storage_bus_on"));
@PartModels
public static final IPartModel MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE,
new Identifier(AppEng.MOD_ID, "part/storage_bus_has_channel"));
private final IActionSource mySrc;
private final AppEngInternalAEInventory Config = new AppEngInternalAEInventory(this, 63);
private int priority = 0;
private boolean cached = false;
private ITickingMonitor monitor = null;
private MEInventoryHandler<IAEItemStack> handler = null;
private int handlerHash = 0;
private boolean wasActive = false;
private byte resetCacheLogic = 0;
public StorageBusPart(final ItemStack is) {
super(is);
this.getConfigManager().registerSetting(Settings.ACCESS, AccessRestriction.READ_WRITE);
this.getConfigManager().registerSetting(Settings.FUZZY_MODE, FuzzyMode.IGNORE_ALL);
this.getConfigManager().registerSetting(Settings.STORAGE_FILTER, StorageFilter.EXTRACTABLE_ONLY);
this.mySrc = new MachineSource(this);
}
@Override
@MENetworkEventSubscribe
public void powerRender(final MENetworkPowerStatusChange c) {
this.updateStatus();
}
private void updateStatus() {
final boolean currentActive = this.getProxy().isActive();
if (this.wasActive != currentActive) {
this.wasActive = currentActive;
try {
this.getProxy().getGrid().postEvent(new MENetworkCellArrayUpdate());
this.getHost().markForUpdate();
} catch (final GridAccessException e) {
// :P
}
}
}
@MENetworkEventSubscribe
public void updateChannels(final MENetworkChannelsChanged changedChannels) {
this.updateStatus();
}
@Override
protected int getUpgradeSlots() {
return 5;
}
@Override
public void updateSetting(final IConfigManager manager, final Settings settingName, final Enum<?> newValue) {
this.resetCache(true);
this.getHost().markForSave();
}
@Override
public void onChangeInventory(final FixedItemInv inv, final int slot, final InvOperation mc,
final ItemStack removedStack, final ItemStack newStack) {
super.onChangeInventory(inv, slot, mc, removedStack, newStack);
if (inv == this.Config) {
this.resetCache(true);
}
}
@Override
public void upgradesChanged() {
super.upgradesChanged();
this.resetCache(true);
}
@Override
public void readFromNBT(final CompoundTag data) {
super.readFromNBT(data);
this.Config.readFromNBT(data, "config");
this.priority = data.getInt("priority");
}
@Override
public void writeToNBT(final CompoundTag data) {
super.writeToNBT(data);
this.Config.writeToNBT(data, "config");
data.putInt("priority", this.priority);
}
@Override
public FixedItemInv getInventoryByName(final String name) {
if (name.equals("config")) {
return this.Config;
}
return super.getInventoryByName(name);
}
private void resetCache(final boolean fullReset) {
if (this.getHost() == null || this.getHost().getTile() == null || this.getHost().getTile().getWorld() == null
|| this.getHost().getTile().getWorld().isClient) {
return;
}
if (fullReset) {
this.resetCacheLogic = 2;
} else {
this.resetCacheLogic = 1;
}
try {
this.getProxy().getTick().alertDevice(this.getProxy().getNode());
} catch (final GridAccessException e) {
// :P
}
}
@Override
public boolean isValid(final Object verificationToken) {
return this.handler == verificationToken;
}
@Override
public void postChange(final IBaseMonitor<IAEItemStack> monitor, final Iterable<IAEItemStack> change,
final IActionSource source) {
try {
if (this.getProxy().isActive()) {
this.getProxy().getStorage().postAlterationOfStoredItems(
AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class), change, this.mySrc);
}
} catch (final GridAccessException e) {
// :(
}
}
@Override
public void onListUpdate() {
// not used here.
}
@Override
public void getBoxes(final IPartCollisionHelper bch) {
bch.addBox(3, 3, 15, 13, 13, 16);
bch.addBox(2, 2, 14, 14, 14, 15);
bch.addBox(5, 5, 12, 11, 11, 14);
}
@Override
public void onneighborUpdate(BlockView w, BlockPos pos, BlockPos neighbor) {
if (pos.offset(this.getSide().getFacing()).equals(neighbor)) {
final BlockEntity te = w.getBlockEntity(neighbor);
// In case the TE was destroyed, we have to do a full reset immediately.
if (te == null) {
this.resetCache(true);
this.resetCache();
} else {
this.resetCache(false);
}
}
}
@Override
public float getCableConnectionLength(AECableType cable) {
return 4;
}
@Override
public boolean onPartActivate(final PlayerEntity player, final Hand hand, final Vec3d pos) {
if (Platform.isServer()) {
ContainerOpener.openContainer(StorageBusContainer.TYPE, player, ContainerLocator.forPart(this));
}
return true;
}
@Override
public TickingRequest getTickingRequest(final IGridNode node) {
return new TickingRequest(TickRates.StorageBus.getMin(), TickRates.StorageBus.getMax(), this.monitor == null,
true);
}
@Override
public TickRateModulation tickingRequest(final IGridNode node, final int ticksSinceLastCall) {
if (this.resetCacheLogic != 0) {
this.resetCache();
}
if (this.monitor != null) {
return this.monitor.onTick();
}
return TickRateModulation.SLEEP;
}
private void resetCache() {
final boolean fullReset = this.resetCacheLogic == 2;
this.resetCacheLogic = 0;
final IMEInventory<IAEItemStack> in = this.getInternalHandler();
IItemList<IAEItemStack> before = AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class)
.createList();
if (in != null) {
before = in.getAvailableItems(before);
}
this.cached = false;
if (fullReset) {
this.handlerHash = 0;
}
final IMEInventory<IAEItemStack> out = this.getInternalHandler();
if (in != out) {
IItemList<IAEItemStack> after = AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class)
.createList();
if (out != null) {
after = out.getAvailableItems(after);
}
Platform.postListChanges(before, after, this, this.mySrc);
}
}
private IMEInventory<IAEItemStack> getInventoryWrapper(BlockEntity target) {
Direction targetSide = this.getSide().getFacing().getOpposite();
// Prioritize a handler to directly link to another ME network
IStorageMonitorableAccessor accessor = getMeAccessor(target, targetSide);
if (accessor != null) {
IStorageMonitorable inventory = accessor.getInventory(this.mySrc);
if (inventory != null) {
return inventory.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class));
}
// So this could / can be a design decision. If the tile does support our custom
// capability,
// but it does not return an inventory for the action source, we do NOT fall
// back to using
// IItemHandler's, as that might circumvent the security setings, and might also
// cause
// performance issues.
return null;
}
// Check via cap for IItemHandler
FixedItemInv handlerExt = getFixedItemInv(target, targetSide);
if (handlerExt != null) {
return new ItemHandlerAdapter(handlerExt, this);
}
return null;
}
// TODO, LazyOptionals are cacheable this might need changing?
private int createHandlerHash(BlockEntity target) {
if (target == null) {
return 0;
}
final Direction targetSide = this.getSide().getFacing().getOpposite();
IStorageMonitorableAccessor accessor = getMeAccessor(target, targetSide);
if (accessor != null) {
return Objects.hash(target, accessor);
}
FixedItemInv itemHandler = getFixedItemInv(target, targetSide);
if (itemHandler != null) {
return Objects.hash(target, itemHandler, itemHandler.getSlotCount());
}
return 0;
}
private FixedItemInv getFixedItemInv(BlockEntity target, Direction targetSide) {
return MEAttributes.getFirstAttributeOnSide(ItemAttributes.FIXED_INV, target, targetSide);
}
private IStorageMonitorableAccessor getMeAccessor(BlockEntity target, Direction targetSide) {
return MEAttributes.getFirstAttributeOnSide(MEAttributes.STORAGE_MONITORABLE_ACCESSOR, target, targetSide);
}
public MEInventoryHandler<IAEItemStack> getInternalHandler() {
if (this.cached) {
return this.handler;
}
final boolean wasSleeping = this.monitor == null;
this.cached = true;
final BlockEntity self = this.getHost().getTile();
final BlockEntity target = self.getWorld().getBlockEntity(self.getPos().offset(this.getSide().getFacing()));
final int newHandlerHash = this.createHandlerHash(target);
if (newHandlerHash != 0 && newHandlerHash == this.handlerHash) {
return this.handler;
}
this.handlerHash = newHandlerHash;
this.handler = null;
this.monitor = null;
if (target != null) {
IMEInventory<IAEItemStack> inv = this.getInventoryWrapper(target);
if (inv instanceof MEMonitorIInventory) {
final MEMonitorIInventory h = (MEMonitorIInventory) inv;
h.setMode((StorageFilter) this.getConfigManager().getSetting(Settings.STORAGE_FILTER));
}
if (inv instanceof ITickingMonitor) {
this.monitor = (ITickingMonitor) inv;
this.monitor.setActionSource(new MachineSource(this));
}
if (inv != null) {
this.checkInterfaceVsStorageBus(target, this.getSide().getOpposite());
this.handler = new MEInventoryHandler<IAEItemStack>(inv,
AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class));
this.handler.setBaseAccess((AccessRestriction) this.getConfigManager().getSetting(Settings.ACCESS));
this.handler.setWhitelist(this.getInstalledUpgrades(Upgrades.INVERTER) > 0 ? IncludeExclude.BLACKLIST
: IncludeExclude.WHITELIST);
this.handler.setPriority(this.priority);
final IItemList<IAEItemStack> priorityList = AEApi.instance().storage()
.getStorageChannel(IItemStorageChannel.class).createList();
final int slotsToUse = 18 + this.getInstalledUpgrades(Upgrades.CAPACITY) * 9;
for (int x = 0; x < this.Config.getSlotCount() && x < slotsToUse; x++) {
final IAEItemStack is = this.Config.getAEStackInSlot(x);
if (is != null) {
priorityList.add(is);
}
}
if (this.getInstalledUpgrades(Upgrades.FUZZY) > 0) {
this.handler.setPartitionList(new FuzzyPriorityList<IAEItemStack>(priorityList,
(FuzzyMode) this.getConfigManager().getSetting(Settings.FUZZY_MODE)));
} else {
this.handler.setPartitionList(new PrecisePriorityList<IAEItemStack>(priorityList));
}
if (inv instanceof IBaseMonitor) {
((IBaseMonitor<IAEItemStack>) inv).addListener(this, this.handler);
}
}
}
// update sleep state...
if (wasSleeping != (this.monitor == null)) {
try {
final ITickManager tm = this.getProxy().getTick();
if (this.monitor == null) {
tm.sleepDevice(this.getProxy().getNode());
} else {
tm.wakeDevice(this.getProxy().getNode());
}
} catch (final GridAccessException e) {
// :(
}
}
try {
// force grid to update handlers...
this.getProxy().getGrid().postEvent(new MENetworkCellArrayUpdate());
} catch (final GridAccessException e) {
// :3
}
return this.handler;
}
private void checkInterfaceVsStorageBus(final BlockEntity target, final AEPartLocation side) {
IInterfaceHost achievement = null;
if (target instanceof IInterfaceHost) {
achievement = (IInterfaceHost) target;
}
if (target instanceof IPartHost) {
final Object part = ((IPartHost) target).getPart(side);
if (part instanceof IInterfaceHost) {
achievement = (IInterfaceHost) part;
}
}
if (achievement != null && achievement.getActionableNode() != null) {
// Platform.increaseStat( achievement.getActionableNode().getPlayerID(),
// Achievements.Recursive.getAchievement()
// );
// Platform.increaseStat( getActionableNode().getPlayerID(),
// Achievements.Recursive.getAchievement() );
}
}
@Override
public List<IMEInventoryHandler> getCellArray(final IStorageChannel channel) {
if (channel == AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class)) {
final IMEInventoryHandler<IAEItemStack> out = this.getProxy().isActive() ? this.getInternalHandler() : null;
if (out != null) {
return Collections.singletonList(out);
}
}
return Collections.emptyList();
}
@Override
public int getPriority() {
return this.priority;
}
@Override
public void setPriority(final int newValue) {
this.priority = newValue;
this.getHost().markForSave();
this.resetCache(true);
}
@Override
public void blinkCell(final int slot) {
}
// TODO: BC PIPE INTEGRATION
/*
* @Override
*
* @Method( iname = IntegrationType.BuildCraftTransport ) public ConnectOverride
* overridePipeConnection( PipeType type, ForgeDirection with ) { return type ==
* PipeType.ITEM && with == this.getSide() ? ConnectOverride.CONNECT :
* ConnectOverride.DISCONNECT; }
*/
@Override
public void saveChanges(final ICellInventory<?> cellInventory) {
// nope!
}
@Override
public IPartModel getStaticModels() {
if (this.isActive() && this.isPowered()) {
return MODELS_HAS_CHANNEL;
} else if (this.isPowered()) {
return MODELS_ON;
} else {
return MODELS_OFF;
}
}
@Override
public ItemStack getItemStackRepresentation() {
return AEApi.instance().definitions().parts().storageBus().maybeStack(1).orElse(ItemStack.EMPTY);
}
@Override
public ScreenHandlerType<?> getContainerType() {
return StorageBusContainer.TYPE;
}
}
@@ -0,0 +1,222 @@
/*
* 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.parts.p2p;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.util.Hand;
import appeng.api.AEApi;
import appeng.api.exceptions.FailedConnectionException;
import appeng.api.networking.GridFlags;
import appeng.api.networking.IGridNode;
import appeng.api.networking.ticking.IGridTickable;
import appeng.api.networking.ticking.TickRateModulation;
import appeng.api.networking.ticking.TickingRequest;
import appeng.api.parts.IPartHost;
import appeng.api.parts.IPartModel;
import appeng.api.util.AECableType;
import appeng.api.util.AEPartLocation;
import appeng.core.AELog;
import appeng.core.settings.TickRates;
import appeng.hooks.TickHandler;
import appeng.items.parts.PartModels;
import appeng.me.GridAccessException;
import appeng.me.cache.helpers.Connections;
import appeng.me.cache.helpers.TunnelConnection;
import appeng.me.helpers.AENetworkProxy;
public class MEP2PTunnelPart extends P2PTunnelPart<MEP2PTunnelPart> implements IGridTickable {
private static final P2PModels MODELS = new P2PModels("part/p2p/p2p_tunnel_me");
@PartModels
public static List<IPartModel> getModels() {
return MODELS.getModels();
}
private final Connections connection = new Connections(this);
private final AENetworkProxy outerProxy = new AENetworkProxy(this, "outer", ItemStack.EMPTY, true);
public MEP2PTunnelPart(final ItemStack is) {
super(is);
this.getProxy().setFlags(GridFlags.REQUIRE_CHANNEL, GridFlags.COMPRESSED_CHANNEL);
this.outerProxy.setFlags(GridFlags.DENSE_CAPACITY, GridFlags.CANNOT_CARRY_COMPRESSED);
}
@Override
public void readFromNBT(final CompoundTag extra) {
super.readFromNBT(extra);
this.outerProxy.readFromNBT(extra);
}
@Override
public void writeToNBT(final CompoundTag extra) {
super.writeToNBT(extra);
this.outerProxy.writeToNBT(extra);
}
@Override
public void onTunnelNetworkChange() {
super.onTunnelNetworkChange();
if (!this.isOutput()) {
try {
this.getProxy().getTick().wakeDevice(this.getProxy().getNode());
} catch (final GridAccessException e) {
// :P
}
}
}
@Override
public AECableType getCableConnectionType(final AEPartLocation dir) {
return AECableType.DENSE_SMART;
}
@Override
public void removeFromWorld() {
super.removeFromWorld();
this.outerProxy.remove();
}
@Override
public void addToWorld() {
super.addToWorld();
this.outerProxy.onReady();
}
@Override
public void setPartHostInfo(final AEPartLocation side, final IPartHost host, final BlockEntity tile) {
super.setPartHostInfo(side, host, tile);
this.outerProxy.setValidSides(EnumSet.of(side.getFacing()));
}
@Override
public IGridNode getExternalFacingNode() {
return this.outerProxy.getNode();
}
@Override
public void onPlacement(final PlayerEntity player, final Hand hand, final ItemStack held,
final AEPartLocation side) {
super.onPlacement(player, hand, held, side);
this.outerProxy.setOwner(player);
}
@Override
public TickingRequest getTickingRequest(final IGridNode node) {
return new TickingRequest(TickRates.METunnel.getMin(), TickRates.METunnel.getMax(), true, false);
}
@Override
public TickRateModulation tickingRequest(final IGridNode node, final int ticksSinceLastCall) {
// just move on...
try {
if (!this.getProxy().getPath().isNetworkBooting()) {
if (!this.getProxy().getEnergy().isNetworkPowered()) {
this.connection.markDestroy();
TickHandler.INSTANCE.addCallable(this.getTile().getWorld(), this.connection);
} else {
if (this.getProxy().isActive()) {
this.connection.markCreate();
TickHandler.INSTANCE.addCallable(this.getTile().getWorld(), this.connection);
} else {
this.connection.markDestroy();
TickHandler.INSTANCE.addCallable(this.getTile().getWorld(), this.connection);
}
}
return TickRateModulation.SLEEP;
}
} catch (final GridAccessException e) {
// meh?
}
return TickRateModulation.IDLE;
}
public void updateConnections(final Connections connections) {
if (connections.isDestroy()) {
for (final TunnelConnection cw : this.connection.getConnections().values()) {
cw.getConnection().destroy();
}
this.connection.getConnections().clear();
} else if (connections.isCreate()) {
final Iterator<TunnelConnection> i = this.connection.getConnections().values().iterator();
while (i.hasNext()) {
final TunnelConnection cw = i.next();
try {
if (cw.getTunnel().getProxy().getGrid() != this.getProxy().getGrid()) {
cw.getConnection().destroy();
i.remove();
} else if (!cw.getTunnel().getProxy().isActive()) {
cw.getConnection().destroy();
i.remove();
}
} catch (final GridAccessException e) {
// :P
}
}
final List<MEP2PTunnelPart> newSides = new ArrayList<>();
try {
for (final MEP2PTunnelPart me : this.getOutputs()) {
if (me.getProxy().isActive() && connections.getConnections().get(me.getGridNode()) == null) {
newSides.add(me);
}
}
for (final MEP2PTunnelPart me : newSides) {
try {
connections.getConnections().put(me.getGridNode(), new TunnelConnection(me, AEApi.instance()
.grid().createGridConnection(this.outerProxy.getNode(), me.outerProxy.getNode())));
} catch (final FailedConnectionException e) {
final BlockEntity start = this.getTile();
final BlockEntity end = me.getTile();
AELog.debug(e);
AELog.warn(
"Failed to establish a ME P2P Tunnel between the tunnels at [x=%d, y=%d, z=%d] and [x=%d, y=%d, z=%d]",
start.getPos().getX(), start.getPos().getY(), start.getPos().getZ(),
end.getPos().getX(), end.getPos().getY(), end.getPos().getZ());
// :(
}
}
} catch (final GridAccessException e) {
AELog.debug(e);
}
}
}
@Override
public IPartModel getStaticModels() {
return MODELS.getModel(this.isPowered(), this.isActive());
}
}
@@ -0,0 +1,74 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.parts.p2p;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.util.Identifier;
import appeng.api.parts.IPartModel;
import appeng.core.AppEng;
import appeng.parts.PartModel;
/**
* Helper for maintaining the models used for a variant of the P2P bus.
*/
class P2PModels {
public static final Identifier MODEL_STATUS_OFF = new Identifier(AppEng.MOD_ID,
"part/p2p/p2p_tunnel_status_off");
public static final Identifier MODEL_STATUS_ON = new Identifier(AppEng.MOD_ID,
"part/p2p/p2p_tunnel_status_on");
public static final Identifier MODEL_STATUS_HAS_CHANNEL = new Identifier(AppEng.MOD_ID,
"part/p2p/p2p_tunnel_status_has_channel");
public static final Identifier MODEL_FREQUENCY = new Identifier(AppEng.MOD_ID,
"part/p2p/p2p_tunnel_frequency");
private final IPartModel modelsOff;
private final IPartModel modelsOn;
private final IPartModel modelsHasChannel;
public P2PModels(String frontModelPath) {
Identifier frontModel = new Identifier(AppEng.MOD_ID, frontModelPath);
this.modelsOff = new PartModel(MODEL_STATUS_OFF, MODEL_FREQUENCY, frontModel);
this.modelsOn = new PartModel(MODEL_STATUS_ON, MODEL_FREQUENCY, frontModel);
this.modelsHasChannel = new PartModel(MODEL_STATUS_HAS_CHANNEL, MODEL_FREQUENCY, frontModel);
}
public IPartModel getModel(boolean hasPower, boolean hasChannel) {
if (hasPower && hasChannel) {
return this.modelsHasChannel;
} else if (hasPower) {
return this.modelsOn;
} else {
return this.modelsOff;
}
}
public List<IPartModel> getModels() {
List<IPartModel> result = new ArrayList<>();
result.add(this.modelsOff);
result.add(this.modelsOn);
result.add(this.modelsHasChannel);
return result;
}
}
@@ -0,0 +1,382 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.parts.p2p;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Optional;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.util.Hand;
import net.minecraft.util.math.Vec3d;
import appeng.api.AEApi;
import appeng.api.config.Actionable;
import appeng.api.config.PowerMultiplier;
import appeng.api.config.PowerUnits;
import appeng.api.config.TunnelType;
import appeng.api.definitions.IParts;
import appeng.api.implementations.items.IMemoryCard;
import appeng.api.implementations.items.MemoryCardMessages;
import appeng.api.parts.IPart;
import appeng.api.parts.IPartCollisionHelper;
import appeng.api.parts.IPartItem;
import appeng.api.parts.PartItemStack;
import appeng.api.util.AECableType;
import appeng.api.util.AEColor;
import appeng.api.util.AEPartLocation;
import appeng.core.AEConfig;
import appeng.me.GridAccessException;
import appeng.me.cache.P2PCache;
import appeng.me.cache.helpers.TunnelCollection;
import appeng.parts.BasicStatePart;
import appeng.util.Platform;
public abstract class P2PTunnelPart<T extends P2PTunnelPart> extends BasicStatePart {
private final TunnelCollection type = new TunnelCollection<T>(null, this.getClass());
private boolean output;
private short freq;
public P2PTunnelPart(final ItemStack is) {
super(is);
}
public TunnelCollection<T> getCollection(final Collection<P2PTunnelPart> collection,
final Class<? extends P2PTunnelPart> c) {
if (this.type.matches(c)) {
this.type.setSource(collection);
return this.type;
}
return null;
}
public T getInput() {
if (this.getFrequency() == 0) {
return null;
}
try {
final P2PTunnelPart tunnel = this.getProxy().getP2P().getInput(this.getFrequency());
if (this.getClass().isInstance(tunnel)) {
return (T) tunnel;
}
} catch (final GridAccessException e) {
// :P
}
return null;
}
public TunnelCollection<T> getOutputs() throws GridAccessException {
if (this.getProxy().isActive()) {
return (TunnelCollection<T>) this.getProxy().getP2P().getOutputs(this.getFrequency(), this.getClass());
}
return new TunnelCollection(new ArrayList(), this.getClass());
}
@Override
public void getBoxes(final IPartCollisionHelper bch) {
bch.addBox(5, 5, 12, 11, 11, 13);
bch.addBox(3, 3, 13, 13, 13, 14);
bch.addBox(2, 2, 14, 14, 14, 16);
}
@Override
public ItemStack getItemStack(final PartItemStack type) {
if (type == PartItemStack.WORLD || type == PartItemStack.NETWORK || type == PartItemStack.WRENCH
|| type == PartItemStack.PICK) {
return super.getItemStack(type);
}
final Optional<ItemStack> maybeMEStack = AEApi.instance().definitions().parts().p2PTunnelME().maybeStack(1);
if (maybeMEStack.isPresent()) {
return maybeMEStack.get();
}
return super.getItemStack(type);
}
@Override
public void readFromNBT(final CompoundTag data) {
super.readFromNBT(data);
this.setOutput(data.getBoolean("output"));
this.freq = data.getShort("freq");
}
@Override
public void writeToNBT(final CompoundTag data) {
super.writeToNBT(data);
data.putBoolean("output", this.isOutput());
data.putShort("freq", this.getFrequency());
}
@Override
public boolean readFromStream(PacketByteBuf data) throws IOException {
final boolean c = super.readFromStream(data);
final short oldf = this.freq;
this.freq = data.readShort();
return c || oldf != this.freq;
}
@Override
public void writeToStream(PacketByteBuf data) throws IOException {
super.writeToStream(data);
data.writeShort(this.getFrequency());
}
@Override
public float getCableConnectionLength(AECableType cable) {
return 1;
}
@Override
public boolean useStandardMemoryCard() {
return false;
}
@Override
public boolean onPartActivate(final PlayerEntity player, final Hand hand, final Vec3d pos) {
if (Platform.isClient()) {
return true;
}
if (hand == Hand.OFF_HAND) {
return false;
}
final ItemStack is = player.getStackInHand(hand);
final TunnelType tt = AEApi.instance().registries().p2pTunnel().getTunnelTypeByItem(is);
if (!is.isEmpty() && is.getItem() instanceof IMemoryCard) {
final IMemoryCard mc = (IMemoryCard) is.getItem();
final CompoundTag data = mc.getData(is);
final ItemStack newType = ItemStack.fromTag(data);
final short freq = data.getShort("freq");
if (!newType.isEmpty()) {
if (newType.getItem() instanceof IPartItem) {
final IPart testPart = ((IPartItem<?>) newType.getItem()).createPart(newType);
if (testPart instanceof P2PTunnelPart) {
this.getHost().removePart(this.getSide(), true);
final AEPartLocation dir = this.getHost().addPart(newType, this.getSide(), player, hand);
final IPart newBus = this.getHost().getPart(dir);
if (newBus instanceof P2PTunnelPart) {
final P2PTunnelPart<?> newTunnel = (P2PTunnelPart<?>) newBus;
newTunnel.setOutput(true);
try {
final P2PCache p2p = newTunnel.getProxy().getP2P();
p2p.updateFreq(newTunnel, freq);
} catch (final GridAccessException e) {
// :P
}
newTunnel.onTunnelNetworkChange();
}
mc.notifyUser(player, MemoryCardMessages.SETTINGS_LOADED);
return true;
}
}
}
mc.notifyUser(player, MemoryCardMessages.INVALID_MACHINE);
} else if (tt != null) // attunement
{
final ItemStack newType;
final IParts parts = AEApi.instance().definitions().parts();
switch (tt) {
case LIGHT:
newType = parts.p2PTunnelLight().maybeStack(1).orElse(ItemStack.EMPTY);
break;
case FE_POWER:
newType = parts.p2PTunnelFE().maybeStack(1).orElse(ItemStack.EMPTY);
break;
case FLUID:
newType = parts.p2PTunnelFluids().maybeStack(1).orElse(ItemStack.EMPTY);
break;
case IC2_POWER:
newType = parts.p2PTunnelEU().maybeStack(1).orElse(ItemStack.EMPTY);
break;
case ITEM:
newType = parts.p2PTunnelItems().maybeStack(1).orElse(ItemStack.EMPTY);
break;
case ME:
newType = parts.p2PTunnelME().maybeStack(1).orElse(ItemStack.EMPTY);
break;
case REDSTONE:
newType = parts.p2PTunnelRedstone().maybeStack(1).orElse(ItemStack.EMPTY);
break;
/*
* case COMPUTER_MESSAGE: for( ItemStack stack :
* parts.p2PTunnelOpenComputers().maybeStack( 1 ).asSet() ) { newType = stack; }
* break;
*/
default:
newType = ItemStack.EMPTY;
break;
}
if (!newType.isEmpty() && !ItemStack.areItemsEqual(newType, this.getItemStack())) {
final boolean oldOutput = this.isOutput();
final short myFreq = this.getFrequency();
this.getHost().removePart(this.getSide(), false);
final AEPartLocation dir = this.getHost().addPart(newType, this.getSide(), player, hand);
final IPart newBus = this.getHost().getPart(dir);
if (newBus instanceof P2PTunnelPart) {
final P2PTunnelPart newTunnel = (P2PTunnelPart) newBus;
newTunnel.setOutput(oldOutput);
newTunnel.onTunnelNetworkChange();
try {
final P2PCache p2p = newTunnel.getProxy().getP2P();
p2p.updateFreq(newTunnel, myFreq);
} catch (final GridAccessException e) {
// :P
}
}
Platform.notifyBlocksOfNeighbors(this.getTile().getWorld(), this.getTile().getPos());
return true;
}
}
return false;
}
@Override
public boolean onPartShiftActivate(final PlayerEntity player, final Hand hand, final Vec3d pos) {
final ItemStack is = player.inventory.getMainHandStack();
if (!is.isEmpty() && is.getItem() instanceof IMemoryCard) {
if (Platform.isClient()) {
return true;
}
final IMemoryCard mc = (IMemoryCard) is.getItem();
final CompoundTag data = mc.getData(is);
final short storedFrequency = data.getShort("freq");
short newFreq = this.getFrequency();
final boolean wasOutput = this.isOutput();
this.setOutput(false);
final boolean needsNewFrequency = wasOutput || this.getFrequency() == 0 || storedFrequency == newFreq;
try {
if (needsNewFrequency) {
newFreq = this.getProxy().getP2P().newFrequency();
}
this.getProxy().getP2P().updateFreq(this, newFreq);
} catch (final GridAccessException e) {
// :P
}
this.onTunnelConfigChange();
final ItemStack p2pItem = this.getItemStack(PartItemStack.WRENCH);
final String type = p2pItem.getTranslationKey();
p2pItem.toTag(data);
data.putShort("freq", this.getFrequency());
final AEColor[] colors = Platform.p2p().toColors(this.getFrequency());
final int[] colorCode = new int[] { colors[0].ordinal(), colors[0].ordinal(), colors[1].ordinal(),
colors[1].ordinal(), colors[2].ordinal(), colors[2].ordinal(), colors[3].ordinal(),
colors[3].ordinal(), };
data.putIntArray("colorCode", colorCode);
mc.setMemoryCardContents(is, type + ".name", data);
if (needsNewFrequency) {
mc.notifyUser(player, MemoryCardMessages.SETTINGS_RESET);
} else {
mc.notifyUser(player, MemoryCardMessages.SETTINGS_SAVED);
}
return true;
}
return false;
}
public void onTunnelConfigChange() {
}
public void onTunnelNetworkChange() {
}
protected void queueTunnelDrain(final PowerUnits unit, final double f) {
final double ae_to_tax = unit.convertTo(PowerUnits.AE, f * AEConfig.TUNNEL_POWER_LOSS);
try {
this.getProxy().getEnergy().extractAEPower(ae_to_tax, Actionable.MODULATE, PowerMultiplier.ONE);
} catch (final GridAccessException e) {
// :P
}
}
public short getFrequency() {
return this.freq;
}
public void setFrequency(final short freq) {
final short oldf = this.freq;
this.freq = freq;
if (oldf != this.freq) {
this.getHost().markForUpdate();
}
}
public boolean isOutput() {
return this.output;
}
void setOutput(final boolean output) {
this.output = output;
}
@Override
public Object getModelData() {
long ret = Short.toUnsignedLong(this.getFrequency());
if (this.isActive() && this.isPowered()) {
ret |= 0x10000L;
}
return ret;
}
}
@@ -0,0 +1,65 @@
/*
* 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.parts.reporting;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import appeng.core.AppEng;
import appeng.items.parts.PartModels;
/**
* A more sophisticated part overlapping all 3 textures.
*
* Subclass this if you need want a new part and need all 3 textures. For more
* concrete implementations, the direct abstract subclasses might be a better
* alternative.
*
* @author AlgorithmX2
* @author yueh
* @version rv3
* @since rv3
*/
public abstract class AbstractDisplayPart extends AbstractReportingPart {
// The base chassis of all display parts
@PartModels
protected static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "part/display_base");
// Models that contain the status indicator light
@PartModels
protected static final Identifier MODEL_STATUS_OFF = new Identifier(AppEng.MOD_ID,
"part/display_status_off");
@PartModels
protected static final Identifier MODEL_STATUS_ON = new Identifier(AppEng.MOD_ID,
"part/display_status_on");
@PartModels
protected static final Identifier MODEL_STATUS_HAS_CHANNEL = new Identifier(AppEng.MOD_ID,
"part/display_status_has_channel");
public AbstractDisplayPart(final ItemStack is) {
super(is, true);
}
@Override
public boolean isLightSource() {
return false;
}
}
@@ -0,0 +1,321 @@
/*
* 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.parts.reporting;
import java.io.IOException;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.util.Util;
import net.minecraft.util.math.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.Vec3d;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import appeng.api.AEApi;
import appeng.api.implementations.parts.IStorageMonitorPart;
import appeng.api.networking.security.IActionSource;
import appeng.api.networking.storage.IStackWatcher;
import appeng.api.networking.storage.IStackWatcherHost;
import appeng.api.parts.IPartModel;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.IStorageChannel;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IAEStack;
import appeng.api.storage.data.IItemList;
import appeng.client.render.TesrRenderHelper;
import appeng.core.localization.PlayerMessages;
import appeng.me.GridAccessException;
import appeng.util.IWideReadableNumberConverter;
import appeng.util.Platform;
import appeng.util.ReadableNumberConverter;
import appeng.util.item.AEItemStack;
/**
* A basic subclass for any item monitor like display with an item icon and an
* amount.
*
* It can also be used to extract items from somewhere and spawned into the
* world.
*
* @author AlgorithmX2
* @author thatsIch
* @author yueh
* @version rv3
* @since rv3
*/
public abstract class AbstractMonitorPart extends AbstractDisplayPart
implements IStorageMonitorPart, IStackWatcherHost {
private static final IWideReadableNumberConverter NUMBER_CONVERTER = ReadableNumberConverter.INSTANCE;
private IAEItemStack configuredItem;
private String lastHumanReadableText;
private boolean isLocked;
private IStackWatcher myWatcher;
public AbstractMonitorPart(final ItemStack is) {
super(is);
}
@Override
public void readFromNBT(final CompoundTag data) {
super.readFromNBT(data);
this.isLocked = data.getBoolean("isLocked");
final CompoundTag myItem = data.getCompound("configuredItem");
this.configuredItem = AEItemStack.fromNBT(myItem);
}
@Override
public void writeToNBT(final CompoundTag data) {
super.writeToNBT(data);
data.putBoolean("isLocked", this.isLocked);
final CompoundTag myItem = new CompoundTag();
if (this.configuredItem != null) {
this.configuredItem.writeToNBT(myItem);
}
data.put("configuredItem", myItem);
}
@Override
public void writeToStream(final PacketByteBuf data) throws IOException {
super.writeToStream(data);
data.writeBoolean(this.isLocked);
data.writeBoolean(this.configuredItem != null);
if (this.configuredItem != null) {
this.configuredItem.writeToPacket(data);
}
}
@Override
public boolean readFromStream(final PacketByteBuf data) throws IOException {
boolean needRedraw = super.readFromStream(data);
final boolean isLocked = data.readBoolean();
needRedraw = this.isLocked != isLocked;
this.isLocked = isLocked;
final boolean val = data.readBoolean();
if (val) {
this.configuredItem = AEItemStack.fromPacket(data);
} else {
this.configuredItem = null;
}
return needRedraw;
}
@Override
public boolean onPartActivate(final PlayerEntity player, final Hand hand, final Vec3d pos) {
if (Platform.isClient()) {
return true;
}
if (!this.getProxy().isActive()) {
return false;
}
if (!Platform.hasPermissions(this.getLocation(), player)) {
return false;
}
if (!this.isLocked) {
final ItemStack eq = player.getStackInHand(hand);
this.configuredItem = AEItemStack.fromItemStack(eq);
this.configureWatchers();
this.getHost().markForSave();
this.getHost().markForUpdate();
} else {
return super.onPartActivate(player, hand, pos);
}
return true;
}
@Override
public boolean onPartShiftActivate(PlayerEntity player, Hand hand, Vec3d pos) {
if (Platform.isClient()) {
return true;
}
if (!this.getProxy().isActive()) {
return false;
}
if (!Platform.hasPermissions(this.getLocation(), player)) {
return false;
}
if (player.getStackInHand(hand).isEmpty()) {
this.isLocked = !this.isLocked;
player.sendSystemMessage((this.isLocked ? PlayerMessages.isNowLocked : PlayerMessages.isNowUnlocked).get(), Util.NIL_UUID);
this.getHost().markForSave();
this.getHost().markForUpdate();
}
return true;
}
// update the system...
private void configureWatchers() {
if (this.myWatcher != null) {
this.myWatcher.reset();
}
try {
if (this.configuredItem != null) {
if (this.myWatcher != null) {
this.myWatcher.add(this.configuredItem);
}
this.updateReportingValue(this.getProxy().getStorage()
.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class)));
}
} catch (final GridAccessException e) {
// >.>
}
}
private void updateReportingValue(final IMEMonitor<IAEItemStack> itemInventory) {
if (this.configuredItem != null) {
final IAEItemStack result = itemInventory.getStorageList().findPrecise(this.configuredItem);
if (result == null) {
this.configuredItem.setStackSize(0);
} else {
this.configuredItem.setStackSize(result.getStackSize());
}
}
}
@Override
@Environment(EnvType.CLIENT)
public void renderDynamic(float partialTicks, MatrixStack matrixStack, VertexConsumerProvider buffers,
int combinedLightIn, int combinedOverlayIn) {
if ((this.getClientFlags() & (PanelPart.POWERED_FLAG | PanelPart.CHANNEL_FLAG)) != (PanelPart.POWERED_FLAG
| PanelPart.CHANNEL_FLAG)) {
return;
}
final IAEItemStack ais = this.getDisplayed();
if (ais == null) {
return;
}
matrixStack.push();
matrixStack.translate(0.5, 0.5, 0.5); // Move into the center of the block
Direction facing = this.getSide().getFacing();
TesrRenderHelper.rotateToFace(matrixStack, facing, this.getSpin());
matrixStack.translate(0, 0.05, 0.5);
TesrRenderHelper.renderItem2dWithAmount(matrixStack, buffers, ais, 0.4f, -0.23f, 15728880, combinedOverlayIn);
matrixStack.pop();
}
@Override
public boolean requireDynamicRender() {
return true;
}
@Override
public IAEItemStack getDisplayed() {
return this.configuredItem;
}
@Override
public boolean isLocked() {
return this.isLocked;
}
@Override
public void updateWatcher(final IStackWatcher newWatcher) {
this.myWatcher = newWatcher;
this.configureWatchers();
}
@Override
public void onStackChange(final IItemList o, final IAEStack fullStack, final IAEStack diffStack,
final IActionSource src, final IStorageChannel chan) {
if (this.configuredItem != null) {
if (fullStack == null) {
this.configuredItem.setStackSize(0);
} else {
this.configuredItem.setStackSize(fullStack.getStackSize());
}
final long stackSize = this.configuredItem.getStackSize();
final String humanReadableText = NUMBER_CONVERTER.toWideReadableForm(stackSize);
if (!humanReadableText.equals(this.lastHumanReadableText)) {
this.lastHumanReadableText = humanReadableText;
this.getHost().markForUpdate();
}
}
}
@Override
public boolean showNetworkInfo(final HitResult where) {
return false;
}
protected IPartModel selectModel(IPartModel off, IPartModel on, IPartModel hasChannel, IPartModel lockedOff,
IPartModel lockedOn, IPartModel lockedHasChannel) {
if (this.isActive()) {
if (this.isLocked()) {
return lockedHasChannel;
} else {
return hasChannel;
}
} else if (this.isPowered()) {
if (this.isLocked()) {
return lockedOn;
} else {
return on;
}
} else {
if (this.isLocked()) {
return lockedOff;
} else {
return off;
}
}
}
}
@@ -0,0 +1,145 @@
/*
* 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.parts.reporting;
import java.util.List;
import alexiil.mc.lib.attributes.item.FixedItemInv;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.Hand;
import net.minecraft.util.math.Vec3d;
import appeng.api.config.Settings;
import appeng.api.config.SortDir;
import appeng.api.config.SortOrder;
import appeng.api.config.ViewItems;
import appeng.api.implementations.tiles.IViewCellStorage;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.IStorageChannel;
import appeng.api.storage.ITerminalHost;
import appeng.api.storage.data.IAEStack;
import appeng.api.util.IConfigManager;
import appeng.container.ContainerLocator;
import appeng.container.ContainerOpener;
import appeng.container.implementations.MEMonitorableContainer;
import appeng.me.GridAccessException;
import appeng.tile.inventory.AppEngInternalInventory;
import appeng.util.ConfigManager;
import appeng.util.IConfigManagerHost;
import appeng.util.inv.IAEAppEngInventory;
import appeng.util.inv.InvOperation;
/**
* Anything resembling an network terminal with view cells can reuse this.
*
* Note this applies only to terminals like the ME Terminal. It does not apply
* for more specialized terminals like the Interface Terminal.
*
* @author AlgorithmX2
* @author yueh
* @version rv3
* @since rv3
*/
public abstract class AbstractTerminalPart extends AbstractDisplayPart
implements ITerminalHost, IConfigManagerHost, IViewCellStorage, IAEAppEngInventory {
private final IConfigManager cm = new ConfigManager(this);
private final AppEngInternalInventory viewCell = new AppEngInternalInventory(this, 5);
public AbstractTerminalPart(final ItemStack is) {
super(is);
this.cm.registerSetting(Settings.SORT_BY, SortOrder.NAME);
this.cm.registerSetting(Settings.VIEW_MODE, ViewItems.ALL);
this.cm.registerSetting(Settings.SORT_DIRECTION, SortDir.ASCENDING);
}
@Override
public void getDrops(final List<ItemStack> drops, final boolean wrenched) {
super.getDrops(drops, wrenched);
for (final ItemStack is : this.viewCell) {
if (!is.isEmpty()) {
drops.add(is);
}
}
}
@Override
public IConfigManager getConfigManager() {
return this.cm;
}
@Override
public void readFromNBT(final CompoundTag data) {
super.readFromNBT(data);
this.cm.readFromNBT(data);
this.viewCell.readFromNBT(data, "viewCell");
}
@Override
public void writeToNBT(final CompoundTag data) {
super.writeToNBT(data);
this.cm.writeToNBT(data);
this.viewCell.writeToNBT(data, "viewCell");
}
@Override
public boolean onPartActivate(final PlayerEntity player, final Hand hand, final Vec3d pos) {
if (!super.onPartActivate(player, hand, pos)) {
if (!player.world.isClient) {
ContainerOpener.openContainer(getContainerType(player), player, ContainerLocator.forPart(this));
}
}
return true;
}
public ScreenHandlerType<?> getContainerType(final PlayerEntity player) {
return MEMonitorableContainer.TYPE;
}
@Override
public <T extends IAEStack<T>> IMEMonitor<T> getInventory(IStorageChannel<T> channel) {
try {
return this.getProxy().getStorage().getInventory(channel);
} catch (final GridAccessException e) {
// err nope?
}
return null;
}
@Override
public void updateSetting(final IConfigManager manager, final Settings settingName, final Enum<?> newValue) {
}
@Override
public FixedItemInv getViewCellStorage() {
return this.viewCell;
}
@Override
public void onChangeInventory(final FixedItemInv inv, final int slot, final InvOperation mc,
final ItemStack removedStack, final ItemStack newStack) {
this.getHost().markForSave();
}
}
@@ -0,0 +1,231 @@
/*
* 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.parts.reporting;
import java.util.Collections;
import java.util.List;
import alexiil.mc.lib.attributes.Simulation;
import alexiil.mc.lib.attributes.item.SingleItemSlot;
import alexiil.mc.lib.attributes.item.compat.FixedInventoryVanillaWrapper;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Vec3d;
import alexiil.mc.lib.attributes.item.FixedItemInv;
import appeng.api.AEApi;
import appeng.api.networking.energy.IEnergySource;
import appeng.api.parts.IPartModel;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack;
import appeng.core.AppEng;
import appeng.items.parts.PartModels;
import appeng.me.GridAccessException;
import appeng.me.helpers.PlayerSource;
import appeng.parts.PartModel;
import appeng.util.InventoryAdaptor;
import appeng.util.Platform;
import appeng.util.item.AEItemStack;
public class ConversionMonitorPart extends AbstractMonitorPart {
@PartModels
public static final Identifier MODEL_OFF = new Identifier(AppEng.MOD_ID, "part/conversion_monitor_off");
@PartModels
public static final Identifier MODEL_ON = new Identifier(AppEng.MOD_ID, "part/conversion_monitor_on");
@PartModels
public static final Identifier MODEL_LOCKED_OFF = new Identifier(AppEng.MOD_ID,
"part/conversion_monitor_locked_off");
@PartModels
public static final Identifier MODEL_LOCKED_ON = new Identifier(AppEng.MOD_ID,
"part/conversion_monitor_locked_on");
public static final IPartModel MODELS_OFF = new PartModel(MODEL_BASE, MODEL_OFF, MODEL_STATUS_OFF);
public static final IPartModel MODELS_ON = new PartModel(MODEL_BASE, MODEL_ON, MODEL_STATUS_ON);
public static final IPartModel MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE, MODEL_ON, MODEL_STATUS_HAS_CHANNEL);
public static final IPartModel MODELS_LOCKED_OFF = new PartModel(MODEL_BASE, MODEL_LOCKED_OFF, MODEL_STATUS_OFF);
public static final IPartModel MODELS_LOCKED_ON = new PartModel(MODEL_BASE, MODEL_LOCKED_ON, MODEL_STATUS_ON);
public static final IPartModel MODELS_LOCKED_HAS_CHANNEL = new PartModel(MODEL_BASE, MODEL_LOCKED_ON,
MODEL_STATUS_HAS_CHANNEL);
public ConversionMonitorPart(final ItemStack is) {
super(is);
}
@Override
public boolean onPartActivate(PlayerEntity player, Hand hand, Vec3d pos) {
if (Platform.isClient()) {
return true;
}
if (!this.getProxy().isActive()) {
return false;
}
if (!Platform.hasPermissions(this.getLocation(), player)) {
return false;
}
final ItemStack eq = player.getStackInHand(hand);
if (this.isLocked()) {
if (eq.isEmpty()) {
this.insertItem(player, hand, true);
} else if (Platform.isWrench(player, eq, this.getLocation().getPos())
&& (this.getDisplayed() == null || !this.getDisplayed().equals(eq))) {
// wrench it
return super.onPartActivate(player, hand, pos);
} else {
this.insertItem(player, hand, false);
}
} else if (this.getDisplayed() != null && this.getDisplayed().equals(eq)) {
this.insertItem(player, hand, false);
} else {
return super.onPartActivate(player, hand, pos);
}
return true;
}
@Override
public boolean onClicked(PlayerEntity player, Hand hand, Vec3d pos) {
if (Platform.isClient()) {
return true;
}
if (!this.getProxy().isActive()) {
return false;
}
if (!Platform.hasPermissions(this.getLocation(), player)) {
return false;
}
if (this.getDisplayed() != null) {
this.extractItem(player, this.getDisplayed().getDefinition().getMaxCount());
}
return true;
}
@Override
public boolean onShiftClicked(PlayerEntity player, Hand hand, Vec3d pos) {
if (Platform.isClient()) {
return true;
}
if (!this.getProxy().isActive()) {
return false;
}
if (!Platform.hasPermissions(this.getLocation(), player)) {
return false;
}
if (this.getDisplayed() != null) {
this.extractItem(player, 1);
}
return true;
}
private void insertItem(final PlayerEntity player, final Hand hand, final boolean allItems) {
try {
final IEnergySource energy = this.getProxy().getEnergy();
final IMEMonitor<IAEItemStack> cell = this.getProxy().getStorage()
.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class));
if (allItems) {
if (this.getDisplayed() != null) {
final IAEItemStack input = this.getDisplayed().copy();
FixedItemInv inv = new FixedInventoryVanillaWrapper(player.inventory);
for (int x = 0; x < inv.getSlotCount(); x++) {
final ItemStack targetStack = inv.getInvStack(x);
if (input.equals(targetStack)) {
SingleItemSlot slot = inv.getSlot(x);
final ItemStack canExtract = slot.attemptAnyExtraction(targetStack.getCount(), Simulation.SIMULATE);
if (!canExtract.isEmpty()) {
input.setStackSize(canExtract.getCount());
final IAEItemStack failedToInsert = Platform.poweredInsert(energy, cell, input,
new PlayerSource(player, this));
slot.extract(failedToInsert == null ? canExtract.getCount()
: canExtract.getCount() - (int) failedToInsert.getStackSize());
}
}
}
}
} else {
final IAEItemStack input = AEItemStack.fromItemStack(player.getStackInHand(hand));
final IAEItemStack failedToInsert = Platform.poweredInsert(energy, cell, input,
new PlayerSource(player, this));
player.setStackInHand(hand, failedToInsert == null ? ItemStack.EMPTY : failedToInsert.createItemStack());
}
} catch (final GridAccessException e) {
// :P
}
}
private void extractItem(final PlayerEntity player, int count) {
final IAEItemStack input = this.getDisplayed();
if (input != null) {
try {
if (!this.getProxy().isActive()) {
return;
}
final IEnergySource energy = this.getProxy().getEnergy();
final IMEMonitor<IAEItemStack> cell = this.getProxy().getStorage()
.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class));
input.setStackSize(count);
final IAEItemStack retrieved = Platform.poweredExtraction(energy, cell, input,
new PlayerSource(player, this));
if (retrieved != null) {
ItemStack newItems = retrieved.createItemStack();
final InventoryAdaptor adaptor = InventoryAdaptor.getAdaptor(player);
newItems = adaptor.addItems(newItems);
if (!newItems.isEmpty()) {
final BlockEntity te = this.getTile();
final List<ItemStack> list = Collections.singletonList(newItems);
Platform.spawnDrops(player.world, te.getPos().offset(this.getSide().getFacing()), list);
}
if (player.currentScreenHandler != null) {
player.currentScreenHandler.sendContentUpdates();
}
}
} catch (final GridAccessException e) {
// :P
}
}
}
@Override
public IPartModel getStaticModels() {
return this.selectModel(MODELS_OFF, MODELS_ON, MODELS_HAS_CHANNEL, MODELS_LOCKED_OFF, MODELS_LOCKED_ON,
MODELS_LOCKED_HAS_CHANNEL);
}
}
@@ -0,0 +1,101 @@
/*
* 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.parts.reporting;
import java.util.List;
import alexiil.mc.lib.attributes.item.FixedItemInv;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.Identifier;
import appeng.api.config.SecurityPermissions;
import appeng.api.parts.IPartModel;
import appeng.container.implementations.CraftingTermContainer;
import appeng.container.implementations.MEMonitorableContainer;
import appeng.core.AppEng;
import appeng.items.parts.PartModels;
import appeng.parts.PartModel;
import appeng.tile.inventory.AppEngInternalInventory;
import appeng.util.Platform;
public class CraftingTerminalPart extends AbstractTerminalPart {
@PartModels
public static final Identifier MODEL_OFF = new Identifier(AppEng.MOD_ID, "part/crafting_terminal_off");
@PartModels
public static final Identifier MODEL_ON = new Identifier(AppEng.MOD_ID, "part/crafting_terminal_on");
public static final IPartModel MODELS_OFF = new PartModel(MODEL_BASE, MODEL_OFF, MODEL_STATUS_OFF);
public static final IPartModel MODELS_ON = new PartModel(MODEL_BASE, MODEL_ON, MODEL_STATUS_ON);
public static final IPartModel MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE, MODEL_ON, MODEL_STATUS_HAS_CHANNEL);
private final AppEngInternalInventory craftingGrid = new AppEngInternalInventory(this, 9);
public CraftingTerminalPart(final ItemStack is) {
super(is);
}
@Override
public void getDrops(final List<ItemStack> drops, final boolean wrenched) {
super.getDrops(drops, wrenched);
for (final ItemStack is : this.craftingGrid) {
if (!is.isEmpty()) {
drops.add(is);
}
}
}
@Override
public void readFromNBT(final CompoundTag data) {
super.readFromNBT(data);
this.craftingGrid.readFromNBT(data, "craftingGrid");
}
@Override
public void writeToNBT(final CompoundTag data) {
super.writeToNBT(data);
this.craftingGrid.writeToNBT(data, "craftingGrid");
}
@Override
public ScreenHandlerType<?> getContainerType(final PlayerEntity p) {
if (Platform.checkPermissions(p, this, SecurityPermissions.CRAFT, false)) {
return CraftingTermContainer.TYPE;
}
return MEMonitorableContainer.TYPE;
}
@Override
public FixedItemInv getInventoryByName(final String name) {
if (name.equals("crafting")) {
return this.craftingGrid;
}
return super.getInventoryByName(name);
}
@Override
public IPartModel getStaticModels() {
return this.selectModel(MODELS_OFF, MODELS_ON, MODELS_HAS_CHANNEL);
}
}
@@ -0,0 +1,66 @@
/*
* 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.parts.reporting;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Vec3d;
import appeng.api.parts.IPartModel;
import appeng.container.ContainerLocator;
import appeng.container.ContainerOpener;
import appeng.container.implementations.InterfaceTerminalContainer;
import appeng.core.AppEng;
import appeng.items.parts.PartModels;
import appeng.parts.PartModel;
import appeng.util.Platform;
public class InterfaceTerminalPart extends AbstractDisplayPart {
@PartModels
public static final Identifier MODEL_OFF = new Identifier(AppEng.MOD_ID, "part/interface_terminal_off");
@PartModels
public static final Identifier MODEL_ON = new Identifier(AppEng.MOD_ID, "part/interface_terminal_on");
public static final IPartModel MODELS_OFF = new PartModel(MODEL_BASE, MODEL_OFF, MODEL_STATUS_OFF);
public static final IPartModel MODELS_ON = new PartModel(MODEL_BASE, MODEL_ON, MODEL_STATUS_ON);
public static final IPartModel MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE, MODEL_ON, MODEL_STATUS_HAS_CHANNEL);
public InterfaceTerminalPart(final ItemStack is) {
super(is);
}
@Override
public boolean onPartActivate(final PlayerEntity player, final Hand hand, final Vec3d pos) {
if (!super.onPartActivate(player, hand, pos)) {
if (Platform.isServer()) {
ContainerOpener.openContainer(InterfaceTerminalContainer.TYPE, player, ContainerLocator.forPart(this));
}
}
return true;
}
@Override
public IPartModel getStaticModels() {
return this.selectModel(MODELS_OFF, MODELS_ON, MODELS_HAS_CHANNEL);
}
}
@@ -0,0 +1,183 @@
/*
* 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.parts.reporting;
import java.util.List;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.Identifier;
import alexiil.mc.lib.attributes.item.FixedItemInv;
import appeng.api.config.SecurityPermissions;
import appeng.api.implementations.ICraftingPatternItem;
import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.api.parts.IPartModel;
import appeng.api.storage.data.IAEItemStack;
import appeng.container.implementations.MEMonitorableContainer;
import appeng.container.implementations.PatternTermContainer;
import appeng.core.AppEng;
import appeng.items.parts.PartModels;
import appeng.parts.PartModel;
import appeng.tile.inventory.AppEngInternalInventory;
import appeng.util.Platform;
import appeng.util.inv.InvOperation;
public class PatternTerminalPart extends AbstractTerminalPart {
@PartModels
public static final Identifier MODEL_OFF = new Identifier(AppEng.MOD_ID, "part/pattern_terminal_off");
@PartModels
public static final Identifier MODEL_ON = new Identifier(AppEng.MOD_ID, "part/pattern_terminal_on");
public static final IPartModel MODELS_OFF = new PartModel(MODEL_BASE, MODEL_OFF, MODEL_STATUS_OFF);
public static final IPartModel MODELS_ON = new PartModel(MODEL_BASE, MODEL_ON, MODEL_STATUS_ON);
public static final IPartModel MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE, MODEL_ON, MODEL_STATUS_HAS_CHANNEL);
private final AppEngInternalInventory crafting = new AppEngInternalInventory(this, 9);
private final AppEngInternalInventory output = new AppEngInternalInventory(this, 3);
private final AppEngInternalInventory pattern = new AppEngInternalInventory(this, 2);
private boolean craftingMode = true;
private boolean substitute = false;
public PatternTerminalPart(final ItemStack is) {
super(is);
}
@Override
public void getDrops(final List<ItemStack> drops, final boolean wrenched) {
for (final ItemStack is : this.pattern) {
if (!is.isEmpty()) {
drops.add(is);
}
}
}
@Override
public void readFromNBT(final CompoundTag data) {
super.readFromNBT(data);
this.setCraftingRecipe(data.getBoolean("craftingMode"));
this.setSubstitution(data.getBoolean("substitute"));
this.pattern.readFromNBT(data, "pattern");
this.output.readFromNBT(data, "outputList");
this.crafting.readFromNBT(data, "craftingGrid");
}
@Override
public void writeToNBT(final CompoundTag data) {
super.writeToNBT(data);
data.putBoolean("craftingMode", this.craftingMode);
data.putBoolean("substitute", this.substitute);
this.pattern.writeToNBT(data, "pattern");
this.output.writeToNBT(data, "outputList");
this.crafting.writeToNBT(data, "craftingGrid");
}
@Override
public ScreenHandlerType<?> getContainerType(final PlayerEntity p) {
if (Platform.checkPermissions(p, this, SecurityPermissions.CRAFT, false)) {
return PatternTermContainer.TYPE;
}
return MEMonitorableContainer.TYPE;
}
@Override
public void onChangeInventory(final FixedItemInv inv, final int slot, final InvOperation mc,
final ItemStack removedStack, final ItemStack newStack) {
if (inv == this.pattern && slot == 1) {
final ItemStack is = this.pattern.getInvStack(1);
if (!is.isEmpty() && is.getItem() instanceof ICraftingPatternItem) {
final ICraftingPatternItem pattern = (ICraftingPatternItem) is.getItem();
final ICraftingPatternDetails details = pattern.getPatternForItem(is,
this.getHost().getTile().getWorld());
if (details != null) {
this.setCraftingRecipe(details.isCraftable());
this.setSubstitution(details.canSubstitute());
for (int x = 0; x < this.crafting.getSlotCount() && x < details.getInputs().length; x++) {
final IAEItemStack item = details.getInputs()[x];
this.crafting.forceSetInvStack(x, item == null ? ItemStack.EMPTY : item.createItemStack());
}
for (int x = 0; x < this.output.getSlotCount() && x < details.getOutputs().length; x++) {
final IAEItemStack item = details.getOutputs()[x];
this.output.forceSetInvStack(x, item == null ? ItemStack.EMPTY : item.createItemStack());
}
}
}
} else if (inv == this.crafting) {
this.fixCraftingRecipes();
}
this.getHost().markForSave();
}
private void fixCraftingRecipes() {
if (this.craftingMode) {
for (int x = 0; x < this.crafting.getSlotCount(); x++) {
final ItemStack is = this.crafting.getInvStack(x);
if (!is.isEmpty()) {
is.setCount(1);
}
}
}
}
public boolean isCraftingRecipe() {
return this.craftingMode;
}
public void setCraftingRecipe(final boolean craftingMode) {
this.craftingMode = craftingMode;
this.fixCraftingRecipes();
}
public boolean isSubstitution() {
return this.substitute;
}
public void setSubstitution(final boolean canSubstitute) {
this.substitute = canSubstitute;
}
@Override
public FixedItemInv getInventoryByName(final String name) {
if (name.equals("crafting")) {
return this.crafting;
}
if (name.equals("output")) {
return this.output;
}
if (name.equals("pattern")) {
return this.pattern;
}
return super.getInventoryByName(name);
}
@Override
public IPartModel getStaticModels() {
return this.selectModel(MODELS_OFF, MODELS_ON, MODELS_HAS_CHANNEL);
}
}
@@ -0,0 +1,68 @@
/*
* 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.parts.reporting;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import appeng.api.parts.IPartModel;
import appeng.core.AppEng;
import appeng.items.parts.PartModels;
import appeng.parts.PartModel;
/**
* @author AlgorithmX2
* @author thatsIch
* @version rv2
* @since rv0
*/
public class StorageMonitorPart extends AbstractMonitorPart {
@PartModels
public static final Identifier MODEL_OFF = new Identifier(AppEng.MOD_ID, "part/storage_monitor_off");
@PartModels
public static final Identifier MODEL_ON = new Identifier(AppEng.MOD_ID, "part/storage_monitor_on");
@PartModels
public static final Identifier MODEL_LOCKED_OFF = new Identifier(AppEng.MOD_ID,
"part/storage_monitor_locked_off");
@PartModels
public static final Identifier MODEL_LOCKED_ON = new Identifier(AppEng.MOD_ID,
"part/storage_monitor_locked_on");
public static final IPartModel MODELS_OFF = new PartModel(MODEL_BASE, MODEL_OFF, MODEL_STATUS_OFF);
public static final IPartModel MODELS_ON = new PartModel(MODEL_BASE, MODEL_ON, MODEL_STATUS_ON);
public static final IPartModel MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE, MODEL_ON, MODEL_STATUS_HAS_CHANNEL);
public static final IPartModel MODELS_LOCKED_OFF = new PartModel(MODEL_BASE, MODEL_LOCKED_OFF, MODEL_STATUS_OFF);
public static final IPartModel MODELS_LOCKED_ON = new PartModel(MODEL_BASE, MODEL_LOCKED_ON, MODEL_STATUS_ON);
public static final IPartModel MODELS_LOCKED_HAS_CHANNEL = new PartModel(MODEL_BASE, MODEL_LOCKED_ON,
MODEL_STATUS_HAS_CHANNEL);
public StorageMonitorPart(final ItemStack is) {
super(is);
}
@Override
public IPartModel getStaticModels() {
return this.selectModel(MODELS_OFF, MODELS_ON, MODELS_HAS_CHANNEL, MODELS_LOCKED_OFF, MODELS_LOCKED_ON,
MODELS_LOCKED_HAS_CHANNEL);
}
}
@@ -0,0 +1,48 @@
/*
* 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.parts.reporting;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import appeng.api.parts.IPartModel;
import appeng.core.AppEng;
import appeng.items.parts.PartModels;
import appeng.parts.PartModel;
public class TerminalPart extends AbstractTerminalPart {
@PartModels
public static final Identifier MODEL_OFF = new Identifier(AppEng.MOD_ID, "part/terminal_off");
@PartModels
public static final Identifier MODEL_ON = new Identifier(AppEng.MOD_ID, "part/terminal_on");
public static final IPartModel MODELS_OFF = new PartModel(MODEL_BASE, MODEL_OFF, MODEL_STATUS_OFF);
public static final IPartModel MODELS_ON = new PartModel(MODEL_BASE, MODEL_ON, MODEL_STATUS_ON);
public static final IPartModel MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE, MODEL_ON, MODEL_STATUS_HAS_CHANNEL);
public TerminalPart(final ItemStack is) {
super(is);
}
@Override
public IPartModel getStaticModels() {
return this.selectModel(MODELS_OFF, MODELS_ON, MODELS_HAS_CHANNEL);
}
}