boardgameio / boardgame.io

State Management and Multiplayer Networking for Turn-Based Games
https://boardgame.io
MIT License
10k stars 706 forks source link

Insufficient documentation/guide on multiplayer #138

Closed viranch closed 6 years ago

viranch commented 6 years ago

The Multiplayer guide mentions that

All you need to do is add multiplayer: true to your client config object [...] You can open multiple browser tabs and you will find that the game board is synced in realtime across all of them

Apparently, that's not all that is needed. There's some magic server code that needs to be written.

Furthermore, its not specified where exactly the code snippet with server.run(8000); is supposed to be put and how it can be executed. The same about the mention of Koa app.

I looked at the examples; multiple games and single/multi player modes are baked in a single app. Inferring the relevant parts from examples, to make just a multiplayer game for example, is difficult. Add to that the Koa and webpack config complexity that is in the examples but nowhere in the guide or documentation.

If the user is expected to already know certain things beforehand (obvious one being React.js) that may not be very obvious, list of such things should be documented.

nicolodavis commented 6 years ago

The example server code (4 lines or so) shown in the documentation should work as is.

That's all you will need to set up a socket server to handle multiplayer. All the other stuff that you're claiming is necessary is actually not. Sorry if the examples are confusing you.

Everything beyond that is up to individual developers. Some may choose to bundle their apps using Webpack. Others may not. Some may choose to server the web app from the same server. Others may not.

Documenting how to use React or Webpack is beyond scope.

Maybe I'll add some steps on how to use create-react-app eject or something like that.

nicolodavis commented 6 years ago

Also, if you're stuck, here is what you need to run the server code shown in the examples:

node server.js

I can document this too if it isn't obvious.

viranch commented 6 years ago

So those 4 lines of code goes in a separate server.js file? Its not really clear in the documentation, nor is how to run it.

I tried node server.js but got the following error:

→ ~/code/personal/mygame » node src/server.js
/Users/vimehta/code/personal/mygame/src/game.js:1
(function (exports, require, module, __filename, __dirname) { import { Game } from 'boardgame.io/core';
                                                              ^^^^^^

SyntaxError: Unexpected token import
   ...
→ ~/code/personal/mygame » cat src/server.js
const Server = require('boardgame.io/server').Server;
const Game = require('./game.js');
const server = Server({ games: [Game] });
server.run(8000);
→ ~/code/personal/mygame » head -1 src/game.js
import { Game } from 'boardgame.io/core';
→ ~/code/personal/mygame » 

So clearly, there's a lot more that the documentation should be specifying, for a beginner who has just finished the tutorial page and wanting to extend the game.

viranch commented 6 years ago

Also, the same error is thrown on running node server.js inside examples:

→ ~/code/personal/boardgame.io/examples <master> » node server.js
/Users/vimehta/code/personal/boardgame.io/examples/server.js:9
import path from 'path';
^^^^^^

SyntaxError: Unexpected token import
    ...
→ ~/code/personal/boardgame.io/examples <master> »

My node version:

→ ~/code/personal/boardgame.io/examples <master> » node -v
v9.8.0
→ ~/code/personal/boardgame.io/examples <master> »
vdfdev commented 6 years ago

@viranch my understanding is that you need to use npm run dev because this JS file needs to go through babel before executing by node. "import" for instance is not supported by node by default, so babel translates it to "require". But you could, technically, code directly in node.js without the need to run through babel first.

viranch commented 6 years ago

@Felizardo correct. I'm now running the server using ./node_modules/babel-cli/bin/babel-node.js.

My point here is, the documentation should mention all of these caveats, if not specify how to get it working. Especially the part that says "All you need to do is add multiplayer: true to your client config object" - that's clearly not the case, and there's significant amount of server setup that's required before multiplayer can just work.

vdfdev commented 6 years ago

I am not sure if this is the case for better documentation on this framework as this is is the default setup for any node js server, really. But you are right that the JS landscape right now is overwhelming for who is beginning now, and it still is for me.

Well, I think doing a tutorial with step by step on how to put all the pieces together (with react starter, koa etc) might be more appropriate.

vdfdev commented 6 years ago

And yes, if you are doing a single player game you dont need a server at all, everything can be in a react component on the client side. In the case you want multiplayer, then you need to setup a node.js server.

viranch commented 6 years ago

Yep, and the multiplayer guide should mention how to setup the server. There's no mention of where the 4 lines of server code should go (I initially put them in App.js itself!) or how to run it. None of them are obvious or straight forward.

I am indeed new to the JS landscape, and my expectation from a piece of documentation may not be inline with the standard in JS world.

I'd appreciate nevertheless if the documentation was beginner-friendly :)

nicolodavis commented 6 years ago

My point here is, the documentation should mention all of these caveats, if not specify how to get it working. Especially the part that says "All you need to do is add multiplayer: true to your client config object" - that's clearly not the case, and there's significant amount of server setup that's required before multiplayer can just work.

You're taking that line out of context. It says that all you need to do is add multiplayer: true to "have a multiplayer enabled client." As far as I'm aware, this is the only change that you need to make on the client side for it to work in a multiplayer game.

About the server side, I'll update the documentation with some copy-pastable commands that you can use. Copying 4 lines of code and running a command or two is not a significant amount of server setup IMO. We could streamline it further by providing a shell script to do the same, but I don't think there is sufficient value-add to warrant that.

viranch commented 6 years ago

Good point. Didn't really work with one/two commands for me, I was probably missing something. Good thing I'll soon find out once the doc is updated :)

nicolodavis commented 6 years ago

I've added a lot more detail in https://github.com/google/boardgame.io/commit/477aaf3a3dc97de361c2b2b5785b000562d55b58 (you can view them on the docs here). Let me know if these steps work for you!

The documentation looks a lot better now. Thanks for bringing this to my attention.

viranch commented 6 years ago

@nicolodavis this is amazing!

I'll go through it and try to setup a multiplayer game from scratch using all the commands and instructions and comment here with my feedback.

viranch commented 6 years ago

Observed the following issues with the instructions:

  1. The npx babel-node [...] command doesn't work because it tries to install babel-node package, but the command is provided by babel-cli package. So the install command should include babel-cli.

  2. The const TicTacToe = require('./game').TicTacToe; line should really be const TicTacToe = require('./game'); - the former evaluates to undefined.

  3. The single server (for client+socket) instructions under Production section don't work: I get a 404 at localhost:8000 on the browser after running npm run build, putting Koa stuff in server.js and re-running the npx babel-node [...] command.

Other comments (just being thorough, may not really need to be addressed):

  1. It should probably be mentioned somewhere that the Game instantiation should be put in a separate game.js file for it to be imported by server.js. The tutorial puts everything into App.js. May be update the tutorial itself to create separate files in the first place?

  2. The flow of the Multiplayer doc is inter-tangling between 'one client+socket server' vs 'separate client & socket servers'. It starts off with adding multiplayer: true line in Client, but goes on to say that server is separate so change it to multiplayer: { server: 'localhost:8000' } and then the "Production" section starts with how to write a single server, immediately followed by separate servers again. Does that make sense?

I can send pull requests for 1 & 2, not sure how to fix 3.

nicolodavis commented 6 years ago

[2] depends on how you export TicTacToe in game.js. I used:

export const TicTacToe = Game({ ... });

This will probably be made clearer by explaining how the code was moved to game.js (your point [4]).

nicolodavis commented 6 years ago

About [1], I'm not sure how it's working for me. Perhaps I've installed something globally. I'll fix that.

For [3], did you put server.js in src, or in the root of the repo? The KoaStatic function needs to point to the build directory.

EDIT: Ah, looks like KoaStatic('../build') is interpreted as relative to the current directory. Fixed using the path module.

nicolodavis commented 6 years ago

I've fixed some of the stuff in https://github.com/google/boardgame.io/commit/f40d9193ab7e4b7e96c0713b07f22197143b8529.

Is [5] the only remaining concern? I think I started with multiplayer: true because it is conceptually the simplest on the client side. I then moved to having a separate socket server because that's simpler on the server side. Then I talk about the more advanced versions. I think I'd like to keep that progression, but maybe we can highlight them a bit better? Maybe only talk about the "single server for app + sockets" in the Production section?

viranch commented 6 years ago

For [3], here's what I'm doing:

→ ~/code/mygame » tree src
src
├── App.css
├── App.js
├── App.test.js
├── board.js
├── client-app.js
├── game.js
├── index.css
├── index.js
├── logo.svg
├── registerServiceWorker.js
└── server.js

0 directories, 11 files
→ ~/code/mygame » cat src/server.js
const KoaStatic = require('koa-static');
const Server = require('boardgame.io/server').Server;
const Drop = require('./game');
const server = Server({ games: [Drop] });
server.app.use(KoaStatic('../build'));
server.run(8000);
→ ~/code/mygame » npm run build

> take3@0.1.0 build /Users/viranch/code/mygame
> react-scripts build

Creating an optimized production build...

File sizes after gzip:

  71.26 KB  build/static/js/main.a7a74910.js
  299 B     build/static/css/main.c17080f1.css

The project was built assuming it is hosted at the server root.
You can control this with the homepage field in your package.json.
For example, add this to build it for GitHub Pages:

  "homepage" : "http://myname.github.io/myapp",

The build folder is ready to be deployed.
You may serve it with a static server:

  yarn global add serve
  serve -s build

Find out more about deployment here:

  http://bit.ly/2vY88Kr

→ ~/code/mygame » tree build
build
├── asset-manifest.json
├── favicon.ico
├── index.html
├── manifest.json
├── service-worker.js
└── static
    ├── css
    │   ├── main.c17080f1.css
    │   └── main.c17080f1.css.map
    ├── js
    │   ├── main.a7a74910.js
    │   └── main.a7a74910.js.map
    └── media
        └── logo.5d5d9eef.svg

4 directories, 10 files
→ ~/code/mygame » npx babel-node --presets zero src/server.js
<Running>...

On other terminal:

→ ~/code/mygame » curl -D-  localhost:8000
HTTP/1.1 404 Not Found
Content-Type: text/plain; charset=utf-8
Content-Length: 9
Date: Tue, 13 Mar 2018 04:33:59 GMT
Connection: keep-alive

Not Found%
→ ~/code/mygame »

I think the command to run the combined server is serve -s build and not the npx babel-node command?

For [5], I think separate sections on 'single server' and 'separate servers' will give more clarity. May be start off as if separate servers is the only way, and then talk about the single server option under Production section.

nicolodavis commented 6 years ago

serve -s build just brings up a regular HTTP server to serve the HTML in the build directory. We want to bring up server.js, which serves both the HTML as well as the socket server.

Can you update src/server.js to use the path module like I have in https://github.com/google/boardgame.io/commit/f40d9193ab7e4b7e96c0713b07f22197143b8529? That should fix it for you.

viranch commented 6 years ago

The new instructions do get rid of the 404. But multiplayer is not working, in either of single server or separate client/socket servers.

I reproduced this several times with roughly the following steps:

cd /tmp
create-react-app game
cd game
npm install --save boardgame.io  # somehow this is removing react,react-dom,react-scripts from ./node_modules/
mkdir src/components
cp ~/code/boardgame.io.git/examples/modules/tic-tac-toe/components/{multiplayer.js,board.*} src/components
cp ~/code/boardgame.io.git/examples/modules/tic-tac-toe/game.js src/

Then put the following in src/App.js:

import Multiplayer from './components/multiplayer';
const App = Multiplayer;
export default App;

And following in src/server.js:

const path = require('path');
const KoaStatic = require('koa-static');
const Server = require('boardgame.io/server').Server;
const TicTacToe = require('./game');
const server = Server({ games: [TicTacToe] });
server.app.use(KoaStatic(path.join(__dirname, '../build')));
server.run(8000);

Then build & start server:

npm run build
npm install -D babel-preset-zero babel-cli
npx babel-node --presets zero src/server.js

Navigating to http://localhost:8000/ does load the app, but the message says "Disconnected!" below the player numbers. No errors on the browser console or network logs.

The same happens even if I run separate servers (after commenting out build path code from server.js and setting multiplayer to server: 'localhost:8000' in multiplayer.js).

I tried to debug extensively numerous times to see if I'm missing something. But couldn't find anything.

Also, the multiplayer documentation has import Client from 'boardgame.io/react'; in the beginning, it should really be import { Client } ....

viranch commented 6 years ago

Just discovered that changing the first 4 lines of server.js (in my previous comment) to following makes the whole thing work, in both single & separate server modes:

import path from 'path';
import KoaStatic from 'koa-static';
import { Server } from 'boardgame.io/server';
import TicTacToe from './game';

Not sure how this should matter.

nicolodavis commented 6 years ago

That's really weird. If you have time, can you upload your not working code to a repo so I can try to reproduce? The change from require to import shouldn't make a difference.

viranch commented 6 years ago

Here: https://github.com/viranch/tic-tac-toe

I've put 2 servers, src/server_that_works.js and src/server_doesnt_work.js. I don't get the "Disconnected!" message anymore with not-working server but the moves still don't reflect on the other player.

simplyjane commented 6 years ago

import path from 'path'; ^^^^^^

SyntaxError: Unexpected token import ... I have the same issue. how can i fix it? download bunch of plugin. wont work

nicolodavis commented 6 years ago

What's the command that you ran? You should be using babel-node.

nicolodavis commented 6 years ago

@viranch Your code doesn't follow the instructions in the documentation. In your version, you just need to change the import line in sever_doesnt_work.js to:

const TicTacToe = require('./game').default;

You will notice that the documentation actually uses a named export and doesn't run into this problem.

nicolodavis commented 6 years ago

Assuming that there are no further problems, I'm going to close this. Feel free to re-open if you find any issues in the future (and also to continue discussion here).

viranch commented 6 years ago

@nicolodavis Oh you're right! Thanks for all the work and help. May be setup a Slack team or something for ad-hoc questions/help instead of having to raise a Github issue?

Stefan-Hanke commented 6 years ago

@viranch There are two gitter rooms, discussion takes place in the General one.

MInner commented 6 years ago

Hi,

I am also struggling with setting up a proper websocket server. I have the following server.js

import path from 'path';
import KoaStatic from 'koa-static';
import { Server } from 'boardgame.io/server';
import TicTacToe from './Game';

console.log(TicTacToe);

const server = Server({ games: [TicTacToe] });
const buildPath = path.join(__dirname, '../build');
server.app.use(KoaStatic(buildPath));
server.run(9000);

that prints

{ name: 'default',
  setup: [Function: setup],
  playerView: [Function: playerView],
  flow: 
   { ctx: [Function: ctx],
     init: [Function: init],
     canUndoMove: [Function: canUndoMove],
     eventNames: [ 'endTurn', 'changeActionPlayers' ],
     processMove: [Function: processMove],
     processGameEvent: [Function: processGameEvent],
     optimisticUpdate: [Function: optimisticUpdate],
     canMakeMove: [Function: canMakeMove] },
  seed: 'jg2yi7ew',
  moveNames: [ 'clickCell' ],
  processMove: [Function: processMove] }

so it must be exported properly in /Game.js.

but http://localhost:9000/ keeps returning only Not Found. Before that I was trying to set them up separately, but websocket server would silently receive connections and not reply anything. Could anyone point me towards possible causes of this behavior?

Thanks! Ben

MInner commented 6 years ago

Hi, does anyone read this?

philihp commented 6 years ago

@MInner yes of course :) perhaps it would help for someone to reproduce the error if you push up your repo for them to see? Feel free to ask on Gitter https://gitter.im/boardgame-io/General