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:
parent
05dc0b021f
commit
24a08e6017
@ -36,7 +36,7 @@ SFML_VERSION = '2.0-rc'
|
|||||||
BIN_DIR = 'bin'
|
BIN_DIR = 'bin'
|
||||||
CXX = 'g++'
|
CXX = 'g++'
|
||||||
CC = 'gcc'
|
CC = 'gcc'
|
||||||
CXXFLAGS = ['-Wall', '-O2', '-g']
|
CXXFLAGS = ['-Wall', '-O0', '-g']
|
||||||
LINKFLAGS = []
|
LINKFLAGS = []
|
||||||
LIBS_client = []
|
LIBS_client = []
|
||||||
LIBS_server = []
|
LIBS_server = []
|
||||||
@ -48,8 +48,8 @@ if 'SFML_PATH' in os.environ:
|
|||||||
LIBPATH = ['%s/lib' % SFML_PATH]
|
LIBPATH = ['%s/lib' % SFML_PATH]
|
||||||
CPPFLAGS = []
|
CPPFLAGS = []
|
||||||
CPPFLAGS += map(lambda x: '-I' + x, find_dirs_under('src/common'))
|
CPPFLAGS += map(lambda x: '-I' + x, find_dirs_under('src/common'))
|
||||||
CPPFLAGS_client = ['-I%s/include' % SFML_PATH,
|
CPPFLAGS += ['-I%s/include' % SFML_PATH]
|
||||||
'-DGL_INCLUDE_FILE=\\"GL3/gl3w.h\\"']
|
CPPFLAGS_client = ['-DGL_INCLUDE_FILE=\\"GL3/gl3w.h\\"']
|
||||||
CPPFLAGS_client += map(lambda x: '-I' + x, find_dirs_under('src/client'))
|
CPPFLAGS_client += map(lambda x: '-I' + x, find_dirs_under('src/client'))
|
||||||
CPPFLAGS_server = map(lambda x: '-I' + x, find_dirs_under('src/server'))
|
CPPFLAGS_server = map(lambda x: '-I' + x, find_dirs_under('src/server'))
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ if platform == 'windows':
|
|||||||
else:
|
else:
|
||||||
LIBS_client += ['sfml-network', 'sfml-window', 'sfml-graphics',
|
LIBS_client += ['sfml-network', 'sfml-window', 'sfml-graphics',
|
||||||
'sfml-system', 'GL', 'GLU']
|
'sfml-system', 'GL', 'GLU']
|
||||||
LIBS_server += ['sfml-network']
|
LIBS_server += ['sfml-system','sfml-network']
|
||||||
LINKFLAGS.append('-Wl,-R%s/lib' % SFML_PATH)
|
LINKFLAGS.append('-Wl,-R%s/lib' % SFML_PATH)
|
||||||
|
|
||||||
# our sources
|
# our sources
|
||||||
|
@ -1,11 +1,21 @@
|
|||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "Client.h"
|
#include "Client.h"
|
||||||
|
#include "Types.h"
|
||||||
|
|
||||||
Client::Client()
|
Client::Client()
|
||||||
{
|
{
|
||||||
|
m_net_client = new Network();
|
||||||
|
m_net_client->Create(59243, "127.0.0.1"); // Just connect to local host for now - testing
|
||||||
|
client_has_focus = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Client::~Client()
|
||||||
|
{
|
||||||
|
m_net_client->Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Client::run(bool fullscreen, int width, int height)
|
void Client::run(bool fullscreen, int width, int height)
|
||||||
{
|
{
|
||||||
if (!create_window(fullscreen, width, height))
|
if (!create_window(fullscreen, width, height))
|
||||||
@ -22,6 +32,7 @@ void Client::run(bool fullscreen, int width, int height)
|
|||||||
double current_time = m_clock.getElapsedTime().asSeconds();
|
double current_time = m_clock.getElapsedTime().asSeconds();
|
||||||
double elapsed_time = current_time - last_time;
|
double elapsed_time = current_time - last_time;
|
||||||
sf::Event event;
|
sf::Event event;
|
||||||
|
|
||||||
while (m_window->pollEvent(event))
|
while (m_window->pollEvent(event))
|
||||||
{
|
{
|
||||||
switch (event.type)
|
switch (event.type)
|
||||||
@ -42,6 +53,12 @@ void Client::run(bool fullscreen, int width, int height)
|
|||||||
case sf::Event::Resized:
|
case sf::Event::Resized:
|
||||||
resize_window(event.size.width, event.size.height);
|
resize_window(event.size.width, event.size.height);
|
||||||
break;
|
break;
|
||||||
|
case sf::Event::LostFocus:
|
||||||
|
client_has_focus = false;
|
||||||
|
break;
|
||||||
|
case sf::Event::GainedFocus:
|
||||||
|
client_has_focus = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -50,37 +67,88 @@ void Client::run(bool fullscreen, int width, int height)
|
|||||||
update(elapsed_time);
|
update(elapsed_time);
|
||||||
redraw();
|
redraw();
|
||||||
last_time = current_time;
|
last_time = current_time;
|
||||||
|
|
||||||
|
// temporary for now. otherwise this thread consumed way too processing
|
||||||
|
sf::sleep(sf::seconds(0.005)); // 5 milli-seconds
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::update(double elapsed_time)
|
void Client::update(double elapsed_time)
|
||||||
{
|
{
|
||||||
const double move_speed = 75.0;
|
static sf::Uint8 w_pressed_prev = KEY_NOT_PRESSED;
|
||||||
|
static sf::Uint8 a_pressed_prev = KEY_NOT_PRESSED;
|
||||||
|
static sf::Uint8 s_pressed_prev = KEY_NOT_PRESSED;
|
||||||
|
static sf::Uint8 d_pressed_prev = KEY_NOT_PRESSED;
|
||||||
|
static sf::Int32 rel_mouse_movement_prev = 0;
|
||||||
|
|
||||||
|
sf::Packet client_packet;
|
||||||
|
|
||||||
|
m_net_client->Receive();
|
||||||
|
client_packet.clear();
|
||||||
|
if(m_net_client->getData(client_packet))
|
||||||
|
{
|
||||||
|
// Update player position as calculated from the server.
|
||||||
|
client_packet >> m_player->direction;
|
||||||
|
client_packet >> m_player->x;
|
||||||
|
client_packet >> m_player->y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For now, we are going to do a very crude shove data into
|
||||||
|
// packet from keyboard and mouse events.
|
||||||
|
// TODO: Clean this up and make it more robust
|
||||||
|
client_packet.clear();
|
||||||
|
|
||||||
|
sf::Uint8 w_pressed = KEY_NOT_PRESSED;
|
||||||
|
sf::Uint8 a_pressed = KEY_NOT_PRESSED;
|
||||||
|
sf::Uint8 s_pressed = KEY_NOT_PRESSED;
|
||||||
|
sf::Uint8 d_pressed = KEY_NOT_PRESSED;
|
||||||
|
sf::Int32 rel_mouse_movement = 0;
|
||||||
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
|
||||||
{
|
{
|
||||||
double direction = m_player->direction + M_PI_2;
|
a_pressed = KEY_PRESSED;
|
||||||
m_player->x += cos(direction) * move_speed * elapsed_time;
|
|
||||||
m_player->y += sin(direction) * move_speed * elapsed_time;
|
|
||||||
}
|
}
|
||||||
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
|
||||||
{
|
{
|
||||||
double direction = m_player->direction - M_PI_2;
|
d_pressed = KEY_PRESSED;
|
||||||
m_player->x += cos(direction) * move_speed * elapsed_time;
|
|
||||||
m_player->y += sin(direction) * move_speed * elapsed_time;
|
|
||||||
}
|
}
|
||||||
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
|
||||||
{
|
{
|
||||||
double direction = m_player->direction;
|
w_pressed = KEY_PRESSED;
|
||||||
m_player->x += cos(direction) * move_speed * elapsed_time;
|
|
||||||
m_player->y += sin(direction) * move_speed * elapsed_time;
|
|
||||||
}
|
}
|
||||||
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
|
||||||
{
|
{
|
||||||
double direction = m_player->direction + M_PI;
|
s_pressed = KEY_PRESSED;
|
||||||
m_player->x += cos(direction) * move_speed * elapsed_time;
|
|
||||||
m_player->y += sin(direction) * move_speed * elapsed_time;
|
|
||||||
}
|
}
|
||||||
int xrel = sf::Mouse::getPosition(*m_window).x - m_width / 2;
|
rel_mouse_movement = sf::Mouse::getPosition(*m_window).x - m_width / 2;
|
||||||
sf::Mouse::setPosition(sf::Vector2i(m_width / 2, m_height / 2), *m_window);
|
|
||||||
m_player->direction -= M_PI * 0.5 * xrel / 1000;
|
// This is a fix so that the mouse will not move outside the window and
|
||||||
|
// cause the user to click on another program.
|
||||||
|
// Note: Does not work well with fast movement.
|
||||||
|
if(client_has_focus)
|
||||||
|
{
|
||||||
|
sf::Mouse::setPosition(sf::Vector2i(m_width / 2, m_height / 2), *m_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send an update to the server if something has changed
|
||||||
|
if((w_pressed_prev != w_pressed) ||
|
||||||
|
(a_pressed_prev != a_pressed) ||
|
||||||
|
(s_pressed_prev != s_pressed) ||
|
||||||
|
(d_pressed_prev != d_pressed) ||
|
||||||
|
(rel_mouse_movement_prev != rel_mouse_movement))
|
||||||
|
{
|
||||||
|
client_packet << w_pressed;
|
||||||
|
client_packet << a_pressed;
|
||||||
|
client_packet << s_pressed;
|
||||||
|
client_packet << d_pressed;
|
||||||
|
client_packet << rel_mouse_movement;
|
||||||
|
|
||||||
|
m_net_client->sendData(client_packet);
|
||||||
|
|
||||||
|
w_pressed_prev = w_pressed;
|
||||||
|
a_pressed_prev = a_pressed;
|
||||||
|
s_pressed_prev = s_pressed;
|
||||||
|
d_pressed_prev = d_pressed;
|
||||||
|
rel_mouse_movement_prev = rel_mouse_movement;
|
||||||
|
}
|
||||||
|
m_net_client->Transmit();
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,13 @@
|
|||||||
#include "WFObj.h"
|
#include "WFObj.h"
|
||||||
#include "GLMatrix.h"
|
#include "GLMatrix.h"
|
||||||
#include "GLBuffer.h"
|
#include "GLBuffer.h"
|
||||||
|
#include "Network.h"
|
||||||
|
|
||||||
class Client
|
class Client
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Client();
|
Client();
|
||||||
|
~Client();
|
||||||
void run(bool fullscreen, int width, int height);
|
void run(bool fullscreen, int width, int height);
|
||||||
protected:
|
protected:
|
||||||
bool create_window(bool fullscreen, int width, int height);
|
bool create_window(bool fullscreen, int width, int height);
|
||||||
@ -39,6 +41,8 @@ class Client
|
|||||||
GLMatrix m_modelview;
|
GLMatrix m_modelview;
|
||||||
GLBuffer m_overlay_hex_attributes;
|
GLBuffer m_overlay_hex_attributes;
|
||||||
GLBuffer m_overlay_hex_indices;
|
GLBuffer m_overlay_hex_indices;
|
||||||
|
refptr<Network> m_net_client;
|
||||||
|
bool client_has_focus;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
403
src/common/Network.cc
Normal file
403
src/common/Network.cc
Normal 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, ¤t_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
src/common/Network.h
Normal file
96
src/common/Network.h
Normal 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
src/common/Timer.cc
Normal file
60
src/common/Timer.cc
Normal 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
src/common/Timer.h
Normal file
50
src/common/Timer.h
Normal 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
src/common/Types.h
Normal file
9
src/common/Types.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef TYPES_H
|
||||||
|
#define TYPES_H
|
||||||
|
|
||||||
|
#define KEY_PRESSED 0xA5u
|
||||||
|
#define KEY_NOT_PRESSED 0x5Au
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
103
src/server/Server.cc
Normal file
103
src/server/Server.cc
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#include "Server.h"
|
||||||
|
#include "Types.h"
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
Server::Server(sf::Uint16 port)
|
||||||
|
{
|
||||||
|
m_net_server = new Network();
|
||||||
|
m_net_server->Create(port, sf::IpAddress::None);
|
||||||
|
m_player = new Player();
|
||||||
|
m_player->x = 0;
|
||||||
|
m_player->y = 0;
|
||||||
|
m_player->direction = M_PI_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Server::~Server()
|
||||||
|
{
|
||||||
|
m_net_server->Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::run( void )
|
||||||
|
{
|
||||||
|
double current_time;
|
||||||
|
double elapsed_time;
|
||||||
|
double last_time = 0.0;
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
current_time = m_clock.getElapsedTime().asSeconds();
|
||||||
|
elapsed_time = current_time - last_time;
|
||||||
|
update( elapsed_time );
|
||||||
|
last_time = current_time;
|
||||||
|
|
||||||
|
// temporary for now. otherwise this thread consumed way too processing
|
||||||
|
sf::sleep(sf::seconds(0.005)); // 5 milli-seconds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Server::update( double elapsed_time )
|
||||||
|
{
|
||||||
|
static Player player_prev;
|
||||||
|
const double move_speed = 75.0;
|
||||||
|
sf::Packet server_packet;
|
||||||
|
static sf::Uint8 w_pressed = KEY_NOT_PRESSED;
|
||||||
|
static sf::Uint8 a_pressed = KEY_NOT_PRESSED;
|
||||||
|
static sf::Uint8 s_pressed = KEY_NOT_PRESSED;
|
||||||
|
static sf::Uint8 d_pressed = KEY_NOT_PRESSED;
|
||||||
|
static sf::Int32 rel_mouse_movement = 0;
|
||||||
|
|
||||||
|
m_net_server->Receive();
|
||||||
|
if(m_net_server->getData(server_packet))
|
||||||
|
{
|
||||||
|
server_packet >> w_pressed;
|
||||||
|
server_packet >> a_pressed;
|
||||||
|
server_packet >> s_pressed;
|
||||||
|
server_packet >> d_pressed;
|
||||||
|
server_packet >> rel_mouse_movement;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (KEY_PRESSED == a_pressed)
|
||||||
|
{
|
||||||
|
double direction = m_player->direction + M_PI_2;
|
||||||
|
m_player->x += cos(direction) * move_speed * elapsed_time;
|
||||||
|
m_player->y += sin(direction) * move_speed * elapsed_time;
|
||||||
|
}
|
||||||
|
if (KEY_PRESSED == d_pressed)
|
||||||
|
{
|
||||||
|
double direction = m_player->direction - M_PI_2;
|
||||||
|
m_player->x += cos(direction) * move_speed * elapsed_time;
|
||||||
|
m_player->y += sin(direction) * move_speed * elapsed_time;
|
||||||
|
}
|
||||||
|
if (KEY_PRESSED == w_pressed)
|
||||||
|
{
|
||||||
|
double direction = m_player->direction;
|
||||||
|
m_player->x += cos(direction) * move_speed * elapsed_time;
|
||||||
|
m_player->y += sin(direction) * move_speed * elapsed_time;
|
||||||
|
}
|
||||||
|
if (KEY_PRESSED == s_pressed)
|
||||||
|
{
|
||||||
|
double direction = m_player->direction + M_PI;
|
||||||
|
m_player->x += cos(direction) * move_speed * elapsed_time;
|
||||||
|
m_player->y += sin(direction) * move_speed * elapsed_time;
|
||||||
|
}
|
||||||
|
m_player->direction -= M_PI * 0.5 * rel_mouse_movement / 1000;
|
||||||
|
|
||||||
|
server_packet.clear();
|
||||||
|
|
||||||
|
// Send the player update if there were changes
|
||||||
|
if((player_prev.direction != m_player->direction) ||
|
||||||
|
(player_prev.x != m_player->x) ||
|
||||||
|
(player_prev.y != m_player->y))
|
||||||
|
{
|
||||||
|
server_packet << m_player->direction;
|
||||||
|
server_packet << m_player->x;
|
||||||
|
server_packet << m_player->y;
|
||||||
|
m_net_server->sendData(server_packet);
|
||||||
|
|
||||||
|
player_prev.direction = m_player->direction;
|
||||||
|
player_prev.x = m_player->x;
|
||||||
|
player_prev.y = m_player->y;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_net_server->Transmit();
|
||||||
|
}
|
16
src/server/Server.h
Normal file
16
src/server/Server.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#include "Network.h"
|
||||||
|
#include "Player.h"
|
||||||
|
#include "refptr.h"
|
||||||
|
|
||||||
|
class Server{
|
||||||
|
public:
|
||||||
|
Server(sf::Uint16 port);
|
||||||
|
~Server();
|
||||||
|
void run( void );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void update(double elapsed_time);
|
||||||
|
refptr<Network> m_net_server;
|
||||||
|
refptr<Player> m_player;
|
||||||
|
sf::Clock m_clock;
|
||||||
|
};
|
@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include "Server.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@ -24,12 +24,9 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: make this work... */
|
|
||||||
#if 0
|
|
||||||
Server server(port);
|
Server server(port);
|
||||||
|
|
||||||
server.run();
|
server.run();
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user