• Stars
    star
    420
  • Rank 103,194 (Top 3 %)
  • Language
    TypeScript
  • License
    ISC License
  • Created over 5 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Make P2P multiplayer browser games, no server hosting or synchronization code required. Powered by rollback netcode + WebRTC.

NetplayJS

Node.js CI npm

Make peer-to-peer WebRTC-based multiplayer games in JavaScript, no server hosting or network synchronization code required!

[CHECK OUT THE DEMOS]

Quick Start

Remix on Glitch

Here's how NetplayJS works:

  • You create your game within static HTML files.
  • You can use a variety of HTML5 game frameworks, including Three.js.
  • You can host your game anywhere (GitHub Pages, Itch.io, Glitch, and many more).

NetplayJS handles most of the complicated aspects of multiplayer game development, letting you create games almost as if they were local multiplayer games. Synchronization and matchmaking are handled automatically under the hood - and best of all you don't have to host any servers!

Let's make a very simple game. Create an HTML file and add the following script tag.

<script src="https://unpkg.com/[email protected]/dist/netplay.js"></script>

Now add this javascript code to the same HTML.

<script>
class SimpleGame extends netplayjs.Game {
  // In the constructor, we initialize the state of our game.
  constructor() {
    super();
    // Initialize our player positions.
    this.aPos = { x: 100, y: 150 };
    this.bPos = { x: 500, y: 150 };
  }

  // The tick function takes a map of Player -> Input and
  // simulates the game forward. Think of it like making
  // a local multiplayer game with multiple controllers.
  tick(playerInputs) {
    for (const [player, input] of playerInputs.entries()) {
      // Generate player velocity from input keys.
      const vel = input.arrowKeys();

      // Apply the velocity to the appropriate player.
      if (player.getID() == 0) {
        this.aPos.x += vel.x * 5;
        this.aPos.y -= vel.y * 5;
      } else if (player.getID() == 1) {
        this.bPos.x += vel.x * 5;
        this.bPos.y -= vel.y * 5;
      }
    }
  }

  // Normally, we have to implement a serialize / deserialize function
  // for our state. However, there is an autoserializer that can handle
  // simple states for us. We don't need to do anything here!
  // serialize() {}
  // deserialize(value) {}

  // Draw the state of our game onto a canvas.
  draw(canvas) {
    const ctx = canvas.getContext("2d");

    // Fill with black.
    ctx.fillStyle = "black";
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    // Draw squares for the players.
    ctx.fillStyle = "red";
    ctx.fillRect(this.aPos.x - 5, this.aPos.y - 5, 10, 10);
    ctx.fillStyle = "blue";
    ctx.fillRect(this.bPos.x - 5, this.bPos.y - 5, 10, 10);
  }
}

SimpleGame.timestep = 1000 / 60; // Our game runs at 60 FPS
SimpleGame.canvasSize = { width: 600, height: 300 };

// Because our game can be easily rewound, we will use Rollback netcode
// If your game cannot be rewound, you should use LockstepWrapper instead.
new netplayjs.RollbackWrapper(SimpleGame).start();
</script>

And voila - we've made a real-time networked game with rollback netcode and client-side prediction.

Overview

NetplayJS is a framework designed to make the process of creating multiplayer browser games simple and fun. It consists of several different components.

  • netplayjs-server - The matchmaking and signaling server. You can host your own or use the public instance.
  • (WIP) netplayjs-netcode - Implementations of rollback netcode and lockstep netcode.
  • (WIP) netplayjs-connection - The client side code that communicates with the matchmaking server to establish connections.
  • netplayjs - A prototyping framework that lets you rapidly create multiplayer games.
  • netplayjs-demos - A collection of demos built in netplayjs to show off how to use it.

Installation

For simple usage, you can include NetplayJS directly from a script tag in an HTML file.

<script src="https://unpkg.com/[email protected]/dist/netplay.js"></script>

For larger projects, you should install NetplayJS from npm and bundle it with your application using Webpack or a similar module bundler.

npm install --save netplayjs

I also highly recommend that you use it with TypeScript, though this is not required. The examples following will be in TypeScript.

Usage

To create a game using NetplayJS, you create a new class that extends netplayjs.Game.

  • This class should implement functions for initializing, updating, and drawing the game.
  • It should implement functions for serializing / deserializing the state (more info in the next section).
  • It should contain static properties used to configure the netcode (see here).
class MyGame extends netplayjs.Game {
  // NetplayJS games use a fixed timestep.
  static timestep = 1000 / 60;

  // NetplayJS games use a fixed canvas size.
  static canvasSize = { width: 600, height: 300 };

  // Initialize the game state.
  constructor(canvas: HTMLCanvasElement, players: Array<NetplayPlayer>) {}

  // Tick the game state forward given the inputs for each player.
  tick(playerInputs: Map<NetplayPlayer, DefaultInput>): void {}

  // Draw the current state of the game to a canvas.
  draw(canvas: HTMLCanvasElement) {}

  // Serialize the state of a game to JSON-compatible value.
  serialize(): JsonValue {}

  // Load the state of a game from a serialized JSON value.
  deserialize(value: JsonValue) {}
}

You can now start the game by passing your game class to one of several wrappers.

  • new LocalWrapper(MyGame).start(); - Runs mutiple instances of the game in the same browser page. Use for local testing and rapid iteration.
  • new RollbackWrapper(MyGame).start(); - Runs the game using rollback netcode. Use for game states that can be rewound and replayed.
  • new LockstepWrapper(MyGame).start(); - Runs the game using lockstep netcode. Use for game states that can't be rewound.

Game State Serialization

The client-side prediction and rewind capabilities of netplayjs are based off of the ability to serialize and deserialize the state of the game. In the quickstart example above, we let the autoserializer take care of this. For most games, however, you will need to implement your own logic. You can do this by overriding Game.serialize and Game.deserialize in your subclass.

If you cannot serialize the game state, you can still use NetplayJS, but you will need to use Lockstep netcode, rather than predictive netcodes like Rollback, and you need to mark your game as deterministic.

NetplayPlayer

A NetplayPlayer represents one player in a game. NetplayPlayer.getID() returns an ID that is stable across each network replication of the game.

DefaultInput

NetplayJS games are synchronized by sending inputs across a network. DefaultInput automatically captures and replicates keyboard events, mouse events, and touch events.

FAQ

Does NetplayJS require game code to be deterministic?

NetplayJS does not require game code to be deterministic, but is more efficient if it is. By default, NetplayJS corrects for drift by having one player (the host) send authoritative state updates to the others. NetplayJS will skip these updates if you explicitly mark your game as being deterministic.

Whether or not JavaScript operations are cross-platform deterministic is a difficult question. Here's what I know:

  • Integer arithmatic can be assumed to be deterministic.
  • In WASM code, floating point operations are cross-platform deterministic, with the exception of the bit pattern of NaN values.
    • This means that WASM physics engines like Ammo.js can be assumed to be deterministic.
  • Anything else is potentially up in the air.

Can NetplayJS be used with Unity, Godot, PlayCanvas, etc?

NetplayJS works best with lightweight game frameworks. The reason is we need game state to be kept in one place, so that it's easy to replicate across the network

Other engines tend to have complicated entity systems with their own state management, and wont fit nicely into the NetplayJS state model.

One way to get around this is to essentially create an invisible NetplayJS game that runs in the background and describes the actual game logic. Then, on draw(), instead of drawing directly, use the current game state to update the entities in your game engine's scene.

Assets Used from Other Projects

This repo contains code and assets from other open source projects.

More Repositories

1

NeuralKart

A Real-time Mario Kart 64 AI using ConvNets.
Lua
663
star
2

blog-cells

Add interactive code snippets to any blog or webpage.
TypeScript
330
star
3

Dygra

A real-time non-euclidean ray-tracer.
C++
94
star
4

ipfs-share

A simple IPFS-powered Pastebin / Image Host / File Sharing application.
HTML
74
star
5

showdownbot

A Pokemon Showdown battling AI.
JavaScript
68
star
6

love-ide

Tools for programming LÖVE games in Atom.
JavaScript
56
star
7

ups

Command line tools for manipulating UPS binary patches, written in Go.
Go
30
star
8

fault

An obstacle avoidance game for Android and iOS.
C
26
star
9

Azathoth

An editor for non-euclidean worlds.
Python
20
star
10

binary-inspector

Web-based inspectors for packets and binary files.
TypeScript
19
star
11

love-console

An easy to integrate in-game console for Love2D games.
Lua
15
star
12

snippets-editor

Manage your Atom snippets using a visual interface.
JavaScript
10
star
13

marble-mouse

A Super Monkey Ball-inspired game made using THREE.js and CANNON.js.
TypeScript
9
star
14

codec2-emscripten

The Codec 2 speech codec, compiled to WASM using Emscripten.
JavaScript
9
star
15

Hnefatafl

Android Hnefatafl game using Google Play Games Services.
Java
6
star
16

sox-emscripten

WASM port of SoX (Sound eXchange) using Emscripten, for use in the browser.
JavaScript
6
star
17

hain-plugin-chrome-bookmarks

A Hain plugin for searching Chrome bookmarks.
JavaScript
6
star
18

todo-list

Find TODOs, NOTEs, and FIXMEs in your project. Sort by assignee and file.
JavaScript
4
star
19

Ulfhednar

A co-op bullet hell shooter, inspired by Norse mythology.
Lua
3
star
20

random-mbmbam

Listen to a Random MBMBAM epsiode.
HTML
3
star
21

pinboard-tools

Miscellaneous utilities for manipulating my Pinboard links.
Python
3
star
22

proctor

A horror game based on 3D-sound, created in Love2D.
Lua
3
star
23

misbehaving-receiver

Replicating the paper "TCP Congestion Control with a Misbehaving Receiver" for CS 244.
C
3
star
24

feedvid-live

A horror game with text-adventure inspired gameplay, created using Three.js and React.
TypeScript
3
star
25

protoworld

[WIP] A live object system for JavaScript, inspired by Self and Smalltalk.
JavaScript
3
star
26

love2d-template

My template for making games in LOVE2D.
Lua
2
star
27

got

[Incomplete] A VCS written in Go.
Go
2
star
28

github-network-analysis

GitHub network analysis for CS224W.
Python
2
star
29

RetroBoy

A cross-platform, GameBoy inspired, fantasy console.
Java
2
star
30

TheSixthSun

[Abandoned] A turn-based, asynchronous, space strategy game that takes place both in space, and across the surface of planets.
C#
2
star
31

Math4D

A tool for visualizing a variety of mathematical constructs, including 3 and 4-variable functions.
Python
2
star
32

linter-luaparse

Linter for Atom that finds Lua syntax errors.
JavaScript
2
star
33

dumblisp

A lisp interpreter written in pure C.
C
2
star
34

hump.timer.actions

Composable actions, powered by Hump.Timer.
Lua
1
star
35

marble-mouse-custom-mapping

Marble Mouse custom mapping guide.
1
star
36

MemChewIonic

Ionic-based client for MemChew.
JavaScript
1
star
37

MemChewAndroid

MemChew Android client.
Java
1
star
38

lolreplay

Python code for parsing League of Legends replay files.
Python
1
star
39

libsrtp-js

[Incomplete] TypeScript binding for libSRTP, using WebAssembly.
TypeScript
1
star
40

jamestown-ai

(Incomplete) AI bot for the bullet hell game Jamestown.
Python
1
star
41

BlueScreen

A first-person stealth / 6DOF shooter mashup. Created in Unity in 48 hours for Ludum Dare 30.
C#
1
star
42

cs234-project

Python
1
star
43

escape-template-string

Escape a string so that it can be eval-ed in as a template literal.
JavaScript
1
star
44

hyperclick-love

A Hyperclick provider for LÖVE.
JavaScript
1
star
45

tldr-ml

The TLDR Machine Learning dictionary.
HTML
1
star
46

love-ide-data

Shared data between autocomplete-love and hyperclick-love.
Lua
1
star
47

user-scripts

User scripts that I use.
JavaScript
1
star
48

ws-relay

A simple WebSocket relay client and server. Can be used for WebRTC signaling, or to send data directly between browsers.
TypeScript
1
star
49

snp

[WIP] An enet-like UDP reliability layer for NodeJS, KaiOS, and other JavaScript environments.
TypeScript
1
star
50

topkappa

Vote on Twitch chat messages in real-time.
JavaScript
1
star