Moved more parts of ME over

This commit is contained in:
Sebastian Hartte
2020-07-01 01:04:53 +02:00
parent 529d03fa9e
commit 007c7ceb56
61 changed files with 322 additions and 264 deletions
-596
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
}
-126
View File
@@ -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;
}
}