colonizers/colonizers

View on GitHub
packages/colonizers/server/schema/room.js

Summary

Maintainability
A
2 hrs
Test Coverage
'use strict';

var mongoose = require('mongoose');
var GameContext = require('colonizers-core/lib/game-context');
var Schema = mongoose.Schema;

var UserId = {
  type: Schema.Types.ObjectId,
  ref: 'User'
};

var MembershipSchema = new Schema({
  user: UserId,
  date: { type: Date, default: Date.now }
});

MembershipSchema.virtual('id').get(function() {
  return this._id.toString();
});

MembershipSchema.methods.toJSON = function() {
  return {
    id: this.id,
    user: this.user,
    date: this.date
  };
};

var RoomSchema = new Schema({
  created: { type: Date, default: Date.now },
  owner: UserId,
  status: {
    type: String,
    default: 'open',
    enum: ['open', 'started', 'finished']
  },
  users: [MembershipSchema],
  numPlayers: Number,
  game: {
    type: Schema.Types.Mixed,
    default: null
  },
  gameOptions: Schema.Types.Mixed
});

RoomSchema.virtual('id').get(function() {
  return this._id.toString();
});

RoomSchema.methods.toJSON = function() {
  return {
    id: this.id,
    owner: this.owner,
    users: this.users,
    numPlayers: this.numPlayers,
    gameOptions: this.gameOptions
  };
};

RoomSchema.methods.join = function(userId, cb) {
  if (userId === 'string') {
    userId = new mongoose.Types.ObjectId(userId);
  }

  var member = this.users.find(x => x.user.equals(userId));

  if (member) {
    return cb(null, member);
  }

  member = {
    user: userId,
    date: Date.now()
  };

  this.users.push(member);

  this.save(
    function(err) {
      if (err) {
        return cb(err);
      }

      var result = this.users.find(x => x.user.equals(userId));

      cb(null, result);
    }.bind(this)
  );
};

RoomSchema.methods.leave = function(userId, cb) {
  var member = this.users.find(x => x.user.equals(userId));

  if (!member) {
    return cb();
  }

  if (this.status !== 'open') {
    return cb('Game has already started.');
  }

  this.users.pull({ _id: member._id });

  this.save(function(err) {
    if (err) {
      return cb(err);
    }

    cb(err, member);
  });
};

RoomSchema.methods.preEvent = function(event, data, next) {
  var GameEvent = mongoose.model('GameEvent');

  GameEvent.create(
    {
      room: this._id,
      event: event,
      data: data
    },
    next
  );
};

RoomSchema.methods.postEvent = function(event, data, next) {
  this.game = this.gameContext.getState();
  this.save(next);
};

RoomSchema.methods.start = function(callback) {
  if (this.status !== 'open') {
    return;
  }

  if (this.users.length !== this.numPlayers) {
    return;
  }

  this.status = 'started';

  var options = {
    gameOptions: this.gameOptions,
    preEvent: this.preEvent.bind(this),
    postEvent: this.postEvent.bind(this),
    players: this.users.map(member => ({
      id: member.user.toString()
    }))
  };

  this.gameContext = GameContext.fromScenario(
    options,
    function(gameContext) {
      this.gameContext = gameContext;
      this.game = gameContext.getState();
      this.save(
        function() {
          this.gameContext.start();
          if (callback) {
            callback(this);
          }
        }.bind(this)
      );
    }.bind(this)
  );
};

RoomSchema.methods.getGameContext = function(options) {
  if (this.status === 'open') {
    return undefined;
  }

  if (this.gameContext) {
    return this.gameContext;
  }

  this.gameContext = GameContext.fromSave({
    game: this.game,
    preEvent: this.preEvent.bind(this),
    postEvent: [this.postEvent.bind(this), options.postEvent]
  });

  return this.gameContext;
};

RoomSchema.statics.getUsers = function(roomId, callback) {
  this.findById(roomId)
    .populate('users.user')
    .exec(function(err, room) {
      if (err || !room) {
        return callback(err, room);
      }

      var users = room.users.map(member => member.user);

      callback(err, users);
    });
};

module.exports = RoomSchema;