SLikeNet  0.1.3
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TeamManager.cpp
Go to the documentation of this file.
1 /*
2  * Original work: Copyright (c) 2014, Oculus VR, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * RakNet License.txt file in the licenses directory of this source tree. An additional grant
7  * of patent rights can be found in the RakNet Patents.txt file in the same directory.
8  *
9  *
10  * Modified work: Copyright (c) 2016-2018, SLikeSoft UG (haftungsbeschränkt)
11  *
12  * This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
13  * license found in the license.txt file in the root directory of this source tree.
14  */
15 
17 #if _RAKNET_SUPPORT_TeamManager==1
18 
19 #include "slikenet/TeamManager.h"
20 #include "slikenet/BitStream.h"
22 #include "slikenet/GetTime.h"
23 
24 using namespace SLNet;
25 
26 
27 enum TeamManagerOperations
28 {
29  ID_RUN_UpdateListsToNoTeam,
30  ID_RUN_UpdateTeamsRequestedToAny,
31  ID_RUN_JoinAnyTeam,
32  ID_RUN_JoinRequestedTeam,
33  ID_RUN_UpdateTeamsRequestedToNoneAndAddTeam,
34  ID_RUN_RemoveFromTeamsRequestedAndAddTeam,
35  ID_RUN_AddToRequestedTeams,
36  ID_RUN_LeaveTeam,
37  ID_RUN_SetMemberLimit,
38  ID_RUN_SetJoinPermissions,
39  ID_RUN_SetBalanceTeams,
40  ID_RUN_SetBalanceTeamsInitial,
41  ID_RUN_SerializeWorld,
42 };
43 
47 
48 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
49 
51 {
52  if (key.whenRequestMade < data.whenRequestMade)
53  return -1;
54  if (key.whenRequestMade > data.whenRequestMade)
55  return 1;
56  if (key.requestIndex < data.requestIndex)
57  return -1;
58  if (key.requestIndex > data.requestIndex)
59  return 1;
60  return 0;
61 }
62 
63 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
64 
66 
67 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
68 
69 TeamSelection::TeamSelection(JoinTeamType itt) : joinTeamType(itt) {}
70 
71 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
72 
73 TeamSelection::TeamSelection(JoinTeamType itt, TM_Team *param) : joinTeamType(itt) {teamParameter.specificTeamToJoin=param;}
74 
75 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
76 
77 TeamSelection::TeamSelection(JoinTeamType itt, NoTeamId param) : joinTeamType(itt) {teamParameter.noTeamSubcategory=param;}
78 
79 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
80 
82 
83 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
84 
85 TeamSelection TeamSelection::SpecificTeam(TM_Team *specificTeamToJoin) {return TeamSelection(JOIN_SPECIFIC_TEAM, specificTeamToJoin);}
86 
87 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
88 
89 TeamSelection TeamSelection::NoTeam(NoTeamId noTeamSubcategory) {return TeamSelection(JOIN_NO_TEAM, noTeamSubcategory);}
90 
91 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
92 
93 
94 
95 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
96 
98 {
99  networkId=0;
100  world=0;
103 }
104 
105 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
106 
108 {
109  if (world)
110  {
112  }
113 }
114 
115 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
116 
117 bool TM_TeamMember::RequestTeam(TeamSelection teamSelection)
118 {
119  if (teamSelection.joinTeamType==JOIN_NO_TEAM)
120  {
121  // If joining no team:
122  // - If already no team, and no team category is the same, return false.
123  // - Execute JoinNoTeam() locally. Return ID_TEAM_BALANCER_TEAM_ASSIGNED locally.
124  // - If we are host, broadcast event. Done.
125  // - Send to remote host event to call JoinNoTeam()
126  // - remote Host executes JoinNoTeam() and broadcasts event. This may cause may cause rebalance if team balancing is on.
127  // - - JoinNoTeam(): Remove from all current and requested teams. Set no-team category.
128 
129  if (teams.Size()==0 && noTeamSubcategory==teamSelection.teamParameter.noTeamSubcategory)
130  {
131  // No change
132  return false;
133  }
134 
135  BitStream bsOut;
137  bsOut.WriteCasted<MessageID>(ID_RUN_UpdateListsToNoTeam);
138  bsOut.Write(world->GetWorldId());
139  bsOut.Write(networkId);
140  bsOut.Write(teamSelection.teamParameter.noTeamSubcategory);
142 
143  StoreLastTeams();
144 
145  UpdateListsToNoTeam(teamSelection.teamParameter.noTeamSubcategory);
146 
149  {
151  world->EnforceTeamBalance(teamSelection.teamParameter.noTeamSubcategory);
152  }
153  }
154  else if (teamSelection.joinTeamType==JOIN_ANY_AVAILABLE_TEAM)
155  {
156  // If joining any team
157  // Execute JoinAnyTeamCheck()
158  // - JoinAnyTeamCheck():
159  // - - If already on a team, return false
160  // - - If any team is already in requested teams, return false.
161  // On local, call UpdateTeamsRequestedToAny(). Send event to also execute this to remote host
162  // If we are host, execute JoinAnyTeam(myguid).
163  // - JoinAnyTeam(requesterGuid): Attempt to join any team immediately. If fails, send to all except requestGuid UpdateTeamsRequestedToAny(). Else sends out new team, including to caller.
164  // On remote host, execute JoinAnyTeamCheck(). If fails, this was because you were added to a team simultaneously on host. This is OK, just ignore the call.
165  // Assuming JoinAnyTeamCheck() passed on remote host, call UpdateTeamsRequestedToAny() for this player. execute JoinAnyTeam(packet->guid).
166 
167  if (JoinAnyTeamCheck()==false)
168  return false;
169 
171 
172  // Send request to host to execute JoinAnyTeam()
173  BitStream bsOut;
175  bsOut.WriteCasted<MessageID>(ID_RUN_JoinAnyTeam);
176  bsOut.Write(world->GetWorldId());
177  bsOut.Write(networkId);
179  }
180  else
181  {
182  RakAssert(teamSelection.joinTeamType==JOIN_SPECIFIC_TEAM);
183 
184  // If joining specific team
185  // Execute JoinSpecificTeamCheck()
186  // JoinSpecificTeamCheck():
187  // - If already on specific team, return false
188  // - If specific team is in requested list, return false
189  // On local, call AddToRequestedTeams(). Send event to also execute this to remote host
190  // If we are host, execute JoinSpecificTeam(myguid)
191  // - JoinSpecificTeam(requesterGuid): Attempt to join specific team immediately. If fails, send to all except requesterGuid to execute AddSpecificToRequested(). Else sends out new team, including to caller.
192  // On remote host, execute JoinSpecificTeamCheck(). If fails, just ignore.
193  // Assuming JoinSpecificTeamCheck() passed on host, call AddSpecificToRequestedList(). Execute JoinSpecificTeam(packet->guid)
194 
195  if (JoinSpecificTeamCheck(teamSelection.teamParameter.specificTeamToJoin,false)==false)
196  return false;
197 
198  AddToRequestedTeams(teamSelection.teamParameter.specificTeamToJoin);
199 
200  // Send request to host to execute JoinRequestedTeam()
201  BitStream bsOut;
203  bsOut.WriteCasted<MessageID>(ID_RUN_JoinRequestedTeam);
204  bsOut.Write(world->GetWorldId());
205  bsOut.Write(networkId);
206  bsOut.Write(teamSelection.teamParameter.specificTeamToJoin->GetNetworkID());
207  bsOut.Write(false);
209  }
210 
211  return true;
212 }
213 
214 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
215 
216 bool TM_TeamMember::RequestTeamSwitch(TM_Team *teamToJoin, TM_Team *teamToLeave)
217 {
218  if (SwitchSpecificTeamCheck(teamToJoin,teamToLeave,false)==false)
219  return false;
220 
221  AddToRequestedTeams(teamToJoin, teamToLeave);
222 
223  // Send request to host to execute JoinRequestedTeam()
224  BitStream bsOut;
226  bsOut.WriteCasted<MessageID>(ID_RUN_JoinRequestedTeam);
227  bsOut.Write(world->GetWorldId());
228  bsOut.Write(networkId);
229  bsOut.Write(teamToJoin->GetNetworkID());
230  bsOut.Write(true);
231  if (teamToLeave)
232  {
233  bsOut.Write(true);
234  bsOut.Write(teamToLeave->GetNetworkID());
235  }
236  else
237  {
238  bsOut.Write(false);
239  }
241 
242  return true;
243 }
244 
245 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
246 
248 {
249  if (teamsRequested.Size()>0)
250  return TeamSelection::SpecificTeam(teamsRequested[0].requested);
251  else if (joinTeamType==JOIN_NO_TEAM)
253  else
255 }
256 
257 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
258 
260 {
261  requestedTeams.Clear(true, _FILE_AND_LINE_);
262  for (unsigned int i=0; i < teamsRequested.Size(); i++)
263  requestedTeams.Push(teamsRequested[i].requested, _FILE_AND_LINE_);
264 }
265 
266 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
267 
269 {
270  unsigned int i = GetRequestedTeamIndex(team);
271  if (i==(unsigned int)-1)
272  return false;
273  return true;
274 }
275 
276 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
277 
278 unsigned int TM_TeamMember::GetRequestedTeamIndex(TM_Team *team) const
279 {
280  unsigned int i;
281  for (i=0; i < teamsRequested.Size(); i++)
282  {
283  if (teamsRequested[i].requested==team)
284  return i;
285  }
286  return (unsigned int) -1;
287 }
288 
289 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
290 
291 unsigned int TM_TeamMember::GetRequestedTeamCount(void) const
292 {
293  return teamsRequested.Size();
294 }
295 
296 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
297 
298 bool TM_TeamMember::CancelTeamRequest(TM_Team *specificTeamToCancel)
299 {
300  if (RemoveFromRequestedTeams(specificTeamToCancel)==false)
301  return false;
302 
303  // Send request to host to execute JoinRequestedTeam()
304  BitStream bsOut;
306  bsOut.Write(world->GetWorldId());
307  bsOut.Write(networkId);
308  if (specificTeamToCancel)
309  {
310  bsOut.Write(true);
311  bsOut.Write(specificTeamToCancel->GetNetworkID());
312  }
313  else
314  {
315  bsOut.Write(false);
316  }
318 
319  world->GetTeamManager()->PushBitStream(&bsOut);
320 
321  return true;
322 }
323 
324 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
325 
326 bool TM_TeamMember::LeaveTeam(TM_Team* team, NoTeamId _noTeamSubcategory)
327 {
328  if (LeaveTeamCheck(team)==false)
329  return false;
330 
332  if (teams.Size()==0)
333  {
334  noTeamSubcategory=_noTeamSubcategory;
336  }
337 
338  // Execute LeaveTeamCheck()
339  // - LeaveTeamCheck():
340  // - - If not on this team, return false
341  // On local, call RemoteFromTeamsList(). Send event to also execute this to remote host
342  // If we are host, execute OnLeaveTeamEvent(myGuid)
343  // - OnLeaveTeamEvent(requesterGuid):
344  // - - If rebalancing is active, rebalance
345  // - - If someone else wants to join this team, let them.
346  // - - Send leave team event notification to all except requesterGuid-
347  // On remote host, execute LeaveTeamCheck(). If fails, ignore.
348  // On remote host, execute RemoteFromTeamsList() followed by OnLeaveTeamEvent(packet->guid)
349 
350  // Pattern:
351  // Execute local check, if fails return false
352  // Locally execute non-host guaranteed changes
353  // If local system is also host, execute host changes. Relay to all but local
354  // On remote host, execute check. If check passes, execute non-host changes, followed by host changes. Relay to all but sender.
355  BitStream bsOut;
357  bsOut.WriteCasted<MessageID>(ID_RUN_LeaveTeam);
358  bsOut.Write(world->GetWorldId());
359  bsOut.Write(networkId);
360  bsOut.Write(team->GetNetworkID());
361  bsOut.Write(noTeamSubcategory);
363 
365  {
366  // Rebalance teams
369  }
370 
371  return true;
372 }
373 
374 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
375 
376 bool TM_TeamMember::LeaveAllTeams(NoTeamId inNoTeamSubcategory)
377 {
378  return RequestTeam(TeamSelection::NoTeam(inNoTeamSubcategory));
379 }
380 
381 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
382 
384 {
385  if (teams.Size()>0)
386  return teams[0];
387  return 0;
388 }
389 
390 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
391 
392 unsigned int TM_TeamMember::GetCurrentTeamCount(void) const
393 {
394  return teams.Size();
395 }
396 
397 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
398 
400 {
401  return teams[index];
402 }
403 
404 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
405 
407 {
408  _teams=teams;
409 }
410 
411 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
412 
414 {
415  _teams=lastTeams;
416 }
417 
418 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
419 
420 bool TM_TeamMember::IsOnTeam(TM_Team *team) const
421 {
422  unsigned int i;
423  for (i=0; i < teams.Size(); i++)
424  {
425  if (teams[i]==team)
426  return true;
427  }
428  return false;
429 }
430 
431 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
432 
434 {
435  return networkId;
436 }
437 
438 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
439 
441 {
442  return world;
443 }
444 
445 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
446 
447 void TM_TeamMember::SerializeConstruction(BitStream *constructionBitstream)
448 {
449  // Write requested teams
450  constructionBitstream->Write(world->GetWorldId());
451  constructionBitstream->Write(networkId);
452  constructionBitstream->WriteCasted<uint16_t>(teamsRequested.Size());
453  for (unsigned int i=0; i < teamsRequested.Size(); i++)
454  {
455  constructionBitstream->Write(teamsRequested[i].isTeamSwitch);
456  if (teamsRequested[i].teamToLeave)
457  {
458  constructionBitstream->Write(true);
459  constructionBitstream->Write(teamsRequested[i].teamToLeave->GetNetworkID());
460  }
461  else
462  {
463  constructionBitstream->Write(false);
464  }
465  if (teamsRequested[i].requested)
466  {
467  constructionBitstream->Write(true);
468  constructionBitstream->Write(teamsRequested[i].requested->GetNetworkID());
469  }
470  else
471  {
472  constructionBitstream->Write(false);
473  }
474  }
475 
476  world->teamManager->EncodeTeamAssigned(constructionBitstream, this);
477 }
478 
479 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
480 
481 bool TM_TeamMember::DeserializeConstruction(TeamManager *teamManager, BitStream *constructionBitstream)
482 {
483  // Read requested teams
484  bool success;
485  uint16_t teamsRequestedSize;
486 
487  WorldId worldId;
488  constructionBitstream->Read(worldId);
489  TM_World *curWorld = teamManager->GetWorldWithId(worldId);
490  RakAssert(curWorld);
491  constructionBitstream->Read(networkId);
492  curWorld->ReferenceTeamMember(this,networkId);
493 
494  success=constructionBitstream->Read(teamsRequestedSize);
495  for (unsigned int i=0; i < teamsRequestedSize; i++)
496  {
497  RequestedTeam rt;
498  rt.isTeamSwitch=false;
499  rt.requested=0;
500  rt.whenRequested=0;
501  constructionBitstream->Read(rt.isTeamSwitch);
502  bool hasTeamToLeave=false;
503  constructionBitstream->Read(hasTeamToLeave);
504  NetworkID teamToLeaveId;
505  if (hasTeamToLeave)
506  {
507  constructionBitstream->Read(teamToLeaveId);
508  rt.teamToLeave = curWorld->GetTeamByNetworkID(teamToLeaveId);
509  RakAssert(rt.teamToLeave);
510  }
511  else
512  rt.teamToLeave=0;
513  bool hasTeamRequested=false;
514  success=constructionBitstream->Read(hasTeamRequested);
515  NetworkID teamRequestedId;
516  if (hasTeamRequested)
517  {
518  success=constructionBitstream->Read(teamRequestedId);
519  rt.requested = curWorld->GetTeamByNetworkID(teamRequestedId);
520  RakAssert(rt.requested);
521  }
522  rt.whenRequested= SLNet::GetTime();
523  rt.requestIndex= curWorld->teamRequestIndex++; // In case whenRequested is the same between two teams when sorting team requests
524  if (
525  (hasTeamToLeave==false || (hasTeamToLeave==true && rt.teamToLeave!=0)) &&
526  (hasTeamRequested==false || (hasTeamRequested==true && rt.requested!=0))
527  )
528  {
530  }
531  }
532 
533 
534  if (success)
535  curWorld->teamManager->ProcessTeamAssigned(constructionBitstream);
536  return success;
537 }
538 
539 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
540 
541 void *TM_TeamMember::GetOwner(void) const
542 {
543  return owner;
544 }
545 
546 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
547 
548 void TM_TeamMember::SetOwner(void *o)
549 {
550  owner=o;
551 }
552 
553 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
554 
556 {
557  return noTeamSubcategory;
558 }
559 
560 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
561 
562 unsigned int TM_TeamMember::GetWorldIndex(void) const
563 {
564  return world->GetTeamMemberIndex(this);
565 }
566 
567 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
568 
569 unsigned long TM_TeamMember::ToUint32( const NetworkID &g )
570 {
571  return g & 0xFFFFFFFF;
572 }
573 
574 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
575 
577 {
579  for (unsigned int i=0; i < teams.Size(); i++)
580  {
581  teams[i]->RemoveFromTeamMemberList(this);
582  }
583  teams.Clear(true, _FILE_AND_LINE_ );
584  noTeamSubcategory=nti;
586 }
587 
588 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
589 
590 bool TM_TeamMember::JoinAnyTeamCheck(void) const
591 {
592  // - - If already on a team, return false
593  if (teams.Size() > 0)
594  return false;
595 
596  // - - If any team is already in requested teams, return false.
598  return false;
599 
600  return true;
601 }
602 
603 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
604 
605 bool TM_TeamMember::JoinSpecificTeamCheck(TM_Team *specificTeamToJoin, bool ignoreRequested) const
606 {
607  // - If already on specific team, return false
608  if (IsOnTeam(specificTeamToJoin))
609  return false;
610 
611  if (ignoreRequested)
612  return true;
613 
614  unsigned int i;
615  for (i=0; i < teamsRequested.Size(); i++)
616  {
617  if (teamsRequested[i].requested==specificTeamToJoin)
618  {
619  if (teamsRequested[i].isTeamSwitch==true)
620  return true; // Turn off team switch
621 
622  // Same thing
623  return false;
624  }
625  }
626 
627  // Not in teams requested
628  return true;
629 }
630 
631 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
632 
633 bool TM_TeamMember::SwitchSpecificTeamCheck(TM_Team *teamToJoin, TM_Team *teamToLeave, bool ignoreRequested) const
634 {
635  RakAssert(teamToJoin!=0);
636 
637  // - If already on specific team, return false
638  if (IsOnTeam(teamToJoin))
639  return false;
640 
641  if (teamToLeave!=0 && IsOnTeam(teamToLeave)==false)
642  return false;
643 
644  if (teamToJoin==teamToLeave)
645  return false;
646 
647  if (ignoreRequested)
648  return true;
649 
650  unsigned int i;
651  for (i=0; i < teamsRequested.Size(); i++)
652  {
653  if (teamsRequested[i].requested==teamToJoin)
654  {
655  if (teamsRequested[i].isTeamSwitch==false)
656  return true; // Different - leave team was off, turn on
657 
658  if (teamsRequested[i].teamToLeave==teamToLeave)
659  return false; // Same thing - leave all or a specific team
660 
661  // Change leave team
662  return true;
663  }
664  }
665 
666  // Not in teams requested
667  return true;
668 }
669 
670 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
671 
672 bool TM_TeamMember::LeaveTeamCheck(TM_Team *team) const
673 {
674  if (IsOnTeam(team)==false)
675  return false;
676  return true;
677 }
678 
679 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
680 
682 {
686  joinAnyRequestIndex=world->teamRequestIndex++; // In case whenRequested is the same between two teams when sorting team requests
687 }
688 
689 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
690 
692 {
695 }
696 
697 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
698 
700 {
701  RemoveFromRequestedTeams(teamToJoin);
702 
703  RequestedTeam rt;
704  rt.isTeamSwitch=false;
705  rt.requested=teamToJoin;
706  rt.teamToLeave=0;
707  rt.whenRequested= SLNet::GetTime();
708  rt.requestIndex=world->teamRequestIndex++; // In case whenRequested is the same between two teams when sorting team requests
710 }
711 
712 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
713 
714 void TM_TeamMember::AddToRequestedTeams(TM_Team *teamToJoin, TM_Team *teamToLeave)
715 {
716  RemoveFromRequestedTeams(teamToJoin);
717 
718  RequestedTeam rt;
719  rt.isTeamSwitch=true;
720  rt.requested=teamToJoin;
721  rt.teamToLeave=teamToLeave;
722  rt.whenRequested= SLNet::GetTime();
723  rt.requestIndex=world->teamRequestIndex++; // In case whenRequested is the same between two teams when sorting team requests
725 }
726 
727 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
728 
730 {
731  if (team==0)
732  {
735  return true;
736  }
737  else
738  {
739  unsigned int i;
740  for (i=0; i < teamsRequested.Size(); i++)
741  {
742  if (teamsRequested[i].requested==team)
743  {
745  if (teamsRequested.Size()==0)
746  {
748  }
749  return true;
750  }
751  }
752  }
753  return false;
754 }
755 
756 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
757 
759 {
760  team->teamMembers.Push(this, _FILE_AND_LINE_ );
761  teams.Push(team, _FILE_AND_LINE_ );
762 }
763 
764 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
765 
767 {
768  unsigned int i,j;
769  for (i=0; i < teams.Size(); i++)
770  {
771  if (teams[i]==team)
772  {
773  for (j=0; j < team->teamMembers.Size(); j++)
774  {
775  if (team->teamMembers[j]==this)
776  {
777  team->teamMembers.RemoveAtIndex(j);
778  break;
779  }
780  }
781  teams.RemoveAtIndex(i);
782  break;
783  }
784  }
785 }
786 
787 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
788 
790 {
791  TM_Team *team;
792  unsigned int i,j;
793  for (i=0; i < teams.Size(); i++)
794  {
795  team = teams[i];
796 
797  for (j=0; j < team->teamMembers.Size(); j++)
798  {
799  if (team->teamMembers[j]==this)
800  {
801  team->teamMembers.RemoveAtIndex(j);
802  break;
803  }
804  }
805  }
806  teams.Clear(true, _FILE_AND_LINE_);
807 }
808 
809 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
810 
812 {
814 }
815 
816 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
817 
818 
819 
820 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
821 
822 
823 
824 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
825 
827 {
828  ID=0;
829  world=0;
831  balancingApplies=true;
832  teamMemberLimit=65535;
833  owner=0;
834 }
835 
836 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
837 
839 {
840  if (world)
841  world->DereferenceTeam(this, 0);
842 }
843 
844 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
845 
846 bool TM_Team::SetMemberLimit(TeamMemberLimit _teamMemberLimit, NoTeamId noTeamId)
847 {
848  if (teamMemberLimit==_teamMemberLimit)
849  return false;
850 
851  teamMemberLimit=_teamMemberLimit;
852  // Network this as request to host
853  BitStream bsOut;
855  bsOut.WriteCasted<MessageID>(ID_RUN_SetMemberLimit);
856  bsOut.Write(world->GetWorldId());
857  bsOut.Write(GetNetworkID());
858  bsOut.Write(teamMemberLimit);
859  bsOut.Write(noTeamId);
860  world->GetTeamManager()->Send(&bsOut, world->GetHost(), false);
861 
862  return true;
863 }
864 
865 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
866 
868 {
869  if (world->GetBalanceTeams()==false)
870  {
871  return teamMemberLimit;
872  }
873  else
874  {
875  TeamMemberLimit limitWithBalancing=world->GetBalancedTeamLimit();
876  if (limitWithBalancing < teamMemberLimit)
877  return limitWithBalancing;
878  return teamMemberLimit;
879  }
880 }
881 
882 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
883 
885 {
886  return teamMemberLimit;
887 }
888 
889 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
890 
891 bool TM_Team::SetJoinPermissions(JoinPermissions _joinPermissions)
892 {
893  if (joinPermissions==_joinPermissions)
894  return false;
895 
896  joinPermissions=_joinPermissions;
897 
898  // Network this as request to host
899  BitStream bsOut;
901  bsOut.WriteCasted<MessageID>(ID_RUN_SetJoinPermissions);
902  bsOut.Write(world->GetWorldId());
903  bsOut.Write(GetNetworkID());
904  bsOut.Write(_joinPermissions);
905  world->GetTeamManager()->Send(&bsOut,world->GetHost(), false);
906 
907  return true;
908 
909 
910 }
911 
912 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
913 
915 {
916  return joinPermissions;
917 }
918 
919 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
920 
921 void TM_Team::LeaveTeam(TM_TeamMember* teamMember, NoTeamId noTeamSubcategory)
922 {
923  teamMember->LeaveTeam(this, noTeamSubcategory);
924 }
925 
926 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
927 
928 bool TM_Team::GetBalancingApplies(void) const
929 {
930  return balancingApplies;
931 }
932 
933 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
934 
936 {
937  _teamMembers=teamMembers;
938 }
939 
940 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
941 
942 unsigned int TM_Team::GetTeamMembersCount(void) const
943 {
944  return teamMembers.Size();
945 }
946 
947 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
948 
949 TM_TeamMember *TM_Team::GetTeamMemberByIndex(unsigned int index) const
950 {
951  return teamMembers[index];
952 }
953 
954 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
955 
957 {
958  return ID;
959 }
960 
961 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
962 
963 TM_World* TM_Team::GetTM_World(void) const
964 {
965  return world;
966 }
967 
968 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
969 
970 void TM_Team::SerializeConstruction(BitStream *constructionBitstream)
971 {
972  // Do not need to serialize member lists, the team members do this
973  constructionBitstream->Write(world->GetWorldId());
974  constructionBitstream->Write(ID);
975  constructionBitstream->Write(joinPermissions);
976  constructionBitstream->Write(balancingApplies);
977  constructionBitstream->Write(teamMemberLimit);
978 
979 }
980 
981 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
982 
983 bool TM_Team::DeserializeConstruction(TeamManager *teamManager, BitStream *constructionBitstream)
984 {
985  WorldId worldId;
986  constructionBitstream->Read(worldId);
987  TM_World *curWorld = teamManager->GetWorldWithId(worldId);
988  RakAssert(curWorld);
989  constructionBitstream->Read(ID);
990  constructionBitstream->Read(joinPermissions);
991  constructionBitstream->Read(balancingApplies);
992  bool b = constructionBitstream->Read(teamMemberLimit);
993  RakAssert(b);
994  if (b)
995  {
996  curWorld->ReferenceTeam(this,ID,balancingApplies);
997  }
998  return b;
999 }
1000 
1001 
1002 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1003 
1004 unsigned long TM_Team::ToUint32( const NetworkID &g )
1005 {
1006  return g & 0xFFFFFFFF;
1007 }
1008 
1009 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1010 
1011 void *TM_Team::GetOwner(void) const
1012 {
1013  return owner;
1014 }
1015 
1016 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1017 
1018 
1019 unsigned int TM_Team::GetWorldIndex(void) const
1020 {
1021  return world->GetTeamIndex(this);
1022 }
1023 
1024 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1025 
1026 void TM_Team::SetOwner(void *o)
1027 {
1028  owner=o;
1029 }
1030 
1031 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1032 
1034 {
1035  unsigned int index = teamMembers.GetIndexOf(teamMember);
1036  RakAssert(index != (unsigned int) -1);
1037  teamMembers.RemoveAtIndex(index);
1038 }
1039 
1040 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1041 
1043 {
1044  unsigned int i;
1045  for (i=0; i < teamMembers.Size(); i++)
1046  {
1047  if (teamMembers[i]->GetCurrentTeamCount()==1)
1048  {
1049  unsigned int j = teamMembers[i]->GetRequestedTeamIndex(team);
1050  if (j!=(unsigned int)-1)
1051  {
1052  if (teamMembers[i]->teamsRequested[j].isTeamSwitch &&
1053  (teamMembers[i]->teamsRequested[j].teamToLeave==0 ||
1054  teamMembers[i]->teamsRequested[j].teamToLeave==teamMembers[i]->teams[0])
1055  )
1056  return i;
1057  }
1058  }
1059  }
1060  return (unsigned int) -1;
1061 }
1062 
1063 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1064 
1065 
1066 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1067 
1069 {
1070  teamManager=0;
1071  balanceTeamsIsActive=false;
1073  worldId=0;
1074  autoAddParticipants=true;
1075  teamRequestIndex=0;
1076 }
1077 
1078 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1079 
1081 {
1082  Clear();
1083 }
1084 
1085 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1086 
1088 {
1089  return teamManager;
1090 }
1091 
1092 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1093 
1094 void TM_World::AddParticipant(RakNetGUID rakNetGUID)
1095 {
1096  participants.Push(rakNetGUID, _FILE_AND_LINE_ );
1097 
1098  // Send to remote system status of balanceTeamsIsActive
1099 
1100  if (GetTeamManager()->GetMyGUIDUnified()==GetHost())
1101  {
1102  // Actually just transmitting initial value of balanceTeamsIsActive
1103  BitStream bsOut;
1105  bsOut.WriteCasted<MessageID>(ID_RUN_SetBalanceTeamsInitial);
1106  bsOut.Write(GetWorldId());
1107  bsOut.Write(balanceTeamsIsActive);
1108  teamManager->SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0,rakNetGUID, false);
1109  }
1110 }
1111 
1112 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1113 
1114 void TM_World::RemoveParticipant(RakNetGUID rakNetGUID)
1115 {
1116  unsigned int i;
1117  i = participants.GetIndexOf(rakNetGUID);
1118  if (i!=(unsigned int)-1)
1120 }
1121 
1122 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1123 
1124 void TM_World::SetAutoManageConnections(bool autoAdd)
1125 {
1126  autoAddParticipants=autoAdd;
1127 }
1128 
1129 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1130 
1132 {
1133  participantList = participants;
1134 }
1135 
1136 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1137 
1138 void TM_World::ReferenceTeam(TM_Team *team, NetworkID networkId, bool applyBalancing)
1139 {
1140  unsigned int i;
1141  for (i=0; i < teams.Size(); i++)
1142  {
1143  if (teams[i]==team)
1144  return;
1145  }
1146 
1147  team->ID=networkId;
1148  team->balancingApplies=applyBalancing;
1149  team->world=this;
1150 
1151  // Add this team to the list of teams
1152  teams.Push(team, _FILE_AND_LINE_);
1153 
1154  teamsHash.Push(networkId,team,_FILE_AND_LINE_);
1155 
1156  // If autobalancing is on, and the team lock state supports it, then call EnforceTeamBalancing()
1157  if (applyBalancing && balanceTeamsIsActive)
1158  {
1159  EnforceTeamBalance(0);
1160  }
1161 }
1162 
1163 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1164 
1165 void TM_World::DereferenceTeam(TM_Team *team, NoTeamId noTeamSubcategory)
1166 {
1167  unsigned int i;
1168  for (i=0; i < teams.Size(); i++)
1169  {
1170  if (teams[i]==team)
1171  {
1172  TM_Team *curTeam = teams[i];
1173  while (curTeam->teamMembers.Size())
1174  {
1175  curTeam->teamMembers[curTeam->teamMembers.Size()-1]->LeaveTeam(curTeam, noTeamSubcategory);
1176  }
1177  teams.RemoveAtIndex(i);
1178 
1180 
1181  break;
1182  }
1183  }
1184 }
1185 
1186 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1187 
1188 unsigned int TM_World::GetTeamCount(void) const
1189 {
1190  return teams.Size();
1191 }
1192 
1193 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1194 
1195 TM_Team *TM_World::GetTeamByIndex(unsigned int index) const
1196 {
1197  return teams[index];
1198 }
1199 
1200 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1201 
1203 {
1205  if (hi.IsInvalid())
1206  return 0;
1207  return teamsHash.ItemAtIndex(hi);
1208 }
1209 
1210 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1211 
1212 unsigned int TM_World::GetTeamIndex(const TM_Team *team) const
1213 {
1214  unsigned int i;
1215  for (i=0; i < teams.Size(); i++)
1216  {
1217  if (teams[i]==team)
1218  return i;
1219  }
1220  return (unsigned int) -1;
1221 }
1222 
1223 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1224 
1225 void TM_World::ReferenceTeamMember(TM_TeamMember *teamMember, NetworkID networkId)
1226 {
1227  unsigned int i;
1228  for (i=0; i < teamMembers.Size(); i++)
1229  {
1230  if (teamMembers[i]==teamMember)
1231  return;
1232  }
1233 
1234  teamMember->world=this;
1235  teamMember->networkId=networkId;
1236 
1237  teamMembers.Push(teamMember, _FILE_AND_LINE_);
1238 
1239  teamMembersHash.Push(networkId,teamMember,_FILE_AND_LINE_);
1240 }
1241 
1242 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1243 
1245 {
1246  unsigned int i;
1247  for (i=0; i < teamMembers.Size(); i++)
1248  {
1249  if (teamMembers[i]==teamMember)
1250  {
1251  teamMembers[i]->UpdateListsToNoTeam(0);
1252  teamMembersHash.Remove(teamMembers[i]->GetNetworkID(),_FILE_AND_LINE_);
1254  break;
1255  }
1256  }
1257 }
1258 
1259 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1260 
1261 unsigned int TM_World::GetTeamMemberCount(void) const
1262 {
1263  return teamMembers.Size();
1264 }
1265 
1266 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1267 
1268 TM_TeamMember *TM_World::GetTeamMemberByIndex(unsigned int index) const
1269 {
1270  return teamMembers[index];
1271 }
1272 
1273 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1274 
1275 NetworkID TM_World::GetTeamMemberIDByIndex(unsigned int index) const
1276 {
1277  return teamMembers[index]->GetNetworkID();
1278 }
1279 
1280 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1281 
1283 {
1285  if (hi.IsInvalid())
1286  return 0;
1287  return teamMembersHash.ItemAtIndex(hi);
1288 }
1289 
1290 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1291 
1292 unsigned int TM_World::GetTeamMemberIndex(const TM_TeamMember *teamMember) const
1293 {
1294  unsigned int i;
1295  for (i=0; i < teamMembers.Size(); i++)
1296  {
1297  if (teamMembers[i]==teamMember)
1298  return i;
1299  }
1300  return (unsigned int) -1;
1301 }
1302 
1303 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1304 
1305 bool TM_World::SetBalanceTeams(bool balanceTeams, NoTeamId noTeamId)
1306 {
1307  if (balanceTeams==balanceTeamsIsActive)
1308  return false;
1309 
1310  balanceTeamsIsActive=balanceTeams;
1311 
1312  // Network this as request to host
1313  BitStream bsOut;
1315  bsOut.WriteCasted<MessageID>(ID_RUN_SetBalanceTeams);
1316  bsOut.Write(GetWorldId());
1317  bsOut.Write(balanceTeams);
1318  bsOut.Write(noTeamId);
1320 
1321  return true;
1322 }
1323 
1324 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1325 
1326 bool TM_World::GetBalanceTeams(void) const
1327 {
1328  return balanceTeamsIsActive;
1329 }
1330 
1331 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1332 
1333 void TM_World::SetHost(RakNetGUID _hostGuid)
1334 {
1335  if (hostGuid==_hostGuid)
1336  return;
1337 
1338  RakAssert(_hostGuid!=UNASSIGNED_RAKNET_GUID);
1339 
1340  hostGuid=_hostGuid;
1341 
1342  if (GetHost()==GetTeamManager()->GetMyGUIDUnified())
1344 }
1345 
1346 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1347 
1348 RakNetGUID TM_World::GetHost(void) const
1349 {
1350  return hostGuid;
1351 }
1352 
1353 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1354 
1355 WorldId TM_World::GetWorldId(void) const
1356 {
1357  return worldId;
1358 }
1359 
1360 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1361 
1362 void TM_World::Clear(void)
1363 {
1364  for (unsigned int i=0; i < teams.Size(); i++)
1365  {
1366  teams[i]->world=0;
1367  }
1368  for (unsigned int i=0; i < teamMembers.Size(); i++)
1369  {
1370  teamMembers[i]->world=0;
1371  }
1373  teams.Clear(true, _FILE_AND_LINE_);
1375 }
1376 
1377 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1378 
1379 void TM_World::OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason )
1380 {
1381  (void) lostConnectionReason;
1382  (void) systemAddress;
1383 
1384  RemoveParticipant(rakNetGUID);
1385 }
1386 
1387 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1388 
1389 void TM_World::OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming)
1390 {
1391  (void) isIncoming;
1392  (void) systemAddress;
1393 
1394  if (autoAddParticipants)
1395  AddParticipant(rakNetGUID);
1396 }
1397 
1398 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1399 
1401 {
1402  // Host only function
1403  RakAssert(GetHost()==GetTeamManager()->GetMyGUIDUnified());
1404 
1405  KickExcessMembers(noTeamId);
1406 }
1407 
1408 
1409 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1410 
1412 {
1413  // Host only function
1414  RakAssert(GetHost()==GetTeamManager()->GetMyGUIDUnified());
1415 
1416  // For each team that applies balancing, if the team is overfull, put on a team that is not overfull if the team has ALLOW_JOIN_REBALANCING set
1417  // If cannot move the player to another team, just take the player off the team and set to noTeamId if they have no team at that point
1418 
1419  TeamMemberLimit balancedTeamLimit;
1421  balancedTeamLimit = GetBalancedTeamLimit();
1422  else
1423  balancedTeamLimit = (TeamMemberLimit) -1;
1424 
1425  TM_Team *team, *teamToJoin;
1426  unsigned int i, teamIndex;
1427  for (i=0; i < teams.Size(); i++)
1428  {
1429  team = teams[i];
1430  while (team->GetMemberLimitSetting() < team->GetTeamMembersCount() ||
1431  (balancedTeamLimit < team->GetTeamMembersCount() && team->GetBalancingApplies()) )
1432  {
1433  TM_TeamMember *teamMember = team->teamMembers[team->teamMembers.Size()-1];
1434 
1435  teamIndex = GetAvailableTeamIndexWithFewestMembers(balancedTeamLimit, ALLOW_JOIN_REBALANCING);
1436  if (teamIndex == (unsigned int)-1)
1437  {
1438  // Move this member to no team
1439  teamMember->LeaveTeam(team, noTeamId);
1440  teamManager->PushTeamAssigned(teamMember);
1441  }
1442  else
1443  {
1444  teamToJoin = teams[teamIndex];
1445 
1446  // Move this member
1447  teamMember->StoreLastTeams();
1448  teamManager->RemoveFromTeamsRequestedAndAddTeam(teamMember, teamToJoin, true, team);
1449 
1450  BitStream bsOut;
1452  bsOut.WriteCasted<MessageID>(ID_RUN_RemoveFromTeamsRequestedAndAddTeam);
1453  bsOut.Write(GetWorldId());
1454  bsOut.Write(teamMember->GetNetworkID());
1455  bsOut.Write(teamToJoin->GetNetworkID());
1456  bsOut.Write(true);
1457  bsOut.Write(true);
1458  bsOut.Write(team->GetNetworkID());
1460  }
1461 
1462  }
1463  }
1464 }
1465 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1466 
1468 {
1469  // Host only function
1470  RakAssert(GetHost()==GetTeamManager()->GetMyGUIDUnified());
1471 
1472 
1473  TeamMemberLimit balancedTeamLimit;
1475  balancedTeamLimit = GetBalancedTeamLimit();
1476  else
1477  balancedTeamLimit = (TeamMemberLimit) -1;
1478 
1479  unsigned int teamIndex, indexIntoTeamsRequested = (unsigned int)-1;
1480  TM_Team *team;
1481  TM_TeamMember *teamMember;
1483  GetSortedJoinRequests(joinRequests);
1484  unsigned int joinRequestIndex;
1485 
1486  for (joinRequestIndex=0; joinRequestIndex < joinRequests.Size(); joinRequestIndex++)
1487  {
1488  teamMember = teamMembers[joinRequests[joinRequestIndex].teamMemberIndex];
1489  if (teamMember->teamsRequested.Size()==0)
1490  {
1491  if (teamMember->joinTeamType==JOIN_ANY_AVAILABLE_TEAM)
1493  else
1494  teamIndex=(unsigned int)-1;
1495  }
1496  else
1497  {
1498  indexIntoTeamsRequested = joinRequests[joinRequestIndex].indexIntoTeamsRequested;
1499 
1500  team = teamMember->teamsRequested[indexIntoTeamsRequested].requested;
1501  if (team->GetTeamMembersCount() < balancedTeamLimit &&
1502  team->GetTeamMembersCount() < team->GetMemberLimitSetting() &&
1504  {
1505  teamIndex=teams.GetIndexOf(team);
1506  }
1507  else
1508  {
1509  teamIndex=(unsigned int)-1;
1510  }
1511  }
1512 
1513  if (teamIndex != (unsigned int)-1)
1514  {
1515  team = teams[teamIndex];
1516 
1517  if (teamMember->teamsRequested.Size()==0)
1518  {
1519  if (teamMember->joinTeamType==JOIN_ANY_AVAILABLE_TEAM)
1520  {
1521  // Join any
1522  teamMember->StoreLastTeams();
1523  teamMember->UpdateTeamsRequestedToNone();
1524  teamMember->AddToTeamList(teams[teamIndex]);
1525  teamManager->PushTeamAssigned(teamMember);
1526 
1527  BitStream bsOut;
1529  bsOut.WriteCasted<MessageID>(ID_RUN_UpdateTeamsRequestedToNoneAndAddTeam);
1530  bsOut.Write(GetWorldId());
1531  bsOut.Write(teamMember->GetNetworkID());
1532  bsOut.Write(team->GetNetworkID());
1534  }
1535  }
1536  else
1537  {
1538  // Switch or join specific
1539  DataStructures::List<TM_Team*> teamsWeAreLeaving;
1540  bool isSwitch = teamMember->teamsRequested[indexIntoTeamsRequested].isTeamSwitch;
1541  TM_Team *teamToLeave;
1542  if (isSwitch)
1543  {
1544  teamToLeave=teamMember->teamsRequested[indexIntoTeamsRequested].teamToLeave;
1545  if (teamToLeave)
1546  {
1547  if (teamMember->IsOnTeam(teamToLeave))
1548  {
1549  teamsWeAreLeaving.Push(teamToLeave, _FILE_AND_LINE_);
1550  }
1551  else
1552  {
1553  teamToLeave=0;
1554  isSwitch=false;
1555  }
1556  }
1557  else
1558  {
1559  teamsWeAreLeaving=teamMember->teams;
1560  }
1561  }
1562  else
1563  teamToLeave=0;
1564 
1565  int teamJoined = JoinSpecificTeam(teamMember, team, isSwitch, teamToLeave, teamsWeAreLeaving);
1566 
1567  if (teamJoined==1)
1568  {
1569  BitStream bsOut;
1571  bsOut.WriteCasted<MessageID>(ID_RUN_RemoveFromTeamsRequestedAndAddTeam);
1572  bsOut.Write(GetWorldId());
1573  bsOut.Write(teamMember->GetNetworkID());
1574  bsOut.Write(team->GetNetworkID());
1575  bsOut.Write(isSwitch);
1576  if (teamToLeave!=0)
1577  {
1578  bsOut.Write(true);
1579  bsOut.Write(teamToLeave->GetNetworkID());
1580  }
1581  else
1582  bsOut.Write(false);
1584  }
1585  }
1586  }
1587  }
1588 }
1589 
1590 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1591 
1592 unsigned int TM_World::GetAvailableTeamIndexWithFewestMembers(TeamMemberLimit secondaryLimit, JoinPermissions joinPermissions)
1593 {
1594  unsigned int teamIndex;
1595 
1596  unsigned int lowestTeamMembers = (unsigned int) -1;
1597  unsigned int lowestIndex = (unsigned int) -1;
1598 
1599  for (teamIndex=0; teamIndex < teams.Size(); teamIndex++)
1600  {
1601  if (teams[teamIndex]->GetTeamMembersCount() < secondaryLimit &&
1602  teams[teamIndex]->GetTeamMembersCount() < teams[teamIndex]->GetMemberLimitSetting() &&
1603  teams[teamIndex]->GetTeamMembersCount() < lowestTeamMembers &&
1604  (joinPermissions & teams[teamIndex]->GetJoinPermissions())!=0)
1605  {
1606  lowestTeamMembers = teams[teamIndex]->GetTeamMembersCount();
1607  lowestIndex = teamIndex;
1608  }
1609  }
1610 
1611  return lowestIndex;
1612 }
1613 
1614 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1615 
1617 {
1618  unsigned int i;
1619 
1620  for (i=0; i < teamMembers.Size(); i++)
1621  {
1622  TM_TeamMember *teamMember = teamMembers[i];
1623  if (teamMember->teamsRequested.Size()==0)
1624  {
1625  if (teamMember->joinTeamType==JOIN_ANY_AVAILABLE_TEAM)
1626  {
1628  jrh.whenRequestMade=teamMember->whenJoinAnyRequested;
1629  jrh.teamMemberIndex=i;
1630  jrh.requestIndex=teamMember->joinAnyRequestIndex;
1631  joinRequests.Insert(jrh, jrh, true, _FILE_AND_LINE_);
1632  }
1633  }
1634  else
1635  {
1636  unsigned int j;
1637  for (j=0; j < teamMember->teamsRequested.Size(); j++)
1638  {
1640  jrh.whenRequestMade=teamMember->teamsRequested[j].whenRequested;
1641  jrh.teamMemberIndex=i;
1643  jrh.requestIndex=teamMember->teamsRequested[j].requestIndex;
1644  joinRequests.Insert(jrh, jrh, true, _FILE_AND_LINE_);
1645  }
1646 
1647  }
1648  }
1649 }
1650 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1651 
1653 {
1654  for (unsigned int i=0; i < participants.Size(); i++)
1655  {
1656  if (participants[i]==exclusionGuid)
1657  continue;
1658  teamManager->SendUnified(bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, participants[i], false);
1659  }
1660 }
1661 
1662 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1663 
1664 void TM_World::BroadcastToParticipants(unsigned char *data, const int length, RakNetGUID exclusionGuid)
1665 {
1666  for (unsigned int i=0; i < participants.Size(); i++)
1667  {
1668  if (participants[i]==exclusionGuid)
1669  continue;
1670  teamManager->SendUnified((const char*) data, length, HIGH_PRIORITY, RELIABLE_ORDERED, 0, participants[i], false);
1671  }
1672 }
1673 
1674 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1675 
1676 TM_Team* TM_World::JoinAnyTeam(TM_TeamMember *teamMember, int *resultCode)
1677 {
1678  TeamMemberLimit balancedLimit = GetBalancedTeamLimit();
1679 
1680  unsigned int idx = GetAvailableTeamIndexWithFewestMembers(balancedLimit, ALLOW_JOIN_ANY_AVAILABLE_TEAM);
1681  if (idx == (unsigned int ) -1)
1682  {
1683  // If any team is joinable but full, return full. Otherwise return locked
1684  for (idx=0; idx < teams.Size(); idx++)
1685  {
1686  if ((teams[idx]->GetTeamMembersCount() >= balancedLimit ||
1687  teams[idx]->GetTeamMembersCount() >= teams[idx]->GetMemberLimitSetting()) &&
1688  teams[idx]->GetMemberLimitSetting() != 0 &&
1689  (ALLOW_JOIN_ANY_AVAILABLE_TEAM & teams[idx]->GetJoinPermissions())!=0)
1690  {
1691  // Full
1692  *resultCode=-2;
1693  return teams[idx];
1694  }
1695  }
1696 
1697  // Locked
1698  *resultCode=-1;
1699  return 0;
1700  }
1701 
1702  TM_Team* lowestMemberTeam = teams[idx];
1703 
1704  teamMember->StoreLastTeams();
1705  teamMember->UpdateTeamsRequestedToNone();
1706  teamMember->AddToTeamList(lowestMemberTeam);
1707  teamManager->PushTeamAssigned(teamMember);
1708 
1709  *resultCode=1;
1710  return lowestMemberTeam;
1711 }
1712 
1713 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1714 
1715 int TM_World::JoinSpecificTeam(TM_TeamMember *teamMember, TM_Team *team, bool isTeamSwitch, TM_Team *teamToLeave, DataStructures::List<TM_Team*> &teamsWeAreLeaving)
1716 {
1718  {
1719  if (balanceTeamsIsActive==false || teamsWeAreLeaving.Size()==0)
1720  {
1721  if (team->GetMemberLimit() > team->GetTeamMembersCount())
1722  {
1723  // Can join normally
1724  teamMember->StoreLastTeams();
1725  teamManager->RemoveFromTeamsRequestedAndAddTeam(teamMember, team, isTeamSwitch, teamToLeave);
1726  return 1;
1727  }
1728  else
1729  {
1730  // Full
1731  return -2;
1732  }
1733  }
1734  else
1735  {
1736  // Note: balanceTeamsIsActive==true && isTeamSwitch==true
1737 
1738  // Do limited team swap
1739  // We must be on one team, target must be on one team, and we want to exchange teams
1740  if (teamsWeAreLeaving.Size()==1)
1741  {
1742  unsigned int j = team->GetMemberWithRequestedSingleTeamSwitch(teamsWeAreLeaving[0]);
1743  if (j!=(unsigned int)-1)
1744  {
1745  TM_TeamMember *swappingMember = team->teamMembers[j];
1746  teamMember->StoreLastTeams();
1747  swappingMember->StoreLastTeams();
1748  teamManager->RemoveFromTeamsRequestedAndAddTeam(teamMember, team, true, 0);
1749  teamManager->RemoveFromTeamsRequestedAndAddTeam(swappingMember, teamsWeAreLeaving[0], true, 0);
1750 
1751  // Send ID_TEAM_BALANCER_TEAM_ASSIGNED to all, for swapped member
1752  // Calling function sends ID_RUN_RemoveFromTeamsRequestedAndAddTeam which pushes ID_TEAM_BALANCER_TEAM_ASSIGNED for teamMember
1753  SLNet::BitStream bitStream;
1755  teamManager->EncodeTeamAssigned(&bitStream, swappingMember);
1757 
1758  return 1;
1759  }
1760  }
1761 
1762  // Full
1763  return -2;
1764  }
1765  }
1766  else
1767  {
1768  // Locked
1769  return -1;
1770  }
1771 }
1772 
1773 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1774 
1776 {
1777  if (teams.Size()==0)
1778  return 0;
1779 
1780  if (balanceTeamsIsActive==false)
1781  return (TeamMemberLimit) -1;
1782 
1783  unsigned int i;
1784  bool additionalTeamsExcluded;
1785  TeamMemberLimit balancedLimit;
1786  unsigned int teamsCount=teams.Size();
1787  unsigned int membersCount=teamMembers.Size();
1788  DataStructures::List<TM_Team*> consideredTeams = teams;
1789 
1790  do
1791  {
1792  additionalTeamsExcluded=false;
1793  balancedLimit = (TeamMemberLimit) ((membersCount+(teamsCount-1))/(teamsCount));
1794  i=0;
1795  while (i < consideredTeams.Size())
1796  {
1797  if (consideredTeams[i]->GetMemberLimitSetting() < balancedLimit)
1798  {
1799  additionalTeamsExcluded=true;
1800  membersCount-=consideredTeams[i]->GetMemberLimitSetting();
1801  teamsCount--;
1802  consideredTeams.RemoveAtIndexFast(i);
1803  }
1804  else
1805  {
1806  i++;
1807  }
1808  }
1809 
1810  } while (additionalTeamsExcluded==true && teamsCount>0);
1811 
1812  return balancedLimit;
1813 }
1814 
1815 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1816 
1817 
1818 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1819 
1821 {
1822  for (unsigned int i=0; i < 255; i++)
1823  worldsArray[i]=0;
1824  autoAddParticipants=true;
1826 }
1827 
1828 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1829 
1831 {
1832  Clear();
1833 }
1834 
1835 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1836 
1838 {
1839  RakAssert(worldsArray[worldId]==0 && "World already in use");
1840 
1841  TM_World *newWorld = SLNet::OP_NEW<TM_World>(_FILE_AND_LINE_);
1842  newWorld->worldId=worldId;
1843  newWorld->teamManager=this;
1844  newWorld->hostGuid=GetMyGUIDUnified();
1845  worldsArray[worldId]=newWorld;
1846  worldsList.Push(newWorld,_FILE_AND_LINE_);
1847  return newWorld;
1848 }
1849 
1850 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1851 
1852 void TeamManager::RemoveWorld(WorldId worldId)
1853 {
1854  RakAssert(worldsArray[worldId]!=0 && "World not in use");
1855  for (unsigned int i=0; i < worldsList.Size(); i++)
1856  {
1857  if (worldsList[i]==worldsArray[worldId])
1858  {
1861  break;
1862  }
1863  }
1864  worldsArray[worldId]=0;
1865 }
1866 
1867 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1868 
1869 unsigned int TeamManager::GetWorldCount(void) const
1870 {
1871  return worldsList.Size();
1872 }
1873 
1874 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1875 
1876 TM_World* TeamManager::GetWorldAtIndex(unsigned int index) const
1877 {
1878  return worldsList[index];
1879 }
1880 
1881 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1882 
1884 {
1885  return worldsArray[worldId];
1886 }
1887 
1888 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1889 
1890 void TeamManager::SetAutoManageConnections(bool autoAdd)
1891 {
1892  autoAddParticipants=autoAdd;
1893 
1894  for (unsigned int i=0; i < worldsList.Size(); i++)
1895  {
1896  worldsList[i]->SetAutoManageConnections(autoAdd);
1897  }
1898 }
1899 
1900 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1901 
1902 void TeamManager::SetTopology(TMTopology _topology)
1903 {
1904  topology=_topology;
1905 }
1906 
1907 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1908 
1909 void TeamManager::EncodeTeamFull(SLNet::BitStream *bitStream, TM_TeamMember *teamMember, TM_Team *team)
1910 {
1912  EncodeTeamFullOrLocked(bitStream, teamMember, team);
1913 }
1914 
1915 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1916 
1918  TM_World **world, TM_TeamMember **teamMember, TM_Team **team,
1919  uint16_t &currentMembers, uint16_t &memberLimitIncludingBalancing, bool &balancingIsActive, JoinPermissions &joinPermissions)
1920 {
1921  BitStream bsIn(packet->data,packet->length,false);
1922  bsIn.IgnoreBytes(sizeof(MessageID));
1923  DecomposeTeamFullOrLocked(&bsIn, world, teamMember, team, currentMembers, memberLimitIncludingBalancing, balancingIsActive, joinPermissions);
1924 }
1925 
1926 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1927 
1928 void TeamManager::EncodeTeamLocked(SLNet::BitStream *bitStream, TM_TeamMember *teamMember, TM_Team *team)
1929 {
1931  EncodeTeamFullOrLocked(bitStream, teamMember, team);
1932 }
1933 
1934 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1935 
1937 {
1938  bitStream->Write(teamMember->world->GetWorldId());
1939  bitStream->Write(teamMember->GetNetworkID());
1940  bitStream->Write(team->GetNetworkID());
1941  bitStream->WriteCasted<uint16_t>(team->GetTeamMembersCount());
1942  bitStream->Write(team->GetMemberLimit());
1943  bitStream->Write(team->GetBalancingApplies());
1944  bitStream->Write(team->GetJoinPermissions());
1945 }
1946 
1947 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1948 
1950  uint16_t &currentMembers, uint16_t &memberLimitIncludingBalancing, bool &balancingIsActive, JoinPermissions &joinPermissions)
1951 {
1952  WorldId worldId;
1953  NetworkID teamMemberId;
1954  NetworkID teamId;
1955 
1956  *teamMember=0;
1957  *team=0;
1958  *world=0;
1959 
1960  bsIn->Read(worldId);
1961  bsIn->Read(teamMemberId);
1962  bsIn->Read(teamId);
1963  bsIn->Read(currentMembers);
1964  bsIn->Read(memberLimitIncludingBalancing);
1965  bsIn->Read(balancingIsActive);
1966  bsIn->Read(joinPermissions);
1967 
1968  *world = GetWorldWithId(worldId);
1969  if (*world)
1970  {
1971  *teamMember = (*world)->GetTeamMemberByNetworkID(teamMemberId);
1972  *team = (*world)->GetTeamByNetworkID(teamId);
1973  }
1974 }
1975 
1976 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1977 
1979  TM_World **world, TM_TeamMember **teamMember, TM_Team **team,
1980  uint16_t &currentMembers, uint16_t &memberLimitIncludingBalancing, bool &balancingIsActive, JoinPermissions &joinPermissions)
1981 {
1982  BitStream bsIn(packet->data,packet->length,false);
1983  bsIn.IgnoreBytes(sizeof(MessageID));
1984  DecomposeTeamFullOrLocked(&bsIn, world, teamMember, team, currentMembers, memberLimitIncludingBalancing, balancingIsActive, joinPermissions);
1985 }
1986 
1987 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1988 
1990 {
1991  bitStream->Write(teamMember->world->GetWorldId());
1992  bitStream->Write(teamMember->GetNetworkID());
1993  bitStream->WriteCasted<uint16_t>(teamMember->teams.Size());
1994  for (unsigned int i=0; i < teamMember->teams.Size(); i++)
1995  {
1996  bitStream->Write(teamMember->teams[i]->GetNetworkID());
1997  }
1998  bitStream->Write(teamMember->noTeamSubcategory);
1999  bitStream->Write(teamMember->joinTeamType);
2000 }
2001 
2002 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2003 
2005 {
2006  TM_World *world;
2007  TM_TeamMember *teamMember;
2008  NoTeamId noTeamId;
2009  JoinTeamType joinTeamType;
2012  DataStructures::List<TM_Team *> teamsJoined;
2013  DecodeTeamAssigned(bsIn, &world, &teamMember, noTeamId, joinTeamType, newTeam, teamsLeft, teamsJoined);
2014  if (teamMember)
2015  {
2016  teamMember->StoreLastTeams();
2017  for (unsigned int i=0; i < teamsLeft.Size(); i++)
2018  {
2019  teamMember->RemoveFromSpecificTeamInternal(teamsLeft[i]);
2020  }
2021  for (unsigned int i=0; i < teamsJoined.Size(); i++)
2022  {
2023  if (teamMember->IsOnTeam(teamsJoined[i])==false)
2024  {
2025  teamMember->RemoveFromRequestedTeams(teamsJoined[i]);
2026  teamMember->AddToTeamList(teamsJoined[i]);
2027  }
2028  }
2029  teamMember->noTeamSubcategory=noTeamId;
2030  teamMember->joinTeamType=joinTeamType;
2031  }
2032 }
2033 
2034 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2035 
2036 void TeamManager::DecodeTeamAssigned(Packet *packet, TM_World **world, TM_TeamMember **teamMember)
2037 {
2038  WorldId worldId;
2039  NetworkID teamMemberId;
2040 
2041  SLNet::BitStream bsIn(packet->data, packet->length, false);
2042  bsIn.IgnoreBytes(sizeof(MessageID));
2043  bsIn.Read(worldId);
2044  bsIn.Read(teamMemberId);
2045  *world = GetWorldWithId(worldId);
2046  if (*world)
2047  {
2048  *teamMember = (*world)->GetTeamMemberByNetworkID(teamMemberId);
2049  }
2050  else
2051  {
2052  *teamMember=0;
2053  }
2054 }
2055 
2056 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2057 
2058 void TeamManager::DecodeTeamCancelled(Packet *packet, TM_World **world, TM_TeamMember **teamMember, TM_Team **teamCancelled)
2059 {
2060  WorldId worldId;
2061  NetworkID teamMemberId;
2062 
2063  SLNet::BitStream bsIn(packet->data, packet->length, false);
2064  bsIn.IgnoreBytes(sizeof(MessageID));
2065  bsIn.Read(worldId);
2066  bsIn.Read(teamMemberId);
2067  bool sp=false;
2068  *world = GetWorldWithId(worldId);
2069  if (*world)
2070  {
2071  *teamMember = (*world)->GetTeamMemberByNetworkID(teamMemberId);
2072  }
2073  else
2074  {
2075  *teamMember=0;
2076  }
2077 
2078  bsIn.Read(sp);
2079  if (sp)
2080  {
2081  NetworkID nid;
2082  bsIn.Read(nid);
2083  *teamCancelled = (*world)->GetTeamByNetworkID(nid);
2084  }
2085  else
2086  {
2087  *teamCancelled = 0;
2088  }
2089 }
2090 
2091 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2092 
2093 void TeamManager::DecodeTeamAssigned(BitStream *bsIn, TM_World **world, TM_TeamMember **teamMember, NoTeamId &noTeamId,
2094  JoinTeamType &joinTeamType, DataStructures::List<TM_Team *> &newTeam,
2096  )
2097 {
2098  newTeam.Clear(true, _FILE_AND_LINE_);
2099  teamsLeft.Clear(true, _FILE_AND_LINE_);
2100  teamsJoined.Clear(true, _FILE_AND_LINE_);
2101 
2102  WorldId worldId;
2103  NetworkID teamMemberId;
2104  NetworkID teamId;
2105 
2106  bsIn->Read(worldId);
2107  bsIn->Read(teamMemberId);
2108  *world = GetWorldWithId(worldId);
2109  if (*world)
2110  {
2111  *teamMember = (*world)->GetTeamMemberByNetworkID(teamMemberId);
2112  uint16_t teamsCount;
2113  bsIn->Read(teamsCount);
2114 
2115  for (unsigned int i=0; i < teamsCount; i++)
2116  {
2117  bsIn->Read(teamId);
2118  TM_Team * team = (*world)->GetTeamByNetworkID(teamId);
2119  RakAssert(team);
2120  if (team)
2121  newTeam.Push(team, _FILE_AND_LINE_);
2122  // else probably didn't reference team first
2123  }
2124 
2125  if (*teamMember)
2126  {
2127  for (unsigned int i=0; i < (*teamMember)->teams.Size(); i++)
2128  {
2129  TM_Team *team = (*teamMember)->teams[i];
2130  if (newTeam.GetIndexOf(team)==(unsigned int)-1)
2131  teamsLeft.Push(team, _FILE_AND_LINE_);
2132  }
2133  }
2134 
2135  for (unsigned int i=0; i < newTeam.Size(); i++)
2136  {
2137  TM_Team *team = newTeam[i];
2138  if ((*teamMember)->teams.GetIndexOf(team)==(unsigned int)-1)
2139  teamsJoined.Push(team, _FILE_AND_LINE_);
2140  }
2141 
2142  bsIn->Read(noTeamId);
2143  bsIn->Read(joinTeamType);
2144  }
2145  else
2146  {
2147  *teamMember=0;
2148  }
2149 }
2150 
2151 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2152 
2153 void TeamManager::Clear(void)
2154 {
2155  for (unsigned int i=0; i < worldsList.Size(); i++)
2156  {
2157  worldsArray[worldsList[i]->worldId]=0;
2158  worldsList[i]->Clear();
2159  SLNet::OP_DELETE(worldsList[i], _FILE_AND_LINE_);
2160  }
2161  worldsList.Clear(false, _FILE_AND_LINE_);
2162 }
2163 
2164 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2165 
2166 void TeamManager::Update(void)
2167 {
2168 }
2169 
2170 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2171 
2173 {
2174  switch (packet->data[0])
2175  {
2176  case ID_FCM2_NEW_HOST:
2177  {
2178  unsigned int i;
2179  for (i=0; i < worldsList.Size(); i++)
2180  worldsList[i]->SetHost(packet->guid);
2181  }
2182  break;
2184  {
2185  BitStream bsIn(packet->data,packet->length,false);
2186  bsIn.IgnoreBytes(sizeof(MessageID));
2187 
2188  ProcessTeamAssigned(&bsIn);
2189  }
2190  break;
2192  {
2193  BitStream bsIn(packet->data,packet->length,false);
2194  bsIn.IgnoreBytes(1);
2195  WorldId worldId;
2196  bsIn.Read(worldId);
2197  TM_World *world = GetWorldWithId(worldId);
2198  if (world==0)
2200  bool validPacket = OnRemoveFromRequestedTeams(packet, world);
2201  if (validPacket==false)
2203  break;
2204  }
2206  {
2207  if (packet->length>=2)
2208  {
2209  BitStream bsIn(packet->data,packet->length,false);
2210  bsIn.IgnoreBytes(2);
2211  WorldId worldId;
2212  bsIn.Read(worldId);
2213  TM_World *world = GetWorldWithId(worldId);
2214  if (world==0)
2216 
2217  switch (packet->data[1])
2218  {
2219  case ID_RUN_UpdateListsToNoTeam:
2220  OnUpdateListsToNoTeam(packet, world);
2221  break;
2222  case ID_RUN_UpdateTeamsRequestedToAny:
2223  OnUpdateTeamsRequestedToAny(packet, world);
2224  break;
2225  case ID_RUN_JoinAnyTeam:
2226  OnJoinAnyTeam(packet, world);
2227  break;
2228  case ID_RUN_JoinRequestedTeam:
2229  OnJoinRequestedTeam(packet, world);
2230  break;
2231  case ID_RUN_UpdateTeamsRequestedToNoneAndAddTeam:
2233  break;
2234  case ID_RUN_RemoveFromTeamsRequestedAndAddTeam:
2235  OnRemoveFromTeamsRequestedAndAddTeam(packet, world);
2236  break;
2237  case ID_RUN_AddToRequestedTeams:
2238  OnAddToRequestedTeams(packet, world);
2239  break;
2240  case ID_RUN_LeaveTeam:
2241  OnLeaveTeam(packet, world);
2242  break;
2243  case ID_RUN_SetMemberLimit:
2244  OnSetMemberLimit(packet, world);
2245  break;
2246  case ID_RUN_SetJoinPermissions:
2247  OnSetJoinPermissions(packet, world);
2248  break;
2249  case ID_RUN_SetBalanceTeams:
2250  OnSetBalanceTeams(packet, world);
2251  break;
2252  case ID_RUN_SetBalanceTeamsInitial:
2253  OnSetBalanceTeamsInitial(packet, world);
2254  break;
2255  }
2256  }
2257  }
2259  }
2260 
2261  return RR_CONTINUE_PROCESSING;
2262 }
2263 
2264 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2265 
2266 void TeamManager::OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason )
2267 {
2268  for (unsigned int i=0; i < worldsList.Size(); i++)
2269  {
2270  worldsList[i]->OnClosedConnection(systemAddress, rakNetGUID, lostConnectionReason);
2271  }
2272 }
2273 
2274 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2275 
2276 void TeamManager::OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming)
2277 {
2278  for (unsigned int i=0; i < worldsList.Size(); i++)
2279  {
2280  worldsList[i]->OnNewConnection(systemAddress, rakNetGUID, isIncoming);
2281  }
2282 }
2283 
2284 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2285 
2286 void TeamManager::Send( const SLNet::BitStream * bitStream, const AddressOrGUID systemIdentifier, bool broadcast )
2287 {
2288  SendUnified(bitStream,HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemIdentifier, broadcast);
2289 }
2290 
2291 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2292 
2293 void TeamManager::RemoveFromTeamsRequestedAndAddTeam(TM_TeamMember *teamMember, TM_Team *team, bool isTeamSwitch, TM_Team *teamToLeave)
2294 {
2295  teamMember->RemoveFromRequestedTeams(team);
2296  if (isTeamSwitch)
2297  {
2298  if (teamToLeave==0)
2299  {
2300  // Leave all teams
2301  teamMember->RemoveFromAllTeamsInternal();
2302  }
2303  else
2304  {
2305  // Leave specific team if it exists
2306  teamMember->RemoveFromSpecificTeamInternal(teamToLeave);
2307  }
2308  }
2309  teamMember->AddToTeamList(team);
2310  PushTeamAssigned(teamMember);
2311 }
2312 
2313 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2314 
2316 {
2317  // Push ID_TEAM_BALANCER_TEAM_ASSIGNED locally
2318  SLNet::BitStream bitStream;
2320  EncodeTeamAssigned(&bitStream, teamMember);
2321 
2322  PushBitStream(&bitStream);
2323 }
2324 
2325 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2326 
2328 {
2330  memcpy(p->data, bitStream->GetData(), bitStream->GetNumberOfBytesUsed());
2334  p->wasGeneratedLocally=true;
2335  PushBackPacketUnified(p, true);
2336 }
2337 
2338 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2339 
2341 {
2342  BitStream bsIn(packet->data,packet->length,false);
2343  bsIn.IgnoreBytes(2+sizeof(WorldId));
2344  NetworkID networkId;
2345  bsIn.Read(networkId);
2346  TM_TeamMember *teamMember = world->GetTeamMemberByNetworkID(networkId);
2347  NoTeamId noTeamId;
2348  bsIn.Read(noTeamId);
2349  if (teamMember)
2350  {
2351  teamMember->StoreLastTeams();
2352  teamMember->UpdateListsToNoTeam(noTeamId);
2353  PushTeamAssigned(teamMember);
2354 
2355  if (world->GetHost()==world->GetTeamManager()->GetMyGUIDUnified())
2356  {
2357  world->FillRequestedSlots();
2358  world->EnforceTeamBalance(noTeamId);
2359 
2361  {
2362  // Relay
2363  world->BroadcastToParticipants(packet->data, packet->length, packet->guid);
2364  }
2365  }
2366  }
2367 }
2368 
2369 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2370 
2372 {
2373  BitStream bsIn(packet->data,packet->length,false);
2374  bsIn.IgnoreBytes(2+sizeof(WorldId));
2375  NetworkID networkId;
2376  bsIn.Read(networkId);
2377  TM_TeamMember *teamMember = world->GetTeamMemberByNetworkID(networkId);
2378  if (teamMember)
2379  {
2380  teamMember->UpdateTeamsRequestedToAny();
2381  }
2382 }
2383 
2384 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2385 
2386 void TeamManager::OnJoinAnyTeam(Packet *packet, TM_World *world)
2387 {
2388  BitStream bsIn(packet->data,packet->length,false);
2389  bsIn.IgnoreBytes(2+sizeof(WorldId));
2390  NetworkID networkId;
2391  bsIn.Read(networkId);
2392  TM_TeamMember *teamMember = world->GetTeamMemberByNetworkID(networkId);
2393  if (teamMember)
2394  {
2395  // This is a host-only operation
2396  RakAssert(world->GetHost()==world->GetTeamManager()->GetMyGUIDUnified());
2397 
2398  teamMember->UpdateTeamsRequestedToAny();
2399 
2400  int resultCode;
2401  TM_Team *newTeam = world->JoinAnyTeam(teamMember, &resultCode);
2402 
2403  if (resultCode==1)
2404  {
2405  // Broadcast packet - remote systems should clear requested teams to none, and add the team we joined.
2406  // Broadcast includes non-host sender (all participants)
2407  BitStream bsOut;
2409  bsOut.WriteCasted<MessageID>(ID_RUN_UpdateTeamsRequestedToNoneAndAddTeam);
2410  bsOut.Write(world->GetWorldId());
2411  bsOut.Write(networkId);
2412  bsOut.Write(newTeam->GetNetworkID());
2413  world->BroadcastToParticipants(&bsOut, packet->guid);
2414 
2415  // Send to sender ID_TEAM_BALANCER_TEAM_ASSIGNED
2416  if (packet->guid!=GetMyGUIDUnified())
2417  {
2418  SLNet::BitStream bitStream;
2420  EncodeTeamAssigned(&bitStream, teamMember);
2421  SendUnified(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, packet->guid, false);
2422  }
2423  }
2424  else
2425  {
2426  // Relay packet to set requested teams to any
2427  BitStream bsOut;
2429  bsOut.WriteCasted<MessageID>(ID_RUN_UpdateTeamsRequestedToAny);
2430  bsOut.Write(world->GetWorldId());
2431  bsOut.Write(networkId);
2432  world->BroadcastToParticipants(&bsOut, packet->guid);
2433 
2434  bsOut.Reset();
2435  if (resultCode==-2)
2436  {
2437  EncodeTeamFull(&bsOut, teamMember, newTeam);
2438  }
2439  else if (resultCode==-1)
2440  {
2441  EncodeTeamLocked(&bsOut, teamMember, newTeam);
2442  }
2443  // SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, packet->guid, false);
2445  if (packet->guid!=GetMyGUIDUnified())
2446  PushBitStream(&bsOut);
2447  }
2448  }
2449 }
2450 
2451 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2452 
2453 void TeamManager::OnJoinRequestedTeam(Packet *packet, TM_World *world)
2454 {
2455  BitStream bsIn(packet->data,packet->length,false);
2456  bsIn.IgnoreBytes(2+sizeof(WorldId));
2457  NetworkID networkId;
2458  bsIn.Read(networkId);
2459  TM_TeamMember *teamMember = world->GetTeamMemberByNetworkID(networkId);
2460  NetworkID teamToJoinNetworkId;
2461  bsIn.Read(teamToJoinNetworkId);
2462  TM_Team *teamToJoin = world->GetTeamByNetworkID(teamToJoinNetworkId);
2463  bool isTeamSwitch=false;
2464  bool switchSpecificTeam=false;
2465  NetworkID teamToLeaveNetworkId=UNASSIGNED_NETWORK_ID;
2466  TM_Team *teamToLeave=0;
2467  bsIn.Read(isTeamSwitch);
2468  if (isTeamSwitch)
2469  {
2470  bsIn.Read(switchSpecificTeam);
2471  if (switchSpecificTeam)
2472  {
2473  bsIn.Read(teamToLeaveNetworkId);
2474  teamToLeave = world->GetTeamByNetworkID(teamToLeaveNetworkId);
2475  if (teamToLeave==0)
2476  isTeamSwitch=false;
2477  }
2478  }
2479  if (teamToJoin && teamMember)
2480  {
2481  if (isTeamSwitch)
2482  {
2483  if (teamMember->SwitchSpecificTeamCheck(teamToJoin, teamToLeave, packet->guid==GetMyGUIDUnified())==false)
2484  return;
2485 
2486  teamMember->AddToRequestedTeams(teamToJoin, teamToLeave);
2487  }
2488  else
2489  {
2490  if (teamMember->JoinSpecificTeamCheck(teamToJoin, packet->guid==GetMyGUIDUnified())==false)
2491  return;
2492 
2493  teamMember->AddToRequestedTeams(teamToJoin);
2494  }
2495 
2496  DataStructures::List<TM_Team*> teamsWeAreLeaving;
2497  if (isTeamSwitch)
2498  {
2499  if (teamToLeave==0)
2500  {
2501  teamsWeAreLeaving=teamMember->teams;
2502  }
2503  else
2504  {
2505  if (teamMember->IsOnTeam(teamToLeave))
2506  teamsWeAreLeaving.Push(teamToLeave, _FILE_AND_LINE_);
2507  }
2508 
2509  if (teamsWeAreLeaving.Size()==0)
2510  isTeamSwitch=false;
2511  }
2512 
2513  int resultCode = world->JoinSpecificTeam(teamMember, teamToJoin, isTeamSwitch, teamToLeave, teamsWeAreLeaving);
2514 
2515  if (resultCode==1)
2516  {
2517  // Broadcast packet - remote systems should remove from requested teams and add the team we joined.
2518  // Broadcast includes non-host sender (all participants)
2519  BitStream bsOut;
2521  bsOut.WriteCasted<MessageID>(ID_RUN_RemoveFromTeamsRequestedAndAddTeam);
2522  bsOut.Write(world->GetWorldId());
2523  bsOut.Write(networkId);
2524  bsOut.Write(teamToJoin->GetNetworkID());
2525  bsOut.Write(isTeamSwitch);
2526  if (isTeamSwitch)
2527  {
2528  bsOut.Write(switchSpecificTeam);
2529  if (switchSpecificTeam)
2530  bsOut.Write(teamToLeaveNetworkId);
2531  }
2532  world->BroadcastToParticipants(&bsOut, packet->guid);
2533 
2534  // Send to sender ID_TEAM_BALANCER_TEAM_ASSIGNED
2535  if (packet->guid!=GetMyGUIDUnified())
2536  {
2537  SLNet::BitStream bitStream;
2539  EncodeTeamAssigned(&bitStream, teamMember);
2540  SendUnified(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, packet->guid, false);
2541  }
2542  }
2543  else
2544  {
2545  // Relay packet to set requested teams to any
2546  BitStream bsOut;
2548  bsOut.WriteCasted<MessageID>(ID_RUN_AddToRequestedTeams);
2549  bsOut.Write(world->GetWorldId());
2550  bsOut.Write(networkId);
2551  bsOut.Write(teamToJoin->GetNetworkID());
2552  bsOut.Write(isTeamSwitch);
2553  if (isTeamSwitch)
2554  {
2555  bsOut.Write(switchSpecificTeam);
2556  if (switchSpecificTeam)
2557  bsOut.Write(teamToLeaveNetworkId);
2558  }
2559  world->BroadcastToParticipants(&bsOut, packet->guid);
2560 
2561  bsOut.Reset();
2562  if (resultCode==-2)
2563  {
2564  EncodeTeamFull(&bsOut, teamMember, teamToJoin);
2565  }
2566  else if (resultCode==-1)
2567  {
2568  EncodeTeamLocked(&bsOut, teamMember, teamToJoin);
2569  }
2570  // SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, packet->guid, false);
2571 
2573  if (packet->guid!=GetMyGUIDUnified())
2574  PushBitStream(&bsOut);
2575  }
2576  }
2577 }
2578 
2579 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2580 
2582 {
2583  BitStream bsIn(packet->data,packet->length,false);
2584  bsIn.IgnoreBytes(2+sizeof(WorldId));
2585  NetworkID networkId;
2586  bsIn.Read(networkId);
2587  TM_TeamMember *teamMember = world->GetTeamMemberByNetworkID(networkId);
2588  NetworkID teamNetworkId;
2589  bsIn.Read(teamNetworkId);
2590  TM_Team *team = world->GetTeamByNetworkID(teamNetworkId);
2591 
2592  if (team && teamMember)
2593  {
2594  teamMember->StoreLastTeams();
2595  teamMember->UpdateTeamsRequestedToNone();
2596  teamMember->AddToTeamList(team);
2597  world->GetTeamManager()->PushTeamAssigned(teamMember);
2598  }
2599 }
2600 
2601 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2602 
2604 {
2605  BitStream bsIn(packet->data,packet->length,false);
2606  bsIn.IgnoreBytes(2+sizeof(WorldId));
2607  NetworkID networkId;
2608  bsIn.Read(networkId);
2609  TM_TeamMember *teamMember = world->GetTeamMemberByNetworkID(networkId);
2610  NetworkID teamNetworkId;
2611  bsIn.Read(teamNetworkId);
2612  bool isTeamSwitch=false, switchSpecificTeam=false;
2613  NetworkID teamToLeaveNetworkId;
2614  TM_Team *teamToLeave=0;
2615  bsIn.Read(isTeamSwitch);
2616  if (isTeamSwitch)
2617  {
2618  bsIn.Read(switchSpecificTeam);
2619  if (switchSpecificTeam)
2620  {
2621  bsIn.Read(teamToLeaveNetworkId);
2622  teamToLeave = world->GetTeamByNetworkID(teamToLeaveNetworkId);
2623  }
2624  }
2625 
2626  TM_Team *team = world->GetTeamByNetworkID(teamNetworkId);
2627  if (team && teamMember)
2628  {
2629  teamMember->StoreLastTeams();
2630  if (teamToLeave)
2631  teamMember->RemoveFromSpecificTeamInternal(teamToLeave);
2632  else if (isTeamSwitch==true && switchSpecificTeam==false)
2633  teamMember->RemoveFromAllTeamsInternal();
2634  RemoveFromTeamsRequestedAndAddTeam(teamMember, team, false, 0);
2635  }
2636 }
2637 
2638 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2639 
2641 {
2642  BitStream bsIn(packet->data,packet->length,false);
2643  bsIn.IgnoreBytes(2+sizeof(WorldId));
2644  NetworkID networkId;
2645  bsIn.Read(networkId);
2646  TM_TeamMember *teamMember = world->GetTeamMemberByNetworkID(networkId);
2647  NetworkID teamNetworkId;
2648  bsIn.Read(teamNetworkId);
2649  TM_Team *team = world->GetTeamByNetworkID(teamNetworkId);
2650 
2651  bool isTeamSwitch=false;
2652  bool switchSpecificTeam=false;
2653  NetworkID teamToLeaveNetworkId=UNASSIGNED_NETWORK_ID;
2654  TM_Team *teamToLeave=0;
2655  bsIn.Read(isTeamSwitch);
2656  if (isTeamSwitch)
2657  {
2658  bsIn.Read(switchSpecificTeam);
2659  if (switchSpecificTeam)
2660  {
2661  bsIn.Read(teamToLeaveNetworkId);
2662  teamToLeave = world->GetTeamByNetworkID(teamToLeaveNetworkId);
2663  if (teamToLeave==0)
2664  isTeamSwitch=false;
2665  }
2666  }
2667 
2668  if (team && teamMember)
2669  {
2670  if (isTeamSwitch)
2671  teamMember->AddToRequestedTeams(team, teamToLeave);
2672  else
2673  teamMember->AddToRequestedTeams(team);
2674  }
2675 }
2676 
2677 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2678 
2680 {
2681  BitStream bsIn(packet->data,packet->length,false);
2682  bsIn.IgnoreBytes(1+sizeof(WorldId));
2683  NetworkID networkId;
2684  bsIn.Read(networkId);
2685  TM_TeamMember *teamMember = world->GetTeamMemberByNetworkID(networkId);
2686  bool hasSpecificTeam=false;
2687  NetworkID teamNetworkId;
2688  TM_Team *team;
2689  bsIn.Read(hasSpecificTeam);
2690  if (hasSpecificTeam)
2691  {
2692  bsIn.Read(teamNetworkId);
2693  team = world->GetTeamByNetworkID(teamNetworkId);
2694  if (team==0)
2695  return false;
2696  }
2697  else
2698  {
2699  team=0;
2700  }
2701 
2702  if (teamMember)
2703  {
2704  teamMember->RemoveFromRequestedTeams(team);
2705 
2706  // Relay as host
2707  if (world->GetHost()==world->GetTeamManager()->GetMyGUIDUnified() && topology==TM_CLIENT_SERVER)
2708  {
2709  world->BroadcastToParticipants(packet->data, packet->length, packet->guid);
2710  }
2711  return true;
2712  }
2713  else
2714  {
2715  return false;
2716  }
2717 }
2718 
2719 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2720 
2721 void TeamManager::OnLeaveTeam(Packet *packet, TM_World *world)
2722 {
2723  BitStream bsIn(packet->data,packet->length,false);
2724  bsIn.IgnoreBytes(2+sizeof(WorldId));
2725  NetworkID networkId;
2726  bsIn.Read(networkId);
2727  TM_TeamMember *teamMember = world->GetTeamMemberByNetworkID(networkId);
2728  NetworkID teamNetworkId;
2729  bsIn.Read(teamNetworkId);
2730  TM_Team *team = world->GetTeamByNetworkID(teamNetworkId);
2731  NoTeamId noTeamId;
2732  bsIn.Read(noTeamId);
2733 
2734  if (team && teamMember)
2735  {
2736  if (teamMember->LeaveTeamCheck(team)==false)
2737  return;
2738 
2739  teamMember->StoreLastTeams();
2740  teamMember->RemoveFromSpecificTeamInternal(team);
2741  if (teamMember->GetCurrentTeamCount()==0)
2742  {
2743  teamMember->noTeamSubcategory=noTeamId;
2744  teamMember->joinTeamType=JOIN_NO_TEAM;
2745  }
2746  PushTeamAssigned(teamMember);
2747 
2748  if (world->GetHost()==world->GetTeamManager()->GetMyGUIDUnified())
2749  {
2750  // Rebalance teams
2751  world->FillRequestedSlots();
2752  world->EnforceTeamBalance(noTeamId);
2753 
2754  // Relay as host
2756  world->BroadcastToParticipants(packet->data, packet->length, packet->guid);
2757  }
2758  }
2759 }
2760 
2761 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2762 
2763 void TeamManager::OnSetMemberLimit(Packet *packet, TM_World *world)
2764 {
2765  BitStream bsIn(packet->data,packet->length,false);
2766  bsIn.IgnoreBytes(2+sizeof(WorldId));
2767  NetworkID teamNetworkId;
2768  bsIn.Read(teamNetworkId);
2769  TeamMemberLimit teamMemberLimit;
2770  NoTeamId noTeamId;
2771  bsIn.Read(teamMemberLimit);
2772  bsIn.Read(noTeamId);
2773 
2774  TM_Team *team = world->GetTeamByNetworkID(teamNetworkId);
2775  if (team)
2776  {
2777  team->teamMemberLimit=teamMemberLimit;
2778 
2779  if (world->GetHost()==world->GetTeamManager()->GetMyGUIDUnified())
2780  {
2781  if (packet->guid==GetMyGUIDUnified())
2782  world->BroadcastToParticipants(packet->data, packet->length, packet->guid);
2783  else
2784  world->BroadcastToParticipants(packet->data, packet->length, UNASSIGNED_RAKNET_GUID);
2785  world->FillRequestedSlots();
2786  world->KickExcessMembers(noTeamId);
2787  }
2788  }
2789 }
2790 
2791 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2792 
2794 {
2795  BitStream bsIn(packet->data,packet->length,false);
2796  bsIn.IgnoreBytes(2+sizeof(WorldId));
2797  NetworkID teamNetworkId;
2798  bsIn.Read(teamNetworkId);
2799  JoinPermissions joinPermissions;
2800  bsIn.Read(joinPermissions);
2801 
2802  TM_Team *team = world->GetTeamByNetworkID(teamNetworkId);
2803  if (team)
2804  {
2805  team->joinPermissions=joinPermissions;
2806 
2807  if (world->GetHost()==world->GetTeamManager()->GetMyGUIDUnified())
2808  {
2809  if (packet->guid==GetMyGUIDUnified())
2810  world->BroadcastToParticipants(packet->data, packet->length, packet->guid);
2811  else
2812  world->BroadcastToParticipants(packet->data, packet->length, UNASSIGNED_RAKNET_GUID);
2813  world->FillRequestedSlots();
2814  }
2815  }
2816 }
2817 
2818 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2819 
2820 void TeamManager::OnSetBalanceTeams(Packet *packet, TM_World *world)
2821 {
2822  BitStream bsIn(packet->data,packet->length,false);
2823  bsIn.IgnoreBytes(2+sizeof(WorldId));
2824  bool balanceTeams=false;
2825  bsIn.Read(balanceTeams);
2826  NoTeamId noTeamId;
2827  bsIn.Read(noTeamId);
2828 
2829  world->balanceTeamsIsActive=balanceTeams;
2830  if (world->GetHost()==world->GetTeamManager()->GetMyGUIDUnified())
2831  {
2832  if (packet->guid==GetMyGUIDUnified())
2833  world->BroadcastToParticipants(packet->data, packet->length, packet->guid);
2834  else
2835  world->BroadcastToParticipants(packet->data, packet->length, UNASSIGNED_RAKNET_GUID);
2836 
2837  if (balanceTeams)
2838  world->EnforceTeamBalance(noTeamId);
2839  else
2840  world->FillRequestedSlots();
2841  }
2842 }
2843 
2844 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2845 
2847 {
2848  BitStream bsIn(packet->data,packet->length,false);
2849  bsIn.IgnoreBytes(2+sizeof(WorldId));
2850  bool balanceTeams=false;
2851  bsIn.Read(balanceTeams);
2852  world->balanceTeamsIsActive=balanceTeams;
2853 }
2854 
2855 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2856 
2857 #endif // _RAKNET_SUPPORT_TeamManager==1
2858