backend-guide-for-beginners

Guide for backend-guide-for-beginners

Backend Guide for Beginners

A simple guide for Rust first-timers and interns.

What Does the Backend Do?

┌──────────┐    WebSocket    ┌──────────────┐    SQL    ┌──────────┐
│  Player  │ ◄────────────► │  Game Server │ ◄───────► │ Database │
│ (Client) │   (real-time)   │    (Rust)    │           │(Postgres)│
└──────────┘                 └──────────────┘           └──────────┘
The backend is the "brain" of the game. It:
  • Accepts player connections
  • Processes actions (move, attack, trade)
  • Saves/loads game data
  • Prevents cheating

Key Technologies Explained

1. Tokio (Async Runtime)

What: Rust's async engine - lets one server handle thousands of players.
Analogy: Like a chef who can cook 50 orders at once by switching between them, instead of finishing one before starting another.
// ❌ Blocking (bad) - waits for database, does nothing else
let user = database.get_user(id);

// ✅ Async (good) - starts the query, does other work while waiting
let user = database.get_user(id).await;
Key files:
  • main.rs - starts the async runtime
  • tick_engine.rs - game loop that runs every 600ms

2. Axum (Web Framework)

What: Handles HTTP requests and WebSocket connections.
Analogy: Like a receptionist who directs visitors to the right department.
// Define routes
let app = Router::new()
    .route("/api/health", get(health_check))
    .route("/ws", get(websocket_handler));
Key files:
  • main.rs - route definitions
  • handlers/ - functions that respond to requests

3. WebSocket + MessagePack

What:
  • WebSocket = Always-open connection (unlike HTTP which opens/closes)
  • MessagePack = Binary JSON (smaller, faster)
Why: Games need instant communication. HTTP is too slow (request → wait → response).
HTTP:     Open → Send → Wait → Receive → Close → Open → ...
WebSocket: Open ←────────────── Send/Receive ──────────────→
Key files:
  • websocket.rs - handles player connections
  • protocol.rs - message format

4. SQLx + PostgreSQL

What: Database for saving player data.
Why SQLx? Compile-time checked queries (catches SQL errors before running!).
// SQLx checks this query at compile time
let player = sqlx::query_as!(
    Player,
    "SELECT * FROM players WHERE id = $1",
    player_id
).fetch_one(&pool).await?;
Key files:
  • database/migrations/ - table definitions
  • Any file with sqlx::query!

5. Redis (Cache)

What: Super-fast temporary storage (in RAM, not disk).
Used for:
  • Player sessions
  • Rate limiting
  • Cross-server chat
Key files:
  • redis_cache.rs

The Tick Engine (600ms)

Every 600 milliseconds, the server:
  1. Processes all pending actions
  2. Updates combat/skills
  3. Sends updates to clients
Why 600ms? This is the OSRS tick rate. All timing is based on "ticks":
  • Walking: 1 tile per tick
  • Eating food: 3 ticks
  • Attack speed: 4-6 ticks
// tick_engine.rs
const TICK_INTERVAL: Duration = Duration::from_millis(600);

loop {
    interval.tick().await;
    state.process_tick();  // Process all player actions
}

QA Environment (4 Zones)

The QA docker-compose runs 4 game server instances - one per zone:
ZonePortPurpose
Central8080Main city
Forest8081Combat area
Mines8082Mining area
Banks8083Fishing/skilling
Why? To test zone transitions before production.

File Structure Cheat Sheet

rust-engine/crates/game-server/src/
├── main.rs              # App entry point
├── websocket.rs         # Player connections
├── tick_engine.rs       # Game loop
├── game_state.rs        # Server state
│
├── combat.rs            # Combat calculations
├── skills.rs            # Skill progression
├── inventory.rs         # Player inventory
├── equipment.rs         # Equip/unequip
│
├── auth/                # Login/JWT
├── handlers/            # API endpoints
└── repositories/        # Database queries

Common Patterns

Error Handling

// Use ? to propagate errors
fn get_player(id: Uuid) -> Result<Player> {
    let player = db.query(id)?;  // If fails, returns error
    Ok(player)
}

Logging

use tracing::{info, warn, error};

info!("Player {} logged in", player_name);
warn!("Slow tick: {:?}", elapsed);
error!("Database connection failed: {}", e);

Getting Started

# 1. Start database
docker-compose up -d postgres redis

# 2. Run server
cd rust-engine
cargo run

# 3. Run tests
cargo test

Need Help?