Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
325 changes: 292 additions & 33 deletions content/2.docs4devs/9.netplay.md
Original file line number Diff line number Diff line change
@@ -1,46 +1,305 @@
# Netplay
# EmulatorJS Netplay Server Setup Guide

The old version of netplay that works versions prior to 4.0 (version 3.0) is really buggy and not recommended unless you need to.
Step-by-step instructions to set up your own EmulatorJS netplay server.

::alert{type="danger"}
::list{type="danger"}
- Netplay is currently **not supported**. Any bugs will not be fixed. A netplay re-write is being worked on.
::
::
## Prerequisites

## To add to your site
Before beginning, ensure you have **Node.js** installed on your system:

1. Set a game id in the javascript config
```js
EJS_gameID = 1; //Id needs to be unique per game in your website!
```
1. Visit the [official Node.js website](https://nodejs.org/)
2. Download the **LTS (Long-Term Support)** version for your operating system
3. Run the installer and accept the default settings

2. At the moment, netplay requires the old cores. To do this you must add this line to your code.
```js
EJS_oldCores = true;
```
## Server Implementation

**These 2 steps will add netplay to your website!**
### Server Code

## To host your own server:
This will be used later:

1. Clone the EmulatorJS-netplay repository
```sh
git clone https://github.com/EmulatorJS/EmulatorJS-netplay-old.git
```
```javascript
const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const cors = require('cors');

2. Install nodejs dependencies
```sh
npm install
```
const app = express();
const server = http.createServer(app);

// Use CORS to allow connections from any origin
app.use(cors());

const io = socketIo(server, {
cors: {
origin: "*", // Allows connections from any website or application. Update as needed.
methods: ['GET', 'POST'],
},
});

const PORT = 3000; // The default port for the server. Change as needed.
let rooms = {};

setInterval(() => {
for (const sessionId in rooms) {
if (Object.keys(rooms[sessionId].players).length === 0) {
delete rooms[sessionId];
console.log(`Cleaned up empty room ${sessionId}`);
}
}
}, 60000);

io.on('connection', (socket) => {
console.log(`User connected: ${socket.id}`);

socket.on('open-room', (data, callback) => {
const { sessionid: sessionId, userid: playerId, room_name: roomName, game_id: gameId, player_name: playerName = 'Unknown' } = data.extra || {};
const maxPlayers = data.maxPlayers || 4;
const roomPassword = data.password || null;

if (!sessionId || !playerId) {
return callback ? callback('Invalid data: sessionId and playerId required') : null;
}
if (rooms[sessionId]) {
return callback ? callback('Room already exists') : null;
}

rooms[sessionId] = {
owner: socket.id,
players: { [playerId]: { ...data.extra, socketId: socket.id } },
roomName: roomName || `Room ${sessionId}`,
gameId: gameId || 'default',
password: roomPassword,
maxPlayers: maxPlayers,
};

socket.join(sessionId);
socket.sessionId = sessionId;
socket.playerId = playerId;

console.log(`Room "${roomName}" (${sessionId}) created by ${playerName}.`);
io.to(sessionId).emit('users-updated', rooms[sessionId].players);
if (callback) callback(null);
});

socket.on('join-room', (data, callback) => {
const { sessionid: sessionId, userid: playerId, player_name: playerName = 'Unknown' } = data.extra || {};

if (!sessionId || !playerId) {
return callback ? callback('Invalid data: sessionId and playerId required') : null;
}

3. start the server
```sh
npm run start
const room = rooms[sessionId];
if (!room) {
return callback ? callback('Room not found') : null;
}
if (room.password && room.password !== data.password) {
return callback ? callback('Incorrect password') : null;
}
if (Object.keys(room.players).length >= room.maxPlayers) {
return callback ? callback('Room full') : null;
}

room.players[playerId] = { ...data.extra, socketId: socket.id };
socket.join(sessionId);
socket.sessionId = sessionId;
socket.playerId = playerId;

console.log(`${playerName} joined room "${room.roomName}" (${sessionId})`);
io.to(sessionId).emit('users-updated', room.players);
if (callback) callback(null, room.players);
});

socket.on('leave-room', () => {
handleDisconnect(socket);
});

socket.on('disconnect', () => {
handleDisconnect(socket);
console.log(`User disconnected: ${socket.id}`);
});

// Forwarding game and WebRTC data
socket.on('webrtc-signal', (data) => {
if (data.target) {
io.to(data.target).emit('webrtc-signal', { ...data, sender: socket.id });
}
});

socket.on('data-message', (data) => {
if (socket.sessionId) {
socket.to(socket.sessionId).emit('data-message', data);
}
});

socket.on('snapshot', (data) => {
if (socket.sessionId) {
socket.to(socket.sessionId).emit('snapshot', data);
}
});

socket.on('input', (data) => {
if (socket.sessionId) {
socket.to(socket.sessionId).emit('input', data);
}
});
});

function handleDisconnect(socket) {
const { sessionId, playerId } = socket;
if (sessionId && playerId && rooms[sessionId]) {
const room = rooms[sessionId];
console.log(`Player ${playerId} left room ${sessionId}`);
delete room.players[playerId];

if (Object.keys(room.players).length === 0) {
delete rooms[sessionId];
console.log(`Room ${sessionId} closed - no players left`);
} else {
// If the owner left, assign a new owner
if (socket.id === room.owner) {
const newOwnerPlayerId = Object.keys(room.players)[0];
room.owner = room.players[newOwnerPlayerId].socketId;
console.log(`New owner for room ${sessionId}: ${room.owner}`);
}
io.to(sessionId).emit('users-updated', room.players);
}
}
}

server.listen(PORT, '0.0.0.0', () => console.log(`Netplay server running on port ${PORT}`));
```

You can then set your netplay server with the `EJS_netplayUrl` setting.
```js
EJS_netplayUrl = "URL HERE";
## Installation Instructions

### Windows Setup

1. **Create Server Directory**
- Create a new folder in an easily accessible location `(Example: D:\)`
- Name it something meaningful like `MyNetplayServer`

2. **Create Server File**
- Right-click inside the folder → **New****Text Document**
- Rename the file to `server.js` (ensure you change the `.txt` extension)
- Open the file with a text editor and paste the server code above
- Save and close the file

3. **Open Command Prompt**
- In the folder's address bar, type `cmd` and press **Enter**
- This opens Command Prompt in the correct directory

4. **Install Dependencies**
```bash
npm install express socket.io cors
```

5. **Start the Server**
```bash
node server.js
```

**Success message:** `Netplay server running on port 3000`

### Linux Setup

1. **Create Server Directory**
```bash
mkdir MyNetplayServer && cd MyNetplayServer
```

2. **Create Server File**
```bash
nano server.js
```
- Paste the server code into the editor
- Press **Ctrl+X**, then **Y**, then **Enter** to save and exit

3. **Install Dependencies**
```bash
npm install express socket.io cors
```

4. **Start the Server**
```bash
node server.js
```

**Success message:** `Netplay server running on port 3000`

## Website Integration

### In your javascript config file

1. **Set Unique Game ID**
```javascript
EJS_gameID = 1; // Must be unique per game on your website
```

2. **Configure Server Settings**
```javascript
EJS_netplayServer: 'https://yourIP:port#',
EJS_netplayICEServers: [
{ urls: 'stun:stun.l.google.com:19302' },
{ urls: 'stun:stun1.l.google.com:19302' },
{ urls: 'stun:stun2.l.google.com:19302' },
{ urls: 'stun:stun.nextcloud.com:3478' },
{ urls: 'turn:openrelay.metered.ca:80', username: 'openrelayproject', credential: 'openrelayproject' },
{ urls: 'turn:openrelay.metered.ca:443', username: 'openrelayproject', credential: 'openrelayproject' }
]
```

> **Note:** Add or remove ICE servers as needed for your specific requirements.
## Network Configuration

To make your server accessible to friends over the internet, you need to configure both your firewall and router.

### Firewall Configuration

#### Windows
1. Search for **"Windows Defender Firewall with Advanced Security"**
2. Navigate to **"Inbound Rules"**
3. Click **"New Rule..."**
4. Select **"Port"** and follow prompts to allow TCP traffic for port **3000**

#### Linux (using ufw)
```bash
sudo ufw allow 3000/tcp
```
<!-- EJS_netplayServer -->

### Port Forwarding

1. **Find Your Local IP Address**
- **Windows:** Run `ipconfig` in Command Prompt, look for "IPv4 Address" (e.g., `192.168.1.15`)
- **Linux:** Run `hostname -I` in terminal

2. **Access Router Admin Panel**
- Open web browser and navigate to router admin page (typically `192.168.1.1` or `192.168.0.1`)

3. **Configure Port Forwarding**
- Locate **"Port Forwarding"** or **"Virtual Server"** section
- Create new rule with these settings:
- **Application Name:** Netplay Server
- **External/Start Port:** 3000
- **Internal/End Port:** 3000
- **Protocol:** TCP
- **Device IP:** Your computer's local IP address
- Save the configuration

## Sharing Your Server

To allow friends to connect:

1. **Find Your Public IP**
- Google search: "what is my IP"
- Copy the displayed IP address

2. **Share Connection Details**
- Format: `[Your Public IP]:3000`
- Example: `123.45.67.89:3000`

## Troubleshooting

- Ensure Node.js is properly installed
- Verify firewall rules are correctly configured
- Check that port forwarding is properly set up on your router
- Confirm your public IP address is current as it likely rotates
- Make sure the server is running before attempting connections