The Metaserver organizes the many-to-many relationship between users and game servers. It enables a single account to work across all game servers, in a cryptographically secure way. The only thing users share with game servers is proof that they are registered and verified with the metaserver. Similarly, users can trust that the game servers listed by the metaserver are administrated by users that are registered and verified with the metaserver.
flowchart BT
m(("Metaserver"))
subgraph gservers [Game servers]
g0["Game server"]
g1["Game server"]
g2["Game server"]
end
subgraph users [Users]
u0["User"]
u1["User"]
u2["User"]
u3["User"]
end
users -->|User proof| gservers
users -->|Registration, login and server management| m
gservers -->|User proof verification| m
Install the dependencies in a virtual env:
- Prepare the env:
python -m venv env
- Activate it for you current shell session:
source env/bin/activate
- Install modules:
pip install -r requirements.txt
- Activate the virtual env (
source env/bin/activate
) - Set
export DEV=true
for verbose SQL logs. - Optionally set your
DATABASE_URL
environment variable to the back-end of your choosing. Otherwise (and during tests) it's in-memory SQLite. - Write tests using the test client in
tests/
and run them withpytest
. No need for throwaway cURL stuff and we end up with some tests too! - Implement things in
metaserver/
. - GOTO 4.
Autogenerating migrations:
alembic revision --autogenerate -m "My migration message"
Applying migrations:
alembic upgrade head
-
Clone the repository.
-
Configure the environment variables:
AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... AWS_DEFAULT_REGION=eu-central-1 DATABASE_URL="sqlite:///metaserver.db"
-
Run with
docker compose up --build --detach
flowchart TD
s(("User starts the game"))
p["Game uses credentials to request\nuser proof from metaserver"]
l["Game shows login screen"]
r["Game shows registration screen"]
register["Game registers user with metaserver\nMetaserver sends email confirmation\nGame shows email token entry screen"]
s -->|Username & password are saved locally| p
s -->|Username & password are not saved locally| l
l -->|User does not have an account| r
l -->|User enters valid auth| p
p -->|Auth is valid| browser["Game stores user credentials on disk\nGame stores user proof in memory\nUser browses servers"]
p -->|Auth is invalid| l
r -->|User enters valid username, display name and password| register
r -->|User enters invalid data\nMetaserver reports errors to game\nGame reports errors to user| r
register -->|User enters valid email token| p
browser -->|User joins server| proof["Game provides user proof to game server"]
proof -->|User proof is invalid| l
proof -->|User proof is valid| play(("User plays game"))
l -->|User enters invalid auth\nMetaserver reports errors to game\nGame reports errors to user| l
- User wants to start a new server.
- POST to
/v1/server/register
.- Authenticate with user auth info
- Post the info of the server that is to be registered (see
/docs
for the schema)
- Receive a server
username
(integer, not secret) and a serverpassword
(string, secret). Store this auth info.
- POST to
- A user wants to see which servers are online. Note: 'online' is defined as
having had their info updated in the last X seconds show up.
- GET
/v1/server/online
.- Authenticate with user auth info.
- GET
- A user wants to see which servers they have registered.
- GET
/v1/server/my
.- Authenticate with user auth info.
- GET
- A user wants to update the information for their server.
- POST
/v1/server/update
.- Authenticate with the server auth info received on registration.
- Pass the new server info as data. This refreshes the datetime on which the server was updated and ensures it is visible when users request a list of online servers.
- POST
Yes. Follow the installation steps, run the server with make serve
and visit
127.0.0.1:8000/docs
. You can even get an openapi.json
file from
http://127.0.0.1:8000/openapi.json
and automatically generate a client from
it.
It's my generalization of the Elo rating
system for teams. Let the
rating of a given player
If player
With
Here
Some nice properties compared to vanilla Elo:
- The expected score is adjusted based on both the player's own rating, as well
as the team's rating. The balance can be adjusted to place more importance on
the team's rating
$(\lambda \rightarrow 1)$ , or the individual's contribution$(\lambda \rightarrow 0)$ . - It's harder for players at the top end to gain/lose rating than it is at the
bottom. This achieves two goals:
- It limits rating inflation over time.
- It limits incentives to be risk-averse for players with a high rating.