Add infos into target window
[ryzomcore.git] / ryzom / server / src / monitor_service / client.cpp
blob93d03d603db6c809b8e213d2f9a16d265b78a181
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2015 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "stdpch.h"
24 #include "client.h"
25 #include "mirrors.h"
27 using namespace std;
28 using namespace NLMISC;
29 using namespace NLNET;
31 extern std::map<TYPE_NAME_STRING_ID, std::string> StringMap;
32 extern std::set<TYPE_NAME_STRING_ID> StringAsked;
34 // ***************************************************************************
36 // Must be a pointer to control when to start listening socket and when stop it
37 extern CCallbackServer *Server;
39 uint32 StillToAdd = 0;
40 uint32 StillToRemove = 0;
41 uint32 Added = 0;
42 uint32 Removed = 0;
43 uint32 CurrentlyInVision = 0;
44 uint32 SentPos = 0;
45 uint32 SentMiscProp = 0;
46 uint32 SentStr = 0;
48 NLMISC_VARIABLE(uint32, StillToAdd, "");
49 NLMISC_VARIABLE(uint32, StillToRemove, "");
50 NLMISC_VARIABLE(uint32, Added, "");
51 NLMISC_VARIABLE(uint32, Removed, "");
52 NLMISC_VARIABLE(uint32, CurrentlyInVision, "");
53 NLMISC_VARIABLE(uint32, SentPos, "");
54 NLMISC_VARIABLE(uint32, SentMiscProp, "");
55 NLMISC_VARIABLE(uint32, SentStr, "");
57 // ***************************************************************************
59 vector<NLMISC::CSmartPtr<CMonitorClient> > Clients;
61 // ***************************************************************************
63 CMonitorClient::CMonitorClient(TSockId sock)
65 _Sock = sock;
66 setWindow(0,0,0,0);
67 StartOffset = 0;
68 AllowedUploadBandwidth = 2048; // 2kB per second for a start
69 // counter = 0;
71 AddWeight = 3.0f;
72 RemoveWeight = 1.0f;
73 PosWeight = 1.0f;
74 StrWeight = 1.0f;
75 MiscPropWeight = 0.5f;
76 Authentificated = false;
77 BadLogin = false;
80 // ***************************************************************************
82 CMonitorClient::~CMonitorClient()
86 // ***************************************************************************
88 void CMonitorClient::setWindow(float xmin, float ymin, float xmax, float ymax)
90 if (xmin > xmax)
92 swap(xmin, xmax);
94 if (ymin > ymax)
96 swap(ymin, ymax);
98 _WindowTopLeft = CVector(xmin, ymin, 0);
99 _WindowBottomRight = CVector(xmax, ymax, 0);
102 // ***************************************************************************
104 void CMonitorClient::add (const TDataSetRow &entity)
106 uint32 index = entity.getIndex();
108 if (index >= Entites.size())
109 Entites.resize(index+1);
111 // don't add twice
112 if ( (Entites[index].Flags & CEntityEntry::Present) != 0)
113 return;
115 // if pending in removal, just remove from PendingRemove list
116 if ( (Entites[index].Flags & CEntityEntry::Pending) != 0)
118 vector<uint32>::iterator it = find(PendingRemove.begin(), PendingRemove.end(), entity.getIndex());
119 if (it != PendingRemove.end())
120 PendingRemove.erase(it);
121 Entites[index].Flags &= (~CEntityEntry::Pending);
122 Entites[index].Flags |= CEntityEntry::Present;
123 return;
126 // set entity as present
127 Entites[index].Flags |= (CEntityEntry::Present | CEntityEntry::DirtyAll | CEntityEntry::Pending);
129 // add to pending to addition entities
130 PendingAdd.push_back(index);
133 // ***************************************************************************
135 void CMonitorClient::remove (const TDataSetRow &entity)
137 uint32 index = entity.getIndex();
139 nlassert( index < Entites.size() );
141 // don't remove twice
142 if ( (Entites[index].Flags & CEntityEntry::Present) == 0)
143 return;
145 // if pending in addition, just remove from PendingAdd list
146 if ( (Entites[index].Flags & CEntityEntry::Pending) != 0)
148 vector<uint32>::iterator it = find(PendingAdd.begin(), PendingAdd.end(), entity.getIndex());
149 if (it != PendingAdd.end())
150 PendingAdd.erase(it);
151 Entites[index].Flags &= (~(CEntityEntry::Pending | CEntityEntry::Present));
152 return;
155 // set entity as not present
156 Entites[index].Flags &= (~CEntityEntry::Present);
157 Entites[index].Flags |= CEntityEntry::Pending;
159 PendingRemove.push_back(index);
162 // ***************************************************************************
164 void CMonitorClient::resetVision()
166 uint i;
168 const CVector &topleft = getTopLeft();
169 const CVector &bottomright = getBottomRight();
171 for (i=0; i<GlobalEntites.size(); ++i)
173 if ((GlobalEntites[i].Flags & CGlobalEntityEntry::Present) != 0)
175 TDataSetRow entityIndex = TDataSetRow::createFromRawIndex (i);
176 CMirrorPropValueRO<TYPE_POSX> valueX( TheDataset, entityIndex, DSPropertyPOSX );
177 CMirrorPropValueRO<TYPE_POSY> valueY( TheDataset, entityIndex, DSPropertyPOSY );
179 CVector pos((float)valueX / 1000.f, (float)valueY / 1000.f, 0.0f);
181 // is entity in client window
182 //nlassert(entityIndex.getIndex() < client.Entites.size());
183 bool wasPresent = (i < Entites.size() && (Entites[i].Flags & CEntityEntry::Present) != 0);
184 if (pos.x > topleft.x && pos.x < bottomright.x && pos.y > topleft.y && pos.y < bottomright.y)
186 if (!wasPresent)
188 // Add
189 add( entityIndex );
192 Entites[i].Flags |= CEntityEntry::DirtyAll;
194 else if (wasPresent)
196 // Rmv
197 remove( entityIndex );
203 // ***************************************************************************
205 void CMonitorClient::update ()
207 StillToAdd = 0;
208 StillToRemove = 0;
209 Added = 0;
210 Removed = 0;
211 CurrentlyInVision = 0;
212 SentPos = 0;
213 SentStr = 0;
215 // compute bandwidth spaces allowed for this cycle
216 float cycleBandw = (float)AllowedUploadBandwidth / 10.0f;
217 float totalRatio = AddWeight + RemoveWeight + PosWeight + StrWeight + MiscPropWeight;
218 uint maxAddSize = (uint)(cycleBandw*AddWeight/totalRatio);
219 uint maxRmvSize = (uint)(cycleBandw*RemoveWeight/totalRatio);
220 uint maxPosSize = (uint)(cycleBandw*PosWeight/totalRatio);
221 uint maxStrSize = (uint)(cycleBandw*StrWeight/totalRatio);
222 uint maxMiscPropSize = (uint)(cycleBandw*MiscPropWeight/totalRatio);
224 const uint addSize = 4+4+8+4+4+4;
225 const uint rmvSize = 4;
226 const uint posSize = 4+4+4+4;
227 const uint miscPropSize = 4+4+4+1+1;
229 CConfigFile::CVar *var = IService::getInstance()->ConfigFile.getVarPtr ("UpdatePerTick");
230 // here we suppose that position is changing often, whereas other less important
231 // properties are updated less frequently
232 uint posToSend = 0;
233 uint miscPropToSend = 0;
235 uint poscount = 10;
236 if (var && (var->Type == CConfigFile::CVar::T_INT))
237 poscount = var->asInt();
239 uint startOffset = StartOffset;
240 if (startOffset >= InVision.size())
241 startOffset = 0;
243 uint entity = startOffset;
244 while (poscount > 0 && !InVision.empty())
246 // is entity dirty ?
247 uint32 entityRawIndex = InVision[entity];
248 if ((Entites[entityRawIndex].Flags & CEntityEntry::PosDirty) != 0)
250 if ((Entites[entityRawIndex].Flags & CEntityEntry::Pending) == 0)
252 ++posToSend;
255 if ((Entites[entityRawIndex].Flags & CEntityEntry::MiscPropDirty) != 0 && (Entites[entityRawIndex].Flags & CEntityEntry::Pending) == 0)
256 ++miscPropToSend;
258 ++entity;
259 if (entity >= InVision.size())
260 entity = 0;
261 if (entity == startOffset)
262 break;
266 uint addTotalSize = (uint)PendingAdd.size()*addSize;
267 uint rmvTotalSize = (uint)PendingRemove.size()*rmvSize;
268 uint posTotalSize = posToSend*posSize;
269 uint miscPropTotalSize = miscPropToSend*miscPropSize;
270 uint strTotalSize = 0;
272 uint i;
273 vector< pair<TYPE_NAME_STRING_ID, string*> > strToSend;
274 for (i=0; i<Str.size() && strTotalSize < (uint)cycleBandw; ++i)
276 TYPE_NAME_STRING_ID id = Str[i];
277 std::map<TYPE_NAME_STRING_ID, std::string>::iterator ite = StringMap.find (id);
278 nlassert (ite != StringMap.end());
279 strToSend.push_back(std::pair<TYPE_NAME_STRING_ID, string*>(id, &((*ite).second)));
280 strTotalSize += 4+4+(uint)(*ite).second.size();
283 bool restrictAdd = (addTotalSize > maxAddSize);
284 bool restrictRmv = (rmvTotalSize > maxRmvSize);
285 bool restrictPos = (posTotalSize > maxPosSize);
286 bool restrictStr = (strTotalSize > maxStrSize);
287 bool restrictMiscProp = (miscPropTotalSize > maxMiscPropSize);
289 float remainingBandw = cycleBandw;
291 if (!restrictAdd) { totalRatio -= AddWeight; remainingBandw -= addTotalSize; }
292 if (!restrictRmv) { totalRatio -= RemoveWeight; remainingBandw -= rmvTotalSize; }
293 if (!restrictPos) { totalRatio -= PosWeight; remainingBandw -= posTotalSize; }
294 if (!restrictStr) { totalRatio -= StrWeight; remainingBandw -= strTotalSize; }
295 if (!restrictMiscProp) { totalRatio -= MiscPropWeight; remainingBandw -= miscPropTotalSize; }
297 if (restrictAdd) addTotalSize = (uint)(remainingBandw*AddWeight/totalRatio);
298 if (restrictRmv) rmvTotalSize = (uint)(remainingBandw*RemoveWeight/totalRatio);
299 if (restrictPos) posTotalSize = (uint)(remainingBandw*PosWeight/totalRatio);
300 if (restrictStr) strTotalSize = (uint)(remainingBandw*StrWeight/totalRatio);
301 if (restrictMiscProp) miscPropTotalSize = (uint)(remainingBandw*MiscPropWeight/totalRatio);
304 // update pending lists
305 uint pendingAddCount = (addTotalSize/addSize);
306 while (!PendingAdd.empty() && pendingAddCount > 0)
308 uint32 entityRawIndex = PendingAdd.back();
309 PendingAdd.pop_back();
310 TDataSetRow entity = TDataSetRow::createFromRawIndex (entityRawIndex);
311 CMirrorPropValueRO<TYPE_NAME_STRING_ID> stringId( TheDataset, entity, DSPropertyNAME_STRING_ID);
312 CMirrorPropValueRO<TYPE_SHEET> sheetId( TheDataset, entity, DSPropertySHEET);
313 CAddData addData;
314 addData.Id = entity.getIndex();
315 addData.StringId = stringId;
316 addData.EntityId = TheDataset.getEntityId (entity);
317 addData.SheetId = sheetId;
318 Add.push_back (addData);
320 Entites[entityRawIndex].Flags &= (~CEntityEntry::Pending);
322 InVision.push_back(entity.getIndex());
324 --pendingAddCount;
325 ++Added;
328 uint pendingRemoveCount = (rmvTotalSize/rmvSize);
329 while (!PendingRemove.empty() && pendingRemoveCount > 0)
331 uint32 entityRawIndex = PendingRemove.back();
333 vector<uint32>::iterator it = find(InVision.begin(), InVision.end(), entityRawIndex);
334 if (it != InVision.end())
335 InVision.erase(it);
337 PendingRemove.pop_back();
338 Rmv.push_back (entityRawIndex);
340 Entites[entityRawIndex].Flags &= (~CEntityEntry::Pending);
342 --pendingRemoveCount;
343 ++Removed;
346 StillToAdd = (uint32)PendingAdd.size();
347 StillToRemove = (uint32)PendingRemove.size();
348 CurrentlyInVision = (uint32)InVision.size();
350 if (StartOffset >= InVision.size())
351 StartOffset = 0;
353 uint entity = StartOffset;
354 uint pendingPosCount = (posTotalSize/posSize);
355 uint pendingMiscPropCount = (miscPropTotalSize/posSize);
356 while ((pendingPosCount > 0 || pendingMiscPropCount > 0) && !InVision.empty())
358 // is entity dirty ?
359 uint32 entityRawIndex = InVision[entity];
360 if ((Entites[entityRawIndex].Flags & CEntityEntry::PosDirty) != 0 && (Entites[entityRawIndex].Flags & CEntityEntry::Pending) == 0)
362 TDataSetRow entityIndex = TDataSetRow::createFromRawIndex (entityRawIndex);
363 CMirrorPropValueRO<TYPE_POSX> valueX( TheDataset, entityIndex, DSPropertyPOSX );
364 CMirrorPropValueRO<TYPE_POSY> valueY( TheDataset, entityIndex, DSPropertyPOSY );
365 CMirrorPropValueRO<TYPE_ORIENTATION> valueT( TheDataset, entityIndex, DSPropertyORIENTATION );
367 CMonitorClient::CPosData posData;
368 posData.X = (float)valueX / 1000.f;
369 posData.Y = (float)valueY / 1000.f;
370 posData.Id = entityRawIndex;
371 posData.Tetha = valueT;
372 Pos.push_back (posData);
374 Entites[entityRawIndex].Flags &= (~CEntityEntry::PosDirty);
376 --pendingPosCount;
377 ++SentPos;
379 if ((Entites[entityRawIndex].Flags & CEntityEntry::MiscPropDirty) != 0 && (Entites[entityRawIndex].Flags & CEntityEntry::Pending) == 0)
381 TDataSetRow entityIndex = TDataSetRow::createFromRawIndex (entityRawIndex);
382 CMirrorPropValueRO<TYPE_CURRENT_HIT_POINTS> valueCurrentHP( TheDataset, entityIndex, DSPropertyCURRENT_HIT_POINTS);
383 CMirrorPropValueRO<TYPE_MAX_HIT_POINTS> valueMaxHP( TheDataset, entityIndex, DSPropertyMAX_HIT_POINTS);
384 CMirrorPropValueRO<TYPE_MODE> valueMode( TheDataset, entityIndex, DSPropertyMODE);
385 CMirrorPropValueRO<TYPE_BEHAVIOUR> valueBehaviour( TheDataset, entityIndex, DSPropertyBEHAVIOUR);
387 CMonitorClient::CMiscPropData miscPropData;
388 miscPropData.Id = entityRawIndex;
389 miscPropData.CurrentHP = valueCurrentHP;
390 miscPropData.MaxHP = valueMaxHP;
391 miscPropData.Mode = (uint8) valueMode;
392 miscPropData.Behaviour = (uint8) valueBehaviour;
393 MiscProp.push_back (miscPropData);
395 Entites[entityRawIndex].Flags &= (~CEntityEntry::MiscPropDirty);
397 --pendingMiscPropCount;
398 ++SentMiscProp;
401 ++entity;
402 if (entity >= InVision.size())
403 entity = 0;
404 if (entity == StartOffset)
405 break;
408 StartOffset = entity;
410 // Send a ADD message
411 if (!Add.empty())
413 CMessage msgout;
414 msgout.setType("ADD");
415 // version 1 : added sheet ID of the entity
416 msgout.serialVersion(1);
417 uint32 count = (uint32)Add.size();
418 msgout.serial(count);
419 uint i;
420 for (i=0; i<count; i++)
422 msgout.serial (Add[i].Id);
423 msgout.serial (Add[i].StringId);
424 msgout.serial (Add[i].EntityId);
425 msgout.serial (Add[i].SheetId);
427 Entites[Add[i].Id].Flags |= CEntityEntry::Present;
429 Server->send(msgout, getSock());
430 Add.clear ();
433 // Send a RMV message
434 if (!Rmv.empty())
436 CMessage msgout;
437 msgout.setType("RMV");
438 msgout.serialVersion(0);
439 uint32 count = (uint32)Rmv.size();
440 msgout.serial(count);
441 uint i;
442 for (i=0; i<count; i++)
444 msgout.serial (Rmv[i]);
445 Entites[Rmv[i]].Flags &= ~CEntityEntry::Present;
447 Server->send(msgout, getSock());
448 Rmv.clear ();
451 // Send a POS message
452 if (!Pos.empty())
454 CMessage msgout;
455 msgout.setType("POS");
456 msgout.serialVersion(0);
457 uint32 count = (uint32)Pos.size();
458 msgout.serial(count);
459 uint i;
460 for (i=0; i<count; i++)
462 msgout.serial (Pos[i].Id);
463 msgout.serial (Pos[i].X);
464 msgout.serial (Pos[i].Y);
465 msgout.serial (Pos[i].Tetha);
467 Server->send(msgout, getSock());
468 Pos.clear ();
471 // Send a MISC_PROP message
472 if (!MiscProp.empty())
474 CMessage msgout;
475 msgout.setType("MISC_PROP");
476 msgout.serialVersion(0);
477 uint32 count = (uint32)MiscProp.size();
478 msgout.serial(count);
479 uint i;
480 for (i=0; i<count; i++)
482 msgout.serial (MiscProp[i].Id);
483 msgout.serial (MiscProp[i].CurrentHP);
484 msgout.serial (MiscProp[i].MaxHP);
485 msgout.serial (MiscProp[i].Mode);
486 msgout.serial (MiscProp[i].Behaviour);
488 Server->send(msgout, getSock());
489 MiscProp.clear ();
493 // Send the strings
494 if (!Str.empty() && strTotalSize > 0)
496 CMessage msgout;
497 msgout.setType("STR");
498 msgout.serialVersion(0);
500 uint sentStrSize = 0;
501 uint i;
502 for (i=0; i<strToSend.size() && sentStrSize < strTotalSize; ++i)
503 sentStrSize += 4+4+(uint)(strToSend[i].second)->size();
505 uint32 count = i;
506 msgout.serial(count);
507 for (i=0; i<count; i++)
509 msgout.serial(strToSend[i].first);
510 msgout.serial(*(strToSend[i].second));
513 Str.erase(Str.begin(), Str.begin()+count);
515 Server->send(msgout, getSock());
516 SentStr = count;
520 // ***************************************************************************