Skip to content

Instantly share code, notes, and snippets.

@tmpvar
Created May 28, 2011 00:31
Show Gist options
  • Save tmpvar/996454 to your computer and use it in GitHub Desktop.
Save tmpvar/996454 to your computer and use it in GitHub Desktop.
/*
TODO: allow for interpolation!
Requirements:
* local pendingPatches
* tick interval
* send queue to server
* concat queue to transmittedPatches
* revert function([patch, patch])
* apply function([patch, patch])
* handle method function([patch, patch, patch])
* calls revert on pendingPatches
* calls revert on appliedPatches
* calls apply([patch, patch, patch])
* calls apply(appliedPatches)
* calls apply(pendingPatches)
var handle = client(10,
function revert(patches, fn) {
// defines how to revert a group of patches
// It is completely feasable to need to do some
// async work while reverting, which is why the
// callback exists.
// it is also feasable that some patches may not revert
// successfully (although, probably rare).
// Arguments:
// 1. patches to drop [array]
// 2. patches to keep [array]
fn([],[]);
},
function compare(patch, patch) {
// or false, depending on whether the patches are the same object
// This should not be an identity comparison as these will most
// likely contain a mix origins (server, user input)
return true;
},
function apply(patches, fn) {
// defines how to apply a group of patches
// the callback takes 2 arrays
// Arguments
// 1. patches that failed to apply [array]
// 2. patches that were applied successfully [array]
fn([], patches);
},
function emit(patches) {
// this method is used to get the queue of
// input patches that the client has to the
// server
socket.io.send(patches);
}
});
handle.local(patches);
handle.remote(patches);
*/
function client(rate, revert, apply, compare, emit) {
var
pendingPatches = [],
transmittedPatches =[];
comparator = comparator || function() { return true; };
setInterval(function tick() {
transmittedPatches = transmittedPatches.concat(pendingPatches);
emit(pendingPatches.splice(0));
}, rate);
return {
local : function(patch) {
transmittedPatches.push(patch);
},
remote : function(patches) {
var localPatches = transmittedPatches.concat(pendingPatches);
// take us back to a saner time
revert(localPatches, function(drop, keep) {
var patchesToApply = patches.concat(keep);
apply(patchesToApply, function(dropped, kept) {
var patchesToRemove = dropped.concat(dropped, patches);
transmittedPatches = transmittedPatches.filter(compare);
pendingPatches = pendingPatches.filter(compare);
});
});
}
};
}
var data = {};
var handle = server(10,
function validate(commands, fn) {
// For simplicity's sake, always return true
fn([], commands);
},
function apply(fn) {
return function(rejected, accepted) {
// last chance to resolve rejected patches
// and apply patches to data
// the final array of patches that will be sent
// to the client
fn(accepted);
}
},
function packet(tick, deltas) {
// send the deltas to the client.
// this would be a good time to merge as many patches
// as possible to speed up transport (save bandwidth)
socket.io.broadcast({
tick : tick,
deltas : delta
});
}
);
socket.io.on('message', function(msg) { handle(msg); });
function server(rate, validate, apply, callback, patches, tick, obj) {
tick = 0;
patches = [];
setInterval(function() {
tick++;
// splice does exactly what we need here
// reset the current snapshots to []
// and return a copy.
// push the collected patches out
callback(tick, patches.splice(0));
}, rate);
// Provide a way to pump new diffs into the system
return function(diffs) {
validate(diffs, apply(function(accepted) {
// merge the latest changeset with the
// existing
patches.concat(accepted);
}));
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment