Access the pre-built web client at https://0xvector.me/mmo-rpg to try out the game without building it yourself!
The server communicates with clients by establishing WebSocket connections.
The clients automatically joins the game after interacting with the game screen. Inactive clients (eg. closed browser) are kicked. Each new instance (eg. browser tab) established a new connection and is considered as a new client.
For now, you can run around the map and kill the slimes spawning. PvP is not yet implemented.
- use
WASD
to move around the map - press
<space>
to attack
- Install bun on your machine (also required for server) with
npm install -g bun
. - Clone with
git clone https://github.com/0xVector/mmo-rpg.git
, thencd mmo-rpg
- Run
bun install --production
here - Build the client with
bun run build
- Serve the client with
bun run client
The client is now running at http://localhost:8080/index.html
.
You can also try the pre-built client served by github pages.
See the respective guide.
- slime death animation
- player hp
make slimes follow players& deal damage- PvP
- redo some parts of attacking (player state sync feels especially fragile)
- knockback
- make attack animation less weird
- document the code better (so the generated docs are not so empty)
- deploy the static client to github pages
- more mobs
- attacking
- map generation
- attacking
- health
- playernames
- configurable settings (port etc.)
- draw own sprites
- split server and client to separate repositories
- save server state
- testing! (unit, possibly e2e - both client & server)
- migrate to the native WebSocket implementation of bun (better performance)
- lag mitigation (client-side prediction etc.)
- server side validation of all data (anticheat)
- better OOP structure (both client & server)
- richer entity inheritance etc.
- split up server service into game logic and server logic
- split up game manager in client
See server.
The client is written in TypeScript with Excalibur.js. It comes with a simple HTTP server that can be run with Bun or NodeJS to server the client page. It uses the native browser WebSocket implementation.
The client utilizes the common ExcaliburJS project structure. The main entrypoint is the game.ts
file, where the engine and all dependencies are instantiated.
Actors are all the moving parts in ExcaliburJS. Here, they are in an inheritance structure resembling that of server, but with its own important distinctions.
There are the entities, with the CustomEntity
base type, which defines the minimal properties of every entity (the main part is having an UUID, which is addressed as netId
in client to distinguish it from the internal ExcaliburJS actor id
). The most notable difference from the server implementation is that there are two different player classes. Player
is the base player and by default represents other players on the map. PlayerOwn
is the own, controllable player that inherits from Player
.
The second kind of actors are items, which is just a basic type for objects on the map, such as rocks. This is an area of future interest.
Only a single World
scene is used.
GameManager
is the manager class responsible for most of the communication, as well as game logic. It seems to be responsible for too many parts of the client logic and should be separated in the future into a communication and pure game part.
One of its main responsibilities is providing handlers for WebSocket request events. These events are a sort of a merge between the server request DTOs and internal events. They define the shape for inbound requests from the server, but are also used internally.
Its second responsibility is holding the game client state and providing some low-level methods allowing the parts with the higher level game logic to make changes to the state.
WSManager
is a class responsible for just the lowest-level communication on the WebSocket layer. It holds the WebSocket
instance of the underlying browser WebSocket implementation representing the client's connection to the server in its state, processes incoming requests and provides a way to register handlers for them.
See the typedoc here.
See the respective package.json
for now.
I used sprites from the free asset pack Mystic woods (thanks!).