/* ZNetworkEvent.hpp Author: James Russell Created: 9/13/2015 Purpose: Network Event abstract class. Intended to be subclassed into various subclasses that will be serialized / deserialized and processed on both client and server. Note that events that originate on the server will generally not have their HandleServer method called, as the server already processed the occurrence that originated the event. Events that originate on the client will generally be pushed to the server, have HandleServer called on them, which will generally also cause an event to be pushed to each client, who will then have HandleClient called when the event gets deserialized. From the above usage pattern, we can see that clients generally push events to the server but do not process the local occurrence (the HandleClient) until after the server has confirmed the event happens by pushing the event back to all clients, the original sender included. This usage pattern is not required for client authoritative events, which are processed locally and then handed to the server to notify other attached clients. License: TODO */ #pragma once #ifndef _ZNETWORKEVENT_HPP #define _ZNETWORKEVENT_HPP #include "ZSimulationDefs.hpp" // forward decl class ZSimulation; /* ZNetworkEvent class. */ class ZNetworkEvent { DISABLE_COPY_AND_ASSIGN(ZNetworkEvent); public: nID Type; // the type of event this is cID NetTarget; // the connection this is targeting cID NetIgnore; // if NetTarget is set to all, this target will be ignored bool InQueue; // flag set during a handle method to indicate this has been queued up for sending // handler for events on client side virtual void HandleClient(ZSimulation& server_sim) = 0; // handler for events on server side virtual void HandleServer(ZSimulation& client_sim) = 0; // called by the network system to deserialize this event from binary form (after header is read) virtual bool Deserialize(ZBinaryBufferReader& reader) = 0; // called by the network system to serialize this event into binary form virtual void Serialize(ZBinaryBufferWriter& writer) = 0; // called to get the serialized size of this event (including uint8_t message type flag) virtual size_t GetSerializedSize() = 0; // called by subclass to serialize the header (Type, PlayerSource, and PlayerTarget) void SerializeHeader(ZBinaryBufferWriter& writer) { writer.WriteU32(Type); } // called by subclass to get serialized header size size_t GetHeaderSize() { return sizeof(nID); } protected: // c'tor ZNetworkEvent(nID type) : Type(type) { } }; /* Network Event base implementation, which attempts to automatically handle serialization and deserialization via template POD structs. Note the template on the game event (DS), which indicates a POD struct. This is the data that is serialized and sent as part of the event. Wrap the struct definition in pragma pack statements to ensure correct behavior across systems and reduce bandwidth. */ template class ZNetworkEventBase : public ZNetworkEvent { DISABLE_COPY_AND_ASSIGN(ZNetworkEventBase); public: // the data struct for this event DS EventData; // called by the network system to deserialize this event from binary form (after header is read) virtual bool Deserialize(ZBinaryBufferReader& reader) { if (reader.CanRead(sizeof(DS))) { reader.ReadU8Array((uint8_t*)&EventData, sizeof(DS)); return true; } else return false; } // called by the network system to serialize this event into binary form virtual void Serialize(ZBinaryBufferWriter& writer) { SerializeHeader(writer); writer.WriteU8Array((uint8_t*)&EventData, sizeof(DS)); } // called to get the serialized size of this event virtual size_t GetSerializedSize() { return GetHeaderSize() + sizeof(DS); } protected: // c'tor ZNetworkEventBase(nID type) : ZNetworkEvent(type) { } }; #pragma pack (push, 1) /* Data struct used for message events, which will simply create the given message on the other side and pass it to the simulation. */ template struct ZMessageEventData { mID Type; eID Sender; eID Target; M MessageData; cID Connection; }; #pragma pack (pop) /* Message network event. This is used to duplicate a message on other connected simulations. The template parameter type is the message data definition struct. Be sure to use pragma pack to reduce network overhead. */ template class ZMessageEvent : public ZNetworkEventBase> { public: // c'tor ZMessageEvent(mID msg_type) : ZNetworkEventBase(0) { } ZMessageEvent(mID msg_type, eID sender, eID target, MT payload, cID connection) : ZNetworkEventBase(0), EventData({msg_type, sender, target, connection, payload}) { } // subclass implementations virtual void HandleClient(ZSimulation& server_sim) { server_sim.SendLocalMessage(Data.Type, Data.Sender, Data.Target, Data.MessageData); } virtual void HandleServer(ZSimulation& client_sim) { client_sim.SendLocalMessage(Data.Type, Data.Sender, Data.Target, Data.MessageData); } }; #endif