DEV Community

DDCoder23
DDCoder23

Posted on

๐Ÿฆ€๐ŸŒ Building the Network Architecture of an Open-Source MMORPG with Rust

๐Ÿฆ€๐ŸŒ Building the Network Architecture of an Open-Source MMORPG with Rust

When building a multiplayer game, one of the first systems that has to become reliable is the network layer.

For The Last Signal Online, an open-source post-apocalyptic MMORPG I'm building, the server is written in Rust and communicates with clients through a custom TCP protocol.

The current networking layer is still under development, but it already has several important components:

  • a TCP server built with Tokio
  • asynchronous client handling
  • a custom binary packet format
  • packet parsing and validation
  • packet routing
  • authentication and account management
  • SQLite integration
  • session management
  • periodic ban verification
  • structured client logging

This article explains how the current architecture works and what I am working toward next.


๐Ÿ—๏ธ Current Architecture

The networking code is organized into five main modules:

server_rust/src/network/

โ”œโ”€โ”€ packet.rs
โ”œโ”€โ”€ client.rs
โ”œโ”€โ”€ server.rs
โ”œโ”€โ”€ handler.rs
โ””โ”€โ”€ parser.rs
Enter fullscreen mode Exit fullscreen mode

Each module currently has a specific responsibility.

                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                    โ”‚      TCP Client      โ”‚
                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                               โ”‚
                               โ”‚ TCP
                               โ–ผ
                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                    โ”‚       Server        โ”‚
                    โ”‚    TcpListener      โ”‚
                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                               โ”‚
                     creates Client
                               โ”‚
                               โ–ผ
                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                    โ”‚       Client        โ”‚
                    โ”‚  session + socket   โ”‚
                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                               โ”‚
                         receive_packet()
                               โ”‚
                               โ–ผ
                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                    โ”‚       Packet        โ”‚
                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                               โ”‚
                               โ–ผ
                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                    โ”‚   PacketHandler     โ”‚
                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                               โ”‚
             โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
             โ–ผ                 โ–ผ                  โ–ผ
          Parser            SQLite             Response
Enter fullscreen mode Exit fullscreen mode

The goal is to keep the low-level TCP handling separate from packet processing and application logic.


๐Ÿš€ 1. The TCP Server

The entry point for incoming network connections is the Server structure.

It contains:

pub struct Server {
    listener: TcpListener,
    database: DatabaseManager,
}
Enter fullscreen mode Exit fullscreen mode

The server creates a Tokio TcpListener and binds it to the configured address.

Once started, it continuously waits for incoming connections:

loop {
    match self.listener.accept().await {
        Ok((stream, address)) => {
            // ...
        }

        Err(e) => {
            // ...
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

When a client connects, the server obtains:

  • the TCP stream
  • the client's socket address

It then creates a new Client instance.


โšก 2. One Asynchronous Task per Client

The current implementation uses Tokio tasks to handle clients independently.

When a connection is accepted:

task::spawn(async move {
    let mut client = Client::new(stream, pool);
    client.run().await;
});
Enter fullscreen mode Exit fullscreen mode

This means the main listener can immediately return to accepting other connections.

Conceptually:

                    TCP Listener
                         โ”‚
          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
          โ–ผ              โ–ผ              โ–ผ
       Client A       Client B       Client C
          โ”‚              โ”‚              โ”‚
       Tokio task     Tokio task     Tokio task
          โ”‚              โ”‚              โ”‚
       run()           run()           run()
Enter fullscreen mode Exit fullscreen mode

This is important for a multiplayer game because the server cannot block while waiting for a single player.


๐Ÿ‘ค 3. The Client Session

Each connected player is represented by a Client.

The structure currently stores:

pub struct Client {
    stream: TcpStream,
    pool: SqlitePool,
    session_id: Uuid,
    client_id: Option<i64>,
    user_id: Option<String>,
    account_id: Option<i64>,
}
Enter fullscreen mode Exit fullscreen mode

This gives the networking layer both the connection itself and some session state.

The session_id is generated when the Client is created:

session_id: Uuid::new_v4(),
Enter fullscreen mode Exit fullscreen mode

This provides a unique identifier for the network session independently from the database user ID.

The client can also progressively acquire information during authentication:

TCP connection
      โ”‚
      โ–ผ
Client created
      โ”‚
      โ”œโ”€โ”€ session_id
      โ”œโ”€โ”€ client_id = None
      โ”œโ”€โ”€ user_id = None
      โ””โ”€โ”€ account_id = None
             โ”‚
             โ”‚ login/signup
             โ–ผ
       session becomes
       associated with
       a user
Enter fullscreen mode Exit fullscreen mode

๐Ÿ”„ 4. The Client Event Loop

Once a client is created, Client::run() becomes responsible for the connection.

The interesting part is the use of:

tokio::select!
Enter fullscreen mode Exit fullscreen mode

The client is currently waiting for two kinds of events:

  1. an incoming network packet
  2. a periodic ban-check timer

Conceptually:

                 Client::run()
                      โ”‚
                 tokio::select!
                 /            \
                /              \
       Network packet       Ban timer
             โ”‚                  โ”‚
             โ–ผ                  โ–ผ
      receive_packet()      get_ban_info()
             โ”‚                  โ”‚
             โ–ผ                  โ–ผ
      PacketHandler          BAN packet
             โ”‚                  โ”‚
             โ–ผ                  โ–ผ
       Response             disconnect
Enter fullscreen mode Exit fullscreen mode

This allows the connection to remain responsive while the server performs periodic session checks.


๐Ÿ“ฆ 5. The Packet Format

The protocol currently uses a small custom binary framing format.

Every packet contains:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Packet size   โ”‚ 4 bytes   โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Packet type   โ”‚ 2 bytes   โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Payload       โ”‚ variable  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
Enter fullscreen mode Exit fullscreen mode

The packet size is encoded as a big-endian u32.

The packet type is encoded as a big-endian u16.

The remaining bytes are the payload.

For example:

[ 4-byte size ]
[ 2-byte type ]
[ payload...  ]
Enter fullscreen mode Exit fullscreen mode

This framing allows the receiver to know exactly how many bytes belong to the current packet before processing it.


๐Ÿงฉ 6. Packet Types

The current protocol defines several packet types:

pub enum PacketType {
    Ping = 1,
    Login = 2,
    Chat = 3,
    Move = 4,
    Log = 5,
    SignUp = 6,
    LoginResponse = 7,
    SignUpResponse = 8,
    BAN = 9,
}
Enter fullscreen mode Exit fullscreen mode

The protocol therefore already covers several fundamental systems:

Packet Current purpose
Ping Connection/liveness test
Login Authentication
Chat Chat messages
Move Player movement
Log Client-side logging
SignUp Account creation
LoginResponse Server login response
SignUpResponse Server signup response
BAN Server-side ban notification

The conversion between the numeric protocol value and the Rust enum is handled by PacketType::from_u16().

Unknown packet types are rejected.


๐Ÿ›ก๏ธ 7. Packet Size Validation

The server currently defines:

pub const MAX_PACKET_SIZE: usize = 10 * 1024 * 1024;
Enter fullscreen mode Exit fullscreen mode

Both sending and receiving enforce this maximum.

A packet smaller than the two bytes required for the packet type is also rejected.

This gives the current framing layer some basic protection against malformed or unexpectedly large frames.

The receiver follows this process:

Read 4 bytes
    โ”‚
    โ–ผ
Decode packet size
    โ”‚
    โ”œโ”€โ”€ size < 2 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ reject
    โ”‚
    โ”œโ”€โ”€ size > 10 MiB โ”€โ”€โ–บ reject
    โ”‚
    โ–ผ
Read exactly `size` bytes
    โ”‚
    โ–ผ
Read packet type
    โ”‚
    โ”œโ”€โ”€ unknown โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ reject
    โ”‚
    โ–ผ
Extract payload
Enter fullscreen mode Exit fullscreen mode

The use of read_exact() is particularly useful here because the server explicitly requests the number of bytes required for the current frame.


๐Ÿ” 8. Parsing Login and Signup Payloads

Packets provide the outer framing.

The parser then interprets the payload for specific packet types.

For login and signup, the current payload format is:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Email length โ”‚ 2 bytes โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Email        โ”‚ variableโ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Password len โ”‚ 2 bytes โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Password     โ”‚ variableโ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
Enter fullscreen mode Exit fullscreen mode

Both lengths are stored as big-endian u16 values.

The parser performs several validation steps:

  • checks that the length field exists
  • checks that the declared number of bytes exists
  • converts the data from UTF-8
  • returns an error when the payload is malformed

For example, an incomplete email is rejected before the server attempts to interpret it.

This keeps payload parsing separate from packet routing.


๐Ÿง  9. Packet Routing

Once a packet has been decoded, it is passed to:

PacketHandler::handle(...)
Enter fullscreen mode Exit fullscreen mode

The handler matches on the packet type.

Conceptually:

Packet
  โ”‚
  โ–ผ
match packet.packet_type
  โ”‚
  โ”œโ”€โ”€ Ping
  โ”œโ”€โ”€ Login
  โ”œโ”€โ”€ SignUp
  โ”œโ”€โ”€ Chat
  โ”œโ”€โ”€ Move
  โ”œโ”€โ”€ Log
  โ”œโ”€โ”€ BAN
  โ””โ”€โ”€ Responses
Enter fullscreen mode Exit fullscreen mode

This is currently the main bridge between the networking layer and the rest of the server.


๐Ÿ“ 10. Ping / Pong

The simplest packet currently implemented is Ping.

When the server receives it, the handler creates another packet:

Packet::new(
    PacketType::Ping,
    b"PONG".to_vec(),
)
Enter fullscreen mode Exit fullscreen mode

The response is then sent back through the same TCP connection.

So the current flow is:

Client
  โ”‚
  โ”‚ PING
  โ–ผ
Server
  โ”‚
  โ”‚ PacketHandler
  โ–ผ
  PONG
  โ”‚
  โ–ผ
Client
Enter fullscreen mode Exit fullscreen mode

This provides a simple way to test basic connectivity.


๐Ÿ” 11. Authentication

The networking layer is already connected to the authentication system.

For a LOGIN packet, the handler:

  1. parses the payload
  2. searches for the user in SQLite
  3. checks permanent and temporary bans
  4. verifies the password hash
  5. tracks failed login attempts
  6. applies the temporary ban mechanism when necessary
  7. checks whether the account is already connected
  8. marks the user as connected
  9. associates the authenticated user with the Client
  10. returns a login response

The password verification itself is delegated to the project's password utility.

The handler therefore acts as the current integration point between:

Network protocol
       โ”‚
       โ–ผ
Login parser
       โ”‚
       โ–ผ
Authentication
       โ”‚
       โ”œโ”€โ”€ SQLite
       โ”œโ”€โ”€ password verification
       โ”œโ”€โ”€ ban system
       โ””โ”€โ”€ session state
Enter fullscreen mode Exit fullscreen mode

๐Ÿšซ 12. Failed Login Attempts and Temporary Bans

The current login system also keeps track of failed attempts.

After three failed attempts, the server can create or extend a temporary ban.

There is also a banssursis mechanism in the current database logic that can modify the duration of the resulting ban.

This means authentication is not simply:

password correct โ†’ login
password wrong   โ†’ reject
Enter fullscreen mode Exit fullscreen mode

There is already a larger state machine:

Login attempt
     โ”‚
     โ–ผ
Find user
     โ”‚
     โ”œโ”€โ”€ not found โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ reject
     โ”‚
     โ–ผ
Check bans
     โ”‚
     โ”œโ”€โ”€ banned โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ reject
     โ”‚
     โ–ผ
Verify password
     โ”‚
     โ”œโ”€โ”€ incorrect
     โ”‚      โ”‚
     โ”‚      โ–ผ
     โ”‚   increment attempts
     โ”‚      โ”‚
     โ”‚      โ”œโ”€โ”€ < 3 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ reject
     โ”‚      โ”‚
     โ”‚      โ””โ”€โ”€ โ‰ฅ 3 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ temporary ban
     โ”‚
     โ–ผ
Check connected status
     โ”‚
     โ”œโ”€โ”€ already connected โ”€โ–บ reject
     โ”‚
     โ–ผ
Mark CONNECTED
     โ”‚
     โ–ผ
Associate user with Client
Enter fullscreen mode Exit fullscreen mode

This is one of the areas where the network layer is already interacting heavily with persistent server state.


๐Ÿ“ 13. Client Logging

The protocol also contains a Log packet.

The client can send structured logging information containing:

pub struct ClientLog {
    pub level: LogLevel,
    pub module: String,
    pub file: String,
    pub line: u32,
    pub message: String,
}
Enter fullscreen mode Exit fullscreen mode

The server deserializes this data using serde_json.

Depending on the received level, it forwards the message to the server's logging system.

Supported levels currently include:

TRACE
DEBUG
INFO
WARNING
ERROR
Enter fullscreen mode Exit fullscreen mode

This gives the client a mechanism for reporting structured diagnostic information to the server.


๐Ÿ’ฌ 14. Chat and Movement

The protocol already defines Chat and Move.

At the current stage, their handling is intentionally simple.

For chat:

Packet::new(
    PacketType::Chat,
    packet.payload,
)
Enter fullscreen mode Exit fullscreen mode

The server currently logs the received message and sends the payload back.

Movement currently follows a similar basic path.

This is important because these packet types are part of the current protocol, but their gameplay functionality is not yet a complete MMORPG networking system.

The architecture is being built before the full gameplay layer is implemented.


โ›” 15. Server-Only Responses

The handler also explicitly rejects packets that should only originate from the server.

For example:

Client โ†’ LoginResponse
Client โ†’ SignUpResponse
Enter fullscreen mode Exit fullscreen mode

are considered invalid directions.

The server logs the situation and does not generate a response.

This establishes an important concept for the protocol:

Not every packet type is valid in both directions.

As the protocol grows, this distinction will become increasingly important.


๐Ÿ”จ 16. Signup

Account creation follows a similar path to login:

SIGN_UP packet
      โ”‚
      โ–ผ
parse_signup_payload()
      โ”‚
      โ–ผ
hash password
      โ”‚
      โ–ผ
generate UUID
      โ”‚
      โ–ผ
INSERT INTO users
      โ”‚
      โ–ผ
associate user with Client
      โ”‚
      โ–ผ
SIGN_UP response
Enter fullscreen mode Exit fullscreen mode

The password is hashed before being stored.

The database also handles duplicate email detection.


๐Ÿ”Œ 17. Session Disconnection

When a client disconnects, the Client performs cleanup.

If the session has an authenticated user, the server updates the database:

CONNECTED
    โ”‚
    โ”‚ disconnect
    โ–ผ
DISCONNECTED
Enter fullscreen mode Exit fullscreen mode

The socket can then be shut down cleanly.

This means the network session and persistent user state are connected.


โฑ๏ธ 18. Periodic Ban Checking

One interesting part of the current architecture is that ban checking does not only happen during login.

The client starts a Tokio interval:

interval(Duration::from_secs(1))
Enter fullscreen mode Exit fullscreen mode

Once a player is authenticated, the server periodically checks whether a ban has become active.

If a ban is detected:

Database
    โ”‚
    โ–ผ
Ban detected
    โ”‚
    โ–ผ
Create BAN packet
    โ”‚
    โ–ผ
Send to client
    โ”‚
    โ–ผ
Disconnect
Enter fullscreen mode Exit fullscreen mode

This means an already-connected player can be removed from the server if their account becomes banned while their session is active.


๐Ÿ” 19. What About Network Security?

The current networking code is intentionally still an evolving part of the project.

The code described in this article provides:

  • packet framing
  • packet size limits
  • packet type validation
  • payload validation
  • authentication
  • password hashing
  • ban handling
  • session tracking

However, this should not be interpreted as a finished secure production protocol.

For example, the networking files shown here implement TCP framing, but they do not themselves provide transport encryption such as TLS.

The project also has experimental cryptography work elsewhere, but that should not be confused with the packet framing layer described here.

Security is an ongoing area of development and review.


๐Ÿงช 20. What I Want to Improve

The current architecture is a foundation rather than the final networking system.

Some of the areas I want to develop further include:

Better protocol validation

More malformed and invalid packet tests are needed.

Examples include:

  • invalid packet sizes
  • unknown packet types
  • truncated payloads
  • invalid UTF-8
  • invalid field lengths
  • unexpected packet directions

Network integration tests

I want to test the complete path:

Client
  โ†“
TCP
  โ†“
Server
  โ†“
Parser
  โ†“
Handler
  โ†“
Database
  โ†“
Response
Enter fullscreen mode Exit fullscreen mode

rather than testing each component only in isolation.

Better packet abstractions

As the game grows, the number of packet types will increase significantly.

The protocol therefore needs to remain easy to extend without turning the handler into an unmaintainable collection of special cases.

Gameplay networking

Movement and chat are currently basic.

The future network layer will need to support much more complex game state:

  • player movement
  • world state
  • combat
  • inventories
  • NPCs
  • interactions
  • guilds
  • territories
  • trading
  • persistent world events

๐Ÿ—บ๏ธ The Bigger Picture

The current architecture can be summarized as:

                         THE LAST SIGNAL
                         NETWORK LAYER

                              TCP
                               โ”‚
                               โ–ผ
                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                    โ”‚      Server        โ”‚
                    โ”‚   TcpListener      โ”‚
                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                              โ”‚
                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                    โ”‚                    โ”‚
                    โ–ผ                    โ–ผ
                Client A             Client B
                    โ”‚                    โ”‚
                    โ–ผ                    โ–ผ
              receive_packet()    receive_packet()
                    โ”‚                    โ”‚
                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                              โ–ผ
                       PacketHandler
                              โ”‚
          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
          โ–ผ          โ–ผ        โ–ผ        โ–ผ          โ–ผ
        Login      Signup    Chat     Move       Log
          โ”‚          โ”‚
          โ–ผ          โ–ผ
       SQLite     SQLite
          โ”‚
          โ–ผ
     Session state
Enter fullscreen mode Exit fullscreen mode

The architecture is deliberately being built in layers:

TCP transport
     โ†“
Packet framing
     โ†“
Payload parsing
     โ†“
Packet routing
     โ†“
Authentication / database
     โ†“
Gameplay systems
Enter fullscreen mode Exit fullscreen mode

This gives the project a foundation on which the larger MMORPG systems can eventually be built.


๐Ÿš€ What's Next?

The network layer is one of the areas I expect to evolve substantially as The Last Signal Online moves from prototype infrastructure toward actual multiplayer gameplay.

The next major challenges are not simply "making packets work".

They are about making the protocol:

  • reliable
  • testable
  • extensible
  • secure
  • efficient
  • easy for contributors to understand

And that is exactly where open-source development becomes interesting.


๐Ÿค Want to Contribute?

The Last Signal Online is an open-source project, and there are several ways to contribute.

You don't need to work on gameplay to help.

Current areas include:

  • ๐Ÿฆ€ Rust server development
  • ๐ŸŒ network protocol development
  • ๐Ÿงช network testing
  • ๐Ÿ Python client development
  • ๐Ÿ” security and cryptography review
  • โš™๏ธ CI/CD
  • ๐Ÿ“š documentation
  • ๐ŸŒ translation
  • ๐ŸŽฎ game design

If you're interested in Rust networking, multiplayer architecture, Python clients, testing, or open-source game development, there are already areas where you can get involved.

๐Ÿ‘‰ ๐Ÿ‘‹ New Contributor? Start Here!

You can also explore the project's open issues and choose a problem that matches your interests and experience.


๐Ÿฆ€ About The Last Signal Online

The Last Signal Online is an open-source post-apocalyptic persistent-world MMORPG built with Rust and Python.

The goal is to create a multiplayer world combining:

  • exploration
  • survival
  • combat
  • player interaction
  • economy
  • crafting
  • factions and territories
  • persistent world systems

The project is still under development, which means the architecture is evolving alongside the game itself.

That also means there are plenty of interesting problems left to solve.

๐Ÿ‘‰ Explore the project on GitHub


๐Ÿ’ฌ Final Thoughts

Building the network layer of an MMORPG is a very different problem from building a simple client/server application.

A Ping packet is easy.

Building a protocol that can eventually carry an entire persistent multiplayer world is much harder.

That's the challenge I'm working on with The Last Signal Online.

And I'm building it openly, one system at a time.

If Rust, networking, Python, game development, or open source interests you, feel free to take a look at the project. ๐Ÿฆ€๐Ÿ๐ŸŒ

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.