// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdpch.h" #include "patat_subscribe_manager.h" #include "game_share/ryzom_entity_id.h" #include "game_share/synchronised_message.h" #include "nel/misc/command.h" #include "nel/pacs/u_move_container.h" #include "nel/pacs/u_collision_desc.h" using namespace std; using namespace NLMISC; using namespace NLNET; using namespace NLLIGO; using namespace NLPACS; /* * Constructor */ CPatatSubscribeManager::CPatatSubscribeManager() { } /* * Destructor */ CPatatSubscribeManager::~CPatatSubscribeManager() { } /* * Init the subscriber */ void CPatatSubscribeManager::init() { _PatatGrid.init(); _PatatMap.clear(); _SubscriberMap.clear(); _TriggerMap.clear(); _ModifiedPatats.clear(); } /* * Serialize a manager file (no subscription saved, only triggers/patats saved) */ void CPatatSubscribeManager::serial(NLMISC::IStream &f) { f.serialVersion(0); if (f.isReading()) init(); f.serial(_PatatGrid); f.serialCont(_PatatMap); f.serialCont(_TriggerMap); } /* * Use a prim file */ void CPatatSubscribeManager::usePrim(const string &primFile) { vector prims; _PatatGrid.usePrim(primFile, prims); uint i; for (i=0; i res = _PatatMap.insert(TPatatMap::value_type(prims[i], CPatat())); itp = res.first; (*itp).second.Name = _PatatGrid.getZoneName(prims[i]); (*itp).second.InternalPatatId = prims[i]; _TriggerMap.insert(TTriggerIdMap::value_type((*itp).second.Name, (*itp).second.InternalPatatId)); } } } /* * Register a pacs trigger id */ void CPatatSubscribeManager::usePacsTrigger(sint32 id, const std::string &name) { // checks if patat exists in subscribed patats (creates and inits if not) TPatatMap::iterator itp = _PatatMap.find(id); if (itp == _PatatMap.end()) { pair res = _PatatMap.insert(TPatatMap::value_type(id, CPatat())); itp = res.first; (*itp).second.Name = name; (*itp).second.InternalPatatId = id; _TriggerMap.insert(TTriggerIdMap::value_type((*itp).second.Name, (*itp).second.InternalPatatId)); } } // /* * Subscribe to a patat */ void CPatatSubscribeManager::subscribe(NLNET::TServiceId service, const TPatatSubscription &patat) { nldebug("Subscribe service %d to patat %s (#id %d)", service.get(), patat.first.c_str(), patat.second); // checks the patat is referenced in patatgrid/pacs triggers TTriggerIdMap::iterator it = _TriggerMap.find(patat.first); if (it == _TriggerMap.end()) { nlwarning("Can't subscribe service %d to patat %s, not referenced in PatatGrid", service.get(), patat.first.c_str()); return; } sint32 patatId = (*it).second; // checks if patat exists in subscribed patats (creates and inits if not) TPatatMap::iterator itp = _PatatMap.find(patatId); if (itp == _PatatMap.end()) { pair res = _PatatMap.insert(TPatatMap::value_type(patatId, CPatat())); itp = res.first; (*itp).second.Name = patat.first; (*itp).second.InternalPatatId = patatId; } // checks if subscriber exists in subscribers (creates and inits if not) TSubscriberMap::iterator its = _SubscriberMap.find(service); if (its == _SubscriberMap.end()) { pair res = _SubscriberMap.insert(TSubscriberMap::value_type(service, CSubscriber())); its = res.first; (*its).second.Service = service; } // checks if service not yet in patat's subscribers uint i; for (i=0; i<(*itp).second.Subscribers.size(); ++i) if ((*itp).second.Subscribers[i].Service == service) break; if (i == (*itp).second.Subscribers.size()) (*itp).second.Subscribers.resize(i+1); (*itp).second.Subscribers[i].Service = service; (*itp).second.Subscribers[i].SubscriberIterator = its; (*itp).second.Subscribers[i].PatatId = patat.second; // checks if patat not yet in service's subscribed patats for (i=0; i<(*its).second.Patats.size(); ++i) if ((*its).second.Patats[i].InternalPatatId == patatId) break; if (i == (*its).second.Patats.size()) (*its).second.Patats.resize(i+1); (*its).second.Patats[i].InternalPatatId = patatId; (*its).second.Patats[i].PatatId = patat.second; (*its).second.Patats[i].PatatIterator = itp; // if (!(*itp).second.StillIns.empty()) { CMessage msg("TRIGGER_IN"); msg.serial(const_cast(patat.second)); msg.serialCont((*itp).second.StillIns); } } /* * Unsubscribe to a patat */ void CPatatSubscribeManager::unsubscribe(NLNET::TServiceId service, TPatatId patat) { nldebug("Unsubscribe service %d to patat #id %d", service.get(), patat); // checks the patat is referenced in patatgrid sint32 patatId = 0; // find patat and remove it TSubscriberMap::iterator its = _SubscriberMap.find(service); TPatatMap::iterator itp = _PatatMap.end(); if (its != _SubscriberMap.end()) { vector::iterator itsp; for (itsp=(*its).second.Patats.begin(); itsp!=(*its).second.Patats.end(); ++itp) { if ((*itsp).PatatId == patat) { patatId = (*itsp).InternalPatatId; itp = (*itsp).PatatIterator; (*its).second.Patats.erase(itsp); break; } } } // find subscriber and remove it if (itp != _PatatMap.end()) { vector::iterator its; for (its=(*itp).second.Subscribers.begin(); its!=(*itp).second.Subscribers.end(); ++its) { if ((*its).Service == service) { (*itp).second.Subscribers.erase(its); break; } } } } /* * Unsubscribe a whole service */ void CPatatSubscribeManager::unsubscribe(NLNET::TServiceId service) { nldebug("Unsubscribe service %d to all subscribed patats", service.get()); // find patat and remove it TSubscriberMap::iterator its = _SubscriberMap.find(service); if (its != _SubscriberMap.end()) { // for all subscribed patats vector::iterator itp; for (itp=(*its).second.Patats.begin(); itp!=(*its).second.Patats.end(); ++itp) { // remove in patats subscriber list all reference to subcriber vector &subscribers = (*((*itp).PatatIterator)).second.Subscribers; vector::iterator it; for (it=subscribers.begin(); it!=subscribers.end(); ) if ((*it).Service == service) it = subscribers.erase(it); else ++it; } } } /* * Get the new entry index for an entity, given its position */ uint32 CPatatSubscribeManager::getNewEntryIndex(const CEntityId &id, const CVector &pos, uint32 previousEntryIndex) { // get the entry index for the position sint32 newEntryIndex = _PatatGrid.getEntryIndex(pos); setNewEntryIndex(id, newEntryIndex, previousEntryIndex); return newEntryIndex; } /* * set the new entry index for an entity */ void CPatatSubscribeManager::setNewEntryIndex(const CEntityId &id, uint32 newEntryIndex, uint32 previousEntryIndex) { vector in, out; // compute the patatId differences between previous and new entry indexes if (!_PatatGrid.diff((CPatatGrid::TEntryIndex)previousEntryIndex, (CPatatGrid::TEntryIndex)newEntryIndex, in, out)) return; uint i; // for each patat left, notify patat the entity left it for (i=0; igetNumTriggerInfo(); uint i; for (i=0; igetTriggerInfo(i); CEntityId trigger = CEntityId(info.Object0); CEntityId entity = CEntityId(info.Object1); if (trigger.getType() != RYZOMID::trigger) swap(trigger, entity); // don't warn of non trigger collision if (trigger.getType() != RYZOMID::trigger) continue; sint32 triggerId = (sint32)trigger.getShortId(); TPatatMap::iterator it = _PatatMap.find(triggerId); if (it == _PatatMap.end()) continue; switch (info.CollisionType) { case UTriggerInfo::In: { nldebug("Notified %s entered trigger %s", entity.toString().c_str(), (*it).second.Name.c_str()); // adds the entity to the ins list (*it).second.Ins.push_back(entity); // don't insert in still list, cause when primitive is deleted, no trigger out event occurs // and that might fill still list quickly ! //(*it).second.StillIns.insert(entity); // adds to the modified list if (!(*it).second.Modified) { (*it).second.Modified = true; _ModifiedPatats.push_back(it); } } break; case UTriggerInfo::Out: { nldebug("Notified %s entered trigger %s", entity.toString().c_str(), (*it).second.Name.c_str()); // adds the entity to the outs list (*it).second.Outs.push_back(entity); //(*it).second.StillIns.erase(entity); // notify it as modified if (!(*it).second.Modified) { (*it).second.Modified = true; _ModifiedPatats.push_back(it); } } break; case UTriggerInfo::Inside: break; } } } /* * Emit changes */ void CPatatSubscribeManager::emitChanges() { // initialize subscribers messages // for each subscriber, reset in and out messages TSubscriberMap::iterator its; for (its=_SubscriberMap.begin(); its!=_SubscriberMap.end(); ++its) { // reset out message CMessage &msgouts = (*its).second.OutsMessage; msgouts.clear(); /*if (msgouts.isReading()) msgouts.invert();*/ msgouts.setType("TRIGGER_OUT"); (*its).second.OutsMsgSize = msgouts.length(); // reset in message CMessage &msgins = (*its).second.InsMessage; msgins.clear(); /*if (msgins.isReading()) msgins.invert();*/ msgins.setType("TRIGGER_IN"); (*its).second.InsMsgSize = msgins.length(); } // for each modified patat, add the patatId and the list of entities that entered/left the patat TModifiedPatats::iterator itm; for (itm=_ModifiedPatats.begin(); itm!=_ModifiedPatats.end(); ++itm) { CPatat &patat = (*(*itm)).second; uint i; // if entities left the patat // notify all subscribers -- serializes in OutsMessage patatId and vector of entity ids if (!patat.Outs.empty()) { for (i=0; i (*its).second.InsMsgSize) sendMessageViaMirror((*its).second.Service, (*its).second.InsMessage); if ((*its).second.OutsMessage.length() > (*its).second.OutsMsgSize) sendMessageViaMirror((*its).second.Service, (*its).second.OutsMessage); } } /* * Display triggers */ void CPatatSubscribeManager::displayTriggers(NLMISC::CLog *log) { log->displayNL("Registered triggers:"); TPatatMap::iterator it; for (it=_PatatMap.begin(); it!=_PatatMap.end(); ++it) { CPatat &patat = (*it).second; log->displayNL(" - '%s', internal #%d, %d subscribers, %d entities in patat [0 for PACS triggers]", patat.Name.c_str(), patat.InternalPatatId, patat.Subscribers.size(), patat.StillIns.size()); } log->displayNL("End of registered triggers"); } /* * Display info for trigger */ void CPatatSubscribeManager::displayTriggerInfo(const string &name, NLMISC::CLog *log) { TTriggerIdMap::iterator it = _TriggerMap.find(name); if (it == _TriggerMap.end()) { log->displayNL("No trigger '%s' registered", name.c_str()); return; } sint32 id = (*it).second; log->displayNL("Trigger info: '%s', internal #%d", name.c_str(), id); TPatatMap::iterator itp = _PatatMap.find(id); if (itp == _PatatMap.end()) { log->displayNL("Trigger not referenced in patat map, data not consistent !"); log->displayNL("End of trigger info"); return; } CPatat &patat = (*itp).second; uint i; log->displayNL("Subscribers:"); for (i=0; idisplayNL(" - %d, userId #d", patat.Subscribers[i].Service.get(), patat.Subscribers[i].PatatId); log->displayNL("Ins:"); for (i=0; idisplayNL(" - %s", patat.Ins[i].toString().c_str()); log->displayNL("Outs:"); for (i=0; idisplayNL(" - %s", patat.Outs[i].toString().c_str()); log->displayNL("Outs:"); for (i=0; idisplayNL(" - %s", patat.Outs[i].toString().c_str()); log->displayNL("StillIns:"); set::iterator its; for (its=patat.StillIns.begin(); its!=patat.StillIns.end(); ++its) log->displayNL(" - %s", (*its).toString().c_str()); log->displayNL("End of trigger info"); } /* * Display subscribers */ void CPatatSubscribeManager::displaySubscribers(NLMISC::CLog *log) { log->displayNL("Registered subscribers:"); TSubscriberMap::iterator it; for (it=_SubscriberMap.begin(); it!=_SubscriberMap.end(); ++it) { CSubscriber &subscriber = (*it).second; log->displayNL(" - %d, %d subscribed triggers", subscriber.Service.get(), subscriber.Patats.size()); } log->displayNL("End of registered subscribers"); } /* * Display info for subscriber */ void CPatatSubscribeManager::displaySubscriberInfo(NLNET::TServiceId service, NLMISC::CLog *log) { TSubscriberMap::iterator it = _SubscriberMap.find(service); if (it == _SubscriberMap.end()) { log->displayNL("Service %d no registered", service.get()); return; } log->displayNL("Subscriber info: %d", service.get()); CSubscriber &subscriber = (*it).second; uint i; log->displayNL("Subscribed triggers:"); for (i=0; idisplayNL(" - internal #%d, subscribed as userId #d", subscriber.Patats[i].InternalPatatId, subscriber.Patats[i].PatatId); log->displayNL("End of subscriber info"); }