Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
268 lines (223 sloc) 5.99 KB


  • entity sync priority: higher the priority, more frequently synced
  • entity relevance:
    • each sim.Observer has view info, ServerSim manages relevant entities
    • Entity has a check, as entities/observers move checks are re-performed
    • events on Observer: createEntity/updateEntity/deleteEntity

Observer??: view info entities[]: only relevant ones entitiesUpdated[] queueEntitiyUpdate(entity) flush(): // could coalesce create/update/delete, if it mattered build and send SyncEntities packet w/ relevant entities: switch on entity.dirtyFlag (created|updated|deleted)

Scheduler: upcomingEntities: sorted list of scheduled entities / buckets / w/e update(frame)

Simulator: entityTypes{}: ID -> class registerEntityFactory(typeId, type)

ServerSimulator: netService entities[]: all active

createEntity(typeId, opt_temporary)

dirtiedEntities[]: all dirtied
  f.e. dirty entitiy:
    if relevance changed:
      reset observer list
      f.e. observer: check relevance, add to list
    f.e. entity.observers: queueEntityUpdate(e)

registerCommandHandler(typeId, callback, opt_scope)
sendCommand(command, opt_user)

update(frame) + other hooks?
  poll incoming packets/commands/etc
  f.e. observer: flush()

ClientSimulator: netService entities[]: all known


registerCommandHandler(typeId, callback, opt_scope)

update(frame) + other hooks? (prediction/input/etc)

Command: (client/server) typeId read(packetReader) write(packetWriter) MyCommand: impls of read/write - use msg format for packets e.g., kill message

ServerEntity: getState() owner = user parent flags: - updates-frequently: optimized for updating every tick - physics: runs through the physics loop - server-only: never send to clients - transient: server may create on clients, but will never update again - latency-compensated: whether the entity is setup for latency compensation dirtyFlag = bitmask of created | updated | deleted lastUpdateTime_ nextUpdateTime_ (estimated) update(time, timeDelta) prot scheduleUpdate(time) prot notifyDirty(): this.sim.notifyEntityDirty(this) MyServerEntity: state = new MyServerEntityState() // + prediction/rewinding/etc

ClientEntity: getState() parent update(frame) render(frame) MyClientEntity: state = new MyClientEntityState() // + interpolation/prediction

IMyEntity: shared stuff interface MySharedEntity: static methods, act on IMyEntity EntityState: MyEntityState: (manual) getVar() / setVar() MyServerEntityState: (generated) MyClientEntityState: (generated)

Client|ServerEntity: StateEntity: GlobalStateEntity PlayerStateEntity InvetoryEntity EventEntity: AmbientSoundEntity WorldEntity: (pos/vel/etc) PositionalSoundEntity ActorEntity: (has controller) LivingEntity TriggerEntity: ButtonEntity TriggerRegionEntity ParticleEmitterEntity: FireEntity ProjectileEntity: RocketEntity WeaponEntity: RocketLauncherEntity

Command: sequence # sim time generated time delta covered (since last command) target entity id (or -1) havePredicted (true if was predicted already) -- client only

Command: PredictedCommand: PlayerMoveCommand - view rotation (NORMALIZED_QUATERNION) - translation bitmask (byte) - actions bitmask (uint) ChangeSkinCommand

Network packets:

  • SyncSimulation {s->c}
    • varint sequence #, counts for each type
    • creates[]:
      • varint entity id
      • flags:
        • temporary
        • ??
      • [full data]
    • updates[]:
      • varint entity id
      • [delta data]
    • deletes[]:
      • varint entity id
    • commands[]:
      • varint typeId
      • [data]
  • ExecCommands {c->s}
    • varint count
    • commands[]:
      • varint typeId
      • [data]


  • entity
  • ctor: someVarOrdinal_ = declareVariable(setSomeVar)
  • f.e. var:
    • someVar_
    • someVarOrdinal_
    • getSomeVar(): return someVar_
    • setSomeVar(v): if (!eq(someVar_, v)) { set(someVar_, v); flagDirtyVar(someVarOrdinal_); this.entity.invalidate(); }
  • read()
  • readDelta()
  • write()
  • writeDelta() <-- use tables

Entity: state = current state parent

ClientEntity: confirmedState = last confirmed state from the server [client only] previousStates[] = previous states, used for interpolation [client only] renderState = interpolated/predicted state, may point at state if neither enabled



  • position
  • orientation
  • boundingRadius
  • getScene()


  • spatialDatabase_

  • addEntity(e)
  • updateEntity(e)
  • updateEntities(e[])
  • removeEntity(e)
  • forEachChildInViewport(viewport)
  • forEachChildInNear(e | point, maxDistance)
  • forEachChildIntersecting(e | point)
  • forEachChildIntersected(ray, maxDistance)
  • findClosestChild(e | point, maxDistance)
  • trace(ray, start, end)

gf.sim.db.ListDatabase gf.sim.db.QuadtreeDatabase gf.sim.db.OctreeDatabase gf.sim.db.KdTreeDatabase

MapEntity <- SceneEntity

  • custom spatial database


EntityID: add getter for entity, cache this.fooId_ = gf.sim.NO_ENTITY_ID; this.fooEntity_ = undefined; prototype.getFooId = ... prototype.getFooEntity = function() { if (this.fooEntity_ == undefined) { if (fooId_ == NO_ENTITY_ID) { this.fooEntity_ = null; } else { this.fooEntity_ = this.entity.getSimulator().getEntity(fooId_); } } return this.fooEntity_; } prototype.setFooId = function(value) { if (changed) { this.fooEntity = undefined; } }


  • last sequence #
  • time base (uint)
  • commands[]
    • time delta (varint in ms)