PlayerList

Copyright(c) 2012 Stefano Balietti MIT Licensed

Stores a collection of Player objects and offers methods to perform operation on them


(function (exports, node) {

Global scope

  

Setting up global scope variables

var JSUS = node.JSUS,
  NDDB = node.NDDB;

var GameState = node.GameState;

Exposing constructor

exports.PlayerList = PlayerList;

Inheriting from NDDB

PlayerList.prototype = new NDDB();
PlayerList.prototype.constructor = PlayerList;

PlayerList.array2Groups (static)

Transforms an array of array (of players) into an array of PlayerList instances and returns it.

The original array is modified.

Params
array Array The array to transform
Returns
Array array The array of PlayerList objects
PlayerList.array2Groups = function (array) {
  if (!array) return;
  for (var i = 0; i < array.length; i++) {
    array[i] = new PlayerList({}, array[i]);
  };
  return array;
};

PlayerList constructor

Creates an instance of PlayerList.

The instance inherits from NDDB, an contains an internal database for storing the players

Params
options object Optional. Configuration options for the instance
db object Optional. An initial set of players to import
parent PlayerList Optional. A parent object for the instance
API
public
function PlayerList (options, db, parent) {
  options = options || {};
  if (!options.log) options.log = node.log;
  NDDB.call(this, options, db, parent);
  
  this.globalCompare = function (pl1, pl2) {
    
    if (pl1.id === pl2.id) {
      return 0;
    }
    else if (pl1.count < pl2.count) {
      return 1;
    }
    else if (pl1.count > pl2.count) {
      return -1;
    }
    else {
      node.log('Two players with different id have the same count number', 'WARN');
      return 0;
    }
  };
};

PlayerList methods

PlayerList.add

Adds a new player to the database

Before insertion, objects are checked to be valid Player objects.

Params
player Player The player object to add to the database
Returns
Boolean TRUE, if the insertion was successful
PlayerList.prototype.add = function (player) {
  if (!player || !player.sid || !player.id) {
    node.log('Only instance of Player objects can be added to a PlayerList', 'ERR');
    return false;
  }
  if (this.exist(player.id)) {
    node.log('Attempt to add a new player already in the player list: ' + player.id, 'ERR');
    return false;
  }
  
  this.insert(player);
  player.count = player.nddbid;
  
  return true;
};

PlayerList.remove

Removes a player from the database based on its id

If no id is passed, removes all currently selected players

Notice: this operation cannot be undone

Params
id number The id of the player to remove
Returns
Boolean TRUE, if a player is found and removed successfully
@see `PlayerList.pop`
PlayerList.prototype.remove = function (id) {
  if (!id) {

fallback on NDDB.remove

    return NDDB.prototype.remove.call(this);
  }
    
  var p = this.select('id', '=', id);
  if (p.length) {
    p.remove();
    return true;
  }

  node.log('Attempt to remove a non-existing player from the the player list. id: ' + id, 'ERR');
  return false;
};

PlayerList.get

Retrieves a player with a given id and returns it

Displays a warning if more than one player is found with the same id

Params
id number The id of the player to retrieve
Returns
Player Boolean The player with the speficied id, or FALSE if no player was found
@see `PlayerList.pop`  
PlayerList.prototype.get = function (id) {  
  if (!id) return false;
  
  var p = this.select('id', '=', id);
  
  if (p.count() > 0) {
    if (p.count() > 1) {
      node.log('More than one player found with id: ' + id, 'WARN');
      return p.fetch();
    }
    return p.first();
  }
  
  node.log('Attempt to access a non-existing player from the the player list. id: ' + id, 'ERR');
  return false;
};

PlayerList.pop

Retrieves a player with a given id, removes it from the database, and returns it

Displays a warning if more than one player is found with the same id

Params
id number The id of the player to retrieve
Returns
Player Boolean The player with the speficied id, or FALSE if no player was found
@see `PlayerList.remove`
PlayerList.prototype.pop = function (id) {  
  if (!id) return false;
  
  var p = this.get(id);
  
  if ('object' === typeof p) {
    this.remove(id);
    return p;
  }
  
  return false;
};

PlayerLIst.getAllIDs

Fetches all the id of the players in the database and returns them into an array

Returns
Array The array of id of players
PlayerList.prototype.getAllIDs = function () {  
  return this.map(function(o){return o.id;});
};

PlayerList.updatePlayerState

Updates the value of the state object of a player in the database

Params
id number The id of the player to update
state GameState The new value of the state property
Returns
Boolean TRUE, if update is successful
PlayerList.prototype.updatePlayerState = function (id, state) {
  
  if (!this.exist(id)) {
    node.log('Attempt to access a non-existing player from the the player list ' + player.id, 'WARN');
    return false; 
  }
  
  if ('undefined' === typeof state) {
    node.log('Attempt to assign to a player an undefined state', 'WARN');
    return false;
  }
  
  this.select('id', '=', id).first().state = state; 

  return true;
};

PlayerList.exist

Checks whether at least one player with a given player exists

Params
id number The id of the player
Returns
Boolean TRUE, if a player with the specified id was found
PlayerList.prototype.exist = function (id) {
  return (this.select('id', '=', id).count() > 0) ? true : false;
};

PlayerList.isStateDone

Checks whether all players in the database are DONE for the specified GameState.

Params
state GameState Optional. The GameState to check. Defaults state = node.game.state
extended Boolean Optional. If TRUE, also newly connected players are checked. Defaults, FALSE
Returns
Boolean TRUE, if all the players are DONE with the specified GameState
@see `PlayerList.actives`
@see `PlayerList.checkState`
PlayerList.prototype.isStateDone = function (state, extended) {
  
  state = state || node.game.state;
  extended = extended || false;
  
  var result = this.map(function(p){
    var gs = new GameState(p.state);
    

Player is done for his state

    if (p.state.is !== node.is.DONE) {
      return 0;
    }

The state of the player is actually the one we are interested in

    if (GameState.compare(state, p.state, false) !== 0) {
      return 0;
    }
    
    return 1;
  });
  
  var i;
  var sum = 0;
  for (i=0; i<result.length;i++) {
    sum = sum + Number(result[i]);
  }
  
  var total = (extended) ? this.length : this.actives(); 
  return (sum === total) ? true : false;
};

PlayerList.actives

Counts the number of player whose state is different from 0:0:0

Returns
number result The number of player whose state is different from 0:0:0
PlayerList.prototype.actives = function () {
  var result = 0;
  var gs;
  this.each(function(p) {
    gs = new GameState(p.state);  
    if (GameState.compare(gs, new GameState()) !== 0) {
      result++;
    }
  }); 
  return result;
};

PlayerList.checkState

If all the players are DONE with the specfied state, emits a STATEDONE event

Params
state GameState Optional. The GameState to check. Defaults state = node.game.state
extended Boolean Optional. If TRUE, also newly connected players are checked. Defaults, FALSE
@see `PlayerList.actives`
@see `PlayerList.isStateDone`
PlayerList.prototype.checkState = function (state, extended) {
  if (this.isStateDone(state, extended)) {
    node.emit('STATEDONE');
  }
};

PlayerList.toString

Returns a string representation of the state of the PlayerList

Params
eol string Optional. End of line separator between players
Returns
string out The string representation of the state of the PlayerList
PlayerList.prototype.toString = function (eol) {
  
  var out = '';
  var EOL = eol || '\n';
  
  this.forEach(function(p) {
      out += p.id + ': ' + p.name;
      var state = new GameState(p.state);
      out += ': ' + state + EOL;
  });
  return out;
};

PlayerList.getNGroups

Creates N random groups of players

Params
N number The number of groups
Returns
Array Array containing N PlayerList objects
@see `JSUS.getNGroups`
PlayerList.prototype.getNGroups = function (N) {
  if (!N) return;
  var groups = JSUS.getNGroups(this.db, N);
  return PlayerList.array2Groups(groups);
};  

PlayerList.getGroupsSizeN

Creates random groups of N players

Params
N number The number player per group
Returns
Array Array containing N PlayerList objects
@see `JSUS.getGroupsSizeN`
PlayerList.prototype.getGroupsSizeN = function (N) {
  if (!N) return;
  var groups = JSUS.getGroupsSizeN(this.db, N);
  return PlayerList.array2Groups(groups);
};  

PlayerList.getRandom

Returns a set of N random players

Params
N number The number of random players to include in the set. Defaults N = 1
Returns
Player Array A single player object or an array of
PlayerList.prototype.getRandom = function (N) { 
  if (!N) N = 1;
  if (N < 1) {
    node.log('N must be an integer >= 1', 'ERR');
    return false;
  }
  this.shuffle();
  
  if (N == 1) {
    return this.first();
  }
  
  return this.limit(N).fetch();
};

Player Class

A Player object is a wrapper object for a number of properties to associate to a player during the game.

Some of the properties are private and can never be changed after an instance of a Player has been created. Defaults one are:

sid: The Socket.io session id associated to the player id: The nodeGame session id associate to the player count: The id of the player within a PlayerList object

Others properties are public and can be changed during the game.

name: An alphanumeric name associated to the player state: The current state of the player as relative to a game ip: The ip address of the player

All the additional properties in the configuration object passed to the constructor are also created as private and cannot be further modified during the game.

For security reasons, non-default properties cannot be function, and cannot overwrite any previously existing property.


Expose Player constructor

exports.Player = Player;

Player constructor

Creates an instance of Player

Params
pl object The object literal representing the player
function Player (pl) {
  pl = pl || {};
  

Private properties

  

Player.sid

The session id received from the nodeGame server

  var sid = pl.sid;
  if (node.support.defineProperty) {
    Object.defineProperty(this, 'sid', {
      value: sid,
        enumerable: true
    });
  }
  else {
    this.sid = sid;
  }
  

Player.id

The nodeGame session id associate to the player

Usually it is the same as the Socket.io id, but in case of reconnections it can change

  var id = pl.id || sid;
  if (node.support.defineProperty) {
    Object.defineProperty(this, 'id', {
      value: id,
        enumerable: true
    });
  }
  else {
    this.id = id;
  }
  

Player.count

The ordinal position of the player in a PlayerList object

@see PlayerList

  var count = pl.count;
  if (node.support.defineProperty) {
    Object.defineProperty(this, 'count', {
        value: count,
        enumerable: true
    });
  }
  else {
    this.count = count;
  }
  

Player public properties

Player.ip

The ip address of the player

Note: this can change in mobile networks

  this.ip = pl.ip;
 

Player.name

An alphanumeric name associated with the player

  this.name = pl.name;
  

Player.state

Reference to the game-state the player currently is

@see node.game.state @see GameState

  this.state = pl.state || new GameState();

  

Extra properties

Non-default properties are all added as private For security reasons, they cannot be of type function, and they cannot overwrite any previously defined variable

  for (var key in pl) {
    if (pl.hasOwnProperty(key)) {
      if ('function' !== typeof pl[key]) {
        if (!this.hasOwnProperty(key)) {
          this[key] = pl[key];
        }
      }
    }
  }
}

Player methods

Player.toString

Returns a string representation of a player

Returns
string The string representation of a player
Player.prototype.toString = function() {
  return (this.name || '' ) + ' (' + this.id + ') ' + new GameState(this.state);
};
    

Closure

})(
  'undefined' != typeof node ? node : module.exports
  , 'undefined' != typeof node ? node : module.parent.exports
);