1 #include "Lobby2Server.h"
2 #include "RakAssert.h"
3 #include "MessageIdentifiers.h"
4 
5 //#define __INTEGRATE_LOBBY2_WITH_ROOMS_PLUGIN
6 
7 #ifdef __INTEGRATE_LOBBY2_WITH_ROOMS_PLUGIN
8 #include "RoomsPlugin.h"
9 #endif
10 
11 using namespace RakNet;
12 
UserCompByUsername(const RakString & key,Lobby2Server::User * const & data)13 int Lobby2Server::UserCompByUsername( const RakString &key, Lobby2Server::User * const &data )
14 {
15 	if (key < data->userName)
16 		return -1;
17 	if (key==data->userName)
18 		return 0;
19 	return 1;
20 }
21 
Lobby2Server()22 Lobby2Server::Lobby2Server()
23 {
24 	DataStructures::OrderedList<SystemAddress, SystemAddress>::IMPLEMENT_DEFAULT_COMPARISON();
25 	DataStructures::OrderedList<RakString, RakString>::IMPLEMENT_DEFAULT_COMPARISON();
26 	roomsPlugin=0;
27 	roomsPluginAddress=UNASSIGNED_SYSTEM_ADDRESS;
28 }
~Lobby2Server()29 Lobby2Server::~Lobby2Server()
30 {
31 	Clear();
32 }
SendMessage(Lobby2Message * msg,const DataStructures::List<SystemAddress> & recipients)33 void Lobby2Server::SendMessage(Lobby2Message *msg, const DataStructures::List<SystemAddress> &recipients)
34 {
35 	RakNet::BitStream bs;
36 	bs.Write((MessageID)ID_LOBBY2_SEND_MESSAGE);
37 	bs.Write((MessageID)msg->GetID());
38 	msg->Serialize(true,true,&bs);
39 	SendUnifiedToMultiple(&bs,packetPriority, RELIABLE_ORDERED, orderingChannel, recipients);
40 }
Update(void)41 void Lobby2Server::Update(void)
42 {
43 	while (threadActionQueue.Size())
44 	{
45 		threadActionQueueMutex.Lock();
46 		if (threadActionQueue.Size())
47 		{
48 			ThreadAction ta = threadActionQueue.Pop();
49 			threadActionQueueMutex.Unlock();
50 			if (ta.action==L2MID_Client_Logoff)
51 			{
52 				OnLogoff(&ta.command, false);
53 			}
54 			else if (ta.action==L2MID_Client_Login)
55 			{
56 				OnLogin(&ta.command, false);
57 			}
58 			else if (ta.action==L2MID_Client_ChangeHandle)
59 			{
60 				OnChangeHandle(&ta.command, false);
61 			}
62 		}
63 		else
64 		{
65 			threadActionQueueMutex.Unlock();
66 			break;
67 		}
68 	}
69 
70 	if (threadPool.HasOutputFast() && threadPool.HasOutput())
71 	{
72 		Lobby2ServerCommand c = threadPool.GetOutput();
73 		c.lobby2Message->ServerPostDBMemoryImpl(this, c.callingUserName);
74 		if (c.returnToSender)
75 		{
76 			RakNet::BitStream bs;
77 			bs.Write((MessageID)ID_LOBBY2_SEND_MESSAGE);
78 			bs.Write((MessageID)c.lobby2Message->GetID());
79 			c.lobby2Message->Serialize(true,true,&bs);
80 			// Have the ID to send to, but not the address. The ID came from the thread, such as notifying another user
81 			if (c.callerSystemAddresses.Size()==0)
82 			{
83 				unsigned int i;
84 				if (c.callerUserId!=0)
85 				{
86 					for (i=0; i < users.Size(); i++)
87 					{
88 						if (users[i]->callerUserId==c.callerUserId)
89 						{
90 							c.callerSystemAddresses=users[i]->systemAddresses;
91 							c.callerGuids=users[i]->guids;
92 
93 							/*
94 							if (c.requiredConnectionAddress!=UNASSIGNED_SYSTEM_ADDRESS)
95 							{
96 								// This message refers to another user that has to be logged on for it to be sent
97 								bool objectExists;
98 								unsigned int idx;
99 								idx = users.GetIndexFromKey(c.callerSystemAddress,&objectExists);
100 								if (objectExists==false)
101 								{
102 									if (c.deallocMsgWhenDone)
103 										RakNet::OP_DELETE(c.lobby2Message, __FILE__, __LINE__);
104 									return;
105 								}
106 							}
107 							*/
108 							break;
109 						}
110 					}
111 				}
112 				if (c.callerSystemAddresses.Size()==0 && c.callingUserName.IsEmpty()==false)
113 				{
114 					for (i=0; i < users.Size(); i++)
115 					{
116 						if (users[i]->callerUserId==c.callerUserId)
117 						{
118 							c.callerSystemAddresses=users[i]->systemAddresses;
119 							c.callerGuids=users[i]->guids;
120 							break;
121 						}
122 					}
123 				}
124 			}
125 			else
126 			{
127 				bool objectExists;
128 				unsigned int idx;
129 				idx = users.GetIndexFromKey(c.callingUserName,&objectExists);
130 				if (objectExists &&
131 					c.callingUserName.IsEmpty()==false &&
132 					users[idx]->userName!=c.callingUserName)
133 				{
134 					// Different user, same IP address. Abort the send.
135 					if (c.deallocMsgWhenDone)
136 						RakNet::OP_DELETE(c.lobby2Message, __FILE__, __LINE__);
137 					return;
138 				}
139 			}
140 			SendUnifiedToMultiple(&bs,packetPriority, RELIABLE_ORDERED, orderingChannel, c.callerSystemAddresses);
141 		}
142 		if (c.deallocMsgWhenDone)
143 			RakNet::OP_DELETE(c.lobby2Message, __FILE__, __LINE__);
144 	}
145 }
OnReceive(Packet * packet)146 PluginReceiveResult Lobby2Server::OnReceive(Packet *packet)
147 {
148 	RakAssert(packet);
149 
150 	switch (packet->data[0])
151 	{
152 	case ID_LOBBY2_SEND_MESSAGE:
153 		OnMessage(packet);
154 		return RR_STOP_PROCESSING_AND_DEALLOCATE;
155 	}
156 
157 	return RR_CONTINUE_PROCESSING;
158 }
OnShutdown(void)159 void Lobby2Server::OnShutdown(void)
160 {
161 	Clear();
162 }
OnClosedConnection(SystemAddress systemAddress,RakNetGUID rakNetGUID,PI2_LostConnectionReason lostConnectionReason)163 void Lobby2Server::OnClosedConnection(SystemAddress systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason )
164 {
165 	(void)rakNetGUID;
166 	(void)lostConnectionReason;
167 
168 	unsigned int index = GetUserIndexBySystemAddress(systemAddress);
169 
170 	// If systemAddress is a user, then notify his friends about him logging off
171 	if (index!=-1)
172 	{
173 		bool found=false;
174 		User *user = users[index];
175 		for (unsigned int i=0; i < user->systemAddresses.Size(); i++)
176 		{
177 			if (user->systemAddresses[i]==systemAddress)
178 			{
179 				found=true;
180 				user->systemAddresses.RemoveAtIndexFast(i);
181 				break;
182 			}
183 		}
184 
185 		if (found && user->systemAddresses.Size()==0)
186 		{
187 			// Log this logoff due to closed connection
188 			Lobby2Message *lobby2Message = msgFactory->Alloc(L2MID_Client_Logoff);
189 			Lobby2ServerCommand command;
190 			command.lobby2Message=lobby2Message;
191 			command.deallocMsgWhenDone=true;
192 			command.returnToSender=true;
193 			command.callerUserId=users[index]->callerUserId;
194 			command.server=this;
195 			ExecuteCommand(&command);
196 
197 			RemoveUser(index);
198 		}
199 	}
200 }
OnMessage(Packet * packet)201 void Lobby2Server::OnMessage(Packet *packet)
202 {
203 	RakNet::BitStream bs(packet->data,packet->length,false);
204 	bs.IgnoreBytes(1); // ID_LOBBY2_SEND_MESSAGE
205 	MessageID msgId;
206 	bs.Read(msgId);
207 	Lobby2MessageID lobby2MessageID = (Lobby2MessageID) msgId;
208 	unsigned int index;
209 	Lobby2Message *lobby2Message = msgFactory->Alloc(lobby2MessageID);
210 	if (lobby2Message)
211 	{
212 		lobby2Message->Serialize(false,false,&bs);
213 		Lobby2ServerCommand command;
214 		command.lobby2Message=lobby2Message;
215 		command.deallocMsgWhenDone=true;
216 		command.returnToSender=true;
217 		index=GetUserIndexBySystemAddress(packet->systemAddress);
218 		if (index!=-1)
219 		{
220 			command.callingUserName=users[index]->userName;
221 			command.callerUserId=users[index]->callerUserId;
222 		}
223 		else
224 		{
225 			if (lobby2Message->RequiresLogin())
226 			{
227 				RakNet::BitStream bs;
228 				bs.Write((MessageID)ID_LOBBY2_SEND_MESSAGE);
229 				bs.Write((MessageID)lobby2Message->GetID());
230 				lobby2Message->resultCode=L2RC_NOT_LOGGED_IN;
231 				lobby2Message->Serialize(true,true,&bs);
232 				SendUnified(&bs,packetPriority, RELIABLE_ORDERED, orderingChannel, packet->systemAddress, false);
233 				return;
234 			}
235 			command.callerUserId=0;
236 		}
237 		command.callerSystemAddresses.Push(packet->systemAddress,__FILE__,__LINE__);
238 		command.callerGuids.Push(packet->guid,__FILE__,__LINE__);
239 		command.server=this;
240 		ExecuteCommand(&command);
241 	}
242 	else
243 	{
244 		RakNet::BitStream out;
245 		out.Write((MessageID)ID_LOBBY2_SERVER_ERROR);
246 		out.Write((unsigned char) L2SE_UNKNOWN_MESSAGE_ID);
247 		out.Write((unsigned int) msgId);
248 		SendUnified(&bs,packetPriority, RELIABLE_ORDERED, orderingChannel, packet->systemAddress, false);
249 	}
250 }
Clear(void)251 void Lobby2Server::Clear(void)
252 {
253 	ClearAdminAddresses();
254 	ClearRankingAddresses();
255 	ClearUsers();
256 	ClearConnections();
257 
258 	threadPool.StopThreads();
259 	RakAssert(threadPool.NumThreadsWorking()==0);
260 
261 	unsigned i;
262 	Lobby2ServerCommand c;
263 	for (i=0; i < threadPool.InputSize(); i++)
264 	{
265 		c = threadPool.GetInputAtIndex(i);
266 		if (c.deallocMsgWhenDone && c.lobby2Message)
267 			RakNet::OP_DELETE(c.lobby2Message, __FILE__, __LINE__);
268 	}
269 	threadPool.ClearInput();
270 	for (i=0; i < threadPool.OutputSize(); i++)
271 	{
272 		c = threadPool.GetOutputAtIndex(i);
273 		if (c.deallocMsgWhenDone && c.lobby2Message)
274 			RakNet::OP_DELETE(c.lobby2Message, __FILE__, __LINE__);
275 	}
276 	threadPool.ClearOutput();
277 
278 	threadActionQueueMutex.Lock();
279 	threadActionQueue.Clear(__FILE__, __LINE__);
280 	threadActionQueueMutex.Unlock();
281 }
AddAdminAddress(SystemAddress addr)282 void Lobby2Server::AddAdminAddress(SystemAddress addr)
283 {
284 	adminAddresses.Insert(addr,addr,false, __FILE__, __LINE__ );
285 }
HasAdminAddress(const DataStructures::List<SystemAddress> & addresses)286 bool Lobby2Server::HasAdminAddress(const DataStructures::List<SystemAddress> &addresses)
287 {
288 	if (addresses.Size()==0)
289 		return true;
290 
291 	unsigned int j;
292 	for (j=0; j < addresses.Size(); j++)
293 	{
294 		if (adminAddresses.HasData(addresses[j]))
295 			return true;
296 	}
297 	return false;
298 }
RemoveAdminAddress(SystemAddress addr)299 void Lobby2Server::RemoveAdminAddress(SystemAddress addr)
300 {
301 	adminAddresses.RemoveIfExists(addr);
302 }
ClearAdminAddresses(void)303 void Lobby2Server::ClearAdminAddresses(void)
304 {
305 	adminAddresses.Clear(false, __FILE__, __LINE__);
306 }
AddRankingAddress(SystemAddress addr)307 void Lobby2Server::AddRankingAddress(SystemAddress addr)
308 {
309 	rankingAddresses.Insert(addr,addr,false, __FILE__, __LINE__ );
310 }
HasRankingAddress(const DataStructures::List<SystemAddress> & addresses)311 bool Lobby2Server::HasRankingAddress(const DataStructures::List<SystemAddress> &addresses)
312 {
313 	if (addresses.Size()==0)
314 		return true;
315 
316 	unsigned int j;
317 	for (j=0; j < addresses.Size(); j++)
318 	{
319 		if (rankingAddresses.HasData(addresses[j]))
320 			return true;
321 	}
322 	return false;
323 }
RemoveRankingAddress(SystemAddress addr)324 void Lobby2Server::RemoveRankingAddress(SystemAddress addr)
325 {
326 	rankingAddresses.RemoveIfExists(addr);
327 }
ClearRankingAddresses(void)328 void Lobby2Server::ClearRankingAddresses(void)
329 {
330 	rankingAddresses.Clear(false, __FILE__, __LINE__);
331 }
ExecuteCommand(Lobby2ServerCommand * command)332 void Lobby2Server::ExecuteCommand(Lobby2ServerCommand *command)
333 {
334 	RakNet::BitStream out;
335 	if (command->lobby2Message->PrevalidateInput()==false)
336 	{
337 		SendMessage(command->lobby2Message, command->callerSystemAddresses);
338 		if (command->deallocMsgWhenDone)
339 			msgFactory->Dealloc(command->lobby2Message);
340 		return;
341 	}
342 
343 	if (command->lobby2Message->RequiresAdmin() && HasAdminAddress(command->callerSystemAddresses)==false)
344 	{
345 		command->lobby2Message->resultCode=L2RC_REQUIRES_ADMIN;
346 		SendMessage(command->lobby2Message, command->callerSystemAddresses);
347 		SendUnifiedToMultiple(&out,packetPriority, RELIABLE_ORDERED, orderingChannel, command->callerSystemAddresses);
348 		if (command->deallocMsgWhenDone)
349 			msgFactory->Dealloc(command->lobby2Message);
350 		return;
351 	}
352 
353 	if (command->lobby2Message->RequiresRankingPermission() && HasRankingAddress(command->callerSystemAddresses)==false)
354 	{
355 		command->lobby2Message->resultCode=L2RC_REQUIRES_ADMIN;
356 		SendMessage(command->lobby2Message, command->callerSystemAddresses);
357 		SendUnifiedToMultiple(&out,packetPriority, RELIABLE_ORDERED, orderingChannel, command->callerSystemAddresses);
358 		if (command->deallocMsgWhenDone)
359 			msgFactory->Dealloc(command->lobby2Message);
360 		return;
361 	}
362 
363 	if (command->lobby2Message->ServerPreDBMemoryImpl(this, command->callingUserName)==true)
364 	{
365 		SendMessage(command->lobby2Message, command->callerSystemAddresses);
366 		if (command->deallocMsgWhenDone)
367 			msgFactory->Dealloc(command->lobby2Message);
368 		return;
369 	}
370 
371 	command->server=this;
372 	AddInputCommand(*command);
373 }
SetRoomsPlugin(RoomsPlugin * rp)374 void Lobby2Server::SetRoomsPlugin(RoomsPlugin *rp)
375 {
376 	roomsPlugin=rp;
377 	roomsPluginAddress=UNASSIGNED_SYSTEM_ADDRESS;
378 }
SetRoomsPluginAddress(SystemAddress address)379 void Lobby2Server::SetRoomsPluginAddress(SystemAddress address)
380 {
381 	roomsPluginAddress=address;
382 	roomsPlugin=0;
383 }
ClearUsers(void)384 void Lobby2Server::ClearUsers(void)
385 {
386 	unsigned int i;
387 	for (i=0; i < users.Size(); i++)
388 		RakNet::OP_DELETE(users[i], __FILE__, __LINE__);
389 	users.Clear(false, __FILE__, __LINE__);
390 }
LogoffFromRooms(User * user)391 void Lobby2Server::LogoffFromRooms(User *user)
392 {
393 	// Remove from the room too
394 #if defined(__INTEGRATE_LOBBY2_WITH_ROOMS_PLUGIN)
395 	// Tell the rooms plugin about the logoff event
396 	if (roomsPlugin)
397 	{
398 		roomsPlugin->LogoffRoomsParticipant(user->userName, UNASSIGNED_SYSTEM_ADDRESS);
399 	}
400 	else if (roomsPluginAddress!=UNASSIGNED_SYSTEM_ADDRESS)
401 	{
402 		RakNet::BitStream bs;
403 		RoomsPlugin::SerializeLogoff(user->userName,&bs);
404 		SendUnified(&bs,packetPriority, RELIABLE_ORDERED, orderingChannel, roomsPluginAddress, false);
405 	}
406 #endif
407 
408 }
SendRemoteLoginNotification(RakNet::RakString handle,const DataStructures::List<SystemAddress> & recipients)409 void Lobby2Server::SendRemoteLoginNotification(RakNet::RakString handle, const DataStructures::List<SystemAddress>& recipients)
410 {
411 	Notification_Client_RemoteLogin notification;
412 	notification.handle=handle;
413 	notification.resultCode=L2RC_SUCCESS;
414 	SendMessage(&notification, recipients);
415 }
OnLogin(Lobby2ServerCommand * command,bool calledFromThread)416 void Lobby2Server::OnLogin(Lobby2ServerCommand *command, bool calledFromThread)
417 {
418 	if (calledFromThread)
419 	{
420 		ThreadAction ta;
421 		ta.action=L2MID_Client_Login;
422 		ta.command=*command;
423 		threadActionQueueMutex.Lock();
424 		threadActionQueue.Push(ta, __FILE__, __LINE__ );
425 		threadActionQueueMutex.Unlock();
426 		return;
427 	}
428 
429 	bool objectExists;
430 	unsigned int insertionIndex = users.GetIndexFromKey(command->callingUserName, &objectExists);
431 	if (objectExists)
432 	{
433 		User * user = users[insertionIndex];
434 		if (user->allowMultipleLogins==false)
435 		{
436 			SendRemoteLoginNotification(user->userName, user->systemAddresses);
437 			LogoffFromRooms(user);
438 
439 			// Already logged in from this system address.
440 			// Delete the existing entry, which will be reinserted.
441 			RakNet::OP_DELETE(user,__FILE__,__LINE__);
442 			users.RemoveAtIndex(insertionIndex);
443 		}
444 		else
445 		{
446 			if (user->systemAddresses.GetIndexOf(command->callerSystemAddresses[0])==(unsigned int) -1)
447 			{
448 				// Just add system address and guid already in use to the list for this user
449 				user->systemAddresses.Push(command->callerSystemAddresses[0], __FILE__, __LINE__);
450 				user->guids.Push(command->callerGuids[0], __FILE__, __LINE__);
451 			}
452 			return;
453 		}
454 	}
455 	else
456 	{
457 		// Different username, from the same IP address or RakNet instance
458 		unsigned int idx2 = GetUserIndexByGUID(command->callerGuids[0]);
459 		unsigned int idx3 = GetUserIndexBySystemAddress(command->callerSystemAddresses[0]);
460 		if (idx2!=(unsigned int) -1)
461 		{
462 			User * user = users[idx2];
463 			if (user->allowMultipleLogins==true)
464 				return;
465 			SendRemoteLoginNotification(user->userName, user->systemAddresses);
466 			LogoffFromRooms(user);
467 
468 			RakNet::OP_DELETE(user,__FILE__,__LINE__);
469 			users.RemoveAtIndex(idx2);
470 
471 			insertionIndex = users.GetIndexFromKey(command->callingUserName, &objectExists);
472 		}
473 		else if (idx3!=(unsigned int) -1)
474 		{
475 			User * user = users[idx3];
476 			if (user->allowMultipleLogins==true)
477 				return;
478 			SendRemoteLoginNotification(user->userName, user->systemAddresses);
479 			LogoffFromRooms(user);
480 
481 			RakNet::OP_DELETE(user,__FILE__,__LINE__);
482 			users.RemoveAtIndex(idx3);
483 
484 			insertionIndex = users.GetIndexFromKey(command->callingUserName, &objectExists);
485 		}
486 	}
487 
488 
489 	User *user = RakNet::OP_NEW<User>( __FILE__, __LINE__ );
490 	user->userName=command->callingUserName;
491 	user->systemAddresses=command->callerSystemAddresses;
492 	user->guids=command->callerGuids;
493 	user->callerUserId=command->callerUserId;
494 	user->allowMultipleLogins=((Client_Login*)command->lobby2Message)->allowMultipleLogins;
495 	users.InsertAtIndex(user, insertionIndex, __FILE__, __LINE__ );
496 
497 #if defined(__INTEGRATE_LOBBY2_WITH_ROOMS_PLUGIN)
498 	// Tell the rooms plugin about the login event
499 	if (roomsPlugin)
500 	{
501 		roomsPlugin->LoginRoomsParticipant(user->userName, user->systemAddresses[0], user->guids[0], UNASSIGNED_SYSTEM_ADDRESS);
502 	}
503 	else if (roomsPluginAddress!=UNASSIGNED_SYSTEM_ADDRESS)
504 	{
505 		RakNet::BitStream bs;
506 		RoomsPlugin::SerializeLogin(user->userName,user->systemAddresses[0], user->guids[0], &bs);
507 		SendUnified(&bs,packetPriority, RELIABLE_ORDERED, orderingChannel, roomsPluginAddress, false);
508 	}
509 #endif
510 }
OnLogoff(Lobby2ServerCommand * command,bool calledFromThread)511 void Lobby2Server::OnLogoff(Lobby2ServerCommand *command, bool calledFromThread)
512 {
513 	if (calledFromThread)
514 	{
515 		ThreadAction ta;
516 		ta.action=L2MID_Client_Logoff;
517 		ta.command=*command;
518 		threadActionQueueMutex.Lock();
519 		threadActionQueue.Push(ta, __FILE__, __LINE__ );
520 		threadActionQueueMutex.Unlock();
521 		return;
522 	}
523 	RemoveUser(command->callingUserName);
524 }
OnChangeHandle(Lobby2ServerCommand * command,bool calledFromThread)525 void Lobby2Server::OnChangeHandle(Lobby2ServerCommand *command, bool calledFromThread)
526 {
527 	if (calledFromThread)
528 	{
529 		ThreadAction ta;
530 		ta.action=L2MID_Client_ChangeHandle;
531 		ta.command=*command;
532 		threadActionQueueMutex.Lock();
533 		threadActionQueue.Push(ta, __FILE__, __LINE__ );
534 		threadActionQueueMutex.Unlock();
535 		return;
536 	}
537 
538 	unsigned int i;
539 	RakNet::RakString oldHandle;
540 	for (i=0; i < users.Size(); i++)
541 	{
542 		if (users[i]->callerUserId==command->callerUserId)
543 		{
544 			oldHandle=users[i]->userName;
545 			users[i]->userName=command->callingUserName;
546 			break;
547 		}
548 	}
549 
550 	if (oldHandle.IsEmpty())
551 		return;
552 
553 #if defined(__INTEGRATE_LOBBY2_WITH_ROOMS_PLUGIN)
554 	// Tell the rooms plugin about the handle change
555 	if (roomsPlugin)
556 	{
557 		roomsPlugin->ChangeHandle(oldHandle, command->callingUserName);
558 	}
559 	else if (roomsPluginAddress!=UNASSIGNED_SYSTEM_ADDRESS)
560 	{
561 		RakNet::BitStream bs;
562 		RoomsPlugin::SerializeChangeHandle(oldHandle,command->callingUserName,&bs);
563 		SendUnified(&bs,packetPriority, RELIABLE_ORDERED, orderingChannel, roomsPluginAddress, false);
564 	}
565 #endif
566 }
RemoveUser(RakString userName)567 void Lobby2Server::RemoveUser(RakString userName)
568 {
569 	bool objectExists;
570 	unsigned int index = users.GetIndexFromKey(userName, &objectExists);
571 	if (objectExists)
572 		RemoveUser(index);
573 }
RemoveUser(unsigned int index)574 void Lobby2Server::RemoveUser(unsigned int index)
575 {
576 	User *user = users[index];
577 
578 	Lobby2ServerCommand command;
579 	Notification_Friends_StatusChange *notification = (Notification_Friends_StatusChange *) GetMessageFactory()->Alloc(L2MID_Notification_Friends_StatusChange);
580 	notification->otherHandle=user->userName;
581 	notification->op=Notification_Friends_StatusChange::FRIEND_LOGGED_OFF;
582 	notification->resultCode=L2RC_SUCCESS;
583 	command.server=this;
584 	command.deallocMsgWhenDone=true;
585 	command.lobby2Message=notification;
586 	command.callerUserId=user->callerUserId;
587 	command.callingUserName=user->userName;
588 	ExecuteCommand(&command);
589 
590 	unsigned i;
591 	i=0;
592 	threadPool.LockInput();
593 	while (i < threadPool.InputSize())
594 	{
595 		Lobby2ServerCommand command;
596 		command = threadPool.GetInputAtIndex(i);
597 		if (command.lobby2Message->CancelOnDisconnect()&& command.callerSystemAddresses.Size()>0 && user->systemAddresses.GetIndexOf(command.callerSystemAddresses[0])!=(unsigned int)-1)
598 		{
599 			if (command.deallocMsgWhenDone)
600 				RakNet::OP_DELETE(command.lobby2Message, __FILE__, __LINE__);
601 			threadPool.RemoveInputAtIndex(i);
602 		}
603 		else
604 			i++;
605 	}
606 	threadPool.UnlockInput();
607 	LogoffFromRooms(user);
608 
609 	RakNet::OP_DELETE(user,__FILE__,__LINE__);
610 	users.RemoveAtIndex(index);
611 
612 }
GetUserIndexBySystemAddress(SystemAddress systemAddress) const613 unsigned int Lobby2Server::GetUserIndexBySystemAddress(SystemAddress systemAddress) const
614 {
615 	unsigned int idx1,idx2;
616 	for (idx1=0; idx1 < users.Size(); idx1++)
617 	{
618 		for (idx2=0; idx2 < users[idx1]->systemAddresses.Size(); idx2++)
619 		{
620 			if (users[idx1]->systemAddresses[idx2]==systemAddress)
621 				return idx1;
622 		}
623 	}
624 	return (unsigned int) -1;
625 }
GetUserIndexByGUID(RakNetGUID guid) const626 unsigned int Lobby2Server::GetUserIndexByGUID(RakNetGUID guid) const
627 {
628 	unsigned int idx1,idx2;
629 	for (idx1=0; idx1 < users.Size(); idx1++)
630 	{
631 		for (idx2=0; idx2 < users[idx1]->guids.Size(); idx2++)
632 		{
633 			if (users[idx1]->guids[idx2]==guid)
634 				return idx1;
635 		}
636 	}
637 	return (unsigned int) -1;
638 }
GetUserIndexByUsername(RakNet::RakString userName) const639 unsigned int Lobby2Server::GetUserIndexByUsername(RakNet::RakString userName) const
640 {
641 	unsigned int idx;
642 	bool objectExists;
643 	idx = users.GetIndexFromKey(userName,&objectExists);
644 	if (objectExists)
645 		return idx;
646 	return (unsigned int) -1;
647 }
StopThreads(void)648 void Lobby2Server::StopThreads(void)
649 {
650 	threadPool.StopThreads();
651 }
SetConfigurationProperties(ConfigurationProperties c)652 void Lobby2Server::SetConfigurationProperties(ConfigurationProperties c)
653 {
654 	configurationProperties=c;
655 }
GetConfigurationProperties(void) const656 const Lobby2Server::ConfigurationProperties *Lobby2Server::GetConfigurationProperties(void) const
657 {
658 	return &configurationProperties;
659 }
GetUserOnlineStatus(UsernameAndOnlineStatus & userInfo) const660 void Lobby2Server::GetUserOnlineStatus(UsernameAndOnlineStatus &userInfo) const
661 {
662 	unsigned int idx = GetUserIndexByUsername(userInfo.handle);
663 	if (idx!=-1)
664 	{
665 		userInfo.isOnline=true;
666 		userInfo.presence=users[idx]->presence;
667 	}
668 	else
669 	{
670 		userInfo.isOnline=false;
671 		userInfo.presence.status=Lobby2Presence::NOT_ONLINE;
672 		userInfo.presence.isVisible=false;
673 	}
674 }
SetPresence(const RakNet::Lobby2Presence & presence,RakNet::RakString userHandle)675 void Lobby2Server::SetPresence(const RakNet::Lobby2Presence &presence, RakNet::RakString userHandle)
676 {
677 	unsigned int index = GetUserIndexByUsername(userHandle);
678 
679 	if (index!=-1)
680 	{
681 		User *user = users[index];
682 		user->presence=presence;
683 
684 		// Push notify presence update to friends
685 		Lobby2ServerCommand command;
686 		Notification_Friends_PresenceUpdate *notification = (Notification_Friends_PresenceUpdate *) GetMessageFactory()->Alloc(L2MID_Notification_Friends_PresenceUpdate);
687 		notification->newPresence=presence;
688 		notification->otherHandle=user->userName;
689 		notification->resultCode=L2RC_SUCCESS;
690 		command.server=this;
691 		command.deallocMsgWhenDone=true;
692 		command.lobby2Message=notification;
693 		command.callerUserId=user->callerUserId;
694 		command.callingUserName=user->userName;
695 		ExecuteCommand(&command);
696 	}
697 }
GetPresence(RakNet::Lobby2Presence & presence,RakNet::RakString userHandle)698 void Lobby2Server::GetPresence(RakNet::Lobby2Presence &presence, RakNet::RakString userHandle)
699 {
700 	unsigned int userIndex = GetUserIndexByUsername(userHandle);
701 	if (userIndex!=-1)
702 	{
703 		presence=users[userIndex]->presence;
704 	}
705 	else
706 	{
707 		presence.status=Lobby2Presence::NOT_ONLINE;
708 	}
709 }
SendUnifiedToMultiple(const RakNet::BitStream * bitStream,PacketPriority priority,PacketReliability reliability,char orderingChannel,const DataStructures::List<SystemAddress> systemAddresses)710 void Lobby2Server::SendUnifiedToMultiple( const RakNet::BitStream * bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel, const DataStructures::List<SystemAddress> systemAddresses )
711 {
712 	for (unsigned int i=0; i < systemAddresses.Size(); i++)
713 		SendUnified(bitStream,priority,reliability,orderingChannel,systemAddresses[i],false);
714 }
715