Sign in to follow this  
  • entries
    45
  • comments
    48
  • views
    51634

Back in the swing

Sign in to follow this  
hplus0603

254 views

I've spent a few hours to get back in the swing of things, and it's paid off pretty well.

I defined packets for creating and removing objects on the client machine, and for updating properties of those objects. Here, the object system I designed a few months ago really helps, because public properties all have known types (long, double, quaternion, string, object reference, etc), and objects are all created from a known template.

Thus, the packets I need are:

- create object
- template name
- object id
- start object
- object id
- remove object
- object id
- update property of type X
- object id
- component index
- property index
- property value


Because all objects are created from the same templates, the component index, and the property index within the components, will be the same, which simplifies addressing. I assume I won't have more than 255 components per object, or more than 255 properties per component, so I use a byte for each.

The "start object" message is there to make sure that I don't start an object that's half configured. The way object start-up actually works is:

Server:
1. Send object creation, including object template.
2. For each component.
2.1 For each property.
2.1.1 If the property differs from the template.
2.1.1.1 Send a property update.
2.1.2 Subscribe to property updates for future sends.
3. Send object start.


When a property updates after being started, a dirty flag is set, and when time comes to update object state, dirty properties are queued for sending. I prioritize property updates such that closer objects get higher priority. I also use a send queue with replacement capability, so if property X updates while it's already queued, I replace that piece of data in the queue with the newer data. This means I can also remove pending updates for objects as those objects are being removed -- no need sending network updates for things that die.

The neat thing is: Pretty much all of this code used infrastructure I already had written for the editor and composable object model!

I haven't debugged it yet, but looking at the code, it's quite simple. There are, however, some inefficiencies that I might want to address later (if profiling shows I need to):

  • The code that determines whether a property has changed from the template or not is inefficient. This affects CPU cost when starting up a new object, or when a new player connects. Bad N-squared cost.

  • Each player connection subscribes to all properties of all objects. This causes lots of allocations (one per subscription). A system of generation/change counts would probably be more efficient, to the point where each player connection stores the latest generation seen, and each property stores the latest generation updated.

  • Each updated property is prefixed with the object id. Some bytes could possibly be saved by grouping updates per object, then per component. This is mainly a network usage issue, and I think it'll be OK as is.

  • Properties are sent as generic pieces of data -- "a double" or "an int". If I had more information about the properties, I could marshal using less network data -- say, compressing floats to a byte when I know they are in the range [0..1] with precision 0.01.



Despite this, I'm pretty psyched! This part really looks straightforward, once all the infrastructure was there (components, properties, subscriptions, etc). Now I need to define some more interesting object kinds than "rock" -- like, for example, "player" :-)
Sign in to follow this  


0 Comments


Recommended Comments

There are no comments to display.

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