Private server research project for a certain discontinued mobile game
Private server research project for a certain discontinued mobile game
Private server research project for a certain discontinued mobile game. Discord server: https://discord.gg/MZAf5aVkJG
Prebuilt binaries are published for Linux, macOS, and Windows on the Releases page.
lunar-tear-server---.{tar.gz,zip})../wizard (macOS/Linux) or double-click wizard.exe (Windows).server/assets/ directorygo install github.com/pressly/goose/v3/cmd/goose@latestThe interactive wizard walks you through setup with a few simple questions — no flags or networking knowledge needed. It auto-detects the right IP address for your emulator or phone and launches all services.
cd server
go run ./cmd/wizardYour choices are saved so next time you just press Enter to relaunch with the same settings. To skip the confirmation prompt entirely (useful for scripts or quick relaunches), pass --prefer-saved:
go run ./cmd/wizard --prefer-savedIf no saved config exists, the flag prints an error and exits.
By default the wizard uses ports 8003 (gRPC), 8080 (CDN), and 3000 (auth). Override any of them with flags:
go run ./cmd/wizard --grpc-port 9003 --cdn-port 9080| Flag | Default | Description |
|---|---|---|
--prefer-saved |
false |
Reuse saved config without prompting |
--grpc-port |
8003 |
gRPC server port |
--cdn-port |
8080 |
CDN server port |
--auth-port |
3000 |
Auth server port |
--admin-port |
0 |
Admin webhook port (0 = disabled). Bound on 127.0.0.1; only takes effect when LUNAR_ADMIN_TOKEN is set in the env. |
Custom ports are saved to .wizard.json alongside your other settings. On the next run the saved ports are reused automatically — no need to pass the flags again. If you later pass different port flags, the wizard warns you that the ports changed and asks for confirmation before continuing.
cd server
make protoPlayer state is stored in a SQLite database. Run migrations before starting the server:
cd server
make migrateOr manually:
cd server
mkdir -p db
goose -dir migrations -allow-missing sqlite3 db/game.db upThe wizard backs up your save every time you launch it. To roll back to an earlier save:
cd server
make restorePick a backup from the list and confirm.
To import a JSON snapshot into the database, use the import tool. The --uuid flag must match the UUID your game client sends during authentication:
cd server
make import SNAPSHOT=snapshots/scene_1.json UUID=Or directly:
go run ./cmd/import-snapshot \
--snapshot snapshots/scene_1.json \
--uuid \
--db db/game.db| Flag | Default | Description |
|---|---|---|
--snapshot |
(required) | Path to JSON snapshot file |
--uuid |
(required) | UUID to assign (must match the client's UUID) |
--db |
db/game.db |
SQLite database path |
The server is split into two binaries: a gRPC game server and an HTTP asset CDN. Both must be running for the client to work.
Start the CDN (serves asset bundles, list.bin, master data, web pages):
cd server
go run ./cmd/octo-cdn \
--listen 0.0.0.0:8080 \
--public-addr 10.0.2.2:8080Start the game server (gRPC, points the client at the CDN):
cd server
go run ./cmd/lunar-tear \
--listen 0.0.0.0:8003 \
--public-addr 10.0.2.2:8003 \
--octo-url http://10.0.2.2:8080The default listen address is 0.0.0.0:443, which requires sudo (privileged port). Use --listen with a high port to avoid this. If you do need port 443, either use sudo or grant the binary the capability on Linux:
go build -o lunar-tear ./cmd/lunar-tear
sudo setcap cap_net_bind_service=+ep ./lunar-tear
./lunar-tear --public-addr 10.0.2.2:443 --octo-url http://10.0.2.2:8080The CDN can run on a completely separate machine — just set --octo-url on the game server and --public-addr on the CDN to the externally-reachable address.
Instead of starting each service individually, use the dev runner to launch all three (auth, CDN, game server) with a single command. No Docker required — works on macOS, Linux, and Windows.
cd server
make devOr directly:
cd server
go run ./cmd/devEach service's output is prefixed with a colored label ([auth], [cdn], [grpc]). Press Ctrl+C to shut everything down.
The dev runner automatically builds each service into bin/ before launching. This means the binaries have stable file paths, so Windows Firewall only prompts once — subsequent runs reuse the same allowed executables. The wizard performs the same build step transparently.
Override defaults with namespaced flags:
go run ./cmd/dev --grpc.listen 0.0.0.0:9000 --grpc.public-addr 10.0.2.2:9000 --cdn.public-addr 192.168.1.50:8080Or via make:
make dev ARGS="--grpc.listen 0.0.0.0:9000 --grpc.public-addr 10.0.2.2:9000"| Flag | Default | Description |
|---|---|---|
--auth.listen |
0.0.0.0:3000 |
auth-server listen address |
--auth.db |
db/auth.db |
auth-server SQLite database path |
--cdn.listen |
0.0.0.0:8080 |
octo-cdn local bind address |
--cdn.public-addr |
10.0.2.2:8080 |
octo-cdn externally-reachable addr |
--grpc.listen |
0.0.0.0:8003 |
lunar-tear gRPC listen address |
--grpc.public-addr |
10.0.2.2:8003 |
lunar-tear externally-reachable addr |
--grpc.octo-url |
http://10.0.2.2:8080 |
Octo CDN base URL passed to lunar-tear |
--grpc.auth-url |
http://localhost:3000 |
auth server base URL passed to lunar-tear |
--no-register |
false |
disable new user registrations (only already registered users can connect). |
--admin.listen |
(empty) | lunar-tear admin webhook bind. Empty = leave default; webhook only binds when LUNAR_ADMIN_TOKEN is set in the env. |
--no-color |
false |
disable colored output |
| Protocol | Port | Binary | Notes |
|---|---|---|---|
| gRPC | 443 | lunar-tear |
default; configurable with --listen (requires patched client) |
| HTTP | 8080 | octo-cdn |
Octo asset API + game web pages |
| HTTP | 8082 | lunar-tear |
admin webhook (/api/admin/master-data/reload); loopback by default, only binds when LUNAR_ADMIN_TOKEN is set |
| HTTP | 3000 | auth-server |
account registration and login |
lunar-tear)| Flag | Default | Description |
|---|---|---|
--listen |
0.0.0.0:443 |
gRPC listen address (host:port) |
--public-addr |
127.0.0.1:443 |
externally-reachable host:port advertised to clients |
--octo-url |
(required) | CDN base URL the client uses for assets (e.g. http://10.0.2.2:8080) |
--db |
db/game.db |
SQLite database path |
--auth-url |
(empty) | Auth server base URL (e.g. http://localhost:3000) |
--admin-listen |
127.0.0.1:8082 |
Admin webhook listen address. Only binds when LUNAR_ADMIN_TOKEN is set. |
--no-register |
false |
Disable new user registrations (only already registered users can connect). |
The game server reads its master data from assets/release/20240404193219.bin.e at startup. To swap in updated content without restarting the server:
assets/release/20240404193219.bin.e on disk with your edited copy.LUNAR_ADMIN_TOKEN:curl -X POST -H "Authorization: Bearer ${LUNAR_ADMIN_TOKEN}" \
http://127.0.0.1:8082/api/admin/master-data/reloadThe server re-reads the file, atomically swaps every in-memory catalog and derived handler, and bumps the file's mtime. The mtime is folded into GetLatestMasterDataVersion, so connected clients see a new version string and re-download the file from the CDN on their next poll.
Security defaults are fail-closed:
LUNAR_ADMIN_TOKEN must be set in the environment, or the webhook listener never binds.--admin-listen defaults to 127.0.0.1:8082 (loopback only). Bind to 0.0.0.0 only if you intend to expose it.octo-cdn)| Flag | Default | Description |
|---|---|---|
--listen |
0.0.0.0:8080 |
local bind address |
--public-addr |
127.0.0.1:8080 |
externally-reachable address (used in list.bin rewriting) |
--assets-dir |
. |
root directory containing the `asse |
No open issues yet, or sync has not completed.