hey everyone,
thanks for the replies.
@hplus
thanks, this is what i was looking for. about the first part of your post, what do you think about
boost multi index containers ?. it seems like boost has solved this problem for us. it also claims to be faster (and obviously easier) then any method we would code ourselves. this way we dont have to manage multiple containers. we simply have a single, multi index container. effectively giving us a std::map which we can do lookups using multiple keys (lookup using name,id,whatever..).
now, on to the other problem. so, you think its worth implementing a grouping system then? i actually started designing almost exactly what you describe before i read your post. i guess great minds think alike [grin]. theres a few things that i dont understand what your saying though..
step 3 and 5 both confused me. what do you mean by "the player is inserted into a "chain of packets""? also, what do you mean by "you iterate all the maps, and for each map, bake the pending messages into a single packet; then, for each player in that map, send the packet to that player. Then clear the pending messages for that map."
im confused by this. however this is what i planned.
when the player enters the game:
//grab the map hes onMap ↦ = map_manager.Get_Map(map_id);//add him to this mapmap.Add_Player(player_id);-- build a packet here called op --//tell everyone on this map about this playermap.Broadcast_Packet(op);std::map<PlayerID,Player> &tmp = map.Get_Players();-- send the new player all of these player's data --
now, when a player sends an "im moving" packet:
//Get_Map() also works with player IDs!!!Map &tmp = map_manager.Get_Map(player_id);tmp.Broadcast_Packet(packet);
it seems like a pretty slick solution to me. a few notes
-the Map class has a std::map<PlayerID,boost::weak pointer to Player> as a member. this represents all plakyers on his map. i will use boost:: weak pointers for this. the maps are not responsible for deleting the memory associated with these Players.
-besides this, we need a "global list of all players in game". this will be a std::map<PlayerID,boost:: shared pointer>. however, im actually most likely going to make this a boost multi index container. it uses shared pointers since this std::map will own the pointers.
(i have never used shared or weak pointers before, but they seem appropriate for this situation, im thinking otherwise i will have to find which Map the Player is in when removing Player's from the global list otherwise, which could be a hassle / slow. i would prefer not to use the boost pointers here just for familiarity reasons though, so if it sounds like its a waste, let me know..)
the last issue is this. i try to keep all of my protocol level code hidden from the rest of the server. that is, my Player will never call server.Send(position info). instead, he will call server.Send_Position_Info(). i do this just in case i ever switch networking API's, i dont have to go to a million different places and change the code, also it helps encapsulate things.
so, the problem is with Map::Broadcast_Packet(). for example, look at the first code i pasted. this code would be inside the Network_Server:: code. so in my Network_Server::Update() (or Proccess_Message(), or whatever), it looks like this:
Map ∓ = Get_Map();mp.Broadcast_Packet()
i call Broadcast_Packet() from my server code, and then my Map::Broadcast_Packet() will in turn call something like Network_Server::Send_Some_Specific_Data(). its kind of ugly, how we are just bouncing data back and fourth like that. however im not sure of any other way to do it....
thanks a lot for anymore help!
EDIT: lightbulb. perhaps the solution to the problem of the server and map code "bouncing back and forth" is simple. instead of having a Map::Broadcast_Packet() function, i simply have a Map::Get_Player_ID_List() function, which returned all the PlayerIDs on the map. then the server code could just loop through all these playerID's and send the packet to that player ID. i could even just give the server code a Broadcast_To_PlayerID_List() function. so instead of
map.Broadcast_Packet();
it looks like:
Broadcast_To(map.Get_PlayerID_List());
EDIT PART 2:
after thinking about it more, now i think i will not use boost shared or weak pointers. instead, when a player exits the game and therefore leaves the "master list", i find what map he is in and remove him from that maps list as well. so, when a player quits the game, it looks like this:
case MSGID_PLAYER_QUIT:{ //or just combine these 2 into a Remove_Player_From_World()..... Remove_From_Global_List(packet->playerID); map_manager.Remove_Player_From_Map(packet->playerID);}//where Remove Player From Map looks like this:Map_Manager::Remove_Player_From_Map(const PlayerID &player_id){ Map &tmp = Get_Map(player_id); tmp.Remove_Player(player_id);}Map &Get_Map(PlayerID player_id){ std::map<PlayerID,Player>::iterator it = players_in_world.find(player_id); //call the Get_Map() function which takes a map ID return Get_Map(it->second.Get_Map());}
also, the last thing i want to get your comment on is storing the Players in the master list. at first i thought i would use pointers for both list's (and i see in your step 1 and 4 you have the same idea). then i thought this might be a waste. why bother call new myself if im not using any polymorphism? instead, the "global list" (the one containing ALL players in the game) will be a std::map<PlayerID,Player>. it will hold actual Player instances. the list that each Map will have will be a std::map<PlayerID,Player*>. it will point to valid instances of Player contained in the global list.
so, watcha think? [smile].
[Edited by - graveyard filla on December 23, 2004 1:03:07 PM]