
mmb.content.stn.network.STNNetworkInventory Maven / Gradle / Ivy
/**
*
*/
package mmb.content.stn.network;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Iterators;
import com.google.common.collect.SetMultimap;
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
import mmb.NN;
import mmb.Nil;
import mmb.engine.debug.Debugger;
import mmb.engine.inv.Inventory;
import mmb.engine.inv.ItemRecord;
import mmb.engine.inv.storage.SimpleInventory;
import mmb.engine.item.ItemEntry;
import mmb.engine.recipe.RecipeOutput;
/**
* The implementation of the Storage component of the STN
* @author oskar
*/
public class STNNetworkInventory implements Inventory{
private static final Debugger debug = new Debugger("STN-inventory");
//Outgoing items
/** The STN storage queue. Items are going to get moved to various inventories from here */
@NN public final SimpleInventory storageQueue = new SimpleInventory().setCapacity(128);
/**
* Creates a network inventory. This is an implementation of inventory for the STN
* @param dataLayerSTN
*/
protected STNNetworkInventory(DataLayerSTN dataLayerSTN) {
// TODO Auto-generated constructor stub
}
@Override
public boolean isEmpty() {
reindex();
return volume == 0;
}
@Override
public @NN Iterator<@NN ItemRecord> iterator() {
return Iterators.transform(storageIndex.keySet().iterator(), this::get);
}
@Override
public ItemRecord get(ItemEntry entry) {
return nget(entry);
}
@Override
public int size() {
reindex();
return storageIndex.size();
}
@Override
@NN public ItemRecord nget(ItemEntry entry) {
reindex();
return new STNNetworkItemNode(entry);
}
@Override
public int insert(ItemEntry ent, int amount) {
return networkInsert(ent, amount);
}
@Override
public int extract(ItemEntry ent, int amount) {
return networkExtract(ent, amount);
}
@Override
public int bulkInsert(RecipeOutput ent, int amount) {
reindex();
int remain = amount;
double attempts0 = 2 + ((ent.outVolume()*amount)/storageQueue.capacity());
int attempts = (int) attempts0;
for(int i = 0; i < attempts; i++) {
int insertion = storageQueue.bulkInsert(ent, remain);
remain -= insertion;
if(remain == 0) break;
if(remain > 0) flushQueue();
}
return amount-remain;
}
/** Flushes the insertion queue */
public void flushQueue() { //fails to move items
for(ItemRecord irecord: storageQueue) {
ItemEntry item = irecord.item();
int amount = irecord.amount();
int move = networkInsert(item, amount);
irecord.extract(move);
}
}
//network methods
//network insert items
private int networkInsert(ItemEntry item, int amount) {
reindex();
int remain = amount;
for(Inventory inv: nodes0) {
int insertion = inv.insert(item, remain);
remain -= insertion;
if(insertion != 0)
itemInvIndex.put(item, inv);
if(remain == 0) break;
}
int inserted = amount - remain;
if(inserted != 0) storageIndex.addTo(item, inserted);
return inserted;
}
private int networkExtract(ItemEntry item, int amount) {
reindex();
long indexed = storageIndex.getLong(item);
//the expected amount of items
int expected = (int)Math.min(indexed, amount);
Set<@NN Inventory> candidates = itemInvIndex.get(item);
int remain = expected;
int extractedTotal = 0;
for(Inventory inv: candidates) {
int extracted = inv.extract(item, remain);
remain -= extracted;
extractedTotal += extracted;
if(remain == 0) break;
}
if(extractedTotal >= indexed) {
//All extracted, remove from index
storageIndex.removeLong(item);
}else {
storageIndex.addTo(item, -extractedTotal);
}
if(extractedTotal != expected) {
//items are missing, rebuild
dirty = true;
}
return extractedTotal;
}
//storage index
@NN private final Set<@NN Inventory> nodes0 = new DirtySet();
/** Inventories connected to the network */
@NN public final Set<@NN Inventory> nodes = Collections.unmodifiableSet(nodes0);
@NN private final Object2LongOpenHashMap storageIndex = new Object2LongOpenHashMap<>();
@NN private final SetMultimap itemInvIndex = HashMultimap.create();
private double volume;
private double capacity;
private boolean dirty;
/** Marks the inventory as dirty (the indexes will be rebuilt on next use) */
public void dirty() {
dirty = true;
}
/** Rebuilds the index if there are inconsistencies */
public void reindex() {
if(!dirty) return;
rebuild();
}
/** Force rebuild the index */
public void rebuild() {
debug.printl("Index rebuild");
//Force rebuild the index
storageIndex.clear();
itemInvIndex.clear();
volume = 0;
capacity = 0;
for(Inventory inv: nodes0) {
volume += inv.volume();
capacity += inv.capacity();
for(ItemRecord irecord: inv) {
itemInvIndex.put(irecord.item(), inv);
storageIndex.addTo(irecord.item(), irecord.amount());
}
}
dirty = false;
}
//Storage volume
@Override
public double capacity() {
reindex();
return capacity;
}
@Override
public double volume() {
reindex();
return volume;
}
//Storage network
/**
* Adds inventory to the network. Rejects STN networks
* @param inv inventory to add
* @return was the inventory added
*/
public boolean addInv(@Nil Inventory inv) {
if(inv == null || inv instanceof STNNetworkInventory) return false;
return nodes0.add(inv);
}
/**
* Removes inventory from the network
* @param inv inventory to remove
* @return was the inventory removed?
*/
public boolean removeInv(@Nil Inventory inv) {
return nodes0.remove(inv);
}
private class DirtySet extends HashSet<@NN Inventory>{
private static final long serialVersionUID = -3126410334552219394L;
@Override
public boolean add(Inventory e) {
boolean result = super.add(e);
dirty |= result;
return result;
}
@Override
public boolean remove(Object o) {
boolean result = super.remove(o);
dirty |= result;
return result;
}
@Override
public void clear() {
dirty = true;
super.clear();
}
}
private class STNNetworkItemNode implements ItemRecord{
@NN private final ItemEntry item;
public STNNetworkItemNode(ItemEntry entry) {
item = entry;
}
@Override
public int amount() {
reindex();
long value = storageIndex.getLong(item);
if(value > Integer.MAX_VALUE) return Integer.MAX_VALUE;
return (int) value;
}
@Override
public Inventory inventory() {
return STNNetworkInventory.this;
}
@Override
public ItemEntry item() {
return item;
}
@Override
public int insert(int amount) {
return STNNetworkInventory.this.insert(item, amount);
}
@Override
public int extract(int amount) {
return STNNetworkInventory.this.extract(item, amount);
}
}
@Override
public boolean test(ItemEntry e) {
return true;
}
@Override
public int insertibleRemainBulk(int amount, RecipeOutput ent) {
return storageQueue.insertibleRemainBulk(amount, ent);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy