123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- const Server = {};
- const appConfig = {};
- const express = require('express');
- const WebSocketServer = require('ws').Server;
- const wrtc = require('wrtc');
- const Peer = require('simple-peer')
- const FPS = 60;
- const { SnapshotInterpolation } = require('@geckos.io/snapshot-interpolation');
- const SI = new SnapshotInterpolation(FPS)
- const path = require('path');
- const view = require('view');
- let wss;
- let peers = {};
- Server.listen = async function listenServer ({ root }) {
- const app = express();
- const server = require('http').Server(app);
- app.use(express.static(path.resolve(root + '/../public'), { extensions: ['html'] }));
- if (appConfig.cacheView) {
- // cached view
- console.log('using cached view');
- let _view = await viewCreate( { path: root + "/../view" });
- app.use(view.middle({view: _view}));
- } else {
- // uncached view
- console.log('using uncached view');
- app.use(function(req, res, next){
- view.create( { path: root + "/../view" }, function(err, _view){
- req.resource = {
- params: {}
- };
- return view.middle({view: _view})(req, res, next)
- });
- });
- }
- createWebsocketServer();
- server.listen(3000, function () {
- console.log(`Listening on ${server.address().port}`);
- });
- };
- // TODO: create new peer for each connected client...
- let players = [
- 'PLAYER_1',
- 'PLAYER_2',
- 'PLAYER_3',
- 'PLAYER_4'
- ];
- function createPeer (playerName) {
- let peer = new Peer({ wrtc: wrtc });
- peer.on('data', function(data){
- let Things = require('../../lib/Geoffrey/Things');
-
- //console.log('peer.data', data.toString());
- // peer.send('test');
- // TODO: add server-side game processing here
- // TODO: only rebroadcast game-state, no out of band messages
- /*
- let msg;
- for (let id in peers) {
- if (peers[id].writable) {
- peers[id].send(data.toString())
- }
- }
- return;
- */
- try {
- msg = JSON.parse(data);
- Things[msg.name].inputs = msg.inputs;
- // console.log('setting', msg.name, Things[msg.name].inputs)
- } catch (err) {
- console.log('parsing error', err)
- }
- });
- peer.on('signal', function(data){
- console.log('peer.signal', data);
- wss.clients.forEach(function each(client) {
- console.log('found client', client.id);
- client.send(JSON.stringify(data));
- });
- });
- peer.on('close', function () {
- console.log("WEBRTC DISCONNECT");
- players.unshift(playerName);
- });
- peer.on('connect', function () {
- console.log('connect');
- // TODO: random x / y
- let startingLocation = {
- x: 150 + players.length * 10,
- y: 250 + players.length * 10
- };
- console.log('CREATING NEW PLAYER', playerName)
- let p1 = Thing.create({
- name: playerName,
- x: startingLocation.x,
- y: startingLocation.y,
- texture: 'mib-caddy'
- });
- p1.setDepth(10);
- Behavior.attach('isMIBCaddy', p1, {
- health: 10
- });
- Behavior.attach('hasScreenWrap', p1);
- });
- return peer;
- }
- function createWebsocketServer () {
- wss = new WebSocketServer({port: 3434});
- console.log('starting websocket server on port 3434');
- createHeadlessGame();
- wss.on('connection', function(ws) {
- // on a websocket connection, get the client ready for a webrtc peering signal with webrtc server
- // TODO: uuid?
- ws.id = new Date().getTime();
- ws.on('close', function(message) {
- // console.log("WS DISCONNECT HAPPENED", ws.id)
- });
- let playerName;
- ws.on('message', function(message) {
- var data = JSON.parse(message);
- console.log('received: %s', message, data);
- /*
- Perform a handshake here with the client
- Now that the client has connected to the game, we need to determine if they will play
- Certain settings would be chosen here such as name
- */
- if (data.type === 'joinGame') {
- if (players.length === 0) {
- // TODO: send error back to client
- console.log('will not allow more than N players. should have stopped before this connected.')
- return;
- }
- // console.log('current available players', players)
- playerName = players.shift();
- // console.log('accepted game for', playerName)
- ws.send(JSON.stringify({ type: 'acceptedGame', playerName: playerName }));
- return;
- }
- if (data.type === 'signal') {
- // console.log('sending signal for', playerName);
- // this won't work as expected for reconnect, this.id is always new
- if (peers[this.id]) {
- let peer = peers[this.id];
- peer.signal(data.payload)
- } else {
- let peer = peers[this.id] = createPeer(playerName);
- peer.signal(data.payload)
- }
- }
- });
- });
- }
- require('@geckos.io/phaser-on-nodejs')
- const Phaser = require('phaser');
- const Game = require('../../lib/Geoffrey/Game');
- const Thing = require('../../lib/Geoffrey/Thing');
- const Behavior = require('../../lib/Geoffrey/Behavior');
- Behavior.mode = 'server';
- // TODO: add headless server, have it broadcast it's state to each client as the authority
- function createHeadlessGame () {
- var worldWidth = 1024;
- var worldHeight = 768;
- // set the fps you need
- global.phaserOnNodeFPS = FPS // default is 60
- // prepare the config for Phaser
- const config = {
- type: Phaser.HEADLESS,
- width: worldWidth,
- height: worldHeight,
- banner: false,
- audio: false,
- fps: {
- target: FPS
- },
- scene: {
- preload: Game.preload,
- create: Game.create,
- update: Game.update,
- render: function(){}
- },
- physics: {
- default: 'matter',
- matter: {
- debug: false, // TODO: use config
- gravity: { y: 0, x: 0 },
- plugins: {
- attractors: true
- }
- }
- }
- }
- let game = global.game = new Phaser.Game(config);
- Game.servermode = true;
- Game.bindUpdate(function(game){
- const snapshot = SI.snapshot.create(game.gamestate.currentState);
- SI.vault.add(snapshot);
- for (let id in peers) {
- //console.log('state', game.gamestate.currentState);
- //console.log('peers[id]', peers[id])
- if (peers[id].writable) {
- try {
- peers[id].send(JSON.stringify(snapshot));
- } catch (err) {
-
- }
- }
- }
- return
- for (let id in peers) {
- //console.log('state', game.gamestate.currentState);
- //console.log('ppppp', peers[id])
- if (peers[id].writable) {
- try {
- peers[id].send(JSON.stringify(game.gamestate.currentState));
- } catch (err) {
- }
- }
- }
- });
- Game.bindCreate(function(){
- game.peers = peers;
- let level0 = Thing.create({
- name: 'sector-0',
- type: 'server-only'
- });
- Behavior.attach('isOnlineLevel', level0);
- Behavior.attach('hasStateManager', level0);
- });
- }
- module.exports = Server;
|