Squashed commit of Chris's networking code

commit 052d5a2ee82d14752ba7a2a89b375de0f4b3214d
Author: Chris Peterson <xethm55@yahoo.com>
Date:   Fri Sep 14 20:49:49 2012 -0400

    Damn! - Forgot to add the Types.h file

commit 8bb6f6d56279289dd0c1f118dffb390dc6538a7c
Author: Chris Peterson <xethm55@yahoo.com>
Date:   Fri Sep 14 20:41:46 2012 -0400

    Fixed a lot of the lag issues.  There are still some tweaks needed, but that is going to happen with the input system changes

commit 0b5fe2dd64b561d965229a8dff25575eaf5c9264
Author: Chris Peterson <xethm55@yahoo.com>
Date:   Fri Sep 14 20:21:31 2012 -0400

    Client server stuff working.  A lot of lag in the system though

commit 07fac2c86d3b379fd1ac287bf3f60b778ca59508
Merge: 5cfd5b2 ac79196
Author: Chris Peterson <xethm55@yahoo.com>
Date:   Fri Sep 14 17:49:18 2012 -0400

    Merging in changes from Holtrop

commit 5cfd5b28d5e384803ef7b807849ac570e6c84e0f
Author: Chris Peterson <xethm55@yahoo.com>
Date:   Sun Sep 9 12:23:12 2012 -0400

    Building on linux now

commit 470d486cdebd95099020911dee7f9290c78ee274
Merge: 842040d f072eec
Author: Chris Peterson <xethm55@yahoo.com>
Date:   Sun Sep 9 11:58:39 2012 -0400

    Merged in master with tank model

commit 842040d0fee481f726b2ae5aec60787371af3923
Merge: 6866c58 9b993f2
Author: Chris Peterson <xethm55@yahoo.com>
Date:   Thu Aug 30 23:25:19 2012 -0400

    Merged in changes from upstream (holtrop/master)

commit 6866c58200cc50d3ccc886266303c1b654c89527
Author: Chris Peterson <xethm55@yahoo.com>
Date:   Sat Aug 18 17:07:50 2012 -0400

    added server code and a simple echo server.
This commit is contained in:
Chris Peterson authored and Josh Holtrop committed 2012-09-15 09:49:12 -04:00
1 parent 05dc0b021f
commit 24a08e6017
11 files changed
+830 -24

No files matched your search

+403
View File
@@ -0,0 +1,403 @@
#include "Network.h"
#include "Timer.h"
#include <cstring>
#include <cstdlib>
#include <iostream>
sf::Uint16 Network::numclients;
sf::UdpSocket Network::net_socket;
char Network::rxbuff[RECEIVE_BUFFER_SIZE];
std::map<sf::Uint32, Transmit_Message_t*> Network::transmit_queue;
Client_t Network::clients[MAX_NUM_CLIENTS];
sf::Clock Network::message_timer;
sf::Uint32 Network::getUniqueMessageId( void )
{
sf::Uint32 next_msg_uid = 0;
while(transmit_queue.find(next_msg_uid) != transmit_queue.end())
{
next_msg_uid++;
}
return next_msg_uid;
}
void Network::Create(sf::Uint16 port, sf::IpAddress address )
{
sf::Uint16 current_client = 0;
Client_t tmpclient;
Reset();
if(sf::IpAddress::None != address)
{
tmpclient.addr = address;
tmpclient.port = port;
numclients = addClients(&tmpclient, &current_client);
net_socket.bind( sf::Socket::AnyPort );
net_socket.setBlocking(false);
}
else
{
net_socket.bind( port );
net_socket.setBlocking(false);
}
}
void Network::Destroy( void )
{
/* Clean and exit */
net_socket.unbind();
}
bool Network::getData(sf::Packet& p)
{
bool rtn = false;
sf::Uint16 curcl;
// Recurse through the client array and return if there is any
// received data for a given client
for(curcl = 0; curcl < numclients; (curcl)++)
{
if(!clients[curcl].receive.empty())
{
p = clients[curcl].receive.front();
clients[curcl].receive.pop();
rtn = true;
break;
}
}
return rtn;
}
bool Network::queueTransmitMessage(Network_Messages_T msg_type , sf::Packet p, Client_t * dest)
{
sf::Packet packet;
sf::Uint8 type = (sf::Uint8)msg_type;
sf::Uint32 uid = UNIQUE_ID;
sf::Uint32 msg_id = getUniqueMessageId();
Transmit_Message_t* message = new Transmit_Message_t();
// Add this to the list of packets expecting a response
packet << uid;
packet << type;
packet << msg_id;
packet.append(p.getData(), p.getDataSize());
message->msg_type = msg_type;
message->Data = packet;
message->TimeStarted = 0.0;
message->dest = dest;
transmit_queue[msg_id] = message;
return true;
}
bool Network::sendData(sf::Packet& p, bool guaranteed)
{
Network_Messages_T message_type = NETWORK_NORMAL;
if(guaranteed)
{
message_type = NETWORK_GUARANTEED;
}
queueTransmitMessage(message_type, p);
return true;
}
int Network::addClients(Client_t *client, sf::Uint16 *curcl)
{
int i;
int nc = -1;
for(i=0;i<MAX_NUM_CLIENTS;i++)
{
if((clients[i].addr == client->addr) && (clients[i].port == client->port))
{
nc = i;
}
else if((clients[i].addr == sf::IpAddress::None) && (clients[i].port == 0))
{
break;
}
}
// Make sure to set the current client location, otherwise
// bad stuffs can happen.
if(nc == -1)
{
clients[i].addr = client->addr;
clients[i].port = client->port;
*curcl = i;
i++;
}
else
{
*curcl = nc;
}
return i;
}
int Network::findClient(Client_t *client)
{
int client_ndx;
for(client_ndx = 0; client_ndx < MAX_NUM_CLIENTS; client_ndx++)
{
if((clients[client_ndx].addr == client->addr) && (clients[client_ndx].port == client->port))
{
break;
}
}
return client_ndx;
}
void Network::Receive()
{
// Get any received packets
sf::IpAddress sender;
Client_t tmpclient;
sf::Uint16 curcl;
sf::Packet receive_packet;
receive_packet.clear();
// Receive any packets from the server
while(net_socket.receive(receive_packet, tmpclient.addr, tmpclient.port) == sf::Socket::Done)
{
sf::Uint32 uid;
receive_packet >> uid;
if(uid == UNIQUE_ID)
{
sf::Uint8 message_type;
sf::Uint32 msg_id;
receive_packet >> message_type;
receive_packet >> msg_id;
numclients = addClients(&tmpclient, &curcl);
switch((Network_Messages_T)message_type)
{
case NETWORK_CONNECT:
{
break;
}
case NETWORK_DISCONNECT:
{
break;
}
case NETWORK_ACK:
{
sf::Uint32 client_id = findClient(&tmpclient);
receive_packet >> message_type;
receive_packet >> msg_id;
switch(message_type)
{
// Handle an acknowledged ping message
case NETWORK_PING:
{
if(MAX_NUM_CLIENTS > client_id)
{
clients[client_id].ping = Timer::GetTimeDouble() - transmit_queue[msg_id]->TimeStarted;
}
break;
}
// Handle an acknowledged guaranteed message
case NETWORK_GUARANTEED:
{
// Set that the message was acknowledged by the client
if(MAX_NUM_CLIENTS > client_id)
{
transmit_queue[msg_id]->Responses[&clients[client_id]] = Timer::GetTimeDouble();
}
break;
}
default:
break; // What the heck happened?
}
break;
}
case NETWORK_PING:
{
// Send a response indicating that ping was received
sf::Packet response;
response.clear();
response << message_type << msg_id;
queueTransmitMessage(NETWORK_ACK, response, &(clients[curcl]));
break;
}
case NETWORK_NORMAL:
{
// Handle any remaining data in the packet
clients[curcl].receive.push(receive_packet);
break;
}
case NETWORK_GUARANTEED:
{
// Send a response indicating that the message was received
sf::Packet response;
clients[curcl].receive.push(receive_packet);
response.clear();
response << message_type << msg_id;
queueTransmitMessage(NETWORK_ACK, response, &(clients[curcl]));
break;
}
// Nothing to do
default:
break;
}
}
}
}
void Network::Transmit()
{
// Broadcast the mesages to all clients
sf::Uint32 msg_id = 0;
static double ping_timer = Timer::GetTimeDouble();
// Once per second, send ping messages ( just for fun )
if((Timer::GetTimeDouble() - ping_timer) > 1000.0)
{
ping_timer = Timer::GetTimeDouble();
sf::Packet response;
response.clear();
queueTransmitMessage(NETWORK_PING, response);
}
// Send any pending messages
while(transmit_queue.find(msg_id) != transmit_queue.end())
{
double curTime = Timer::GetTimeDouble();
Transmit_Message_t * message = transmit_queue[msg_id];
switch(message->msg_type)
{
case NETWORK_PING:
case NETWORK_GUARANTEED:
{
// If the message has not yet been sent
// send the message and update the sent times.
if(0.0 == message->TimeStarted)
{
message->TimeStarted = Timer::GetTimeDouble();
for(int i = 0; i < MAX_NUM_CLIENTS; i++)
{
if((clients[i].addr != sf::IpAddress::None) && (clients[i].port != 0))
{
message->ClientTimeSent[&clients[i]] = message->TimeStarted;
net_socket.send(message->Data, clients[i].addr, clients[i].port);
}
}
}
else
{
// Message has already been sent, check to see if a response has been received
// if not, send another request after retry timer expired.
if(message->ClientTimeSent.size() > message->Responses.size())
{
// Look for any clients that haven't responded
for ( std::map<Client_t*, double>::iterator iter = message->ClientTimeSent.begin(); iter != message->ClientTimeSent.end(); ++iter )
{
// Determine if enough time has elapsed to try and re-send
if((curTime - iter->second) >= 0.5)
{
// Determine if a response was already received from this client
if(message->Responses.find(iter->first) == message->Responses.end())
{
// Resend the message to the client
net_socket.send(message->Data, iter->first->addr, iter->first->port);
message->ClientTimeSent[iter->first] = curTime;
}
}
}
}
else
{
// All clients have received the message, so remove it from the list
delete message;
transmit_queue.erase(transmit_queue.find(msg_id));
}
}
break;
}
// When sending an ACK, we only need to send the ACK to the sender.
case NETWORK_ACK:
{
if(NULL != message->dest)
{
net_socket.send(message->Data, message->dest->addr, message->dest->port);
}
// Transmitted the message, so remove it from the list
delete message;
transmit_queue.erase(transmit_queue.find(msg_id));
break;
}
default:
{
// A normal message, no response needed
// just send to all clients, then delete the message
for(int i=0;i<numclients;i++)
{
net_socket.send(message->Data, clients[i].addr, clients[i].port);
}
delete message;
transmit_queue.erase(transmit_queue.find(msg_id));
break;
}
}
msg_id++;
}
}
int Network::getNumConnected( void )
{
return numclients;
}
void Network::Reset()
{
numclients = 0;
for(int i = 0; i < MAX_NUM_CLIENTS; i++)
{
clients[i].addr = sf::IpAddress();
clients[i].port = 0;
while(!clients[i].receive.empty())
{
clients[i].receive.pop();
}
}
sf::Uint32 next_msg_uid = 0;
while(transmit_queue.find(next_msg_uid) != transmit_queue.end())
{
delete transmit_queue[next_msg_uid];
next_msg_uid++;
}
transmit_queue.clear();
message_timer.restart();
}
sf::Packet& operator <<(sf::Packet& Packet, const Network_Messages_T& NMT)
{
sf::Uint8 net_msg_t = (sf::Uint8)NMT;
return Packet << net_msg_t;
}
sf::Packet& operator >>(sf::Packet& Packet, Network_Messages_T& NMT)
{
sf::Uint8 net_msg_t;
Packet >> net_msg_t;
NMT = (Network_Messages_T)net_msg_t;
return Packet;
}
+96
View File
@@ -0,0 +1,96 @@
#ifndef _NETWORK_HPP
#define _NETWORK_HPP
#include <map>
#include <SFML/Config.hpp>
#include <SFML/Network.hpp>
#include <SFML/System/Clock.hpp>
#include <vector>
#include <queue>
#define MAX_NUM_CLIENTS 8
#define MAX_NUM_TUBES 4
#define UNIQUE_ID 0xDEADBEEF
#define RECEIVE_BUFFER_SIZE 1024
// In milliseconds
#define NETWORK_TIMEOUT 5000
// The bit indicating if the message requires a response
#define MSG_REQUIRES_RESPONSE_BIT ((sf::Uint16)1 << 15)
// The bit indicating if the message is a transmission or a response
#define MSG_TX_BIT ((sf::Uint16)1 << 14)
typedef enum{
NETWORK_NONE,
NETWORK_CONNECT,
NETWORK_DISCONNECT,
NETWORK_ACK,
NETWORK_PING,
NETWORK_NORMAL,
NETWORK_GUARANTEED
}Network_Messages_T;
typedef struct{
sf::IpAddress addr;
unsigned short port;
double ping;
std::queue<sf::Packet> receive;
}Client_t;
typedef struct{
// The packet
sf::Packet Data;
// The type of message that is to be sent.
Network_Messages_T msg_type;
// Destination client for an ACK message
// Perhaps later I will enable the ability to only send updates
// to specific clients.
Client_t * dest;
// The time at which the message was origionally sent
double TimeStarted;
// The time at which the message was last sent to each client
std::map<Client_t*, double> ClientTimeSent;
// The time at which a response was received from each client
std::map<Client_t*, double> Responses;
} Transmit_Message_t;
class Network{
private:
static sf::Uint16 numclients;
static sf::UdpSocket net_socket;
static std::map<sf::Uint32, Transmit_Message_t*> transmit_queue;
static char rxbuff[RECEIVE_BUFFER_SIZE];
static sf::Clock message_timer;
static sf::Uint32 getUniqueMessageId( void );
static int addClients(Client_t *client, sf::Uint16 *curcl);
static int findClient(Client_t *client);
static bool queueTransmitMessage(Network_Messages_T msg_type , sf::Packet p, Client_t * dest = NULL);
public:
static Client_t clients[MAX_NUM_CLIENTS];
static void Create( sf::Uint16 port, sf::IpAddress address );
static void Destroy( void );
static bool getData(sf::Packet& p);
static bool sendData(sf::Packet& p, bool guaranteed = false);
static int getNumConnected( void );
static void Transmit();
static void Receive();
static void Reset();
};
sf::Packet& operator <<(sf::Packet& Packet, const Network_Messages_T& NMT);
sf::Packet& operator >>(sf::Packet& Packet, Network_Messages_T& NMT);
#endif
+60
View File
@@ -0,0 +1,60 @@
#include "Timer.h"
// The number of time steps per second
const float STEPS_PER_SECOND = 60.0f;
double Timer::totalElapsedTime;
float Timer::stepTime;
sf::Uint32 Timer::curTimeStep;
void Timer::Init(void)
{
// Reset the clock
myClock.restart();
// Set the time keepers to zero
myTotalElapsedTime = 0;
// Reset the game speed
gameSpeed = 1.0f;
}
void Timer::Update(void)
{
// Record the time step
stepTime = ((myClock.getElapsedTime().asSeconds() / 1000.0f) * gameSpeed);
//stepTime = ((((sf::Window*)screen)->GetFrameTime() / 1000.0f) * gameSpeed);
myClock.restart();
// Add the time to the total time
myTotalElapsedTime += stepTime;
totalElapsedTime = myTotalElapsedTime;
// Calculate the game step
curTimeStep = (sf::Uint32)(totalElapsedTime * STEPS_PER_SECOND);
}
sf::Uint32 Timer::GetTime(void)
{
return curTimeStep;
}
float Timer::GetStepTime(void)
{
return stepTime;
}
sf::Uint32 Timer::GetTotalTime(void)
{
return (sf::Uint32)(totalElapsedTime * 1000.0f);
}
double Timer::GetTimeDouble(void)
{
return totalElapsedTime;
}
float Timer::GetElapsedTime(sf::Uint32 baseTime)
{
return (totalElapsedTime - ((double)baseTime / STEPS_PER_SECOND));
}
+50
View File
@@ -0,0 +1,50 @@
#ifndef _TIMER_H
#define _TIMER_H
#include <SFML/System/Clock.hpp>
class Timer
{
public:
// Initializes the time module
void Init(void);
// Updates the time module
void Update();
// Returns the current time step
static sf::Uint32 GetTime(void);
// Returns the time that elapsed this step
static float GetStepTime(void);
// Returns the total time elapsed in milliseconds
static sf::Uint32 GetTotalTime(void);
// Returns the total time in seconds as a double
static double GetTimeDouble(void);
// Returns the difference between the current time and the given time in seconds
static float GetElapsedTime(sf::Uint32 baseTime);
private:
// The clock used to take the time measurements
sf::Clock myClock;
// The game speed
float gameSpeed;
// The total elapsed time since the start of the game
double myTotalElapsedTime;
// The total elapsed time since the start of the game
static double totalElapsedTime;
// The time that elapsed this step
static float stepTime;
// The number of time steps since the start of the game
static sf::Uint32 curTimeStep;
};
#endif
+9
View File
@@ -0,0 +1,9 @@
#ifndef TYPES_H
#define TYPES_H
#define KEY_PRESSED 0xA5u
#define KEY_NOT_PRESSED 0x5Au
#endif