mirror of
https://github.com/ApfelTeeSaft/WV-Networking.git
synced 2026-08-26 19:43:26 +00:00
23 KiB
23 KiB
WVNet - Networking Architecture Design
Overview
WVNet is a networking library for WV-Core that implements Unreal Engine-style server-authoritative networking and replication. This document outlines the architecture, design decisions, and implementation strategy.
Architecture Diagram
┌─────────────────────────────────────────────────────────────┐
│ WV-Core App │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ App::Run() Game Loop │ │
│ │ Start() -> Update() -> NetworkTick() -> Render() │ │
│ └─────────────────────┬────────────────────────────────┘ │
└────────────────────────┼──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ WVNet Library │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ NetworkManager │ │
│ │ • Initialize/Shutdown │ │
│ │ • Tick (process packets, replicate actors) │ │
│ │ • Owns NetDriver │ │
│ └────────┬─────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ NetDriver │ │
│ │ • Socket management │ │
│ │ • Accept/connect clients │ │
│ │ • Send/receive packets │ │
│ │ • Owns multiple NetConnections │ │
│ └────────┬─────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ NetConnection (per client) │ │
│ │ • Packet buffering & reliability │ │
│ │ • Sequence numbers │ │
│ │ • Connection state (connecting/open/closed) │ │
│ │ • Per-connection replication state │ │
│ └────────┬─────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ ReplicationManager │ │
│ │ • Track replicated actors │ │
│ │ • Compute property deltas │ │
│ │ • Relevancy/interest management │ │
│ │ • Serialize/deserialize actor state │ │
│ └────────┬─────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ RPCManager │ │
│ │ • Register RPC functions │ │
│ │ • Serialize/deserialize RPC calls │ │
│ │ • Dispatch RPCs (Server/Client/Multicast) │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Platform Socket Abstraction │ │
│ │ • WVSocket, WVSocketAddress │ │
│ │ • Windows: WinSock2 │ │
│ │ • macOS/Linux: BSD sockets │ │
│ └──────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
Core Components
1. NetworkManager (Singleton)
Responsibilities:
- Central networking coordinator
- Initialize/shutdown networking subsystem
- Main tick function called from game loop
- Configuration management
- Access point for networking functionality
API:
class NetworkManager {
public:
static NetworkManager& Get();
void Initialize(const NetworkConfig& config);
void Shutdown();
void Tick(float deltaTime);
bool IsServer() const;
bool IsClient() const;
bool IsNetworked() const;
NetDriver* GetNetDriver();
ReplicationManager* GetReplicationManager();
RPCManager* GetRPCManager();
};
Configuration:
struct NetworkConfig {
NetworkMode mode; // Server, Client, or Standalone
std::string serverAddress; // For clients
uint16_t serverPort; // Default: 7777
uint32_t maxConnections; // For servers, default: 64
float tickRate; // Network update rate (Hz), default: 30
bool enableRelevancy; // Enable actor relevancy checks
float relevancyDistance; // Default relevancy distance
};
2. NetDriver
Responsibilities:
- Low-level socket management
- Accept incoming connections (server)
- Connect to server (client)
- Send/receive raw packets
- Manage NetConnection objects
- Packet routing
API:
class NetDriver {
public:
bool InitAsServer(uint16_t port, uint32_t maxConnections);
bool InitAsClient(const std::string& address, uint16_t port);
void Shutdown();
void Tick(float deltaTime);
void SendPacket(NetConnection* connection, const Packet& packet);
const std::vector<NetConnection*>& GetConnections() const;
NetConnection* GetServerConnection(); // For clients
private:
WVSocket* m_socket;
std::vector<std::unique_ptr<NetConnection>> m_connections;
NetConnection* m_serverConnection; // Client only
NetworkMode m_mode;
};
3. NetConnection
Responsibilities:
- Represents a single network connection
- Packet reliability and ordering
- Sequence number management
- Connection state tracking
- Per-connection replication state
API:
enum class ConnectionState {
Connecting,
Connected,
Disconnecting,
Disconnected
};
class NetConnection {
public:
NetConnection(const WVSocketAddress& address);
void SendPacket(const Packet& packet, bool reliable = true);
void ReceivePacket(const Packet& packet);
void Tick(float deltaTime);
ConnectionState GetState() const;
const WVSocketAddress& GetAddress() const;
float GetRoundTripTime() const;
// Replication state per actor per connection
ActorReplicationState* GetActorReplicationState(uint32_t actorNetId);
private:
WVSocketAddress m_address;
ConnectionState m_state;
// Reliability
uint32_t m_outgoingSequence;
uint32_t m_incomingSequence;
std::map<uint32_t, Packet> m_reliableBuffer; // Awaiting ack
std::queue<Packet> m_outgoingQueue;
// Timing
float m_roundTripTime;
float m_lastReceiveTime;
// Replication state
std::unordered_map<uint32_t, std::unique_ptr<ActorReplicationState>> m_replicationState;
};
4. ReplicationManager
Responsibilities:
- Track all replicated actors in the world
- Compute property deltas (what changed since last replication)
- Manage actor relevancy (which clients see which actors)
- Serialize/deserialize actor state
- Handle actor spawn/destroy replication
API:
class ReplicationManager {
public:
void Tick(float deltaTime);
// Actor registration
void RegisterActor(Actor* actor);
void UnregisterActor(Actor* actor);
// Replication
void ReplicateActors(NetConnection* connection);
void ProcessActorReplication(const Packet& packet);
// Relevancy
bool IsActorRelevantForConnection(Actor* actor, NetConnection* connection);
void SetRelevancyDistance(float distance);
private:
std::vector<Actor*> m_replicatedActors;
float m_replicationInterval; // 1.0 / tickRate
float m_timeSinceLastReplication;
float m_relevancyDistance;
};
Actor Replication State (per actor, per connection):
struct ActorReplicationState {
uint32_t actorNetId;
std::unordered_map<std::string, ReplicatedProperty> properties;
float lastReplicationTime;
bool spawned; // Has this actor been spawned on the client?
};
struct ReplicatedProperty {
std::string name;
PropertyType type;
std::vector<uint8_t> lastValue; // Last replicated value
bool dirty; // Has it changed?
};
5. RPCManager
Responsibilities:
- Register RPC functions with metadata
- Serialize RPC calls with parameters
- Deserialize and dispatch RPC calls
- Handle different RPC types (Server, Client, Multicast)
API:
enum class RPCType {
Server, // Called on client, executed on server
Client, // Called on server, executed on specific client
Multicast // Called on server, executed on all clients
};
class RPCManager {
public:
// Registration
void RegisterRPC(const std::string& functionName, RPCType type,
std::function<void(Actor*, BitStream&)> handler);
// Invocation
void CallServerRPC(Actor* actor, const std::string& functionName, BitStream& params);
void CallClientRPC(Actor* actor, NetConnection* client, const std::string& functionName, BitStream& params);
void CallMulticastRPC(Actor* actor, const std::string& functionName, BitStream& params);
// Processing
void ProcessRPC(const Packet& packet, NetConnection* sender);
private:
struct RPCMetadata {
std::string name;
RPCType type;
std::function<void(Actor*, BitStream&)> handler;
};
std::unordered_map<std::string, RPCMetadata> m_rpcRegistry;
};
6. Actor System (New for WV-Core)
Since WV-Core lacks an entity/actor system, we'll introduce a lightweight one:
Actor Base Class:
class Actor {
public:
Actor();
virtual ~Actor();
virtual void Tick(float deltaTime) {}
virtual void OnSpawn() {}
virtual void OnDestroy() {}
// Networking
void SetReplicates(bool replicates);
bool GetReplicates() const;
uint32_t GetNetId() const;
bool IsNetworked() const;
// Transform (basic, can be extended)
void SetPosition(const glm::vec3& pos);
glm::vec3 GetPosition() const;
void SetRotation(const glm::quat& rot);
glm::quat GetRotation() const;
// Replication hooks
virtual void GetReplicatedProperties(std::vector<ReplicatedProperty*>& outProps);
virtual void OnReplicated() {}
protected:
// Helpers for derived classes
void RegisterReplicatedProperty(const std::string& name, void* ptr, PropertyType type);
private:
uint32_t m_netId;
bool m_replicates;
glm::vec3 m_position;
glm::quat m_rotation;
std::unordered_map<std::string, ReplicatedProperty> m_replicatedProperties;
};
World/Scene Manager:
class World {
public:
static World& Get();
void Tick(float deltaTime);
Actor* SpawnActor(std::unique_ptr<Actor> actor);
void DestroyActor(Actor* actor);
Actor* GetActorByNetId(uint32_t netId);
const std::vector<Actor*>& GetActors() const;
private:
std::vector<std::unique_ptr<Actor>> m_actors;
std::unordered_map<uint32_t, Actor*> m_actorsByNetId;
uint32_t m_nextNetId;
};
7. Platform Socket Abstraction
Cross-platform socket wrapper:
// Socket address abstraction
class WVSocketAddress {
public:
WVSocketAddress();
WVSocketAddress(const std::string& ip, uint16_t port);
std::string GetIP() const;
uint16_t GetPort() const;
bool IsValid() const;
// Platform-specific accessors
#ifdef PLATFORM_WINDOWS
const sockaddr_in& GetNative() const;
#else
const sockaddr_in& GetNative() const;
#endif
private:
sockaddr_in m_address;
};
// Socket abstraction
class WVSocket {
public:
WVSocket();
~WVSocket();
// Initialization
bool CreateUDP();
bool Bind(uint16_t port);
void Close();
// I/O (non-blocking)
bool SetNonBlocking(bool nonBlocking);
int32_t SendTo(const void* data, size_t size, const WVSocketAddress& dest);
int32_t ReceiveFrom(void* buffer, size_t size, WVSocketAddress& source);
// State
bool IsValid() const;
int32_t GetLastError() const;
private:
#ifdef PLATFORM_WINDOWS
SOCKET m_socket;
bool m_wsaInitialized;
#else
int m_socket;
#endif
};
// Socket initialization helper
class SocketSystem {
public:
static bool Initialize();
static void Shutdown();
};
Packet Structure
Base Packet Format
┌────────────────────────────────────────────────────┐
│ Header (12 bytes) │
├────────────────────────────────────────────────────┤
│ uint32_t magic (4 bytes) - 0x57564E45 ('WVNE') │
│ uint32_t sequence (4 bytes) │
│ uint16_t packetType (2 bytes) │
│ uint16_t payloadSize (2 bytes) │
├────────────────────────────────────────────────────┤
│ Payload (variable size) │
└────────────────────────────────────────────────────┘
Packet Types
enum class PacketType : uint16_t {
// Connection
ConnectionRequest = 0,
ConnectionAccept = 1,
ConnectionDenied = 2,
Disconnect = 3,
// Reliability
Acknowledgement = 10,
// Replication
ActorSpawn = 20,
ActorDestroy = 21,
ActorReplication = 22,
// RPC
RPCServer = 30,
RPCClient = 31,
RPCMulticast = 32,
// Control
Heartbeat = 100,
};
Replication Strategy
Property Replication
- Registration: Actors register properties for replication using macros or manual registration
- Delta Calculation: Before sending, compare current value with last replicated value
- Serialization: Only serialize changed properties (delta compression)
- Per-Connection State: Track what each client has received independently
Example Usage
class PlayerActor : public Actor {
public:
PlayerActor() {
SetReplicates(true);
RegisterReplicatedProperty("Health", &m_health, PropertyType::Int32);
RegisterReplicatedProperty("Position", &m_position, PropertyType::Vector3);
}
WV_RPC_SERVER
void TakeDamage(int32_t damage) {
if (NetworkManager::Get().IsServer()) {
m_health -= damage;
if (m_health <= 0) {
OnDeath();
}
}
}
WV_RPC_MULTICAST
void OnDeath() {
// Play death animation on all clients
}
private:
int32_t m_health = 100;
glm::vec3 m_position;
};
RPC System
RPC Macros
// Macro definitions
#define WV_RPC_SERVER // Marks function as Server RPC
#define WV_RPC_CLIENT // Marks function as Client RPC
#define WV_RPC_MULTICAST // Marks function as Multicast RPC
// Implementation uses template metaprogramming to:
// 1. Automatically serialize parameters
// 2. Generate network call wrapper
// 3. Register with RPCManager
RPC Serialization
- Automatic serialization for primitive types (int, float, bool, etc.)
- Manual serialization for custom types via
BitStream& operator<< - Variadic templates for flexible parameter lists
Relevancy & Interest Management
Initial Implementation (Distance-Based)
bool ReplicationManager::IsActorRelevantForConnection(Actor* actor, NetConnection* connection) {
// Get the player's pawn/controlled actor for this connection
Actor* playerActor = connection->GetPlayerActor();
if (!playerActor) return false;
// Always relevant if within distance
float distance = glm::distance(actor->GetPosition(), playerActor->GetPosition());
return distance <= m_relevancyDistance;
}
Future Extensions
- Always Relevant: Certain actors (e.g., game state) always replicate
- Owner Relevant: Actor always replicates to its owner
- Team Relevant: Replicate based on team membership
- Custom Relevancy: User-defined relevancy functions
Integration with WV-Core
Minimal Changes to WV-Core
- Add network tick to game loop (
src/app/App.cpp):
void App::Run() {
// ... existing code ...
while(!window.ShouldClose()) {
// ... existing code ...
Update();
// Network tick (if initialized)
if (NetworkManager::Get().IsNetworked()) {
NetworkManager::Get().Tick(m_deltaTime);
}
Render();
// ... existing code ...
}
}
- Optional: Add World::Tick() to update all actors if actor system is adopted
Application Usage
class MyGame : public WillowVox::App {
public:
void Start() override {
// Initialize networking
WVNet::NetworkConfig config;
config.mode = WVNet::NetworkMode::Server;
config.serverPort = 7777;
config.maxConnections = 32;
config.tickRate = 30.0f;
WVNet::NetworkManager::Get().Initialize(config);
// Spawn some actors
auto player = std::make_unique<PlayerActor>();
WVNet::World::Get().SpawnActor(std::move(player));
}
void Update() override {
// Game logic
WVNet::World::Get().Tick(m_deltaTime);
}
};
Build System Integration
CMakeLists.txt Addition
# Add WVNet library
add_subdirectory(WVNet)
# Link to WVCore
target_link_libraries(WVCore PUBLIC WVNet)
# Platform-specific networking libraries
if(WIN32)
target_link_libraries(WVNet PRIVATE ws2_32)
elseif(UNIX)
# BSD sockets are part of libc on Unix
endif()
Design Principles
- Minimal Coupling: WVNet should work with WV-Core without heavy modifications
- Opt-in: Networking is optional; non-networked games shouldn't include overhead
- Extensible: Easy to add custom replication logic, relevancy rules, or packet types
- Performance: Delta compression, relevancy culling, and efficient serialization
- Cross-platform: Same API on Windows, macOS, and Linux
- Developer-Friendly: Clear APIs, good defaults, easy debugging
Unreal Engine Concept Mapping
| Unreal Engine | WVNet | Notes |
|---|---|---|
UNetDriver |
NetDriver |
Socket management and connection handling |
UNetConnection |
NetConnection |
Per-client connection state |
UChannel |
(Implicit in PacketType) | Simplified; may add explicit channels later |
AActor |
Actor |
Replicated game object base class |
UWorld |
World |
Scene/level container for actors |
UPROPERTY(Replicated) |
RegisterReplicatedProperty() |
Property replication registration |
UFUNCTION(Server) |
WV_RPC_SERVER |
Server RPC macro |
UFUNCTION(Client) |
WV_RPC_CLIENT |
Client RPC macro |
UFUNCTION(NetMulticast) |
WV_RPC_MULTICAST |
Multicast RPC macro |
GetLifetimeReplicatedProps() |
GetReplicatedProperties() |
Property registration hook |
IsNetRelevantFor() |
IsActorRelevantForConnection() |
Relevancy check |
FRepLayout |
ActorReplicationState |
Per-connection replication state |
File Structure
WVNet/
├── include/
│ └── wvnet/
│ ├── Core.h # Core definitions and macros
│ ├── NetworkManager.h
│ ├── NetDriver.h
│ ├── NetConnection.h
│ ├── ReplicationManager.h
│ ├── RPCManager.h
│ ├── Actor.h
│ ├── World.h
│ ├── Packet.h
│ ├── BitStream.h # Serialization helper
│ └── platform/
│ ├── Socket.h # Platform-agnostic API
│ ├── SocketWindows.h # Windows implementation
│ └── SocketUnix.h # Unix/macOS implementation
├── src/
│ ├── NetworkManager.cpp
│ ├── NetDriver.cpp
│ ├── NetConnection.cpp
│ ├── ReplicationManager.cpp
│ ├── RPCManager.cpp
│ ├── Actor.cpp
│ ├── World.cpp
│ ├── Packet.cpp
│ ├── BitStream.cpp
│ └── platform/
│ ├── SocketWindows.cpp
│ └── SocketUnix.cpp
├── samples/
│ ├── SimpleServer/
│ └── SimpleClient/
├── tests/
│ ├── SocketTests.cpp
│ ├── SerializationTests.cpp
│ └── ReplicationTests.cpp
├── CMakeLists.txt
└── README.md
End of Design Document