diff --git a/lib/Chuck/ClientGame.js b/lib/Chuck/ClientGame.js index d1bf21b..08ce95a 100644 --- a/lib/Chuck/ClientGame.js +++ b/lib/Chuck/ClientGame.js @@ -2,7 +2,7 @@ define(["Chuck/Processors/ClientProcessor"], function(ClientProcessor) { function ClientGame(networker, id) { this.networker = networker; - this.processor = new ClientProcessor(); + this.processor = new ClientProcessor(this); this.processor.spawnMeWithId(id); } @@ -15,7 +15,11 @@ define(["Chuck/Processors/ClientProcessor"], function(ClientProcessor) { }; ClientGame.prototype.processGameCommand = function(command, options){ - console.log('(not implemented) processGameCommand:', command, options); + this.processor.processGameCommand(command, options); + } + + ClientGame.prototype.sendGameCommand = function(command, options) { + this.networker.sendGameCommand(command, options); } ClientGame.prototype.destruct = function(){ diff --git a/lib/Chuck/Control/InputControlUnit.js b/lib/Chuck/Control/InputControlUnit.js index fa43ee6..86d7c99 100755 --- a/lib/Chuck/Control/InputControlUnit.js +++ b/lib/Chuck/Control/InputControlUnit.js @@ -1,17 +1,11 @@ -define(["Chuck/Control/KeyboardInput"], function(KeyboardInput){ +define(["Chuck/Control/InputController", "Chuck/Control/KeyboardInput"], function(InputController, KeyboardInput){ - function InputControlUnit(me) { + function InputControlUnit(me, clientProcessor) { - this._keyboardInput = new KeyboardInput(this); - this._me = me; + this.clientProcessor = clientProcessor; + this.inputController = new InputController(me); - this._shift; - this._isJumping; - - this.KEY_LEFT = 65; - this.KEY_RIGHT = 68; - this.KEY_UP = 87; - this.KEY_DOWN = 83; + this.keyboardInput = new KeyboardInput(this); var keys = { w:87, @@ -30,67 +24,70 @@ define(["Chuck/Control/KeyboardInput"], function(KeyboardInput){ InputControlUnit.prototype.init = function(keys) { - this._keyboardInput.registerKey(keys.a, 'moveLeft', 'stop', 'moveLeft'); - this._keyboardInput.registerKey(keys.left, 'moveLeft', 'stop', 'moveLeft'); + this.keyboardInput.registerKey(keys.a, 'moveLeft', 'stop', 'moveLeft'); + this.keyboardInput.registerKey(keys.left, 'moveLeft', 'stop', 'moveLeft'); - this._keyboardInput.registerKey(keys.d, 'moveRight', 'stop', 'moveRight'); - this._keyboardInput.registerKey(keys.right, 'moveRight', 'stop', 'moveRight'); + this.keyboardInput.registerKey(keys.d, 'moveRight', 'stop', 'moveRight'); + this.keyboardInput.registerKey(keys.right, 'moveRight', 'stop', 'moveRight'); - this._keyboardInput.registerKey(keys.w, 'jump', 'jumped', 'jumping'); - this._keyboardInput.registerKey(keys.up, 'jump', 'jumped', 'jumping'); + this.keyboardInput.registerKey(keys.w, 'jump', 'jumped', 'jumping'); + this.keyboardInput.registerKey(keys.up, 'jump', 'jumped', 'jumping'); - this._keyboardInput.registerKey(keys.s, 'duck', 'standUp', 'duck'); - this._keyboardInput.registerKey(keys.down, 'duck', 'standUp', 'duck'); + this.keyboardInput.registerKey(keys.s, 'duck', 'standUp', 'duck'); + this.keyboardInput.registerKey(keys.down, 'duck', 'standUp', 'duck'); - this._keyboardInput.registerKey(keys.s, 'activateShift', 'activateShift', 'deactivateShift'); - this._keyboardInput.registerKey(keys.down, 'activateShift', 'activateShift', 'deactivateShift'); + this.keyboardInput.registerKey(keys.s, 'activateShift', 'activateShift', 'deactivateShift'); + this.keyboardInput.registerKey(keys.down, 'activateShift', 'activateShift', 'deactivateShift'); } InputControlUnit.prototype.moveLeft = function() { - this._me.move(-1); + this.inputController.moveLeft(); + this.clientProcessor.sendGameCommand('moveLeft'); } InputControlUnit.prototype.moveRight = function() { - this._me.move(1); + this.inputController.moveRight(); + this.clientProcessor.sendGameCommand('moveRight'); } InputControlUnit.prototype.stop = function() { - this._me.stop(); + this.inputController.stop(); + this.clientProcessor.sendGameCommand('stop'); } InputControlUnit.prototype.jump = function() { - this._isJumping = true; - this._me.jump(); + this.inputController.jump(); + this.clientProcessor.sendGameCommand('jump'); } InputControlUnit.prototype.jumped = function() { - this._isJumping = false; + this.inputController.jumped(); } InputControlUnit.prototype.jumping = function() { - if (this._isJumping) { - this._me.jumping(); - } + this.inputController.jumping(); } InputControlUnit.prototype.duck = function() { - this._me.duck(); + this.inputController.duck(); + this.clientProcessor.sendGameCommand('duck'); } InputControlUnit.prototype.standUp = function() { - this._me.standUp(); + this.inputController.standUp(); } InputControlUnit.prototype.activateShift = function() { - this._shift = true; + this.inputController.activateShift(); + this.clientProcessor.sendGameCommand('activateShift'); } InputControlUnit.prototype.deactivateShift = function() { - this._shift = false; + this.inputController.deactivateShift(); } InputControlUnit.prototype.update = function() { - this._keyboardInput.update(); + this.keyboardInput.update(); } return InputControlUnit; diff --git a/lib/Chuck/Control/InputController.js b/lib/Chuck/Control/InputController.js new file mode 100644 index 0000000..db85b7b --- /dev/null +++ b/lib/Chuck/Control/InputController.js @@ -0,0 +1,59 @@ +define(function(){ + + function InputController(player) { + + this.player = player; + + this._shift; + this._isJumping; + } + + InputController.prototype.moveLeft = function() { + this.player.move(-1); + } + + InputController.prototype.moveRight = function() { + this.player.move(1); + } + + InputController.prototype.stop = function() { + this.player.stop(); + } + + InputController.prototype.jump = function() { + this._isJumping = true; + this.player.jump(); + } + + InputController.prototype.jumped = function() { + this._isJumping = false; + } + + InputController.prototype.jumping = function() { + if (this._isJumping) { + this.player.jumping(); + } + } + + InputController.prototype.duck = function() { + this.player.duck(); + } + + InputController.prototype.standUp = function() { + this.player.standUp(); + } + + InputController.prototype.activateShift = function() { + this._shift = true; + } + + InputController.prototype.deactivateShift = function() { + this._shift = false; + } + + InputController.prototype.update = function() { + + } + + return InputController; +}); \ No newline at end of file diff --git a/lib/Chuck/Physics/Doll.js b/lib/Chuck/Physics/Doll.js index caea7d2..84e959b 100644 --- a/lib/Chuck/Physics/Doll.js +++ b/lib/Chuck/Physics/Doll.js @@ -18,6 +18,7 @@ define(["Vendor/Box2D", "Chuck/Settings"], function(Box2D, Settings){ bodyDef.fixedRotation = true; bodyDef.linearDamping = Settings.PLAYER_LINEAR_DAMPING; bodyDef.type = Box2D.Dynamics.b2Body.b2_dynamicBody; + bodyDef.userData = 'player-' + this.id; this._body = world.CreateBody(bodyDef); @@ -31,14 +32,14 @@ define(["Vendor/Box2D", "Chuck/Settings"], function(Box2D, Settings){ headShape.SetLocalPosition(new Box2D.Common.Math.b2Vec2(0 / Settings.RATIO, -37 / Settings.RATIO)); fixtureDef.shape = headShape; fixtureDef.isSensor = false; - fixtureDef.userData = 'myHead' + this.id; + fixtureDef.userData = 'myHead-' + this.id; this._body.CreateFixture(fixtureDef); var bodyShape = new Box2D.Collision.Shapes.b2PolygonShape(); bodyShape.SetAsOrientedBox(5 / Settings.RATIO, 16 / Settings.RATIO, new Box2D.Common.Math.b2Vec2(0 / Settings.RATIO, -21 / Settings.RATIO)); fixtureDef.shape = bodyShape; fixtureDef.isSensor = false; - fixtureDef.userData = 'myBody' + this.id; + fixtureDef.userData = 'myBody-' + this.id; this._body.CreateFixture(fixtureDef); var legsShape = new Box2D.Collision.Shapes.b2CircleShape(); @@ -47,7 +48,7 @@ define(["Vendor/Box2D", "Chuck/Settings"], function(Box2D, Settings){ fixtureDef.shape = legsShape; fixtureDef.friction = Settings.PLAYER_FRICTION; fixtureDef.isSensor = false; - fixtureDef.userData = 'myLegs' + this.id; + fixtureDef.userData = 'myLegs-' + this.id; this._legs = this._body.CreateFixture(fixtureDef); var feetShape = new Box2D.Collision.Shapes.b2CircleShape(); @@ -55,7 +56,7 @@ define(["Vendor/Box2D", "Chuck/Settings"], function(Box2D, Settings){ feetShape.SetLocalPosition(new Box2D.Common.Math.b2Vec2(0 / Settings.RATIO, 0 / Settings.RATIO)); fixtureDef.shape = feetShape; fixtureDef.isSensor = true; - fixtureDef.userData = 'myFeet' + this.id; + fixtureDef.userData = 'myFeet-' + this.id; this._body.CreateFixture(fixtureDef); this._body.SetActive(false); diff --git a/lib/Chuck/Player.js b/lib/Chuck/Player.js index 525a5c3..c30ec60 100644 --- a/lib/Chuck/Player.js +++ b/lib/Chuck/Player.js @@ -1,120 +1,120 @@ define(["Chuck/Physics/Doll", "Chuck/Settings"], function(Doll, Settings){ function Player (physicsEngine, id, repository) { - this._physicsEngine = physicsEngine; + this.physicsEngine = physicsEngine; this.id = id; - this._repository = repository; - this._standing = false; - this._doll; - this._mc; - this._currentAnimationState = 'stand'; - this._lookDirection = 1; - this._moveDirection = 0; + this.repository = repository; + this.standing = false; + this.doll; + this.mc; + this.currentAnimationState = 'stand'; + this.lookDirection = 1; + this.moveDirection = 0; this.init(id); } Player.prototype.init = function(id) { - this._doll = new Doll(this._physicsEngine, id); - //this._mc = EmbedHandler.load(EmbedHandler.CHUCK); - //this._mc.stop(); + this.doll = new Doll(this.physicsEngine, id); + //this.mc = EmbedHandler.load(EmbedHandler.CHUCK); + //this.mc.stop(); //var mclp = new MovieClipLabelParser(); - //mclp.parse(this._mc); + //mclp.parse(this.mc); } Player.prototype.spawn = function(x, y) { - //this._repository.createModel(this._mc, this._doll.getBody()); - this._doll.spawn(x, y); + //this.repository.createModel(this.mc, this.doll.getBody()); + this.doll.spawn(x, y); } Player.prototype.getDoll = function() { - return this._doll; + return this.doll; } Player.prototype.getBody = function() { - return this._doll.getBody(); + return this.doll.getBody(); } Player.prototype.setStanding = function(isStanding) { var resetStates = ['jump', 'jumploop']; - if (resetStates.indexOf(this._currentAnimationState)>=0 && !this._standing && isStanding) { - this._animate('stand'); + if (resetStates.indexOf(this.currentAnimationState)>=0 && !this.standing && isStanding) { + this.animate('stand'); } - this._standing = isStanding; + this.standing = isStanding; } Player.prototype.isStanding = function() { - return this._standing; + return this.standing; } Player.prototype.move = function(direction) { - this._moveDirection = direction; + this.moveDirection = direction; switch(true) { - case direction == this._lookDirection && this.isStanding(): - this._doll.move(direction, Settings.RUN_SPEED); + case direction == this.lookDirection && this.isStanding(): + this.doll.move(direction, Settings.RUN_SPEED); break; case !this.isStanding(): - this._doll.move(direction, Settings.FLY_SPEED); + this.doll.move(direction, Settings.FLY_SPEED); break; default: - this._doll.move(direction, Settings.WALK_SPEED); + this.doll.move(direction, Settings.WALK_SPEED); break; } if (this.isStanding()) { - this._animate(this._calculateWalkAnimation()); + this.animate(this.calculateWalkAnimation()); } } Player.prototype.stop = function() { - this._moveDirection = 0; - this._doll.stop(); - if (this._isWalking() || this._standing) { - this._animate('stand'); + this.moveDirection = 0; + this.doll.stop(); + if (this.isWalking() || this.standing) { + this.animate('stand'); } } Player.prototype.jump = function() { if (this.isStanding()) { - this._doll.jump(); - this._animate('jump'); + this.doll.jump(); + this.animate('jump'); this.setStanding(false); } } Player.prototype.jumping = function() { if (!this.isStanding()) { - this._doll.jumping(); + this.doll.jumping(); } } Player.prototype.duck = function() { - if (this._standing && !this._isWalking()) { - this._animate('duck'); + if (this.standing && !this.isWalking()) { + this.animate('duck'); } } Player.prototype.standUp = function() { - if (this._standing) { - this._animate('standup'); + if (this.standing) { + this.animate('standup'); } } - Player.prototype._animate = function(type) { - if (type == this._currentAnimationState) { + Player.prototype.animate = function(type) { + if (type == this.currentAnimationState) { return; } - //this._mc.gotoAndPlay(type); + //this.mc.gotoAndPlay(type); - this._currentAnimationState = type; + this.currentAnimationState = type; } - Player.prototype._calculateWalkAnimation = function() { - if (this._moveDirection == this._lookDirection) { + Player.prototype.calculateWalkAnimation = function() { + if (this.moveDirection == this.lookDirection) { return 'run'; } return 'walkback'; @@ -123,29 +123,29 @@ define(["Chuck/Physics/Doll", "Chuck/Settings"], function(Doll, Settings){ Player.prototype.look = function(x, y) { /* var degree = Math.atan2(Settings.STAGE_WIDTH / 2 - x, Settings.STAGE_HEIGHT / 2 - 25 - y) / (Math.PI / 180); - var lastLookDirection = this._lookDirection; + var lastLookDirection = this.lookDirection; if (x < Settings.STAGE_WIDTH / 2) { - this._mc.scaleX = -1; - this._lookDirection = -1; + this.mc.scaleX = -1; + this.lookDirection = -1; degree = (-45 + degree / 2); - this._mc.head.rotation = degree; + this.mc.head.rotation = degree; } else if (x >= Settings.STAGE_WIDTH / 2) { - this._mc.scaleX = 1; - this._lookDirection = 1; + this.mc.scaleX = 1; + this.lookDirection = 1; degree = (45 + -degree / 2) - 90; - this._mc.head.rotation = degree; + this.mc.head.rotation = degree; } - if (this._lookDirection != lastLookDirection && this._isWalking()) { - this._animate(this._calculateWalkAnimation()); + if (this.lookDirection != lastLookDirection && this.isWalking()) { + this.animate(this.calculateWalkAnimation()); }*/ } - Player.prototype._isWalking = function() { + Player.prototype.isWalking = function() { var states = ['walk', 'walkback', 'run']; - if (states.indexOf(this._currentAnimationState) >= 0) { + if (states.indexOf(this.currentAnimationState) >= 0) { return true; } return false; @@ -154,7 +154,7 @@ define(["Chuck/Physics/Doll", "Chuck/Settings"], function(Doll, Settings){ // called by CollisionDetection Player.prototype.onFootSensorDetection = function(isColliding) { if(isColliding) { - if(this._doll.getBody().GetLinearVelocity().y < -Settings.JUMP_SPEED && !this.isStanding()) { + if(this.doll.getBody().GetLinearVelocity().y < -Settings.JUMP_SPEED && !this.isStanding()) { return; } this.setStanding(true); @@ -164,18 +164,18 @@ define(["Chuck/Physics/Doll", "Chuck/Settings"], function(Doll, Settings){ // to group all tiles together //this.setStanding(false); - //this._animate('jumploop'); + //this.animate('jumploop'); } } Player.prototype.update = function() { - //this._mc.head.y = this._mc.head_posmask.y; + //this.mc.head.y = this.mc.head_posmask.y; - if (this._doll.getBody().GetLinearVelocity().x == 0 && this._isWalking()) { + if (this.doll.getBody().GetLinearVelocity().x == 0 && this.isWalking()) { this.stop(); } - if (!this._doll.getBody().IsAwake()) { + if (!this.doll.getBody().IsAwake()) { this.setStanding(true); } } diff --git a/lib/Chuck/Processors/ClientProcessor.js b/lib/Chuck/Processors/ClientProcessor.js index b6c626b..1fecad0 100755 --- a/lib/Chuck/Processors/ClientProcessor.js +++ b/lib/Chuck/Processors/ClientProcessor.js @@ -12,7 +12,8 @@ var requires = [ define(requires, function(ViewController, PhysicsEngine, Player, InputControlUnit, Settings, Box2D, Level, requestAnimFrame) { - function ClientProcessor () { + function ClientProcessor (clientGame) { + this.clientGame = clientGame; this.init(); }; @@ -46,6 +47,7 @@ define(requires, this.physicsEngine.update(); this.viewController.update(); + if(this.me) { this.inputControlUnit.update(); this.me.update(); @@ -65,7 +67,35 @@ define(requires, ClientProcessor.prototype.spawnMeWithId = function(id) { this.me = this.spawnNewPlayerWithId(id); - this.inputControlUnit = new InputControlUnit(this.me); + this.inputControlUnit = new InputControlUnit(this.me, this); + } + + ClientProcessor.prototype.sendGameCommand = function(command, options) { + this.clientGame.sendGameCommand(command, options); + } + + ClientProcessor.prototype.processGameCommand = function(command, options) { + + if (command == "worldUpdate") { + + var body = this.physicsEngine.world.GetBodyList(); + do { + var userData = body.GetUserData(); + if(userData && options[userData]) { + var update = options[userData]; + + //console.log('position difference:', (body.GetPosition().y - update.p.y) * 30, body.GetLinearVelocity().y); + + body.SetAwake(true); + body.SetPosition(update.p); + body.SetAngle(update.a); + body.SetLinearVelocity(update.lv); + body.SetAngularVelocity(update.av); + } + } while (body = body.GetNext()); + + } + } return ClientProcessor; diff --git a/lib/Chuck/Processors/ServerProcessor.js b/lib/Chuck/Processors/ServerProcessor.js index 412ac4e..0c01b65 100755 --- a/lib/Chuck/Processors/ServerProcessor.js +++ b/lib/Chuck/Processors/ServerProcessor.js @@ -3,13 +3,14 @@ var requires = [ "Chuck/Player", "Vendor/Box2D", "Chuck/Loader/Level", + "Chuck/Control/InputController", "RequestAnimationFrame" ]; -define(requires, function(PhysicsEngine, Player, Box2D, Level, requestAnimFrame){ +define(requires, function(PhysicsEngine, Player, Box2D, Level, InputController, requestAnimFrame){ - function ServerProcessor (ServerProcessor) { - this.ServerProcessor = ServerProcessor; + function ServerProcessor (serverGame) { + this.serverGame = serverGame; this.players = {}; this.init(); }; @@ -18,6 +19,7 @@ define(requires, function(PhysicsEngine, Player, Box2D, Level, requestAnimFrame) this.physicsEngine = new PhysicsEngine(); this.update(); + this.updateWorld(); } ServerProcessor.prototype.loadLevel = function(path) { @@ -39,7 +41,7 @@ define(requires, function(PhysicsEngine, Player, Box2D, Level, requestAnimFrame) this.physicsEngine.update(); for(var id in this.players) { - this.players[id].update(); + this.players[id].player.update(); } } @@ -49,23 +51,33 @@ define(requires, function(PhysicsEngine, Player, Box2D, Level, requestAnimFrame) ServerProcessor.prototype.createPlayerWithId = function(id) { var player = new Player(this.physicsEngine, id, null); - this.players[id] = player; + this.players[id] = { + player: player, + inputController: new InputController(player) + }; player.spawn(100, 0); this.physicsEngine.setCollisionDetector(player); } + ServerProcessor.prototype.progressGameCommandFromId = function(command, options, id) { + var inputController = this.players[id].inputController; + if (typeof inputController[command] == 'function') { + inputController[command](options); + } + } + ServerProcessor.prototype.updateWorld = function() { var update = {}; var isUpdateNeeded = false; - var body = world.GetBodyList(); + var body = this.physicsEngine.world.GetBodyList(); do { var userData = body.GetUserData(); - if(userData && userData.bodyId && body.IsAwake()){ - update[userData.bodyId] = { + if(userData && body.IsAwake()){ + update[userData] = { p: body.GetPosition(), a: body.GetAngle(), lv: body.GetLinearVelocity(), @@ -76,8 +88,10 @@ define(requires, function(PhysicsEngine, Player, Box2D, Level, requestAnimFrame) } while (body = body.GetNext()); if(isUpdateNeeded) { - this.ServerProcessor.updateClientsWorld(update); + this.serverGame.updateClientsWorld(update); } + + setTimeout(this.updateWorld.bind(this), 500); // FIXME: do this a different hearbeat } return ServerProcessor; diff --git a/lib/Chuck/ServerGame.js b/lib/Chuck/ServerGame.js index 2965864..76d7bf5 100644 --- a/lib/Chuck/ServerGame.js +++ b/lib/Chuck/ServerGame.js @@ -9,8 +9,8 @@ define(["Chuck/Processors/ServerProcessor"], function(ServerProcessor) { this.serverProcessor.loadLevel(path); } - ServerGame.prototype.processGameCommand = function(command, options) { - console.log('(not implemented) processGameCommand:', command, options); + ServerGame.prototype.progressGameCommandFromUser = function(command, options, user) { + this.serverProcessor.progressGameCommandFromId(command, options, user.id); } ServerGame.prototype.destruct = function() { @@ -22,7 +22,7 @@ define(["Chuck/Processors/ServerProcessor"], function(ServerProcessor) { } ServerGame.prototype.updateClientsWorld = function(update_world) { - this.channel.sendCommandToAllUsers('gameCommand', update_world); + this.channel.sendCommandToAllUsers('gameCommand', {worldUpdate: update_world}); } return ServerGame; diff --git a/lib/Client/Networker.js b/lib/Client/Networker.js index 8657eec..dfd1969 100644 --- a/lib/Client/Networker.js +++ b/lib/Client/Networker.js @@ -58,7 +58,13 @@ define(["Protocol/Helper", "Chuck/ClientGame"], function(ProtocolHelper, ClientG Networker.prototype.onUserJoined = function(userId) { this.clientGame.userJoined(userId); console.log("User " + userId + " joined"); - }; + } + + Networker.prototype.sendGameCommand = function(command, options) { + var message = {}; + message[command] = options || true; + this.sendCommand('gameCommand', message); + } Networker.prototype.processControlCommand = function(command, options) { switch(command) { @@ -67,7 +73,9 @@ define(["Protocol/Helper", "Chuck/ClientGame"], function(ProtocolHelper, ClientG break; case 'gameCommand': - this.clientGame.processGameCommand(options); + for(var c in options) { + this.clientGame.processGameCommand(c, options[c]); + } break; case 'userJoined': diff --git a/lib/Server/Channel.js b/lib/Server/Channel.js index 2fed92f..3860ff4 100644 --- a/lib/Server/Channel.js +++ b/lib/Server/Channel.js @@ -13,7 +13,7 @@ define(["Chuck/ServerGame"], function(ServerGame) { Channel.prototype.addUser = function(user){ this.users[user.id] = user; - user.sendCommand('joinSuccess', {chanelName: this.name, id: user.id}); + user.sendCommand('joinSuccess', {channelName: this.name, id: user.id}); this.sendCommandToAllUsersExcept('userJoined', user.id, user); this.serverGame.createPlayerForUser(user) @@ -37,8 +37,8 @@ define(["Chuck/ServerGame"], function(ServerGame) { } } - Channel.prototype.processGameCommandFromUser = function(command, user) { - console.log("not implemented processGameCommandFromUser: " + command + user); + Channel.prototype.processGameCommandFromUser = function(command, options, user) { + this.serverGame.progressGameCommandFromUser(command, options, user); } return Channel; diff --git a/lib/Server/User.js b/lib/Server/User.js index 452d8a7..3ea4f4e 100644 --- a/lib/Server/User.js +++ b/lib/Server/User.js @@ -55,7 +55,9 @@ define(["Protocol/Helper"], function(ProtocolHelper) { break; case 'gameCommand': - this.channel.processGameCommandFromUser(options, this); + for(var c in options) { + this.channel.processGameCommandFromUser(c, options[c], this); + } break; default: @@ -63,6 +65,10 @@ define(["Protocol/Helper"], function(ProtocolHelper) { } } + User.prototype.toString = function() { + return "[User " + this.id + "]"; + }; + return User; }); \ No newline at end of file