Skip to content

Commit 0935318

Browse files
authored
Merge pull request #105 from TheNexusCity/master
Add multiplayer docs, a little org and fix vroid link
2 parents 149cc6b + ef5eed1 commit 0935318

File tree

9 files changed

+14946
-88
lines changed

9 files changed

+14946
-88
lines changed

docs/create/overview.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,6 @@ In addition, Webaverse supports traditional 3D models. Any content creation plat
2929

3030
**I want to package my creations from...**
3131

32-
- [VRoid Studio](./import-vroid-studio.md)
32+
- [VRoid Studio](./import-vroid.md)
3333
- [Blender](./import-blender.md)
3434
- [MagicaVoxel](./import-magicavoxel.md)

docs/engineering/graves-notes/graves-notes-intro.md

-12
This file was deleted.

docs/engineering/graves-notes/graves-notes-unsorted.md docs/engineering/miscellaneous/graves-notes-unsorted.md

-7
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,6 @@ const {offset, duration} = audioSpec;
8484

8585
# Systems/Algorithms
8686

87-
## CRDT theory
88-
89-
Conflict-free Replicated Data types are the technology that webas multiplayer system is based on. Necessary knowledge for anyone who might work on multiplayer
90-
91-
- Massive overview of CRDTs from creation to optimization. https://bartoszsypytkowski.com/the-state-of-a-state-based-crdts/
92-
93-
9487
## L-system Theory
9588

9689
L-systems are used to effiently store and generate fractals like plants and crystal structures. This will be an effective way to generate plants for the game world.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
---
2+
id: multiplayer-overview
3+
title: Multiplayer Overview
4+
---
5+
6+
Some notes on the current state of multiplayer development, as well as some quick what-you-need-to-know to get started with developing for multiplayer
7+
8+
## What can I do in multiplayer?
9+
- Jump seamlessly between single and multiplayer
10+
- Switch my avatar, either from an avatar in the world or from the menus
11+
- Speak with my voice
12+
- Switch my voice pack and voice engine
13+
- Have my character's mouth respond to my voice with mouth movement
14+
- Change my name, and see other user's names as a nameplate over their head
15+
- Chat, and have my character speak whatever I chat
16+
- Drop items into the world and use them
17+
- Drop pets and vehicles into the world and activate them
18+
- Pick up weapons and damage mobs
19+
- Die and respawn at current world spawn point
20+
21+
## Important Files
22+
The important, high-touch documents for multiplayer are:
23+
- avatars/avatars.js
24+
- app-manager.js
25+
- character-controller.js
26+
- chat-manager.js
27+
- players-manager.js
28+
- webaverse.js
29+
- universe.js
30+
- world.js
31+
32+
## Where do I start?
33+
The main entrypoint to the Webaverse app is the Webaverse class in webaverse.js -- this is where everything gets set up and the main loop starts. The world, local and remote players are updated from here.
34+
35+
Multiplayer starts from enterWorld in **universe.js**
36+
37+
## Key Concepts
38+
39+
#### CRDTs
40+
Webaverse is a peer-authoratative system. Objects in the world can be moved and manipulated by peers, and these changes will be reflected by the server out to other peers. It is simple in theory, but in practice this can potentially lead to conflicts where peers don't agree on where something is, or *what* it is.
41+
42+
**Conflict-free replicated data types** or CRDTs are a set of data structures which can be merged in such a way that any inconsistencies are eventually resolved, and all peers will have the same document state. Additional reading can be found here:
43+
[Conflict-free_replicated_data_type](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type)
44+
45+
#### Websockets, WebRTC and WSRTC
46+
Previously, Webaverse used a server-authoritative WebRTC implementation for voice and data. However, this has significant scalability issues and was generally not fun to work with. The current implementation uses pure WebSockets. In the future we will adopt WebTransport and turn on AV1 and WebCodecs once they are well-supported in Safari and Firefox.
47+
48+
## Multiplayer-Related Packages
49+
50+
#### zjs
51+
zjs is a purpose-built API-compatible clone of yjs for multiplayer realtime games. Most of the concepts and documentation for yjs applies, so please read before attempting to work on the multiplayer.
52+
53+
The TL;DR is that zjs is a CRDT-backed document store. When changes to the Doc object occur, zjs will handle any conflicts and then send change events with the final state at that moment to all connected clients.
54+
55+
Any object in Webaverse which has a bound state -- players, app managers and tracked apps -- will be subscribed to these change events. This is done using the "observer" pattern, and zjs maps and arrays are observable objects.
56+
57+
#### wsrtc
58+
Actual socket communication is handled by wsrtc, another webaverse project, which moves app data and voice packets over websockets. wsrtc is heavily bound to zjs. Messages received from peers are passed into the server's own zjs instance, where conflicts are handled and final state is passed back out to peers.
59+
60+
An important note about wsrtc is that this will eventually be replaced with redis or a similar distribute key-value store and possibly phased out entirely.
61+
62+
#### totum / metaversefile
63+
Totum (formerly metaversefile, and still called this everywhere) is an API for Webaverse to load composable apps and for said apps to communicate with the Webaverse core. The metaversefileApi contains useful helper functions for initializing and interacting with metaverse apps, or for getting important core data into those apps. A good example would be accessing the local player's app manager, or checking if the scene is loaded.
64+
65+
## Development
66+
#### Player Controllers
67+
The character-controller.js file holds the LocalPlayer, RemotePlayer and the Player base class. Everything related to character state, including transform, movement, actions, wearing, etc is here. NPCs are also a type of player
68+
69+
The actual visual avatar display is largely handled by the Avatars class in the avatars/avatars.js file. The character controller sets the velocity of it's avatar class instance, which then handles the animation update.
70+
71+
Player objects are held in the PlayersManager class in players-manager.js, this is initialized when the client connects to a room. The PlayersManager object is a zjs map of player objects, which are also zjs maps, containing component information that might change. Players sync most things via "actions", but also have information like name, instance ID and their chosen voice engine and voice pack.
72+
73+
Player objects have a playerId, and are stored in the playersArray of the PlayersManager class instance
74+
75+
The instanceId of the avatar can be found inside the player map's avatar key, or through calling CharacterController.getAvatarState()
76+
77+
#### Apps
78+
The AppManager class (app-manager.js) handles setting up, tearing down and updating apps. Apps can be avatars, wearables, buildings, anything that lives in the world with the player. All AppManagers are bound to state, which can be local or networked. world.connectState sets up all of the AppManager bindings locally, while world.connectRoom sets up the bindings globally.
79+
80+
When an app is loaded, it is bound to a map or array in zjs. Each app has an instanceId, which is a 5-digit alphanumeric hash. The instanceId of an object on one client should match the next.
81+
82+
The instanceId is a useful key for getting the app. Each app has a list of components, a contentId and an instanceId (which should be unique).
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
id: multiplayer-stack-flow
3+
title: Multiplayer Stack Flow
4+
---
5+
6+
This is the stack-flow of initialization calls and event responses. This is subject to change and should be updated to UML.
7+
8+
### App.jsx Initialization
9+
> universe.js > enterWorld # user pressed multiplayer button or went to multiplayer room
10+
>> world.js > connectRoom()
11+
>>> players-manager.js > playersManager.bindState # start listening for players added and removed to this array
12+
>>>> players-manager.js > bindState.observe(**observePlayersFn**)
13+
14+
>> world.js > connectRoom()
15+
>>> character-controller.js > localPlayer.bindState # Start listening for changes to this player
16+
>>>> character-controller.js > bindState.observe(**observeAvatarFn**) # Listen for changes to the avatar
17+
>>>>> character-controller.js > localPlayer.attachState
18+
>>>>>> app-manager.js > appManager.bindState # Listen to changes to individual apps
19+
>>>>>>> app-manager.js > bindState.observe(**observeAppsFn**)
20+
21+
### Observer Event Handlers
22+
player **observeAvatarFn**
23+
> character-controller.js > **observeAvatarFn** > syncAvatar()
24+
>> character-controller.js > **observeAvatarFn** > transplantApp()
25+
26+
appManager **observeAppsFn**
27+
> (respond to added and removed events on apps)
28+
29+
app-manager.js **observeTrackedAppFn**
30+
> (if event contains transform update, update app transform)
31+
32+
### Remote Player
33+
34+
players-manager.js **observePlayersFn**
35+
> (remote player joins) > new RemoterPlayer()
36+
>> character-controller.js > remotePlayer.bindState
37+
>>> character-controller.js > bindState.observe(**observeAvatarFn**)
38+
>>>> character-controller.js > remotePlayer.attachState
39+
>>>>> app-manager.js > appManager.bindState
40+
>>>>>> app-manager.js > bindState.observe(**observeAppsFn**)

docs/engineering/wsrtc/wsrtc-quickstart.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ title: WSRTC Quick Start
77

88
## Introduction
99

10-
WSRTC (WebSockets RealTime Communication) is part of a multi-room system that uses binary websocket messages to transfer y.js state across the network. Combined with the World and Universe systems, that's how multiplayer data is updated within the App.
10+
WSRTC (WebSockets RealTime Communication) is part of a multi-room system that uses binary websocket messages to transfer zjs state across the network. Combined with the World and Universe systems, that's how multiplayer data is updated within the App.
1111

1212
Wsrtc also uses web codecs to perform voice encoding and decoding and as well as some spectrum analysis for doing things like animating the mouth flaps of the avatar/rig.
1313

docs/engineering/zjs/zjs-overview.md

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
---
2+
id: zjs-quickstart
3+
title: ZJS Quickstart
4+
---
5+
6+
# Overview
7+
zjs is a purpose-built API-compatible clone of yjs for multiplayer realtime games. Most of the concepts and documentation for yjs applies, so please read before attempting to work on the multiplayer.
8+
9+
The TL;DR is that zjs is a CRDT-backed document store. When changes to the Doc object occur, zjs will handle any conflicts and then send change events with the final state at that moment to all connected clients.
10+
11+
Any object in Webaverse which has a bound state -- players, app managers and tracked apps -- will be subscribed to these change events. This is done using the "observer" pattern, and zjs maps and arrays are observable objects.
12+
13+
## Where Do I Start for Development?
14+
If you are going to work on zjs you should start by reading through the tests. For any work you do, please write new tests and verify that they work.
15+
16+
#### CRDTs
17+
Webaverse is a peer-authoratative system. Objects in the world can be moved and manipulated by peers, and these changes will be reflected by the server out to other peers. It is simple in theory, but in practice this can potentially lead to conflicts where peers don't agree on where something is, or *what* it is.
18+
19+
**Conflict-free replicated data types** or CRDTs are a set of data structures which can be merged in such a way that any inconsistencies are eventually resolved, and all peers will have the same document state. Additional reading can be found here:
20+
[Conflict-free_replicated_data_type](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type)
21+
22+
#### zjs document hierarchy
23+
24+
Z.Doc
25+
- AppManager.appsArray -- all apps in the world
26+
- PlayersManager.playersArray -- a list of all playerMap objects
27+
-- CharacterController.playerMap -- all the data synced about the player, including playerId, apps and transform
28+
-- CharacterController.avatarmap (getAvatarState) -- A map of avatar data
29+
30+
Here is an example of an app stored as a Z.Map
31+
```json
32+
{
33+
"instanceId": "rum6g", // shared by all users
34+
"contentId": "https://webaverse.github.io/silsword/",
35+
"transform": [ -6, 0.5, 12, 0, 0, 0, 1, 1, 1, 1, 0 ],
36+
"components": "[]"
37+
}
38+
```
39+
40+
Here is an example of a player stored as a Z.Map -- the player has an avatar and is holding a sword
41+
```js
42+
const examplePlayer = {
43+
"playerId": "GoK3g",
44+
"avatar": { "instanceId": "qgboft" },
45+
"transform": {
46+
"0": -1.3072199821472168, // position x
47+
"1": 1.2576431035995483, // y
48+
"2": 6.1084885597229, // z
49+
"3": 0, // quaternion x
50+
"4": 0.10555386543273926, // y
51+
"5": 0, // z
52+
"6": 0.9944136142730713, // w
53+
"7": 16.66699981689453 // time delta
54+
},
55+
"actions": {
56+
"e": [
57+
{
58+
"type": "wear",
59+
"instanceId": "nxAup", // reference to the silsword user is holding
60+
"actionId": "Hgos0"
61+
}
62+
],
63+
"i": [ "bafb82" ]
64+
},
65+
"apps": {
66+
"e": [
67+
{ // avatar
68+
"instanceId": "qgboft",
69+
"contentId": "./avatars/scillia_drophunter_v15_vian.vrm",
70+
"transform": {
71+
"0": 0, // position x
72+
"1": 0, // y
73+
"2": 0, // z
74+
"3": 0, // quaternion x
75+
"4": 0, // y
76+
"5": 0, // z
77+
"6": 1, // w
78+
"7": 1, // scale x
79+
"8": 1, // scale y
80+
"9": 1, // scale z
81+
"10": 0 // time delta
82+
},
83+
"components": "[]"
84+
},
85+
{
86+
"instanceId": "nxAup",
87+
"contentId": "https://webaverse.github.io/silsword/",
88+
"transform": {
89+
"0": -0.9813549518585205, // position x
90+
"1": 1.536096215248108, // y
91+
"2": 6.172163963317871, // z
92+
"3": 0.9454419016838074, // quaternion x
93+
"4": -0.30134329199790955, // y
94+
"5": -0.11808272451162338, // z
95+
"6": 0.037259675562381744, // w
96+
"7": 1, // scale x
97+
"8": 1, // scale y
98+
"9": 1, // scale z
99+
"10": 0 // time delta
100+
},
101+
"components": "[]"
102+
}
103+
],
104+
"i": [ "952bde", "808f75" ]
105+
}
106+
}
107+
```

0 commit comments

Comments
 (0)