diff --git a/yojimbo.h b/yojimbo.h index 807cc119..4aa51578 100644 --- a/yojimbo.h +++ b/yojimbo.h @@ -44,6 +44,8 @@ #include "yojimbo_network_info.h" #include "yojimbo_server_interface.h" #include "yojimbo_base_server.h" +#include "yojimbo_server.h" +#include "yojimbo_client_interface.h" /** @file */ @@ -83,295 +85,6 @@ void ShutdownYojimbo(); namespace yojimbo { - /** - Dedicated server implementation. - */ - - class Server : public BaseServer - { - public: - - Server( Allocator & allocator, const uint8_t privateKey[], const Address & address, const ClientServerConfig & config, Adapter & adapter, double time ); - - ~Server(); - - void Start( int maxClients ); - - void Stop(); - - void DisconnectClient( int clientIndex ); - - void DisconnectAllClients(); - - void SendPackets(); - - void ReceivePackets(); - - void AdvanceTime( double time ); - - bool IsClientConnected( int clientIndex ) const; - - uint64_t GetClientId( int clientIndex ) const; - - netcode_address_t * GetClientAddress( int clientIndex ) const; - - int GetNumConnectedClients() const; - - void ConnectLoopbackClient( int clientIndex, uint64_t clientId, const uint8_t * userData ); - - void DisconnectLoopbackClient( int clientIndex ); - - bool IsLoopbackClient( int clientIndex ) const; - - void ProcessLoopbackPacket( int clientIndex, const uint8_t * packetData, int packetBytes, uint64_t packetSequence ); - - const Address & GetAddress() const { return m_boundAddress; } - - private: - - void TransmitPacketFunction( int clientIndex, uint16_t packetSequence, uint8_t * packetData, int packetBytes ); - - int ProcessPacketFunction( int clientIndex, uint16_t packetSequence, uint8_t * packetData, int packetBytes ); - - void ConnectDisconnectCallbackFunction( int clientIndex, int connected ); - - void SendLoopbackPacketCallbackFunction( int clientIndex, const uint8_t * packetData, int packetBytes, uint64_t packetSequence ); - - static void StaticConnectDisconnectCallbackFunction( void * context, int clientIndex, int connected ); - - static void StaticSendLoopbackPacketCallbackFunction( void * context, int clientIndex, const uint8_t * packetData, int packetBytes, uint64_t packetSequence ); - - ClientServerConfig m_config; - netcode_server_t * m_server; - Address m_address; // original address passed to ctor - Address m_boundAddress; // address after socket bind, eg. valid port - uint8_t m_privateKey[KeyBytes]; - }; - - /** - The set of client states. - */ - - enum ClientState - { - CLIENT_STATE_ERROR = -1, - CLIENT_STATE_DISCONNECTED = 0, - CLIENT_STATE_CONNECTING, - CLIENT_STATE_CONNECTED, - }; - - /** - The common interface for all clients. - */ - - class ClientInterface - { - public: - - virtual ~ClientInterface() {} - - /** - Set the context for reading and writing packets. - This is optional. It lets you pass in a pointer to some structure that you want to have available when reading and writing packets via Stream::GetContext. - Typical use case is to pass in an array of min/max ranges for values determined by some data that is loaded from a toolchain vs. being known at compile time. - If you do use a context, make sure the same context data is set on client and server, and include a checksum of the context data in the protocol id. - */ - - virtual void SetContext( void * context ) = 0; - - /** - Disconnect from the server. - */ - - virtual void Disconnect() = 0; - - /** - Send packets to server. - */ - - virtual void SendPackets() = 0; - - /** - Receive packets from the server. - */ - - virtual void ReceivePackets() = 0; - - /** - Advance client time. - Call this at the end of each frame to advance the client time forward. - IMPORTANT: Please use a double for your time value so it maintains sufficient accuracy as time increases. - */ - - virtual void AdvanceTime( double time ) = 0; - - /** - Is the client connecting to a server? - This is true while the client is negotiation connection with a server. - @returns true if the client is currently connecting to, but is not yet connected to a server. - */ - - virtual bool IsConnecting() const = 0; - - /** - Is the client connected to a server? - This is true once a client successfully finishes connection negotiatio, and connects to a server. It is false while connecting to a server. - @returns true if the client is connected to a server. - */ - - virtual bool IsConnected() const = 0; - - /** - Is the client in a disconnected state? - A disconnected state corresponds to the client being in the disconnected, or in an error state. Both are logically "disconnected". - @returns true if the client is disconnected. - */ - - virtual bool IsDisconnected() const = 0; - - /** - Is the client in an error state? - When the client disconnects because of an error, it enters into this error state. - @returns true if the client is in an error state. - */ - - virtual bool ConnectionFailed() const = 0; - - /** - Get the current client state. - */ - - virtual ClientState GetClientState() const = 0; - - /** - Get the client index. - The client index is the slot number that the client is occupying on the server. - @returns The client index in [0,maxClients-1], where maxClients is the number of client slots allocated on the server in Server::Start. - */ - - virtual int GetClientIndex() const = 0; - - /** - Get the client id. - The client id is a unique identifier of this client. - @returns The client id. - */ - - virtual uint64_t GetClientId() const = 0; - - /** - Get the current client time. - @see Client::AdvanceTime - */ - - virtual double GetTime() const = 0; - - /** - Create a message of the specified type. - @param type The type of the message to create. The message types corresponds to the message factory created by the adaptor set on this client. - */ - - virtual Message * CreateMessage( int type ) = 0; - - /** - Helper function to allocate a data block. - This is typically used to create blocks of data to attach to block messages. See BlockMessage for details. - @param bytes The number of bytes to allocate. - @returns The pointer to the data block. This must be attached to a message via Client::AttachBlockToMessage, or freed via Client::FreeBlock. - */ - - virtual uint8_t * AllocateBlock( int bytes ) = 0; - - /** - Attach data block to message. - @param message The message to attach the block to. This message must be derived from BlockMessage. - @param block Pointer to the block of data to attach. Must be created via Client::AllocateBlock. - @param bytes Length of the block of data in bytes. - */ - - virtual void AttachBlockToMessage( Message * message, uint8_t * block, int bytes ) = 0; - - /** - Free a block of memory. - @param block The block of memory created by Client::AllocateBlock. - */ - - virtual void FreeBlock( uint8_t * block ) = 0; - - /** - Can we send a message on a channel? - @param channelIndex The channel index in range [0,numChannels-1]. - @returns True if a message can be sent over the channel, false otherwise. - */ - - virtual bool CanSendMessage( int channelIndex ) const = 0; - - /** - Send a message on a channel. - @param channelIndex The channel index in range [0,numChannels-1]. - @param message The message to send. - */ - - virtual void SendMessage( int channelIndex, Message * message ) = 0; - - /** - Receive a message from a channel. - @param channelIndex The channel index in range [0,numChannels-1]. - @returns The message received, or NULL if no message is available. Make sure to release this message by calling Client::ReleaseMessage. - */ - - virtual Message * ReceiveMessage( int channelIndex ) = 0; - - /** - Release a message. - Call this for messages received by Client::ReceiveMessage. - @param message The message to release. - */ - - virtual void ReleaseMessage( Message * message ) = 0; - - /** - Get client network info. - Call this to receive information about the client network connection to the server, eg. round trip time, packet loss %, # of packets sent and so on. - @param info The struct to be filled with network info [out]. - */ - - virtual void GetNetworkInfo( NetworkInfo & info ) const = 0; - - /** - Connect to server over loopback. - This allows you to have local clients connected to a server, for example for integrated server or singleplayer. - @param clientIndex The index of the client. - @param clientId The unique client id. - @param maxClients The maximum number of clients supported by the server. - */ - - virtual void ConnectLoopback( int clientIndex, uint64_t clientId, int maxClients ) = 0; - - /** - Disconnect from server over loopback. - */ - - virtual void DisconnectLoopback() = 0; - - /** - Is this a loopback client? - @returns true if the client is a loopback client, false otherwise. - */ - - virtual bool IsLoopback() const = 0; - - /** - Process loopback packet. - Use this to pass packets from a server directly to the loopback client. - @param packetData The packet data to process. - @param packetBytes The number of bytes of packet data. - @param packetSequence The packet sequence number. - */ - - virtual void ProcessLoopbackPacket( const uint8_t * packetData, int packetBytes, uint64_t packetSequence ) = 0; - }; - /** Functionality that is common across all client implementations. */ diff --git a/yojimbo_client_interface.h b/yojimbo_client_interface.h new file mode 100644 index 00000000..a160c3cb --- /dev/null +++ b/yojimbo_client_interface.h @@ -0,0 +1,257 @@ +/* + Yojimbo Client/Server Network Library. + + Copyright © 2016 - 2024, Mas Bandwidth LLC. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef YOJIMBO_CLIENT_INTERFACE_H +#define YOJIMBO_CLIENT_INTERFACE_H + +#include "yojimbo_config.h" + +namespace yojimbo +{ + /** + The set of client states. + */ + + enum ClientState + { + CLIENT_STATE_ERROR = -1, + CLIENT_STATE_DISCONNECTED = 0, + CLIENT_STATE_CONNECTING, + CLIENT_STATE_CONNECTED, + }; + + /** + The common interface for all clients. + */ + + class ClientInterface + { + public: + + virtual ~ClientInterface() {} + + /** + Set the context for reading and writing packets. + This is optional. It lets you pass in a pointer to some structure that you want to have available when reading and writing packets via Stream::GetContext. + Typical use case is to pass in an array of min/max ranges for values determined by some data that is loaded from a toolchain vs. being known at compile time. + If you do use a context, make sure the same context data is set on client and server, and include a checksum of the context data in the protocol id. + */ + + virtual void SetContext( void * context ) = 0; + + /** + Disconnect from the server. + */ + + virtual void Disconnect() = 0; + + /** + Send packets to server. + */ + + virtual void SendPackets() = 0; + + /** + Receive packets from the server. + */ + + virtual void ReceivePackets() = 0; + + /** + Advance client time. + Call this at the end of each frame to advance the client time forward. + IMPORTANT: Please use a double for your time value so it maintains sufficient accuracy as time increases. + */ + + virtual void AdvanceTime( double time ) = 0; + + /** + Is the client connecting to a server? + This is true while the client is negotiation connection with a server. + @returns true if the client is currently connecting to, but is not yet connected to a server. + */ + + virtual bool IsConnecting() const = 0; + + /** + Is the client connected to a server? + This is true once a client successfully finishes connection negotiatio, and connects to a server. It is false while connecting to a server. + @returns true if the client is connected to a server. + */ + + virtual bool IsConnected() const = 0; + + /** + Is the client in a disconnected state? + A disconnected state corresponds to the client being in the disconnected, or in an error state. Both are logically "disconnected". + @returns true if the client is disconnected. + */ + + virtual bool IsDisconnected() const = 0; + + /** + Is the client in an error state? + When the client disconnects because of an error, it enters into this error state. + @returns true if the client is in an error state. + */ + + virtual bool ConnectionFailed() const = 0; + + /** + Get the current client state. + */ + + virtual ClientState GetClientState() const = 0; + + /** + Get the client index. + The client index is the slot number that the client is occupying on the server. + @returns The client index in [0,maxClients-1], where maxClients is the number of client slots allocated on the server in Server::Start. + */ + + virtual int GetClientIndex() const = 0; + + /** + Get the client id. + The client id is a unique identifier of this client. + @returns The client id. + */ + + virtual uint64_t GetClientId() const = 0; + + /** + Get the current client time. + @see Client::AdvanceTime + */ + + virtual double GetTime() const = 0; + + /** + Create a message of the specified type. + @param type The type of the message to create. The message types corresponds to the message factory created by the adaptor set on this client. + */ + + virtual Message * CreateMessage( int type ) = 0; + + /** + Helper function to allocate a data block. + This is typically used to create blocks of data to attach to block messages. See BlockMessage for details. + @param bytes The number of bytes to allocate. + @returns The pointer to the data block. This must be attached to a message via Client::AttachBlockToMessage, or freed via Client::FreeBlock. + */ + + virtual uint8_t * AllocateBlock( int bytes ) = 0; + + /** + Attach data block to message. + @param message The message to attach the block to. This message must be derived from BlockMessage. + @param block Pointer to the block of data to attach. Must be created via Client::AllocateBlock. + @param bytes Length of the block of data in bytes. + */ + + virtual void AttachBlockToMessage( Message * message, uint8_t * block, int bytes ) = 0; + + /** + Free a block of memory. + @param block The block of memory created by Client::AllocateBlock. + */ + + virtual void FreeBlock( uint8_t * block ) = 0; + + /** + Can we send a message on a channel? + @param channelIndex The channel index in range [0,numChannels-1]. + @returns True if a message can be sent over the channel, false otherwise. + */ + + virtual bool CanSendMessage( int channelIndex ) const = 0; + + /** + Send a message on a channel. + @param channelIndex The channel index in range [0,numChannels-1]. + @param message The message to send. + */ + + virtual void SendMessage( int channelIndex, Message * message ) = 0; + + /** + Receive a message from a channel. + @param channelIndex The channel index in range [0,numChannels-1]. + @returns The message received, or NULL if no message is available. Make sure to release this message by calling Client::ReleaseMessage. + */ + + virtual Message * ReceiveMessage( int channelIndex ) = 0; + + /** + Release a message. + Call this for messages received by Client::ReceiveMessage. + @param message The message to release. + */ + + virtual void ReleaseMessage( Message * message ) = 0; + + /** + Get client network info. + Call this to receive information about the client network connection to the server, eg. round trip time, packet loss %, # of packets sent and so on. + @param info The struct to be filled with network info [out]. + */ + + virtual void GetNetworkInfo( NetworkInfo & info ) const = 0; + + /** + Connect to server over loopback. + This allows you to have local clients connected to a server, for example for integrated server or singleplayer. + @param clientIndex The index of the client. + @param clientId The unique client id. + @param maxClients The maximum number of clients supported by the server. + */ + + virtual void ConnectLoopback( int clientIndex, uint64_t clientId, int maxClients ) = 0; + + /** + Disconnect from server over loopback. + */ + + virtual void DisconnectLoopback() = 0; + + /** + Is this a loopback client? + @returns true if the client is a loopback client, false otherwise. + */ + + virtual bool IsLoopback() const = 0; + + /** + Process loopback packet. + Use this to pass packets from a server directly to the loopback client. + @param packetData The packet data to process. + @param packetBytes The number of bytes of packet data. + @param packetSequence The packet sequence number. + */ + + virtual void ProcessLoopbackPacket( const uint8_t * packetData, int packetBytes, uint64_t packetSequence ) = 0; + }; +} + +#endif // #ifndef YOJIMBO_CLIENT_INTERFACE_H diff --git a/yojimbo_server.h b/yojimbo_server.h new file mode 100644 index 00000000..16b2ac46 --- /dev/null +++ b/yojimbo_server.h @@ -0,0 +1,100 @@ +/* + Yojimbo Client/Server Network Library. + + Copyright © 2016 - 2024, Mas Bandwidth LLC. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef YOJIMBO_SERVER_H +#define YOJIMBO_SERVER_H + +#include "yojimbo_config.h" + +struct netcode_server_t; + +namespace yojimbo +{ + /** + Server implementation. + */ + + class Server : public BaseServer + { + public: + + Server( Allocator & allocator, const uint8_t privateKey[], const Address & address, const ClientServerConfig & config, Adapter & adapter, double time ); + + ~Server(); + + void Start( int maxClients ); + + void Stop(); + + void DisconnectClient( int clientIndex ); + + void DisconnectAllClients(); + + void SendPackets(); + + void ReceivePackets(); + + void AdvanceTime( double time ); + + bool IsClientConnected( int clientIndex ) const; + + uint64_t GetClientId( int clientIndex ) const; + + netcode_address_t * GetClientAddress( int clientIndex ) const; + + int GetNumConnectedClients() const; + + void ConnectLoopbackClient( int clientIndex, uint64_t clientId, const uint8_t * userData ); + + void DisconnectLoopbackClient( int clientIndex ); + + bool IsLoopbackClient( int clientIndex ) const; + + void ProcessLoopbackPacket( int clientIndex, const uint8_t * packetData, int packetBytes, uint64_t packetSequence ); + + const Address & GetAddress() const { return m_boundAddress; } + + private: + + void TransmitPacketFunction( int clientIndex, uint16_t packetSequence, uint8_t * packetData, int packetBytes ); + + int ProcessPacketFunction( int clientIndex, uint16_t packetSequence, uint8_t * packetData, int packetBytes ); + + void ConnectDisconnectCallbackFunction( int clientIndex, int connected ); + + void SendLoopbackPacketCallbackFunction( int clientIndex, const uint8_t * packetData, int packetBytes, uint64_t packetSequence ); + + static void StaticConnectDisconnectCallbackFunction( void * context, int clientIndex, int connected ); + + static void StaticSendLoopbackPacketCallbackFunction( void * context, int clientIndex, const uint8_t * packetData, int packetBytes, uint64_t packetSequence ); + + ClientServerConfig m_config; + netcode_server_t * m_server; + Address m_address; // original address passed to ctor + Address m_boundAddress; // address after socket bind, eg. valid port + uint8_t m_privateKey[KeyBytes]; + }; +} + +#endif // #ifndef YOJIMBO_SERVER_H