Ejemplo n.º 1
0
void StoresManagementSystem::getAllStores(StoreIndex const &index, std::vector<Store::RefT> &stores) const {
	assert(index.isHardpoint());
	Store *store = index.valid() ? m_Hardpoints.at(index.hardpoint())->getStore() : 0;
	if (store) {
		stores.push_back(store);
		if(store->asRack()) store->asRack()->getChildren(stores, true);
	}
}
Ejemplo n.º 2
0
bool StoresManagementSystem::mountStore(StoreIndex const &index, Store *store) {
	assert(store && index.valid());
	if (index.isHardpoint()) {
		return m_Hardpoints.at(index.hardpoint())->mountStore(store);
	}
	Hardpoint *hp = m_Hardpoints.at(index.hardpoint()).get();
	assert(hp);
	if (!hp->data()->isCompatible(store->key())) {
		CSPLOG(INFO, OBJECT) << "store " << store->name() << " incompatible with hardpoint " << hp->name();
		return false;
	}
	Store *parent = hp->getStore(index.parent());
	if (!parent || !parent->asRack()) {
		CSPLOG(INFO, OBJECT) << "cannot mount store " << store->name() << "; mount point not found on hardpoint " << hp->name();
		return false;
	}
	return parent->asRack()->setChild(index, store);
}
Ejemplo n.º 3
0
// FIXME the implementation leaves a bit to be desired; it works reasonably well and provides
// a simple interface to a complex selection process, but hopefully the code can be cleaned up
// and simplified a bit.  note also that this method neglects inventory constraints (although
// this probably won't be possible until a campaign system is implemented).
// the caller must call setDirtyDynamics() and signalConfiguration() afterward (multiple
// updates should be batched before calling the latter).
bool StoresManagementSystem::loadStores(StoreIndex const &idx, Key const &store, unsigned count) {
	if (!idx.isHardpoint() || count < 1) return false;
	Hardpoint *hp = m_Hardpoints.at(idx.hardpoint()).get(); assert(hp);
	HardpointData const *data = hp->data();

	// before we do a lot of work, make sure the hardpoint supports this store.
	if (!data->isCompatible(store)) return false;

	StoresDatabase &db = StoresDatabase::getInstance();

	// existing pylon?
	//   - yes: existing, compatible rack?
	//          - yes: mount on rack
	//          - no : can mount directly on pylon?
	//                 -yes: mount on pylon
	//                 -no : add prefered rack, mount on rack
	//   - no: add compatble pylon
	//   - repeat: as above

	StoreData const *store_data = db.getStoreData(store);
	if (!store_data) return false;

	bool add_pylon = false;
	Rack::RefT pylon;
	Store *existing_store = hp->getStore();
	if (existing_store) {
		pylon = existing_store->asRack();
		if (!pylon) return false;
	}

	// if no existing pylon, we are fairly unconstrained (and hence have to do the most work).
	if (!pylon) {
		// simplest case: a single store can be mounted directly on the hardpoint.
		if (data->isMountCompatible(store) && count == 1) {
			Store::RefT instance = db.getStore(store);
			return instance.valid() && mountStore(idx, instance.get());
		}

		// otherwise we'll need a pylon, so find the best.
		StoreSet mountable;
		data->getMountCompatibleStores(mountable);

		// get all possible racks and pylons.
		StoreSet const *tmp = db.getCompatibleRacks(store);
		assert(tmp);
		StoreSet racks;  // racks of racks
		db.getCompatibleRacks(*tmp, racks);
		racks.insert(tmp->begin(), tmp->end());

		// find the best rack/stack to use as a pylon
		std::vector<Key> const &pylons = data->preferredRacks();
		for (unsigned i = 0; i < pylons.size(); ++i) {
			if (racks.count(pylons[i]) > 0) {
				Store::RefT s = db.getStore(pylons[i]);
				pylon = !s ? 0 : s->asRack();
				break;
			}
		}

		// if there isn't a preferred pylon, choose the first one that is compatible.
		if (!pylon) {
			for (StoreSet::const_iterator iter = racks.begin(); iter != racks.end(); ++iter) {
				if (data->isMountCompatible(*iter)) {
					Store::RefT s = db.getStore(*iter);
					pylon = !s ? 0 : s->asRack();
					break;
				}
			}
			if (!pylon) return false;
		}

		add_pylon = true;
	}

	Rack::RefT rack = pylon;

	// now we have a mounted pylon that we know will work!  if possible, mount the
	// store(s) directly on the pylon.  otherwise we need to use existing racks or
	// add our own.
	unsigned pylon_capacity = pylon->availableSpace(store);
	if (pylon_capacity < count) {
		// first check for existing capacity.
		unsigned capacity = 0;
		for (unsigned i = 0; i < pylon->getNumChildren(); ++i) {
			Store *child = pylon->getChild(i);
			if (child && child->asRack()) {
				capacity += child->asRack()->availableSpace(store);
				if (capacity >= count) break;
			}
		}

		// if not enough space, try to add racks
		if (capacity < count) {
			// first find suitable racks
			StoreSet const *racks = db.getCompatibleRacks(store);
			StoreSet const *subracks = db.getCompatibleStores(pylon->key());
			StoreSet suitable = (*racks & *subracks);
			// add one or more racks of the same type
			for (StoreSet::const_iterator iter = suitable.begin(); iter != suitable.end(); ++iter) {
				unsigned rack_count = pylon->availableSpace(*iter);
				if (rack_count) {
					unsigned stations = db.getStoreData(*iter)->asRackData()->capacity(store);
					if (capacity + stations * rack_count >= count) {
						if (add_pylon) mountStore(idx, pylon.get());
						unsigned add = (count - capacity) / stations;
						unsigned added = pylon->mountStores(db.getStoreData(*iter), add);
						assert(added == add);
						capacity += added * stations;
						break;
					}
				}
			}
			if (capacity < count) return false;
		} else {
			if (add_pylon) mountStore(idx, pylon.get());
		}

		// now fill up the racks
		for (unsigned i = 0; i < pylon->getNumChildren(); ++i) {
			Store *rack = pylon->getChild(i);
			if (!rack || !rack->asRack()) continue;
			count -= rack->asRack()->mountStores(store_data, count);
			if (count == 0) break;
		}
		assert(count == 0);
	} else {
		// mount all stores on the first available stations.
		if (add_pylon) mountStore(idx, pylon.get());
		unsigned added = pylon->mountStores(store_data, count);
		assert(count == added);
	}

	return true;
}