Contributing¶
We welcome contributions to MafiaNet! This guide will help you get started.
Getting Started¶
Fork the repository on GitHub
Clone your fork locally
Create a branch for your changes
git clone https://github.com/YOUR_USERNAME/MafiaNet.git
cd MafiaNet
git checkout -b feature/my-new-feature
Code Style¶
Use C++17 features where appropriate
Follow existing code formatting conventions
Add comments for complex logic
Keep functions focused and reasonably sized
Building and Testing¶
The test suite lives in Samples/Tests and is built as part of the samples,
so enable MAFIANET_BUILD_SAMPLES:
mkdir build && cd build
cmake -DMAFIANET_BUILD_SAMPLES=ON ..
cmake --build .
./Samples/Tests/Tests # run all tests
./Samples/Tests/Tests VirtualWorldTest # run one test by name
A test is a class deriving from TestInterface (see
Samples/Tests/TestInterface.h). RunTest() returns 0 on success or a
non-zero error code on failure; map each code to a human-readable string in
ErrorCodeToString() so failures are diagnosable. Register a new test by
adding its header to Samples/Tests/IncludeAllTests.h and a
testList.Push(new MyTest(), _FILE_AND_LINE_) line in
Samples/Tests/Tests.cpp. RPC4ContextTest and VirtualWorldTest are
good templates.
How to test a new feature¶
Follow test-driven development: write the test first, watch it fail for the right reason, then write the minimal code to make it pass. A test that passes the moment you write it has proven nothing.
Test at two levels — both are required for anything that touches networking or replication:
Unit level (deterministic). Exercise the feature’s logic directly with no sockets, so it is fast and never flaky.
VirtualWorldTestconstructs replicas/connections on the stack and asserts the exact return values of the query hooks. This pins down what each decision should be.End-to-end / integration (real wire). Stand up real peers (a server and one or more clients) over loopback and drive them with
RakPeerInterface::Receive()until the expected state converges. Use condition-based waiting (pump until the condition holds or a generous ceiling is reached), never a fixedsleep.Samples/VirtualWorldis a self-contained example that doubles as a smoke test (it returns non-zero on failure).
Warning
Unit tests alone are not enough for replication/networking features. Many bugs only appear in a real topology, because plugins such as ReplicaManager3 run the same callbacks on every peer (server, clients, peers), and the interesting failures live in how those sides interact over the wire. The virtual world feature, for example, passed every unit test but had a bug where a client told the server to delete an object — something only a real client/server run could surface. If your feature sends anything over the network, you must exercise it end-to-end before it is “done”.
When something only fails over the wire, instrument the message boundary rather
than guessing: temporary, env-var-guarded prints in the send path
(Connection_RM3::SendConstruction) and the receive path
(ReplicaManager3::OnConstruction / OnSerialize), keyed on the relevant
NetworkID, will show exactly which peer did what. Remove the instrumentation
before committing.
Gotchas when running several peers in one process¶
Self-contained tests and samples often create multiple peers in a single process. Two collisions to be aware of:
GUID collision. On POSIX a peer’s GUID is seeded from the microsecond clock at construction, so peers created back-to-back can get identical GUIDs and a server will drop the duplicate connection. Space out the
GetInstance()calls (e.g. a shortRakSleepbetween them) so each GUID is distinct.NetworkID collision. Each
NetworkIDManagerassigns ids from the same base, andNetworkIDcarries no creator information, so two independent creators can mint the same id (the second is rejected as a duplicate on the receiver). Use a single authoritative creator, or otherwise guarantee globally unique ids.
Releasing¶
Version bumps touch several files that must stay in sync. The full procedure is
documented in CLAUDE.md (the “Releasing” section) — follow it exactly when
cutting a release.
Submitting Changes¶
Ensure all tests pass
Commit your changes with a clear message
Push to your fork
Open a Pull Request
License¶
By contributing, you agree that your contributions will be licensed under the MIT License.