backgammonjs icon indicating copy to clipboard operation
backgammonjs copied to clipboard

Spectator Mode

Open slayer1ss opened this issue 7 years ago • 9 comments

Is it possible to add a spectator mode? I have been trying to accomplish that and have been able to get a 3rd player to the game screen but data doesnt get refreshed...

Can you please tell me what to do?

slayer1ss avatar Jun 14 '18 19:06 slayer1ss

He is how I would approach this.

You can start by adding a spectators field to the Match class (in lib\model.js):

/**
 * Match
 * @constructor
 */
function Match() {
............
  /**
   * List of IDs of all spectators watching a match
   * @type {Array}
   */
  this.spectators = [];
............

Next, you would need a to change the game protocol. For that you have to modify comm.js and both app\server\server.js and lib\client.js. There are several approaches here:

  • Modify the handler of JOIN_MATCH messages to accept an additional parameter that determines if the user is a spectator or a player. or
  • Define a new command, eg. WATCH_MATCH, in comm.js, and create a new handler for it in the server. That handler should add the user to the spectators array. Apart from that you will need to change some of the other request handlers and make them also send responses and events to spectators.

Then change the client and the user interface to send the WATCH_MATCH command when the user wants to join a specific match - it could work via a link, similarly to the challange link, or, as a start, it could join you to a random match.

Once you have the logic to join a match as a spectator you will need to update message handlers in the client and make them check if the user is a spectator. If that is the case the client should ignore requests for rolling the dice or piece movement and should only update the board.

I personally don't have spare time at the moment for this feature request, but hopefully this can get you started.

quasoft avatar Jun 15 '18 08:06 quasoft

Thank you for the fast response... Before I opened this thread I made below changes...

To server/server.js -> in handleJoinMatch function:

if(match.guest){
	var rule=model.Utils.loadRule(match.ruleName);
	this.setSocketMatch(socket,match);
	this.setSocketRule(socket,rule);
	reply.ruleName=match.ruleName;
	reply.host=match.host;
	reply.guest=match.guest;
	reply.spectator=1;
	return true;
}

To lib/client.js -> handleJoinMatch function:

if(params.guest.id===this.player.id){
	this.updatePlayer(params.guest);
	this.updateOtherPlayer(params.host);
}else{this.player.spectator=1;}
this.updateMatch(params.match);
this.updateRule(this.loadRule(params.ruleName));
this.resetBoard(this.match,this.rule);

My idea was to remove the block in server.js that prevents joining of more than 2 players and add a marker to player array to determine they are spectator by just checking if the guest.id is added to match...

The changes I made actually works, a 3rd player can login as a spectator to game with challenge link and they have spectator flag, they actually can see the current state of the game, but for some reason it is just stuck there.

What I mean is that the spectators doesn't get new rolled dice status or new piece movement data... I thought there might be some javascript errors or something but there is nothing in console... I even thought about making a js interval to update board for spectators every second but that didnt work too...

Is my approach wrong? Should i start again? Or is there something I am missing in client.js or simpleboardui.js?

slayer1ss avatar Jun 15 '18 10:06 slayer1ss

It's not wrong, it's a possible approach.

In that case I would expect that changes in SimpleBoardUI.js will be needed as it depends on this.client.player to determine the current player.

You will also have to stop client.js from responding to messages from the server. It should only listen for responses and events and process them.

Try to instrument with console.log important steps in the server and client in order to get better understanding why it does not work. The client already prints some messages in the handleEventDiceRoll ('Dice rolled') and handleEventPieceMove ('Piece moved') handlers. Do you see those in the browser console of the spectator?

quasoft avatar Jun 15 '18 11:06 quasoft

Actually no, when i roll the dice spectator console is empty... That is what i am stuck at, no errors or any responses... It is like the spectator client is not listening anything...

You can see it in https://kuponuna-rulet.herokuapp.com/

slayer1ss avatar Jun 15 '18 12:06 slayer1ss

The client's main message handler (handleMessage) is not called for the spectator, which means that it is not receiving any messages - it should print a 'Reply/event received: ' message on every reply/event.

So it's either the server not sending messages to the spectator or the client gets disconnected immediately after the match starts.

The server is instrumented to log 'Sending message ' + msg + ' to client ' each time it sends a reply/event to a client, so check server logs to make sure it's actually sending the message to all three clients.

Excerpt from app\server.js:

...
this.sendMessage = function (socket, msg, params) {
    console.log('Sending message ' + msg + ' to client ' + socket.id);
    socket.emit(msg, params);
  };
...

quasoft avatar Jun 16 '18 09:06 quasoft

Well this is starting to get more wierder for me :) As for the server logs show 3rd player logs in gets an id and socket but after that it is just gone, no replies or anything... Shouldnt it write disconnected if it is dropped? Also for some reason on an empty server that no one knows there are 7 players listed in server logs? 2 of them are test players i am using, 3rd player is no where to be found but there are extra 5 players...

Here are the server logs...

--> 3rd player joins by link
2018-06-16T22:49:20.140786+00:00 app[web.1]: New player ID: 25192150
2018-06-16T22:49:20.140821+00:00 app[web.1]: Sending message createGuest to client pCyWAwCll1hUVUW6AAAH
2018-06-16T22:49:20.234336+00:00 app[web.1]: Request received: joinMatch
2018-06-16T22:49:20.234419+00:00 app[web.1]: Joining match { matchID: 36615305, clientMsgSeq: 2 }
2018-06-16T22:49:20.234485+00:00 app[web.1]: Loading rule in file ./rules/RuleBgCasual.js
2018-06-16T22:49:20.234873+00:00 app[web.1]: Sending message joinMatch to client pCyWAwCll1hUVUW6AAAH
-> 1st player requested dice roll
2018-06-16T22:49:24.048271+00:00 app[web.1]: Request received: rollDice
2018-06-16T22:49:24.048563+00:00 app[web.1]: Rolling dice
2018-06-16T22:49:24.057523+00:00 app[web.1]: Player {
2018-06-16T22:49:24.057525+00:00 app[web.1]:   id: 92091790,
2018-06-16T22:49:24.057529+00:00 app[web.1]:   currentMatch: null,
2018-06-16T22:49:24.057538+00:00 app[web.1]:   socketID: 'zmrFe-ORPImInzyCAAAA' }
2018-06-16T22:49:24.057636+00:00 app[web.1]: Player {
2018-06-16T22:49:24.057638+00:00 app[web.1]:   id: 20724286,
2018-06-16T22:49:24.057641+00:00 app[web.1]:   currentMatch: null,
2018-06-16T22:49:24.057647+00:00 app[web.1]:   socketID: 'GL9NEBVSmPIwpYY1AAAB' }
2018-06-16T22:49:24.057747+00:00 app[web.1]: Player {
2018-06-16T22:49:24.057750+00:00 app[web.1]:   id: 59801939,
2018-06-16T22:49:24.057753+00:00 app[web.1]:   currentMatch: null,
2018-06-16T22:49:24.057758+00:00 app[web.1]:   socketID: '4n84Fj5M2CZS6437AAAC' }
2018-06-16T22:49:24.057877+00:00 app[web.1]: Player {
2018-06-16T22:49:24.057880+00:00 app[web.1]:   id: 55670796,
2018-06-16T22:49:24.057882+00:00 app[web.1]:   currentMatch: null,
2018-06-16T22:49:24.057888+00:00 app[web.1]:   socketID: 'AANwJIZfnJXFnAyUAAAD' }
2018-06-16T22:49:24.057987+00:00 app[web.1]: Player {
2018-06-16T22:49:24.057989+00:00 app[web.1]:   id: 70210220,
2018-06-16T22:49:24.057992+00:00 app[web.1]:   currentMatch: null,
2018-06-16T22:49:24.057997+00:00 app[web.1]:   socketID: 'QrBMC0OmRi-QKMmNAAAE' }
2018-06-16T22:49:24.058097+00:00 app[web.1]: Player {
2018-06-16T22:49:24.058099+00:00 app[web.1]:   id: 50388040,
2018-06-16T22:49:24.058102+00:00 app[web.1]:   currentMatch: 36615305,
2018-06-16T22:49:24.058108+00:00 app[web.1]:   socketID: '52u8s02IelINg6ncAAAF' }
2018-06-16T22:49:24.058203+00:00 app[web.1]: Player {
2018-06-16T22:49:24.058205+00:00 app[web.1]:   id: 59287495,
2018-06-16T22:49:24.058208+00:00 app[web.1]:   currentMatch: 36615305,
2018-06-16T22:49:24.058214+00:00 app[web.1]:   socketID: 'jlLk-QZA9POGUTJ2AAAG' }
2018-06-16T22:49:24.058311+00:00 app[web.1]: Found Player {
2018-06-16T22:49:24.058313+00:00 app[web.1]:   id: 59287495,
2018-06-16T22:49:24.058316+00:00 app[web.1]:   currentMatch: 36615305,
2018-06-16T22:49:24.058322+00:00 app[web.1]:   socketID: 'jlLk-QZA9POGUTJ2AAAG' }
2018-06-16T22:49:24.058367+00:00 app[web.1]: Sending message eventDiceRoll to client jlLk-QZA9POGUTJ2AAAG
2018-06-16T22:49:24.060515+00:00 app[web.1]: Sending message rollDice to client 52u8s02IelINg6ncAAAF

slayer1ss avatar Jun 16 '18 23:06 slayer1ss

When the server receives the join command, it adds the client to the players array.

It does so by using either the Match.addHostPlayer or Match.addGuestPlayer.

Both of these make sure there are only two players in the array. For example in Match.addHostPlayer:

...
if (match.host)
  {
    throw new Error("Match already has a host player!");
}
...

You will either need to change that or create a new method, eg. Match.addSpectator.

As for ghost players, player objects remain the array in case the client has temporary disconnected and wants to reconnect, so these are probably left over from previous test games. This should not be related to the problem.

quasoft avatar Jun 17 '18 07:06 quasoft

these comments helped me and I developed Spectator Mode successfully. thanks for your amazing project

Ali9731 avatar Feb 28 '23 10:02 Ali9731

Great to hear!

I myself don't have time to work on this project so it is great there are forks adding new features.

Wish you luck!

quasoft avatar Feb 28 '23 11:02 quasoft