Moved more parts of ME over
This commit is contained in:
@@ -134,24 +134,6 @@ public class ClientHelper extends ServerHelper {
|
||||
return this.renderModeForPlayer(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triggerUpdates() {
|
||||
final MinecraftClient mc = MinecraftClient.getInstance();
|
||||
if (mc.player == null || mc.world == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final PlayerEntity player = mc.player;
|
||||
|
||||
final int x = (int) player.getX();
|
||||
final int y = (int) player.getY();
|
||||
final int z = (int) player.getZ();
|
||||
|
||||
final int range = 16 * 16;
|
||||
|
||||
mc.worldRenderer.markBlockRangeForRenderUpdate(x - range, y - range, z - range, x + range, y + range,
|
||||
z + range);
|
||||
}
|
||||
|
||||
private void postPlayerRender(final RenderLivingEvent.Pre p) {
|
||||
// FIXME final PlayerColor player = TickHandler.INSTANCE.getPlayerColors().get( p.getEntity().getEntityId() );
|
||||
|
||||
@@ -1,235 +0,0 @@
|
||||
/*
|
||||
* 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.container;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.ItemUsageContext;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import appeng.api.parts.IPartHost;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.api.util.DimensionalCoord;
|
||||
import appeng.parts.AEBasePart;
|
||||
|
||||
/**
|
||||
* Describes how a container the player has opened was originally located. This
|
||||
* can be one of three ways:
|
||||
*
|
||||
* <ul>
|
||||
* <li>A block entity at a given block position.</li>
|
||||
* <li>A part (i.e. cable bus part) at the side of a given block position.</li>
|
||||
* <li>An item held by the player.</li>
|
||||
* </ul>
|
||||
*/
|
||||
public final class ContainerLocator {
|
||||
|
||||
private enum Type {
|
||||
/**
|
||||
* An item used from the player's inventory.
|
||||
*/
|
||||
PLAYER_INVENTORY,
|
||||
/**
|
||||
* An item used from the player's inventory, but right-clicked on a block face,
|
||||
* has block position and side in addition to the above.
|
||||
*/
|
||||
PLAYER_INVENTORY_WITH_BLOCK_CONTEXT, BLOCK, PART
|
||||
}
|
||||
|
||||
private final Type type;
|
||||
private final int itemIndex;
|
||||
private final int dimensionId;
|
||||
private final BlockPos blockPos;
|
||||
private final AEPartLocation side;
|
||||
|
||||
private ContainerLocator(Type type, int itemIndex, int dimensionId, BlockPos blockPos, AEPartLocation side) {
|
||||
this.type = type;
|
||||
this.itemIndex = itemIndex;
|
||||
this.dimensionId = dimensionId;
|
||||
this.blockPos = blockPos;
|
||||
this.side = side;
|
||||
}
|
||||
|
||||
public static ContainerLocator forTileEntity(BlockEntity te) {
|
||||
if (te.getWorld() == null) {
|
||||
throw new IllegalArgumentException("Cannot open a block entity that is not in a world");
|
||||
}
|
||||
int dimensionId = te.getWorld().getDimension().getType().getId();
|
||||
return new ContainerLocator(Type.BLOCK, -1, dimensionId, te.getPos(), null);
|
||||
}
|
||||
|
||||
public static ContainerLocator forTileEntitySide(BlockEntity te, Direction side) {
|
||||
if (te.getWorld() == null) {
|
||||
throw new IllegalArgumentException("Cannot open a block entity that is not in a world");
|
||||
}
|
||||
int dimensionId = te.getWorld().getDimension().getType().getId();
|
||||
return new ContainerLocator(Type.PART, -1, dimensionId, te.getPos(), AEPartLocation.fromFacing(side));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a container locator for an item being used on a block. The item
|
||||
* could still open a container for itself, but it might also open a special
|
||||
* container for the block being right-clicked.
|
||||
*/
|
||||
public static ContainerLocator forItemUseContext(ItemUsageContext context) {
|
||||
PlayerEntity player = context.getPlayer();
|
||||
if (player == null) {
|
||||
throw new IllegalArgumentException("Cannot open a container without a player");
|
||||
}
|
||||
int dimensionId = player.world.getDimension().getType().getId();
|
||||
int slot = getPlayerInventorySlotFromHand(player, context.getHand());
|
||||
AEPartLocation side = AEPartLocation.fromFacing(context.getFace());
|
||||
return new ContainerLocator(Type.PLAYER_INVENTORY_WITH_BLOCK_CONTEXT, slot, dimensionId, context.getBlockPos(),
|
||||
side);
|
||||
}
|
||||
|
||||
public static ContainerLocator forHand(PlayerEntity player, Hand hand) {
|
||||
int slot = getPlayerInventorySlotFromHand(player, hand);
|
||||
return new ContainerLocator(Type.PLAYER_INVENTORY, slot, -1, null, null);
|
||||
}
|
||||
|
||||
private static int getPlayerInventorySlotFromHand(PlayerEntity player, Hand hand) {
|
||||
ItemStack is = player.getStackInHand(hand);
|
||||
if (is.isEmpty()) {
|
||||
throw new IllegalArgumentException("Cannot open an item-inventory with empty hands");
|
||||
}
|
||||
int invSize = player.inventory.size();
|
||||
for (int i = 0; i < invSize; i++) {
|
||||
if (player.inventory.getStack(i) == is) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Could not find item held in hand " + hand + " in player inventory");
|
||||
}
|
||||
|
||||
public static ContainerLocator forPart(AEBasePart part) {
|
||||
IPartHost host = part.getHost();
|
||||
DimensionalCoord pos = host.getLocation();
|
||||
return new ContainerLocator(Type.PART, -1, pos.getWorld().getDimension().getType().getId(), pos.getBlockPos(),
|
||||
part.getSide());
|
||||
}
|
||||
|
||||
public boolean hasItemIndex() {
|
||||
return type == Type.PLAYER_INVENTORY || type == Type.PLAYER_INVENTORY_WITH_BLOCK_CONTEXT;
|
||||
}
|
||||
|
||||
public int getItemIndex() {
|
||||
Preconditions.checkState(hasItemIndex());
|
||||
return itemIndex;
|
||||
}
|
||||
|
||||
public int getDimensionId() {
|
||||
return dimensionId;
|
||||
}
|
||||
|
||||
public boolean hasBlockPos() {
|
||||
return type == Type.BLOCK || type == Type.PART || type == Type.PLAYER_INVENTORY_WITH_BLOCK_CONTEXT;
|
||||
}
|
||||
|
||||
public BlockPos getBlockPos() {
|
||||
Preconditions.checkState(hasBlockPos());
|
||||
return blockPos;
|
||||
}
|
||||
|
||||
public boolean hasSide() {
|
||||
return type == Type.PART || type == Type.PLAYER_INVENTORY_WITH_BLOCK_CONTEXT;
|
||||
}
|
||||
|
||||
public AEPartLocation getSide() {
|
||||
Preconditions.checkState(hasSide());
|
||||
return side;
|
||||
}
|
||||
|
||||
public void write(PacketByteBuf buf) {
|
||||
switch (type) {
|
||||
case PLAYER_INVENTORY:
|
||||
buf.writeByte(0);
|
||||
buf.writeInt(itemIndex);
|
||||
break;
|
||||
case PLAYER_INVENTORY_WITH_BLOCK_CONTEXT:
|
||||
buf.writeByte(1);
|
||||
buf.writeInt(itemIndex);
|
||||
buf.writeInt(dimensionId);
|
||||
buf.writeBlockPos(blockPos);
|
||||
buf.writeByte(side.ordinal());
|
||||
break;
|
||||
case BLOCK:
|
||||
buf.writeByte(2);
|
||||
buf.writeInt(dimensionId);
|
||||
buf.writeBlockPos(blockPos);
|
||||
break;
|
||||
case PART:
|
||||
buf.writeByte(3);
|
||||
buf.writeInt(dimensionId);
|
||||
buf.writeBlockPos(blockPos);
|
||||
buf.writeByte(side.ordinal());
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unsupported ContainerLocator type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
public static ContainerLocator read(PacketByteBuf buf) {
|
||||
byte type = buf.readByte();
|
||||
switch (type) {
|
||||
case 0:
|
||||
return new ContainerLocator(Type.PLAYER_INVENTORY, buf.readInt(), -1, null, null);
|
||||
case 1:
|
||||
return new ContainerLocator(Type.PLAYER_INVENTORY_WITH_BLOCK_CONTEXT, buf.readInt(), buf.readInt(),
|
||||
buf.readBlockPos(), AEPartLocation.values()[buf.readByte()]);
|
||||
case 2:
|
||||
return new ContainerLocator(Type.BLOCK, -1, buf.readInt(), buf.readBlockPos(), null);
|
||||
case 3:
|
||||
return new ContainerLocator(Type.PART, -1, buf.readInt(), buf.readBlockPos(),
|
||||
AEPartLocation.values()[buf.readByte()]);
|
||||
default:
|
||||
throw new DecoderException("ContainerLocator type out of range: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder result = new StringBuilder(type.name());
|
||||
result.append('{');
|
||||
if (hasItemIndex()) {
|
||||
result.append("slot=").append(itemIndex).append(',');
|
||||
}
|
||||
if (hasBlockPos()) {
|
||||
result.append("dim=").append(dimensionId).append(',');
|
||||
result.append("pos=").append(blockPos).append(',');
|
||||
}
|
||||
if (hasSide()) {
|
||||
result.append("side=").append(side).append(',');
|
||||
}
|
||||
if (result.charAt(result.length() - 1) == ',') {
|
||||
result.setLength(result.length() - 1);
|
||||
}
|
||||
result.append('}');
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -56,8 +56,6 @@ public abstract class CommonHelper {
|
||||
|
||||
public abstract CableRenderMode getRenderMode();
|
||||
|
||||
public abstract void triggerUpdates();
|
||||
|
||||
public abstract void updateRenderMode(PlayerEntity player);
|
||||
|
||||
public abstract boolean isActionKey(@Nonnull final ActionKey key, InputUtil.Key input);
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* 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.core.sync.packets;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
|
||||
import appeng.api.util.AEColor;
|
||||
import appeng.core.sync.BasePacket;
|
||||
import appeng.core.sync.network.INetworkInfo;
|
||||
import appeng.hooks.TickHandler;
|
||||
import appeng.hooks.TickHandler.PlayerColor;
|
||||
|
||||
public class PaintedEntityPacket extends BasePacket {
|
||||
|
||||
private final AEColor myColor;
|
||||
private final int entityId;
|
||||
private int ticks;
|
||||
|
||||
public PaintedEntityPacket(final PacketByteBuf stream) {
|
||||
this.entityId = stream.readInt();
|
||||
this.myColor = AEColor.values()[stream.readByte()];
|
||||
this.ticks = stream.readInt();
|
||||
}
|
||||
|
||||
// api
|
||||
public PaintedEntityPacket(final int myEntity, final AEColor myColor, final int ticksLeft) {
|
||||
|
||||
final PacketByteBuf data = new PacketByteBuf(Unpooled.buffer());
|
||||
|
||||
data.writeInt(this.getPacketID());
|
||||
data.writeInt(this.entityId = myEntity);
|
||||
data.writeByte((this.myColor = myColor).ordinal());
|
||||
data.writeInt(ticksLeft);
|
||||
|
||||
this.configureWrite(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clientPacketData(final INetworkInfo network, final PlayerEntity player) {
|
||||
final PlayerColor pc = new PlayerColor(this.entityId, this.myColor, this.ticks);
|
||||
TickHandler.INSTANCE.getPlayerColors().put(this.entityId, pc);
|
||||
}
|
||||
}
|
||||
@@ -1,299 +0,0 @@
|
||||
/*
|
||||
* 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.hooks;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import com.google.common.collect.LinkedListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
import net.minecraft.world.WorldAccess;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.event.TickEvent.Phase;
|
||||
import net.minecraftforge.event.TickEvent.Type;
|
||||
import net.minecraftforge.event.TickEvent.WorldTickEvent;
|
||||
import net.minecraftforge.event.world.WorldEvent;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.parts.CableRenderMode;
|
||||
import appeng.api.util.AEColor;
|
||||
import appeng.core.AEConfig;
|
||||
import appeng.core.AELog;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.core.sync.packets.PaintedEntityPacket;
|
||||
import appeng.crafting.CraftingJob;
|
||||
import appeng.me.Grid;
|
||||
import appeng.tile.AEBaseBlockEntity;
|
||||
import appeng.util.IWorldCallable;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public class TickHandler {
|
||||
|
||||
public static final TickHandler INSTANCE = new TickHandler();
|
||||
private final Queue<IWorldCallable<?>> serverQueue = new ArrayDeque<>();
|
||||
private final Multimap<World, CraftingJob> craftingJobs = LinkedListMultimap.create();
|
||||
private final WeakHashMap<WorldAccess, Queue<IWorldCallable<?>>> callQueue = new WeakHashMap<>();
|
||||
private final HandlerRep server = new HandlerRep();
|
||||
private final HandlerRep client = new HandlerRep();
|
||||
private final HashMap<Integer, PlayerColor> cliPlayerColors = new HashMap<>();
|
||||
private final HashMap<Integer, PlayerColor> srvPlayerColors = new HashMap<>();
|
||||
private CableRenderMode crm = CableRenderMode.STANDARD;
|
||||
|
||||
public HashMap<Integer, PlayerColor> getPlayerColors() {
|
||||
if (Platform.isServer()) {
|
||||
return this.srvPlayerColors;
|
||||
}
|
||||
return this.cliPlayerColors;
|
||||
}
|
||||
|
||||
public void addCallable(final WorldAccess w, final IWorldCallable<?> c) {
|
||||
if (w == null) {
|
||||
this.serverQueue.add(c);
|
||||
} else {
|
||||
Queue<IWorldCallable<?>> queue = this.callQueue.get(w);
|
||||
|
||||
if (queue == null) {
|
||||
queue = new ArrayDeque<>();
|
||||
this.callQueue.put(w, queue);
|
||||
}
|
||||
|
||||
queue.add(c);
|
||||
}
|
||||
}
|
||||
|
||||
public void addInit(final AEBaseBlockEntity tile) {
|
||||
if (Platform.isServer()) // for no there is no reason to care about this on the client...
|
||||
{
|
||||
this.getRepo().tiles.add(tile);
|
||||
}
|
||||
}
|
||||
|
||||
private HandlerRep getRepo() {
|
||||
if (Platform.isServer()) {
|
||||
return this.server;
|
||||
}
|
||||
return this.client;
|
||||
}
|
||||
|
||||
public void addNetwork(final Grid grid) {
|
||||
if (Platform.isServer()) // for no there is no reason to care about this on the client...
|
||||
{
|
||||
this.getRepo().addNetwork(grid);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeNetwork(final Grid grid) {
|
||||
if (Platform.isServer()) // for no there is no reason to care about this on the client...
|
||||
{
|
||||
this.getRepo().removeNetwork(grid);
|
||||
}
|
||||
}
|
||||
|
||||
public Iterable<Grid> getGridList() {
|
||||
return this.getRepo().networks;
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
this.getRepo().clear();
|
||||
}
|
||||
|
||||
public void unloadWorld(final WorldEvent.Unload ev) {
|
||||
if (Platform.isServer()) // for no there is no reason to care about this on the client...
|
||||
{
|
||||
final List<IGridNode> toDestroy = new ArrayList<>();
|
||||
|
||||
this.getRepo().updateNetworks();
|
||||
for (final Grid g : this.getRepo().networks) {
|
||||
for (final IGridNode n : g.getNodes()) {
|
||||
if (n.getWorld() == ev.getWorld()) {
|
||||
toDestroy.add(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (final IGridNode n : toDestroy) {
|
||||
n.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onTick(final TickEvent ev) {
|
||||
|
||||
if (ev.type == Type.CLIENT && ev.phase == Phase.START) {
|
||||
this.tickColors(this.cliPlayerColors);
|
||||
final CableRenderMode currentMode = AEApi.instance().partHelper().getCableRenderMode();
|
||||
if (currentMode != this.crm) {
|
||||
this.crm = currentMode;
|
||||
AppEng.proxy.triggerUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
if (ev.type == Type.WORLD && ev.phase == Phase.END) {
|
||||
final WorldTickEvent wte = (WorldTickEvent) ev;
|
||||
synchronized (this.craftingJobs) {
|
||||
final Collection<CraftingJob> jobSet = this.craftingJobs.get(wte.world);
|
||||
if (!jobSet.isEmpty()) {
|
||||
final int simTime = Math.max(1,
|
||||
AEConfig.instance().getCraftingCalculationTimePerTick() / jobSet.size());
|
||||
final Iterator<CraftingJob> i = jobSet.iterator();
|
||||
while (i.hasNext()) {
|
||||
final CraftingJob cj = i.next();
|
||||
if (!cj.simulateFor(simTime)) {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for no there is no reason to care about this on the client...
|
||||
else if (ev.type == Type.SERVER && ev.phase == Phase.END) {
|
||||
this.tickColors(this.srvPlayerColors);
|
||||
// ready tiles.
|
||||
final HandlerRep repo = this.getRepo();
|
||||
while (!repo.tiles.isEmpty()) {
|
||||
final AEBaseBlockEntity bt = repo.tiles.poll();
|
||||
if (!bt.isRemoved()) {
|
||||
bt.onReady();
|
||||
}
|
||||
}
|
||||
|
||||
// tick networks.
|
||||
this.getRepo().updateNetworks();
|
||||
for (final Grid g : this.getRepo().networks) {
|
||||
g.update();
|
||||
}
|
||||
|
||||
// cross world queue.
|
||||
this.processQueue(this.serverQueue, null);
|
||||
}
|
||||
|
||||
// world synced queue(s)
|
||||
if (ev.type == Type.WORLD && ev.phase == Phase.START) {
|
||||
final World world = ((WorldTickEvent) ev).world;
|
||||
final Queue<IWorldCallable<?>> queue = this.callQueue.get(world);
|
||||
this.processQueue(queue, world);
|
||||
}
|
||||
}
|
||||
|
||||
private void tickColors(final HashMap<Integer, PlayerColor> playerSet) {
|
||||
final Iterator<PlayerColor> i = playerSet.values().iterator();
|
||||
while (i.hasNext()) {
|
||||
final PlayerColor pc = i.next();
|
||||
if (pc.ticksLeft <= 0) {
|
||||
i.remove();
|
||||
}
|
||||
pc.ticksLeft--;
|
||||
}
|
||||
}
|
||||
|
||||
private void processQueue(final Queue<IWorldCallable<?>> queue, final World world) {
|
||||
if (queue == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Stopwatch sw = Stopwatch.createStarted();
|
||||
|
||||
IWorldCallable<?> c = null;
|
||||
while ((c = queue.poll()) != null) {
|
||||
try {
|
||||
c.call(world);
|
||||
|
||||
if (sw.elapsed(TimeUnit.MILLISECONDS) > 50) {
|
||||
break;
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
AELog.debug(e);
|
||||
}
|
||||
}
|
||||
|
||||
// long time = sw.elapsed( TimeUnit.MILLISECONDS );
|
||||
// if ( time > 0 )
|
||||
// AELog.info( "processQueue Time: " + time + "ms" );
|
||||
}
|
||||
|
||||
public void registerCraftingSimulation(final World world, final CraftingJob craftingJob) {
|
||||
synchronized (this.craftingJobs) {
|
||||
this.craftingJobs.put(world, craftingJob);
|
||||
}
|
||||
}
|
||||
|
||||
private static class HandlerRep {
|
||||
|
||||
private Queue<AEBaseBlockEntity> tiles = new ArrayDeque<>();
|
||||
private Set<Grid> networks = new HashSet<>();
|
||||
private Set<Grid> toAdd = new HashSet<>();
|
||||
private Set<Grid> toRemove = new HashSet<>();
|
||||
|
||||
private void clear() {
|
||||
this.tiles = new ArrayDeque<>();
|
||||
this.networks = new HashSet<>();
|
||||
this.toAdd = new HashSet<>();
|
||||
this.toRemove = new HashSet<>();
|
||||
}
|
||||
|
||||
private synchronized void addNetwork(Grid g) {
|
||||
this.toAdd.add(g);
|
||||
this.toRemove.remove(g);
|
||||
}
|
||||
|
||||
private synchronized void removeNetwork(Grid g) {
|
||||
this.toRemove.add(g);
|
||||
this.toAdd.remove(g);
|
||||
}
|
||||
|
||||
private synchronized void updateNetworks() {
|
||||
this.networks.removeAll(this.toRemove);
|
||||
this.toRemove.clear();
|
||||
|
||||
this.networks.addAll(this.toAdd);
|
||||
this.toAdd.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static class PlayerColor {
|
||||
|
||||
public final AEColor myColor;
|
||||
private final int myEntity;
|
||||
private int ticksLeft;
|
||||
|
||||
public PlayerColor(final int id, final AEColor col, final int ticks) {
|
||||
this.myEntity = id;
|
||||
this.myColor = col;
|
||||
this.ticksLeft = ticks;
|
||||
}
|
||||
|
||||
public PaintedEntityPacket getPacket() {
|
||||
return new PaintedEntityPacket(this.myEntity, this.myColor, this.ticksLeft);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,251 +0,0 @@
|
||||
/*
|
||||
* 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.me;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridCache;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridStorage;
|
||||
import appeng.api.networking.IMachineSet;
|
||||
import appeng.api.networking.events.MENetworkEvent;
|
||||
import appeng.api.networking.events.MENetworkPostCacheConstruction;
|
||||
import appeng.api.util.IReadOnlyCollection;
|
||||
import appeng.core.worlddata.WorldData;
|
||||
import appeng.hooks.TickHandler;
|
||||
import appeng.util.ReadOnlyCollection;
|
||||
|
||||
public class Grid implements IGrid {
|
||||
private final NetworkEventBus eventBus = new NetworkEventBus();
|
||||
private final Map<Class<? extends IGridHost>, MachineSet> machines = new HashMap<>();
|
||||
private final Map<Class<? extends IGridCache>, GridCacheWrapper> caches = new HashMap<>();
|
||||
private GridNode pivot;
|
||||
private int priority; // how import is this network?
|
||||
private GridStorage myStorage;
|
||||
|
||||
public Grid(final GridNode center) {
|
||||
this.pivot = center;
|
||||
|
||||
final Map<Class<? extends IGridCache>, IGridCache> myCaches = AEApi.instance().registries().gridCache()
|
||||
.createCacheInstance(this);
|
||||
for (final Entry<Class<? extends IGridCache>, IGridCache> c : myCaches.entrySet()) {
|
||||
final Class<? extends IGridCache> key = c.getKey();
|
||||
final IGridCache value = c.getValue();
|
||||
final Class<? extends IGridCache> valueClass = value.getClass();
|
||||
|
||||
this.eventBus.readClass(key, valueClass);
|
||||
this.caches.put(key, new GridCacheWrapper(value));
|
||||
}
|
||||
|
||||
this.postEvent(new MENetworkPostCacheConstruction());
|
||||
|
||||
TickHandler.INSTANCE.addNetwork(this);
|
||||
center.setGrid(this);
|
||||
}
|
||||
|
||||
int getPriority() {
|
||||
return this.priority;
|
||||
}
|
||||
|
||||
IGridStorage getMyStorage() {
|
||||
return this.myStorage;
|
||||
}
|
||||
|
||||
Map<Class<? extends IGridCache>, GridCacheWrapper> getCaches() {
|
||||
return this.caches;
|
||||
}
|
||||
|
||||
public Iterable<Class<? extends IGridHost>> getMachineClasses() {
|
||||
return this.machines.keySet();
|
||||
}
|
||||
|
||||
int size() {
|
||||
int out = 0;
|
||||
for (final Collection<?> x : this.machines.values()) {
|
||||
out += x.size();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void remove(final GridNode gridNode) {
|
||||
for (final IGridCache c : this.caches.values()) {
|
||||
final IGridHost machine = gridNode.getMachine();
|
||||
c.removeNode(gridNode, machine);
|
||||
}
|
||||
|
||||
final Class<? extends IGridHost> machineClass = gridNode.getMachineClass();
|
||||
final Set<IGridNode> nodes = this.machines.get(machineClass);
|
||||
if (nodes != null) {
|
||||
nodes.remove(gridNode);
|
||||
}
|
||||
|
||||
gridNode.setGridStorage(null);
|
||||
|
||||
if (this.pivot == gridNode) {
|
||||
final Iterator<IGridNode> n = this.getNodes().iterator();
|
||||
if (n.hasNext()) {
|
||||
this.pivot = (GridNode) n.next();
|
||||
} else {
|
||||
this.pivot = null;
|
||||
TickHandler.INSTANCE.removeNetwork(this);
|
||||
this.myStorage.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add(final GridNode gridNode) {
|
||||
final Class<? extends IGridHost> mClass = gridNode.getMachineClass();
|
||||
|
||||
MachineSet nodes = this.machines.get(mClass);
|
||||
if (nodes == null) {
|
||||
nodes = new MachineSet(mClass);
|
||||
this.machines.put(mClass, nodes);
|
||||
this.eventBus.readClass(mClass, mClass);
|
||||
}
|
||||
|
||||
// handle loading grid storages.
|
||||
if (gridNode.getGridStorage() != null) {
|
||||
final GridStorage gs = gridNode.getGridStorage();
|
||||
final IGrid grid = gs.getGrid();
|
||||
|
||||
if (grid == null) {
|
||||
this.myStorage = gs;
|
||||
this.myStorage.setGrid(this);
|
||||
|
||||
for (final IGridCache gc : this.caches.values()) {
|
||||
gc.onJoin(this.myStorage);
|
||||
}
|
||||
} else if (grid != this) {
|
||||
if (this.myStorage == null) {
|
||||
this.myStorage = WorldData.instance().storageData().getNewGridStorage();
|
||||
this.myStorage.setGrid(this);
|
||||
}
|
||||
|
||||
final IGridStorage tmp = new GridStorage();
|
||||
if (!gs.hasDivided(this.myStorage)) {
|
||||
gs.addDivided(this.myStorage);
|
||||
|
||||
for (final IGridCache gc : ((Grid) grid).caches.values()) {
|
||||
gc.onSplit(tmp);
|
||||
}
|
||||
|
||||
for (final IGridCache gc : this.caches.values()) {
|
||||
gc.onJoin(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (this.myStorage == null) {
|
||||
this.myStorage = WorldData.instance().storageData().getNewGridStorage();
|
||||
this.myStorage.setGrid(this);
|
||||
}
|
||||
|
||||
// update grid node...
|
||||
gridNode.setGridStorage(this.myStorage);
|
||||
|
||||
// track node.
|
||||
nodes.add(gridNode);
|
||||
|
||||
for (final IGridCache cache : this.caches.values()) {
|
||||
final IGridHost machine = gridNode.getMachine();
|
||||
cache.addNode(gridNode, machine);
|
||||
}
|
||||
|
||||
gridNode.getGridProxy().gridChanged();
|
||||
// postEventTo( gridNode, networkChanged );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C extends IGridCache> C getCache(final Class<? extends IGridCache> iface) {
|
||||
return (C) this.caches.get(iface).getCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MENetworkEvent postEvent(final MENetworkEvent ev) {
|
||||
return this.eventBus.postEvent(this, ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MENetworkEvent postEventTo(final IGridNode node, final MENetworkEvent ev) {
|
||||
return this.eventBus.postEventTo(this, (GridNode) node, ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IReadOnlyCollection<Class<? extends IGridHost>> getMachinesClasses() {
|
||||
final Set<Class<? extends IGridHost>> machineKeys = this.machines.keySet();
|
||||
|
||||
return new ReadOnlyCollection<>(machineKeys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMachineSet getMachines(final Class<? extends IGridHost> c) {
|
||||
final MachineSet s = this.machines.get(c);
|
||||
if (s == null) {
|
||||
return new MachineSet(c);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IReadOnlyCollection<IGridNode> getNodes() {
|
||||
return new GridNodeCollection(this.machines);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.pivot == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridNode getPivot() {
|
||||
return this.pivot;
|
||||
}
|
||||
|
||||
void setPivot(final GridNode pivot) {
|
||||
this.pivot = pivot;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
for (final IGridCache gc : this.caches.values()) {
|
||||
// are there any nodes left?
|
||||
if (this.pivot != null) {
|
||||
gc.onUpdateTick();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void saveState() {
|
||||
for (final IGridCache c : this.caches.values()) {
|
||||
c.populateGridStorage(this.myStorage);
|
||||
}
|
||||
}
|
||||
|
||||
public void setImportantFlag(final int i, final boolean publicHasPower) {
|
||||
final int flag = 1 << i;
|
||||
this.priority = (this.priority & ~flag) | (publicHasPower ? flag : 0);
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* 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.me;
|
||||
|
||||
public class GridAccessException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 3914554394866375300L;
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* 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.me;
|
||||
|
||||
import appeng.api.networking.IGridCache;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridStorage;
|
||||
|
||||
public class GridCacheWrapper implements IGridCache {
|
||||
|
||||
private final IGridCache myCache;
|
||||
private final String name;
|
||||
|
||||
public GridCacheWrapper(final IGridCache gc) {
|
||||
this.myCache = gc;
|
||||
this.name = this.getCache().getClass().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateTick() {
|
||||
this.getCache().onUpdateTick();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNode(final IGridNode gridNode, final IGridHost machine) {
|
||||
this.getCache().removeNode(gridNode, machine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNode(final IGridNode gridNode, final IGridHost machine) {
|
||||
this.getCache().addNode(gridNode, machine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSplit(final IGridStorage storageB) {
|
||||
this.getCache().onSplit(storageB);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onJoin(final IGridStorage storageB) {
|
||||
this.getCache().onJoin(storageB);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateGridStorage(final IGridStorage storage) {
|
||||
this.getCache().populateGridStorage(storage);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
IGridCache getCache() {
|
||||
return this.myCache;
|
||||
}
|
||||
}
|
||||
@@ -1,256 +0,0 @@
|
||||
/*
|
||||
* 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.me;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import appeng.api.exceptions.ExistingConnectionException;
|
||||
import appeng.api.exceptions.FailedConnectionException;
|
||||
import appeng.api.exceptions.NullNodeConnectionException;
|
||||
import appeng.api.exceptions.SecurityConnectionException;
|
||||
import appeng.api.features.AEFeature;
|
||||
import appeng.api.networking.GridFlags;
|
||||
import appeng.api.networking.IGridConnection;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.events.MENetworkChannelsChanged;
|
||||
import appeng.api.networking.pathing.IPathingGrid;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.api.util.DimensionalCoord;
|
||||
import appeng.api.util.IReadOnlyCollection;
|
||||
import appeng.core.AEConfig;
|
||||
import appeng.core.AELog;
|
||||
import appeng.me.pathfinding.IPathItem;
|
||||
import appeng.util.Platform;
|
||||
import appeng.util.ReadOnlyCollection;
|
||||
|
||||
public class GridConnection implements IGridConnection, IPathItem {
|
||||
|
||||
private static final String EXISTING_CONNECTION_MESSAGE = "Connection between node [machine=%s, %s] and [machine=%s, %s] on [%s] already exists.";
|
||||
|
||||
private static final MENetworkChannelsChanged EVENT = new MENetworkChannelsChanged();
|
||||
private int channelData = 0;
|
||||
private Object visitorIterationNumber = null;
|
||||
private GridNode sideA;
|
||||
private AEPartLocation fromAtoB;
|
||||
private GridNode sideB;
|
||||
|
||||
private GridConnection(final GridNode aNode, final GridNode bNode, final AEPartLocation fromAtoB) {
|
||||
this.sideA = aNode;
|
||||
this.fromAtoB = fromAtoB;
|
||||
this.sideB = bNode;
|
||||
}
|
||||
|
||||
private boolean isNetworkABetter(final GridNode a, final GridNode b) {
|
||||
return a.getMyGrid().getPriority() > b.getMyGrid().getPriority() || a.getMyGrid().size() > b.getMyGrid().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridNode getOtherSide(final IGridNode gridNode) {
|
||||
if (gridNode == this.sideA) {
|
||||
return this.sideB;
|
||||
}
|
||||
if (gridNode == this.sideB) {
|
||||
return this.sideA;
|
||||
}
|
||||
|
||||
throw new GridException("Invalid Side of Connection");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AEPartLocation getDirection(final IGridNode side) {
|
||||
if (this.fromAtoB == AEPartLocation.INTERNAL) {
|
||||
return this.fromAtoB;
|
||||
}
|
||||
|
||||
if (this.sideA == side) {
|
||||
return this.fromAtoB;
|
||||
} else {
|
||||
return this.fromAtoB.getOpposite();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
// a connection was destroyed RE-PATH!!
|
||||
final IPathingGrid p = this.sideA.getInternalGrid().getCache(IPathingGrid.class);
|
||||
p.repath();
|
||||
|
||||
this.sideA.removeConnection(this);
|
||||
this.sideB.removeConnection(this);
|
||||
|
||||
this.sideA.validateGrid();
|
||||
this.sideB.validateGrid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridNode a() {
|
||||
return this.sideA;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridNode b() {
|
||||
return this.sideB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDirection() {
|
||||
return this.fromAtoB != AEPartLocation.INTERNAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUsedChannels() {
|
||||
return (this.channelData >> 8) & 0xff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPathItem getControllerRoute() {
|
||||
if (this.sideA.getFlags().contains(GridFlags.CANNOT_CARRY)) {
|
||||
return null;
|
||||
}
|
||||
return this.sideA;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setControllerRoute(final IPathItem fast, final boolean zeroOut) {
|
||||
if (zeroOut) {
|
||||
this.channelData &= ~0xff;
|
||||
}
|
||||
|
||||
if (this.sideB == fast) {
|
||||
final GridNode tmp = this.sideA;
|
||||
this.sideA = this.sideB;
|
||||
this.sideB = tmp;
|
||||
this.fromAtoB = this.fromAtoB.getOpposite();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSupportMoreChannels() {
|
||||
return this.getLastUsedChannels() < 32; // max, PERIOD.
|
||||
}
|
||||
|
||||
@Override
|
||||
public IReadOnlyCollection<IPathItem> getPossibleOptions() {
|
||||
return new ReadOnlyCollection<>(Arrays.asList((IPathItem) this.a(), (IPathItem) this.b()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementChannelCount(final int usedChannels) {
|
||||
this.channelData += usedChannels;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<GridFlags> getFlags() {
|
||||
return EnumSet.noneOf(GridFlags.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finalizeChannels() {
|
||||
if (this.getUsedChannels() != this.getLastUsedChannels()) {
|
||||
this.channelData &= 0xff;
|
||||
this.channelData |= this.channelData << 8;
|
||||
|
||||
if (this.sideA.getInternalGrid() != null) {
|
||||
this.sideA.getInternalGrid().postEventTo(this.sideA, EVENT);
|
||||
}
|
||||
|
||||
if (this.sideB.getInternalGrid() != null) {
|
||||
this.sideB.getInternalGrid().postEventTo(this.sideB, EVENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getLastUsedChannels() {
|
||||
return this.channelData & 0xff;
|
||||
}
|
||||
|
||||
Object getVisitorIterationNumber() {
|
||||
return this.visitorIterationNumber;
|
||||
}
|
||||
|
||||
void setVisitorIterationNumber(final Object visitorIterationNumber) {
|
||||
this.visitorIterationNumber = visitorIterationNumber;
|
||||
}
|
||||
|
||||
public static GridConnection create(final IGridNode aNode, final IGridNode bNode, final AEPartLocation fromAtoB)
|
||||
throws FailedConnectionException {
|
||||
if (aNode == null || bNode == null) {
|
||||
throw new NullNodeConnectionException();
|
||||
}
|
||||
|
||||
final GridNode a = (GridNode) aNode;
|
||||
final GridNode b = (GridNode) bNode;
|
||||
|
||||
if (a.hasConnection(b) || b.hasConnection(a)) {
|
||||
final String aMachineClass = a.getGridBlock().getMachine().getClass().getSimpleName();
|
||||
final String bMachineClass = b.getGridBlock().getMachine().getClass().getSimpleName();
|
||||
final String aCoordinates = a.getGridBlock().getLocation().toString();
|
||||
final String bCoordinates = b.getGridBlock().getLocation().toString();
|
||||
|
||||
throw new ExistingConnectionException(String.format(EXISTING_CONNECTION_MESSAGE, aMachineClass,
|
||||
aCoordinates, bMachineClass, bCoordinates, fromAtoB));
|
||||
}
|
||||
|
||||
if (!Platform.securityCheck(a, b)) {
|
||||
if (AEConfig.instance().isFeatureEnabled(AEFeature.LOG_SECURITY_AUDITS)) {
|
||||
final DimensionalCoord aCoordinates = a.getGridBlock().getLocation();
|
||||
final DimensionalCoord bCoordinates = b.getGridBlock().getLocation();
|
||||
|
||||
AELog.info("Security audit 1 failed at [%s] belonging to player [id=%d]", aCoordinates.toString(),
|
||||
a.getPlayerID());
|
||||
AELog.info("Security audit 2 failed at [%s] belonging to player [id=%d]", bCoordinates.toString(),
|
||||
b.getPlayerID());
|
||||
}
|
||||
|
||||
throw new SecurityConnectionException();
|
||||
}
|
||||
|
||||
// Create the actual connection
|
||||
final GridConnection connection = new GridConnection(a, b, fromAtoB);
|
||||
|
||||
// Update both nodes with the new connection.
|
||||
if (a.getMyGrid() == null) {
|
||||
b.setGrid(a.getInternalGrid());
|
||||
} else {
|
||||
if (a.getMyGrid() == null) {
|
||||
final GridPropagator gp = new GridPropagator(b.getInternalGrid());
|
||||
aNode.beginVisit(gp);
|
||||
} else if (b.getMyGrid() == null) {
|
||||
final GridPropagator gp = new GridPropagator(a.getInternalGrid());
|
||||
bNode.beginVisit(gp);
|
||||
} else if (connection.isNetworkABetter(a, b)) {
|
||||
final GridPropagator gp = new GridPropagator(a.getInternalGrid());
|
||||
b.beginVisit(gp);
|
||||
} else {
|
||||
final GridPropagator gp = new GridPropagator(b.getInternalGrid());
|
||||
a.beginVisit(gp);
|
||||
}
|
||||
}
|
||||
|
||||
// a connection was destroyed RE-PATH!!
|
||||
final IPathingGrid p = connection.sideA.getInternalGrid().getCache(IPathingGrid.class);
|
||||
p.repath();
|
||||
|
||||
connection.sideA.addConnection(connection);
|
||||
connection.sideB.addConnection(connection);
|
||||
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* 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.me;
|
||||
|
||||
public class GridException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = -8110077032108243076L;
|
||||
|
||||
public GridException(final String s) {
|
||||
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
@@ -1,617 +0,0 @@
|
||||
/*
|
||||
* 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.me;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Deque;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
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.WorldAccess;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import appeng.api.exceptions.FailedConnectionException;
|
||||
import appeng.api.exceptions.SecurityConnectionException;
|
||||
import appeng.api.networking.GridFlags;
|
||||
import appeng.api.networking.GridNotification;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridBlock;
|
||||
import appeng.api.networking.IGridCache;
|
||||
import appeng.api.networking.IGridConnection;
|
||||
import appeng.api.networking.IGridConnectionVisitor;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridVisitor;
|
||||
import appeng.api.networking.energy.IEnergyGrid;
|
||||
import appeng.api.networking.events.MENetworkChannelsChanged;
|
||||
import appeng.api.networking.pathing.IPathingGrid;
|
||||
import appeng.api.util.AEColor;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.api.util.DimensionalCoord;
|
||||
import appeng.api.util.IReadOnlyCollection;
|
||||
import appeng.core.AELog;
|
||||
import appeng.core.worlddata.WorldData;
|
||||
import appeng.hooks.TickHandler;
|
||||
import appeng.me.pathfinding.IPathItem;
|
||||
import appeng.util.IWorldCallable;
|
||||
import appeng.util.ReadOnlyCollection;
|
||||
|
||||
public class GridNode implements IGridNode, IPathItem {
|
||||
private static final MENetworkChannelsChanged EVENT = new MENetworkChannelsChanged();
|
||||
private static final int[] CHANNEL_COUNT = { 0, 8, 32 };
|
||||
|
||||
private final List<IGridConnection> connections = new ArrayList<>();
|
||||
private final IGridBlock gridProxy;
|
||||
// old power draw, used to diff
|
||||
private double previousDraw = 0.0;
|
||||
private long lastSecurityKey = -1;
|
||||
private int playerID = -1;
|
||||
private GridStorage myStorage = null;
|
||||
private Grid myGrid;
|
||||
private Object visitorIterationNumber = null;
|
||||
// connection criteria
|
||||
private int compressedData = 0;
|
||||
private int usedChannels = 0;
|
||||
private int lastUsedChannels = 0;
|
||||
|
||||
public GridNode(final IGridBlock what) {
|
||||
this.gridProxy = what;
|
||||
}
|
||||
|
||||
IGridBlock getGridProxy() {
|
||||
return this.gridProxy;
|
||||
}
|
||||
|
||||
Grid getMyGrid() {
|
||||
return this.myGrid;
|
||||
}
|
||||
|
||||
public int usedChannels() {
|
||||
return this.lastUsedChannels;
|
||||
}
|
||||
|
||||
Class<? extends IGridHost> getMachineClass() {
|
||||
return this.getMachine().getClass();
|
||||
}
|
||||
|
||||
void addConnection(final IGridConnection gridConnection) {
|
||||
this.connections.add(gridConnection);
|
||||
if (gridConnection.hasDirection()) {
|
||||
this.gridProxy.onGridNotification(GridNotification.CONNECTIONS_CHANGED);
|
||||
}
|
||||
|
||||
final IGridNode gn = this;
|
||||
|
||||
Collections.sort(this.connections, new ConnectionComparator(gn));
|
||||
}
|
||||
|
||||
void removeConnection(final IGridConnection gridConnection) {
|
||||
this.connections.remove(gridConnection);
|
||||
if (gridConnection.hasDirection()) {
|
||||
this.gridProxy.onGridNotification(GridNotification.CONNECTIONS_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasConnection(final IGridNode otherSide) {
|
||||
for (final IGridConnection gc : this.connections) {
|
||||
if (gc.a() == otherSide || gc.b() == otherSide) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void validateGrid() {
|
||||
final GridSplitDetector gsd = new GridSplitDetector(this.getInternalGrid().getPivot());
|
||||
this.beginVisit(gsd);
|
||||
if (!gsd.isPivotFound()) {
|
||||
final IGridVisitor gp = new GridPropagator(new Grid(this));
|
||||
this.beginVisit(gp);
|
||||
}
|
||||
}
|
||||
|
||||
public Grid getInternalGrid() {
|
||||
if (this.myGrid == null) {
|
||||
this.myGrid = new Grid(this);
|
||||
}
|
||||
|
||||
return this.myGrid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginVisit(final IGridVisitor g) {
|
||||
final Object tracker = new Object();
|
||||
|
||||
Deque<GridNode> nextRun = new ArrayDeque<>();
|
||||
nextRun.add(this);
|
||||
|
||||
this.visitorIterationNumber = tracker;
|
||||
|
||||
if (g instanceof IGridConnectionVisitor) {
|
||||
final Deque<IGridConnection> nextConn = new ArrayDeque<>();
|
||||
final IGridConnectionVisitor gcv = (IGridConnectionVisitor) g;
|
||||
|
||||
while (!nextRun.isEmpty()) {
|
||||
while (!nextConn.isEmpty()) {
|
||||
gcv.visitConnection(nextConn.poll());
|
||||
}
|
||||
|
||||
final Iterable<GridNode> thisRun = nextRun;
|
||||
nextRun = new ArrayDeque<>();
|
||||
|
||||
for (final GridNode n : thisRun) {
|
||||
n.visitorConnection(tracker, g, nextRun, nextConn);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (!nextRun.isEmpty()) {
|
||||
final Iterable<GridNode> thisRun = nextRun;
|
||||
nextRun = new ArrayDeque<>();
|
||||
|
||||
for (final GridNode n : thisRun) {
|
||||
n.visitorNode(tracker, g, nextRun);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState() {
|
||||
final EnumSet<GridFlags> set = this.gridProxy.getFlags();
|
||||
|
||||
this.compressedData = set.contains(GridFlags.CANNOT_CARRY) ? 0
|
||||
: (set.contains(GridFlags.DENSE_CAPACITY) ? 2 : 1);
|
||||
|
||||
this.compressedData |= (this.gridProxy.getGridColor().ordinal() << 3);
|
||||
|
||||
for (final Direction dir : this.gridProxy.getConnectableSides()) {
|
||||
this.compressedData |= (1 << (dir.ordinal() + 8));
|
||||
}
|
||||
|
||||
this.findConnections();
|
||||
this.getInternalGrid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridHost getMachine() {
|
||||
return this.gridProxy.getMachine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGrid getGrid() {
|
||||
return this.myGrid;
|
||||
}
|
||||
|
||||
void setGrid(final Grid grid) {
|
||||
if (this.myGrid == grid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.myGrid != null) {
|
||||
this.myGrid.remove(this);
|
||||
|
||||
if (this.myGrid.isEmpty()) {
|
||||
this.myGrid.saveState();
|
||||
|
||||
for (final IGridCache c : grid.getCaches().values()) {
|
||||
c.onJoin(this.myGrid.getMyStorage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.myGrid = grid;
|
||||
this.myGrid.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
while (!this.connections.isEmpty()) {
|
||||
// not part of this network for real anymore.
|
||||
if (this.connections.size() == 1) {
|
||||
this.setGridStorage(null);
|
||||
}
|
||||
|
||||
final IGridConnection c = this.connections.listIterator().next();
|
||||
final GridNode otherSide = (GridNode) c.getOtherSide(this);
|
||||
otherSide.getInternalGrid().setPivot(otherSide);
|
||||
c.destroy();
|
||||
}
|
||||
|
||||
if (this.myGrid != null) {
|
||||
this.myGrid.remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldAccess getWorld() {
|
||||
return this.gridProxy.getLocation().getWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<AEPartLocation> getConnectedSides() {
|
||||
final EnumSet<AEPartLocation> set = EnumSet.noneOf(AEPartLocation.class);
|
||||
for (final IGridConnection gc : this.connections) {
|
||||
set.add(gc.getDirection(this));
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IReadOnlyCollection<IGridConnection> getConnections() {
|
||||
return new ReadOnlyCollection<>(this.connections);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridBlock getGridBlock() {
|
||||
return this.gridProxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
final IGrid g = this.getGrid();
|
||||
if (g != null) {
|
||||
final IPathingGrid pg = g.getCache(IPathingGrid.class);
|
||||
final IEnergyGrid eg = g.getCache(IEnergyGrid.class);
|
||||
return eg.isNetworkPowered() && !pg.isNetworkBooting() && this.meetsChannelRequirements();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadFromNBT(final String name, final CompoundTag nodeData) {
|
||||
if (this.myGrid == null) {
|
||||
final CompoundTag node = nodeData.getCompound(name);
|
||||
this.playerID = node.getInt("p");
|
||||
this.setLastSecurityKey(node.getLong("k"));
|
||||
|
||||
final long storageID = node.getLong("g");
|
||||
final GridStorage gridStorage = WorldData.instance().storageData().getGridStorage(storageID);
|
||||
this.setGridStorage(gridStorage);
|
||||
} else {
|
||||
throw new IllegalStateException("Loading data after part of a grid, this is invalid.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveToNBT(final String name, final CompoundTag nodeData) {
|
||||
if (this.myStorage != null) {
|
||||
final CompoundTag node = new CompoundTag();
|
||||
|
||||
node.putInt("p", this.playerID);
|
||||
node.putLong("k", this.getLastSecurityKey());
|
||||
node.putLong("g", this.myStorage.getID());
|
||||
|
||||
nodeData.put(name, node);
|
||||
} else {
|
||||
nodeData.remove(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean meetsChannelRequirements() {
|
||||
return (!this.gridProxy.getFlags().contains(GridFlags.REQUIRE_CHANNEL) || this.getUsedChannels() > 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFlag(final GridFlags flag) {
|
||||
return this.gridProxy.getFlags().contains(flag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPlayerID() {
|
||||
return this.playerID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerID(final int playerID) {
|
||||
if (playerID >= 0) {
|
||||
this.playerID = playerID;
|
||||
}
|
||||
}
|
||||
|
||||
private int getUsedChannels() {
|
||||
return this.usedChannels;
|
||||
}
|
||||
|
||||
private void findConnections() {
|
||||
if (!this.gridProxy.isWorldAccessible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final EnumSet<AEPartLocation> newSecurityConnections = EnumSet.noneOf(AEPartLocation.class);
|
||||
|
||||
final DimensionalCoord dc = this.gridProxy.getLocation();
|
||||
for (final AEPartLocation f : AEPartLocation.SIDE_LOCATIONS) {
|
||||
final IGridHost te = this.findGridHost(dc.getWorld(), dc.x + f.xOffset, dc.y + f.yOffset, dc.z + f.zOffset);
|
||||
if (te != null) {
|
||||
final GridNode node = (GridNode) te.getGridNode(f.getOpposite());
|
||||
if (node == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final boolean isValidConnection = this.canConnect(node, f) && node.canConnect(this, f.getOpposite());
|
||||
|
||||
IGridConnection con = null; // find the connection for this
|
||||
// direction..
|
||||
for (final IGridConnection c : this.getConnections()) {
|
||||
if (c.getDirection(this) == f) {
|
||||
con = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (con != null) {
|
||||
final IGridNode os = con.getOtherSide(this);
|
||||
if (os == node) {
|
||||
// if this connection is no longer valid, destroy it.
|
||||
if (!isValidConnection) {
|
||||
con.destroy();
|
||||
}
|
||||
} else {
|
||||
con.destroy();
|
||||
// throw new GridException( "invalid state found, encountered connection to
|
||||
// phantom block." );
|
||||
}
|
||||
} else if (isValidConnection) {
|
||||
if (node.getLastSecurityKey() != -1) {
|
||||
newSecurityConnections.add(f);
|
||||
} else {
|
||||
// construct a new connection between these two nodes.
|
||||
try {
|
||||
GridConnection.create(node, this, f.getOpposite());
|
||||
} catch (SecurityConnectionException e) {
|
||||
AELog.debug(e);
|
||||
TickHandler.INSTANCE.addCallable(node.getWorld(), new MachineSecurityBreak(this));
|
||||
|
||||
return;
|
||||
} catch (final FailedConnectionException e) {
|
||||
AELog.debug(e);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (final AEPartLocation f : newSecurityConnections) {
|
||||
final IGridHost te = this.findGridHost(dc.getWorld(), dc.x + f.xOffset, dc.y + f.yOffset, dc.z + f.zOffset);
|
||||
if (te != null) {
|
||||
final GridNode node = (GridNode) te.getGridNode(f.getOpposite());
|
||||
if (node == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// construct a new connection between these two nodes.
|
||||
try {
|
||||
GridConnection.create(node, this, f.getOpposite());
|
||||
} catch (SecurityConnectionException e) {
|
||||
AELog.debug(e);
|
||||
|
||||
TickHandler.INSTANCE.addCallable(node.getWorld(), new MachineSecurityBreak(this));
|
||||
|
||||
return;
|
||||
} catch (final FailedConnectionException e) {
|
||||
AELog.debug(e);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IGridHost findGridHost(final WorldAccess world, final int x, final int y, final int z) {
|
||||
final BlockPos pos = new BlockPos(x, y, z);
|
||||
if (world.isChunkLoaded(pos)) {
|
||||
final BlockEntity te = world.getBlockEntity(pos);
|
||||
if (te instanceof IGridHost) {
|
||||
return (IGridHost) te;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean canConnect(final GridNode from, final AEPartLocation dir) {
|
||||
if (!this.isValidDirection(dir)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!from.getColor().matches(this.getColor())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isValidDirection(final AEPartLocation dir) {
|
||||
return (this.compressedData & (1 << (8 + dir.ordinal()))) > 0;
|
||||
}
|
||||
|
||||
private AEColor getColor() {
|
||||
return AEColor.values()[(this.compressedData >> 3) & 0x1F];
|
||||
}
|
||||
|
||||
private void visitorConnection(final Object tracker, final IGridVisitor g, final Deque<GridNode> nextRun,
|
||||
final Deque<IGridConnection> nextConnections) {
|
||||
if (g.visitNode(this)) {
|
||||
for (final IGridConnection gc : this.getConnections()) {
|
||||
final GridNode gn = (GridNode) gc.getOtherSide(this);
|
||||
final GridConnection gcc = (GridConnection) gc;
|
||||
|
||||
if (gcc.getVisitorIterationNumber() != tracker) {
|
||||
gcc.setVisitorIterationNumber(tracker);
|
||||
nextConnections.add(gc);
|
||||
}
|
||||
|
||||
if (tracker == gn.visitorIterationNumber) {
|
||||
continue;
|
||||
}
|
||||
|
||||
gn.visitorIterationNumber = tracker;
|
||||
|
||||
nextRun.add(gn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void visitorNode(final Object tracker, final IGridVisitor g, final Deque<GridNode> nextRun) {
|
||||
if (g.visitNode(this)) {
|
||||
for (final IGridConnection gc : this.getConnections()) {
|
||||
final GridNode gn = (GridNode) gc.getOtherSide(this);
|
||||
|
||||
if (tracker == gn.visitorIterationNumber) {
|
||||
continue;
|
||||
}
|
||||
|
||||
gn.visitorIterationNumber = tracker;
|
||||
|
||||
nextRun.add(gn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GridStorage getGridStorage() {
|
||||
return this.myStorage;
|
||||
}
|
||||
|
||||
void setGridStorage(final GridStorage s) {
|
||||
this.myStorage = s;
|
||||
this.usedChannels = 0;
|
||||
this.lastUsedChannels = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPathItem getControllerRoute() {
|
||||
if (this.connections.isEmpty() || this.getFlags().contains(GridFlags.CANNOT_CARRY)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (IPathItem) this.connections.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setControllerRoute(final IPathItem fast, final boolean zeroOut) {
|
||||
if (zeroOut) {
|
||||
this.usedChannels = 0;
|
||||
}
|
||||
|
||||
final int idx = this.connections.indexOf(fast);
|
||||
if (idx > 0) {
|
||||
this.connections.remove(fast);
|
||||
this.connections.add(0, (IGridConnection) fast);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSupportMoreChannels() {
|
||||
return this.getUsedChannels() < this.getMaxChannels();
|
||||
}
|
||||
|
||||
private int getMaxChannels() {
|
||||
return CHANNEL_COUNT[this.compressedData & 0x03];
|
||||
}
|
||||
|
||||
@Override
|
||||
public IReadOnlyCollection<IPathItem> getPossibleOptions() {
|
||||
return (IReadOnlyCollection) this.getConnections();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementChannelCount(final int usedChannels) {
|
||||
this.usedChannels += usedChannels;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<GridFlags> getFlags() {
|
||||
return this.gridProxy.getFlags();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finalizeChannels() {
|
||||
if (this.getFlags().contains(GridFlags.CANNOT_CARRY)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.getLastUsedChannels() != this.getUsedChannels()) {
|
||||
this.lastUsedChannels = this.usedChannels;
|
||||
|
||||
if (this.getInternalGrid() != null) {
|
||||
this.getInternalGrid().postEventTo(this, EVENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getLastUsedChannels() {
|
||||
return this.lastUsedChannels;
|
||||
}
|
||||
|
||||
public long getLastSecurityKey() {
|
||||
return this.lastSecurityKey;
|
||||
}
|
||||
|
||||
public void setLastSecurityKey(final long lastSecurityKey) {
|
||||
this.lastSecurityKey = lastSecurityKey;
|
||||
}
|
||||
|
||||
public double getPreviousDraw() {
|
||||
return this.previousDraw;
|
||||
}
|
||||
|
||||
public void setPreviousDraw(final double previousDraw) {
|
||||
this.previousDraw = previousDraw;
|
||||
}
|
||||
|
||||
private static class MachineSecurityBreak implements IWorldCallable<Void> {
|
||||
private final GridNode node;
|
||||
|
||||
public MachineSecurityBreak(final GridNode node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void call(final World world) throws Exception {
|
||||
this.node.getMachine().securityBreak();
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ConnectionComparator implements Comparator<IGridConnection> {
|
||||
private final IGridNode gn;
|
||||
|
||||
public ConnectionComparator(final IGridNode gn) {
|
||||
this.gn = gn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(final IGridConnection o1, final IGridConnection o2) {
|
||||
final boolean preferredA = o1.getOtherSide(this.gn).hasFlag(GridFlags.PREFERRED);
|
||||
final boolean preferredB = o2.getOtherSide(this.gn).hasFlag(GridFlags.PREFERRED);
|
||||
|
||||
return preferredA == preferredB ? 0 : (preferredA ? -1 : 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* 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.me;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.util.IReadOnlyCollection;
|
||||
|
||||
public class GridNodeCollection implements IReadOnlyCollection<IGridNode> {
|
||||
private final Map<Class<? extends IGridHost>, MachineSet> machines;
|
||||
|
||||
public GridNodeCollection(final Map<Class<? extends IGridHost>, MachineSet> machines) {
|
||||
this.machines = machines;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<IGridNode> iterator() {
|
||||
return new GridNodeIterator(this.machines);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
int size = 0;
|
||||
|
||||
for (final Set<IGridNode> o : this.machines.values()) {
|
||||
size += o.size();
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
for (final Set<IGridNode> o : this.machines.values()) {
|
||||
if (!o.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(final Object maybeGridNode) {
|
||||
final boolean doesContainNode;
|
||||
|
||||
if (maybeGridNode instanceof IGridNode) {
|
||||
final IGridNode node = (IGridNode) maybeGridNode;
|
||||
final IGridHost machine = node.getMachine();
|
||||
final Class<? extends IGridHost> machineClass = machine.getClass();
|
||||
|
||||
final MachineSet machineSet = this.machines.get(machineClass);
|
||||
|
||||
doesContainNode = machineSet != null && machineSet.contains(maybeGridNode);
|
||||
} else {
|
||||
doesContainNode = false;
|
||||
}
|
||||
|
||||
return doesContainNode;
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* 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.me;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
|
||||
/**
|
||||
* Nested iterator for {@link appeng.me.MachineSet}
|
||||
*
|
||||
* Traverses first over the {@link appeng.me.MachineSet} and then over every
|
||||
* containing {@link appeng.api.networking.IGridNode}
|
||||
*/
|
||||
public class GridNodeIterator implements Iterator<IGridNode> {
|
||||
private final Iterator<MachineSet> outerIterator;
|
||||
private Iterator<IGridNode> innerIterator;
|
||||
|
||||
public GridNodeIterator(final Map<Class<? extends IGridHost>, MachineSet> machines) {
|
||||
this.outerIterator = machines.values().iterator();
|
||||
this.innerHasNext();
|
||||
}
|
||||
|
||||
private boolean innerHasNext() {
|
||||
final boolean hasNext = this.outerIterator.hasNext();
|
||||
|
||||
if (hasNext) {
|
||||
final MachineSet nextElem = this.outerIterator.next();
|
||||
this.innerIterator = nextElem.iterator();
|
||||
}
|
||||
|
||||
return hasNext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
while (true) {
|
||||
if (this.innerIterator.hasNext()) {
|
||||
return true;
|
||||
} else if (!this.innerHasNext()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridNode next() {
|
||||
return this.innerIterator.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
this.innerIterator.remove();
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* 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.me;
|
||||
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridVisitor;
|
||||
|
||||
public class GridPropagator implements IGridVisitor {
|
||||
private final Grid g;
|
||||
|
||||
public GridPropagator(final Grid g) {
|
||||
this.g = g;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitNode(final IGridNode n) {
|
||||
final GridNode gn = (GridNode) n;
|
||||
if (gn.getMyGrid() != this.g || this.g.getPivot() == n) {
|
||||
gn.setGrid(this.g);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* 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.me;
|
||||
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridVisitor;
|
||||
|
||||
class GridSplitDetector implements IGridVisitor {
|
||||
|
||||
private final IGridNode pivot;
|
||||
private boolean pivotFound;
|
||||
|
||||
public GridSplitDetector(final IGridNode pivot) {
|
||||
this.pivot = pivot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitNode(final IGridNode n) {
|
||||
if (n == this.pivot) {
|
||||
this.setPivotFound(true);
|
||||
}
|
||||
|
||||
return !this.isPivotFound();
|
||||
}
|
||||
|
||||
public boolean isPivotFound() {
|
||||
return this.pivotFound;
|
||||
}
|
||||
|
||||
private void setPivotFound(final boolean pivotFound) {
|
||||
this.pivotFound = pivotFound;
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* 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.me;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IMachineSet;
|
||||
|
||||
public class MachineSet extends HashSet<IGridNode> implements IMachineSet {
|
||||
|
||||
private static final long serialVersionUID = 3224660708327386933L;
|
||||
|
||||
private final Class<? extends IGridHost> machine;
|
||||
|
||||
MachineSet(final Class<? extends IGridHost> m) {
|
||||
this.machine = m;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends IGridHost> getMachineClass() {
|
||||
return this.machine;
|
||||
}
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
/*
|
||||
* 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.me;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IMachineSet;
|
||||
import appeng.api.networking.events.MENetworkEvent;
|
||||
import appeng.api.networking.events.MENetworkEventSubscribe;
|
||||
import appeng.core.AELog;
|
||||
|
||||
public class NetworkEventBus {
|
||||
private static final Collection<Class> READ_CLASSES = new HashSet<>();
|
||||
private static final Map<Class<? extends MENetworkEvent>, Map<Class, MENetworkEventInfo>> EVENTS = new HashMap<>();
|
||||
|
||||
void readClass(final Class listAs, final Class c) {
|
||||
if (READ_CLASSES.contains(c)) {
|
||||
return;
|
||||
}
|
||||
READ_CLASSES.add(c);
|
||||
|
||||
try {
|
||||
for (final Method m : c.getMethods()) {
|
||||
final MENetworkEventSubscribe s = m.getAnnotation(MENetworkEventSubscribe.class);
|
||||
if (s != null) {
|
||||
final Class[] types = m.getParameterTypes();
|
||||
if (types.length == 1) {
|
||||
if (MENetworkEvent.class.isAssignableFrom(types[0])) {
|
||||
|
||||
Map<Class, MENetworkEventInfo> classEvents = EVENTS.get(types[0]);
|
||||
if (classEvents == null) {
|
||||
EVENTS.put(types[0], classEvents = new HashMap<>());
|
||||
}
|
||||
|
||||
MENetworkEventInfo thisEvent = classEvents.get(listAs);
|
||||
if (thisEvent == null) {
|
||||
thisEvent = new MENetworkEventInfo();
|
||||
}
|
||||
|
||||
thisEvent.Add(types[0], c, m);
|
||||
|
||||
classEvents.put(listAs, thisEvent);
|
||||
} else {
|
||||
throw new IllegalStateException("Invalid ME Network Event Subscriber, " + m.getName()
|
||||
+ "s Parameter must extend MENetworkEvent.");
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException("Invalid ME Network Event Subscriber, " + m.getName()
|
||||
+ " must have exactly 1 parameter.");
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final Throwable t) {
|
||||
throw new IllegalStateException("Error while adding " + c.getName() + " to event bus", t);
|
||||
}
|
||||
}
|
||||
|
||||
MENetworkEvent postEvent(final Grid g, final MENetworkEvent e) {
|
||||
final Map<Class, MENetworkEventInfo> subscribers = EVENTS.get(e.getClass());
|
||||
int x = 0;
|
||||
|
||||
try {
|
||||
if (subscribers != null) {
|
||||
for (final Entry<Class, MENetworkEventInfo> subscriber : subscribers.entrySet()) {
|
||||
final MENetworkEventInfo target = subscriber.getValue();
|
||||
final GridCacheWrapper cache = g.getCaches().get(subscriber.getKey());
|
||||
if (cache != null) {
|
||||
x++;
|
||||
target.invoke(cache.getCache(), e);
|
||||
}
|
||||
|
||||
// events may create or remove grid nodes in rare cases
|
||||
final IMachineSet machines = g.getMachines(subscriber.getKey());
|
||||
final List<IGridNode> work = new ArrayList<>(machines.size());
|
||||
machines.forEach(work::add);
|
||||
|
||||
for (final IGridNode obj : work) {
|
||||
// stil part of grid?
|
||||
if (machines.contains(obj)) {
|
||||
x++;
|
||||
target.invoke(obj.getMachine(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final NetworkEventDone done) {
|
||||
// Early out.
|
||||
}
|
||||
|
||||
e.setVisitedObjects(x);
|
||||
return e;
|
||||
}
|
||||
|
||||
MENetworkEvent postEventTo(final Grid grid, final GridNode node, final MENetworkEvent e) {
|
||||
final Map<Class, MENetworkEventInfo> subscribers = EVENTS.get(e.getClass());
|
||||
int x = 0;
|
||||
|
||||
try {
|
||||
if (subscribers != null) {
|
||||
final MENetworkEventInfo target = subscribers.get(node.getMachineClass());
|
||||
if (target != null) {
|
||||
x++;
|
||||
target.invoke(node.getMachine(), e);
|
||||
}
|
||||
}
|
||||
} catch (final NetworkEventDone done) {
|
||||
// Early out.
|
||||
}
|
||||
|
||||
e.setVisitedObjects(x);
|
||||
return e;
|
||||
}
|
||||
|
||||
private static class NetworkEventDone extends Throwable {
|
||||
|
||||
private static final long serialVersionUID = -3079021487019171205L;
|
||||
}
|
||||
|
||||
private class EventMethod {
|
||||
|
||||
private final Class objClass;
|
||||
private final Method objMethod;
|
||||
private final Class objEvent;
|
||||
|
||||
public EventMethod(final Class Event, final Class ObjClass, final Method ObjMethod) {
|
||||
this.objClass = ObjClass;
|
||||
this.objMethod = ObjMethod;
|
||||
this.objEvent = Event;
|
||||
}
|
||||
|
||||
private void invoke(final Object obj, final MENetworkEvent e) throws NetworkEventDone {
|
||||
try {
|
||||
this.objMethod.invoke(obj, e);
|
||||
} catch (final Throwable e1) {
|
||||
AELog.error("[AppEng] Network Event caused exception:");
|
||||
AELog.error("Class: %1s, Object: %2s", obj.getClass().getName(), obj.toString());
|
||||
AELog.info(e1);
|
||||
throw new IllegalStateException(e1);
|
||||
}
|
||||
|
||||
if (e.isCanceled()) {
|
||||
throw new NetworkEventDone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MENetworkEventInfo {
|
||||
|
||||
private final List<EventMethod> methods = new ArrayList<>();
|
||||
|
||||
private void Add(final Class Event, final Class ObjClass, final Method ObjMethod) {
|
||||
this.methods.add(new EventMethod(Event, ObjClass, ObjMethod));
|
||||
}
|
||||
|
||||
private void invoke(final Object obj, final MENetworkEvent e) throws NetworkEventDone {
|
||||
for (final EventMethod em : this.methods) {
|
||||
em.invoke(obj, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-596
@@ -1,596 +0,0 @@
|
||||
/*
|
||||
* 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.me.cache;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.HashMultiset;
|
||||
import com.google.common.collect.Multiset;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import appeng.api.config.AccessRestriction;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.config.PowerMultiplier;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridBlock;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridStorage;
|
||||
import appeng.api.networking.energy.IAEPowerStorage;
|
||||
import appeng.api.networking.energy.IEnergyGrid;
|
||||
import appeng.api.networking.energy.IEnergyGridProvider;
|
||||
import appeng.api.networking.energy.IEnergyWatcher;
|
||||
import appeng.api.networking.energy.IEnergyWatcherHost;
|
||||
import appeng.api.networking.events.MENetworkEventSubscribe;
|
||||
import appeng.api.networking.events.MENetworkPostCacheConstruction;
|
||||
import appeng.api.networking.events.MENetworkPowerIdleChange;
|
||||
import appeng.api.networking.events.MENetworkPowerStatusChange;
|
||||
import appeng.api.networking.events.MENetworkPowerStorage;
|
||||
import appeng.api.networking.events.MENetworkPowerStorage.PowerEventType;
|
||||
import appeng.api.networking.pathing.IPathingGrid;
|
||||
import appeng.me.Grid;
|
||||
import appeng.me.GridNode;
|
||||
import appeng.me.energy.EnergyThreshold;
|
||||
import appeng.me.energy.EnergyWatcher;
|
||||
|
||||
public class EnergyGridCache implements IEnergyGrid {
|
||||
|
||||
private static final double MAX_BUFFER_STORAGE = 800;
|
||||
|
||||
private static final Comparator<IEnergyGridProvider> COMPARATOR_HIGHEST_AMOUNT_STORED_FIRST = (o1, o2) -> Double
|
||||
.compare(o2.getProviderStoredEnergy(), o1.getProviderStoredEnergy());
|
||||
|
||||
private static final Comparator<IEnergyGridProvider> COMPARATOR_LOWEST_PERCENTAGE_FIRST = (o1, o2) -> {
|
||||
final double percent1 = (o1.getProviderStoredEnergy() + 1) / (o1.getProviderMaxEnergy() + 1);
|
||||
final double percent2 = (o2.getProviderStoredEnergy() + 1) / (o2.getProviderMaxEnergy() + 1);
|
||||
|
||||
return Double.compare(percent1, percent2);
|
||||
};
|
||||
|
||||
private final NavigableSet<EnergyThreshold> interests = Sets.newTreeSet();
|
||||
private final double averageLength = 40.0;
|
||||
private final Set<IAEPowerStorage> providers = new LinkedHashSet<>();
|
||||
private final Set<IAEPowerStorage> requesters = new LinkedHashSet<>();
|
||||
private final Multiset<IEnergyGridProvider> energyGridProviders = HashMultiset.create();
|
||||
private final IGrid myGrid;
|
||||
private final HashMap<IGridNode, IEnergyWatcher> watchers = new HashMap<>();
|
||||
|
||||
/**
|
||||
* estimated power available.
|
||||
*/
|
||||
private int availableTicksSinceUpdate = 0;
|
||||
private double globalAvailablePower = 0;
|
||||
private double globalMaxPower = MAX_BUFFER_STORAGE;
|
||||
|
||||
/**
|
||||
* idle draw.
|
||||
*/
|
||||
private double drainPerTick = 0;
|
||||
private double avgDrainPerTick = 0;
|
||||
private double avgInjectionPerTick = 0;
|
||||
private double tickDrainPerTick = 0;
|
||||
private double tickInjectionPerTick = 0;
|
||||
|
||||
/**
|
||||
* power status
|
||||
*/
|
||||
private boolean publicHasPower = false;
|
||||
private boolean hasPower = true;
|
||||
private long ticksSinceHasPowerChange = 900;
|
||||
|
||||
private PathGridCache pgc;
|
||||
private double lastStoredPower = -1;
|
||||
|
||||
private final GridPowerStorage localStorage = new GridPowerStorage();
|
||||
|
||||
public EnergyGridCache(final IGrid g) {
|
||||
this.myGrid = g;
|
||||
this.requesters.add(this.localStorage);
|
||||
this.providers.add(this.localStorage);
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void postInit(final MENetworkPostCacheConstruction pcc) {
|
||||
this.pgc = this.myGrid.getCache(IPathingGrid.class);
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void nodeIdlePowerChangeHandler(final MENetworkPowerIdleChange ev) {
|
||||
// update power usage based on event.
|
||||
final GridNode node = (GridNode) ev.node;
|
||||
final IGridBlock gb = node.getGridBlock();
|
||||
|
||||
final double newDraw = gb.getIdlePowerUsage();
|
||||
final double diffDraw = newDraw - node.getPreviousDraw();
|
||||
node.setPreviousDraw(newDraw);
|
||||
|
||||
this.drainPerTick += diffDraw;
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void storagePowerChangeHandler(final MENetworkPowerStorage ev) {
|
||||
if (ev.storage.isAEPublicPowerStorage()) {
|
||||
switch (ev.type) {
|
||||
case PROVIDE_POWER:
|
||||
if (ev.storage.getPowerFlow() != AccessRestriction.WRITE) {
|
||||
this.providers.add(ev.storage);
|
||||
}
|
||||
break;
|
||||
case REQUEST_POWER:
|
||||
if (ev.storage.getPowerFlow() != AccessRestriction.READ) {
|
||||
this.requesters.add(ev.storage);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
(new RuntimeException("Attempt to ask the IEnergyGrid to charge a non public energy store."))
|
||||
.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateTick() {
|
||||
if (!this.interests.isEmpty()) {
|
||||
final double oldPower = this.lastStoredPower;
|
||||
this.lastStoredPower = this.getStoredPower();
|
||||
|
||||
final EnergyThreshold low = new EnergyThreshold(Math.min(oldPower, this.lastStoredPower),
|
||||
Integer.MIN_VALUE);
|
||||
final EnergyThreshold high = new EnergyThreshold(Math.max(oldPower, this.lastStoredPower),
|
||||
Integer.MAX_VALUE);
|
||||
|
||||
for (final EnergyThreshold th : this.interests.subSet(low, true, high, true)) {
|
||||
((EnergyWatcher) th.getEnergyWatcher()).post(this);
|
||||
}
|
||||
}
|
||||
|
||||
this.avgDrainPerTick *= (this.averageLength - 1) / this.averageLength;
|
||||
this.avgInjectionPerTick *= (this.averageLength - 1) / this.averageLength;
|
||||
|
||||
this.avgDrainPerTick += this.tickDrainPerTick / this.averageLength;
|
||||
this.avgInjectionPerTick += this.tickInjectionPerTick / this.averageLength;
|
||||
|
||||
this.tickDrainPerTick = 0;
|
||||
this.tickInjectionPerTick = 0;
|
||||
|
||||
// power information.
|
||||
boolean currentlyHasPower = false;
|
||||
|
||||
if (this.drainPerTick > 0.0001) {
|
||||
final double drained = this.extractAEPower(this.getIdlePowerUsage(), Actionable.MODULATE,
|
||||
PowerMultiplier.CONFIG);
|
||||
currentlyHasPower = drained >= this.drainPerTick - 0.001;
|
||||
} else {
|
||||
currentlyHasPower = this.extractAEPower(0.1, Actionable.SIMULATE, PowerMultiplier.CONFIG) > 0;
|
||||
}
|
||||
|
||||
// ticks since change..
|
||||
if (currentlyHasPower == this.hasPower) {
|
||||
this.ticksSinceHasPowerChange++;
|
||||
} else {
|
||||
this.ticksSinceHasPowerChange = 0;
|
||||
}
|
||||
|
||||
// update status..
|
||||
this.hasPower = currentlyHasPower;
|
||||
|
||||
// update public status, this buffers power ups for 30 ticks.
|
||||
if (this.hasPower && this.ticksSinceHasPowerChange > 30) {
|
||||
this.publicPowerState(true, this.myGrid);
|
||||
} else if (!this.hasPower) {
|
||||
this.publicPowerState(false, this.myGrid);
|
||||
}
|
||||
|
||||
this.availableTicksSinceUpdate++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double extractAEPower(final double amt, final Actionable mode, final PowerMultiplier pm) {
|
||||
final double toExtract = pm.multiply(amt);
|
||||
final Queue<IEnergyGridProvider> toVisit = new PriorityQueue<>(COMPARATOR_HIGHEST_AMOUNT_STORED_FIRST);
|
||||
final Set<IEnergyGridProvider> visited = new HashSet<>();
|
||||
|
||||
double extracted = 0;
|
||||
toVisit.add(this);
|
||||
|
||||
while (!toVisit.isEmpty() && extracted < toExtract) {
|
||||
final IEnergyGridProvider next = toVisit.poll();
|
||||
visited.add(next);
|
||||
|
||||
extracted += next.extractProviderPower(toExtract - extracted, mode);
|
||||
|
||||
for (IEnergyGridProvider iEnergyGridProvider : next.providers()) {
|
||||
if (!visited.contains(iEnergyGridProvider)) {
|
||||
toVisit.add(iEnergyGridProvider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pm.divide(extracted);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getIdlePowerUsage() {
|
||||
return this.drainPerTick + this.pgc.getChannelPowerUsage();
|
||||
}
|
||||
|
||||
private void publicPowerState(final boolean newState, final IGrid grid) {
|
||||
if (this.publicHasPower == newState) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.publicHasPower = newState;
|
||||
((Grid) this.myGrid).setImportantFlag(0, this.publicHasPower);
|
||||
grid.postEvent(new MENetworkPowerStatusChange());
|
||||
}
|
||||
|
||||
/**
|
||||
* refresh current stored power.
|
||||
*/
|
||||
private void refreshPower() {
|
||||
this.availableTicksSinceUpdate = 0;
|
||||
this.globalAvailablePower = 0;
|
||||
for (final IAEPowerStorage p : this.providers) {
|
||||
this.globalAvailablePower += p.getAECurrentPower();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<IEnergyGridProvider> providers() {
|
||||
return this.energyGridProviders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double extractProviderPower(final double amt, final Actionable mode) {
|
||||
double extractedPower = 0;
|
||||
|
||||
final Iterator<IAEPowerStorage> it = this.providers.iterator();
|
||||
|
||||
while (extractedPower < amt && it.hasNext()) {
|
||||
final IAEPowerStorage node = it.next();
|
||||
|
||||
final double req = amt - extractedPower;
|
||||
final double newPower = node.extractAEPower(req, mode, PowerMultiplier.ONE);
|
||||
extractedPower += newPower;
|
||||
|
||||
if (newPower < req && mode == Actionable.MODULATE) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
final double result = Math.min(extractedPower, amt);
|
||||
|
||||
if (mode == Actionable.MODULATE) {
|
||||
if (extractedPower > amt) {
|
||||
this.localStorage.addCurrentAEPower(extractedPower - amt);
|
||||
}
|
||||
|
||||
this.globalAvailablePower -= result;
|
||||
this.tickDrainPerTick += result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double injectProviderPower(double amt, final Actionable mode) {
|
||||
final double originalAmount = amt;
|
||||
|
||||
final Iterator<IAEPowerStorage> it = this.requesters.iterator();
|
||||
|
||||
while (amt > 0 && it.hasNext()) {
|
||||
final IAEPowerStorage node = it.next();
|
||||
amt = node.injectAEPower(amt, mode);
|
||||
|
||||
if (amt > 0 && mode == Actionable.MODULATE) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
final double overflow = Math.max(0.0, amt);
|
||||
|
||||
if (mode == Actionable.MODULATE) {
|
||||
this.tickInjectionPerTick += originalAmount - overflow;
|
||||
}
|
||||
|
||||
return overflow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getProviderEnergyDemand(final double maxRequired) {
|
||||
double required = 0;
|
||||
|
||||
final Iterator<IAEPowerStorage> it = this.requesters.iterator();
|
||||
while (required < maxRequired && it.hasNext()) {
|
||||
final IAEPowerStorage node = it.next();
|
||||
if (node.getPowerFlow() != AccessRestriction.READ) {
|
||||
required += Math.max(0.0, node.getAEMaxPower() - node.getAECurrentPower());
|
||||
}
|
||||
}
|
||||
|
||||
return required;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getAvgPowerUsage() {
|
||||
return this.avgDrainPerTick;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getAvgPowerInjection() {
|
||||
return this.avgInjectionPerTick;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNetworkPowered() {
|
||||
return this.publicHasPower;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double injectPower(final double amt, final Actionable mode) {
|
||||
final Queue<IEnergyGridProvider> toVisit = new PriorityQueue<>(COMPARATOR_LOWEST_PERCENTAGE_FIRST);
|
||||
final Set<IEnergyGridProvider> visited = new HashSet<>();
|
||||
toVisit.add(this);
|
||||
|
||||
double leftover = amt;
|
||||
|
||||
while (!toVisit.isEmpty() && leftover > 0) {
|
||||
final IEnergyGridProvider next = toVisit.poll();
|
||||
visited.add(next);
|
||||
|
||||
leftover = next.injectProviderPower(leftover, mode);
|
||||
|
||||
for (IEnergyGridProvider iEnergyGridProvider : next.providers()) {
|
||||
if (!visited.contains(iEnergyGridProvider)) {
|
||||
toVisit.add(iEnergyGridProvider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return leftover;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getStoredPower() {
|
||||
if (this.availableTicksSinceUpdate > 90) {
|
||||
this.refreshPower();
|
||||
}
|
||||
|
||||
return Math.max(0.0, this.globalAvailablePower);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getMaxStoredPower() {
|
||||
return this.globalMaxPower;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getEnergyDemand(final double maxRequired) {
|
||||
final Queue<IEnergyGridProvider> toVisit = new PriorityQueue<>(COMPARATOR_LOWEST_PERCENTAGE_FIRST);
|
||||
final Set<IEnergyGridProvider> visited = new HashSet<>();
|
||||
toVisit.add(this);
|
||||
|
||||
double required = 0;
|
||||
|
||||
while (!toVisit.isEmpty() && required < maxRequired) {
|
||||
final IEnergyGridProvider next = toVisit.poll();
|
||||
visited.add(next);
|
||||
|
||||
required += next.getProviderEnergyDemand(maxRequired - required);
|
||||
|
||||
for (IEnergyGridProvider iEnergyGridProvider : next.providers()) {
|
||||
if (!visited.contains(iEnergyGridProvider)) {
|
||||
toVisit.add(iEnergyGridProvider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return required;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getProviderStoredEnergy() {
|
||||
return this.getStoredPower();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getProviderMaxEnergy() {
|
||||
return this.getMaxStoredPower();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNode(final IGridNode node, final IGridHost machine) {
|
||||
if (machine instanceof IEnergyGridProvider) {
|
||||
this.energyGridProviders.remove(machine);
|
||||
}
|
||||
|
||||
// idle draw.
|
||||
final GridNode gridNode = (GridNode) node;
|
||||
this.drainPerTick -= gridNode.getPreviousDraw();
|
||||
|
||||
// power storage.
|
||||
if (machine instanceof IAEPowerStorage) {
|
||||
final IAEPowerStorage ps = (IAEPowerStorage) machine;
|
||||
if (ps.isAEPublicPowerStorage()) {
|
||||
if (ps.getPowerFlow() != AccessRestriction.WRITE) {
|
||||
this.globalMaxPower -= ps.getAEMaxPower();
|
||||
this.globalAvailablePower -= ps.getAECurrentPower();
|
||||
}
|
||||
|
||||
this.providers.remove(ps);
|
||||
this.requesters.remove(ps);
|
||||
}
|
||||
}
|
||||
|
||||
if (machine instanceof IEnergyWatcherHost) {
|
||||
final IEnergyWatcher watcher = this.watchers.get(node);
|
||||
|
||||
if (watcher != null) {
|
||||
watcher.reset();
|
||||
this.watchers.remove(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNode(final IGridNode node, final IGridHost machine) {
|
||||
if (machine instanceof IEnergyGridProvider) {
|
||||
this.energyGridProviders.add((IEnergyGridProvider) machine);
|
||||
}
|
||||
|
||||
// idle draw...
|
||||
final GridNode gridNode = (GridNode) node;
|
||||
final IGridBlock gb = gridNode.getGridBlock();
|
||||
gridNode.setPreviousDraw(gb.getIdlePowerUsage());
|
||||
this.drainPerTick += gridNode.getPreviousDraw();
|
||||
|
||||
// power storage
|
||||
if (machine instanceof IAEPowerStorage) {
|
||||
final IAEPowerStorage ps = (IAEPowerStorage) machine;
|
||||
if (ps.isAEPublicPowerStorage()) {
|
||||
final double max = ps.getAEMaxPower();
|
||||
final double current = ps.getAECurrentPower();
|
||||
|
||||
if (ps.getPowerFlow() != AccessRestriction.WRITE) {
|
||||
this.globalMaxPower += ps.getAEMaxPower();
|
||||
}
|
||||
|
||||
if (current > 0 && ps.getPowerFlow() != AccessRestriction.WRITE) {
|
||||
this.globalAvailablePower += current;
|
||||
this.providers.add(ps);
|
||||
}
|
||||
|
||||
if (current < max && ps.getPowerFlow() != AccessRestriction.READ) {
|
||||
this.requesters.add(ps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (machine instanceof IEnergyWatcherHost) {
|
||||
final IEnergyWatcherHost swh = (IEnergyWatcherHost) machine;
|
||||
final EnergyWatcher iw = new EnergyWatcher(this, swh);
|
||||
|
||||
this.watchers.put(node, iw);
|
||||
swh.updateWatcher(iw);
|
||||
}
|
||||
|
||||
this.myGrid.postEventTo(node, new MENetworkPowerStatusChange());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSplit(final IGridStorage storageB) {
|
||||
final double newBuffer = this.localStorage.getAECurrentPower() / 2;
|
||||
this.localStorage.removeCurrentAEPower(newBuffer);
|
||||
storageB.dataObject().putDouble("buffer", newBuffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onJoin(final IGridStorage storageB) {
|
||||
this.localStorage.addCurrentAEPower(storageB.dataObject().getDouble("buffer"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateGridStorage(final IGridStorage storage) {
|
||||
storage.dataObject().putDouble("buffer", this.localStorage.getAECurrentPower());
|
||||
}
|
||||
|
||||
public boolean registerEnergyInterest(final EnergyThreshold threshold) {
|
||||
return this.interests.add(threshold);
|
||||
}
|
||||
|
||||
public boolean unregisterEnergyInterest(final EnergyThreshold threshold) {
|
||||
return this.interests.remove(threshold);
|
||||
}
|
||||
|
||||
private class GridPowerStorage implements IAEPowerStorage {
|
||||
private double stored = 0;
|
||||
|
||||
@Override
|
||||
public double extractAEPower(double amt, Actionable mode, PowerMultiplier usePowerMultiplier) {
|
||||
double extracted = Math.min(amt, this.stored);
|
||||
|
||||
if (mode == Actionable.MODULATE) {
|
||||
this.removeCurrentAEPower(extracted);
|
||||
}
|
||||
|
||||
return extracted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAEPublicPowerStorage() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double injectAEPower(double amt, Actionable mode) {
|
||||
double toStore = Math.min(amt, MAX_BUFFER_STORAGE - this.stored);
|
||||
|
||||
if (mode == Actionable.MODULATE) {
|
||||
this.addCurrentAEPower(toStore);
|
||||
}
|
||||
|
||||
return amt - toStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessRestriction getPowerFlow() {
|
||||
return AccessRestriction.READ_WRITE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getAEMaxPower() {
|
||||
return MAX_BUFFER_STORAGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getAECurrentPower() {
|
||||
return this.stored;
|
||||
}
|
||||
|
||||
private void addCurrentAEPower(double amount) {
|
||||
this.stored += amount;
|
||||
|
||||
if (this.stored > 0.01) {
|
||||
EnergyGridCache.this.myGrid.postEvent(new MENetworkPowerStorage(this, PowerEventType.PROVIDE_POWER));
|
||||
}
|
||||
}
|
||||
|
||||
private void removeCurrentAEPower(double amount) {
|
||||
this.stored -= amount;
|
||||
|
||||
if (this.stored < MAX_BUFFER_STORAGE - 0.001) {
|
||||
EnergyGridCache.this.myGrid.postEvent(new MENetworkPowerStorage(this, PowerEventType.REQUEST_POWER));
|
||||
}
|
||||
|
||||
if (this.stored < 0.01) {
|
||||
EnergyGridCache.this.ticksSinceHasPowerChange = 0;
|
||||
EnergyGridCache.this.publicPowerState(false, EnergyGridCache.this.myGrid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-306
@@ -1,306 +0,0 @@
|
||||
/*
|
||||
* 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.me.cache;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.SetMultimap;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridStorage;
|
||||
import appeng.api.networking.events.MENetworkCellArrayUpdate;
|
||||
import appeng.api.networking.events.MENetworkEventSubscribe;
|
||||
import appeng.api.networking.security.IActionHost;
|
||||
import appeng.api.networking.security.IActionSource;
|
||||
import appeng.api.networking.security.ISecurityGrid;
|
||||
import appeng.api.networking.storage.IStackWatcher;
|
||||
import appeng.api.networking.storage.IStackWatcherHost;
|
||||
import appeng.api.networking.storage.IStorageGrid;
|
||||
import appeng.api.storage.IMEInventoryHandler;
|
||||
import appeng.api.storage.IMEMonitor;
|
||||
import appeng.api.storage.IStorageChannel;
|
||||
import appeng.api.storage.cells.ICellContainer;
|
||||
import appeng.api.storage.cells.ICellProvider;
|
||||
import appeng.api.storage.data.IAEItemStack;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.me.helpers.BaseActionSource;
|
||||
import appeng.me.helpers.GenericInterestManager;
|
||||
import appeng.me.helpers.MachineSource;
|
||||
import appeng.me.storage.ItemWatcher;
|
||||
import appeng.me.storage.NetworkInventoryHandler;
|
||||
|
||||
public class GridStorageCache implements IStorageGrid {
|
||||
|
||||
private final IGrid myGrid;
|
||||
private final HashSet<ICellProvider> activeCellProviders = new HashSet<>();
|
||||
private final HashSet<ICellProvider> inactiveCellProviders = new HashSet<>();
|
||||
private final SetMultimap<IAEStack, ItemWatcher> interests = HashMultimap.create();
|
||||
private final GenericInterestManager<ItemWatcher> interestManager = new GenericInterestManager<>(this.interests);
|
||||
private final HashMap<IGridNode, IStackWatcher> watchers = new HashMap<>();
|
||||
private Map<IStorageChannel<? extends IAEStack>, NetworkInventoryHandler<?>> storageNetworks;
|
||||
private Map<IStorageChannel<? extends IAEStack>, NetworkMonitor<?>> storageMonitors;
|
||||
|
||||
public GridStorageCache(final IGrid g) {
|
||||
this.myGrid = g;
|
||||
this.storageNetworks = new IdentityHashMap<>();
|
||||
this.storageMonitors = new IdentityHashMap<>();
|
||||
|
||||
AEApi.instance().storage().storageChannels()
|
||||
.forEach(channel -> this.storageMonitors.put(channel, new NetworkMonitor<>(this, channel)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateTick() {
|
||||
this.storageMonitors.forEach((channel, monitor) -> monitor.onTick());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNode(final IGridNode node, final IGridHost machine) {
|
||||
if (machine instanceof ICellContainer) {
|
||||
final ICellContainer cc = (ICellContainer) machine;
|
||||
final CellChangeTracker tracker = new CellChangeTracker();
|
||||
|
||||
this.removeCellProvider(cc, tracker);
|
||||
this.inactiveCellProviders.remove(cc);
|
||||
this.getGrid().postEvent(new MENetworkCellArrayUpdate());
|
||||
|
||||
tracker.applyChanges();
|
||||
}
|
||||
|
||||
if (machine instanceof IStackWatcherHost) {
|
||||
final IStackWatcher myWatcher = this.watchers.get(machine);
|
||||
|
||||
if (myWatcher != null) {
|
||||
myWatcher.reset();
|
||||
this.watchers.remove(machine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNode(final IGridNode node, final IGridHost machine) {
|
||||
if (machine instanceof ICellContainer) {
|
||||
final ICellContainer cc = (ICellContainer) machine;
|
||||
this.inactiveCellProviders.add(cc);
|
||||
|
||||
this.getGrid().postEvent(new MENetworkCellArrayUpdate());
|
||||
|
||||
if (node.isActive()) {
|
||||
final CellChangeTracker tracker = new CellChangeTracker();
|
||||
|
||||
this.addCellProvider(cc, tracker);
|
||||
tracker.applyChanges();
|
||||
}
|
||||
}
|
||||
|
||||
if (machine instanceof IStackWatcherHost) {
|
||||
final IStackWatcherHost swh = (IStackWatcherHost) machine;
|
||||
final ItemWatcher iw = new ItemWatcher(this, swh);
|
||||
this.watchers.put(node, iw);
|
||||
swh.updateWatcher(iw);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSplit(final IGridStorage storageB) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onJoin(final IGridStorage storageB) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateGridStorage(final IGridStorage storage) {
|
||||
|
||||
}
|
||||
|
||||
public <T extends IAEStack<T>> IMEInventoryHandler<T> getInventoryHandler(IStorageChannel<T> channel) {
|
||||
return (IMEInventoryHandler<T>) this.storageNetworks.computeIfAbsent(channel, this::buildNetworkStorage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IAEStack<T>> IMEMonitor<T> getInventory(IStorageChannel<T> channel) {
|
||||
return (IMEMonitor<T>) this.storageMonitors.get(channel);
|
||||
}
|
||||
|
||||
private CellChangeTracker addCellProvider(final ICellProvider cc, final CellChangeTracker tracker) {
|
||||
if (this.inactiveCellProviders.contains(cc)) {
|
||||
this.inactiveCellProviders.remove(cc);
|
||||
this.activeCellProviders.add(cc);
|
||||
|
||||
final IActionSource actionSrc = cc instanceof IActionHost ? new MachineSource((IActionHost) cc)
|
||||
: new BaseActionSource();
|
||||
|
||||
this.storageMonitors.forEach((channel, monitor) -> {
|
||||
for (final IMEInventoryHandler<?> h : cc.getCellArray(channel)) {
|
||||
tracker.postChanges(channel, 1, h, actionSrc);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return tracker;
|
||||
}
|
||||
|
||||
private CellChangeTracker removeCellProvider(final ICellProvider cc, final CellChangeTracker tracker) {
|
||||
if (this.activeCellProviders.contains(cc)) {
|
||||
this.activeCellProviders.remove(cc);
|
||||
this.inactiveCellProviders.add(cc);
|
||||
|
||||
final IActionSource actionSrc = cc instanceof IActionHost ? new MachineSource((IActionHost) cc)
|
||||
: new BaseActionSource();
|
||||
|
||||
this.storageMonitors.forEach((channel, monitor) -> {
|
||||
for (final IMEInventoryHandler<IAEItemStack> h : cc.getCellArray(channel)) {
|
||||
tracker.postChanges(channel, -1, h, actionSrc);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return tracker;
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void cellUpdate(final MENetworkCellArrayUpdate ev) {
|
||||
this.storageNetworks.clear();
|
||||
|
||||
final List<ICellProvider> ll = new ArrayList<ICellProvider>();
|
||||
ll.addAll(this.inactiveCellProviders);
|
||||
ll.addAll(this.activeCellProviders);
|
||||
|
||||
final CellChangeTracker tracker = new CellChangeTracker();
|
||||
|
||||
for (final ICellProvider cc : ll) {
|
||||
boolean active = true;
|
||||
|
||||
if (cc instanceof IActionHost) {
|
||||
final IGridNode node = ((IActionHost) cc).getActionableNode();
|
||||
if (node != null && node.isActive()) {
|
||||
active = true;
|
||||
} else {
|
||||
active = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (active) {
|
||||
this.addCellProvider(cc, tracker);
|
||||
} else {
|
||||
this.removeCellProvider(cc, tracker);
|
||||
}
|
||||
}
|
||||
|
||||
this.storageMonitors.forEach((channel, monitor) -> monitor.forceUpdate());
|
||||
|
||||
tracker.applyChanges();
|
||||
}
|
||||
|
||||
private <T extends IAEStack<T>, C extends IStorageChannel<T>> void postChangesToNetwork(final C chan,
|
||||
final int upOrDown, final IItemList<T> availableItems, final IActionSource src) {
|
||||
this.storageMonitors.get(chan).postChange(upOrDown > 0, (Iterable) availableItems, src);
|
||||
}
|
||||
|
||||
private <T extends IAEStack<T>, C extends IStorageChannel<T>> NetworkInventoryHandler<T> buildNetworkStorage(
|
||||
final C chan) {
|
||||
final SecurityCache security = this.getGrid().getCache(ISecurityGrid.class);
|
||||
|
||||
final NetworkInventoryHandler<T> storageNetwork = new NetworkInventoryHandler<>(chan, security);
|
||||
|
||||
for (final ICellProvider cc : this.activeCellProviders) {
|
||||
for (final IMEInventoryHandler<T> h : cc.getCellArray(chan)) {
|
||||
storageNetwork.addNewStorage(h);
|
||||
}
|
||||
}
|
||||
|
||||
return storageNetwork;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postAlterationOfStoredItems(final IStorageChannel<?> chan, final Iterable<? extends IAEStack<?>> input,
|
||||
final IActionSource src) {
|
||||
this.storageMonitors.get(chan).postChange(true, (Iterable) input, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCellProvider(final ICellProvider provider) {
|
||||
this.inactiveCellProviders.add(provider);
|
||||
this.addCellProvider(provider, new CellChangeTracker()).applyChanges();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterCellProvider(final ICellProvider provider) {
|
||||
this.removeCellProvider(provider, new CellChangeTracker()).applyChanges();
|
||||
this.inactiveCellProviders.remove(provider);
|
||||
}
|
||||
|
||||
public GenericInterestManager<ItemWatcher> getInterestManager() {
|
||||
return this.interestManager;
|
||||
}
|
||||
|
||||
IGrid getGrid() {
|
||||
return this.myGrid;
|
||||
}
|
||||
|
||||
private class CellChangeTrackerRecord<T extends IAEStack<T>> {
|
||||
|
||||
final IStorageChannel<T> channel;
|
||||
final int up_or_down;
|
||||
final IItemList<T> list;
|
||||
final IActionSource src;
|
||||
|
||||
public CellChangeTrackerRecord(final IStorageChannel<T> channel, final int i, final IMEInventoryHandler<T> h,
|
||||
final IActionSource actionSrc) {
|
||||
this.channel = channel;
|
||||
this.up_or_down = i;
|
||||
this.src = actionSrc;
|
||||
|
||||
this.list = h.getAvailableItems(channel.createList());
|
||||
}
|
||||
|
||||
public void applyChanges() {
|
||||
GridStorageCache.this.postChangesToNetwork(this.channel, this.up_or_down, this.list, this.src);
|
||||
}
|
||||
}
|
||||
|
||||
private class CellChangeTracker<T extends IAEStack<T>> {
|
||||
|
||||
final List<CellChangeTrackerRecord<T>> data = new ArrayList<>();
|
||||
|
||||
public void postChanges(final IStorageChannel<T> channel, final int i, final IMEInventoryHandler<T> h,
|
||||
final IActionSource actionSrc) {
|
||||
this.data.add(new CellChangeTrackerRecord<T>(channel, i, h, actionSrc));
|
||||
}
|
||||
|
||||
public void applyChanges() {
|
||||
for (final CellChangeTrackerRecord<T> rec : this.data) {
|
||||
rec.applyChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-286
@@ -1,286 +0,0 @@
|
||||
/*
|
||||
* 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.me.cache;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.annotation.Nonnegative;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Queues;
|
||||
|
||||
import appeng.api.config.AccessRestriction;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.networking.events.MENetworkStorageEvent;
|
||||
import appeng.api.networking.security.IActionSource;
|
||||
import appeng.api.storage.IMEInventoryHandler;
|
||||
import appeng.api.storage.IMEMonitor;
|
||||
import appeng.api.storage.IMEMonitorHandlerReceiver;
|
||||
import appeng.api.storage.IStorageChannel;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.me.storage.ItemWatcher;
|
||||
|
||||
public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T> {
|
||||
@Nonnull
|
||||
private static final Deque<NetworkMonitor<?>> GLOBAL_DEPTH = Queues.newArrayDeque();
|
||||
|
||||
@Nonnull
|
||||
private final GridStorageCache myGridCache;
|
||||
@Nonnull
|
||||
private final IStorageChannel<T> myChannel;
|
||||
@Nonnull
|
||||
private final IItemList<T> cachedList;
|
||||
@Nonnull
|
||||
private final Map<IMEMonitorHandlerReceiver<T>, Object> listeners;
|
||||
|
||||
private boolean sendEvent = false;
|
||||
private boolean hasChanged = false;
|
||||
@Nonnegative
|
||||
private int localDepthSemaphore = 0;
|
||||
|
||||
public NetworkMonitor(final GridStorageCache cache, final IStorageChannel<T> chan) {
|
||||
this.myGridCache = cache;
|
||||
this.myChannel = chan;
|
||||
this.cachedList = chan.createList();
|
||||
this.listeners = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(final IMEMonitorHandlerReceiver<T> l, final Object verificationToken) {
|
||||
this.listeners.put(l, verificationToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAccept(final T input) {
|
||||
return this.getHandler().canAccept(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T extractItems(final T request, final Actionable mode, final IActionSource src) {
|
||||
if (mode == Actionable.SIMULATE) {
|
||||
return this.getHandler().extractItems(request, mode, src);
|
||||
}
|
||||
|
||||
this.localDepthSemaphore++;
|
||||
final T leftover = this.getHandler().extractItems(request, mode, src);
|
||||
this.localDepthSemaphore--;
|
||||
|
||||
if (this.localDepthSemaphore == 0) {
|
||||
this.monitorDifference(request.copy(), leftover, true, src);
|
||||
}
|
||||
|
||||
return leftover;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessRestriction getAccess() {
|
||||
return this.getHandler().getAccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<T> getAvailableItems(final IItemList<T> out) {
|
||||
return this.getHandler().getAvailableItems(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IStorageChannel<T> getChannel() {
|
||||
return this.getHandler().getChannel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority() {
|
||||
return this.getHandler().getPriority();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlot() {
|
||||
return this.getHandler().getSlot();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public IItemList<T> getStorageList() {
|
||||
if (this.hasChanged) {
|
||||
this.hasChanged = false;
|
||||
this.cachedList.resetStatus();
|
||||
return this.getAvailableItems(this.cachedList);
|
||||
}
|
||||
|
||||
return this.cachedList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T injectItems(final T input, final Actionable mode, final IActionSource src) {
|
||||
if (mode == Actionable.SIMULATE) {
|
||||
return this.getHandler().injectItems(input, mode, src);
|
||||
}
|
||||
|
||||
this.localDepthSemaphore++;
|
||||
final T leftover = this.getHandler().injectItems(input, mode, src);
|
||||
this.localDepthSemaphore--;
|
||||
|
||||
if (this.localDepthSemaphore == 0) {
|
||||
this.monitorDifference(input.copy(), leftover, false, src);
|
||||
}
|
||||
|
||||
return leftover;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrioritized(final T input) {
|
||||
return this.getHandler().isPrioritized(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(final IMEMonitorHandlerReceiver<T> l) {
|
||||
this.listeners.remove(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validForPass(final int i) {
|
||||
return this.getHandler().validForPass(i);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private IMEInventoryHandler<T> getHandler() {
|
||||
return this.myGridCache.getInventoryHandler(this.myChannel);
|
||||
}
|
||||
|
||||
private Iterator<Entry<IMEMonitorHandlerReceiver<T>, Object>> getListeners() {
|
||||
return this.listeners.entrySet().iterator();
|
||||
}
|
||||
|
||||
private T monitorDifference(final IAEStack<T> original, final T leftOvers, final boolean extraction,
|
||||
final IActionSource src) {
|
||||
final T diff = original.copy();
|
||||
|
||||
if (extraction) {
|
||||
diff.setStackSize(leftOvers == null ? 0 : -leftOvers.getStackSize());
|
||||
} else if (leftOvers != null) {
|
||||
diff.decStackSize(leftOvers.getStackSize());
|
||||
}
|
||||
|
||||
if (diff.getStackSize() != 0) {
|
||||
this.postChangesToListeners(ImmutableList.of(diff), src);
|
||||
}
|
||||
|
||||
return leftOvers;
|
||||
}
|
||||
|
||||
private void notifyListenersOfChange(final Iterable<T> diff, final IActionSource src) {
|
||||
this.hasChanged = true;
|
||||
final Iterator<Entry<IMEMonitorHandlerReceiver<T>, Object>> i = this.getListeners();
|
||||
|
||||
while (i.hasNext()) {
|
||||
final Entry<IMEMonitorHandlerReceiver<T>, Object> o = i.next();
|
||||
final IMEMonitorHandlerReceiver<T> receiver = o.getKey();
|
||||
if (receiver.isValid(o.getValue())) {
|
||||
receiver.postChange(this, diff, src);
|
||||
} else {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void postChangesToListeners(final Iterable<T> changes, final IActionSource src) {
|
||||
this.postChange(true, changes, src);
|
||||
}
|
||||
|
||||
protected void postChange(final boolean add, final Iterable<T> changes, final IActionSource src) {
|
||||
if (this.localDepthSemaphore > 0 || GLOBAL_DEPTH.contains(this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
GLOBAL_DEPTH.push(this);
|
||||
this.localDepthSemaphore++;
|
||||
|
||||
this.sendEvent = true;
|
||||
|
||||
this.notifyListenersOfChange(changes, src);
|
||||
|
||||
for (final T changedItem : changes) {
|
||||
T difference = changedItem;
|
||||
|
||||
if (!add && changedItem != null) {
|
||||
difference = changedItem.copy();
|
||||
difference.setStackSize(-changedItem.getStackSize());
|
||||
}
|
||||
|
||||
if (this.myGridCache.getInterestManager().containsKey(changedItem)) {
|
||||
final Collection<ItemWatcher> list = this.myGridCache.getInterestManager().get(changedItem);
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
IAEStack<T> fullStack = this.getStorageList().findPrecise(changedItem);
|
||||
|
||||
if (fullStack == null) {
|
||||
fullStack = changedItem.copy();
|
||||
fullStack.setStackSize(0);
|
||||
}
|
||||
|
||||
this.myGridCache.getInterestManager().enableTransactions();
|
||||
|
||||
for (final ItemWatcher iw : list) {
|
||||
iw.getHost().onStackChange(this.getStorageList(), fullStack, difference, src,
|
||||
this.getChannel());
|
||||
}
|
||||
|
||||
this.myGridCache.getInterestManager().disableTransactions();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final NetworkMonitor<?> last = GLOBAL_DEPTH.pop();
|
||||
this.localDepthSemaphore--;
|
||||
|
||||
if (last != this) {
|
||||
throw new IllegalStateException("Invalid Access to Networked Storage API detected.");
|
||||
}
|
||||
}
|
||||
|
||||
void forceUpdate() {
|
||||
this.hasChanged = true;
|
||||
|
||||
final Iterator<Entry<IMEMonitorHandlerReceiver<T>, Object>> i = this.getListeners();
|
||||
while (i.hasNext()) {
|
||||
final Entry<IMEMonitorHandlerReceiver<T>, Object> o = i.next();
|
||||
final IMEMonitorHandlerReceiver<T> receiver = o.getKey();
|
||||
|
||||
if (receiver.isValid(o.getValue())) {
|
||||
receiver.onListUpdate();
|
||||
} else {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onTick() {
|
||||
if (this.sendEvent) {
|
||||
this.sendEvent = false;
|
||||
this.myGridCache.getGrid().postEvent(new MENetworkStorageEvent(this, this.myChannel));
|
||||
}
|
||||
}
|
||||
}
|
||||
-371
@@ -1,371 +0,0 @@
|
||||
/*
|
||||
* 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.me.cache;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.features.AEFeature;
|
||||
import appeng.api.networking.GridFlags;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridBlock;
|
||||
import appeng.api.networking.IGridConnection;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridMultiblock;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridStorage;
|
||||
import appeng.api.networking.events.MENetworkBootingStatusChange;
|
||||
import appeng.api.networking.events.MENetworkChannelChanged;
|
||||
import appeng.api.networking.events.MENetworkControllerChange;
|
||||
import appeng.api.networking.events.MENetworkEventSubscribe;
|
||||
import appeng.api.networking.pathing.ControllerState;
|
||||
import appeng.api.networking.pathing.IPathingGrid;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.api.util.DimensionalCoord;
|
||||
import appeng.core.AEConfig;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.core.stats.IAdvancementTrigger;
|
||||
import appeng.me.GridConnection;
|
||||
import appeng.me.GridNode;
|
||||
import appeng.me.pathfinding.AdHocChannelUpdater;
|
||||
import appeng.me.pathfinding.ControllerChannelUpdater;
|
||||
import appeng.me.pathfinding.ControllerValidator;
|
||||
import appeng.me.pathfinding.IPathItem;
|
||||
import appeng.me.pathfinding.PathSegment;
|
||||
import appeng.tile.networking.ControllerBlockEntity;
|
||||
|
||||
public class PathGridCache implements IPathingGrid {
|
||||
|
||||
private final List<PathSegment> active = new ArrayList<>();
|
||||
private final Set<ControllerBlockEntity> controllers = new HashSet<>();
|
||||
private final Set<IGridNode> requireChannels = new HashSet<>();
|
||||
private final Set<IGridNode> blockDense = new HashSet<>();
|
||||
private final IGrid myGrid;
|
||||
private int channelsInUse = 0;
|
||||
private int channelsByBlocks = 0;
|
||||
private double channelPowerUsage = 0.0;
|
||||
private boolean recalculateControllerNextTick = true;
|
||||
private boolean updateNetwork = true;
|
||||
private boolean booting = false;
|
||||
private ControllerState controllerState = ControllerState.NO_CONTROLLER;
|
||||
private int ticksUntilReady = 20;
|
||||
private int lastChannels = 0;
|
||||
private HashSet<IPathItem> semiOpen = new HashSet<>();
|
||||
|
||||
public PathGridCache(final IGrid g) {
|
||||
this.myGrid = g;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateTick() {
|
||||
if (this.recalculateControllerNextTick) {
|
||||
this.recalcController();
|
||||
}
|
||||
|
||||
if (this.updateNetwork) {
|
||||
if (!this.booting) {
|
||||
this.myGrid.postEvent(new MENetworkBootingStatusChange());
|
||||
}
|
||||
|
||||
this.booting = true;
|
||||
this.updateNetwork = false;
|
||||
this.setChannelsInUse(0);
|
||||
|
||||
if (this.controllerState == ControllerState.NO_CONTROLLER) {
|
||||
final int requiredChannels = this.calculateRequiredChannels();
|
||||
int used = requiredChannels;
|
||||
if (requiredChannels > 8) {
|
||||
used = 0;
|
||||
}
|
||||
|
||||
final int nodes = this.myGrid.getNodes().size();
|
||||
this.setChannelsInUse(used);
|
||||
|
||||
this.ticksUntilReady = 20 + Math.max(0, nodes / 100 - 20);
|
||||
this.setChannelsByBlocks(nodes * used);
|
||||
this.setChannelPowerUsage(this.getChannelsByBlocks() / 128.0);
|
||||
|
||||
this.myGrid.getPivot().beginVisit(new AdHocChannelUpdater(used));
|
||||
} else if (this.controllerState == ControllerState.CONTROLLER_CONFLICT) {
|
||||
this.ticksUntilReady = 20;
|
||||
this.myGrid.getPivot().beginVisit(new AdHocChannelUpdater(0));
|
||||
} else {
|
||||
final int nodes = this.myGrid.getNodes().size();
|
||||
this.ticksUntilReady = 20 + Math.max(0, nodes / 100 - 20);
|
||||
final HashSet<IPathItem> closedList = new HashSet<>();
|
||||
this.semiOpen = new HashSet<>();
|
||||
|
||||
// myGrid.getPivot().beginVisit( new AdHocChannelUpdater( 0 )
|
||||
// );
|
||||
for (final IGridNode node : this.myGrid.getMachines(ControllerBlockEntity.class)) {
|
||||
closedList.add((IPathItem) node);
|
||||
for (final IGridConnection gcc : node.getConnections()) {
|
||||
final GridConnection gc = (GridConnection) gcc;
|
||||
if (!(gc.getOtherSide(node).getMachine() instanceof ControllerBlockEntity)) {
|
||||
final List<IPathItem> open = new ArrayList<>();
|
||||
closedList.add(gc);
|
||||
open.add(gc);
|
||||
gc.setControllerRoute((GridNode) node, true);
|
||||
this.active.add(new PathSegment(this, open, this.semiOpen, closedList));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.active.isEmpty() || this.ticksUntilReady > 0) {
|
||||
final Iterator<PathSegment> i = this.active.iterator();
|
||||
while (i.hasNext()) {
|
||||
final PathSegment pat = i.next();
|
||||
if (pat.step()) {
|
||||
pat.setDead(true);
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
|
||||
this.ticksUntilReady--;
|
||||
|
||||
if (this.active.isEmpty() && this.ticksUntilReady <= 0) {
|
||||
if (this.controllerState == ControllerState.CONTROLLER_ONLINE) {
|
||||
final Iterator<ControllerBlockEntity> controllerIterator = this.controllers.iterator();
|
||||
if (controllerIterator.hasNext()) {
|
||||
final ControllerBlockEntity controller = controllerIterator.next();
|
||||
controller.getGridNode(AEPartLocation.INTERNAL).beginVisit(new ControllerChannelUpdater());
|
||||
}
|
||||
}
|
||||
|
||||
// check for achievements
|
||||
this.achievementPost();
|
||||
|
||||
this.booting = false;
|
||||
this.setChannelPowerUsage(this.getChannelsByBlocks() / 128.0);
|
||||
this.myGrid.postEvent(new MENetworkBootingStatusChange());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNode(final IGridNode gridNode, final IGridHost machine) {
|
||||
if (machine instanceof ControllerBlockEntity) {
|
||||
this.controllers.remove(machine);
|
||||
this.recalculateControllerNextTick = true;
|
||||
}
|
||||
|
||||
final EnumSet<GridFlags> flags = gridNode.getGridBlock().getFlags();
|
||||
|
||||
if (flags.contains(GridFlags.REQUIRE_CHANNEL)) {
|
||||
this.requireChannels.remove(gridNode);
|
||||
}
|
||||
|
||||
if (flags.contains(GridFlags.CANNOT_CARRY_COMPRESSED)) {
|
||||
this.blockDense.remove(gridNode);
|
||||
}
|
||||
|
||||
this.repath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNode(final IGridNode gridNode, final IGridHost machine) {
|
||||
if (machine instanceof ControllerBlockEntity) {
|
||||
this.controllers.add((ControllerBlockEntity) machine);
|
||||
this.recalculateControllerNextTick = true;
|
||||
}
|
||||
|
||||
final EnumSet<GridFlags> flags = gridNode.getGridBlock().getFlags();
|
||||
|
||||
if (flags.contains(GridFlags.REQUIRE_CHANNEL)) {
|
||||
this.requireChannels.add(gridNode);
|
||||
}
|
||||
|
||||
if (flags.contains(GridFlags.CANNOT_CARRY_COMPRESSED)) {
|
||||
this.blockDense.add(gridNode);
|
||||
}
|
||||
|
||||
this.repath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSplit(final IGridStorage storageB) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onJoin(final IGridStorage storageB) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateGridStorage(final IGridStorage storage) {
|
||||
|
||||
}
|
||||
|
||||
private void recalcController() {
|
||||
this.recalculateControllerNextTick = false;
|
||||
final ControllerState old = this.controllerState;
|
||||
|
||||
if (this.controllers.isEmpty()) {
|
||||
this.controllerState = ControllerState.NO_CONTROLLER;
|
||||
} else {
|
||||
final IGridNode startingNode = this.controllers.iterator().next().getGridNode(AEPartLocation.INTERNAL);
|
||||
if (startingNode == null) {
|
||||
this.controllerState = ControllerState.CONTROLLER_CONFLICT;
|
||||
return;
|
||||
}
|
||||
|
||||
final DimensionalCoord dc = startingNode.getGridBlock().getLocation();
|
||||
final ControllerValidator cv = new ControllerValidator(dc.x, dc.y, dc.z);
|
||||
|
||||
startingNode.beginVisit(cv);
|
||||
|
||||
if (cv.isValid() && cv.getFound() == this.controllers.size()) {
|
||||
this.controllerState = ControllerState.CONTROLLER_ONLINE;
|
||||
} else {
|
||||
this.controllerState = ControllerState.CONTROLLER_CONFLICT;
|
||||
}
|
||||
}
|
||||
|
||||
if (old != this.controllerState) {
|
||||
this.myGrid.postEvent(new MENetworkControllerChange());
|
||||
}
|
||||
}
|
||||
|
||||
private int calculateRequiredChannels() {
|
||||
this.semiOpen.clear();
|
||||
|
||||
int depth = 0;
|
||||
for (final IGridNode nodes : this.requireChannels) {
|
||||
if (!this.semiOpen.contains(nodes)) {
|
||||
final IGridBlock gb = nodes.getGridBlock();
|
||||
final EnumSet<GridFlags> flags = gb.getFlags();
|
||||
|
||||
if (flags.contains(GridFlags.COMPRESSED_CHANNEL) && !this.blockDense.isEmpty()) {
|
||||
return 9;
|
||||
}
|
||||
|
||||
depth++;
|
||||
|
||||
if (flags.contains(GridFlags.MULTIBLOCK)) {
|
||||
final IGridMultiblock gmb = (IGridMultiblock) gb;
|
||||
final Iterator<IGridNode> i = gmb.getMultiblockNodes();
|
||||
while (i.hasNext()) {
|
||||
this.semiOpen.add((IPathItem) i.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
private void achievementPost() {
|
||||
if (this.lastChannels != this.getChannelsInUse() && AEConfig.instance().isFeatureEnabled(AEFeature.CHANNELS)) {
|
||||
final IAdvancementTrigger currentBracket = this.getAchievementBracket(this.getChannelsInUse());
|
||||
final IAdvancementTrigger lastBracket = this.getAchievementBracket(this.lastChannels);
|
||||
if (currentBracket != lastBracket && currentBracket != null) {
|
||||
for (final IGridNode n : this.requireChannels) {
|
||||
PlayerEntity player = AEApi.instance().registries().players().findPlayer(n.getPlayerID());
|
||||
if (player instanceof ServerPlayerEntity) {
|
||||
currentBracket.trigger((ServerPlayerEntity) player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.lastChannels = this.getChannelsInUse();
|
||||
}
|
||||
|
||||
private IAdvancementTrigger getAchievementBracket(final int ch) {
|
||||
if (ch < 8) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (ch < 128) {
|
||||
return AppEng.instance().getAdvancementTriggers().getNetworkApprentice();
|
||||
}
|
||||
|
||||
if (ch < 2048) {
|
||||
return AppEng.instance().getAdvancementTriggers().getNetworkEngineer();
|
||||
}
|
||||
|
||||
return AppEng.instance().getAdvancementTriggers().getNetworkAdmin();
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
void updateNodReq(final MENetworkChannelChanged ev) {
|
||||
final IGridNode gridNode = ev.node;
|
||||
|
||||
if (gridNode.getGridBlock().getFlags().contains(GridFlags.REQUIRE_CHANNEL)) {
|
||||
this.requireChannels.add(gridNode);
|
||||
} else {
|
||||
this.requireChannels.remove(gridNode);
|
||||
}
|
||||
|
||||
this.repath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNetworkBooting() {
|
||||
return !this.booting && !this.active.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ControllerState getControllerState() {
|
||||
return this.controllerState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void repath() {
|
||||
// clean up...
|
||||
this.active.clear();
|
||||
|
||||
this.setChannelsByBlocks(0);
|
||||
this.updateNetwork = true;
|
||||
}
|
||||
|
||||
double getChannelPowerUsage() {
|
||||
return this.channelPowerUsage;
|
||||
}
|
||||
|
||||
private void setChannelPowerUsage(final double channelPowerUsage) {
|
||||
this.channelPowerUsage = channelPowerUsage;
|
||||
}
|
||||
|
||||
public int getChannelsByBlocks() {
|
||||
return this.channelsByBlocks;
|
||||
}
|
||||
|
||||
public void setChannelsByBlocks(final int channelsByBlocks) {
|
||||
this.channelsByBlocks = channelsByBlocks;
|
||||
}
|
||||
|
||||
public int getChannelsInUse() {
|
||||
return this.channelsInUse;
|
||||
}
|
||||
|
||||
public void setChannelsInUse(final int channelsInUse) {
|
||||
this.channelsInUse = channelsInUse;
|
||||
}
|
||||
}
|
||||
-169
@@ -1,169 +0,0 @@
|
||||
/*
|
||||
* 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.me.cache;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
|
||||
import appeng.api.config.SecurityPermissions;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridStorage;
|
||||
import appeng.api.networking.events.MENetworkEventSubscribe;
|
||||
import appeng.api.networking.events.MENetworkSecurityChange;
|
||||
import appeng.api.networking.security.ISecurityGrid;
|
||||
import appeng.api.networking.security.ISecurityProvider;
|
||||
import appeng.core.worlddata.WorldData;
|
||||
import appeng.me.GridNode;
|
||||
|
||||
public class SecurityCache implements ISecurityGrid {
|
||||
|
||||
private final IGrid myGrid;
|
||||
private final List<ISecurityProvider> securityProvider = new ArrayList<>();
|
||||
private final HashMap<Integer, EnumSet<SecurityPermissions>> playerPerms = new HashMap<>();
|
||||
private long securityKey = -1;
|
||||
|
||||
public SecurityCache(final IGrid g) {
|
||||
this.myGrid = g;
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void updatePermissions(final MENetworkSecurityChange ev) {
|
||||
this.playerPerms.clear();
|
||||
if (this.securityProvider.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.securityProvider.get(0).readPermissions(this.playerPerms);
|
||||
}
|
||||
|
||||
public long getSecurityKey() {
|
||||
return this.securityKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateTick() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNode(final IGridNode gridNode, final IGridHost machine) {
|
||||
if (machine instanceof ISecurityProvider) {
|
||||
this.securityProvider.remove(machine);
|
||||
this.updateSecurityKey();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSecurityKey() {
|
||||
final long lastCode = this.securityKey;
|
||||
|
||||
if (this.securityProvider.size() == 1) {
|
||||
this.securityKey = this.securityProvider.get(0).getSecurityKey();
|
||||
} else {
|
||||
this.securityKey = -1;
|
||||
}
|
||||
|
||||
if (lastCode != this.securityKey) {
|
||||
this.getGrid().postEvent(new MENetworkSecurityChange());
|
||||
for (final IGridNode n : this.getGrid().getNodes()) {
|
||||
((GridNode) n).setLastSecurityKey(this.securityKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNode(final IGridNode gridNode, final IGridHost machine) {
|
||||
if (machine instanceof ISecurityProvider) {
|
||||
this.securityProvider.add((ISecurityProvider) machine);
|
||||
this.updateSecurityKey();
|
||||
} else {
|
||||
((GridNode) gridNode).setLastSecurityKey(this.securityKey);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSplit(final IGridStorage destinationStorage) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onJoin(final IGridStorage sourceStorage) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateGridStorage(final IGridStorage destinationStorage) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return this.securityProvider.size() == 1 && this.securityProvider.get(0).isSecurityEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(final PlayerEntity player, final SecurityPermissions perm) {
|
||||
Preconditions.checkNotNull(player);
|
||||
Preconditions.checkNotNull(perm);
|
||||
|
||||
final GameProfile profile = player.getGameProfile();
|
||||
final int playerID = WorldData.instance().playerData().getMePlayerId(profile);
|
||||
|
||||
return this.hasPermission(playerID, perm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(final int playerID, final SecurityPermissions perm) {
|
||||
if (this.isAvailable()) {
|
||||
final EnumSet<SecurityPermissions> perms = this.playerPerms.get(playerID);
|
||||
|
||||
if (perms == null) {
|
||||
if (playerID == -1) // no default?
|
||||
{
|
||||
return false;
|
||||
} else {
|
||||
return this.hasPermission(-1, perm);
|
||||
}
|
||||
}
|
||||
|
||||
return perms.contains(perm);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOwner() {
|
||||
if (this.isAvailable()) {
|
||||
return this.securityProvider.get(0).getOwner();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public IGrid getGrid() {
|
||||
return this.myGrid;
|
||||
}
|
||||
}
|
||||
-238
@@ -1,238 +0,0 @@
|
||||
/*
|
||||
* 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.me.cache;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import net.minecraft.util.crash.CrashException;
|
||||
import net.minecraft.util.crash.CrashReport;
|
||||
import net.minecraft.util.crash.CrashReportSection;
|
||||
import net.minecraft.util.crash.CrashException;
|
||||
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridStorage;
|
||||
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.me.cache.helpers.TickTracker;
|
||||
|
||||
public class TickManagerCache implements ITickManager {
|
||||
|
||||
private final IGrid myGrid;
|
||||
private final HashMap<IGridNode, TickTracker> alertable = new HashMap<>();
|
||||
private final HashMap<IGridNode, TickTracker> sleeping = new HashMap<>();
|
||||
private final HashMap<IGridNode, TickTracker> awake = new HashMap<>();
|
||||
private final PriorityQueue<TickTracker> upcomingTicks = new PriorityQueue<>();
|
||||
|
||||
private long currentTick = 0;
|
||||
|
||||
public TickManagerCache(final IGrid g) {
|
||||
this.myGrid = g;
|
||||
}
|
||||
|
||||
public long getCurrentTick() {
|
||||
return this.currentTick;
|
||||
}
|
||||
|
||||
public long getAvgNanoTime(final IGridNode node) {
|
||||
TickTracker tt = this.awake.get(node);
|
||||
|
||||
if (tt == null) {
|
||||
tt = this.sleeping.get(node);
|
||||
}
|
||||
|
||||
if (tt == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return tt.getAvgNanos();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateTick() {
|
||||
TickTracker tt = null;
|
||||
|
||||
try {
|
||||
this.currentTick++;
|
||||
|
||||
while (!this.upcomingTicks.isEmpty()) {
|
||||
tt = this.upcomingTicks.peek();
|
||||
|
||||
// Stop once it reaches a TickTracker running at a later tick
|
||||
if (tt.getNextTick() > this.currentTick) {
|
||||
break;
|
||||
}
|
||||
|
||||
this.upcomingTicks.poll();
|
||||
|
||||
final int diff = (int) (this.currentTick - tt.getLastTick());
|
||||
final TickRateModulation mod = tt.getGridTickable().tickingRequest(tt.getNode(), diff);
|
||||
|
||||
switch (mod) {
|
||||
case FASTER:
|
||||
tt.setCurrentRate(tt.getCurrentRate() - 2);
|
||||
break;
|
||||
case IDLE:
|
||||
tt.setCurrentRate(tt.getRequest().maxTickRate);
|
||||
break;
|
||||
case SAME:
|
||||
break;
|
||||
case SLEEP:
|
||||
this.sleepDevice(tt.getNode());
|
||||
break;
|
||||
case SLOWER:
|
||||
tt.setCurrentRate(tt.getCurrentRate() + 1);
|
||||
break;
|
||||
case URGENT:
|
||||
tt.setCurrentRate(0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.awake.containsKey(tt.getNode())) {
|
||||
this.addToQueue(tt);
|
||||
}
|
||||
}
|
||||
} catch (final Throwable t) {
|
||||
final CrashReport crashreport = CrashReport.create(t, "Ticking GridNode");
|
||||
final CrashReportSection section = crashreport
|
||||
.addElement(tt.getGridTickable().getClass().getSimpleName() + " being ticked.");
|
||||
tt.addEntityCrashInfo(section);
|
||||
throw new CrashException(crashreport);
|
||||
}
|
||||
}
|
||||
|
||||
private void addToQueue(final TickTracker tt) {
|
||||
tt.setLastTick(this.currentTick);
|
||||
this.upcomingTicks.add(tt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNode(final IGridNode gridNode, final IGridHost machine) {
|
||||
if (machine instanceof IGridTickable) {
|
||||
this.alertable.remove(gridNode);
|
||||
this.sleeping.remove(gridNode);
|
||||
this.awake.remove(gridNode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNode(final IGridNode gridNode, final IGridHost machine) {
|
||||
if (machine instanceof IGridTickable) {
|
||||
final IGridTickable tickable = ((IGridTickable) machine);
|
||||
final TickingRequest tr = tickable.getTickingRequest(gridNode);
|
||||
|
||||
Preconditions.checkNotNull(tr);
|
||||
|
||||
final TickTracker tt = new TickTracker(tr, gridNode, (IGridTickable) machine, this.currentTick, this);
|
||||
|
||||
if (tr.canBeAlerted) {
|
||||
this.alertable.put(gridNode, tt);
|
||||
}
|
||||
|
||||
if (tr.isSleeping) {
|
||||
this.sleeping.put(gridNode, tt);
|
||||
} else {
|
||||
this.awake.put(gridNode, tt);
|
||||
this.addToQueue(tt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSplit(final IGridStorage storageB) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onJoin(final IGridStorage storageB) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateGridStorage(final IGridStorage storage) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean alertDevice(final IGridNode node) {
|
||||
Preconditions.checkNotNull(node);
|
||||
|
||||
final TickTracker tt = this.alertable.get(node);
|
||||
if (tt == null) {
|
||||
return false;
|
||||
}
|
||||
// throw new RuntimeException(
|
||||
// "Invalid alerted device, this node is not marked as alertable, or part of
|
||||
// this grid." );
|
||||
|
||||
// set to awake, this is for sanity.
|
||||
this.sleeping.remove(node);
|
||||
this.awake.put(node, tt);
|
||||
|
||||
// configure sort.
|
||||
tt.setLastTick(tt.getLastTick() - tt.getRequest().maxTickRate);
|
||||
tt.setCurrentRate(tt.getRequest().minTickRate);
|
||||
|
||||
// prevent dupes and tick build up.
|
||||
this.upcomingTicks.remove(tt);
|
||||
this.upcomingTicks.add(tt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sleepDevice(final IGridNode node) {
|
||||
Preconditions.checkNotNull(node);
|
||||
|
||||
if (this.awake.containsKey(node)) {
|
||||
final TickTracker gt = this.awake.get(node);
|
||||
this.awake.remove(node);
|
||||
this.sleeping.put(node, gt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wakeDevice(final IGridNode node) {
|
||||
Preconditions.checkNotNull(node);
|
||||
|
||||
if (this.sleeping.containsKey(node)) {
|
||||
final TickTracker gt = this.sleeping.get(node);
|
||||
this.sleeping.remove(node);
|
||||
this.awake.put(node, gt);
|
||||
this.upcomingTicks.remove(gt);
|
||||
this.addToQueue(gt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* 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.me.cache.helpers;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import net.minecraft.util.crash.CrashReportSection;
|
||||
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.ticking.IGridTickable;
|
||||
import appeng.api.networking.ticking.TickingRequest;
|
||||
import appeng.api.util.DimensionalCoord;
|
||||
import appeng.me.cache.TickManagerCache;
|
||||
import appeng.parts.AEBasePart;
|
||||
import net.minecraft.util.crash.CrashReportSection;
|
||||
|
||||
public class TickTracker implements Comparable<TickTracker> {
|
||||
|
||||
private final TickingRequest request;
|
||||
private final IGridTickable gt;
|
||||
private final IGridNode node;
|
||||
|
||||
private final long LastFiveTicksTime = 0;
|
||||
|
||||
private long lastTick;
|
||||
private int currentRate;
|
||||
|
||||
public TickTracker(final TickingRequest req, final IGridNode node, final IGridTickable gt, final long currentTick,
|
||||
final TickManagerCache tickManagerCache) {
|
||||
this.request = req;
|
||||
this.gt = gt;
|
||||
this.node = node;
|
||||
this.setCurrentRate((req.minTickRate + req.maxTickRate) / 2);
|
||||
this.setLastTick(currentTick);
|
||||
}
|
||||
|
||||
public long getAvgNanos() {
|
||||
return (this.LastFiveTicksTime / 5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@Nonnull final TickTracker t) {
|
||||
int next = Long.compare(this.getNextTick(), t.getNextTick());
|
||||
|
||||
if (next != 0) {
|
||||
return next;
|
||||
}
|
||||
|
||||
int last = Long.compare(this.getLastTick(), t.getLastTick());
|
||||
|
||||
if (last != 0) {
|
||||
return last;
|
||||
}
|
||||
|
||||
return Integer.compare(this.getCurrentRate(), t.getCurrentRate());
|
||||
|
||||
}
|
||||
|
||||
public void addEntityCrashInfo(final CrashReportSection section) {
|
||||
if (this.getGridTickable() instanceof AEBasePart) {
|
||||
final AEBasePart part = (AEBasePart) this.getGridTickable();
|
||||
part.addEntityCrashInfo(section);
|
||||
}
|
||||
|
||||
section.add("CurrentTickRate", this.getCurrentRate());
|
||||
section.add("MinTickRate", this.getRequest().minTickRate);
|
||||
section.add("MaxTickRate", this.getRequest().maxTickRate);
|
||||
section.add("MachineType", this.getGridTickable().getClass().getName());
|
||||
section.add("GridBlockType", this.getNode().getGridBlock().getClass().getName());
|
||||
section.add("ConnectedSides", this.getNode().getConnectedSides());
|
||||
|
||||
final DimensionalCoord dc = this.getNode().getGridBlock().getLocation();
|
||||
if (dc != null) {
|
||||
section.add("Location", dc);
|
||||
}
|
||||
}
|
||||
|
||||
public int getCurrentRate() {
|
||||
return this.currentRate;
|
||||
}
|
||||
|
||||
public void setCurrentRate(final int currentRate) {
|
||||
this.currentRate = Math.min(this.getRequest().maxTickRate,
|
||||
Math.max(this.getRequest().minTickRate, currentRate));
|
||||
}
|
||||
|
||||
public long getNextTick() {
|
||||
return this.lastTick + this.currentRate;
|
||||
}
|
||||
|
||||
public long getLastTick() {
|
||||
return this.lastTick;
|
||||
}
|
||||
|
||||
public void setLastTick(final long lastTick) {
|
||||
this.lastTick = lastTick;
|
||||
}
|
||||
|
||||
public IGridNode getNode() {
|
||||
return this.node;
|
||||
}
|
||||
|
||||
public IGridTickable getGridTickable() {
|
||||
return this.gt;
|
||||
}
|
||||
|
||||
public TickingRequest getRequest() {
|
||||
return this.request;
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* 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.me.cluster;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import appeng.api.networking.IGridHost;
|
||||
|
||||
public interface IAECluster {
|
||||
|
||||
void updateStatus(boolean updateGrid);
|
||||
|
||||
void destroy();
|
||||
|
||||
Iterator<IGridHost> getTiles();
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* 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.me.cluster;
|
||||
|
||||
public interface IAEMultiBlock {
|
||||
|
||||
void disconnect(boolean b);
|
||||
|
||||
IAECluster getCluster();
|
||||
|
||||
boolean isValid();
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* 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.me.energy;
|
||||
|
||||
import appeng.api.networking.energy.IEnergyWatcher;
|
||||
|
||||
public class EnergyThreshold implements Comparable<EnergyThreshold> {
|
||||
|
||||
private final double threshold;
|
||||
private final IEnergyWatcher watcher;
|
||||
private final int watcherHash;
|
||||
|
||||
public EnergyThreshold(final double lim, final IEnergyWatcher watcher) {
|
||||
this.threshold = lim;
|
||||
this.watcher = watcher;
|
||||
this.watcherHash = watcher.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Special constructor to allow querying a for a subset of thresholds.
|
||||
*
|
||||
* @param lim
|
||||
* @param bound
|
||||
*/
|
||||
public EnergyThreshold(final double lim, final int bound) {
|
||||
this.threshold = lim;
|
||||
this.watcher = null;
|
||||
this.watcherHash = bound;
|
||||
}
|
||||
|
||||
public IEnergyWatcher getEnergyWatcher() {
|
||||
return this.watcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(EnergyThreshold o) {
|
||||
int a = Double.compare(this.threshold, o.threshold);
|
||||
|
||||
if (a == 0) {
|
||||
return Integer.compare(this.watcherHash, o.watcherHash);
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
long temp;
|
||||
temp = Double.doubleToLongBits(this.threshold);
|
||||
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||
result = prime * result + ((this.watcher == null) ? 0 : this.watcher.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (this.getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EnergyThreshold other = (EnergyThreshold) obj;
|
||||
if (Double.doubleToLongBits(this.threshold) != Double.doubleToLongBits(other.threshold)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.watcher == null) {
|
||||
if (other.watcher != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!this.watcher.equals(other.watcher)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* 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.me.energy;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import appeng.api.networking.energy.IEnergyWatcher;
|
||||
import appeng.api.networking.energy.IEnergyWatcherHost;
|
||||
import appeng.me.cache.EnergyGridCache;
|
||||
|
||||
/**
|
||||
* Maintain my interests, and a global watch list, they should always be fully
|
||||
* synchronized.
|
||||
*/
|
||||
public class EnergyWatcher implements IEnergyWatcher {
|
||||
|
||||
private final EnergyGridCache gsc;
|
||||
private final IEnergyWatcherHost watcherHost;
|
||||
private final Set<EnergyThreshold> myInterests = new HashSet<>();
|
||||
|
||||
public EnergyWatcher(final EnergyGridCache cache, final IEnergyWatcherHost host) {
|
||||
this.gsc = cache;
|
||||
this.watcherHost = host;
|
||||
}
|
||||
|
||||
public void post(final EnergyGridCache energyGridCache) {
|
||||
this.watcherHost.onThresholdPass(energyGridCache);
|
||||
}
|
||||
|
||||
public IEnergyWatcherHost getHost() {
|
||||
return this.watcherHost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(final double amount) {
|
||||
final EnergyThreshold eh = new EnergyThreshold(amount, this);
|
||||
|
||||
if (this.myInterests.contains(eh))
|
||||
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.gsc.registerEnergyInterest(eh) && this.myInterests.add(eh);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(final double amount) {
|
||||
final EnergyThreshold eh = new EnergyThreshold(amount, this);
|
||||
|
||||
return this.myInterests.remove(eh) && this.gsc.unregisterEnergyInterest(eh);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
for (Iterator<EnergyThreshold> iterator = this.myInterests.iterator(); iterator.hasNext();) {
|
||||
final EnergyThreshold threshold = iterator.next();
|
||||
|
||||
this.gsc.unregisterEnergyInterest(threshold);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* 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.me.helpers;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
|
||||
import appeng.api.networking.security.IActionHost;
|
||||
import appeng.api.networking.security.IActionSource;
|
||||
|
||||
public class BaseActionSource implements IActionSource {
|
||||
|
||||
@Override
|
||||
public Optional<PlayerEntity> player() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<IActionHost> machine() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Optional<T> context(Class<T> key) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* 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.me.helpers;
|
||||
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.config.PowerMultiplier;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.energy.IEnergySource;
|
||||
|
||||
public class ChannelPowerSrc implements IEnergySource {
|
||||
|
||||
private final IGridNode node;
|
||||
private final IEnergySource realSrc;
|
||||
|
||||
public ChannelPowerSrc(final IGridNode networkNode, final IEnergySource src) {
|
||||
this.node = networkNode;
|
||||
this.realSrc = src;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double extractAEPower(final double amt, final Actionable mode, final PowerMultiplier usePowerMultiplier) {
|
||||
if (this.node.isActive()) {
|
||||
return this.realSrc.extractAEPower(amt, mode, usePowerMultiplier);
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* 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.me.helpers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
|
||||
public class GenericInterestManager<T> {
|
||||
|
||||
private final Multimap<IAEStack, T> container;
|
||||
private List<SavedTransactions> transactions = null;
|
||||
private int transDepth = 0;
|
||||
|
||||
public GenericInterestManager(final Multimap<IAEStack, T> interests) {
|
||||
this.container = interests;
|
||||
}
|
||||
|
||||
public void enableTransactions() {
|
||||
if (this.transDepth == 0) {
|
||||
this.transactions = new ArrayList<>();
|
||||
}
|
||||
|
||||
this.transDepth++;
|
||||
}
|
||||
|
||||
public void disableTransactions() {
|
||||
this.transDepth--;
|
||||
|
||||
if (this.transDepth == 0) {
|
||||
final List<SavedTransactions> myActions = this.transactions;
|
||||
this.transactions = null;
|
||||
|
||||
for (final SavedTransactions t : myActions) {
|
||||
if (t.put) {
|
||||
this.put(t.stack, t.iw);
|
||||
} else {
|
||||
this.remove(t.stack, t.iw);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean put(final IAEStack stack, final T iw) {
|
||||
if (this.transactions != null) {
|
||||
this.transactions.add(new SavedTransactions(true, stack, iw));
|
||||
return true;
|
||||
} else {
|
||||
return this.container.put(stack, iw);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean remove(final IAEStack stack, final T iw) {
|
||||
if (this.transactions != null) {
|
||||
this.transactions.add(new SavedTransactions(false, stack, iw));
|
||||
return true;
|
||||
} else {
|
||||
return this.container.remove(stack, iw);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean containsKey(final IAEStack stack) {
|
||||
return this.container.containsKey(stack);
|
||||
}
|
||||
|
||||
public Collection<T> get(final IAEStack stack) {
|
||||
return this.container.get(stack);
|
||||
}
|
||||
|
||||
private class SavedTransactions {
|
||||
|
||||
private final boolean put;
|
||||
private final IAEStack stack;
|
||||
private final T iw;
|
||||
|
||||
public SavedTransactions(final boolean putOperation, final IAEStack myStack, final T watcher) {
|
||||
this.put = putOperation;
|
||||
this.stack = myStack;
|
||||
this.iw = watcher;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,188 +0,0 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013 AlgorithmX2
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package appeng.me.helpers;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import appeng.api.config.AccessRestriction;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.networking.security.IActionSource;
|
||||
import appeng.api.storage.IMEInventoryHandler;
|
||||
import appeng.api.storage.IMEMonitor;
|
||||
import appeng.api.storage.IMEMonitorHandlerReceiver;
|
||||
import appeng.api.storage.IStorageChannel;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
|
||||
/**
|
||||
* Common implementation of a simple class that monitors injection/extraction of
|
||||
* a inventory to send events to a list of listeners.
|
||||
*
|
||||
* @param <T>
|
||||
*
|
||||
* TODO: Needs to be redesigned to solve performance issues.
|
||||
*/
|
||||
public class MEMonitorHandler<T extends IAEStack<T>> implements IMEMonitor<T> {
|
||||
|
||||
private final IMEInventoryHandler<T> internalHandler;
|
||||
private final IItemList<T> cachedList;
|
||||
private final HashMap<IMEMonitorHandlerReceiver<T>, Object> listeners = new HashMap<>();
|
||||
|
||||
protected boolean hasChanged = true;
|
||||
|
||||
public MEMonitorHandler(final IMEInventoryHandler<T> t) {
|
||||
this.internalHandler = t;
|
||||
this.cachedList = t.getChannel().createList();
|
||||
}
|
||||
|
||||
public MEMonitorHandler(final IMEInventoryHandler<T> t, final IStorageChannel<T> chan) {
|
||||
this.internalHandler = t;
|
||||
this.cachedList = chan.createList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(final IMEMonitorHandlerReceiver<T> l, final Object verificationToken) {
|
||||
this.listeners.put(l, verificationToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(final IMEMonitorHandlerReceiver<T> l) {
|
||||
this.listeners.remove(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T injectItems(final T input, final Actionable mode, final IActionSource src) {
|
||||
if (mode == Actionable.SIMULATE) {
|
||||
return this.getHandler().injectItems(input, mode, src);
|
||||
}
|
||||
return this.monitorDifference(input.copy(), this.getHandler().injectItems(input, mode, src), false, src);
|
||||
}
|
||||
|
||||
protected IMEInventoryHandler<T> getHandler() {
|
||||
return this.internalHandler;
|
||||
}
|
||||
|
||||
private T monitorDifference(final T original, final T leftOvers, final boolean extraction,
|
||||
final IActionSource src) {
|
||||
final T diff = original.copy();
|
||||
|
||||
if (extraction) {
|
||||
diff.setStackSize(leftOvers == null ? 0 : -leftOvers.getStackSize());
|
||||
} else if (leftOvers != null) {
|
||||
diff.decStackSize(leftOvers.getStackSize());
|
||||
}
|
||||
|
||||
if (diff.getStackSize() != 0) {
|
||||
this.postChangesToListeners(ImmutableList.of(diff), src);
|
||||
}
|
||||
|
||||
return leftOvers;
|
||||
}
|
||||
|
||||
protected void postChangesToListeners(final Iterable<T> changes, final IActionSource src) {
|
||||
this.notifyListenersOfChange(changes, src);
|
||||
}
|
||||
|
||||
protected void notifyListenersOfChange(final Iterable<T> diff, final IActionSource src) {
|
||||
this.hasChanged = true;// need to update the cache.
|
||||
final Iterator<Entry<IMEMonitorHandlerReceiver<T>, Object>> i = this.getListeners();
|
||||
while (i.hasNext()) {
|
||||
final Entry<IMEMonitorHandlerReceiver<T>, Object> o = i.next();
|
||||
final IMEMonitorHandlerReceiver<T> receiver = o.getKey();
|
||||
if (receiver.isValid(o.getValue())) {
|
||||
receiver.postChange(this, diff, src);
|
||||
} else {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Iterator<Entry<IMEMonitorHandlerReceiver<T>, Object>> getListeners() {
|
||||
return this.listeners.entrySet().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T extractItems(final T request, final Actionable mode, final IActionSource src) {
|
||||
if (mode == Actionable.SIMULATE) {
|
||||
return this.getHandler().extractItems(request, mode, src);
|
||||
}
|
||||
return this.monitorDifference(request.copy(), this.getHandler().extractItems(request, mode, src), true, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IStorageChannel<T> getChannel() {
|
||||
return this.getHandler().getChannel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessRestriction getAccess() {
|
||||
return this.getHandler().getAccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<T> getStorageList() {
|
||||
if (this.hasChanged) {
|
||||
this.hasChanged = false;
|
||||
this.cachedList.resetStatus();
|
||||
return this.getAvailableItems(this.cachedList);
|
||||
}
|
||||
|
||||
return this.cachedList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrioritized(final T input) {
|
||||
return this.getHandler().isPrioritized(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAccept(final T input) {
|
||||
return this.getHandler().canAccept(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<T> getAvailableItems(final IItemList<T> out) {
|
||||
return this.getHandler().getAvailableItems(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority() {
|
||||
return this.getHandler().getPriority();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlot() {
|
||||
return this.getHandler().getSlot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validForPass(final int i) {
|
||||
return this.getHandler().validForPass(i);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* 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.me.helpers;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
|
||||
import appeng.api.networking.security.IActionHost;
|
||||
import appeng.api.networking.security.IActionSource;
|
||||
|
||||
public class MachineSource implements IActionSource {
|
||||
|
||||
private final IActionHost via;
|
||||
|
||||
public MachineSource(final IActionHost v) {
|
||||
this.via = v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<PlayerEntity> player() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<IActionHost> machine() {
|
||||
return Optional.of(this.via);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Optional<T> context(Class<T> key) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* 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.me.helpers;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
|
||||
import appeng.api.networking.security.IActionHost;
|
||||
import appeng.api.networking.security.IActionSource;
|
||||
|
||||
public class PlayerSource implements IActionSource {
|
||||
|
||||
private final PlayerEntity player;
|
||||
private final IActionHost via;
|
||||
|
||||
public PlayerSource(final PlayerEntity p, final IActionHost v) {
|
||||
Preconditions.checkNotNull(p);
|
||||
this.player = p;
|
||||
this.via = v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<PlayerEntity> player() {
|
||||
return Optional.of(this.player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<IActionHost> machine() {
|
||||
return Optional.ofNullable(this.via);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Optional<T> context(Class<T> key) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* 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.me.pathfinding;
|
||||
|
||||
import appeng.api.networking.IGridConnection;
|
||||
import appeng.api.networking.IGridConnectionVisitor;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.me.GridConnection;
|
||||
import appeng.me.GridNode;
|
||||
|
||||
public class AdHocChannelUpdater implements IGridConnectionVisitor {
|
||||
|
||||
private final int usedChannels;
|
||||
|
||||
public AdHocChannelUpdater(final int used) {
|
||||
this.usedChannels = used;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitNode(final IGridNode n) {
|
||||
final GridNode gn = (GridNode) n;
|
||||
gn.setControllerRoute(null, true);
|
||||
gn.incrementChannelCount(this.usedChannels);
|
||||
gn.finalizeChannels();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitConnection(final IGridConnection gcc) {
|
||||
final GridConnection gc = (GridConnection) gcc;
|
||||
gc.setControllerRoute(null, true);
|
||||
gc.incrementChannelCount(this.usedChannels);
|
||||
gc.finalizeChannels();
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* 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.me.pathfinding;
|
||||
|
||||
import appeng.api.networking.IGridConnection;
|
||||
import appeng.api.networking.IGridConnectionVisitor;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.me.GridConnection;
|
||||
import appeng.me.GridNode;
|
||||
|
||||
public class ControllerChannelUpdater implements IGridConnectionVisitor {
|
||||
|
||||
@Override
|
||||
public boolean visitNode(final IGridNode n) {
|
||||
final GridNode gn = (GridNode) n;
|
||||
gn.finalizeChannels();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitConnection(final IGridConnection gcc) {
|
||||
final GridConnection gc = (GridConnection) gcc;
|
||||
gc.finalizeChannels();
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* 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.me.pathfinding;
|
||||
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridVisitor;
|
||||
import appeng.tile.networking.ControllerBlockEntity;
|
||||
|
||||
public class ControllerValidator implements IGridVisitor {
|
||||
|
||||
private boolean isValid = true;
|
||||
private int found = 0;
|
||||
private int minX;
|
||||
private int minY;
|
||||
private int minZ;
|
||||
private int maxX;
|
||||
private int maxY;
|
||||
private int maxZ;
|
||||
|
||||
public ControllerValidator(final int x, final int y, final int z) {
|
||||
this.minX = x;
|
||||
this.maxX = x;
|
||||
this.minY = y;
|
||||
this.maxY = y;
|
||||
this.minZ = z;
|
||||
this.maxZ = z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitNode(final IGridNode n) {
|
||||
final IGridHost host = n.getMachine();
|
||||
if (this.isValid() && host instanceof ControllerBlockEntity) {
|
||||
final ControllerBlockEntity c = (ControllerBlockEntity) host;
|
||||
|
||||
final BlockPos pos = c.getPos();
|
||||
|
||||
this.minX = Math.min(pos.getX(), this.minX);
|
||||
this.maxX = Math.max(pos.getX(), this.maxX);
|
||||
this.minY = Math.min(pos.getY(), this.minY);
|
||||
this.maxY = Math.max(pos.getY(), this.maxY);
|
||||
this.minZ = Math.min(pos.getZ(), this.minZ);
|
||||
this.maxZ = Math.max(pos.getZ(), this.maxZ);
|
||||
|
||||
if (this.maxX - this.minX < 7 && this.maxY - this.minY < 7 && this.maxZ - this.minZ < 7) {
|
||||
this.setFound(this.getFound() + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
this.setValid(false);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.isValid();
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return this.isValid;
|
||||
}
|
||||
|
||||
private void setValid(final boolean isValid) {
|
||||
this.isValid = isValid;
|
||||
}
|
||||
|
||||
public int getFound() {
|
||||
return this.found;
|
||||
}
|
||||
|
||||
private void setFound(final int found) {
|
||||
this.found = found;
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* 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.me.pathfinding;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import appeng.api.networking.GridFlags;
|
||||
import appeng.api.util.IReadOnlyCollection;
|
||||
|
||||
public interface IPathItem {
|
||||
|
||||
IPathItem getControllerRoute();
|
||||
|
||||
void setControllerRoute(IPathItem fast, boolean zeroOut);
|
||||
|
||||
/**
|
||||
* used to determine if the finder can continue.
|
||||
*/
|
||||
boolean canSupportMoreChannels();
|
||||
|
||||
/**
|
||||
* find possible choices for other pathing.
|
||||
*/
|
||||
IReadOnlyCollection<IPathItem> getPossibleOptions();
|
||||
|
||||
/**
|
||||
* add one to the channel count, this is mostly for cables.
|
||||
*/
|
||||
void incrementChannelCount(int usedChannels);
|
||||
|
||||
/**
|
||||
* get the grid flags for this IPathItem.
|
||||
*
|
||||
* @return the flag set.
|
||||
*/
|
||||
EnumSet<GridFlags> getFlags();
|
||||
|
||||
/**
|
||||
* channels are done, wrap it up.
|
||||
*/
|
||||
void finalizeChannels();
|
||||
}
|
||||
@@ -1,145 +0,0 @@
|
||||
/*
|
||||
* 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.me.pathfinding;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import appeng.api.networking.GridFlags;
|
||||
import appeng.api.networking.IGridMultiblock;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.me.cache.PathGridCache;
|
||||
|
||||
public class PathSegment {
|
||||
|
||||
private final PathGridCache pgc;
|
||||
private final Set<IPathItem> semiOpen;
|
||||
private final Set<IPathItem> closed;
|
||||
private boolean isDead;
|
||||
private List<IPathItem> open;
|
||||
|
||||
public PathSegment(final PathGridCache myPGC, final List<IPathItem> open, final Set<IPathItem> semiOpen,
|
||||
final Set<IPathItem> closed) {
|
||||
this.open = open;
|
||||
this.semiOpen = semiOpen;
|
||||
this.closed = closed;
|
||||
this.pgc = myPGC;
|
||||
this.setDead(false);
|
||||
}
|
||||
|
||||
public boolean step() {
|
||||
final List<IPathItem> oldOpen = this.open;
|
||||
this.open = new ArrayList<>();
|
||||
|
||||
for (final IPathItem i : oldOpen) {
|
||||
for (final IPathItem pi : i.getPossibleOptions()) {
|
||||
final EnumSet<GridFlags> flags = pi.getFlags();
|
||||
|
||||
if (!this.closed.contains(pi)) {
|
||||
pi.setControllerRoute(i, true);
|
||||
|
||||
if (flags.contains(GridFlags.REQUIRE_CHANNEL)) {
|
||||
// close the semi open.
|
||||
if (!this.semiOpen.contains(pi)) {
|
||||
final boolean worked;
|
||||
|
||||
if (flags.contains(GridFlags.COMPRESSED_CHANNEL)) {
|
||||
worked = this.useDenseChannel(pi);
|
||||
} else {
|
||||
worked = this.useChannel(pi);
|
||||
}
|
||||
|
||||
if (worked && flags.contains(GridFlags.MULTIBLOCK)) {
|
||||
final Iterator<IGridNode> oni = ((IGridMultiblock) ((IGridNode) pi).getGridBlock())
|
||||
.getMultiblockNodes();
|
||||
while (oni.hasNext()) {
|
||||
final IGridNode otherNodes = oni.next();
|
||||
if (otherNodes != pi) {
|
||||
this.semiOpen.add((IPathItem) otherNodes);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pi.incrementChannelCount(1); // give a channel.
|
||||
this.semiOpen.remove(pi);
|
||||
}
|
||||
}
|
||||
|
||||
this.closed.add(pi);
|
||||
this.open.add(pi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.open.isEmpty();
|
||||
}
|
||||
|
||||
private boolean useDenseChannel(final IPathItem start) {
|
||||
IPathItem pi = start;
|
||||
while (pi != null) {
|
||||
if (!pi.canSupportMoreChannels() || pi.getFlags().contains(GridFlags.CANNOT_CARRY_COMPRESSED)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pi = pi.getControllerRoute();
|
||||
}
|
||||
|
||||
pi = start;
|
||||
while (pi != null) {
|
||||
this.pgc.setChannelsByBlocks(this.pgc.getChannelsByBlocks() + 1);
|
||||
pi.incrementChannelCount(1);
|
||||
pi = pi.getControllerRoute();
|
||||
}
|
||||
|
||||
this.pgc.setChannelsInUse(this.pgc.getChannelsInUse() + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean useChannel(final IPathItem start) {
|
||||
IPathItem pi = start;
|
||||
while (pi != null) {
|
||||
if (!pi.canSupportMoreChannels()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pi = pi.getControllerRoute();
|
||||
}
|
||||
|
||||
pi = start;
|
||||
while (pi != null) {
|
||||
this.pgc.setChannelsByBlocks(this.pgc.getChannelsByBlocks() + 1);
|
||||
pi.incrementChannelCount(1);
|
||||
pi = pi.getControllerRoute();
|
||||
}
|
||||
|
||||
this.pgc.setChannelsInUse(this.pgc.getChannelsInUse() + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDead() {
|
||||
return this.isDead;
|
||||
}
|
||||
|
||||
public void setDead(final boolean isDead) {
|
||||
this.isDead = isDead;
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* 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.me.storage;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.implementations.tiles.IChestOrDrive;
|
||||
import appeng.api.networking.security.IActionSource;
|
||||
import appeng.api.storage.cells.CellState;
|
||||
import appeng.api.storage.cells.ICellHandler;
|
||||
import appeng.api.storage.cells.ICellInventoryHandler;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
|
||||
public class DriveWatcher<T extends IAEStack<T>> extends MEInventoryHandler<T> {
|
||||
|
||||
private CellState oldStatus = CellState.EMPTY;
|
||||
private final ItemStack is;
|
||||
private final ICellHandler handler;
|
||||
private final IChestOrDrive cord;
|
||||
|
||||
public DriveWatcher(final ICellInventoryHandler<T> i, final ItemStack is, final ICellHandler han,
|
||||
final IChestOrDrive cod) {
|
||||
super(i, i.getChannel());
|
||||
this.is = is;
|
||||
this.handler = han;
|
||||
this.cord = cod;
|
||||
}
|
||||
|
||||
public CellState getStatus() {
|
||||
return this.handler.getStatusForCell(this.is, (ICellInventoryHandler) this.getInternal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public T injectItems(final T input, final Actionable type, final IActionSource src) {
|
||||
final long size = input.getStackSize();
|
||||
|
||||
final T a = super.injectItems(input, type, src);
|
||||
|
||||
if (type == Actionable.MODULATE && (a == null || a.getStackSize() != size)) {
|
||||
final CellState newStatus = this.getStatus();
|
||||
|
||||
if (newStatus != this.oldStatus) {
|
||||
this.cord.blinkCell(this.getSlot());
|
||||
this.oldStatus = newStatus;
|
||||
}
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T extractItems(final T request, final Actionable type, final IActionSource src) {
|
||||
final T a = super.extractItems(request, type, src);
|
||||
|
||||
if (type == Actionable.MODULATE && a != null) {
|
||||
final CellState newStatus = this.getStatus();
|
||||
|
||||
if (newStatus != this.oldStatus) {
|
||||
this.cord.blinkCell(this.getSlot());
|
||||
this.oldStatus = newStatus;
|
||||
}
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* 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.me.storage;
|
||||
|
||||
import appeng.api.networking.security.IActionSource;
|
||||
import appeng.api.networking.ticking.TickRateModulation;
|
||||
|
||||
public interface ITickingMonitor {
|
||||
|
||||
TickRateModulation onTick();
|
||||
|
||||
void setActionSource(IActionSource actionSource);
|
||||
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* 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.me.storage;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import appeng.api.networking.storage.IStackWatcher;
|
||||
import appeng.api.networking.storage.IStackWatcherHost;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.me.cache.GridStorageCache;
|
||||
|
||||
/**
|
||||
* Maintain my interests, and a global watch list, they should always be fully
|
||||
* synchronized.
|
||||
*/
|
||||
public class ItemWatcher implements IStackWatcher {
|
||||
|
||||
private final GridStorageCache gsc;
|
||||
private final IStackWatcherHost myObject;
|
||||
private final Set<IAEStack> myInterests = new HashSet<>();
|
||||
|
||||
public ItemWatcher(final GridStorageCache cache, final IStackWatcherHost host) {
|
||||
this.gsc = cache;
|
||||
this.myObject = host;
|
||||
}
|
||||
|
||||
public IStackWatcherHost getHost() {
|
||||
return this.myObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(final IAEStack e) {
|
||||
if (this.myInterests.contains(e)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.myInterests.add(e.copy()) && this.gsc.getInterestManager().put(e, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(final IAEStack o) {
|
||||
return this.myInterests.remove(o) && this.gsc.getInterestManager().remove(o, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
final Iterator<IAEStack> i = this.myInterests.iterator();
|
||||
|
||||
while (i.hasNext()) {
|
||||
this.gsc.getInterestManager().remove(i.next(), this);
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,309 +0,0 @@
|
||||
/*
|
||||
* 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.me.storage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.NavigableMap;
|
||||
import java.util.concurrent.ConcurrentSkipListMap;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.config.AccessRestriction;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.config.StorageFilter;
|
||||
import appeng.api.networking.security.IActionSource;
|
||||
import appeng.api.networking.ticking.TickRateModulation;
|
||||
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.IItemList;
|
||||
import appeng.util.InventoryAdaptor;
|
||||
import appeng.util.Platform;
|
||||
import appeng.util.inv.ItemSlot;
|
||||
|
||||
public class MEMonitorIInventory implements IMEMonitor<IAEItemStack>, ITickingMonitor {
|
||||
|
||||
private final InventoryAdaptor adaptor;
|
||||
private final IItemList<IAEItemStack> list = AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class)
|
||||
.createList();
|
||||
private final HashMap<IMEMonitorHandlerReceiver<IAEItemStack>, Object> listeners = new HashMap<>();
|
||||
private final NavigableMap<Integer, CachedItemStack> memory;
|
||||
private IActionSource mySource;
|
||||
private StorageFilter mode = StorageFilter.EXTRACTABLE_ONLY;
|
||||
|
||||
public MEMonitorIInventory(final InventoryAdaptor adaptor) {
|
||||
this.adaptor = adaptor;
|
||||
this.memory = new ConcurrentSkipListMap<>();
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEItemStack injectItems(final IAEItemStack input, final Actionable type, final IActionSource src) {
|
||||
ItemStack out = ItemStack.EMPTY;
|
||||
|
||||
if (type == Actionable.SIMULATE) {
|
||||
out = this.adaptor.simulateAdd(input.createItemStack());
|
||||
} else {
|
||||
out = this.adaptor.addItems(input.createItemStack());
|
||||
}
|
||||
|
||||
if (type == Actionable.MODULATE) {
|
||||
this.onTick();
|
||||
}
|
||||
|
||||
if (out.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// better then doing construction from scratch :3
|
||||
final IAEItemStack o = input.copy();
|
||||
o.setStackSize(out.getCount());
|
||||
return o;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEItemStack extractItems(final IAEItemStack request, final Actionable type, final IActionSource src) {
|
||||
ItemStack out = ItemStack.EMPTY;
|
||||
|
||||
if (type == Actionable.SIMULATE) {
|
||||
out = this.adaptor.simulateRemove((int) request.getStackSize(), request.getDefinition(), null);
|
||||
} else {
|
||||
out = this.adaptor.removeItems((int) request.getStackSize(), request.getDefinition(), null);
|
||||
}
|
||||
|
||||
if (out.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// better then doing construction from scratch :3
|
||||
final IAEItemStack o = request.copy();
|
||||
o.setStackSize(out.getCount());
|
||||
|
||||
if (type == Actionable.MODULATE) {
|
||||
this.onTick();
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IStorageChannel getChannel() {
|
||||
return AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickRateModulation onTick() {
|
||||
|
||||
final List<IAEItemStack> changes = new ArrayList<>();
|
||||
|
||||
this.list.resetStatus();
|
||||
int high = 0;
|
||||
boolean changed = false;
|
||||
for (final ItemSlot is : this.adaptor) {
|
||||
final CachedItemStack old = this.memory.get(is.getSlot());
|
||||
high = Math.max(high, is.getSlot());
|
||||
|
||||
final ItemStack newIS = !is.isExtractable() && this.getMode() == StorageFilter.EXTRACTABLE_ONLY
|
||||
? ItemStack.EMPTY
|
||||
: is.getItemStack();
|
||||
final ItemStack oldIS = old == null ? ItemStack.EMPTY : old.itemStack;
|
||||
|
||||
if (this.isDifferent(newIS, oldIS)) {
|
||||
final CachedItemStack cis = new CachedItemStack(is.getItemStack());
|
||||
this.memory.put(is.getSlot(), cis);
|
||||
|
||||
if (old != null && old.aeStack != null) {
|
||||
old.aeStack.setStackSize(-old.aeStack.getStackSize());
|
||||
changes.add(old.aeStack);
|
||||
}
|
||||
|
||||
if (cis.aeStack != null) {
|
||||
changes.add(cis.aeStack);
|
||||
this.list.add(cis.aeStack);
|
||||
}
|
||||
|
||||
changed = true;
|
||||
} else {
|
||||
final int newSize = (newIS.isEmpty() ? 0 : newIS.getCount());
|
||||
final int diff = newSize - (oldIS.isEmpty() ? 0 : oldIS.getCount());
|
||||
|
||||
final IAEItemStack stack = (old == null || old.aeStack == null
|
||||
? AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class).createStack(newIS)
|
||||
: old.aeStack.copy());
|
||||
if (stack != null) {
|
||||
stack.setStackSize(newSize);
|
||||
this.list.add(stack);
|
||||
}
|
||||
|
||||
if (diff != 0 && stack != null) {
|
||||
final CachedItemStack cis = new CachedItemStack(is.getItemStack());
|
||||
this.memory.put(is.getSlot(), cis);
|
||||
|
||||
final IAEItemStack a = stack.copy();
|
||||
a.setStackSize(diff);
|
||||
changes.add(a);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// detect dropped items; should fix non IISided Inventory Changes.
|
||||
final NavigableMap<Integer, CachedItemStack> end = this.memory.tailMap(high, false);
|
||||
if (!end.isEmpty()) {
|
||||
for (final CachedItemStack cis : end.values()) {
|
||||
if (cis != null && cis.aeStack != null) {
|
||||
final IAEItemStack a = cis.aeStack.copy();
|
||||
a.setStackSize(-a.getStackSize());
|
||||
changes.add(a);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
end.clear();
|
||||
}
|
||||
|
||||
if (!changes.isEmpty()) {
|
||||
this.postDifference(changes);
|
||||
}
|
||||
|
||||
return changed ? TickRateModulation.URGENT : TickRateModulation.SLOWER;
|
||||
}
|
||||
|
||||
private boolean isDifferent(final ItemStack a, final ItemStack b) {
|
||||
if (a == b && b.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((a.isEmpty() && !b.isEmpty()) || (!a.isEmpty() && b.isEmpty())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !Platform.itemComparisons().isSameItem(a, b);
|
||||
}
|
||||
|
||||
private void postDifference(final Iterable<IAEItemStack> a) {
|
||||
// AELog.info( a.getItemStack().getTranslationKey() + " @ " + a.getStackSize()
|
||||
// );
|
||||
if (a != null) {
|
||||
final Iterator<Entry<IMEMonitorHandlerReceiver<IAEItemStack>, Object>> i = this.listeners.entrySet()
|
||||
.iterator();
|
||||
while (i.hasNext()) {
|
||||
final Entry<IMEMonitorHandlerReceiver<IAEItemStack>, Object> l = i.next();
|
||||
final IMEMonitorHandlerReceiver<IAEItemStack> key = l.getKey();
|
||||
if (key.isValid(l.getValue())) {
|
||||
key.postChange(this, a, this.getActionSource());
|
||||
} else {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessRestriction getAccess() {
|
||||
return AccessRestriction.READ_WRITE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrioritized(final IAEItemStack input) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAccept(final IAEItemStack input) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlot() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validForPass(final int i) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<IAEItemStack> getAvailableItems(final IItemList out) {
|
||||
for (final CachedItemStack is : this.memory.values()) {
|
||||
out.addStorage(is.aeStack);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<IAEItemStack> getStorageList() {
|
||||
return this.list;
|
||||
}
|
||||
|
||||
private StorageFilter getMode() {
|
||||
return this.mode;
|
||||
}
|
||||
|
||||
public void setMode(final StorageFilter mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
private IActionSource getActionSource() {
|
||||
return this.mySource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActionSource(final IActionSource mySource) {
|
||||
this.mySource = mySource;
|
||||
}
|
||||
|
||||
private static class CachedItemStack {
|
||||
|
||||
private final ItemStack itemStack;
|
||||
private final IAEItemStack aeStack;
|
||||
|
||||
public CachedItemStack(final ItemStack is) {
|
||||
if (is.isEmpty()) {
|
||||
this.itemStack = ItemStack.EMPTY;
|
||||
this.aeStack = null;
|
||||
} else {
|
||||
this.itemStack = is.copy();
|
||||
this.aeStack = AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class).createStack(is);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
/*
|
||||
* 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.me.storage;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import appeng.api.networking.security.IActionSource;
|
||||
import appeng.api.networking.storage.IBaseMonitor;
|
||||
import appeng.api.storage.IMEInventory;
|
||||
import appeng.api.storage.IMEMonitor;
|
||||
import appeng.api.storage.IMEMonitorHandlerReceiver;
|
||||
import appeng.api.storage.IStorageChannel;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.util.Platform;
|
||||
import appeng.util.inv.ItemListIgnoreCrafting;
|
||||
|
||||
public class MEMonitorPassThrough<T extends IAEStack<T>> extends MEPassThrough<T>
|
||||
implements IMEMonitor<T>, IMEMonitorHandlerReceiver<T> {
|
||||
|
||||
private final HashMap<IMEMonitorHandlerReceiver<T>, Object> listeners = new HashMap<>();
|
||||
private IActionSource changeSource;
|
||||
private IMEMonitor<T> monitor;
|
||||
|
||||
public MEMonitorPassThrough(final IMEInventory<T> i, final IStorageChannel channel) {
|
||||
super(i, channel);
|
||||
if (i instanceof IMEMonitor) {
|
||||
this.monitor = (IMEMonitor<T>) i;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInternal(final IMEInventory<T> i) {
|
||||
if (this.monitor != null) {
|
||||
this.monitor.removeListener(this);
|
||||
}
|
||||
|
||||
this.monitor = null;
|
||||
final IItemList<T> before = this.getInternal() == null ? this.getWrappedChannel().createList()
|
||||
: this.getInternal()
|
||||
.getAvailableItems(new ItemListIgnoreCrafting(this.getWrappedChannel().createList()));
|
||||
|
||||
super.setInternal(i);
|
||||
if (i instanceof IMEMonitor) {
|
||||
this.monitor = (IMEMonitor<T>) i;
|
||||
}
|
||||
|
||||
final IItemList<T> after = this.getInternal() == null ? this.getWrappedChannel().createList()
|
||||
: this.getInternal()
|
||||
.getAvailableItems(new ItemListIgnoreCrafting(this.getWrappedChannel().createList()));
|
||||
|
||||
if (this.monitor != null) {
|
||||
this.monitor.addListener(this, this.monitor);
|
||||
}
|
||||
|
||||
Platform.postListChanges(before, after, this, this.getChangeSource());
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<T> getAvailableItems(final IItemList out) {
|
||||
super.getAvailableItems(new ItemListIgnoreCrafting(out));
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(final IMEMonitorHandlerReceiver<T> l, final Object verificationToken) {
|
||||
this.listeners.put(l, verificationToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(final IMEMonitorHandlerReceiver<T> l) {
|
||||
this.listeners.remove(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<T> getStorageList() {
|
||||
if (this.monitor == null) {
|
||||
final IItemList<T> out = this.getWrappedChannel().createList();
|
||||
this.getInternal().getAvailableItems(new ItemListIgnoreCrafting(out));
|
||||
return out;
|
||||
}
|
||||
return this.monitor.getStorageList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(final Object verificationToken) {
|
||||
return verificationToken == this.monitor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postChange(final IBaseMonitor<T> monitor, final Iterable<T> change, final IActionSource source) {
|
||||
final Iterator<Entry<IMEMonitorHandlerReceiver<T>, Object>> i = this.listeners.entrySet().iterator();
|
||||
while (i.hasNext()) {
|
||||
final Entry<IMEMonitorHandlerReceiver<T>, Object> e = i.next();
|
||||
final IMEMonitorHandlerReceiver<T> receiver = e.getKey();
|
||||
if (receiver.isValid(e.getValue())) {
|
||||
receiver.postChange(this, change, source);
|
||||
} else {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onListUpdate() {
|
||||
final Iterator<Entry<IMEMonitorHandlerReceiver<T>, Object>> i = this.listeners.entrySet().iterator();
|
||||
while (i.hasNext()) {
|
||||
final Entry<IMEMonitorHandlerReceiver<T>, Object> e = i.next();
|
||||
final IMEMonitorHandlerReceiver<T> receiver = e.getKey();
|
||||
if (receiver.isValid(e.getValue())) {
|
||||
receiver.onListUpdate();
|
||||
} else {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IActionSource getChangeSource() {
|
||||
return this.changeSource;
|
||||
}
|
||||
|
||||
public void setChangeSource(final IActionSource changeSource) {
|
||||
this.changeSource = changeSource;
|
||||
}
|
||||
}
|
||||
@@ -1,278 +0,0 @@
|
||||
/*
|
||||
* 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.me.storage;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.Deque;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.NavigableMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import appeng.api.config.AccessRestriction;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.config.SecurityPermissions;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.security.IActionSource;
|
||||
import appeng.api.networking.security.ISecurityGrid;
|
||||
import appeng.api.storage.IMEInventoryHandler;
|
||||
import appeng.api.storage.IStorageChannel;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.me.cache.SecurityCache;
|
||||
|
||||
public class NetworkInventoryHandler<T extends IAEStack<T>> implements IMEInventoryHandler<T> {
|
||||
|
||||
private static final ThreadLocal<Deque> DEPTH_MOD = new ThreadLocal<>();
|
||||
private static final ThreadLocal<Deque> DEPTH_SIM = new ThreadLocal<>();
|
||||
private static final Comparator<Integer> PRIORITY_SORTER = (o1, o2) -> Integer.compare(o2, o1);
|
||||
|
||||
private static int currentPass = 0;
|
||||
private final IStorageChannel<T> myChannel;
|
||||
private final SecurityCache security;
|
||||
private final NavigableMap<Integer, List<IMEInventoryHandler<T>>> priorityInventory;
|
||||
private int myPass = 0;
|
||||
|
||||
public NetworkInventoryHandler(final IStorageChannel<T> chan, final SecurityCache security) {
|
||||
this.myChannel = chan;
|
||||
this.security = security;
|
||||
this.priorityInventory = new TreeMap<>(PRIORITY_SORTER);
|
||||
}
|
||||
|
||||
public void addNewStorage(final IMEInventoryHandler<T> h) {
|
||||
final int priority = h.getPriority();
|
||||
List<IMEInventoryHandler<T>> list = this.priorityInventory.get(priority);
|
||||
if (list == null) {
|
||||
this.priorityInventory.put(priority, list = new ArrayList<>());
|
||||
}
|
||||
|
||||
list.add(h);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T injectItems(T input, final Actionable type, final IActionSource src) {
|
||||
if (this.diveList(this, type)) {
|
||||
return input;
|
||||
}
|
||||
|
||||
if (this.testPermission(src, SecurityPermissions.INJECT)) {
|
||||
this.surface(this, type);
|
||||
return input;
|
||||
}
|
||||
|
||||
for (final List<IMEInventoryHandler<T>> invList : this.priorityInventory.values()) {
|
||||
Iterator<IMEInventoryHandler<T>> ii = invList.iterator();
|
||||
while (ii.hasNext() && input != null) {
|
||||
final IMEInventoryHandler<T> inv = ii.next();
|
||||
|
||||
if (inv.validForPass(1) && inv.canAccept(input)
|
||||
&& (inv.isPrioritized(input) || inv.extractItems(input, Actionable.SIMULATE, src) != null)) {
|
||||
input = inv.injectItems(input, type, src);
|
||||
}
|
||||
}
|
||||
|
||||
// We need to ignore prioritized inventories in the second pass. If they were
|
||||
// not able to store everything
|
||||
// during the first pass, they will do so in the second, but as this is
|
||||
// stateless we will just report twice
|
||||
// the amount of storable items.
|
||||
// ignores craftingcache on the second pass.
|
||||
ii = invList.iterator();
|
||||
while (ii.hasNext() && input != null) {
|
||||
final IMEInventoryHandler<T> inv = ii.next();
|
||||
|
||||
if (inv.validForPass(2) && inv.canAccept(input) && !inv.isPrioritized(input)) {
|
||||
input = inv.injectItems(input, type, src);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.surface(this, type);
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
private boolean diveList(final NetworkInventoryHandler<T> networkInventoryHandler, final Actionable type) {
|
||||
final Deque cDepth = this.getDepth(type);
|
||||
if (cDepth.contains(networkInventoryHandler)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
cDepth.push(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean testPermission(final IActionSource src, final SecurityPermissions permission) {
|
||||
if (src.player().isPresent()) {
|
||||
if (!this.security.hasPermission(src.player().get(), permission)) {
|
||||
return true;
|
||||
}
|
||||
} else if (src.machine().isPresent()) {
|
||||
if (this.security.isAvailable()) {
|
||||
final IGridNode n = src.machine().get().getActionableNode();
|
||||
if (n == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final IGrid gn = n.getGrid();
|
||||
if (gn != this.security.getGrid()) {
|
||||
|
||||
final ISecurityGrid sg = gn.getCache(ISecurityGrid.class);
|
||||
final int playerID = sg.getOwner();
|
||||
|
||||
if (!this.security.hasPermission(playerID, permission)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void surface(final NetworkInventoryHandler<T> networkInventoryHandler, final Actionable type) {
|
||||
if (this.getDepth(type).pop() != this) {
|
||||
throw new IllegalStateException("Invalid Access to Networked Storage API detected.");
|
||||
}
|
||||
}
|
||||
|
||||
private Deque getDepth(final Actionable type) {
|
||||
final ThreadLocal<Deque> depth = type == Actionable.MODULATE ? DEPTH_MOD : DEPTH_SIM;
|
||||
|
||||
Deque s = depth.get();
|
||||
|
||||
if (s == null) {
|
||||
depth.set(s = new ArrayDeque<>());
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T extractItems(T request, final Actionable mode, final IActionSource src) {
|
||||
if (this.diveList(this, mode)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.testPermission(src, SecurityPermissions.EXTRACT)) {
|
||||
this.surface(this, mode);
|
||||
return null;
|
||||
}
|
||||
|
||||
final Iterator<List<IMEInventoryHandler<T>>> i = this.priorityInventory.descendingMap().values().iterator();// priorityInventory.asMap().descendingMap().entrySet().iterator();
|
||||
|
||||
final T output = request.copy();
|
||||
request = request.copy();
|
||||
output.setStackSize(0);
|
||||
final long req = request.getStackSize();
|
||||
|
||||
while (i.hasNext()) {
|
||||
final List<IMEInventoryHandler<T>> invList = i.next();
|
||||
|
||||
final Iterator<IMEInventoryHandler<T>> ii = invList.iterator();
|
||||
while (ii.hasNext() && output.getStackSize() < req) {
|
||||
final IMEInventoryHandler<T> inv = ii.next();
|
||||
|
||||
request.setStackSize(req - output.getStackSize());
|
||||
output.add(inv.extractItems(request, mode, src));
|
||||
}
|
||||
}
|
||||
|
||||
this.surface(this, mode);
|
||||
|
||||
if (output.getStackSize() <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<T> getAvailableItems(IItemList<T> out) {
|
||||
if (this.diveIteration(this, Actionable.SIMULATE)) {
|
||||
return out;
|
||||
}
|
||||
|
||||
// for (Entry<Integer, IMEInventoryHandler<T>> h : priorityInventory.entries())
|
||||
for (final List<IMEInventoryHandler<T>> i : this.priorityInventory.values()) {
|
||||
for (final IMEInventoryHandler<T> j : i) {
|
||||
out = j.getAvailableItems(out);
|
||||
}
|
||||
}
|
||||
|
||||
this.surface(this, Actionable.SIMULATE);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
private boolean diveIteration(final NetworkInventoryHandler<T> networkInventoryHandler, final Actionable type) {
|
||||
final Deque cDepth = this.getDepth(type);
|
||||
if (cDepth.isEmpty()) {
|
||||
currentPass++;
|
||||
this.myPass = currentPass;
|
||||
} else {
|
||||
if (currentPass == this.myPass) {
|
||||
return true;
|
||||
} else {
|
||||
this.myPass = currentPass;
|
||||
}
|
||||
}
|
||||
|
||||
cDepth.push(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IStorageChannel<T> getChannel() {
|
||||
return this.myChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessRestriction getAccess() {
|
||||
return AccessRestriction.READ_WRITE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrioritized(final T input) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAccept(final T input) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlot() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validForPass(final int i) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* 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.me.storage;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.config.AccessRestriction;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.networking.security.IActionSource;
|
||||
import appeng.api.storage.IMEInventoryHandler;
|
||||
import appeng.api.storage.IStorageChannel;
|
||||
import appeng.api.storage.channels.IItemStorageChannel;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
|
||||
public class NullInventory<T extends IAEStack<T>> implements IMEInventoryHandler<T> {
|
||||
|
||||
@Override
|
||||
public T injectItems(final T input, final Actionable mode, final IActionSource src) {
|
||||
return input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T extractItems(final T request, final Actionable mode, final IActionSource src) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<T> getAvailableItems(final IItemList out) {
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IStorageChannel getChannel() {
|
||||
return AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessRestriction getAccess() {
|
||||
return AccessRestriction.READ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrioritized(final T input) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAccept(final T input) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlot() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validForPass(final int i) {
|
||||
return i == 2;
|
||||
}
|
||||
}
|
||||
@@ -182,6 +182,7 @@ public abstract class AEBasePart implements IPart, IGridProxyable, IActionHost,
|
||||
return this.getItemStack().hasCustomName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntityCrashInfo(final CrashReportSection section) {
|
||||
section.add("Part Side", this.getSide());
|
||||
}
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
/*
|
||||
* 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 net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
||||
import appeng.api.config.Upgrades;
|
||||
import appeng.api.implementations.items.IUpgradeModule;
|
||||
import appeng.tile.inventory.AppEngInternalInventory;
|
||||
import appeng.util.Platform;
|
||||
import appeng.util.inv.IAEAppEngInventory;
|
||||
import appeng.util.inv.InvOperation;
|
||||
import appeng.util.inv.filter.IAEItemFilter;
|
||||
|
||||
public abstract class UpgradeInventory extends AppEngInternalInventory implements IAEAppEngInventory {
|
||||
private final IAEAppEngInventory parent;
|
||||
|
||||
private boolean cached = false;
|
||||
private int fuzzyUpgrades = 0;
|
||||
private int speedUpgrades = 0;
|
||||
private int redstoneUpgrades = 0;
|
||||
private int capacityUpgrades = 0;
|
||||
private int inverterUpgrades = 0;
|
||||
private int craftingUpgrades = 0;
|
||||
|
||||
public UpgradeInventory(final IAEAppEngInventory parent, final int s) {
|
||||
super(null, s, 1);
|
||||
this.setTileEntity(this);
|
||||
this.parent = parent;
|
||||
this.setFilter(new UpgradeInvFilter());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean eventsEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getInstalledUpgrades(final Upgrades u) {
|
||||
if (!this.cached) {
|
||||
this.updateUpgradeInfo();
|
||||
}
|
||||
|
||||
switch (u) {
|
||||
case CAPACITY:
|
||||
return this.capacityUpgrades;
|
||||
case FUZZY:
|
||||
return this.fuzzyUpgrades;
|
||||
case REDSTONE:
|
||||
return this.redstoneUpgrades;
|
||||
case SPEED:
|
||||
return this.speedUpgrades;
|
||||
case INVERTER:
|
||||
return this.inverterUpgrades;
|
||||
case CRAFTING:
|
||||
return this.craftingUpgrades;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract int getMaxInstalled(Upgrades upgrades);
|
||||
|
||||
private void updateUpgradeInfo() {
|
||||
this.cached = true;
|
||||
this.inverterUpgrades = this.capacityUpgrades = this.redstoneUpgrades = this.speedUpgrades = this.fuzzyUpgrades = this.craftingUpgrades = 0;
|
||||
|
||||
for (final ItemStack is : this) {
|
||||
if (is == null || is.getItem() == Items.AIR || !(is.getItem() instanceof IUpgradeModule)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final Upgrades myUpgrade = ((IUpgradeModule) is.getItem()).getType(is);
|
||||
switch (myUpgrade) {
|
||||
case CAPACITY:
|
||||
this.capacityUpgrades++;
|
||||
break;
|
||||
case FUZZY:
|
||||
this.fuzzyUpgrades++;
|
||||
break;
|
||||
case REDSTONE:
|
||||
this.redstoneUpgrades++;
|
||||
break;
|
||||
case SPEED:
|
||||
this.speedUpgrades++;
|
||||
break;
|
||||
case INVERTER:
|
||||
this.inverterUpgrades++;
|
||||
break;
|
||||
case CRAFTING:
|
||||
this.craftingUpgrades++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.capacityUpgrades = Math.min(this.capacityUpgrades, this.getMaxInstalled(Upgrades.CAPACITY));
|
||||
this.fuzzyUpgrades = Math.min(this.fuzzyUpgrades, this.getMaxInstalled(Upgrades.FUZZY));
|
||||
this.redstoneUpgrades = Math.min(this.redstoneUpgrades, this.getMaxInstalled(Upgrades.REDSTONE));
|
||||
this.speedUpgrades = Math.min(this.speedUpgrades, this.getMaxInstalled(Upgrades.SPEED));
|
||||
this.inverterUpgrades = Math.min(this.inverterUpgrades, this.getMaxInstalled(Upgrades.INVERTER));
|
||||
this.craftingUpgrades = Math.min(this.craftingUpgrades, this.getMaxInstalled(Upgrades.CRAFTING));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromNBT(final CompoundTag target) {
|
||||
super.readFromNBT(target);
|
||||
this.updateUpgradeInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveChanges() {
|
||||
if (this.parent != null) {
|
||||
this.parent.saveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChangeInventory(final FixedItemInv inv, final int slot, final InvOperation mc,
|
||||
final ItemStack removedStack, final ItemStack newStack) {
|
||||
this.cached = false;
|
||||
if (this.parent != null && Platform.isServer()) {
|
||||
this.parent.onChangeInventory(inv, slot, mc, removedStack, newStack);
|
||||
}
|
||||
}
|
||||
|
||||
private class UpgradeInvFilter implements IAEItemFilter {
|
||||
|
||||
@Override
|
||||
public boolean allowExtract(FixedItemInv inv, int slot, int amount) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowInsert(FixedItemInv inv, int slot, ItemStack itemstack) {
|
||||
if (itemstack.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
final Item it = itemstack.getItem();
|
||||
if (it instanceof IUpgradeModule) {
|
||||
final Upgrades u = ((IUpgradeModule) it).getType(itemstack);
|
||||
if (u != null) {
|
||||
return UpgradeInventory.this.getInstalledUpgrades(u) < UpgradeInventory.this.getMaxInstalled(u);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,7 +113,7 @@ public class CableAnchorPart implements IPart {
|
||||
|
||||
@Override
|
||||
public boolean isLadder(final LivingEntity entity) {
|
||||
return this.mySide.yOffset == 0 && (entity.collidedHorizontally || !entity.onGround);
|
||||
return this.mySide.yOffset == 0 && (entity.horizontalCollision || !entity.isOnGround());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -121,11 +121,6 @@ public class ServerHelper extends CommonHelper {
|
||||
return this.renderModeForPlayer(this.renderModeBased);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triggerUpdates() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRenderMode(final PlayerEntity player) {
|
||||
this.renderModeBased = player;
|
||||
|
||||
Reference in New Issue
Block a user