Here is a brief explanation of how this part of MikeNet will operate.
An instance is either a connection or a server hosting which is setup with either mnConnect or mnStartServer. You can have as many instances as you want and although they run inside the same worker threads, they do not interact with each other. The new system will basically allow you to use multiple instances of MikeNet at the same time within the same application. You can be connected to as many different servers as you want and host as many servers as you want at the same time.
I have written an example which is a modified version of the cube world demo. In this example an application can host a server and be connected to this server at the same time. Most commands now have an instance parameter which allows you to specify which instance the command should apply to.
There is also a new way of using mnConnect. The last parameter (bool) specifies whether or not to block on the connection until the timeout expires. If you choose not to then you can use mnPollConnect to poll on the connection process and wait for it to complete whilst doing other things. You can use mnStopConnect to halt the connection process thus enabling you to include a cancel button.
Example:
#include <DarkGDK.h>
#include <MikeNet.h>
// Tcp
#define OP_NEWPLAYER 0
#define OP_LEFTPLAYER 1
// Udp
#define OP_POSITIONPLAYER 0
// Mode
#define MODE_HOST 0
#define MODE_CONNECT 1
// Variables
// Set velocity and turn speed for player movement
const int Velocity = 5, TurnSpeed = 5;
// To be filled during connection
int MaximumClients;
int MaximumOperations;
// Stores the mode we are in (connect or host)
int iMode;
// Variable to hold the result of a MikeNet command
int Result;
void DarkGDK(void)
{
// Set UDP and TCP port of the server, which is 6789
unsigned short ConnectPort = 6789;
int Timeout = 10;
int NoThreads = 0;
// Start MikeNet
// Parameter 1 sets the number of instances to create
// Parameter 2 sets the number of threads to be used between each instance
mnStart(2,NoThreads);
// Find out whether to host a server or just connect to one
dbPrint("Would you like to host a game or connect to an existing one?");
dbPrint("Press 1 to host and 2 to connect");
while(LoopGDK() == true)
{
// If '1' key is pressed
if(dbScanCode() == 2)
{
dbPrint("Entering host mode...");
iMode = MODE_HOST;
break;
}
// If '2' key is pressed
if(dbScanCode() == 3)
{
dbPrint("Entering connect mode...");
iMode = MODE_CONNECT;
break;
}
dbWait(1);
}
dbWaitKey();
char * ConnectIP;
if(iMode == MODE_CONNECT)
{
// Get IP address to connect to via UDP and TCP
dbPrint("Enter the IP that you would like to connect to: ");
ConnectIP = dbInput();
}
else
{
unsigned short ConnectPort = 6789;
int MaxClients = 50;
int MaxOperations = 1;
int UdpMode = UDPMODE_PER_CLIENT_PER_OPERATION;
int NoThreads = 0;
// Set server local address information
Result = mnSetLocal(MODE_HOST,"",ConnectPort,"",ConnectPort);
if(Result == -1)
{
dbPrint("Error setting the local address");
dbWaitKey();
return;
}
// Start the server
Result = mnStartServer(MODE_HOST,MaxClients,MaxOperations,UdpMode);
// If started successfully
if(Result == 0)
{
dbPrint("Server started");
dbPrint();
dbPrint("Server local TCP port: ");
dbPrint(dbStr(mnGetLocalPortTCP(MODE_HOST)));
dbPrint("Server local UDP port: ");
dbPrint(dbStr(mnGetLocalPortUDP(MODE_HOST)));
}
// If failed to start
else
{
dbPrint("Server failed to start");
dbWaitKey();
return;
}
// Ensure that we connect to our own server
ConnectIP = "127.0.0.1";
}
// Try to connect
mnConnect(MODE_CONNECT,ConnectIP,ConnectPort,ConnectIP,ConnectPort,Timeout,false);
int Connect;
do{
// Ensure that connection is accepted
// mnClientJoined must be called otherwise connection will not be accepted
if(iMode == MODE_HOST)
{
mnClientJoined(MODE_HOST);
}
Connect = mnPollConnect(MODE_CONNECT);
// If the connection was successful
if(Connect == 1)
{
dbPrint("Connection was successful!");
// Find maximum number of clients and operations
// necassary for udp receiving
MaximumClients = mnGetMaxClients(MODE_CONNECT);
MaximumOperations = mnGetMaxOperations(MODE_CONNECT);
// Print our local IP, port and udp mode
dbPrintC("The local TCP IP is: ");
dbPrint(mnGetLocalIPTCP(MODE_CONNECT));
dbPrintC("The local TCP port is: ");
dbPrint(dbStr(mnGetLocalPortTCP(MODE_CONNECT)));
dbPrintC("The local UDP IP is: ");
dbPrint(mnGetLocalIPUDP(MODE_CONNECT));
dbPrintC("The local UDP port is: ");
dbPrint(dbStr(mnGetLocalPortUDP(MODE_CONNECT)));
dbPrintC("Your client ID is: ");
dbPrint(dbStr(mnGetClientID(MODE_CONNECT)));
dbPrint("Press any key to continue");
dbWaitKey();
}
// If the connection timed out
if(Connect == 0)
{
dbPrint("Connection timed out! Check that the server is switched on");
dbWaitKey();
return;
}
// If an error occurred during connection
if(Connect == -1)
{
dbPrint("An error occurred whilst trying to connect");
dbWaitKey();
return;
}
}while(Connect == 2); // While connection is in progress
// Setup the world for us to run around in
dbSyncOn();
dbSyncRate(40);
dbAutoCamOff();
dbMakeMatrix(1,5000,5000,50,50);
dbPositionMatrix(1,dbCameraPositionX(),dbCameraPositionY()-20,dbCameraPositionZ());
// Once connected, we loop until we become disconnected or darkgdk tells us to exit
while( (mnClientConnected(MODE_CONNECT,0) == 1) && (LoopGDK() == true) )
{
// SERVER STUFF
if(iMode == MODE_HOST)
{
// Check to see if a new client has joined
int Joined = mnClientJoined(MODE_HOST);
// If a new client has joined
if(Joined > 0)
{
// Tell the new client what clients are currently connected
for(int Client = 1;Client<=MaximumClients;Client++)
{
if(mnClientConnected(MODE_HOST, Client) == 1)
{
if(Client != Joined)
{
mnAddInt(MODE_HOST,OP_NEWPLAYER);
mnAddInt(MODE_HOST,Client);
mnSendTCP(MODE_HOST,Joined,false,false);
}
}
}
// Tell clients that a new client has joined
mnAddInt(MODE_HOST,OP_NEWPLAYER);
mnAddInt(MODE_HOST,Joined);
mnSendTCPAll(MODE_HOST,false,false,Joined);
}
// Check to see if any clients have left recently
int Left = mnClientLeft(MODE_HOST);
// If a client has left recently
if(Left > 0)
{
// Tell clients that a client has left
mnAddInt(MODE_HOST,OP_LEFTPLAYER);
mnAddInt(MODE_HOST,Left);
mnSendTCPAll(MODE_HOST,false,false,Left);
}
}
// CLIENT STUFF
// Refresh screen
dbSync();
// Player movement
if(dbUpKey() == 1){dbMoveCamera(Velocity);}
if(dbDownKey() == 1){dbMoveCamera(-Velocity);}
if(dbLeftKey() == 1){dbTurnCameraLeft(TurnSpeed);}
if(dbRightKey() == 1){dbTurnCameraRight(TurnSpeed);}
// Send our position/angle to the server via UDP
// Formulate packet
mnAddInt(MODE_CONNECT,OP_POSITIONPLAYER);
mnAddFloat(MODE_CONNECT,dbCameraPositionX());
mnAddFloat(MODE_CONNECT,dbCameraPositionY());
mnAddFloat(MODE_CONNECT,dbCameraPositionZ());
mnAddFloat(MODE_CONNECT,dbCameraAngleX());
mnAddFloat(MODE_CONNECT,dbCameraAngleY());
mnAddFloat(MODE_CONNECT,dbCameraAngleZ());
// Send packet
mnSendUDP(MODE_CONNECT,NULL,false,true);
// Check for new TCP messages
int iTcpPackets = mnRecvTCP(MODE_CONNECT,NULL);
// If there is a new TCP message
if(iTcpPackets > 0)
{
// Get operation of new message
// and player that it applies to
int Operation = mnGetInt(MODE_CONNECT);
int Player = mnGetInt(MODE_CONNECT);
// If the server is telling us that a new player has joined
// then create a cube for that player
if(Operation == OP_NEWPLAYER)
{
if(dbObjectExist(Player) == 0)
{
dbMakeObjectCube(Player,50);
}
}
// If the server is telling us that a player has left then
// delete the cube of that player
if(Operation == OP_LEFTPLAYER)
{
if(dbObjectExist(Player) == 1)
{
dbDeleteObject(Player);
}
}
}
// CLIENT AND SERVER STUFF
// Check for new UDP messages on a per client per operation basis
// Check each client
for(int Player = 1;Player<=MaximumClients;Player++)
{
// SERVER
if(iMode == MODE_HOST)
{
// Discard any TCP packets that are received, we are not expecting any
int TcpPackets = mnRecvTCP(MODE_HOST,Player);
if(TcpPackets > 0)
{
// Do nothing
}
}
// Check each operation for current client
for(int Operation = 0;Operation<MaximumOperations;Operation++)
{
// Check for new UDP messages
// CLIENT
int UdpPackets;
UdpPackets = mnRecvUDP(MODE_CONNECT,Player,Operation);
if(dbObjectExist(Player) == 1)
{
// If there is a new UDP message
if(UdpPackets == 1)
{
// Get the player's position and angle
// and apply them to his/her cube
float PosX = mnGetFloat(MODE_CONNECT);
float PosY = mnGetFloat(MODE_CONNECT);
float PosZ = mnGetFloat(MODE_CONNECT);
float RotX = mnGetFloat(MODE_CONNECT);
float RotY = mnGetFloat(MODE_CONNECT);
float RotZ = mnGetFloat(MODE_CONNECT);
dbPositionObject(Player,PosX,PosY,PosZ);
dbRotateObject(Player,RotX,RotY,RotZ);
}
}
// SERVER
if(iMode == MODE_HOST)
{
UdpPackets = mnRecvUDP(MODE_HOST,Player,Operation);
// If there is a new UDP message
if(UdpPackets == 1)
{
// Get data from packet
float PosX = mnGetFloat(MODE_HOST);
float PosY = mnGetFloat(MODE_HOST);
float PosZ = mnGetFloat(MODE_HOST);
float RotX = mnGetFloat(MODE_HOST);
float RotY = mnGetFloat(MODE_HOST);
float RotZ = mnGetFloat(MODE_HOST);
// Relay data to clients
// Formulate packet
mnAddInt(MODE_HOST,Player);
mnAddInt(MODE_HOST,OP_POSITIONPLAYER);
mnAddFloat(MODE_HOST,PosX);
mnAddFloat(MODE_HOST,PosY);
mnAddFloat(MODE_HOST,PosZ);
mnAddFloat(MODE_HOST,RotX);
mnAddFloat(MODE_HOST,RotY);
mnAddFloat(MODE_HOST,RotZ);
// Send packet to all clients
mnSendUDPAll(MODE_HOST,false,false,Player);
}
}
}
}
}
// If we have become disconnected from the server
dbPrint("Lost connection to server!");
dbSync();
dbWaitKey();
mnFinish(-1); // Close ports and deallocate memory for all instances
return;
}