Sign in to follow this  

Players and visibility

This topic is 4374 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm currently pseudo coding the portion of my network code that will hide/show players as they move into the current player's range of visibility. I'm halfway where I need to be :) When a player (VisiblePlayer) moves into the range of visibility (CurrentPlayer): -Server sends CurrentClient a packet describing a position for a VisiblePlayer. -Client establishes that the VisiblePlayer is not in the current list of visible players. -Client then sends back asking for full details of the VisiblePlayer, so it can be drawn on the screen -Server determines of the requested details are allowed to be shown on the screen (to prevent hacks and spoofing of requests) -Server then sends back, if allowed, the details of the VisiblePlayer -Client draws VisiblePlayer at updatedlocation On the other hand, when VisiblePlayer walks outside of the visibility range of CurrentPlayer, how do you tell the Client to drop the player off its visible players list? One thought I had was to have a "LastUpdated" timer. If an update wasn't received within XX seconds, then the Client would remove the VisiblePlayer. This would require a "heartbeat" type function though, I believe. IE, what if a player goes AFK..they should just stand there, not go poof. Thanks in advance :) Edit: If this is in the wrong place, please move to where applicable :D Thx!

Share this post


Link to post
Share on other sites
what type of game is this? 2d or 3d??

it's been a while, but IIRC, the way I handled this in my 2D mini MMORPG it is this:

-player requests to move
-server verifies
-server checks ALL players on the SAME MAP to see who is in the range of the player, and forwards the movement to only the people within that range


if you need "full details" on how the player should be rendered, then when the player first enters the map, send everyone on the map these details. you could even get more in-depth and keep "version numbers", so when people left the map, and came back, the server checks to see if the visible players have the same "version" of what that player looks like, and only sends the data to people with "older versions".

of course i'm assuming you are making a game that would fit to this protocol. you have to give more information [grin].

Share this post


Link to post
Share on other sites
Sorry...

This is a 3d game, aiming for MMORPG.

I dont' want to send any player data unless the player is absolutely visible to the person requesting (snuffs out radar hacks and the likes).


Edit: And I'm pretty sure I can handles the "enters visible range" events, but I'm not sure about the "exit visible range" events.

Share this post


Link to post
Share on other sites
Quote:
Original post by Siberwulf
On the other hand, when VisiblePlayer walks outside of the visibility range of CurrentPlayer, how do you tell the Client to drop the player off its visible players list?


Ok... I think I fully understand your problem now... and I don't think my last reply was too helpfull [grin].

OK, I have solved this EXACT problem in my game before, but it's been so long... I believe it worked something like this:

- on the server, each player has a list of what players are visible to him. he builds this for each player when they first enter the map.
- client requests to move
- server loops through each player on the map...is this player close enough? if so, make sure he is on that players list...if not, add him to that list. is the player NOT close enough? if so, remove him from the list
- server forwards movement message to all players on the list. he then forwards to all players who were removed, telling them he is no longer visible. this should only have to be a singly byte (EDIT: you said MMMORPG, so 2 bytes probably), minus headers and stuff.

hope that helps.


Share this post


Link to post
Share on other sites
step 3/4 should look like this in pseudo-code:


case REQUEST_MOVEMENT:

P1 = this player who's requesting movement

for each player (NOT P1) P2 on this map
if(P2.IsVisible(P1))
P2.AddToList(P1)
P1.AddToList(P2)
else
P2.RemoveFromList(P1)
P1.RemoveFromList(P2)


You can assume that the AddToList() and RemoveFromList() functions will check if they were actually added / removed, and if so send the apprioriate packet.

Share this post


Link to post
Share on other sites
Quote:
Original post by Siberwulf
Sorry...

This is a 3d game, aiming for MMORPG.

I dont' want to send any player data unless the player is absolutely visible to the person requesting (snuffs out radar hacks and the likes).


Edit: And I'm pretty sure I can handles the "enters visible range" events, but I'm not sure about the "exit visible range" events.


This post confused me. In the original post you made, your logic prevents the client from getting movement packets unless the player is in range, therefore they can't have radar hacks and stuff.

Really the only reason to send a "player is no longer visible" to the client would be for rendering, not security purposes. It is for the situation where player A left player B's range, and stops getting movement packets.... then player B has player A's OLD position, and if he runs into that position, player A will be rendered there, in a frozen type state. (even though he's somewhere completely different, probably moving around)...... although I'm sure you know this already, I just had to remember it for myself [grin]. In this case my logic should handle this.

Share this post


Link to post
Share on other sites
I've been stewing on this...

I really don't want the client to rely on the server to remove a player from the render/visibilty list. Yes, I know the hardfast rule that server > client, but i think as far as overhead goes, it might be more prudent to do something like this:

Each player has a heartbeat function. If they haven't sent a movement command in XX seconds, the heartbeat kicks in, like a keep alive. It broadcasts "I'm alive" for all players in visible range. If a client hasn't gotten a heartbeat from a player that is in visible range, its safe to say that player either went link dead, disconnected, or exited the visible range.

Whats your thoughts?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by Siberwulf
Each player has a heartbeat function. If they haven't sent a movement command in XX seconds, the heartbeat kicks in, like a keep alive. It broadcasts "I'm alive" for all players in visible range. If a client hasn't gotten a heartbeat from a player that is in visible range, its safe to say that player either went link dead, disconnected, or exited the visible range.
Whats your thoughts?


This solution is based on timing. In case of lag, it's perfectly possible that the client won't get any updates for some time, and every other player will disappear (because they time out). It's true that they reappear once the next update gets through, but it's not pretty or clean.

A simple way is to have a list on the server, and have the server check the list and update it. Then calculate the difference with the last list sent to the client and only send what changed. This way you could send a 'remove client' event in case a client moves or disconnects, or you could send a 'client keepalive' event in case you want to use timeouts. When large crowds are standing, like on a marketplace, the keepalive (or zero movement) vs. remove client balance will move towards using remove events.

Viktor

Share this post


Link to post
Share on other sites
I see what you're saying, and I agree.

But, isn't that a whole lot of overhead? You have to pull a list of visible players, and save it. Next time through, you have to pull the list and compare it to the old list (seems like the bulk of nastiness is that step). Then you can finally send additions/removals to clients. Rinse and repeat for every player connected... Seems it would be ugly to do it that way, but I am seeing flaws in my own idea.

Share this post


Link to post
Share on other sites
This is, more or less, how we do it:

For each player, keep a list of other visible players, sorted by player ID.

Once every 5 seconds or so, build a new list by traversing your quadtree of player locations. Compare this list (again sorted by player ID) to the old list, and enqueue visibility/invisibility messages based on the differences. Because the lists are both sorted, this can be done in O(visible players) time.

You can even make the number of seconds between visibility events be (1 + #players / 10) or something like that so that your server will scale more gracefully under load. You can also increase the time between visibility checks if you want lots of players on the server, and think that searching the quadtree (or hash grid) of players will take a lot of CPU -- the number of seconds that will work fine is mostly a function of how far away you want to see players pop in at the latest compared to nominal, and how fast players can move.

However, our rule is that you get the closest N players (modified by distance) rather than all players within M meters. The thinking is that, with a bandwidth budget of X per player, X*N is our channel size, and we manage the (narrow) channel quite closely.

Share this post


Link to post
Share on other sites
Hrm, I'll have to investigate this quadtree you speak of. Right now, for ease of use and quick implementation, I have everyone stored as a "Player" object in an arraylist. Methinks thats a bad idea.

Thanks for the post :)

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
If you want to stick with your basic array right now you could maintain a list of information about visible players in the server's player structures.

for example, a list of structures such as:

struct visibility_struct
{
int player_handle;
bool is_dirty;
}

When a server does it's proximity check for each player:

1. It sets all of the is_dirty bits to true.
2. It searches for all players that are in range
3. If it finds a player in range, it checks to see if a visibility_struct exists for that player in the list.
4. If the player's visivility_struct exists in the list, set it's is_dirty flag to false, else, add a new visibility structure (with the is_dirty bit set to false) and send a player visible message to the client.
5. repeat steps 3 - 4 until no more players are found.
6. remove from the list any structures that have an is_dirty flag set to true, and send a message to the client informing him to stop displaying that player.

This way will use more memory on the server than maintaining 2 octrees, but will use less cpu as it does not have to cast a volume through the octree twice a frame.

a maximum memory usage of:
(sizeof(int) + sizeof(bool) + sizeof(visibility_struct*)) * (playercount*playercount)

Will grow exponentially. If you have 100 players within range of each other, the tables will take up a total of 90k of memory, but if you have 1000 players in range of each other, it will take up a total of 9 megs of memory. Rarely will you have this many players within range of each other, so the memory impact may be minimal.. it all depends on whether your game would be CPU bound or memory bound.

Share this post


Link to post
Share on other sites

This topic is 4374 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this