- Broker: Public HiveMQ (
broker.hivemq.com:1883) - Position Updates: Every 20ms (throttled), QoS 0 (fire-and-forget)
- Game State: Published on events (not regular timer)
- Serialization: JSON
- Architecture: Host-client (host authoritative for game state, players authoritative for own position/bullets)
-
Broker Location: Public broker may be geographically distant from players
- All messages route through broker (extra hop)
- Network latency to broker + broker processing + network latency to other players
- Typical round-trip: 50-200ms depending on location
-
JSON Serialization Overhead:
- Text-based format is verbose
- Parsing overhead on both ends
- Larger message sizes = more network time
-
No Client-Side Prediction:
- Remote players appear to "lag" because updates are delayed
- No interpolation between position updates
- Jerky movement when updates arrive
-
Update Frequency:
- 20ms position updates = 50 updates/second (good)
- But with broker latency, effective update rate is lower
- Game state snapshots are event-based (could miss updates)
- Option: Deploy local Mosquitto broker or use regional HiveMQ Cloud
- Benefit: Reduce network latency to broker
- Drawback: Requires infrastructure setup
- Latency Improvement: 20-50ms reduction
- Option: Replace JSON with binary serialization
- Benefit:
- Smaller message sizes (30-50% reduction)
- Faster serialization/deserialization
- Lower bandwidth usage
- Drawback: Requires code changes, less human-readable
- Latency Improvement: 5-15ms reduction per message
- Option: Predict remote player positions between updates
- Implementation:
- Store last 2-3 position updates per player
- Interpolate position between updates
- Extrapolate if update is late
- Snap to authoritative position when received
- Benefit: Smooth movement even with 50-100ms latency
- Drawback: Requires interpolation logic, may cause slight "rubber-banding"
- Latency Improvement: Perceived latency reduced by 50-70%
- Option: Reduce position update throttle to 10ms (100 updates/sec)
- Benefit: More frequent updates = smoother movement
- Drawback: Higher bandwidth, more broker load
- Latency Improvement: Minimal (still limited by broker latency)
- Current: Already using QoS 0 for positions (good)
- Recommendation: Use QoS 0 for all non-critical updates
- Benefit: No acknowledgment overhead
- Latency Improvement: 5-10ms per message
- Option: Only send changed data, not full state
- Benefit: Smaller messages, faster transmission
- Drawback: More complex state management
- Latency Improvement: 10-20ms for large state updates
- Best Case: 50-100ms total latency (with all optimizations)
- Realistic: 80-150ms total latency
- Still noticeable for fast-paced gameplay
WebSockets provide a direct TCP connection between clients, but still require a server for:
- Matchmaking/Signaling: Finding and connecting players
- NAT Traversal: Most players are behind routers (NAT)
┌─────────┐ ┌──────────────┐ ┌─────────┐
│ Player1 │◄───────►│ WebSocket │◄───────►│ Player2 │
│ (Host) │ │ Server │ │ (Client)│
└─────────┘ └──────────────┘ └─────────┘
How It Works:
- Host starts game → connects to WebSocket server
- Server generates game ID, stores host connection
- Client joins → connects to same server with game ID
- Server routes messages between players in same game
- All game messages go through server (similar to MQTT broker)
User Experience:
- ✅ Same as MQTT: Host selects "Start Game", others "Join Game" with ID
- ✅ No IP addresses needed
- ✅ Works across internet (server handles NAT)
- ✅ Lower latency than MQTT (direct TCP, no MQTT protocol overhead)
Latency: 30-80ms (depending on server location)
Implementation Requirements:
- WebSocket server (can be same machine as game, or cloud-hosted)
- Simple message routing logic
- Connection management
┌─────────┐ ┌──────────────┐ ┌─────────┐
│ Player1 │◄────────│ Signaling │────────►│ Player2 │
│ (Host) │ │ Server │ │ (Client)│
└─────────┘ └──────────────┘ └─────────┘
│ │
└──────── Direct P2P ──────────────────┘
How It Works:
- Host and clients connect to signaling server (for matchmaking only)
- Signaling server exchanges connection info (ICE candidates)
- Players establish direct P2P connection (bypassing server)
- Game messages sent directly between players
User Experience:
- ✅ Same: Host "Start Game", others "Join Game" with ID
- ✅ No IP addresses needed (signaling server handles discovery)
- ✅ Lowest latency (direct connection, no server hop)
⚠️ May not work if both players behind strict NATs
Latency: 20-60ms (direct connection)
Implementation Requirements:
- Signaling server (lightweight, just for matchmaking)
- WebRTC library (complex, but handles NAT traversal)
- Fallback to server relay if P2P fails
- Use WebSocket server for matchmaking and initial connection
- Attempt direct TCP connection between players
- Fall back to server relay if direct connection fails
- Best of both worlds: low latency when possible, reliable when not
| Aspect | MQTT (Current) | WebSockets |
|---|---|---|
| Latency | 80-200ms | 30-80ms |
| Protocol Overhead | Higher (MQTT protocol) | Lower (raw TCP) |
| Message Format | JSON (can be binary) | JSON or binary |
| Connection Model | Pub/Sub (broker) | Direct (server relay) |
| NAT Traversal | Handled by broker | Requires server |
| User Experience | Game ID join | Game ID join (same) |
| Infrastructure | Public broker (free) | Need to host server |
| Scalability | Excellent (broker handles) | Good (server handles) |
| Complexity | Medium | Medium-High |
Server Requirements:
- Simple WebSocket server (Node.js, C#, Python, etc.)
- Game room management (track active games)
- Message routing (forward messages to all players in game)
- Can be hosted on:
- Same machine as game (for LAN)
- Cloud service (AWS, Azure, DigitalOcean)
- Free tier services (Heroku, Railway, Fly.io)
Message Protocol (similar to MQTT):
{
"type": "position",
"gameId": "ABC123",
"playerId": "player1",
"data": { "x": 150, "y": 200, "sequence": 123 }
}Code Changes Required:
- Replace
MqttGameClientwithWebSocketGameClient - Replace broker connection with WebSocket server connection
- Similar message routing logic
- Same DTOs can be reused
How It Works:
- Direct UDP sockets between players
- Requires port forwarding or UPnP
- No server needed (for LAN play)
Pros:
- Lowest latency (10-30ms)
- No server costs
- Full control
Cons:
- ❌ Requires IP addresses (or LAN discovery)
- ❌ NAT traversal issues (won't work across internet without setup)
- ❌ No reliability (UDP is unreliable)
- ❌ More complex implementation
User Experience:
⚠️ Players need to know host IP address⚠️ May require port forwarding⚠️ Only works on LAN or with network configuration
Not Recommended for internet play.
How It Works:
- Use existing game networking library
- Hosted service or self-hosted server
Pros:
- ✅ Battle-tested, optimized
- ✅ Built-in features (lag compensation, prediction)
- ✅ Good documentation
Cons:
- ❌ Additional dependency
- ❌ May have licensing costs
- ❌ Less control over implementation
- ❌ May be overkill for this project
Examples:
- Photon (Unity-focused, but has .NET SDK)
- Mirror Networking
- Lidgren Network
Already covered in Option 2B - see WebRTC section above.
Quick Wins (1-2 days work):
- ✅ Add client-side interpolation for remote players
- ✅ Switch to MessagePack for binary serialization
- ✅ Implement delta compression for game state
- ✅ Increase position update frequency to 10ms
Expected Result: 50-70% perceived latency reduction, still noticeable but playable
Implementation (3-5 days work):
- Create simple WebSocket server (C# or Node.js)
- Replace MQTT client with WebSocket client
- Implement message routing on server
- Deploy server (cloud or local)
Expected Result: 60-80% latency reduction, smooth gameplay
Server Options:
- Local: Run on same machine (LAN only)
- Cloud Free Tier: Railway, Fly.io, Render (free tier available)
- Self-Hosted: VPS ($5-10/month)
Implementation (1-2 weeks work):
- Implement WebRTC signaling server
- Integrate WebRTC library
- Handle NAT traversal and fallbacks
Expected Result: 80-90% latency reduction, near-instant response
| Criteria | MQTT (Improved) | WebSocket Server | WebRTC P2P |
|---|---|---|---|
| Latency | Medium (80-150ms) | Low (30-80ms) | Very Low (20-60ms) |
| Implementation Time | 1-2 days | 3-5 days | 1-2 weeks |
| Infrastructure Cost | Free (public broker) | Free-$10/mo | Free-$5/mo |
| User Experience | Same (Game ID) | Same (Game ID) | Same (Game ID) |
| Reliability | High | High | Medium (NAT issues) |
| Complexity | Low | Medium | High |
| Scalability | Excellent | Good | Excellent |
Start with WebSocket Server approach:
- Best latency improvement for effort invested
- Same user experience (no IP addresses needed)
- Manageable complexity (similar to MQTT)
- Flexible deployment (local for testing, cloud for production)
- Can be implemented incrementally (keep MQTT as fallback initially)
Implementation Plan:
- Create simple WebSocket server (C# console app or ASP.NET Core)
- Implement game room management
- Replace MQTT client with WebSocket client in game
- Test locally first
- Deploy to cloud for internet play
Server Code Structure (pseudo-code):
// WebSocket server
- GameRoom class (tracks players, routes messages)
- WebSocket handler (accepts connections, manages rooms)
- Message router (forwards messages to all players in room)Client Code Changes:
- Replace
MqttGameClientwithWebSocketGameClient - Same message types (DTOs can be reused)
- Similar connection flow (connect → join game → play)
Would you like me to proceed with implementing the WebSocket server approach, or would you prefer to try improving MQTT first?
gRPC is a high-performance RPC (Remote Procedure Call) framework that:
- Uses HTTP/2 as transport (multiplexed, efficient)
- Uses Protocol Buffers (protobuf) for serialization (binary, compact)
- Supports bidirectional streaming (similar to WebSockets)
- Provides strong typing and code generation
- Lower latency than REST/JSON APIs
Architecture:
┌─────────┐ ┌──────────────┐ ┌─────────┐
│ Player1 │◄───────►│ gRPC Server │◄───────►│ Player2 │
│ (Host) │ │ (Streaming) │ │ (Client)│
└─────────┘ └──────────────┘ └─────────┘
How It Works:
- Host starts game → connects to gRPC server via bidirectional stream
- Server generates game ID, stores host stream
- Client joins → connects to same server with game ID
- Server routes messages between players using streaming
- All game messages go through server (similar to WebSocket server)
User Experience:
- ✅ Same as WebSocket: Host "Start Game", others "Join Game" with ID
- ✅ No IP addresses needed
- ✅ Works across internet (server handles NAT)
- ✅ Lower latency than WebSockets (HTTP/2 multiplexing, binary protobuf)
Latency: 25-70ms (slightly better than WebSockets due to HTTP/2 efficiency)
Key Advantages Over WebSockets:
- HTTP/2 Multiplexing: Multiple streams over single connection (less overhead)
- Binary Protobuf: More efficient than JSON (30-50% smaller messages)
- Built-in Code Generation: Type-safe messages, less manual serialization
- Better Compression: HTTP/2 header compression
- Streaming Built-in: Native bidirectional streaming support
- Strong Typing: Compile-time type checking
Implementation Requirements:
- gRPC server (ASP.NET Core gRPC, or standalone)
- Protocol buffer definitions (.proto files)
- Code generation for client/server
| Aspect | WebSockets | gRPC |
|---|---|---|
| Transport | TCP (raw) | HTTP/2 |
| Serialization | JSON (or binary) | Protobuf (binary) |
| Message Size | Larger (JSON) | Smaller (protobuf) |
| Latency | 30-80ms | 25-70ms |
| Type Safety | Manual (DTOs) | Generated (protobuf) |
| Multiplexing | No (one stream) | Yes (HTTP/2) |
| Compression | Manual | Built-in (HTTP/2) |
| Code Generation | No | Yes (.proto → C#) |
| Browser Support | Excellent | Limited (needs gRPC-Web) |
| Complexity | Medium | Medium-High |
| .NET Support | Good | Excellent (native) |
Protocol Buffer Definition (example):
syntax = "proto3";
package nsnipes;
// Game service for multiplayer
service GameService {
// Bidirectional streaming for game messages
rpc GameStream(stream GameMessage) returns (stream GameMessage);
// Join game request
rpc JoinGame(JoinRequest) returns (JoinResponse);
// Get game state
rpc GetGameState(GameStateRequest) returns (GameStateSnapshot);
}
message GameMessage {
string gameId = 1;
string playerId = 2;
oneof message {
PlayerPositionUpdate position = 10;
BulletUpdate bullet = 11;
GameStateSnapshot state = 12;
// ... other message types
}
}
message PlayerPositionUpdate {
int32 x = 1;
int32 y = 2;
int64 sequence = 3;
int64 timestamp = 4;
}
message BulletUpdate {
string bulletId = 1;
double x = 2;
double y = 3;
double velocityX = 4;
double velocityY = 5;
string action = 6; // "fired", "updated", "hit", "expired"
}Server Code (C# ASP.NET Core):
public class GameService : GameServiceBase
{
private readonly GameRoomManager _roomManager;
public override async Task GameStream(
IAsyncStreamReader<GameMessage> requestStream,
IServerStreamWriter<GameMessage> responseStream,
ServerCallContext context)
{
// Handle bidirectional streaming
// Similar to WebSocket message handling
}
}Client Code (C#):
var channel = GrpcChannel.ForAddress("https://game-server.example.com");
var client = new GameService.GameServiceClient(channel);
// Bidirectional streaming
using var call = client.GameStream();
// Send/receive messagesCode Changes Required:
- Define
.protofiles for all message types - Generate C# code from protobuf
- Replace
MqttGameClientwithGrpcGameClient - Implement gRPC server (ASP.NET Core or standalone)
- Similar message routing logic (can reuse business logic)
Not Recommended - gRPC doesn't fit MQTT's pub/sub model:
- MQTT is publish/subscribe (many-to-many)
- gRPC is request/response or streaming (point-to-point)
- Would require significant architecture change
- Better to replace MQTT entirely with gRPC than try to combine
gRPC vs WebSockets:
- ✅ gRPC wins on: Efficiency, type safety, code generation
- ✅ WebSockets win on: Simplicity, browser support, wider adoption
- Verdict: gRPC is better for .NET-to-.NET communication, WebSockets better for web compatibility
gRPC vs Direct UDP:
- ✅ gRPC wins on: Reliability, NAT traversal, ease of use
- ✅ UDP wins on: Raw latency (but requires manual implementation)
- Verdict: gRPC is much better for internet play
gRPC vs WebRTC:
- ✅ gRPC wins on: Simplicity, server-based (no NAT issues)
- ✅ WebRTC wins on: Direct P2P latency (when it works)
- Verdict: gRPC is more reliable, WebRTC is lower latency when P2P works
Best Use Case: Replace WebSocket server with gRPC server
Why:
- Better Performance: HTTP/2 + protobuf = lower latency than WebSockets
- Type Safety: Generated code reduces bugs
- Native .NET: Excellent C# support (ASP.NET Core gRPC)
- Same User Experience: Game ID join, no IP addresses needed
- Future-Proof: Modern, actively developed
Implementation Plan:
- Define
.protofiles for all game messages - Generate C# code from protobuf
- Create gRPC server (ASP.NET Core)
- Implement game room management
- Replace MQTT client with gRPC client
- Deploy server (same options as WebSocket server)
Estimated Latency: 25-70ms (5-10ms better than WebSockets)
Complexity: Medium-High (requires learning protobuf, but well-documented)
| Criteria | MQTT (Improved) | WebSocket Server | gRPC Server | WebRTC P2P |
|---|---|---|---|---|
| Latency | Medium (80-150ms) | Low (30-80ms) | Very Low (25-70ms) | Very Low (20-60ms) |
| Implementation Time | 1-2 days | 3-5 days | 4-6 days | 1-2 weeks |
| Infrastructure Cost | Free (public broker) | Free-$10/mo | Free-$10/mo | Free-$5/mo |
| User Experience | Same (Game ID) | Same (Game ID) | Same (Game ID) | Same (Game ID) |
| Reliability | High | High | High | Medium (NAT issues) |
| Complexity | Low | Medium | Medium-High | High |
| Type Safety | Manual | Manual | Generated | Manual |
| Message Efficiency | JSON | JSON/Binary | Protobuf (best) | Binary |
| .NET Support | Good (MQTTnet) | Good | Excellent (native) | Limited |
If you want the best latency with good .NET support:
- ✅ Lowest latency of server-based solutions (25-70ms)
- ✅ Best message efficiency (protobuf)
- ✅ Type-safe generated code
- ✅ Native .NET support (ASP.NET Core gRPC)
⚠️ Requires learning protobuf (but well-documented)⚠️ Slightly more complex than WebSockets
Best for: Production-ready solution with best performance
If you want good performance with simpler implementation:
- ✅ Good latency (30-80ms)
- ✅ Simpler than gRPC
- ✅ Easy to understand and debug
- ✅ Wide compatibility
⚠️ Slightly higher latency than gRPC⚠️ Manual serialization
Best for: Quick implementation with good results
If you want minimal changes:
- ✅ Fastest to implement (1-2 days)
- ✅ No infrastructure changes
⚠️ Still noticeable latency (80-150ms)⚠️ Limited improvement potential
Best for: Quick fix while planning better solution
For NSnipes, I recommend gRPC Server:
- Best latency of server-based solutions (25-70ms)
- Excellent .NET support (native ASP.NET Core)
- Type safety reduces bugs
- Future-proof technology
- Same user experience (Game ID join)
- Manageable complexity (4-6 days implementation)
The slight additional complexity over WebSockets is worth it for the performance gains and type safety benefits, especially since you're already using C# and .NET.
Would you like me to:
- Implement gRPC server approach (recommended)
- Implement WebSocket server approach (simpler alternative)
- Improve MQTT first (quick fix)