Library / SDK
sniper00/moon avatar
sniper00/moon

moon: an actor model game server framework with Lua for game logic

A lightweight game server framework implemented with Actor Model

976 stars212 forksC++MIT

At a glance

What is it?
moon is a lightweight C++ game server framework where actors, also called services, live on worker threads and talk through message queues, while the game logic itself is written in Lua and driven by coroutines. It builds with premake5 on Windows, Linux and MacOS.
Who is it for?
moon is a reasonable fit for a team that already thinks in services and actors, wants its game logic in a scripting language, and needs to ship a server that builds identically on Windows, Linux and MacOS. It is the wrong choice for a project that needs a mature, battle-tested networking stack or that expects a documented API beyond the wiki, because the README is a feature list and the documentation lives in the repository wiki.
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 69 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One worker thread, many services, message queues between them

moon is described as a lightweight game server framework based on the actor model, and the README gives the model in one sentence: one worker thread can have one or more actors, also called services, which communicate with each other through message queues.

That is the whole architectural claim, and it is a modest one. Rather than a large framework with a plugin system, an ORM, a scheduler of its own design and a configuration schema, moon gives you the actor pattern and a scripting language on top. The stated advantage is that the architecture is simple and the source code is concise and easy to understand.

The services directory at the top level of the repository and the example scripts named example_create_service.lua and example_create_service_benchmark.lua indicate that service creation is the first thing you are expected to write. The example folder also contains example_queue.lua, which suggests the message queue is directly reachable from Lua rather than being hidden behind C++.

For a reader deciding on the framework, the important question is whether the actor model matches how the game is already structured. Moon assumes the server side decomposes into services that talk to each other through queues. If your game logic is one large shared state machine, the framework will not help, and it will add an indirection layer you did not ask for.

ASIO for scheduling, Lua coroutines for asynchronous logic

Two layers of concurrency sit on top of each other. The C++ side uses ASIO for scheduling and for the networking, and the Lua side is asynchronous on the basis of Lua coroutines.

The list of things built on coroutines is the clearest statement of the design. A coroutine-socket lets a Lua script wait on network I/O without blocking the worker thread. Timers work the same way. Inter-service communication and inter-process communication are coroutine based as well, which means a script waiting on a reply from another service reads like ordinary sequential code. Then there are the async client drivers for Redis, PostgreSQL, MongoDB and MySQL, all of them coroutine based so a script can issue a query and keep serving other messages in the meantime.

This is the design that makes a single-threaded actor model workable. An actor that blocks would stall every other service on the same worker thread, so the framework pushes all waiting into coroutines and keeps the thread free.

The cost is that the asynchronous behaviour is a property of the framework, not of your language, and debugging it requires understanding how a message is queued while a coroutine is suspended. The README also claims a high performance and optimized Lua Json library and a Lua protobuf library, which tells you the hot path is data marshalling rather than computation, and that the project has invested in that path specifically.

Transports: TCP, UDP with KCP, WebSockets and HTTP

The networking list in the README covers four families. Tcp for reliable ordered connections. Udp/Kcp, so you can use UDP with a reliable-ish protocol layered on top. Websockets for browser clients. Http for request and response style traffic.

The example directory maps onto that list almost one to one, which is a good way to size up the work: example_kcp.lua and example_udp.lua cover the datagram side, network_websocket.lua covers WebSockets, and example_http.lua covers HTTP. There is also a cluster directory and a guess_game directory, the latter tied to a guessing game example described in example/GuessGame.md.

Two details are worth flagging for a real project. First, the HTTP support appears in a game server framework where you might not expect it, and the example named example_http.lua suggests it serves a request/response channel rather than only serving static assets. Second, the game itself needs a client protocol, and the framework supplies a Lua protobuf library plus a sharetable example, which is how a designer or a server admin would distribute configuration tables to clients.

The README describes the networking as optimized but publishes no numbers, and the benchmark scripts are named send_benchmark.lua, call_benchmark.lua and create_service_benchmark.lua, so if throughput is the deciding factor you should read those scripts to see what is actually being measured before drawing a conclusion.

The Lua standard library that ships with the framework

Beyond networking, moon ships a set of Lua libraries inside the lualib directory, and this is a substantial part of what the framework is.

There is a Lua Json library, described as high performance and optimized, and a Lua protobuf library for encoding and decoding. There is a Lua filesystem binding, which matters because game servers read configuration and content files. There is a Lua zset library for ranklists, which is the data structure you want for leaderboards where scores are updated frequently and read in order. There is Recast Navigation support, with example_navmesh.lua and a navmesh directory, so a server can do pathfinding rather than only shuffling messages. The examples also show example_schema.lua for defining data structures and example_sharetable.lua for distributing tables.

There is a Lua filesystem and there is a navmesh, and both of these are the kind of native binding that turns a scripting layer into a platform. The cost is a native extension surface: when a Lua call blocks or crashes, you are in C++ code, not in a script you can read quickly.

Extension libraries live outside the core repository. The README points to a separate repository for more of them, and the build instructions show how to add one through premake5. That is a healthy sign for a framework with a small core, and it also means the set of available libraries depends on that other repository rather than on what you read in this README.

Building with premake5 and a C++23 toolchain

The build system is premake5, and the compiler requirement is not trivial. The README asks for a compiler that supports C++23: vs2022 17.5 or newer, gcc 13 or newer, or clang 16 or newer.

The sequence is: install premake5 and put the premake5 executable on your system path, then clone the source. On macOS the README suggests installing it with Homebrew:

shell
brew install premake

Clone the repository, optionally adding an extension library in the same step:

shell
git clone https://github.com/sniper00/moon.git

The build and run targets are premake5 subcommands. Build from the moon directory:

shell
cd moon
premake5 build --release

Run one of the example scripts with the same tool, which is how you see a service working without writing your own first:

shell
premake5 run --release example/send_benchmark.lua

And publishing is also a premake5 action, which packages the built artifacts:

shell
premake5 publish

The repository root holds premake5.lua, the build script, and a third directory for third-party code, plus a .gitmodules file, so some dependencies arrive as submodules. The CI badges at the top of the README show four build configurations covered by workflows: linux-gcc, linux-clang, macos-clang and windows-vs2022, which is a fair description of the supported platforms.

Running a script directly, and what the examples cover

The fastest way to see the framework work is to run a script against the pre-built binary. The README links a pre-built binaries release and then shows three invocations, one for the test script, one for an example in the example directory, and one for the guessing game:

shell
./moon example/test/main_test.lua
./moon example/example_timer.lua
./moon example/main_game.lua

That the test suite is itself a Lua script is itself a design statement. The tests run inside the framework, using the same coroutine and timer machinery as the game code, which means the test harness exercises the runtime rather than mocking it.

The example directory doubles as the API documentation, because the README does not document the API. It contains example_redis.lua, example_mysql.lua, example_pgsql.lua and example_mongo.lua for the four database drivers, example_kcp.lua and example_udp.lua for datagram transports, example_timer.lua for the timer coroutine, example_queue.lua for the message queue, example_random.lua, example_shutdown.lua for a controlled stop, example_wait_all.lua, example_tobeclosed.lua, example_pb.lua for protobuf, example_schema.lua, example_sharetable.lua, example_navmesh.lua, example_http.lua and network_websocket.lua.

Two of those names hint at the awkward parts of any server. example_shutdown.lua and example_wait_all.lua are about orderly termination, which is where actor frameworks typically get messy: you have to drain queues, close services and stop accepting connections. example_tobeclosed.lua suggests the framework has a concept of a service that is expected to close, which is a lifecycle mechanism rather than a leak.

Licence, versioning, and the gap between tags and artifacts

The licence is MIT, with the LICENSE file at the repository root. That permits commercial use, modification and redistribution, and the only obligation is to keep the notice. For a game server framework that you intend to ship inside a commercial product, this removes a negotiation step.

On versioning, the numbers are more interesting than they first look. The most recent release artifact is named prebuilt and dated 2026-08-15, the same date as the last push to the default branch master. Before that, the tags are v0.9 from 2024-08-22 and v0.8 from 2023-04-27.

So the tagged versions are old, and the actively used artifact is a rolling prebuilt bundle rather than a numbered release. The repository is not archived and the last push was on 2026-08-15, so work on the code base is current, but you cannot point at a version number and know what is inside it. A team that pins versions for reproducible builds has to decide whether to pin the prebuilt artifact from a given date or to build from a specific commit.

Documentation is thin by the standards of comparable frameworks. The README links a wiki, a community chat badge, a QQ group, and a separate demo repository, and the API reference is not in the README at all. A CHANGELOG.md and a docs directory exist in the repository, and the wiki is linked as the document source, so the detail lives outside the code you clone. Read the wiki before committing a team to it, because the examples show what is possible while the wiki is where the contracts are.

Editorial conclusion

moon is a reasonable fit for a team that already thinks in services and actors, wants its game logic in a scripting language, and needs to ship a server that builds identically on Windows, Linux and MacOS. It is the wrong choice for a project that needs a mature, battle-tested networking stack or that expects a documented API beyond the wiki, because the README is a feature list and the documentation lives in the repository wiki. Verify first that your compiler supports C++23 (vs2022 17.5+, gcc 13+, clang 16+), that premake5 is on your path, and that the examples in the example directory cover the transport and driver you intend to use before you commit to the framework. Note also that the last tagged version is v0.9 from 2024-08-22 while the most recent artifact is the prebuilt release dated 2026-08-15, so pin a binary deliberately.

Frequently asked questions

What is moon and what language is it written in?

moon is a lightweight game server framework based on the actor model, written in C++ with Lua used for the game logic. One worker thread can hold one or more actors, also called services, which communicate through message queues.

How do I build moon from source?

Install premake5 and make sure it is on your system path, clone the repository, then run premake5 build --release from the moon directory. The compiler must support C++23, meaning vs2022 17.5+, gcc 13+ or clang 16+.

How do I run a moon example script?

Download the pre-built binaries, then run the executable with a script path, for example ./moon example/example_timer.lua. The same script can be run from a build with premake5 run --release example/send_benchmark.lua.

Which databases and network protocols does moon support?

The README lists coroutine based async client drivers for Redis, PostgreSQL, MongoDB and MySQL, and networking over Tcp, Udp/Kcp, Websockets and Http. The example directory contains a script for each of these.

What licence does moon use?

moon is released under the MIT licence, with the licence text in the LICENSE file at the repository root.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. sniper00/moon on GitHub
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/sniper00-moon.svg)](https://hysenlabs.com/projects/sniper00-moon)

Was this useful?