Resolve "Toggle Free Look with Hotkey"
[ryzomcore.git] / ryzom / server / src / gpm_service / patat_subscribe_manager.cpp
blobef49e49f9ebfd3131c661dbe7c71a2c2347cc740
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "stdpch.h"
20 #include "patat_subscribe_manager.h"
22 #include "game_share/ryzom_entity_id.h"
23 #include "game_share/synchronised_message.h"
25 #include "nel/misc/command.h"
26 #include "nel/pacs/u_move_container.h"
27 #include "nel/pacs/u_collision_desc.h"
29 using namespace std;
30 using namespace NLMISC;
31 using namespace NLNET;
32 using namespace NLLIGO;
33 using namespace NLPACS;
36 * Constructor
38 CPatatSubscribeManager::CPatatSubscribeManager()
44 * Destructor
46 CPatatSubscribeManager::~CPatatSubscribeManager()
52 * Init the subscriber
54 void CPatatSubscribeManager::init()
56 _PatatGrid.init();
57 _PatatMap.clear();
58 _SubscriberMap.clear();
59 _TriggerMap.clear();
60 _ModifiedPatats.clear();
64 * Serialize a manager file (no subscription saved, only triggers/patats saved)
66 void CPatatSubscribeManager::serial(NLMISC::IStream &f)
68 f.serialVersion(0);
70 if (f.isReading())
71 init();
73 f.serial(_PatatGrid);
74 f.serialCont(_PatatMap);
75 f.serialCont(_TriggerMap);
80 * Use a prim file
82 void CPatatSubscribeManager::usePrim(const string &primFile)
84 vector<uint32> prims;
85 _PatatGrid.usePrim(primFile, prims);
87 uint i;
88 for (i=0; i<prims.size(); ++i)
90 // checks if patat exists in subscribed patats (creates and inits if not)
91 TPatatMap::iterator itp = _PatatMap.find(prims[i]);
92 if (itp == _PatatMap.end())
94 pair<TPatatMap::iterator, bool> res = _PatatMap.insert(TPatatMap::value_type(prims[i], CPatat()));
95 itp = res.first;
96 (*itp).second.Name = _PatatGrid.getZoneName(prims[i]);
97 (*itp).second.InternalPatatId = prims[i];
99 _TriggerMap.insert(TTriggerIdMap::value_type((*itp).second.Name, (*itp).second.InternalPatatId));
105 * Register a pacs trigger id
107 void CPatatSubscribeManager::usePacsTrigger(sint32 id, const std::string &name)
109 // checks if patat exists in subscribed patats (creates and inits if not)
110 TPatatMap::iterator itp = _PatatMap.find(id);
111 if (itp == _PatatMap.end())
113 pair<TPatatMap::iterator, bool> res = _PatatMap.insert(TPatatMap::value_type(id, CPatat()));
114 itp = res.first;
115 (*itp).second.Name = name;
116 (*itp).second.InternalPatatId = id;
118 _TriggerMap.insert(TTriggerIdMap::value_type((*itp).second.Name, (*itp).second.InternalPatatId));
127 * Subscribe to a patat
129 void CPatatSubscribeManager::subscribe(NLNET::TServiceId service, const TPatatSubscription &patat)
131 nldebug("Subscribe service %d to patat %s (#id %d)", service.get(), patat.first.c_str(), patat.second);
133 // checks the patat is referenced in patatgrid/pacs triggers
134 TTriggerIdMap::iterator it = _TriggerMap.find(patat.first);
136 if (it == _TriggerMap.end())
138 nlwarning("Can't subscribe service %d to patat %s, not referenced in PatatGrid", service.get(), patat.first.c_str());
139 return;
142 sint32 patatId = (*it).second;
144 // checks if patat exists in subscribed patats (creates and inits if not)
145 TPatatMap::iterator itp = _PatatMap.find(patatId);
146 if (itp == _PatatMap.end())
148 pair<TPatatMap::iterator, bool> res = _PatatMap.insert(TPatatMap::value_type(patatId, CPatat()));
149 itp = res.first;
151 (*itp).second.Name = patat.first;
152 (*itp).second.InternalPatatId = patatId;
155 // checks if subscriber exists in subscribers (creates and inits if not)
156 TSubscriberMap::iterator its = _SubscriberMap.find(service);
157 if (its == _SubscriberMap.end())
159 pair<TSubscriberMap::iterator, bool> res = _SubscriberMap.insert(TSubscriberMap::value_type(service, CSubscriber()));
160 its = res.first;
162 (*its).second.Service = service;
167 // checks if service not yet in patat's subscribers
168 uint i;
169 for (i=0; i<(*itp).second.Subscribers.size(); ++i)
170 if ((*itp).second.Subscribers[i].Service == service)
171 break;
173 if (i == (*itp).second.Subscribers.size())
174 (*itp).second.Subscribers.resize(i+1);
176 (*itp).second.Subscribers[i].Service = service;
177 (*itp).second.Subscribers[i].SubscriberIterator = its;
178 (*itp).second.Subscribers[i].PatatId = patat.second;
180 // checks if patat not yet in service's subscribed patats
181 for (i=0; i<(*its).second.Patats.size(); ++i)
182 if ((*its).second.Patats[i].InternalPatatId == patatId)
183 break;
185 if (i == (*its).second.Patats.size())
186 (*its).second.Patats.resize(i+1);
188 (*its).second.Patats[i].InternalPatatId = patatId;
189 (*its).second.Patats[i].PatatId = patat.second;
190 (*its).second.Patats[i].PatatIterator = itp;
193 if (!(*itp).second.StillIns.empty())
195 CMessage msg("TRIGGER_IN");
196 msg.serial(const_cast<uint16&>(patat.second));
197 msg.serialCont((*itp).second.StillIns);
202 * Unsubscribe to a patat
204 void CPatatSubscribeManager::unsubscribe(NLNET::TServiceId service, TPatatId patat)
206 nldebug("Unsubscribe service %d to patat #id %d", service.get(), patat);
207 // checks the patat is referenced in patatgrid
209 sint32 patatId = 0;
211 // find patat and remove it
212 TSubscriberMap::iterator its = _SubscriberMap.find(service);
213 TPatatMap::iterator itp = _PatatMap.end();
214 if (its != _SubscriberMap.end())
216 vector<CSubscribedPatat>::iterator itsp;
217 for (itsp=(*its).second.Patats.begin(); itsp!=(*its).second.Patats.end(); ++itp)
219 if ((*itsp).PatatId == patat)
221 patatId = (*itsp).InternalPatatId;
222 itp = (*itsp).PatatIterator;
223 (*its).second.Patats.erase(itsp);
224 break;
229 // find subscriber and remove it
230 if (itp != _PatatMap.end())
232 vector<CPatatSubscriber>::iterator its;
233 for (its=(*itp).second.Subscribers.begin(); its!=(*itp).second.Subscribers.end(); ++its)
235 if ((*its).Service == service)
237 (*itp).second.Subscribers.erase(its);
238 break;
245 * Unsubscribe a whole service
247 void CPatatSubscribeManager::unsubscribe(NLNET::TServiceId service)
249 nldebug("Unsubscribe service %d to all subscribed patats", service.get());
251 // find patat and remove it
252 TSubscriberMap::iterator its = _SubscriberMap.find(service);
253 if (its != _SubscriberMap.end())
255 // for all subscribed patats
256 vector<CSubscribedPatat>::iterator itp;
257 for (itp=(*its).second.Patats.begin(); itp!=(*its).second.Patats.end(); ++itp)
259 // remove in patats subscriber list all reference to subcriber
260 vector<CPatatSubscriber> &subscribers = (*((*itp).PatatIterator)).second.Subscribers;
261 vector<CPatatSubscriber>::iterator it;
262 for (it=subscribers.begin(); it!=subscribers.end(); )
263 if ((*it).Service == service)
264 it = subscribers.erase(it);
265 else
266 ++it;
274 * Get the new entry index for an entity, given its position
276 uint32 CPatatSubscribeManager::getNewEntryIndex(const CEntityId &id, const CVector &pos, uint32 previousEntryIndex)
278 // get the entry index for the position
279 sint32 newEntryIndex = _PatatGrid.getEntryIndex(pos);
281 setNewEntryIndex(id, newEntryIndex, previousEntryIndex);
283 return newEntryIndex;
287 * set the new entry index for an entity
289 void CPatatSubscribeManager::setNewEntryIndex(const CEntityId &id, uint32 newEntryIndex, uint32 previousEntryIndex)
291 vector<uint32> in, out;
293 // compute the patatId differences between previous and new entry indexes
294 if (!_PatatGrid.diff((CPatatGrid::TEntryIndex)previousEntryIndex, (CPatatGrid::TEntryIndex)newEntryIndex, in, out))
295 return;
297 uint i;
298 // for each patat left, notify patat the entity left it
299 for (i=0; i<out.size(); ++i)
301 nldebug("Notfied %s left patat %s", id.toString().c_str(), _PatatGrid.getZoneName(out[i]).c_str());
303 // find the left patat
304 TPatatMap::iterator it = _PatatMap.find((sint32)out[i]);
305 if (it == _PatatMap.end())
306 continue; // not referenced
308 // adds the entity to the outs list
309 (*it).second.Outs.push_back(id);
310 (*it).second.StillIns.erase(id);
312 // notify it as modified
313 if (!(*it).second.Modified)
315 (*it).second.Modified = true;
316 _ModifiedPatats.push_back(it);
320 // same job, but for entered patats
321 for (i=0; i<in.size(); ++i)
323 nldebug("Notfied %s entered patat %s", id.toString().c_str(), _PatatGrid.getZoneName(in[i]).c_str());
325 TPatatMap::iterator it = _PatatMap.find((sint32)in[i]);
326 if (it == _PatatMap.end())
327 continue;
329 (*it).second.Ins.push_back(id);
330 (*it).second.StillIns.insert(id);
332 if (!(*it).second.Modified)
334 (*it).second.Modified = true;
335 _ModifiedPatats.push_back(it);
341 * Process pacs trigger collisions
343 void CPatatSubscribeManager::processPacsTriggers(UMoveContainer *moveContainer)
345 uint num = moveContainer->getNumTriggerInfo();
346 uint i;
348 for (i=0; i<num; ++i)
350 const UTriggerInfo &info = moveContainer->getTriggerInfo(i);
352 CEntityId trigger = CEntityId(info.Object0);
353 CEntityId entity = CEntityId(info.Object1);
355 if (trigger.getType() != RYZOMID::trigger)
356 swap(trigger, entity);
358 // don't warn of non trigger collision
359 if (trigger.getType() != RYZOMID::trigger)
360 continue;
362 sint32 triggerId = (sint32)trigger.getShortId();
364 TPatatMap::iterator it = _PatatMap.find(triggerId);
365 if (it == _PatatMap.end())
366 continue;
368 switch (info.CollisionType)
370 case UTriggerInfo::In:
372 nldebug("Notified %s entered trigger %s", entity.toString().c_str(), (*it).second.Name.c_str());
373 // adds the entity to the ins list
374 (*it).second.Ins.push_back(entity);
375 // don't insert in still list, cause when primitive is deleted, no trigger out event occurs
376 // and that might fill still list quickly !
377 //(*it).second.StillIns.insert(entity);
379 // adds to the modified list
380 if (!(*it).second.Modified)
382 (*it).second.Modified = true;
383 _ModifiedPatats.push_back(it);
386 break;
387 case UTriggerInfo::Out:
389 nldebug("Notified %s entered trigger %s", entity.toString().c_str(), (*it).second.Name.c_str());
390 // adds the entity to the outs list
391 (*it).second.Outs.push_back(entity);
392 //(*it).second.StillIns.erase(entity);
394 // notify it as modified
395 if (!(*it).second.Modified)
397 (*it).second.Modified = true;
398 _ModifiedPatats.push_back(it);
401 break;
402 case UTriggerInfo::Inside:
403 break;
410 * Emit changes
412 void CPatatSubscribeManager::emitChanges()
414 // initialize subscribers messages
415 // for each subscriber, reset in and out messages
416 TSubscriberMap::iterator its;
417 for (its=_SubscriberMap.begin(); its!=_SubscriberMap.end(); ++its)
419 // reset out message
420 CMessage &msgouts = (*its).second.OutsMessage;
421 msgouts.clear();
422 /*if (msgouts.isReading())
423 msgouts.invert();*/
424 msgouts.setType("TRIGGER_OUT");
425 (*its).second.OutsMsgSize = msgouts.length();
427 // reset in message
428 CMessage &msgins = (*its).second.InsMessage;
429 msgins.clear();
430 /*if (msgins.isReading())
431 msgins.invert();*/
432 msgins.setType("TRIGGER_IN");
433 (*its).second.InsMsgSize = msgins.length();
436 // for each modified patat, add the patatId and the list of entities that entered/left the patat
437 TModifiedPatats::iterator itm;
438 for (itm=_ModifiedPatats.begin(); itm!=_ModifiedPatats.end(); ++itm)
440 CPatat &patat = (*(*itm)).second;
441 uint i;
443 // if entities left the patat
444 // notify all subscribers -- serializes in OutsMessage patatId and vector of entity ids
445 if (!patat.Outs.empty())
447 for (i=0; i<patat.Subscribers.size(); ++i)
449 its = patat.Subscribers[i].SubscriberIterator;
450 // serialize patatId for this subscriber (different from internal patatid)
451 (*its).second.OutsMessage.serial(patat.Subscribers[i].PatatId);
452 // serialize vector of CEntityId
453 (*its).second.OutsMessage.serialCont(patat.Outs);
457 // if entities entered the patat
458 // notify all subscribers -- serializes in InsMessage patatId and vector of entity ids
459 if (!patat.Ins.empty())
461 for (i=0; i<patat.Subscribers.size(); ++i)
463 its = patat.Subscribers[i].SubscriberIterator;
464 // serialize patatId for this subscriber (different from internal patatid)
465 (*its).second.InsMessage.serial(patat.Subscribers[i].PatatId);
466 // serialize vector of CEntityId
467 (*its).second.InsMessage.serialCont(patat.Ins);
471 // reset modify state
472 patat.Modified = false;
473 // and clear temp in/out vectors
474 patat.Ins.clear();
475 patat.Outs.clear();
478 // reset the list of modified patat
479 _ModifiedPatats.clear();
481 // and send messages to subscribers (if needed)
482 for (its=_SubscriberMap.begin(); its!=_SubscriberMap.end(); ++its)
484 if ((*its).second.InsMessage.length() > (*its).second.InsMsgSize)
485 sendMessageViaMirror((*its).second.Service, (*its).second.InsMessage);
487 if ((*its).second.OutsMessage.length() > (*its).second.OutsMsgSize)
488 sendMessageViaMirror((*its).second.Service, (*its).second.OutsMessage);
494 * Display triggers
496 void CPatatSubscribeManager::displayTriggers(NLMISC::CLog *log)
498 log->displayNL("Registered triggers:");
500 TPatatMap::iterator it;
501 for (it=_PatatMap.begin(); it!=_PatatMap.end(); ++it)
503 CPatat &patat = (*it).second;
504 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());
507 log->displayNL("End of registered triggers");
511 * Display info for trigger
513 void CPatatSubscribeManager::displayTriggerInfo(const string &name, NLMISC::CLog *log)
515 TTriggerIdMap::iterator it = _TriggerMap.find(name);
516 if (it == _TriggerMap.end())
518 log->displayNL("No trigger '%s' registered", name.c_str());
519 return;
522 sint32 id = (*it).second;
524 log->displayNL("Trigger info: '%s', internal #%d", name.c_str(), id);
526 TPatatMap::iterator itp = _PatatMap.find(id);
527 if (itp == _PatatMap.end())
529 log->displayNL("Trigger not referenced in patat map, data not consistent !");
530 log->displayNL("End of trigger info");
531 return;
534 CPatat &patat = (*itp).second;
536 uint i;
538 log->displayNL("Subscribers:");
539 for (i=0; i<patat.Subscribers.size(); ++i)
540 log->displayNL(" - %d, userId #d", patat.Subscribers[i].Service.get(), patat.Subscribers[i].PatatId);
542 log->displayNL("Ins:");
543 for (i=0; i<patat.Ins.size(); ++i)
544 log->displayNL(" - %s", patat.Ins[i].toString().c_str());
546 log->displayNL("Outs:");
547 for (i=0; i<patat.Ins.size(); ++i)
548 log->displayNL(" - %s", patat.Outs[i].toString().c_str());
550 log->displayNL("Outs:");
551 for (i=0; i<patat.Ins.size(); ++i)
552 log->displayNL(" - %s", patat.Outs[i].toString().c_str());
554 log->displayNL("StillIns:");
555 set<NLMISC::CEntityId>::iterator its;
556 for (its=patat.StillIns.begin(); its!=patat.StillIns.end(); ++its)
557 log->displayNL(" - %s", (*its).toString().c_str());
559 log->displayNL("End of trigger info");
563 * Display subscribers
565 void CPatatSubscribeManager::displaySubscribers(NLMISC::CLog *log)
567 log->displayNL("Registered subscribers:");
569 TSubscriberMap::iterator it;
570 for (it=_SubscriberMap.begin(); it!=_SubscriberMap.end(); ++it)
572 CSubscriber &subscriber = (*it).second;
573 log->displayNL(" - %d, %d subscribed triggers", subscriber.Service.get(), subscriber.Patats.size());
576 log->displayNL("End of registered subscribers");
580 * Display info for subscriber
582 void CPatatSubscribeManager::displaySubscriberInfo(NLNET::TServiceId service, NLMISC::CLog *log)
584 TSubscriberMap::iterator it = _SubscriberMap.find(service);
585 if (it == _SubscriberMap.end())
587 log->displayNL("Service %d no registered", service.get());
588 return;
591 log->displayNL("Subscriber info: %d", service.get());
593 CSubscriber &subscriber = (*it).second;
595 uint i;
597 log->displayNL("Subscribed triggers:");
598 for (i=0; i<subscriber.Patats.size(); ++i)
599 log->displayNL(" - internal #%d, subscribed as userId #d", subscriber.Patats[i].InternalPatatId, subscriber.Patats[i].PatatId);
601 log->displayNL("End of subscriber info");