//======================================================================== // // PlanetObject.cpp // // copyright 2001 Sony Online Entertainment // //======================================================================== #include "serverGame/FirstServerGame.h" #include "serverGame/PlanetObject.h" #include "UnicodeUtils.h" #include "boost/smart_ptr.hpp" #include "serverGame/ConfigServerGame.h" #include "serverGame/CreatureObject.h" #include "serverGame/GameServer.h" #include "serverGame/GuildObject.h" #include "serverGame/MessageToQueue.h" #include "serverGame/ObjectIdManager.h" #include "serverGame/PlanetController.h" #include "serverGame/PlayerCreatureController.h" #include "serverGame/PlayerObject.h" #include "serverGame/Pvp.h" #include "serverGame/ResourcePoolObject.h" #include "serverGame/ResourceTypeObject.h" #include "serverGame/ServerBuildoutManager.h" #include "serverGame/ServerPlanetObjectTemplate.h" #include "serverGame/ServerResourceClassObject.h" #include "serverGame/ServerUniverse.h" #include "serverGame/ServerWorld.h" #include "serverScript/GameScriptObject.h" #include "serverScript/ScriptParameters.h" #include "serverUtility/ServerClock.h" #include "sharedFoundation/CalendarTime.h" #include "sharedFoundation/DynamicVariableList.h" #include "sharedFoundation/DynamicVariableListNestedList.h" #include "sharedFoundation/FormattedString.h" #include "sharedFoundation/GameControllerMessage.h" #include "sharedGame/PlanetMapManager.h" #include "sharedGame/PvpData.h" #include "sharedGame/TravelPoint.h" #include "sharedLog/Log.h" #include "sharedNetworkMessages/MapLocation.h" #include "sharedNetworkMessages/MapLocationArchive.h" #include "sharedNetworkMessages/MessageQueueGenericValueType.h" #include "sharedNetworkMessages/GenericValueTypeMessage.h" #include "sharedObject/NetworkIdManager.h" #include "swgServerNetworkMessages/MessageQueuePlanetAddTravelPoint.h" #include #include //---------------------------------------------------------------------- namespace PlanetObjectNamespace { const int s_maxMapLocationsStatic = 1000; const int s_maxMapLocationsDynamic = 1000; const int s_maxMapLocationsPersist = 1000; // objvars for collection "server first" tracking const std::string OBJVAR_COLLECTION_SERVER_FIRST("collectionServerFirst"); const std::string OBJVAR_COLLECTION_SERVER_FIRST_UPDATE_NUMBER("collectionServerFirstUpdateNumber"); typedef std::pair StringIndexPair; void ParseEventString(std::string const & eventString, std::vector & parsedVector) { std::string delimiter = ","; std::string::size_type index = eventString.find(delimiter); std::string::size_type offset = 0; parsedVector.clear(); if(eventString.empty()) return; if(index == std::string::npos) { parsedVector.push_back(eventString); return; } while(index != std::string::npos) { std::string subString = eventString.substr(offset, (index - offset)); parsedVector.push_back(subString); offset = index + 1; index = eventString.find(delimiter, offset); } std::string subString = eventString.substr(offset, eventString.size()); parsedVector.push_back(subString); } void ParseEventString(std::string const & eventString, std::vector & parsedVector) { std::string delimiter = ","; std::string::size_type index = eventString.find(delimiter); std::string::size_type offset = 0; parsedVector.clear(); if(eventString.empty()) return; if(index == std::string::npos) { parsedVector.push_back(std::make_pair(eventString, 0)); return; } while(index != std::string::npos) { std::string subString = eventString.substr(offset, (index - offset)); parsedVector.push_back(std::make_pair(subString, index)); offset = index + 1; index = eventString.find(delimiter, offset); } std::string subString = eventString.substr(offset, eventString.size()); parsedVector.push_back(std::make_pair(subString, index)); } const char * makeCopyOfString(const char * rhs) { char * lhs = nullptr; if (rhs) { lhs = new char[strlen(rhs) + 1]; strcpy(lhs, rhs); } else { lhs = new char[1]; lhs[0] = '\0'; } return lhs; } int getNextGcwScoreDecayTime(int base); // dictionary containing the table showing factional presence activity ScriptParams * s_factionalPresenceSuiTable = nullptr; bool s_factionalPresenceSuiTableNeedRebuild = true; void decrementConnectedCharacterLfgDataFactionalPresenceCount(Archive::AutoDeltaMap, PlanetObject> & connectedCharacterLfgDataFactionalPresence, const LfgCharacterData & lfgCharacterData); void incrementConnectedCharacterLfgDataFactionalPresenceCount(Archive::AutoDeltaMap, PlanetObject> & connectedCharacterLfgDataFactionalPresence, const LfgCharacterData & lfgCharacterData); void decrementConnectedCharacterLfgDataFactionalPresenceGridCount(Archive::AutoDeltaMap >, std::pair > > & connectedCharacterLfgDataFactionalPresenceGrid, const LfgCharacterData & lfgCharacterData); void incrementConnectedCharacterLfgDataFactionalPresenceGridCount(Archive::AutoDeltaMap >, std::pair > > & connectedCharacterLfgDataFactionalPresenceGrid, const LfgCharacterData & lfgCharacterData); void removeFactionalPresenceGridFromPlanetMap(std::string const & planetName, NetworkId const & locationId); void addFactionalPresenceGridToPlanetMap(std::string const & planetName, NetworkId const & locationId, int gridX, int gridZ, bool imperial, bool rebel); #ifdef _DEBUG bool ms_printEventDebug = false; #endif } using namespace PlanetObjectNamespace; //----------------------------------------------------------------------- PlanetObject::PlanetObject(const ServerPlanetObjectTemplate* newTemplate) : UniverseObject(newTemplate), m_planetName(), m_builtAvailableResourceList(false), m_availableResourceListExpirationTime(0), m_availableResourceList(), m_travelPointList (), m_weatherIndex(0), m_windVelocityX(0.0f), m_windVelocityY(0.0f), m_windVelocityZ(0.0f), m_mapLocationMapStatic (), m_mapLocationMapDynamic (), m_mapLocationMapPersist (), // reserve version number 0, so that the client can use 0 to force an update m_mapLocationVersionStatic (1), m_mapLocationVersionDynamic (1), m_mapLocationVersionPersist (1), m_mapLocationListStatic (), m_mapLocationListDynamic (), m_mapLocationListPersist (), // reserve version number 0, so that the client can use 0 to force an update m_mapLocationListVersionStatic (1), m_mapLocationListVersionDynamic (1), m_mapLocationListVersionPersist (1), // used to track changes to the collection system "server first" tracking system m_collectionServerFirst (), m_collectionServerFirstUpdateNumber(0), // information tracked for each connected character m_connectedCharacterLfgData (), m_connectedCharacterLfgDataFactionalPresence(), m_connectedCharacterLfgDataFactionalPresenceGrid(), m_connectedCharacterBiographyData(), m_currentEvents (), m_nextGcwTrackingUpdate (0), m_gcwImperialScoreAdjustment (), m_gcwRebelScoreAdjustment (), m_gcwImperialScore (), m_gcwRebelScore () { addMembersToPackages(); m_collectionServerFirst.setSourceObject(this); m_currentEvents.setSourceObject(this); m_connectedCharacterLfgDataFactionalPresence.setOnErase(this, &PlanetObject::connectedCharacterLfgDataFactionalPresenceOnErase); m_connectedCharacterLfgDataFactionalPresence.setOnInsert(this, &PlanetObject::connectedCharacterLfgDataFactionalPresenceOnInsert); m_connectedCharacterLfgDataFactionalPresence.setOnSet(this, &PlanetObject::connectedCharacterLfgDataFactionalPresenceOnSet); } //----------------------------------------------------------------------- PlanetObject::~PlanetObject() { } //----------------------------------------------------------------------- /** * Creates a default controller for this object. * * @return the object's controller */ Controller* PlanetObject::createDefaultController(void) { Controller* controller = new PlanetController(this); setController(controller); return controller; } // PlanetObject::createDefaultController // ---------------------------------------------------------------------- void PlanetObject::debugOutputPools(std::string &output) const { buildAvailableResourceList(); output+=m_planetName.get(); output+='\n'; for (std::vector::const_iterator i=m_availableResourceList.begin(); i!=m_availableResourceList.end(); ++i) { if (*i) (*i)->debugOutput(output); } } // ---------------------------------------------------------------------- void PlanetObject::setupUniverse() { ServerUniverse::getInstance().registerPlanetObject(*this); } // ---------------------------------------------------------------------- /** * Returns a list of all the non-depleted resources that have a pool on this planet */ void PlanetObject::getAvailableResourceList(std::vector &buffer) const { buildAvailableResourceList(); buffer = m_availableResourceList; } // ---------------------------------------------------------------------- /** * Returns a list of all non-depeleted resources that have a pool on this * planet and are derived from the specified class */ void PlanetObject::getAvailableResourceList(std::vector &buffer, const ResourceClassObject &masterClass) const { buildAvailableResourceList(); buffer.clear(); for (std::vector::const_iterator i=m_availableResourceList.begin(); i!=m_availableResourceList.end(); ++i) { if (*i && (*i)->isDerivedFrom(masterClass)) { buffer.push_back(*i); } } } // ---------------------------------------------------------------------- void PlanetObject::setPlanetName(const std::string &newName) { if (isAuthoritative()) { m_planetName=newName; } else { //TODO: message } } //----------------------------------------------------------------------- /** * Sets the weather for the planet. */ void PlanetObject::setWeather(int weather, float windVelocityX, float windVelocityY, float windVelocityZ) { if (isAuthoritative()) { m_weatherIndex = weather; m_windVelocityX = windVelocityX; m_windVelocityY = windVelocityY; m_windVelocityZ = windVelocityZ; } else { sendControllerMessageToAuthServer(CM_setWeather, new MessageQueueGenericValueType >( std::make_pair(weather, Vector(windVelocityX, windVelocityY, windVelocityZ)))); } } // ---------------------------------------------------------------------- void PlanetObject::getAttributes(std::vector > &data) const { UniverseObject::getAttributes(data); } // ---------------------------------------------------------------------- void PlanetObject::addTravelPoint (const std::string& name, const Vector& position_w, const int cost, const bool interplanetary, const TravelPoint::TravelPointType type) { if (ConfigServerGame::getDisableTravel()) { //travel in a planet is off. return; } if (isAuthoritative ()) { if (getTravelPoint (name)) { DEBUG_WARNING (true, ("PlanetObject::addTravelPoint: adding existing travel point %s for planet %s", name.c_str (), getName ().c_str ())); return; } m_travelPointList.push_back (TravelPoint (name, Pvp::getGcwScoreCategoryRegion(m_planetName.get(), position_w), position_w, cost, interplanetary, type)); DEBUG_REPORT_LOG_PRINT (true, ("PlanetObject::addTravelPoint: adding travel point %s for planet %s at position <%1.2f, %1.2f, %1.2f>\n", name.c_str (), getName ().c_str (), position_w.x, position_w.y, position_w.z)); } else { Controller* const controller = getController (); if (!controller) { DEBUG_WARNING (true, ("PlanetObject::addTravelPoint: planet object %s has no controller", getName ().c_str ())); return; } MessageQueuePlanetAddTravelPoint* const message = new MessageQueuePlanetAddTravelPoint (name, position_w, cost, interplanetary, static_cast(type)); getController ()->appendMessage (static_cast(CM_planetAddTravelPoint), 0.f, message, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); DEBUG_REPORT_LOG_PRINT (true, ("PlanetObject::addTravelPoint: sending add travel point %s for planet %s at position <%1.2f, %1.2f, %1.2f> to authoritative server\n", name.c_str (), getName ().c_str (), position_w.x, position_w.y, position_w.z)); } } // ---------------------------------------------------------------------- void PlanetObject::removeTravelPoint (const std::string& name) { if (isAuthoritative ()) { int travelPointIndex; if (!getTravelPointIndex (name, travelPointIndex)) { DEBUG_WARNING (true, ("PlanetObject::removeTravelPoint: attempting to remove non-existant travel point %s for planet %s", name.c_str (), getName ().c_str ())); return; } m_travelPointList.erase (static_cast (travelPointIndex)); DEBUG_REPORT_LOG_PRINT (true, ("PlanetObject::removeTravelPoint: removing travel point %s for planet %s\n", name.c_str (), getName ().c_str ())); } else { Controller* const controller = getController (); if (!controller) { DEBUG_WARNING (true, ("PlanetObject::removeTravelPoint: planet object %s has no controller", getName ().c_str ())); return; } MessageQueueGenericValueType* const message = new MessageQueueGenericValueType (std::string (name)); controller->appendMessage (static_cast(CM_planetRemoveTravelPoint), 0.f, message, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); DEBUG_REPORT_LOG_PRINT (true, ("PlanetObject::removeTravelPoint: sending remove travel point %s for planet %s to authoritative server\n", name.c_str (), getName ().c_str ())); } } // ---------------------------------------------------------------------- int PlanetObject::getNumberOfTravelPoints () const { return static_cast(m_travelPointList.size ()); } // ---------------------------------------------------------------------- const TravelPoint* PlanetObject::getTravelPoint (const int travelPointIndex) const { if (travelPointIndex < 0 || travelPointIndex >= getNumberOfTravelPoints ()) return 0; return &m_travelPointList [static_cast (travelPointIndex)]; } // ---------------------------------------------------------------------- const TravelPoint* PlanetObject::getTravelPoint (const std::string& name) const { int i; for (i = 0; i < getNumberOfTravelPoints (); ++i) { const TravelPoint* const travelPoint = getTravelPoint (i); if (name == travelPoint->getName ()) return travelPoint; } return 0; } // ---------------------------------------------------------------------- bool PlanetObject::getTravelPointIndex (const std::string& name, int& travelPointIndex) const { int i; for (i = 0; i < getNumberOfTravelPoints (); ++i) { const TravelPoint* const travelPoint = getTravelPoint (i); if (name == travelPoint->getName ()) { travelPointIndex = i; return true; } } return false; } // ---------------------------------------------------------------------- void PlanetObject::getTravelPointNameList (std::vector& travelPointNameList) const { int i; for (i = 0; i < getNumberOfTravelPoints (); ++i) { const TravelPoint* const travelPoint = getTravelPoint (i); travelPointNameList.push_back (travelPoint->getName ()); } } // ---------------------------------------------------------------------- void PlanetObject::getTravelPointPointList (std::vector& travelPointPointList) const { int i; for (i = 0; i < getNumberOfTravelPoints (); ++i) { const TravelPoint* const travelPoint = getTravelPoint (i); travelPointPointList.push_back (travelPoint->getPosition_w ()); } } // ---------------------------------------------------------------------- void PlanetObject::getTravelPointCostList (std::vector& travelPointCostList) const { int i; for (i = 0; i < getNumberOfTravelPoints (); ++i) { const TravelPoint* const travelPoint = getTravelPoint (i); travelPointCostList.push_back (travelPoint->getCost ()); } } // ---------------------------------------------------------------------- void PlanetObject::getTravelPointInterplanetaryList (std::vector& travelPointInterplanetaryList) const { int i; for (i = 0; i < getNumberOfTravelPoints (); ++i) { const TravelPoint* const travelPoint = getTravelPoint (i); travelPointInterplanetaryList.push_back (travelPoint->getInterplanetary ()); //lint !e1025 !e1703 // lint can't parse this line } } //---------------------------------------------------------------------- //-- Map Location Stuff //---------------------------------------------------------------------- //---------------------------------------------------------------------- bool PlanetObject::addMapLocation (const MapLocation &location, const int mapLocationType, const bool enforceLocationCountLimits) { if (!location.m_category) { WARNING (true, ("PlanetObject can't add map location with zero category")); return false; } if (!location.m_locationId.isValid ()) { WARNING (true, ("PlanetObject can't add map location with invalid id")); return false; } if (location.m_locationName.empty ()) { WARNING (true, ("PlanetObject can't add map location with empty name")); return false; } if (!isAuthoritative ()) { sendControllerMessageToAuthServer(CM_serverAddPlanetMapLocation, new MessageQueueGenericValueType > >(std::make_pair(location, std::make_pair(mapLocationType, (enforceLocationCountLimits ? static_cast(1) : static_cast(0)))))); return true; } int limit = 0; switch (mapLocationType) { case PlanetMapManager::MLT_static: limit = s_maxMapLocationsStatic; break; case PlanetMapManager::MLT_dynamic: limit = s_maxMapLocationsDynamic; break; case PlanetMapManager::MLT_persist: limit = s_maxMapLocationsPersist; break; default: break; } ArchiveMapLocationMap & locationMap = getMapLocationMapForTypeInternal (mapLocationType); //-- see if we are adding a new location, or just overwriting it in place MapLocationMap::const_iterator it = locationMap.find (location.m_locationId); if (it == locationMap.end ()) { if (enforceLocationCountLimits && (static_cast(locationMap.size ()) >= limit)) { WARNING (true, ("PlanetObject limit [%d] reached for type [%d], can't add map location [%s,%s,%d,%d]", limit, mapLocationType, location.m_locationId.getValueString ().c_str (), Unicode::wideToNarrow (location.m_locationName).c_str (), location.m_category, location.m_subCategory)); return false; } } locationMap.set (location.m_locationId, location); //-- remove the location if it exists on another list { for (int i = 0; i < static_cast(PlanetMapManager::MLT_numTypes); ++i) { if (i != mapLocationType) IGNORE_RETURN(removeMapLocation (location.m_locationId, i)); } } incrementMapLocationCacheVersion (mapLocationType); return true; } //---------------------------------------------------------------------- bool PlanetObject::removeMapLocation (const NetworkId &id, int mapLocationType) { if (!isAuthoritative ()) { WARNING (true, ("PlanetObject::removeMapLocation (const NetworkId &id, int mapLocationType) invalid from non-auth planet object")); return false; } ArchiveMapLocationMap & locationMap = getMapLocationMapForTypeInternal (mapLocationType); if (locationMap.find (id) != locationMap.end ()) { IGNORE_RETURN(locationMap.erase (id)); incrementMapLocationCacheVersion (mapLocationType); return true; } return false; } //---------------------------------------------------------------------- bool PlanetObject::removeMapLocation (const NetworkId &id) { if (!isAuthoritative ()) { sendControllerMessageToAuthServer(CM_serverRemovePlanetMapLocation, new MessageQueueGenericValueType(id)); return true; } bool found = false; for (int i = 0; i < static_cast(PlanetMapManager::MLT_numTypes); ++i) { if (removeMapLocation (id, i)) found = true; } return found; } //---------------------------------------------------------------------- void PlanetObject::getMapLocations (MapLocationVector & result) const { for (int i = 0; i < static_cast(PlanetMapManager::MLT_numTypes); ++i) { const MapLocationVector & mlv = getMapLocations (i); result.insert (result.end (), mlv.begin (), mlv.end ()); } } //---------------------------------------------------------------------- const PlanetObject::MapLocationVector & PlanetObject::getMapLocations (int mapLocationType) const { const MapLocationVector & locationList = getMapLocationListForType (mapLocationType); return locationList; } //---------------------------------------------------------------------- void PlanetObject::getMapLocationsByCategories (int mapLocationType, uint8 category, uint8 subCategory, MapLocationVector & result) const { const MapLocationVector & locationList = getMapLocationListForType (mapLocationType); for (MapLocationVector::const_iterator i = locationList.begin (); i != locationList.end (); ++i) { const MapLocation & ml = *i; if (ml.getCategory() == category && ml.getSubCategory() == subCategory) { result.push_back (ml); } } } //---------------------------------------------------------------------- void PlanetObject::incrementMapLocationCacheVersion (int mapLocationType) { if (!isAuthoritative ()) { WARNING (true, ("PlanetObject::incrementMapLocationCacheVersion invalid from non-auth planet object")); return; } Archive::AutoDeltaVariable & var = getMapLocationVersionForTypeInternal (mapLocationType); // reserve version number 0, so that the client can use 0 to force an update int version = var.get (); if (++version == 0) ++version; var.set (version); } //lint !e1762 // function looks like it could be made const, but better not to make it const because it uses a reference to set a member variable //---------------------------------------------------------------------- int & PlanetObject::getMapLocationListVersionForTypeInternal (int mapLocationType) const { switch (mapLocationType) { case PlanetMapManager::MLT_static: return m_mapLocationListVersionStatic; case PlanetMapManager::MLT_dynamic: return m_mapLocationListVersionDynamic; case PlanetMapManager::MLT_persist: return m_mapLocationListVersionPersist; default: break; } FATAL (true, ("PlanetObject::getMapLocationVersionForType failed")); static int broken; //lint !e527 // unreachable return broken; } //---------------------------------------------------------------------- int PlanetObject::getMapLocationVersionForType (int mapLocationType) const { return const_cast(this)->getMapLocationVersionForTypeInternal (mapLocationType).get (); } //---------------------------------------------------------------------- Archive::AutoDeltaVariable & PlanetObject::getMapLocationVersionForTypeInternal (int mapLocationType) const { switch (mapLocationType) { case PlanetMapManager::MLT_static: return m_mapLocationVersionStatic; case PlanetMapManager::MLT_dynamic: return m_mapLocationVersionDynamic; case PlanetMapManager::MLT_persist: return m_mapLocationVersionPersist; default: break; } FATAL (true, ("PlanetObject::getMapLocationVersionForType failed")); static Archive::AutoDeltaVariable broken; //lint !e527 // unreachable return broken; } //---------------------------------------------------------------------- const PlanetObject::MapLocationVector & PlanetObject::getMapLocationListForType (int mapLocationType) const { checkUpdateInternalListVersion (mapLocationType); return const_cast(this)->getMapLocationListForTypeInternal (mapLocationType); } //---------------------------------------------------------------------- PlanetObject::MapLocationVector & PlanetObject::getMapLocationListForTypeInternal (int mapLocationType) { switch (mapLocationType) { case PlanetMapManager::MLT_static: return m_mapLocationListStatic; case PlanetMapManager::MLT_dynamic: return m_mapLocationListDynamic; case PlanetMapManager::MLT_persist: return m_mapLocationListPersist; default: break; } static MapLocationVector broken; return broken; } //---------------------------------------------------------------------- const PlanetObject::ArchiveMapLocationMap & PlanetObject::getMapLocationMapForType (int mapLocationType) const { return const_cast(this)->getMapLocationMapForTypeInternal (mapLocationType); } //---------------------------------------------------------------------- PlanetObject::ArchiveMapLocationMap & PlanetObject::getMapLocationMapForTypeInternal (int mapLocationType) { switch (mapLocationType) { case PlanetMapManager::MLT_static: return m_mapLocationMapStatic; case PlanetMapManager::MLT_dynamic: return m_mapLocationMapDynamic; case PlanetMapManager::MLT_persist: return m_mapLocationMapPersist; default: break; } static ArchiveMapLocationMap broken; return broken; } //---------------------------------------------------------------------- void PlanetObject::getMapLocationCategories (int parentCategory, int mapLocationType, IntVector & result) const { const MapLocationVector & locationList = getMapLocationListForType (mapLocationType); size_t const numLocations = locationList.size (); for (size_t i = 0; i < numLocations; ++i) { const MapLocation & ml = locationList [i]; int cat = 0; if (!parentCategory) cat = ml.m_category; else if (parentCategory == ml.m_category) cat = ml.m_subCategory; if (cat) { if (std::binary_search (result.begin (), result.end (), cat)) continue; result.push_back (cat); std::sort (result.begin (), result.end ()); } } } //---------------------------------------------------------------------- const MapLocation * PlanetObject::getMapLocation (int mapLocationType, const NetworkId & id) const { // call this to update the cache, if necessary IGNORE_RETURN(getMapLocationListForType (mapLocationType)); // but perform the search in the map (rather than the cache) for performance const ArchiveMapLocationMap & mapLocationMap = getMapLocationMapForType (mapLocationType); const ArchiveMapLocationMap::const_iterator iterFind = mapLocationMap.find(id); if (iterFind != mapLocationMap.end()) return &(iterFind->second); return 0; } //---------------------------------------------------------------------- void PlanetObject::checkUpdateInternalListVersion (int mapLocationType) const { const int mapVersion = getMapLocationVersionForTypeInternal (mapLocationType).get (); int & internalListVersion = getMapLocationListVersionForTypeInternal (mapLocationType); if (mapVersion != internalListVersion) { MapLocationVector & mapLocationList = const_cast(this)->getMapLocationListForTypeInternal (mapLocationType); const ArchiveMapLocationMap & mapLocationMap = getMapLocationMapForType (mapLocationType); mapLocationList.clear (); mapLocationList.reserve (mapLocationMap.size ()); for (ArchiveMapLocationMap::const_iterator it = mapLocationMap.begin (); it != mapLocationMap.end (); ++it) mapLocationList.push_back ((*it).second); internalListVersion = mapVersion; } } //---------------------------------------------------------------------- void PlanetObject::connectedCharacterLfgDataFactionalPresenceOnErase(std::string const & keyValue, std::pair const & value) { UNREF(keyValue); if ((value.first > 0) || (value.second > 0)) s_factionalPresenceSuiTableNeedRebuild = true; } //---------------------------------------------------------------------- void PlanetObject::connectedCharacterLfgDataFactionalPresenceOnInsert(std::string const & keyValue, std::pair const & value) { UNREF(keyValue); if ((value.first > 0) || (value.second > 0)) s_factionalPresenceSuiTableNeedRebuild = true; } //---------------------------------------------------------------------- void PlanetObject::connectedCharacterLfgDataFactionalPresenceOnSet(std::string const & keyValue, std::pair const & oldValue, std::pair const & newValue) { UNREF(keyValue); // 0 -> non-zero or non-zero -> 0 if ((oldValue.first != newValue.first) && ((oldValue.first <= 0) || (newValue.first <= 0))) s_factionalPresenceSuiTableNeedRebuild = true; else if ((oldValue.second != newValue.second) && ((oldValue.second <= 0) || (newValue.second <= 0))) s_factionalPresenceSuiTableNeedRebuild = true; } // ---------------------------------------------------------------------- void PlanetObject::unload() { FATAL(true, ("Tried to unload PlanetObject %s.", getNetworkId().getValueString().c_str())); } //----------------------------------------------------------------------- void PlanetObject::onLoadedFromDatabase() { UniverseObject::onLoadedFromDatabase(); // depersist collection "server first" information if (m_planetName.get() != "tatooine") return; // to avoid inefficient multiple calls to the CollectionServerFirstObserver // class, we temporarily disable it here while we depersist collection // "server first" information and manually create the CollectionServerFirstObserver // object, so that there will only be 1 call to the CollectionServerFirstObserver // object when it goes out of scope at the end of the function m_collectionServerFirst.setSourceObject(nullptr); CollectionServerFirstObserver observer(this, Archive::ADOO_set); const DynamicVariableList & objvars = getObjVars(); std::string objvar; std::vector value; time_t claimTime; NetworkId claimantId; Unicode::String claimantName; std::map const & allServerFirstCollections = CollectionsDataTable::getAllServerFirstCollections(); for (std::map::const_iterator iter = allServerFirstCollections.begin(); iter != allServerFirstCollections.end(); ++iter) { objvar = OBJVAR_COLLECTION_SERVER_FIRST + "." + iter->second->name; if (!objvars.hasItem(objvar) || (DynamicVariable::STRING_ARRAY != objvars.getType(objvar))) continue; value.clear(); if (!objvars.getItem(objvar, value)) continue; if (value.size() != 3) continue; claimTime = static_cast(::atol(Unicode::wideToNarrow(value[0]).c_str())); claimantId = NetworkId(Unicode::wideToNarrow(value[1])); claimantName = value[2]; m_collectionServerFirst.insert(std::make_pair(std::make_pair(static_cast(claimTime), iter->second->name), std::make_pair(claimantId, claimantName))); } int collectionServerFirstUpdateNumber = 0; if (!objvars.getItem(OBJVAR_COLLECTION_SERVER_FIRST_UPDATE_NUMBER, collectionServerFirstUpdateNumber)) collectionServerFirstUpdateNumber = 0; m_collectionServerFirstUpdateNumber = collectionServerFirstUpdateNumber; // restore observer m_collectionServerFirst.setSourceObject(this); } // ---------------------------------------------------------------------- /** * Build or update the list of resources available on this planet, as appropriate. * Keeps track of the minimum expiration time of the resources in the list. If that * time has passed, it rebuilds the list. */ void PlanetObject::buildAvailableResourceList() const { if (!m_builtAvailableResourceList || ServerClock::getInstance().getGameTimeSeconds() > m_availableResourceListExpirationTime) { m_availableResourceListExpirationTime = ServerClock::cms_endOfTime; m_availableResourceList.clear(); ServerResourceClassObject const * const root=NON_NULL(safe_cast(ServerUniverse::getInstance().getResourceTreeRoot())); std::vector typeList; root->getAllDerivedResourceTypes(typeList); for (std::vector::const_iterator i=typeList.begin(); i!=typeList.end(); ++i) { NOT_NULL(*i); m_availableResourceListExpirationTime = std::min(m_availableResourceListExpirationTime, (*i)->getDepletedTimestamp()); if ((*i)->hasPoolForPlanet(getNetworkId())) { m_availableResourceList.push_back(*i); } } m_builtAvailableResourceList = true; } } // ---------------------------------------------------------------------- void PlanetObject::setCollectionServerFirst(const CollectionsDataTable::CollectionInfoCollection& collectionInfo, const NetworkId& claimantId, const Unicode::String& claimantName, const std::string& claimantAccountInfo) { if (m_planetName.get() != "tatooine") return; if (isAuthoritative()) { if (!collectionInfo.trackServerFirst) return; const DynamicVariableList & objvars = getObjVars(); const std::string objvar = OBJVAR_COLLECTION_SERVER_FIRST + "." + collectionInfo.name; if (objvars.hasItem(objvar) && (DynamicVariable::STRING_ARRAY == objvars.getType(objvar))) return; const time_t timeNow = ::time(nullptr); char buffer[64]; snprintf(buffer, sizeof(buffer)-1, "%ld", timeNow); buffer[sizeof(buffer)-1] = '\0'; std::vector value; value.push_back(Unicode::narrowToWide(buffer)); value.push_back(Unicode::narrowToWide(claimantId.getValueString())); value.push_back(claimantName); if (setObjVarItem(objvar, value)) { int collectionServerFirstUpdateNumber = 0; if (!objvars.getItem(OBJVAR_COLLECTION_SERVER_FIRST_UPDATE_NUMBER, collectionServerFirstUpdateNumber)) collectionServerFirstUpdateNumber = 0; ++collectionServerFirstUpdateNumber; IGNORE_RETURN(setObjVarItem(OBJVAR_COLLECTION_SERVER_FIRST_UPDATE_NUMBER, collectionServerFirstUpdateNumber)); m_collectionServerFirstUpdateNumber = collectionServerFirstUpdateNumber; m_collectionServerFirst.insert(std::make_pair(std::make_pair(static_cast(timeNow), collectionInfo.name), std::make_pair(claimantId, claimantName))); // let claimant know "server first" claim was successful MessageToQueue::getInstance().sendMessageToC(claimantId, "C++OnCollectionServerFirst", collectionInfo.name, 0, false); // CS log LOG("CustomerService", ("CollectionServerFirst:(%s/%s/%s) granted to %s at %ld (%s) (update #%d)", collectionInfo.page.book.name.c_str(), collectionInfo.page.name.c_str(), collectionInfo.name.c_str(), claimantAccountInfo.c_str(), timeNow, CalendarTime::convertEpochToTimeStringLocal(timeNow).c_str(), collectionServerFirstUpdateNumber)); } } else { Controller* const controller = getController(); if (!controller) { DEBUG_WARNING(true, ("PlanetObject::setCollectionServerFirst: planet object %s has no controller", getName().c_str())); return; } MessageQueueGenericValueType, std::pair > >* const message = new MessageQueueGenericValueType, std::pair > >(std::make_pair(std::make_pair(collectionInfo.name, claimantId), std::make_pair(claimantName, claimantAccountInfo))); controller->appendMessage(static_cast(CM_collectionRequestServerFirst), 0.f, message, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } // ---------------------------------------------------------------------- void PlanetObject::removeCollectionServerFirst(const CollectionsDataTable::CollectionInfoCollection& collectionInfo) { if (m_planetName.get() != "tatooine") return; if (isAuthoritative()) { const DynamicVariableList & objvars = getObjVars(); const std::string objvar = OBJVAR_COLLECTION_SERVER_FIRST + "." + collectionInfo.name; if (!objvars.hasItem(objvar) || (DynamicVariable::STRING_ARRAY != objvars.getType(objvar))) return; std::vector value; if (!objvars.getItem(objvar, value)) return; if (value.size() != 3) return; const time_t claimTime = static_cast(::atol(Unicode::wideToNarrow(value[0]).c_str())); const NetworkId claimantId = NetworkId(Unicode::wideToNarrow(value[1])); const Unicode::String claimantName = value[2]; removeObjVarItem(objvar); int collectionServerFirstUpdateNumber = 0; if (!objvars.getItem(OBJVAR_COLLECTION_SERVER_FIRST_UPDATE_NUMBER, collectionServerFirstUpdateNumber)) collectionServerFirstUpdateNumber = 0; ++collectionServerFirstUpdateNumber; IGNORE_RETURN(setObjVarItem(OBJVAR_COLLECTION_SERVER_FIRST_UPDATE_NUMBER, collectionServerFirstUpdateNumber)); m_collectionServerFirstUpdateNumber = collectionServerFirstUpdateNumber; IGNORE_RETURN(m_collectionServerFirst.erase(std::make_pair(std::make_pair(static_cast(claimTime), collectionInfo.name), std::make_pair(claimantId, claimantName)))); // CS log LOG("CustomerService", ("CollectionServerFirst:revoked (%s/%s/%s) which was granted to (%s, %s) at %ld (%s) (update #%d)", collectionInfo.page.book.name.c_str(), collectionInfo.page.name.c_str(), collectionInfo.name.c_str(), claimantId.getValueString().c_str(), Unicode::wideToNarrow(claimantName).c_str(), claimTime, CalendarTime::convertEpochToTimeStringLocal(claimTime).c_str(), collectionServerFirstUpdateNumber)); } else { Controller* const controller = getController(); if (!controller) { DEBUG_WARNING(true, ("PlanetObject::removeCollectionServerFirst: planet object %s has no controller", getName().c_str())); return; } MessageQueueGenericValueType* const message = new MessageQueueGenericValueType(collectionInfo.name); controller->appendMessage(static_cast(CM_collectionRevokeServerFirst), 0.f, message, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } // ---------------------------------------------------------------------- void PlanetObject::handleCMessageTo(MessageToPayload const &message) { if (message.getMethod() == "C++SetCollectionServerFirstTime") { if ((m_planetName.get() == "tatooine") && !message.getPackedDataVector().empty()) { std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); Unicode::String const delimiters(Unicode::narrowToWide("|")); Unicode::UnicodeStringVector tokens; if ((Unicode::tokenize(Unicode::narrowToWide(params), tokens, &delimiters, nullptr)) && (tokens.size() == 2)) { CollectionsDataTable::CollectionInfoCollection const * const collectionInfo = CollectionsDataTable::getCollectionByName(Unicode::wideToNarrow(tokens[0])); if (collectionInfo && collectionInfo->trackServerFirst && (collectionInfo->serverFirstClaimTime > 0)) { const DynamicVariableList & objvars = getObjVars(); const std::string objvar = OBJVAR_COLLECTION_SERVER_FIRST + "." + collectionInfo->name; if (objvars.hasItem(objvar) && (DynamicVariable::STRING_ARRAY == objvars.getType(objvar))) { std::vector value; if (objvars.getItem(objvar, value) && (value.size() == 3)) { const time_t serverFirstOldTime = static_cast(::atol(Unicode::wideToNarrow(value[0]).c_str())); const time_t serverFirstNewTime = static_cast(::atol(Unicode::wideToNarrow(tokens[1]).c_str())); if (serverFirstOldTime != serverFirstNewTime) { const NetworkId claimantId = NetworkId(Unicode::wideToNarrow(value[1])); const Unicode::String claimantName = value[2]; char buffer[64]; snprintf(buffer, sizeof(buffer)-1, "%ld", serverFirstNewTime); buffer[sizeof(buffer)-1] = '\0'; // set the "server first" new completion time value[0] = Unicode::narrowToWide(buffer); if (setObjVarItem(objvar, value)) { int collectionServerFirstUpdateNumber = 0; if (!objvars.getItem(OBJVAR_COLLECTION_SERVER_FIRST_UPDATE_NUMBER, collectionServerFirstUpdateNumber)) collectionServerFirstUpdateNumber = 0; ++collectionServerFirstUpdateNumber; IGNORE_RETURN(setObjVarItem(OBJVAR_COLLECTION_SERVER_FIRST_UPDATE_NUMBER, collectionServerFirstUpdateNumber)); m_collectionServerFirstUpdateNumber = collectionServerFirstUpdateNumber; IGNORE_RETURN(m_collectionServerFirst.erase(std::make_pair(std::make_pair(static_cast(serverFirstOldTime), collectionInfo->name), std::make_pair(claimantId, claimantName)))); m_collectionServerFirst.insert(std::make_pair(std::make_pair(static_cast(serverFirstNewTime), collectionInfo->name), std::make_pair(claimantId, claimantName))); // CS log LOG("CustomerService", ("CollectionServerFirst:(%s/%s/%s) \"server first\" completion time changed from %ld (%s) to %ld (%s) (update #%d)", collectionInfo->page.book.name.c_str(), collectionInfo->page.name.c_str(), collectionInfo->name.c_str(), serverFirstOldTime, CalendarTime::convertEpochToTimeStringLocal(serverFirstOldTime).c_str(), serverFirstNewTime, CalendarTime::convertEpochToTimeStringLocal(serverFirstNewTime).c_str(), collectionServerFirstUpdateNumber)); } } } } } } } } else if (message.getMethod() == "C++DoGcwDecay") { // start decay handling loop int const now = static_cast(::time(nullptr)); int timeNextGcwScoreDecay; if (!getObjVars().getItem("gcwScore.nextDecayTime", timeNextGcwScoreDecay) || (timeNextGcwScoreDecay <= 0)) { timeNextGcwScoreDecay = getNextGcwScoreDecayTime(now); if (timeNextGcwScoreDecay >= now) { setObjVarItem("gcwScore.nextDecayTime", timeNextGcwScoreDecay); } } if ((timeNextGcwScoreDecay <= now) && (timeNextGcwScoreDecay > 0)) { // decay GCW score LOG("CustomerService", ("GcwScore: decaying GCW score for period ending (%s)", CalendarTime::convertEpochToTimeStringGMT(timeNextGcwScoreDecay).c_str())); std::vector scoreObjvar(2); std::map > newGcwScore; std::set updatedScoreCategories; std::map >::const_iterator iterBegin = m_gcwImperialScore.begin(); std::map >::const_iterator iterEnd = m_gcwImperialScore.end(); for (; iterBegin != iterEnd; ++iterBegin) { newGcwScore[iterBegin->first] = std::make_pair((iterBegin->second.first / static_cast(2)) + (iterBegin->second.second / static_cast(2)), 0); } iterBegin = newGcwScore.begin(); iterEnd = newGcwScore.end(); for (; iterBegin != iterEnd; ++iterBegin) { updatedScoreCategories.insert(iterBegin->first); if (iterBegin->second.first <= 0) { m_gcwImperialScore.erase(iterBegin->first); removeObjVarItem("gcwScore.Imp." + iterBegin->first); } else { m_gcwImperialScore.set(iterBegin->first, iterBegin->second); scoreObjvar[0] = NetworkId(iterBegin->second.first); scoreObjvar[1] = NetworkId(iterBegin->second.second); setObjVarItem("gcwScore.Imp." + iterBegin->first, scoreObjvar); } } newGcwScore.clear(); iterBegin = m_gcwRebelScore.begin(); iterEnd = m_gcwRebelScore.end(); for (; iterBegin != iterEnd; ++iterBegin) { newGcwScore[iterBegin->first] = std::make_pair((iterBegin->second.first / static_cast(2)) + (iterBegin->second.second / static_cast(2)), 0); } iterBegin = newGcwScore.begin(); iterEnd = newGcwScore.end(); for (; iterBegin != iterEnd; ++iterBegin) { updatedScoreCategories.insert(iterBegin->first); if (iterBegin->second.first <= 0) { m_gcwRebelScore.erase(iterBegin->first); removeObjVarItem("gcwScore.Reb." + iterBegin->first); } else { m_gcwRebelScore.set(iterBegin->first, iterBegin->second); scoreObjvar[0] = NetworkId(iterBegin->second.first); scoreObjvar[1] = NetworkId(iterBegin->second.second); setObjVarItem("gcwScore.Reb." + iterBegin->first, scoreObjvar); } } // we need to recalculate the score percentile for score categories that change; // halving both the imperial and rebel score shouldn't cause the percentile to // change, but as the number gets smaller, integer division truncation will start // to cause the percentile to change; in the worse case, when one side hits 0, // the other side will immediately jump to 100%, and then when that side hits 0, // it then becomes 50/50 if (!updatedScoreCategories.empty()) { GuildObject * const go = ServerUniverse::getInstance().getMasterGuildObject(); if (go && go->isAuthoritative()) { go->updateGcwImperialScorePercentile(updatedScoreCategories); } } // set up next decay calculation time timeNextGcwScoreDecay = getNextGcwScoreDecayTime(now + 1); if (timeNextGcwScoreDecay > 0) { setObjVarItem("gcwScore.nextDecayTime", timeNextGcwScoreDecay); } } if (timeNextGcwScoreDecay > 0) { MessageToQueue::sendMessageToC(getNetworkId(), "C++DoGcwDecay", std::string(), std::max(0, timeNextGcwScoreDecay - now) + 1, false); } } else if (message.getMethod() == "C++DoGcwDecayImmediate") { if ((m_planetName.get() == "tatooine") && !message.getPackedDataVector().empty()) { bool recalculatePercentile = false; std::string const gcwScoreCategory(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); std::map >::const_iterator iterFind = m_gcwImperialScore.find(gcwScoreCategory); if (iterFind != m_gcwImperialScore.end()) { int64 const newScore = (iterFind->second.first / static_cast(2)) + (iterFind->second.second / static_cast(2)); if (newScore <= 0) { m_gcwImperialScore.erase(gcwScoreCategory); removeObjVarItem("gcwScore.Imp." + gcwScoreCategory); } else { m_gcwImperialScore.set(gcwScoreCategory, std::make_pair(newScore, 0)); std::vector scoreObjvar(2); scoreObjvar[0] = NetworkId(newScore); scoreObjvar[1] = NetworkId(static_cast(0)); setObjVarItem("gcwScore.Imp." + gcwScoreCategory, scoreObjvar); } recalculatePercentile = true; } iterFind = m_gcwRebelScore.find(gcwScoreCategory); if (iterFind != m_gcwRebelScore.end()) { int64 const newScore = (iterFind->second.first / static_cast(2)) + (iterFind->second.second / static_cast(2)); if (newScore <= 0) { m_gcwRebelScore.erase(gcwScoreCategory); removeObjVarItem("gcwScore.Reb." + gcwScoreCategory); } else { m_gcwRebelScore.set(gcwScoreCategory, std::make_pair(newScore, 0)); std::vector scoreObjvar(2); scoreObjvar[0] = NetworkId(newScore); scoreObjvar[1] = NetworkId(static_cast(0)); setObjVarItem("gcwScore.Reb." + gcwScoreCategory, scoreObjvar); } recalculatePercentile = true; } if (recalculatePercentile) { std::set updatedScoreCategories; updatedScoreCategories.insert(gcwScoreCategory); GuildObject * const go = ServerUniverse::getInstance().getMasterGuildObject(); if (go && go->isAuthoritative()) { go->updateGcwImperialScorePercentile(updatedScoreCategories); } } } } else { UniverseObject::handleCMessageTo(message); } } // ---------------------------------------------------------------------- void PlanetObject::endBaselines() { UniverseObject::endBaselines(); if (isAuthoritative() && (m_planetName.get() == "tatooine")) { // depersist GCW score std::vector scoreObjvar; { DynamicVariableList::NestedList const gcwImperialScore(getObjVars(), "gcwScore.Imp"); for (DynamicVariableList::NestedList::const_iterator i = gcwImperialScore.begin(); i != gcwImperialScore.end(); ++i) { if (Pvp::getGcwScoreCategory(i.getName()) && i.getValue(scoreObjvar) && (scoreObjvar.size() == 2)) m_gcwImperialScore.set(i.getName(), std::make_pair(scoreObjvar[0].getValue(), scoreObjvar[1].getValue())); } } { DynamicVariableList::NestedList const gcwRebelScore(getObjVars(), "gcwScore.Reb"); for (DynamicVariableList::NestedList::const_iterator i = gcwRebelScore.begin(); i != gcwRebelScore.end(); ++i) { if (Pvp::getGcwScoreCategory(i.getName()) && i.getValue(scoreObjvar) && (scoreObjvar.size() == 2)) m_gcwRebelScore.set(i.getName(), std::make_pair(scoreObjvar[0].getValue(), scoreObjvar[1].getValue())); } } // start decay handling loop int const now = static_cast(::time(nullptr)); int timeNextGcwScoreDecay; if (!getObjVars().getItem("gcwScore.nextDecayTime", timeNextGcwScoreDecay) || (timeNextGcwScoreDecay <= 0)) { timeNextGcwScoreDecay = getNextGcwScoreDecayTime(now); if (timeNextGcwScoreDecay >= now) { setObjVarItem("gcwScore.nextDecayTime", timeNextGcwScoreDecay); } } if (timeNextGcwScoreDecay > 0) { MessageToQueue::sendMessageToC(getNetworkId(), "C++DoGcwDecay", std::string(), std::max(0, timeNextGcwScoreDecay - now) + 1, false); } } } // ---------------------------------------------------------------------- void PlanetObject::setConnectedCharacterLfgData(const NetworkId & characterId, const LfgCharacterData & lfgCharacterData) { if (m_planetName.get() != "tatooine") return; if (isAuthoritative()) { std::map::const_iterator iterFind = m_connectedCharacterLfgData.find(characterId); if (iterFind != m_connectedCharacterLfgData.end()) { // don't call decrement followed by increment if it will result in the same // final value, as that causes an unnecessary change to the AutoDeltaMap, // causing the AutoDeltaMap change handlers to unnecessarily fire if (iterFind->second.locationFactionalPresenceGcwRegion != lfgCharacterData.locationFactionalPresenceGcwRegion) { decrementConnectedCharacterLfgDataFactionalPresenceCount(m_connectedCharacterLfgDataFactionalPresence, iterFind->second); incrementConnectedCharacterLfgDataFactionalPresenceCount(m_connectedCharacterLfgDataFactionalPresence, lfgCharacterData); decrementConnectedCharacterLfgDataFactionalPresenceGridCount(m_connectedCharacterLfgDataFactionalPresenceGrid, iterFind->second); incrementConnectedCharacterLfgDataFactionalPresenceGridCount(m_connectedCharacterLfgDataFactionalPresenceGrid, lfgCharacterData); } else if ((iterFind->second.faction != lfgCharacterData.faction) && !iterFind->second.locationFactionalPresenceGcwRegion.empty()) { decrementConnectedCharacterLfgDataFactionalPresenceCount(m_connectedCharacterLfgDataFactionalPresence, iterFind->second); incrementConnectedCharacterLfgDataFactionalPresenceCount(m_connectedCharacterLfgDataFactionalPresence, lfgCharacterData); decrementConnectedCharacterLfgDataFactionalPresenceGridCount(m_connectedCharacterLfgDataFactionalPresenceGrid, iterFind->second); incrementConnectedCharacterLfgDataFactionalPresenceGridCount(m_connectedCharacterLfgDataFactionalPresenceGrid, lfgCharacterData); } else if (((iterFind->second.locationFactionalPresenceGridX != lfgCharacterData.locationFactionalPresenceGridX) || (iterFind->second.locationFactionalPresenceGridZ != lfgCharacterData.locationFactionalPresenceGridZ)) && !iterFind->second.locationFactionalPresenceGcwRegion.empty()) { decrementConnectedCharacterLfgDataFactionalPresenceGridCount(m_connectedCharacterLfgDataFactionalPresenceGrid, iterFind->second); incrementConnectedCharacterLfgDataFactionalPresenceGridCount(m_connectedCharacterLfgDataFactionalPresenceGrid, lfgCharacterData); } } else { incrementConnectedCharacterLfgDataFactionalPresenceCount(m_connectedCharacterLfgDataFactionalPresence, lfgCharacterData); incrementConnectedCharacterLfgDataFactionalPresenceGridCount(m_connectedCharacterLfgDataFactionalPresenceGrid, lfgCharacterData); } m_connectedCharacterLfgData.set(characterId, lfgCharacterData); } else { Controller* const controller = getController(); if (!controller) { DEBUG_WARNING(true, ("PlanetObject::setConnectedCharacterLfgData: planet object %s has no controller", getName().c_str())); return; } MessageQueueGenericValueType >* const message = new MessageQueueGenericValueType >(std::make_pair(characterId, lfgCharacterData)); controller->appendMessage(static_cast(CM_setConnectedCharacterLfgData), 0.f, message, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } // ---------------------------------------------------------------------- ScriptParams const *PlanetObject::getConnectedCharacterLfgDataFactionalPresenceTableDictionary() { if (s_factionalPresenceSuiTableNeedRebuild) { delete s_factionalPresenceSuiTable; s_factionalPresenceSuiTable = nullptr; PlanetObject const * const tatooine = ServerUniverse::getInstance().getTatooinePlanet(); if (tatooine) { std::map > const & connectedCharacterLfgDataFactionalPresence = tatooine->getConnectedCharacterLfgDataFactionalPresence(); if (!connectedCharacterLfgDataFactionalPresence.empty()) { size_t const size = connectedCharacterLfgDataFactionalPresence.size(); s_factionalPresenceSuiTable = new ScriptParams(); std::vector * scriptParamsGcwContestedRegion = new std::vector(size); std::vector * scriptParamsImperial = new std::vector(size); std::vector * scriptParamsRebel = new std::vector(size); char buffer[128]; int index = 0; for (std::map >::const_iterator iter = connectedCharacterLfgDataFactionalPresence.begin(); iter != connectedCharacterLfgDataFactionalPresence.end(); ++iter, ++index) { snprintf(buffer, sizeof(buffer)-1, "@gcw_regions:%s", iter->first.c_str()); buffer[sizeof(buffer)-1] = '\0'; (*scriptParamsGcwContestedRegion)[index] = makeCopyOfString(buffer); (*scriptParamsImperial)[index] = makeCopyOfString((iter->second.first > 0) ? "X" : ""); (*scriptParamsRebel)[index] = makeCopyOfString((iter->second.second > 0) ? "X" : ""); } // column header static const char * s_scriptParamsColumnHeadersText[3] = { "Region", "Rebel", "Imperial" }; static std::vector s_scriptParamsColumnHeaders(s_scriptParamsColumnHeadersText, s_scriptParamsColumnHeadersText + (sizeof(s_scriptParamsColumnHeadersText) / sizeof(const char *))); // column type static const char * s_scriptParamsColumnTypeText[3] = { "text", "text", "text" }; static std::vector s_scriptParamsColumnType(s_scriptParamsColumnTypeText, s_scriptParamsColumnTypeText + (sizeof(s_scriptParamsColumnTypeText) / sizeof(const char *))); s_factionalPresenceSuiTable->addParam(s_scriptParamsColumnHeaders, "column", false); s_factionalPresenceSuiTable->addParam(s_scriptParamsColumnType, "columnType", false); s_factionalPresenceSuiTable->addParam(*scriptParamsGcwContestedRegion, "column0", true); s_factionalPresenceSuiTable->addParam(*scriptParamsRebel, "column1", true); s_factionalPresenceSuiTable->addParam(*scriptParamsImperial, "column2", true); } } s_factionalPresenceSuiTableNeedRebuild = false; } return s_factionalPresenceSuiTable; } // ---------------------------------------------------------------------- void PlanetObject::setConnectedCharacterGroupData(const NetworkId & characterId, const NetworkId & groupId) { if (m_planetName.get() != "tatooine") return; if (isAuthoritative()) { std::map::const_iterator iterFind = m_connectedCharacterLfgData.find(characterId); if ((iterFind != m_connectedCharacterLfgData.end()) && (iterFind->second.groupId != groupId)) { LfgCharacterData lfgCharacterData = iterFind->second; lfgCharacterData.groupId = groupId; m_connectedCharacterLfgData.set(characterId, lfgCharacterData); } } else { Controller* const controller = getController(); if (!controller) { DEBUG_WARNING(true, ("PlanetObject::setConnectedCharacterGroupData: planet object %s has no controller", getName().c_str())); return; } MessageQueueGenericValueType >* const message = new MessageQueueGenericValueType >(std::make_pair(characterId, groupId)); controller->appendMessage(static_cast(CM_setConnectedCharacterGroupData), 0.f, message, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } // ---------------------------------------------------------------------- void PlanetObject::setConnectedCharacterPlanetData(const NetworkId & characterId, const std::string & planetName) { if (m_planetName.get() != "tatooine") return; if (isAuthoritative()) { std::map::const_iterator iterFind = m_connectedCharacterLfgData.find(characterId); if ((iterFind != m_connectedCharacterLfgData.end()) && (iterFind->second.locationPlanet != planetName)) { LfgCharacterData lfgCharacterData = iterFind->second; decrementConnectedCharacterLfgDataFactionalPresenceCount(m_connectedCharacterLfgDataFactionalPresence, lfgCharacterData); decrementConnectedCharacterLfgDataFactionalPresenceGridCount(m_connectedCharacterLfgDataFactionalPresenceGrid, lfgCharacterData); lfgCharacterData.locationPlanet = planetName; // changing planet, clear region and player city info, which will get updated separately lfgCharacterData.locationRegion.clear(); lfgCharacterData.locationFactionalPresenceGcwRegion.clear(); lfgCharacterData.locationFactionalPresenceGridX = 0; lfgCharacterData.locationFactionalPresenceGridZ = 0; lfgCharacterData.locationPlayerCity.clear(); m_connectedCharacterLfgData.set(characterId, lfgCharacterData); } } else { Controller* const controller = getController(); if (!controller) { DEBUG_WARNING(true, ("PlanetObject::setConnectedCharacterPlanetData: planet object %s has no controller", getName().c_str())); return; } MessageQueueGenericValueType >* const message = new MessageQueueGenericValueType >(std::make_pair(planetName, characterId)); controller->appendMessage(static_cast(CM_setConnectedCharacterPlanetData), 0.f, message, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } // ---------------------------------------------------------------------- void PlanetObject::setConnectedCharacterRegionData(const NetworkId & characterId, const std::string & regionName) { if (m_planetName.get() != "tatooine") return; if (isAuthoritative()) { std::map::const_iterator iterFind = m_connectedCharacterLfgData.find(characterId); if ((iterFind != m_connectedCharacterLfgData.end()) && (iterFind->second.locationRegion != regionName)) { LfgCharacterData lfgCharacterData = iterFind->second; lfgCharacterData.locationRegion = regionName; m_connectedCharacterLfgData.set(characterId, lfgCharacterData); } } else { Controller* const controller = getController(); if (!controller) { DEBUG_WARNING(true, ("PlanetObject::setConnectedCharacterRegionData: planet object %s has no controller", getName().c_str())); return; } MessageQueueGenericValueType >* const message = new MessageQueueGenericValueType >(std::make_pair(regionName, characterId)); controller->appendMessage(static_cast(CM_setConnectedCharacterRegionData), 0.f, message, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } // ---------------------------------------------------------------------- void PlanetObject::setConnectedCharacterPlayerCityData(const NetworkId & characterId, const std::string & playerCityName) { if (m_planetName.get() != "tatooine") return; if (isAuthoritative()) { std::map::const_iterator iterFind = m_connectedCharacterLfgData.find(characterId); if ((iterFind != m_connectedCharacterLfgData.end()) && (iterFind->second.locationPlayerCity != playerCityName)) { LfgCharacterData lfgCharacterData = iterFind->second; lfgCharacterData.locationPlayerCity = playerCityName; m_connectedCharacterLfgData.set(characterId, lfgCharacterData); } } else { Controller* const controller = getController(); if (!controller) { DEBUG_WARNING(true, ("PlanetObject::setConnectedCharacterPlayerCityData: planet object %s has no controller", getName().c_str())); return; } MessageQueueGenericValueType >* const message = new MessageQueueGenericValueType >(std::make_pair(playerCityName, characterId)); controller->appendMessage(static_cast(CM_setConnectedCharacterPlayerCityData), 0.f, message, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } // ---------------------------------------------------------------------- void PlanetObject::setConnectedCharacterLevelData(const NetworkId & characterId, int16 level) { if (m_planetName.get() != "tatooine") return; if (isAuthoritative()) { std::map::const_iterator iterFind = m_connectedCharacterLfgData.find(characterId); if ((iterFind != m_connectedCharacterLfgData.end()) && (iterFind->second.level != level)) { LfgCharacterData lfgCharacterData = iterFind->second; lfgCharacterData.level = level; m_connectedCharacterLfgData.set(characterId, lfgCharacterData); } } else { Controller* const controller = getController(); if (!controller) { DEBUG_WARNING(true, ("PlanetObject::setConnectedCharacterLevelData: planet object %s has no controller", getName().c_str())); return; } MessageQueueGenericValueType >* const message = new MessageQueueGenericValueType >(std::make_pair(characterId, static_cast(level))); controller->appendMessage(static_cast(CM_setConnectedCharacterLevelData), 0.f, message, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } // ---------------------------------------------------------------------- void PlanetObject::setConnectedCharacterProfessionData(const NetworkId & characterId, LfgCharacterData::Profession profession) { if (m_planetName.get() != "tatooine") return; if (isAuthoritative()) { std::map::const_iterator iterFind = m_connectedCharacterLfgData.find(characterId); if ((iterFind != m_connectedCharacterLfgData.end()) && (iterFind->second.profession != profession)) { LfgCharacterData lfgCharacterData = iterFind->second; lfgCharacterData.profession = profession; m_connectedCharacterLfgData.set(characterId, lfgCharacterData); } } else { Controller* const controller = getController(); if (!controller) { DEBUG_WARNING(true, ("PlanetObject::setConnectedCharacterProfessionData: planet object %s has no controller", getName().c_str())); return; } MessageQueueGenericValueType >* const message = new MessageQueueGenericValueType >(std::make_pair(characterId, static_cast(profession))); controller->appendMessage(static_cast(CM_setConnectedCharacterProfessionData), 0.f, message, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } // ---------------------------------------------------------------------- void PlanetObject::setConnectedCharacterSearchableByCtsSourceGalaxyData(const NetworkId & characterId, bool searchableByCtsSourceGalaxy) { if (m_planetName.get() != "tatooine") return; if (isAuthoritative()) { std::map::const_iterator iterFind = m_connectedCharacterLfgData.find(characterId); if ((iterFind != m_connectedCharacterLfgData.end()) && (iterFind->second.searchableByCtsSourceGalaxy != searchableByCtsSourceGalaxy)) { LfgCharacterData lfgCharacterData = iterFind->second; lfgCharacterData.searchableByCtsSourceGalaxy = searchableByCtsSourceGalaxy; m_connectedCharacterLfgData.set(characterId, lfgCharacterData); } } else { Controller* const controller = getController(); if (!controller) { DEBUG_WARNING(true, ("PlanetObject::setConnectedCharacterSearchableByCtsSourceGalaxyData: planet object %s has no controller", getName().c_str())); return; } MessageQueueGenericValueType >* const message = new MessageQueueGenericValueType >(std::make_pair(characterId, static_cast(searchableByCtsSourceGalaxy ? 1 : 0))); controller->appendMessage(static_cast(CM_setConnectedCharacterSearchableByCtsSourceGalaxyData), 0.f, message, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } // ---------------------------------------------------------------------- void PlanetObject::setConnectedCharacterDisplayLocationInSearchResultsData(const NetworkId & characterId, bool displayLocationInSearchResults) { if (m_planetName.get() != "tatooine") return; if (isAuthoritative()) { std::map::const_iterator iterFind = m_connectedCharacterLfgData.find(characterId); if ((iterFind != m_connectedCharacterLfgData.end()) && (iterFind->second.displayLocationInSearchResults != displayLocationInSearchResults)) { LfgCharacterData lfgCharacterData = iterFind->second; lfgCharacterData.displayLocationInSearchResults = displayLocationInSearchResults; m_connectedCharacterLfgData.set(characterId, lfgCharacterData); } } else { Controller* const controller = getController(); if (!controller) { DEBUG_WARNING(true, ("PlanetObject::setConnectedCharacterDisplayLocationInSearchResultsData: planet object %s has no controller", getName().c_str())); return; } MessageQueueGenericValueType >* const message = new MessageQueueGenericValueType >(std::make_pair(characterId, static_cast(displayLocationInSearchResults ? 1 : 0))); controller->appendMessage(static_cast(CM_setConnectedCharacterDisplayLocationInSearchResultsData), 0.f, message, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } // ---------------------------------------------------------------------- void PlanetObject::setConnectedCharacterAnonymousData(const NetworkId & characterId, bool anonymous) { if (m_planetName.get() != "tatooine") return; if (isAuthoritative()) { std::map::const_iterator iterFind = m_connectedCharacterLfgData.find(characterId); if ((iterFind != m_connectedCharacterLfgData.end()) && (iterFind->second.anonymous != anonymous)) { LfgCharacterData lfgCharacterData = iterFind->second; lfgCharacterData.anonymous = anonymous; m_connectedCharacterLfgData.set(characterId, lfgCharacterData); } } else { Controller* const controller = getController(); if (!controller) { DEBUG_WARNING(true, ("PlanetObject::setConnectedCharacterAnonymousData: planet object %s has no controller", getName().c_str())); return; } MessageQueueGenericValueType >* const message = new MessageQueueGenericValueType >(std::make_pair(characterId, static_cast(anonymous ? 1 : 0))); controller->appendMessage(static_cast(CM_setConnectedCharacterAnonymousData), 0.f, message, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } // ---------------------------------------------------------------------- void PlanetObject::setConnectedCharacterInterestsData(const NetworkId & characterId, BitArray const & interests) { if (m_planetName.get() != "tatooine") return; if (isAuthoritative()) { std::map::const_iterator iterFind = m_connectedCharacterLfgData.find(characterId); if ((iterFind != m_connectedCharacterLfgData.end()) && (iterFind->second.characterInterests != interests)) { LfgCharacterData lfgCharacterData = iterFind->second; lfgCharacterData.characterInterests = interests; m_connectedCharacterLfgData.set(characterId, lfgCharacterData); } } else { Controller* const controller = getController(); if (!controller) { DEBUG_WARNING(true, ("PlanetObject::setConnectedCharacterInterestsData: planet object %s has no controller", getName().c_str())); return; } MessageQueueGenericValueType >* const message = new MessageQueueGenericValueType >(std::make_pair(characterId, interests)); controller->appendMessage(static_cast(CM_setConnectedCharacterInterestsData), 0.f, message, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } // ---------------------------------------------------------------------- void PlanetObject::setConnectedCharacterBiographyData(const NetworkId & characterId, const Unicode::String & biography) { if (m_planetName.get() != "tatooine") return; if (isAuthoritative()) { m_connectedCharacterBiographyData.set(characterId, biography); } else { Controller* const controller = getController(); if (!controller) { DEBUG_WARNING(true, ("PlanetObject::setConnectedCharacterBiographyData: planet object %s has no controller", getName().c_str())); return; } MessageQueueGenericValueType >* const message = new MessageQueueGenericValueType >(std::make_pair(biography, characterId)); controller->appendMessage(static_cast(CM_setConnectedCharacterBiographyData), 0.f, message, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } // ---------------------------------------------------------------------- void PlanetObject::removeConnectedCharacterBiographyData(const NetworkId & characterId) { if (m_planetName.get() != "tatooine") return; if (isAuthoritative()) { IGNORE_RETURN(m_connectedCharacterBiographyData.erase(characterId)); } else { Controller* const controller = getController(); if (!controller) { DEBUG_WARNING(true, ("PlanetObject::removeConnectedCharacterBiographyData: planet object %s has no controller", getName().c_str())); return; } MessageQueueGenericValueType* const message = new MessageQueueGenericValueType(characterId); controller->appendMessage(static_cast(CM_removeConnectedCharacterBiographyData), 0.f, message, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } // ---------------------------------------------------------------------- void PlanetObject::removeConnectedCharacterData(const NetworkId & characterId) { if (m_planetName.get() != "tatooine") return; if (isAuthoritative()) { std::map::const_iterator iterFind = m_connectedCharacterLfgData.find(characterId); if (iterFind != m_connectedCharacterLfgData.end()) { decrementConnectedCharacterLfgDataFactionalPresenceCount(m_connectedCharacterLfgDataFactionalPresence, iterFind->second); decrementConnectedCharacterLfgDataFactionalPresenceGridCount(m_connectedCharacterLfgDataFactionalPresenceGrid, iterFind->second); IGNORE_RETURN(m_connectedCharacterLfgData.erase(characterId)); } } else { Controller* const controller = getController(); if (!controller) { DEBUG_WARNING(true, ("PlanetObject::removeConnectedCharacterData: planet object %s has no controller", getName().c_str())); return; } MessageQueueGenericValueType* const message = new MessageQueueGenericValueType(characterId); controller->appendMessage(static_cast(CM_removeConnectedCharacterData), 0.f, message, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } // ---------------------------------------------------------------------- PlanetObject::CollectionServerFirstObserver::CollectionServerFirstObserver(PlanetObject *planet, Archive::AutoDeltaObserverOp) : m_target(planet) { } // ---------------------------------------------------------------------- PlanetObject::CollectionServerFirstObserver::~CollectionServerFirstObserver() { if (m_target && (m_target->m_planetName.get() == "tatooine")) { CollectionsDataTable::setServerFirstData(m_target->m_collectionServerFirst.get()); } } // ---------------------------------------------------------------------- void PlanetObject::addUniverseEvent(std::string const & eventName) { if(m_planetName.get() != "tatooine") return; if(isAuthoritative()) { std::string current = m_currentEvents.get(); std::vector currentEventVector; ParseEventString(current, currentEventVector); std::vector::size_type i = 0; for(; i < currentEventVector.size(); ++i) { if(currentEventVector[i] == eventName) { return; } } if(current.empty()) current.append(eventName); else { current.append(","); current.append(eventName); } m_currentEvents.set(current); } else { Controller* const controller = getController(); if (!controller) { DEBUG_WARNING(true, ("PlanetObject::addUniverseEvent: planet object %s has no controller", getName().c_str())); return; } MessageQueueGenericValueType* const message = new MessageQueueGenericValueType(eventName); controller->appendMessage(static_cast(CM_addUniverseEvent), 0.f, message, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } // ---------------------------------------------------------------------- void PlanetObject::removeUniverseEvent(std::string const & eventName) { if(m_planetName.get() != "tatooine") return; if(isAuthoritative()) { std::string current = m_currentEvents.get(); std::string::size_type index = current.find(eventName); if( index == std::string::npos) return; // Event currently isn't running. // Sanity check because of how String find works. ////////////////////////////////////////////////// std::vector currentEventVector; bool entryValidated = false; ParseEventString(current, currentEventVector); std::vector::size_type i = 0; for(; i < currentEventVector.size(); ++i) { if(currentEventVector[i].first == eventName) { index = currentEventVector[i].second; entryValidated = true; } } if(!entryValidated) return; ////////////////////////////////////////////////// if(index != 0) // See if we need to clean up the prepending ','. current = current.erase(index - 1, eventName.size() + 1); else current = current.erase(index, index + eventName.size()); m_currentEvents.set(current); } else { Controller* const controller = getController(); if (!controller) { DEBUG_WARNING(true, ("PlanetObject::removeUniverseEvent: planet object %s has no controller", getName().c_str())); return; } MessageQueueGenericValueType* const message = new MessageQueueGenericValueType(eventName); controller->appendMessage(static_cast(CM_removeUniverseEvent), 0.f, message, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } // ---------------------------------------------------------------------- std::string const & PlanetObject::getCurrentEvents() const { return m_currentEvents.get(); } // ---------------------------------------------------------------------- void PlanetObject::EventsUpdatedCallback::modified(PlanetObject &/*target*/, std::string oldValue, std::string value, bool /*isLocal*/) { if(oldValue != value) { std::vector oldList; std::vector newList; ParseEventString(oldValue, oldList); ParseEventString(value, newList); // First lets find out what events stopped. - O(n) UGHHHhhhhhh std::vector::size_type i = 0; std::vector::size_type oldListSize = oldList.size(); std::vector::size_type newListSize = newList.size(); for(; i < oldListSize; ++i) { bool found = false; std::vector::size_type j = 0; for(; j < newListSize; ++j) { if(newList[j] == oldList[i]) { found = true; break; } } if(!found) { DEBUG_WARNING(ms_printEventDebug, ("------- PlanetObject - Trying to stop Event %s -------\n", oldList[i].c_str())); ServerBuildoutManager::onEventStopped(oldList[i]); } } // Now let's find out what events have started. - Same as above. Perhaps change this to a map/set/something else? i = 0; for(; i < newListSize; ++i) { bool found = false; std::vector::size_type j = 0; for(; j < oldListSize; ++j) { if(oldList[j] == newList[i]) { found = true; break; } } if(!found) { DEBUG_WARNING(ms_printEventDebug, ("------- PlanetObject - Trying to start Event %s -------\n", newList[i].c_str())); ServerBuildoutManager::onEventStarted(newList[i]); } } } } // ---------------------------------------------------------------------- void PlanetObject::parseCurrentEventsList(std::vector & outVector) { std::string const events = getCurrentEvents(); ParseEventString(events, outVector); } // ---------------------------------------------------------------------- void PlanetObject::updateGcwTrackingData() { // send our GCW score to the other clusters and process GCW scores we received from other clusters if (isAuthoritative() && (ConfigServerGame::getBroadcastGcwScoreToOtherGalaxies() || ConfigServerGame::getReceiveGcwScoreFromOtherGalaxies())) { static time_t timeNextBroadcast = ::time(nullptr) + ConfigServerGame::getBroadcastGcwScoreToOtherGalaxiesIntervalSeconds(); time_t const timeNow = ::time(nullptr); if (timeNextBroadcast < timeNow) { if (ConfigServerGame::getBroadcastGcwScoreToOtherGalaxies()) { std::string const & clusterName = GameServer::getInstance().getClusterName(); GuildObject const * guildObject = ServerUniverse::getInstance().getMasterGuildObject(); if (!clusterName.empty() && guildObject && guildObject->isAuthoritative()) { #ifdef _DEBUG // to allow testing without having to have another cluster std::string gcwScoreReportDifferentClusterName; getObjVars().getItem("gcwScoreReportDifferentClusterName", gcwScoreReportDifferentClusterName); const GenericValueTypeMessage >, std::map > > > > gcwScoreStatRaw("GcwScoreStatRaw", std::make_pair((gcwScoreReportDifferentClusterName.empty() ? clusterName : gcwScoreReportDifferentClusterName), std::make_pair(getGcwImperialScore(), getGcwRebelScore()))); const GenericValueTypeMessage, std::map > > > gcwScoreStatPct("GcwScoreStatPct", std::make_pair((gcwScoreReportDifferentClusterName.empty() ? clusterName : gcwScoreReportDifferentClusterName), std::make_pair(guildObject->getGcwImperialScorePercentile(), guildObject->getGcwGroupImperialScorePercentile()))); #else const GenericValueTypeMessage >, std::map > > > > gcwScoreStatRaw("GcwScoreStatRaw", std::make_pair(clusterName, std::make_pair(getGcwImperialScore(), getGcwRebelScore()))); const GenericValueTypeMessage, std::map > > > gcwScoreStatPct("GcwScoreStatPct", std::make_pair(clusterName, std::make_pair(guildObject->getGcwImperialScorePercentile(), guildObject->getGcwGroupImperialScorePercentile()))); #endif GameServer::getInstance().sendToCentralServer(gcwScoreStatRaw); GameServer::getInstance().sendToCentralServer(gcwScoreStatPct); } } if (ConfigServerGame::getReceiveGcwScoreFromOtherGalaxies()) { GuildObject * guildObject = ServerUniverse::getInstance().getMasterGuildObject(); if (guildObject && guildObject->isAuthoritative()) { guildObject->calculateGcwImperialScorePercentileForSwg(); } } timeNextBroadcast = timeNow + ConfigServerGame::getBroadcastGcwScoreToOtherGalaxiesIntervalSeconds(); } } if (m_nextGcwTrackingUpdate == 0) return; if (ServerClock::getInstance().getGameTimeSeconds() <= m_nextGcwTrackingUpdate) return; if (!isAuthoritative()) { // send updates to auth game server Controller *controller = getController(); if (controller) { if (!m_gcwImperialScoreAdjustment.empty()) { controller->appendMessage( CM_adjustGcwImperialScore, 0.0f, new MessageQueueGenericValueType >(m_gcwImperialScoreAdjustment), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } if (!m_gcwRebelScoreAdjustment.empty()) { controller->appendMessage( CM_adjustGcwRebelScore, 0.0f, new MessageQueueGenericValueType >(m_gcwRebelScoreAdjustment), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } } else { static std::pair score; static std::vector scoreObjvar(2); // we'll need to recalculate the score percentile for score categories that change std::set updatedScoreCategories; std::map >::const_iterator iterFind; { for (std::map::const_iterator iterImp = m_gcwImperialScoreAdjustment.begin(); iterImp != m_gcwImperialScoreAdjustment.end(); ++iterImp) { if (iterImp->second == 0ll) continue; iterFind = m_gcwImperialScore.find(iterImp->first); if (iterFind != m_gcwImperialScore.end()) { score.first = iterFind->second.first; score.second = iterFind->second.second + (iterImp->second * static_cast(Pvp::c_gcwScoreScaleFactor)); } else { score.first = 0ll; score.second = iterImp->second * static_cast(Pvp::c_gcwScoreScaleFactor); } // handle negative score if (score.second < 0ll) { score.second = 0ll; } m_gcwImperialScore.set(iterImp->first, score); scoreObjvar[0] = NetworkId(score.first); scoreObjvar[1] = NetworkId(score.second); setObjVarItem("gcwScore.Imp." + iterImp->first, scoreObjvar); updatedScoreCategories.insert(iterImp->first); } } { for (std::map::const_iterator iterReb = m_gcwRebelScoreAdjustment.begin(); iterReb != m_gcwRebelScoreAdjustment.end(); ++iterReb) { if (iterReb->second == 0ll) continue; iterFind = m_gcwRebelScore.find(iterReb->first); if (iterFind != m_gcwRebelScore.end()) { score.first = iterFind->second.first; score.second = iterFind->second.second + (iterReb->second * static_cast(Pvp::c_gcwScoreScaleFactor)); } else { score.first = 0ll; score.second = iterReb->second * static_cast(Pvp::c_gcwScoreScaleFactor); } // handle negative score if (score.second < 0ll) { score.second = 0ll; } m_gcwRebelScore.set(iterReb->first, score); scoreObjvar[0] = NetworkId(score.first); scoreObjvar[1] = NetworkId(score.second); setObjVarItem("gcwScore.Reb." + iterReb->first, scoreObjvar); updatedScoreCategories.insert(iterReb->first); } } // we need to recalculate the score percentile for score categories that change if (!updatedScoreCategories.empty()) { GuildObject * const go = ServerUniverse::getInstance().getMasterGuildObject(); if (go && go->isAuthoritative()) { go->updateGcwImperialScorePercentile(updatedScoreCategories); } } } m_gcwImperialScoreAdjustment.clear(); m_gcwRebelScoreAdjustment.clear(); m_nextGcwTrackingUpdate = 0; } // ---------------------------------------------------------------------- void PlanetObject::adjustGcwImperialScore(std::string const & source, CreatureObject * sourceObject, std::string const & gcwCategory, int64 adjustment) { Pvp::GcwScoreCategory const * const gcwCategoryData = Pvp::getGcwScoreCategory(gcwCategory); if (!gcwCategoryData) return; // queue up adjustments and periodically update the data if (source != "CM_adjustGcwImperialScore") { if (sourceObject) { // if object is player object, store GCW contribution tracking information PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(sourceObject); if (playerObject) { int const timeNow = static_cast(::time(nullptr)); IGNORE_RETURN(playerObject->setObjVarItem(std::string("gcwContributionTracking.") + gcwCategory, timeNow)); IGNORE_RETURN(playerObject->setObjVarItem(std::string("gcwContributionTrackingLastUpdated"), timeNow)); // grant GCW Region Defender bonus float bonus = 0.0f; if (gcwCategoryData->gcwRegionDefender && PvpData::isImperialFactionId(sourceObject->getPvpFaction()) && (adjustment > 0) && (playerObject->getCurrentGcwRegion() == gcwCategory) && Pvp::getGcwDefenderRegionBonus(*sourceObject, *playerObject, bonus) && (bonus > 0.0f)) adjustment += std::max(1ll, static_cast(static_cast(bonus) * static_cast(adjustment) / static_cast(100))); } LOG("CustomerService", ("GcwScore: imperial %s %d (from %s - %s)", gcwCategory.c_str(), static_cast(adjustment), source.c_str(), sourceObject->getNetworkId().getValueString().c_str())); } else { LOG("CustomerService", ("GcwScore: imperial %s %d (from %s)", gcwCategory.c_str(), static_cast(adjustment), source.c_str())); } } std::pair::iterator, bool> result = m_gcwImperialScoreAdjustment.insert(std::make_pair(gcwCategory, adjustment)); if (!result.second) result.first->second += adjustment; // non-auth game servers send their updates to auth game server in/every 10 seconds; // auth game server updates the universe data in/every 60 seconds if (m_nextGcwTrackingUpdate == 0) m_nextGcwTrackingUpdate = ServerClock::getInstance().getGameTimeSeconds() + (isAuthoritative() ? 60 : 10); } // ---------------------------------------------------------------------- void PlanetObject::adjustGcwRebelScore(std::string const & source, CreatureObject * sourceObject, std::string const & gcwCategory, int64 adjustment) { Pvp::GcwScoreCategory const * const gcwCategoryData = Pvp::getGcwScoreCategory(gcwCategory); if (!gcwCategoryData) return; // queue up adjustments and periodically update the data if (source != "CM_adjustGcwRebelScore") { if (sourceObject) { // if object is player object, store GCW contribution tracking information PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(sourceObject); if (playerObject) { int const timeNow = static_cast(::time(nullptr)); IGNORE_RETURN(playerObject->setObjVarItem(std::string("gcwContributionTracking.") + gcwCategory, timeNow)); IGNORE_RETURN(playerObject->setObjVarItem(std::string("gcwContributionTrackingLastUpdated"), timeNow)); // grant GCW Region Defender bonus float bonus = 0.0f; if (gcwCategoryData->gcwRegionDefender && PvpData::isRebelFactionId(sourceObject->getPvpFaction()) && (adjustment > 0) && (playerObject->getCurrentGcwRegion() == gcwCategory) && Pvp::getGcwDefenderRegionBonus(*sourceObject, *playerObject, bonus) && (bonus > 0.0f)) adjustment += std::max(1ll, static_cast(static_cast(bonus) * static_cast(adjustment) / static_cast(100))); } LOG("CustomerService", ("GcwScore: rebel %s %d (from %s - %s)", gcwCategory.c_str(), static_cast(adjustment), source.c_str(), sourceObject->getNetworkId().getValueString().c_str())); } else { LOG("CustomerService", ("GcwScore: rebel %s %d (from %s)", gcwCategory.c_str(), static_cast(adjustment), source.c_str())); } } std::pair::iterator, bool> result = m_gcwRebelScoreAdjustment.insert(std::make_pair(gcwCategory, adjustment)); if (!result.second) result.first->second += adjustment; // non-auth game servers send their updates to auth game server in/every 10 seconds; // auth game server updates the universe data in/every 60 seconds if (m_nextGcwTrackingUpdate == 0) m_nextGcwTrackingUpdate = ServerClock::getInstance().getGameTimeSeconds() + (isAuthoritative() ? 60 : 10); } // ---------------------------------------------------------------------- // the rebel score is 100 - the imperial score int PlanetObject::getGcwImperialScorePercentile(std::string const & gcwCategory) const { return Pvp::calculateGcwImperialScorePercentile(gcwCategory, m_gcwImperialScore.getMap(), m_gcwRebelScore.getMap()); } // ---------------------------------------------------------------------- int PlanetObjectNamespace::getNextGcwScoreDecayTime(int base) { int nextTime = -1; int time; std::vector, std::pair > > const & gcwScoreDecayTime = ConfigServerGame::getGcwScoreDecayTime(); for (std::vector, std::pair > >::const_iterator iter = gcwScoreDecayTime.begin(); iter != gcwScoreDecayTime.end(); ++iter) { time = static_cast(CalendarTime::getNextGMTTimeOcurrence(static_cast(base), iter->first.first, iter->first.second, iter->second.first, iter->second.second)); if (time > 0) { if ((nextTime < 0) || (time < nextTime)) nextTime = time; } } if (nextTime < 0) nextTime = static_cast(::time(nullptr)) + (60 * 60 * 24 * 7); return nextTime; } // ---------------------------------------------------------------------- void PlanetObjectNamespace::decrementConnectedCharacterLfgDataFactionalPresenceCount(Archive::AutoDeltaMap, PlanetObject> & connectedCharacterLfgDataFactionalPresence, const LfgCharacterData & lfgCharacterData) { if (!lfgCharacterData.locationFactionalPresenceGcwRegion.empty()) { std::map >::const_iterator iterFindFactionPresence = connectedCharacterLfgDataFactionalPresence.find(lfgCharacterData.locationFactionalPresenceGcwRegion); if (iterFindFactionPresence != connectedCharacterLfgDataFactionalPresence.end()) { std::pair count = iterFindFactionPresence->second; if (PvpData::isImperialFactionId(lfgCharacterData.faction)) count.first = std::max(0, count.first - 1); else if (PvpData::isRebelFactionId(lfgCharacterData.faction)) count.second = std::max(0, count.second - 1); if ((count.first <= 0) && (count.second <= 0)) IGNORE_RETURN(connectedCharacterLfgDataFactionalPresence.erase(lfgCharacterData.locationFactionalPresenceGcwRegion)); else connectedCharacterLfgDataFactionalPresence.set(lfgCharacterData.locationFactionalPresenceGcwRegion, count); } } } // ---------------------------------------------------------------------- void PlanetObjectNamespace::incrementConnectedCharacterLfgDataFactionalPresenceCount(Archive::AutoDeltaMap, PlanetObject> & connectedCharacterLfgDataFactionalPresence, const LfgCharacterData & lfgCharacterData) { if (!lfgCharacterData.locationFactionalPresenceGcwRegion.empty()) { std::map >::const_iterator iterFindFactionPresence = connectedCharacterLfgDataFactionalPresence.find(lfgCharacterData.locationFactionalPresenceGcwRegion); if (iterFindFactionPresence != connectedCharacterLfgDataFactionalPresence.end()) { if (PvpData::isImperialFactionId(lfgCharacterData.faction)) connectedCharacterLfgDataFactionalPresence.set(lfgCharacterData.locationFactionalPresenceGcwRegion, std::make_pair(iterFindFactionPresence->second.first + 1, iterFindFactionPresence->second.second)); else if (PvpData::isRebelFactionId(lfgCharacterData.faction)) connectedCharacterLfgDataFactionalPresence.set(lfgCharacterData.locationFactionalPresenceGcwRegion, std::make_pair(iterFindFactionPresence->second.first, iterFindFactionPresence->second.second + 1)); } else if (PvpData::isImperialFactionId(lfgCharacterData.faction)) { connectedCharacterLfgDataFactionalPresence.set(lfgCharacterData.locationFactionalPresenceGcwRegion, std::make_pair(1, 0)); } else if (PvpData::isRebelFactionId(lfgCharacterData.faction)) { connectedCharacterLfgDataFactionalPresence.set(lfgCharacterData.locationFactionalPresenceGcwRegion, std::make_pair(0, 1)); } } } // ---------------------------------------------------------------------- void PlanetObjectNamespace::decrementConnectedCharacterLfgDataFactionalPresenceGridCount(Archive::AutoDeltaMap >, std::pair > > & connectedCharacterLfgDataFactionalPresenceGrid, const LfgCharacterData & lfgCharacterData) { // factional presence grid tracking is only used for ground if (::strncmp("space_", lfgCharacterData.locationPlanet.c_str(), 6) == 0) return; if (!lfgCharacterData.locationFactionalPresenceGcwRegion.empty()) { std::map >, std::pair > >::const_iterator iterFindFactionPresence = connectedCharacterLfgDataFactionalPresenceGrid.find(std::make_pair(lfgCharacterData.locationPlanet, std::make_pair(lfgCharacterData.locationFactionalPresenceGridX, lfgCharacterData.locationFactionalPresenceGridZ))); if (iterFindFactionPresence != connectedCharacterLfgDataFactionalPresenceGrid.end()) { std::pair > const oldValue = iterFindFactionPresence->second; std::pair > newValue = iterFindFactionPresence->second; if (PvpData::isImperialFactionId(lfgCharacterData.faction)) newValue.second.first = std::max(0, newValue.second.first - 1); else if (PvpData::isRebelFactionId(lfgCharacterData.faction)) newValue.second.second = std::max(0, newValue.second.second - 1); if ((newValue.second.first <= 0) && (newValue.second.second <= 0)) { IGNORE_RETURN(connectedCharacterLfgDataFactionalPresenceGrid.erase(std::make_pair(lfgCharacterData.locationPlanet, std::make_pair(lfgCharacterData.locationFactionalPresenceGridX, lfgCharacterData.locationFactionalPresenceGridZ)))); // remove from planet map location if ((oldValue.second.first > 0) || (oldValue.second.second > 0)) removeFactionalPresenceGridFromPlanetMap(lfgCharacterData.locationPlanet, oldValue.first); } else { // non-zero -> 0 if ((oldValue.second.first != newValue.second.first) && (newValue.second.first <= 0)) { removeFactionalPresenceGridFromPlanetMap(lfgCharacterData.locationPlanet, oldValue.first); newValue.first = ObjectIdManager::getInstance().getNewObjectId(); addFactionalPresenceGridToPlanetMap(lfgCharacterData.locationPlanet, newValue.first, lfgCharacterData.locationFactionalPresenceGridX, lfgCharacterData.locationFactionalPresenceGridZ, (newValue.second.first > 0), (newValue.second.second > 0)); } else if ((oldValue.second.second != newValue.second.second) && (newValue.second.second <= 0)) { removeFactionalPresenceGridFromPlanetMap(lfgCharacterData.locationPlanet, oldValue.first); newValue.first = ObjectIdManager::getInstance().getNewObjectId(); addFactionalPresenceGridToPlanetMap(lfgCharacterData.locationPlanet, newValue.first, lfgCharacterData.locationFactionalPresenceGridX, lfgCharacterData.locationFactionalPresenceGridZ, (newValue.second.first > 0), (newValue.second.second > 0)); } connectedCharacterLfgDataFactionalPresenceGrid.set(std::make_pair(lfgCharacterData.locationPlanet, std::make_pair(lfgCharacterData.locationFactionalPresenceGridX, lfgCharacterData.locationFactionalPresenceGridZ)), newValue); } } } } // ---------------------------------------------------------------------- void PlanetObjectNamespace::incrementConnectedCharacterLfgDataFactionalPresenceGridCount(Archive::AutoDeltaMap >, std::pair > > & connectedCharacterLfgDataFactionalPresenceGrid, const LfgCharacterData & lfgCharacterData) { // factional presence grid tracking is only used for ground if (::strncmp("space_", lfgCharacterData.locationPlanet.c_str(), 6) == 0) return; if (!lfgCharacterData.locationFactionalPresenceGcwRegion.empty()) { std::pair > oldValue; std::pair > newValue; std::map >, std::pair > >::const_iterator iterFindFactionPresence = connectedCharacterLfgDataFactionalPresenceGrid.find(std::make_pair(lfgCharacterData.locationPlanet, std::make_pair(lfgCharacterData.locationFactionalPresenceGridX, lfgCharacterData.locationFactionalPresenceGridZ))); if (iterFindFactionPresence != connectedCharacterLfgDataFactionalPresenceGrid.end()) { oldValue = iterFindFactionPresence->second; newValue = iterFindFactionPresence->second; } else { oldValue = std::make_pair(NetworkId::cms_invalid, std::make_pair(0, 0)); newValue = std::make_pair(NetworkId::cms_invalid, std::make_pair(0, 0)); } if (PvpData::isImperialFactionId(lfgCharacterData.faction)) ++(newValue.second.first); else if (PvpData::isRebelFactionId(lfgCharacterData.faction)) ++(newValue.second.second); // 0 -> non-zero if ((oldValue.second.first != newValue.second.first) && (oldValue.second.first <= 0)) { if (oldValue.first.isValid()) removeFactionalPresenceGridFromPlanetMap(lfgCharacterData.locationPlanet, oldValue.first); newValue.first = ObjectIdManager::getInstance().getNewObjectId(); addFactionalPresenceGridToPlanetMap(lfgCharacterData.locationPlanet, newValue.first, lfgCharacterData.locationFactionalPresenceGridX, lfgCharacterData.locationFactionalPresenceGridZ, (newValue.second.first > 0), (newValue.second.second > 0)); } else if ((oldValue.second.second != newValue.second.second) && (oldValue.second.second <= 0)) { if (oldValue.first.isValid()) removeFactionalPresenceGridFromPlanetMap(lfgCharacterData.locationPlanet, oldValue.first); newValue.first = ObjectIdManager::getInstance().getNewObjectId(); addFactionalPresenceGridToPlanetMap(lfgCharacterData.locationPlanet, newValue.first, lfgCharacterData.locationFactionalPresenceGridX, lfgCharacterData.locationFactionalPresenceGridZ, (newValue.second.first > 0), (newValue.second.second > 0)); } connectedCharacterLfgDataFactionalPresenceGrid.set(std::make_pair(lfgCharacterData.locationPlanet, std::make_pair(lfgCharacterData.locationFactionalPresenceGridX, lfgCharacterData.locationFactionalPresenceGridZ)), newValue); } } // ---------------------------------------------------------------------- void PlanetObjectNamespace::removeFactionalPresenceGridFromPlanetMap(std::string const & planetName, NetworkId const & locationId) { // factional presence grid tracking is only used for ground if (::strncmp("space_", planetName.c_str(), 6) == 0) return; PlanetObject * const planet = ServerUniverse::getInstance().getPlanetByName(planetName); if (planet) planet->removeMapLocation(locationId, static_cast(PlanetMapManager::MLT_dynamic)); } // ---------------------------------------------------------------------- void PlanetObjectNamespace::addFactionalPresenceGridToPlanetMap(std::string const & planetName, NetworkId const & locationId, int gridX, int gridZ, bool imperial, bool rebel) { // factional presence grid tracking is only used for ground if (::strncmp("space_", planetName.c_str(), 6) == 0) return; if (!imperial && !rebel) return; PlanetObject * const planet = ServerUniverse::getInstance().getPlanetByName(planetName); if (planet) { MapLocation ml; ml.m_locationId = locationId; if (imperial && rebel) { ml.m_subCategory = PlanetMapManager::findCategory("gcw_factional_presence_rebel_and_imperial"); ml.m_locationName = Unicode::narrowToWide(FormattedString<512>().sprintf("\\#FFFFFFGCW FP Grid (%d, %d) -> (%d, %d)", (gridX - (PvpData::getGcwFactionalPresenceGridSize() / 2)), (gridZ - (PvpData::getGcwFactionalPresenceGridSize() / 2)), (gridX + (PvpData::getGcwFactionalPresenceGridSize() / 2)), (gridZ + (PvpData::getGcwFactionalPresenceGridSize() / 2)))); } else if (imperial) { ml.m_subCategory = PlanetMapManager::findCategory("gcw_factional_presence_imperial_only"); ml.m_locationName = Unicode::narrowToWide(FormattedString<512>().sprintf("\\#C2B5C9GCW FP Grid (%d, %d) -> (%d, %d)", (gridX - (PvpData::getGcwFactionalPresenceGridSize() / 2)), (gridZ - (PvpData::getGcwFactionalPresenceGridSize() / 2)), (gridX + (PvpData::getGcwFactionalPresenceGridSize() / 2)), (gridZ + (PvpData::getGcwFactionalPresenceGridSize() / 2)))); } else { ml.m_subCategory = PlanetMapManager::findCategory("gcw_factional_presence_rebel_only"); ml.m_locationName = Unicode::narrowToWide(FormattedString<512>().sprintf("\\#D93311GCW FP Grid (%d, %d) -> (%d, %d)", (gridX - (PvpData::getGcwFactionalPresenceGridSize() / 2)), (gridZ - (PvpData::getGcwFactionalPresenceGridSize() / 2)), (gridX + (PvpData::getGcwFactionalPresenceGridSize() / 2)), (gridZ + (PvpData::getGcwFactionalPresenceGridSize() / 2)))); } ml.m_location = Vector2d(static_cast(gridX), static_cast(gridZ)); ml.m_category = PlanetMapManager::findCategory("gcw_factional_presence"); planet->addMapLocation(ml, static_cast(PlanetMapManager::MLT_dynamic), false); } } // ======================================================================