diff --git a/src/client/Client-gl.cc b/src/client/Client-gl.cc index 2acc88a..41fc340 100644 --- a/src/client/Client-gl.cc +++ b/src/client/Client-gl.cc @@ -1,4 +1,3 @@ - #include #include #include GL_INCLUDE_FILE @@ -216,16 +215,21 @@ 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); + for(std::map >::iterator piter = m_players.begin(); piter != m_players.end(); piter++) + { + draw_player(piter->second); + } + + draw_map(); draw_sky(); draw_lava(); @@ -357,8 +361,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); @@ -409,8 +413,8 @@ void Client::draw_overlay() GLMatrix::Identity.to_uniform( m_overlay_hover_program.uniform("projection")); modelview.load_identity(); - modelview.translate(m_player->hover - 1, 0, 0); - modelview.scale(m_player->hover * 2, 2.0, 1.0); + modelview.translate(m_players[current_player]->hover - 1, 0, 0); + modelview.scale(m_players[current_player]->hover * 2, 2.0, 1.0); modelview.to_uniform(m_overlay_hover_program.uniform("modelview")); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); @@ -450,8 +454,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..0363961 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -1,12 +1,15 @@ #include #include "Client.h" #include "Types.h" +#include "Timer.h" 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; + m_players.clear(); + current_player = 0; } Client::~Client() @@ -15,16 +18,16 @@ Client::~Client() } -void Client::run(bool fullscreen, int width, int height) +void Client::run(bool fullscreen, int width, int height, std::string pname) { + Timer client_timer; + client_timer.Init(); + 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()) { @@ -63,8 +66,16 @@ void Client::run(bool fullscreen, int width, int height) } } + // Time must be updated before any messages are sent + // Especially guaranteed messages, since the time needs to be + // non zero. + client_timer.Update(); + update(elapsed_time); - redraw(); + if(m_players.size() > 0) + { + redraw(); + } last_time = current_time; // temporary for now. otherwise this thread consumed way too processing @@ -74,81 +85,150 @@ 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: + { + sf::Uint8 pindex; + std::string name = ""; + client_packet >> pindex; + client_packet >> name; + // Should be a much better way of doing this. + // Perhaps generate a random number + if(name == current_player_name) + { + current_player = pindex; + } + + // Create a new player if one does not exist. + if(m_players.end() == m_players.find(pindex)) + { + refptr p = new Player(); + p->name = name; + client_packet >> p->direction; + client_packet >> p->x; + client_packet >> p->y; + 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(); - - 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(m_players.size() > 0) { - if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) + 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) { - a_pressed = KEY_PRESSED; + 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); } - if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) + + // 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)) { - d_pressed = KEY_PRESSED; + 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; + + m_net_client->sendData(client_packet); + + 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; } - 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((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)) + else if(!registered_player) { - 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; + 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, true); + registered_player = true; + } + else + { + // Do nothing. } m_net_client->Transmit(); } diff --git a/src/client/Client.h b/src/client/Client.h index 1e0160f..6518f71 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -1,4 +1,3 @@ - #ifndef CLIENT_H #define CLIENT_H @@ -18,7 +17,7 @@ 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(); @@ -34,7 +33,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; + 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..276275d 100644 --- a/src/client/main.cc +++ b/src/client/main.cc @@ -1,4 +1,3 @@ - #include #include #include "Client.h" @@ -8,11 +7,13 @@ 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'}, + {"name", required_argument, NULL, 'n'}, {NULL, 0, NULL, 0} }; for (;;) @@ -31,12 +32,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/HexTile.cc b/src/common/HexTile.cc index e9774bb..526c1e5 100644 --- a/src/common/HexTile.cc +++ b/src/common/HexTile.cc @@ -1,4 +1,3 @@ - #include #include "HexTile.h" diff --git a/src/common/HexTile.h b/src/common/HexTile.h index b4c1beb..4944ad6 100644 --- a/src/common/HexTile.h +++ b/src/common/HexTile.h @@ -1,4 +1,3 @@ - #ifndef HEXTILE_H #define HEXTILE_H diff --git a/src/common/Map.cc b/src/common/Map.cc index ea901b3..4953752 100644 --- a/src/common/Map.cc +++ b/src/common/Map.cc @@ -1,4 +1,3 @@ - #include "Map.h" #include "HexTile.h" diff --git a/src/common/Map.h b/src/common/Map.h index 64e898d..b3050ba 100644 --- a/src/common/Map.h +++ b/src/common/Map.h @@ -1,4 +1,3 @@ - #ifndef MAP_H #define MAP_H diff --git a/src/common/Player.cc b/src/common/Player.cc index c9467fc..2b76977 100644 --- a/src/common/Player.cc +++ b/src/common/Player.cc @@ -1,10 +1,17 @@ - #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..015e0c5 100644 --- a/src/common/Player.h +++ b/src/common/Player.h @@ -1,8 +1,9 @@ - #ifndef PLAYER_H #define PLAYER_H #include +#include "Types.h" +#include "SFML/Config.hpp" class Player { @@ -12,6 +13,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/Timer.cc b/src/common/Timer.cc index b5e5137..8c854e9 100644 --- a/src/common/Timer.cc +++ b/src/common/Timer.cc @@ -23,7 +23,6 @@ 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 diff --git a/src/common/Types.h b/src/common/Types.h index 215e744..a2da1d9 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/common/refptr.h b/src/common/refptr.h index 7335af5..6209953 100644 --- a/src/common/refptr.h +++ b/src/common/refptr.h @@ -1,4 +1,3 @@ - #ifndef REFPTR_H #define REFPTR_H REFPTR_H diff --git a/src/server/Server.cc b/src/server/Server.cc index 9b28625..1344f94 100644 --- a/src/server/Server.cc +++ b/src/server/Server.cc @@ -1,15 +1,13 @@ #include "Server.h" #include "Types.h" #include +#include "Timer.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; + m_players.clear(); } Server::~Server() @@ -22,10 +20,18 @@ void Server::run( void ) double current_time; double elapsed_time; double last_time = 0.0; + Timer server_timer; + server_timer.Init(); while(1) { current_time = m_clock.getElapsedTime().asSeconds(); elapsed_time = current_time - last_time; + + // Time must be updated before any messages are sent + // Especially guaranteed messages, since the time needs to be + // non zero. + server_timer.Update(); + update( elapsed_time ); last_time = current_time; @@ -40,65 +46,143 @@ 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: + { + refptr p = new Player(); + 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; + + // Alert all connected clients of all the connected players. + for(std::map >::iterator piter = m_players.begin(); piter != m_players.end(); piter++) + { + server_packet.clear(); + server_packet << ptype; + server_packet << piter->first; + server_packet << piter->second->name; + // Send correct starting locations so that they match + // the other players screens. + server_packet << piter->second->direction; + server_packet << piter->second->x; + server_packet << piter->second->y; + 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; + } + } } - if (KEY_PRESSED == a_pressed) + for(std::map >::iterator piter = m_players.begin(); piter != m_players.end(); piter++) { - 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; + sf::Uint8 pindex = piter->first; + if (KEY_PRESSED == m_players[pindex]->a_pressed) + { + double 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) + { + double 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) + { + double 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) + { + double 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; + } + if(0 != m_players[pindex]->rel_mouse_movement) + { + m_players[pindex]->direction -= M_PI * 0.5 * m_players[pindex]->rel_mouse_movement / 1000; + m_players[pindex]->updated = true; + } - 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; - } + server_packet.clear(); + // 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..248b045 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; + std::map > m_players; sf::Clock m_clock; };