-
Notifications
You must be signed in to change notification settings - Fork 18
Data Exchange Examples v7
- status: complete
- version: 7.x
- follows from: Step Callbacks Functions
There are 4 main functions to send data:
Command | Description | Recipient code required |
---|---|---|
node.say | sends data to other clients or server | yes, must implement node.on.data event listener |
node.set | sends data to server | no, automatically inserted in node.game.memory database |
node.done | terminates current step, and calls node.set | see node.set
|
node.get | invokes a remote function, and waits for return value | yes, must implement node.on event listener |
and two functions to handle receiving data:
Command | Description |
---|---|
node.on | catches internal events, including those generated by incoming messages, as well as requests from node.get
|
node.on.data | catches node.say and node.set incoming messages with a given label |
To learn how to exchange data, let us assume the following use case:
- a player makes a decision by typing a numeric value into an input form,
- the value is validated and sent to the server,
- the server manipulates the value and stores it to compute the final payoff of the player,
- the server sends the final payoffs to all players.
Note! As explained in the client types page, the client-side
code goes in file player.js
, and the server-side code goes in file logic.js
.
Client-Side (player.js).
- Get the input from user, validate it, and show error if not valid.
// Assuming a user typed a numeric value into an input form.
var value = W.getElementById('myFormId').value;
// Parse the input and validate its range, say 0-10.
var parsedValue = JSUS.isInt(value, 0, 10); // See also JSUS.isNumber.
if (false === parsedValue) {
alert('Invalid value: ' + value);
return;
}
- Send the validated input to the server using
node.say
.
// Send the value to the server.
node.say('USER_INPUT', 'SERVER', parsedValue);
node.say
takes the following input parameters:
- a label (
USER_INPUT
), - a recipient (
SERVER
), - an optional data value (
parsedValue
).
Server-Side (logic.js).
- Declare an event-listener on incoming messages with label "USER_INPUT"; the listener manipulates the incoming data and saves it into the channel's registry.
function storeData(msg) {
var parsedValue = msg.data;
// Important! Re-validate the incoming data if sensitive (for example,
// it is used to compute payoffs).
// Manipulate the input (e.g. exchange from input to a monetary value).
parsedValue *= 1.5;
// Store the value in the registry under the ID of the player (msg.from).
var userData = channel.registry.getClient(msg.from);
// Update/create the win variable.
userData.win = userData.win ? (userData.win + parsedValue) : parsedValue;
}
node.on.data('USER_INPUT', storeData);
- At the end of the game, all connected players are notified of their total winnings.
// Loop through all connected players.
node.game.pl.each(function(player) {
// Get the value saved in the registry and send it.
var cumulativeWin = channel.registry.getClient(player.id).win;
node.say('WIN', player.id, cumulativeWin);
});
Client-Side (player.js).
- Display the total amount won by the user.
// Listen to the WIN message.
node.on.data('WIN', function(msg) {
// Write inside the element with ID 'win' the amount of money won.
W.setInnerHTML('win', 'You won: ' + msg.data);
});
If a player takes multiple decisions within the same step (e.g., in a real-time
game), node.set
can be used to record each of these.
Replace step 2. of Example 1. with:
node.set({ USER_INPUT: value});
node.set
takes the following input parameters:
- the value to set, it can be an object or a string; if a string, it will be
transformed into an object containing a key with the name of the string set to
true (
{ USER_INPUT: value}
), - the recipient (default
SERVER
), - (Optional) The text property of the message (if set, you can define
node.on.data
listeners).
Example including optional input parameters:
node.set({ USER_INPUT: value}, 'SERVER', 'decision');
Important! The content of each set message is added to the database, there is no check for duplicates.
If there are no more actions to be taken in a step, the step is over and the game should advance.
The end-of-step command is node.done
, and it can also be used to send data to server (as in node.set
).
Compared to Example 1., sending data with node.done
has the advantage of automatically storing the data in the memory database
with timestamps and duration; moreover, it makes it easier to save all results
at the end of the game (see point 6 below).
Client-Side (player.js).
Replace step 2. of Example 1. with:
node.done({ USER_INPUT: value});
node.done
takes one input parameter, which is sent to the server with a call to node.set
.
Server-Side (logic.js).
To listen to items inserted in the memory database, one can implement the 'insert' listener. For instance, the following code can replace step 3. of Example 1:
node.game.memory.on('insert', function(item) {
if ('string' === typeof item.USER_INPUT) {
// Save data to registry, the same as in Example 1.
storeData({ data: item.USER_INPUT });
}
});
- Saves all results in the
data/
folder of the game.
node.game.memory.save('myresults.json');
To invoke a specific function on a remote client and to asynchronously receive
back the results of the call, use node.get
. The example below executes
server-side validation of the input value.
Client-Side (player.js).
var parsedValue = 1234; // Some user-defined value.
node.get('validateInput', function(data) {
// If server validates input call node.done().
if (data.valid) {
node.done({ USER_INPUT: parsedValue });
}
},
'SERVER',
{
data: parsedValue
});
node.get
gets the following input parameters:
- The label of the GET message ('validateInput'),
- The callback function that handles the return message,
- (Optional) The recipient of the msg (default: 'SERVER'),
- (Optional) An object with extra options:
- timeout: The number of milliseconds after which the return listener will be removed,
- timeoutCb: A callback function to call on timeout (no reply received),
- executeOnce: TRUE if listener should be removed after one execution,
- data: The data field of the GET msg,
- target Override the default DATA target of the GET msg.
Server-Side (logic.js).
node.on('get.validateInput', function(msg) {
// Validate data.
var valid = true;
if (!J.isInt(msg.data)) valid = false;
return { valid : valid };
});
Note: the server must implement a synchronous reply to the incoming GET message.
Messages can be exchanged at any point in the game, but ideally inside the step-callback functions to avoid timing issues with event listeners registered in the same step. For instance:
- This should be avoided:
// Logic.js
stager.extendStep('step1', {
init: function() {
node.say('Hello!', 'PLAYER_ID');
},
// ...
});
// Player.js
stager.extendStep('step1', {
cb: function() {
node.on.data('Hello!', function(msg) {
// This listener might be registered after the message arrives.
});
},
// ...
});
- This is acceptable, because the
Hello!
msg is sent in the step callback.
// Logic.js
stager.extendStep('step1', {
cb: function() {
node.say('Hello!', 'PLAYER_ID');
},
// ...
});
// Player.js
stager.extendStep('step1', {
cb: function() {
node.on.data('Hello!', function(msg) {
// This listener is registered on time.
});
},
// ...
});
- This is also acceptable, because the
Hello!
listener is already registered beforestep1
.
// Logic.js
stager.extendStep('step1', {
init: function() {
node.say('Hello!', 'PLAYER_ID');
},
// ...
});
// Player.js
stager.setOnInit(function() {
node.on.data('Hello!', function(msg) {
// This listener is registered for the entire game.
});
});
Go back to the wiki Home.
Copyright (C) 2021 Stefano Balietti
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.