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 runtimetick_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 definitionshandlers/- 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 connectionsprotocol.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:
- Processes all pending actions
- Updates combat/skills
- 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:
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 queriesCommon 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 testNeed Help?
- Rust Book: https://doc.rust-lang.org/book/
- Tokio Tutorial: https://tokio.rs/tokio/tutorial
- Axum Examples: https://github.com/tokio-rs/axum/tree/main/examples