Lunar Tear re-implements a discontinued mobile game's server in Go
Private server research project for a certain discontinued mobile game
At a glance
- What is it?
- A research project that rebuilds the backend of a shut down mobile game, with a gRPC game server, an asset CDN and an auth service, a setup wizard that writes its own config, and a SQLite database with migrations.
- Who is it for?
- Adopt Lunar Tear if you are doing research on this particular game and can accept a project that is young, MIT licensed and backed by a Discord rather than a company, and if you have the original client and the asset files. Do not adopt it as production infrastructure: the last push was on 2026-05-28, the release line only reached v1.0.2, and the wizard, the migrations and the snapshot import all assume a single operator on a workstation.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 150 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Lunar Tear is, and what kind of work it is
Lunar Tear is described in one line as a private server research project for a certain discontinued mobile game. The game is shut down, so there is no running service to connect to, and this project rebuilds the parts of the backend that a client expects to talk to. It is written in Go, it is MIT licensed, and it is developed in the open under the Walter-Sparrow organisation with a Discord server linked from the README.
The word research is doing real work in that description. This is not a commercial host, and the README does not describe accounts, monetisation or service level. It is a reimplementation of a protocol, which means it has to be faithful to what a specific client build expects, and the documentation reflects that constraint everywhere. For example, the snapshot import tool insists that the UUID it writes must match the UUID the game client sends during authentication. That is a detail you would never see in a general purpose server, and it tells you the target is one client talking to this implementation.
The scope is broad for something released in a single week of versions. v1.0.0 landed on 2026-05-22, v1.0.1 on 2026-05-25 and v1.0.2 on 2026-05-28, and the last push to the repository was on 2026-05-28. That is a young project with a short history, and the version numbers say the API and the file formats may still move.
The three services and how the client is pointed at them
The server is split into three processes, and the README is explicit that the game server and the asset CDN both have to be running for the client to work. The game server speaks gRPC, the CDN is an HTTP service that serves asset bundles, list.bin, master data and web pages, and there is a separate auth service that the dev runner starts alongside them.
Each service takes a listen address and a public address, and the distinction matters on a machine with a NAT or an emulator. The listen address is where the process binds, and the public address is what it advertises to the client. In the README's own example, the emulator's address 10.0.2.2 is used for both, with the CDN on 8080 and the game server on 8003, and the game server is told where the CDN lives:
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:8080That separation also lets the CDN live on another machine entirely. The README says the CDN can run on a completely separate host, in which case you set the game server's octo-url to the CDN's address and the CDN's public-addr to the externally reachable one. The wizard, by contrast, auto-detects the right IP address for an emulator or a phone and launches all services, so the operator does not have to work out which address to advertise.
Ports are configurable at every level. The wizard defaults to 8003 for gRPC, 8080 for the CDN and 3000 for auth, and each can be overridden with a flag.
The wizard is the front door, and it remembers your answers
The setup path is an interactive program rather than a configuration file you write by hand. Running it walks through a few questions, needs no flags and no networking knowledge, and it auto-detects the address to advertise. For a research tool that has to work on a laptop, a phone and an emulator, that is the right amount of ceremony.
The wizard also persists state. Your choices are saved, so a second run only needs Enter to relaunch with the same settings, and the saved configuration includes the custom ports in a file called .wizard.json. If you pass different port flags on a later run, the wizard warns that the ports changed and asks for confirmation before continuing, which is a sensible guard against a typo quietly moving your services.
For scripts there is a flag that skips the confirmation entirely:
cd server
go run ./cmd/wizard --prefer-savedThe README states the failure mode for that path, which is worth noting because it is easy to hit: if no saved configuration exists, the flag prints an error and exits. The custom port flags are the same shape as the others:
go run ./cmd/wizard --grpc-port 9003 --cdn-port 9080The admin webhook is configured differently from the rest. Its port defaults to 0, which means disabled, it is bound on 127.0.0.1, and it only takes effect when LUNAR_ADMIN_TOKEN is set in the environment. The token in the environment, with the port left at zero by default, is a sane arrangement for a service that could otherwise expose administrative actions on the same interfaces as the game traffic.
Building from source, and the dev runner that avoids Docker
The quick path is a prebuilt binary. The releases page publishes archives for Linux, macOS and Windows named lunar-tear-server-<version>-<os>-<arch>, as a tar.gz or a zip, and the instruction is to run the wizard inside it, or double-click wizard.exe on Windows. No setup is needed for that route.
Building from source needs Go 1.25 or newer, the goose migration tool, and a populated server/assets/ directory. The tool is installed with the standard go install form, and the README links the goose repository rather than shipping a pinned copy:
go install github.com/pressly/goose/v3/cmd/goose@latestThe dev runner starts all three services, auth, CDN and game server, with one command and no container runtime, and it works on macOS, Linux and Windows. Each service's output is prefixed with a coloured label, so you can tell the streams apart, and Ctrl+C stops everything:
cd server
make devIt also builds each service into bin/ before launching. The README explains why that matters: because the binaries keep stable file paths, Windows Firewall only prompts once, and later runs reuse the same allowed executables. The wizard performs the same build step transparently. Overrides are namespaced per service, either as flags or through the Makefile:
make dev ARGS="--grpc.listen 0.0.0.0:9000 --grpc.public-addr 10.0.2.2:9000"The one friction point in the whole build path is the asset directory. It is listed as a prerequisite, the README does not say where the bundles come from, and the CDN cannot serve anything it does not have.
SQLite, migrations, snapshots and the backup the wizard takes
Player state lives in SQLite. The database is created by migrations, and the Makefile wraps the goose invocation:
cd server
make migrateThe manual equivalent shows the details, including the migrations directory and the database path:
cd server
mkdir -p db
goose -dir migrations -allow-missing sqlite3 db/game.db upThe allow-missing flag is worth understanding rather than copying blindly.
Snapshots come in as JSON and are written into the database by a separate tool, with the client UUID as a required argument:
cd server
make import SNAPSHOT=snapshots/scene_1.json UUID=<your-client-uuid>Backups are handled by the wizard, which the README says backs up the save every time it launches, and by a restore target that lists the available backups and asks you to pick one:
cd server
make restoreThe auth service has its own database file, db/auth.db, separate from the game database db/game.db, so the two state stores can be backed up and reset independently.
The admin webhook, protobuf stubs and the licence
The administrative surface is deliberately narrow. The admin webhook port is 0 by default, which means the webhook is off unless someone asks for it, it binds to the loopback address 127.0.0.1, and it only comes alive when LUNAR_ADMIN_TOKEN is present in the environment. For a project that is often run on a shared network, a loopback-bound administrative endpoint that requires an explicit token is the right default, and it is also the piece most likely to matter for anyone hosting the stack for others.
The wire format is protobuf, and the stubs are regenerated with a make target rather than by hand:
cd server
make protoThe licence is MIT, which is the permissive end of the spectrum and means the code can be reused, modified and redistributed with attribution. The README itself does not spell the terms out, so the LICENSE file in the repository root is the document to read.
Maintenance is the main caveat. The last push was on 2026-05-28, the same day as v1.0.2, and there have been no pushes since in the repository as described here. The code is young, the release history is three patch versions, and the project offers a Discord rather than a documentation site, so knowledge lives with the community rather than in files.
Where this approach is the wrong one
The obvious limit is that this is a reimplementation, not an emulator. A proxy or packet level approach sits between the client and something that still has to exist, while a reimplementation owns the whole protocol surface, and the cost of that choice is visible in the tooling: the UUID in an imported snapshot has to match the one the client sends, the asset directory has to be populated by hand, and the service list is fixed at auth, CDN and gRPC game server. A project that wanted to keep working across client updates would have to track every protocol change by hand.
The second limit is the operational surface. The wizard is built for one operator on one machine, the whole stack expects to be reachable at a known address, and the three services have to be started together for the client to work at all. The one real deployment escape hatch, moving the CDN to a different host, still requires the public address and the octo-url to agree, and nothing in the README describes TLS termination, authentication of the game protocol, or what happens when the SQLite database is opened by two processes.
The third is the default port. The game server's default listen address is 0.0.0.0:443, a privileged port, and the README is upfront that it requires sudo or a capability grant on Linux:
go build -o lunar-tear ./cmd/lunar-tear
sudo setcap cap_net_bind_service=+ep ./lunar-tearGranting a binary the ability to bind a privileged port, on a machine that also runs a game client, is a decision worth making deliberately rather than accepting from the default.
Editorial conclusion
Adopt Lunar Tear if you are doing research on this particular game and can accept a project that is young, MIT licensed and backed by a Discord rather than a company, and if you have the original client and the asset files. Do not adopt it as production infrastructure: the last push was on 2026-05-28, the release line only reached v1.0.2, and the wizard, the migrations and the snapshot import all assume a single operator on a workstation. Verify first that server/assets/ is populated, because the README lists it as a prerequisite and does not say where the asset bundles come from, then run the wizard once and read the .wizard.json it writes before changing any port.
Frequently asked questions
How do I build and launch the Lunar Tear server?
You need Go 1.25 or newer, the goose migration tool, and a populated server/assets/ directory. The README gives goose as a go install command, then the dev runner starts auth, CDN and game server together with make dev, and the interactive wizard is started with go run ./cmd/wizard.
Which ports does the Lunar Tear server use?
The wizard defaults to 8003 for the gRPC server, 8080 for the CDN and 3000 for auth, and each can be changed with the grpc-port, cdn-port and auth-port flags. The admin webhook port defaults to 0, which means disabled, binds on 127.0.0.1, and only takes effect when LUNAR_ADMIN_TOKEN is set in the environment.
How do I import a JSON snapshot into the Lunar Tear database?
Use the import tool with a snapshot path and the UUID that your game client sends during authentication, for example make import SNAPSHOT=snapshots/scene_1.json UUID=<your-client-uuid>. The same run can be done directly with go run ./cmd/import-snapshot, passing --snapshot, --uuid and --db.
How do I roll back a save in Lunar Tear?
The wizard backs up the save every time it launches, and make restore lists the available backups and asks you to confirm the one to restore. Player state is kept in SQLite, with the game data in db/game.db and the auth service in db/auth.db.
Why does the Lunar Tear game server need port 443?
The default listen address is 0.0.0.0:443, which is a privileged port. The README says you can either use sudo, or grant the binary the capability on Linux with sudo setcap cap_net_bind_service=+ep ./lunar-tear, or pass --listen with a high port to avoid the issue.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/walter-sparrow-lunar-tear)Was this useful?