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); } }
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); }
// 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; }