All Downloads are FREE. Search and download functionalities are using the official Maven repository.

mmb.content.stn.network.STNNetworkInventory Maven / Gradle / Ivy

Go to download

Dependency for the MultiMachineBuilder, a voxel game about building an industrial empire in a finite world. THIS RELEASE IS NOT PLAYABLE. To play the game, donwload from >ITCH.IO LINK HERE< or >GH releases link here<

There is a newer version: 0.6
Show newest version
/**
 * 
 */
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.craft.RecipeOutput;
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;

/**
 * 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 - 2024 Weber Informatics LLC | Privacy Policy