GameStream
Get your state from here to there
- Github: https://github.com/spiderworm/gamestream
- NPM: https://www.npmjs.com/package/gamestream
- Demos: https://spiderworm.github.io/gamestream
The goal of this project is to create a library to make it easy to stream state data from your JavaScript server to JavaScript clients, while still giving you full control over the stream.
Should I Use This?
This library is in it's very infancy! Really, I'm less than 100 commits into this thing. It does seem to work, however, and it's making my game dev projects easier, and I think it might help you too!
How Can I Help?
Please provide me with feedback on the following by either opening an issue, or submitting a pull request:
- documentation
- interface, usability
If you like this project, please watch it or star it in GitHub! Thanks!
Installation
The simplest installation is by using npm.
npm install gamestream
Examples
Simplest Scenario
First, create a stream:
var stream1 = ;
Next, set up something to listen to your stream:
stream1;
Put state into your stream:
stream1;
Finally, run your script and see your data outputted to the console.
Piping It
Of course, you probably want something a little more useful than getting your state output to the console. GameStream makes use of the Node pipe pattern. Try this:
var stream1 = ; var stream2 = ;stream2; stream1;stream1;
... and observe how data from stream1 flows into stream2. In some scenarios, it might also be useful to stream three or more GameStreams together, and you can totally do that.
Streaming it to the Client
One of the most common scenarios is syncing state between a game server and clients. You can use the built-in socket pipes for that.
On the server:
// it is recommended to store socketConfig in a module shared by client and server.var socketConfig = host: 'localhost' port: 5000; var serverStream = ;var socketServer = socketConfig;serverStream;
On the client:
// again, it is recommended to store socketConfig in a module shared by client and server.var socketConfig = host: 'localhost' port: 5000; var clientStream = ;clientStream;var clientSocket = socketConfig;clientSocket;
Now as you push data into the serverStream...
var count = 0;;
... the client will automatically receive them! Amazing!
Synchronization
One of the trickier things to deal with in multi-user experiences is to deal with late input. Your server may send out state information to clients but later (after receiving information from a laggy player) need to revise some part of the state. GameStream has a number of features to help with that problem!
Firstly, there's .updateAt(). This method allows you to write updated state information at any time in your timeline: past, present, or future.
var timestamp = 1474149814385; // what time in the past/present/future would you like to change the state at?
myStream.updateAt(timestamp, { newProp: 'newValue' });
Any downstream data receivers will receive the update automatically!
Secondly, you can force a GameStream to output data on a delay. This is useful in cases where you have clients downstream that are experiencing stuttering gameplay when history is rewritten upstream. Just update the lag property on an existing GameStream:
clientStreamlag = 100; // milliseconds. Usually done to the client stream
... or set the lag value when you create your stream: var clientStream = new GameStream({ lag: 100 });
Playback Controls
All instances of GameStream are automatically given the ability to pause, rewind, and fast-forward their data streams.
stream1;stream1; // rewind at double speedstream1; // fast-forward really faststream1;
When combined with piping, playback controls can be useful when you want to set up easy replays on your client.
var clientStream = ;var replayStream = ;clientStream; // set up a handler to pipe the updates into your game { if dataupdate myGame; } // a simple method to toggle between the normal stream and the replay stream { if oldStream oldStream; myGame; // set the initial state newStream;} // when you want to switch control over to the replay:;replayStreamtime = 1474149814385; // timestamp you want the replay to start atreplayStream; // or .rewind(), .fastForward(), etc // when you are ready to switch back over to the main;
Pausing, rewinding, and fast-forwarding states is a non-trivial operation in cases where your game interpolates or extrapolates state (i.e. when using a physics engine). Review the documentation and examples for more detailed help.
Documentation
Class GameStream
Properties
- push (default true) - When false, do not push updates to downstream listeners. Otherwise, do push updates.
- pushInterval (default 0) - When zero, send data to downstream listeners immediately. When non-zero, queue updates and push those on the interval
- lag (default 0) - Push updates to listeners after the specified delay. Pausing, rewinding, and fast-forwarding the stream will nullify the effect of this property.
- state - The current total state that the GameStream knows of at the current playback time (please note, the current playback time may differ from the actual machine time).
- maxStorage (default 1000) - The max number of states you wish the library to store. Please keep in mind that lower values, while less memory intensive, can create issues with replaying state or rewriting history.
Methods
- write(streamData) - Useful for building custom pipes. A required method for NodeJS writeable pipes.
- updateAt(timestamp, data) - Add updated state data at the specified time.
- updateNow(data) - Add updated state data at the current machine time.
- getState() - get the current state.