Skip to content
irrld edited this page Jul 30, 2026 · 5 revisions

Events

znet reports everything through one callback per object. You set it once, and dispatch inside it by type.

void OnEvent(Event& event) {
  EventDispatcher dispatcher{event};
  dispatcher.Dispatch<IncomingClientConnectedEvent>(
      ZNET_BIND_GLOBAL_FN(OnClientConnected));
  dispatcher.Dispatch<ServerClientDisconnectedEvent>(
      ZNET_BIND_GLOBAL_FN(OnClientDisconnected));
}

Each Dispatch<T> runs its function only if the event is a T. Handlers return bool: true marks the event handled, false leaves it for anything after it. false is the usual answer.

ZNET_BIND_GLOBAL_FN wraps a free function; ZNET_BIND_FN wraps a member function, capturing this.

Server events

Event When Accessors
ServerStartupEvent The listener is up, before any connection server()
IncomingClientConnectedEvent A session finished its handshake and is ready session()
ServerClientDisconnectedEvent A session ended session()
ServerShutdownEvent The listener is closing, before sessions are torn down server()

IncomingClientConnectedEvent is where a session gets its codec and handler. It fires once the handshake is done, so encryption is already negotiated and the session can send immediately.

A session that dies before becoming ready produces no ServerClientDisconnectedEvent, because it never produced a connected event either. Events come in pairs, so you do not have to track half-open connections to keep your own bookkeeping balanced.

Client events

Event When Accessors
ClientConnectedToServerEvent The handshake completed session()
ClientDisconnectedFromServerEvent The session ended session()

A connection attempt that never succeeds — refused, unreachable, or past connection_timeout — produces a disconnect event without a preceding connect event. This is the one place the pairing does not hold, and it is how you detect a failed dial.

P2P events

Covered in Peer-to-Peer: PeerLocatorReadyEvent, PeerConnectedEvent, PeerLocatorCloseEvent.

Which thread calls you

The callback does not run on the thread that created the server or client.

  • Server: the worker that owns that session, or the acceptor thread for a session not yet promoted
  • Client: the client's loop thread

So anything your handler touches is shared state, and needs its own synchronization. Full rules in Threading Model.

Defining your own events

Any type deriving from Event and carrying the two class macros can go through the same dispatcher:

class MatchStartedEvent : public Event {
 public:
  ZNET_EVENT_CLASS_TYPE(MatchStartedEvent)
  ZNET_EVENT_CLASS_CATEGORY(EventCategoryUser)
};

Useful for routing your own state changes through the same callback rather than maintaining a second path beside it.

Clone this wiki locally