Networking
Traditionally changing the network layer in MUDs is nigh impossible. But with Ranvier the server, like everything else, is event based and the core code has no opinions on what network layer is used.
This guide will walk through creating an example websocket networking bundle.
Note: There is already a websocket networking bundle available for you to use as well as a telnet networking bundle. See the Community Bundles page for a full list.
The Transport Stream¶
First we will have to create a custom TransportStream
to act as an adapter between the WebSocket
and Ranvier. To do
this inside your bundle directory create a folder called lib/
and in that folder let's create a file called
WebsocketStream.js
bundles/my-bundle/ lib/ WebsocketStream.js
In this file we will use the TransportStream
class provided by the core as the base for our adapter.
'use strict'; const { TransportStream } = require('ranvier'); /** * Essentially we want to look at the methods of WebSocket and match them to the * appropriate methods on TransportStream */ class WebsocketStream extends TransportStream { attach(socket) { super.attach(socket); // websocket uses 'message' instead of the 'data' event net.Socket uses socket.on('message', message => { this.emit('data', message); }); } /** * A WebSocket is writable if its readyState is 1 */ get writable() { return this.socket.readyState === 1; } write(...args) { if (!this.writable) { return; } // this.socket will be set when we do `ourWebsocketStream.attach(websocket)` this.socket.send(...args); } pause() { this.socket.pause(); } resume() { this.socket.resume(); } end() { // 1000 = normal close, no error this.socket.close(1000); } } module.exports = WebsocketStream;
Starting the Server¶
To actually start the server we'll want to create our server event script. We will need a third party Node library
called ws
so inside your bundle folder run npm init
to create a package.json file for your bundle then npm install
--save ws
.
bundles/my-bundle/ server-events/ websocket-server.js
'use strict'; // import 3rd party websocket library const WebSocket = require('ws'); // import core logger const { Logger } = require('ranvier'); // import our adapter const WebsocketStream = require('../lib/WebsocketStream'); module.exports = { listeners: { startup: state => function (commander) { // create a new websocket server using the port command line argument const wss = new WebSocket.Server({ port: commander.port }); // This creates a super basic "echo" websocket server wss.on('connection', function connection(ws) { // create our adapter const stream = new WebsocketStream(); // and attach the raw websocket stream.attach(ws); // this attaches out stream to the input events which handle direct input // from the player, everything from login to commands state.InputEventManager.attach(stream); stream.write("Connecting...\n"); Logger.log("User connected via websocket..."); // fire off the intro event to be handled by an input-event listener stream.emit('intro', stream); }); }, shutdown: state => function () { // no need to do anything special in shutdown }, } };
Enabling our bundle¶
Finally inside ranvier.json
in the root of the project add my-bundle
to this enabled bundles list and Bob's your
uncle, as they say. Completely rewriting the network layer of the game engine in less than 100 lines of code including
comments: not bad at all.