diff --git a/src/client/Client-gl.cc b/src/client/Client-gl.cc index 1f49b3a..915489b 100644 --- a/src/client/Client-gl.cc +++ b/src/client/Client-gl.cc @@ -258,17 +258,22 @@ void Client::redraw() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - double dir_x = cos(m_player->direction); - double dir_y = sin(m_player->direction); + double dir_x = cos((*m_players)[current_player].direction); + double dir_y = sin((*m_players)[current_player].direction); m_modelview.load_identity(); m_modelview.look_at( - m_player->x - dir_x * 25, m_player->y - dir_y * 25, 30, - m_player->x, m_player->y, 20, + (*m_players)[current_player].x - dir_x * 25, (*m_players)[current_player].y - dir_y * 25, 30, + (*m_players)[current_player].x, (*m_players)[current_player].y, 20, 0, 0, 1); // TODO: call draw_player() for each networked player - draw_player(m_player); - draw_map(); + for(std::map::iterator piter = m_players->begin(); piter != m_players->end(); piter++) + { + draw_player(piter->second); + } + + + draw_map(); draw_sky(); draw_lava(); @@ -277,12 +282,12 @@ void Client::redraw() m_window->display(); } -void Client::draw_player(refptr player) +void Client::draw_player(Player player) { m_obj_program.use(); m_modelview.push(); - m_modelview.translate(player->x, player->y, 4); - m_modelview.rotate(player->direction * 180.0 / M_PI, 0, 0, 1); + m_modelview.translate(player.x, player.y, 4); + m_modelview.rotate(player.direction * 180.0 / M_PI, 0, 0, 1); m_modelview.scale(2, 2, 2); m_tank_obj.bindBuffers(); glEnableVertexAttribArray(0); @@ -398,8 +403,8 @@ void Client::draw_overlay() proj.ortho(-span, span, -span, span, -1, 1); proj.to_uniform(m_overlay_program.uniform("projection")); GLMatrix modelview; - modelview.rotate(90 - m_player->direction * 180 / M_PI, 0, 0, 1); - modelview.translate(-m_player->x, -m_player->y, 0); + modelview.rotate(90 - (*m_players)[current_player].direction * 180 / M_PI, 0, 0, 1); + modelview.translate(-(*m_players)[current_player].x, -(*m_players)[current_player].y, 0); m_overlay_hex_attributes.bind(); m_overlay_hex_indices.bind(); glEnableVertexAttribArray(0); @@ -452,8 +457,8 @@ void Client::draw_sky() m_sky_attributes.bind(); m_projection.to_uniform(m_sky_program.uniform("projection")); m_modelview.push(); - m_modelview.translate(m_player->x, m_player->y, 0); - m_modelview.rotate(m_player->direction * 180.0 / M_PI, 0, 0, 1); + m_modelview.translate((*m_players)[current_player].x, (*m_players)[current_player].y, 0); + m_modelview.rotate((*m_players)[current_player].direction * 180.0 / M_PI, 0, 0, 1); m_modelview.to_uniform(m_sky_program.uniform("modelview")); m_modelview.pop(); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, diff --git a/src/client/Client.cc b/src/client/Client.cc index 349d6b1..f6d3a81 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -6,7 +6,10 @@ 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_has_focus = true; + m_players = new std::map; + m_players->clear(); + current_player = 0; } Client::~Client() @@ -15,16 +18,15 @@ Client::~Client() } -void Client::run(bool fullscreen, int width, int height) +void Client::run(bool fullscreen, int width, int height, std::string pname) { + + current_player_name = pname; if (!create_window(fullscreen, width, height)) return; - m_player = new Player(); - m_player->x = 0; - m_player->y = 0; - m_player->direction = M_PI_2; m_clock.restart(); sf::Mouse::setPosition(sf::Vector2i(m_width / 2, m_height / 2), *m_window); + double last_time = 0.0; while (m_window->isOpen()) { @@ -64,8 +66,11 @@ void Client::run(bool fullscreen, int width, int height) } update(elapsed_time); - redraw(); - last_time = current_time; + if(m_players->size() > 0) + { + redraw(); + } + last_time = current_time; // temporary for now. otherwise this thread consumed way too processing sf::sleep(sf::seconds(0.005)); // 5 milli-seconds @@ -74,81 +79,136 @@ void Client::run(bool fullscreen, int width, int height) void Client::update(double elapsed_time) { - 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; - + static bool registered_player = false; sf::Packet client_packet; + m_net_client->Receive(); client_packet.clear(); // Handle all received data (only really want the latest) while(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; + sf::Uint8 packet_type; + client_packet >> packet_type; + switch(packet_type) + { + case PLAYER_CONNECT: + { + Player p; + sf::Uint8 pindex; + std::string name = ""; + client_packet >> pindex; + client_packet >> name; + if(name == current_player_name) + { + current_player = pindex; + } + p.name = name; + (*m_players)[pindex] = p; + break; + } + case PLAYER_UPDATE: + { + sf::Uint8 player_index; + // Update player position as calculated from the server. + client_packet >> player_index; + if(m_players->end() != m_players->find(player_index)) + { + client_packet >> (*m_players)[player_index].direction; + client_packet >> (*m_players)[player_index].x; + client_packet >> (*m_players)[player_index].y; + } + break; + } + case PLAYER_DISCONNECT: + { + // This will remove the player once the disconnect algorithm is implemented + break; + } + case PLAYER_DEATH: + { + // This will set a death flag in the player struct. + break; + } + default : + { + // Eat the packet + break; + } + } } // 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(); + if(m_players->size() > 0) + { + 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; - 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; + // 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) + { + if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) + { + a_pressed = KEY_PRESSED; + } + if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) + { + d_pressed = KEY_PRESSED; + } + if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) + { + w_pressed = KEY_PRESSED; + } + if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) + { + s_pressed = KEY_PRESSED; + } + 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); + } - // 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) - { - if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) - { - a_pressed = KEY_PRESSED; - } - if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) - { - d_pressed = KEY_PRESSED; - } - if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) - { - w_pressed = KEY_PRESSED; - } - if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) - { - s_pressed = KEY_PRESSED; - } - 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); - } + // Send an update to the server if something has changed + if(((*m_players)[current_player].w_pressed != w_pressed) || + ((*m_players)[current_player].a_pressed != a_pressed) || + ((*m_players)[current_player].s_pressed != s_pressed) || + ((*m_players)[current_player].d_pressed != d_pressed) || + ((*m_players)[current_player].rel_mouse_movement != rel_mouse_movement)) + { + sf::Uint8 packet_type = PLAYER_UPDATE; + client_packet.clear(); + client_packet << packet_type; + client_packet << current_player; + client_packet << w_pressed; + client_packet << a_pressed; + client_packet << s_pressed; + client_packet << d_pressed; + client_packet << rel_mouse_movement; - // 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); - 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_players)[current_player].w_pressed = w_pressed; + (*m_players)[current_player].a_pressed = a_pressed; + (*m_players)[current_player].s_pressed = s_pressed; + (*m_players)[current_player].d_pressed = d_pressed; + (*m_players)[current_player].rel_mouse_movement = rel_mouse_movement; + } + } + else if(!registered_player) + { + sf::Uint8 packet_type = PLAYER_CONNECT; + client_packet.clear(); + client_packet << packet_type; + client_packet << current_player; + client_packet << current_player_name; + m_net_client->sendData(client_packet); + registered_player = true; + } m_net_client->Transmit(); } diff --git a/src/client/Client.h b/src/client/Client.h index 766b330..f6232e7 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -18,14 +18,14 @@ class Client public: Client(); ~Client(); - void run(bool fullscreen, int width, int height); + void run(bool fullscreen, int width, int height, std::string pname); protected: bool create_window(bool fullscreen, int width, int height); bool initgl(); void resize_window(int width, int height); void update(double elapsed_time); void redraw(); - void draw_player(refptr player); + void draw_player(Player player); void draw_map(); void draw_overlay(); void draw_sky(); @@ -34,7 +34,9 @@ class Client refptr m_window; sf::Clock m_clock; Map m_map; - refptr m_player; + sf::Uint8 current_player; + std::string current_player_name; + refptr< std::map > m_players; int m_width; int m_height; GLProgram m_obj_program; diff --git a/src/client/main.cc b/src/client/main.cc index ec111df..84bdff3 100644 --- a/src/client/main.cc +++ b/src/client/main.cc @@ -8,12 +8,14 @@ int main(int argc, char *argv[]) bool fullscreen = false; int width = 1200; int height = 900; + std::string player_name = "Player"; struct option longopts[] = { {"fullscreen", no_argument, NULL, 'f'}, {"height", required_argument, NULL, 'h'}, {"width", required_argument, NULL, 'w'}, - {NULL, 0, NULL, 0} + {"name", required_argument, NULL, 'n'}, + {NULL, 0, NULL, 0} }; for (;;) { @@ -31,12 +33,15 @@ int main(int argc, char *argv[]) case 'w': width = atoi(optarg); break; + case 'n': + player_name = std::string(optarg); + break; } } Client client; - client.run(fullscreen, width, height); + client.run(fullscreen, width, height, player_name); return 0; } diff --git a/src/common/Player.cc b/src/common/Player.cc index c9467fc..1bf8ee1 100644 --- a/src/common/Player.cc +++ b/src/common/Player.cc @@ -1,10 +1,18 @@ #include "Player.h" +#include Player::Player() { x = 0.0; y = 0.0; - direction = 0.0; + direction = M_PI_2; hover = 1.0; + name = ""; + w_pressed = KEY_NOT_PRESSED; + a_pressed = KEY_NOT_PRESSED; + s_pressed = KEY_NOT_PRESSED; + d_pressed = KEY_NOT_PRESSED; + rel_mouse_movement = 0; + updated = false; } diff --git a/src/common/Player.h b/src/common/Player.h index 6f662a7..e692d81 100644 --- a/src/common/Player.h +++ b/src/common/Player.h @@ -3,6 +3,8 @@ #define PLAYER_H #include +#include "Types.h" +#include "SFML/Config.hpp" class Player { @@ -12,6 +14,12 @@ class Player double y; double direction; /* 0 = East, M_PI_2 = North, M_PI = West, ... */ double hover; + sf::Uint8 w_pressed; + sf::Uint8 a_pressed; + sf::Uint8 s_pressed; + sf::Uint8 d_pressed; + sf::Int32 rel_mouse_movement; + bool updated; Player(); }; diff --git a/src/common/Types.h b/src/common/Types.h index 215e744..91c0620 100644 --- a/src/common/Types.h +++ b/src/common/Types.h @@ -4,6 +4,9 @@ #define KEY_PRESSED 0xA5u #define KEY_NOT_PRESSED 0x5Au - +#define PLAYER_CONNECT 0x1Au +#define PLAYER_DISCONNECT 0x2Bu +#define PLAYER_DEATH 0x3Cu +#define PLAYER_UPDATE 0x4Du #endif diff --git a/src/server/Server.cc b/src/server/Server.cc index 9b28625..d5ab153 100644 --- a/src/server/Server.cc +++ b/src/server/Server.cc @@ -6,10 +6,8 @@ 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; + m_players = new std::map; + m_players->clear(); } Server::~Server() @@ -40,65 +38,137 @@ 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(); // Handle all received data (only really want the latest) while(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; + sf::Uint8 ptype; + // Get packet type + server_packet >> ptype; + switch(ptype) + { + case PLAYER_CONNECT: + { + Player p; + std::string pname; + sf::Uint8 pindex; + + server_packet >> pindex; + server_packet >> pname; + // When a player connects, we need to associate + // that player with a new ID. find first unused id + // player zero means a player does not exist. + if(pindex == 0) + { + for(pindex = 1u; pindex < 255u; pindex++ ) + { + if(m_players->end() == m_players->find(pindex)) + { + break; + } + } + p.name = pname; + (*m_players)[pindex] = p; + + // Send a response to the newly added player + server_packet.clear(); + server_packet << ptype; + server_packet << pindex; + server_packet << p.name; + m_net_server->sendData(server_packet, true); + } + break; + } + case PLAYER_UPDATE: + { + // Need to determine the correct player id + // then update the stored contents. + sf::Uint8 pindex; + server_packet >> pindex; + if(m_players->end() != m_players->find(pindex)) + { + server_packet >> (*m_players)[pindex].w_pressed; + server_packet >> (*m_players)[pindex].a_pressed; + server_packet >> (*m_players)[pindex].s_pressed; + server_packet >> (*m_players)[pindex].d_pressed; + server_packet >> (*m_players)[pindex].rel_mouse_movement; + } + break; + } + case PLAYER_DISCONNECT: + { + // This completely removes the player from the game + // Deletes member from the player list + break; + } + case PLAYER_DEATH: + { + // This just forces the player to dissapper from the + // playing field. + break; + } + default: + { + // Just eat the packet + break; + } + } } + + for(std::map::iterator piter = m_players->begin(); piter != m_players->end(); piter++) + { + sf::Uint8 pindex = piter->first; + double direction = (*m_players)[pindex].direction; + direction -= M_PI * 0.5 * (*m_players)[pindex].rel_mouse_movement / 1000; + if(direction != (*m_players)[pindex].direction) + { + (*m_players)[pindex].direction = direction; + (*m_players)[pindex].updated = true; + } + if (KEY_PRESSED == (*m_players)[pindex].a_pressed) + { + direction = (*m_players)[pindex].direction + M_PI_2; + (*m_players)[pindex].x += cos(direction) * move_speed * elapsed_time; + (*m_players)[pindex].y += sin(direction) * move_speed * elapsed_time; + (*m_players)[pindex].updated = true; + } + if (KEY_PRESSED == (*m_players)[pindex].d_pressed) + { + direction = (*m_players)[pindex].direction - M_PI_2; + (*m_players)[pindex].x += cos(direction) * move_speed * elapsed_time; + (*m_players)[pindex].y += sin(direction) * move_speed * elapsed_time; + (*m_players)[pindex].updated = true; + } + if (KEY_PRESSED == (*m_players)[pindex].w_pressed) + { + direction = (*m_players)[pindex].direction; + (*m_players)[pindex].x += cos(direction) * move_speed * elapsed_time; + (*m_players)[pindex].y += sin(direction) * move_speed * elapsed_time; + (*m_players)[pindex].updated = true; + } + if (KEY_PRESSED == (*m_players)[pindex].s_pressed) + { + direction = (*m_players)[pindex].direction + M_PI; + (*m_players)[pindex].x += cos(direction) * move_speed * elapsed_time; + (*m_players)[pindex].y += sin(direction) * move_speed * elapsed_time; + (*m_players)[pindex].updated = true; + } + + server_packet.clear(); - 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; - } - + // Send the player update if there were changes + if((*m_players)[pindex].updated) + { + sf::Uint8 ptype = PLAYER_UPDATE; + server_packet << ptype; + server_packet << pindex; + server_packet << (*m_players)[pindex].direction; + server_packet << (*m_players)[pindex].x; + server_packet << (*m_players)[pindex].y; + m_net_server->sendData(server_packet); + (*m_players)[pindex].updated = false; + } + } m_net_server->Transmit(); } diff --git a/src/server/Server.h b/src/server/Server.h index 5812a06..ff8b064 100644 --- a/src/server/Server.h +++ b/src/server/Server.h @@ -1,6 +1,7 @@ #include "Network.h" #include "Player.h" #include "refptr.h" +#include "SFML/Config.hpp" class Server{ public: @@ -11,6 +12,6 @@ class Server{ protected: void update(double elapsed_time); refptr m_net_server; - refptr m_player; + refptr< std::map > m_players; sf::Clock m_clock; };