Skip to content

Instantly share code, notes, and snippets.

@mzgoddard
Created September 18, 2012 21:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mzgoddard/3745965 to your computer and use it in GitHub Desktop.
Save mzgoddard/3745965 to your computer and use it in GitHub Desktop.
GameLoop and Network stubs
// Actions should only store primitive values, when acting it'll look up stuff in a given idSetHash to act on
function Action() {}
// should be false if it shouldn't be cleared from a statebag, example player add / remove actions
Action.prototype.canClear = true
// some deserialized actions may produce a graphics effect, but otherwise their side effects should already be a part of the state?
// flags is an object determining if client, server, or under prediction or lockstep
Action.prototype.act = function( actionList, idSetHash, flags ) {}
// serialize for network transmission
Action.serialize = function( encoder, action ) {
// return argsArray as compressedString
encoder.uintV( action.idOfSomething );
// (random example encoding)
encoder.int( action.x );
encoder.int( action.y );
// return nothing or encoder (network layer will determine how to use data stored in encoder)
}
// deserialize from network data
Action.deserialize = function( decoder ) {
// default to building the action
// return action (which will be added to its actionlist)
return bytesUsed // decoder.used()
}
function ActionList() {}
// act all actions
ActionList.prototype.act = function() {}
ActionList.prototype.clear = function() {}
ActionList.prototype.store = function() {}
// act on actions added since last call to actNew
// useful in GameLoop.internal step where actions are added before the physics step and actions are added after physics step. both groups need to execute to produce secondary actions and have those acted on.
ActionList.prototype.actNew = function() {}
ActionList.serialize = function( encoder, actionlist ) {}
ActionList.deserialize = function( decoder, idSetHash ) {}
// Example
// set the input to use for a future turn
function SetFutureInputAction(){}
function Coder() {
// put these here for easy access in serialize and deserialize methods?
this.flags = {
prediction
lockstep
client
server
};
this.output = {
// output flags, like replay
};
}
function Encoder() {}
Encoder.prototype = Object.create( Coder.prototype )
Encoder.prototype.uintByte
Encoder.prototype.uintShort
Encoder.prototype.uint
Encoder.prototype.uintV
Encoder.prototype.intByte
Encoder.prototype.intShort
Encoder.prototype.int
Encoder.prototype.intV
Encoder.prototype.asciiString
Encoder.prototype.utf8String
// network layer picks
Encoder.prototype.toString = function(){}
Encoder.prototype.toBinary = function(){}
// reusable encoder
Encoder.prototype.clear = function(){}
function Decoder() {}
Decoder.prototype = Object.create( Coder.prototype )
Decoder.prototype.setString = function( data )
Decoder.prototype.setBinary = function( data )
Decoder.prototype.tell
Decoder.prototype.seek
Decoder.prototype.uintByte
Decoder.prototype.uintShort
Decoder.prototype.uint
Decoder.prototype.uintV
Decoder.prototype.intByte
Decoder.prototype.intShort
Decoder.prototype.int
Decoder.prototype.intV
Decoder.prototype.asciiString
Decoder.prototype.utf8String
// availability for different id sets? (stamp(1<<14), user(1<<7), vehicle(1<<7), projectiles(1<<14)) (assume utf8 limit for max?)
// arguments
// - max:
// - loop:
// if false use freeList full of values given by deleteId,
// if true loop when max reached and don't care about delete id?
function IdSet( max, loop ) {}
IdSet.prototype.getId
IdSet.prototype.deleteId
function IdSetHash() {
this.stampIdSet = new IdSet
this.statebags = {} // use stampSet
this.actionlists = {} // use stampSet
this.inputIdSet = new IdSet
this.inputs = {} // statebags containing inputstates
this.userIdSet = new IdSet
this.users = {}
// could be renamed entities
this.vehicleIdSet = new IdSet
this.vehicles = {}
// could be renamed temporaryEntities (tmpEntities)
this.projectileIdSet = new IdSet
this.projectiles = {}
}
function TimeInfo() {
fixedTime = 1 / 60
deltaTime = ( time since last step )
}
function GameLoop() {
idSetHash = new IdSetObject()
timeInfo = new TimeInfo()
emitter = new EventEmitter()
}
/* GameLoop Events */
fixedUpdate( timeInfo, actionlist, idSetHash ) // pre physics step
postFixedUpdate( timeInfo, actionlist, idSetHash ) // post physics step
stash( statebag ) // create states
/* End Events */
GameLoop.prototype.internalStep = function( timeInfo, statebag, actionlist ) {
actions = [];
// perform game logic ( produce actions )
/// act on new actions
// perform physics
// post physics stuff ( produce actions )
/// act on post physics actions
// build actionlist ( with original executed actions, ( actions created by actions don't need to be stored ) )
// build statebag
}
GameLoop.prototype.replay = function( startStamp, endStamp ) {
var stamp = startStamp;
// disable entities until they have been set by a state
this.states[ stamp ].set( ... );
// execute "skipped" inputs ( perform steps of deltaTime = 0 )
stamp = nextStamp();
state = this.stateBags[ stamp ];
actions = this.actionList[ stamp ];
for ( input = nextInput(); input < state.inputId; input = nextInput();
this.internalStep( TimeInfo( 0 ), state, actions );
}
for ( ; stamp < endStamp; ) {
// set input objects
input = nextInput();
input.set();
this.internalStep( timeInfo, state, actions )
stamp = nextStamp()
state = this.stateBags[ stamp ];
state.clear();
actions = this.actionList[ stamp ];
actions.clear();
}
}
GameLoop.prototype.step = function() {
// act on most recent net datas
var statebag, actionlist
network( statebag, actionlist );
// decide how to act on statebag actionlist from network
// create new state
var statebag = new StateBag();
var actionlist = new ActionList();
// record inputs
this.internalStep( timeInfo, statebag, actionlist );
render();
}
function Network( address ) {
}
// subclass some event emitter class
Network.prototype = Object.create( EventEmitter.prototype );
Network.prototype.constructor = Network;
Network.prototype.registerHandler = function( name, serialize, deserialize, context ) {}
// convenience method, maps to registerHandler
Network.prototype.registerSerializable = function( serializable ) {}
// actions is an array of Arrays or Actions
Network.prototype.send = function( actions ) {}
Network.prototype.step = function() {}
// events
Network.on( 'socket:open', function( network, socketInfo ) {
// socketInfo will have have a socketInfo.id managed by network,
// a separate userId should be created
} )
Network.on( 'socket:close', function( network, socketInfo ) {
//
} )
/*
* Usage
*/
// server
var net = new Network( 'game.its.gs/xxxx' ); // bind to address
net.registerHandler( NewPlayerAction.name
net.registerHandler( NewVehicleAction.name, NewVehicleAction.serialize ... );
net.registerHandler( SpawnVehicleAction.name
net.registerHandler( TransformAction.name, TransformAction.serialize, TransformAction.deserialize, TransformAction );
net.registerHandler( InputAction.name,
var vehicleId = net.getId();
net.send( [
[ 'NewPlayerAction', userId, ... ],
[ 'NewVehicleAction', vehicleid, ... ],
[ 'TransformAction', vehicleId, stampFromInput, x, y, angle ] ] );
// client
var net = net Network( 'game.its.gs/xxxx' ); // connect to address
net.registerAction( NewPlayerAction );
net.registerAction( NewVehicleAction );
net.registerAction( SpawnVehicleAction );
net.registerAction( TransformAction );
net.registerAction( VehicleInputAction );
var vehicleId = net.getId();
// respond to actions
// send inputs
net.send( [
[ 'VehicleInputAction', localUserId, localStamp, up, down, left, right, strafeleft, straferight, fire ] ] );
// pick
net.send( [
[ 'VehicleChoiceAction', localUserId, vehicleNum ] ] );
function Serializable(){}
Serializable.serialize = function( encoder, serializable ) {}
Serializable.deserialize = function( decoder ) {}
function StateBag( stamp ) {}
// clear actions previously stored
StateBag.prototype.clear = function() {}
// append actions produced by the last step
StateBag.prototype.store = function( states ) {}
// act all actions
StateBag.prototype.set = function( idSetHash ) {}
// act on any input actions
StateBag.prototype.setInputs = function( idSetHash ) {}
StateBag.serialize = function( encoder, stateBag ) {
// serialize all states in bag
}
StateBag.deserialize = function( decoder ) {
// build statebag
// deserialize states and add to bag
// hook bag in appropriate idSetHash
// return bag
}
// States only contain primitive values
function State() {}
// should be false if it shouldn't be cleared from a statebag, example input
State.prototype.canClear = true
// find the appropriate object stored in idSetHash and set it
// if object is a component of an entity or entity, enable the entity
// flags is an object determining if client, server, or under prediction or lockstep
State.prototype.set = function( idSetHash, flags ) {}
// implement per State subclass
State.serialize = function( encoder, state ) {}
State.deserialize = function( decoder, idSetHash ) {}
// Example
TransformState.deserialize = function( decoder ) {
// build state
// return state
}
InputState.deserialize = function( decoder ) {
userId = decoder.uint()
vehicleId = decoder.uint()
// build state
// copy input map into input queue here? or should statebag do that?
// return state
}
  • InputQueue (list of statebags only containing inputstates?)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment