Jump to content
  • Advertisement
Sign in to follow this  

Object permanence

This topic is 3602 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

Perhaps its a design question more than anything else, but I was curious about your views on this. When a player encounters a thing, information about this thing is transmitted to the player with an associated object ID so that the player can interact with it. The player walks far away, and thus is out of range for receiving updates regarding this object, and then walks back to the object so that they begin receiving updates again. When the player gets back, there are several such objects laying around, including the original object. The server then transmits the information regarding these objects with associated ids, including the id associated with the original object. There is now a link establishable between the object that the player previously encountered and the object they encountered just now. In most instances this doesn't matter, since it is in fact the same object, but in some cases this could be quite relevant. This was originally of concern to me when I was working on my network code some time ago, so I instated a per-connection filter process that maps internal ID's to a session private ID, so that it would be impossible for players to trace objects as they moved about. I found that there were certain things that I would transmit redundantly about things a player encountered, that it would be useful if they could already be assumed to know. On the other hand, I could afford to transmit smaller ID's to players, while maintaining larger ID's internally where bandwidth isn't an issue. Perhaps persistent object ID's could be a good thing though. Player specific information isn't retransmitted about, notes can be taken regarding specific objects that can be player specific, and stored on the client side, and so on. Any points of view?

Share this post


Link to post
Share on other sites
Advertisement
Do you have a question?

ID space compression is a practical way, if you can afford per-client mapping. This usually means that the number of IDs shared is small enough to be managable.

This type of mapping will probably happen already, since database IDs will be different from your logical IDs in memory. It's probably most practical when using 64-bit IDs, which are mapped on client as 16/24-bit ones. The 16-bit version requires about 256k per client, and if that's managable, then you can save some bandwidth. The lookup cost however may become high.

Quote:
I found that there were certain things that I would transmit redundantly about things


Yes, this can happen. One way to solve this is to give client deterministic caching behavior.

When you transmit ObjectDelete(id) to client, you know how long they will keep the old data around. If you need to resend them the same entity, instead of sending everything, you just send CacheRemapped(oldid, newid), and then the delta state.

Problem with this is simply in that you must know what the client's latest state is (before it got marked for deletion), meaning that you gain nothing by deleting object on client, so you might as well just resend full state.

Another way is to assign fixed size to client's cache (for example 2^16 entities), and use LRU removal. This can be done without any additional transmission, if the cache is deterministic.

Share this post


Link to post
Share on other sites
It was a question about design, rather than a technical question. The big over arching question is whether or not a client should have persistent knowledge of the world objects, which becomes possible if you allow the client to have object id's that are used internally, so long as these id's are never reassigned. A question of whether or not a client should be allowed to have a long term memory regarding game state. There are pros and cons to either method, though either one is technically sound. The reason I went with the ID scheme I did was to remove the possibility of a client tracking objects in the long term, such as discovering a player wearing a disguise, or allowing for the tracking of other characters' inventory. Each time a player encounters an object, that player sees it with a new ID, and thus cannot imply any relationship between this object and previously seen objects.

I was intending to start a discussion about allowance for a client to maintain information about world persistence, vs a client only having knowledge of what is immediately relevant. So how about this, to put it in the form of a question.

In a multiplayer game featuring a world with some sort of persistence, should this persistence be exposed to the client as well, or should the client have a more immediate view of the game.

Share this post


Link to post
Share on other sites
Quote:
Original post by Drigovas

In a multiplayer game featuring a world with some sort of persistence, should this persistence be exposed to the client as well, or should the client have a more immediate view of the game.


Knowledge of your database? Of course not.

As for client, it needs to have exactly the same view of the game as server. No more, no less.

If you find yourself with some static data, then feel free to pre-load this on client. Changing this data however requires server restart and patch download on each client.

One way to achieve that, is to separate your IDs into regions. For example, if you're using ints as IDs, let positive values be dynamic objects, and negative values the static content. Static content is pre-loaded via patch.

Share this post


Link to post
Share on other sites
In general, you can store the mapped ID on a per-session basis. When first introducing a new ID for the session, send a mapping "client 16-bit ID == server 128-bit GUID" (or whatever). Then, each time after that you need to send the same ID, send just the 16-bit ID.

You can do the same thing for strings. The first time you send a string, send an ID and the string. If you ever need to send the string again, send only the ID. Great for things like user-customizable objects where different textures can be swapped out, and are referenced by name, for example.

In general, any kind of large-ish data that remains reasonable consistent and re-used can be treated this way. It's almost like a manual form of LZ77 compression with very long memory :-)

Share this post


Link to post
Share on other sites
For dynamic objects:
I dont see why you would hide the id.. In most network games users have a "nick" anyway, that will give them away.

In our games the ids are two uint32's, one is instance and other is type.
(type is needed for object factory and instance is actual id)

If you really need to hide the id, introducing a per client translation table for ids on server end would do the work.

And here i am assuming that once an object goes out of view scope it is deleted on the client, and next time it comes into scope it will be reconstructed from scratch. (caching resources (audio, textures, etc) associated with the object is propably a good idea)

Ie.
Object enters vicinity : servers sends full update
Object is doing stuff in vicinity: server sends update
Object leaves vicinity: server sends remove

Static objects:
When the server isnt really controlling them, should be handled by client only. (trees, buildings, signs, etc)

I'm not sure i answered any of your questions though ;)

Share this post


Link to post
Share on other sites
Quote:
Original post by hplus0603

In general, any kind of large-ish data that remains reasonable consistent and re-used can be treated this way. It's almost like a manual form of LZ77 compression with very long memory :-)


One interesting variation of this, if serialization is performed within context of client's connection, is to use adaptive huffman coding for such values. Or arithmetic compression, for that matter.

As long as peers are kept in sync for this purpose (unreliable messages simply don't use this scheme), one gets "free" optimal encoding, regardless of internal ID length. Free in respect that it doesn't take manual mapping of code/value pairs, but they are kept as implicitly in huffman tree.

A side effect of this is security through obscurity, since packet contents on wire will vary unpredictably. While not cryptographically secure, the decoding can no longer be performed without context, which requires perfect replication of de/encoder.

From design perspective, this encoding can be nicely and transparently incorporated into serialization schemes which have ability to output to bit streams. Each connection merely maintains huffman tree for each separate data type.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!