diff --git a/CMakeLists.txt b/CMakeLists.txt index 7691ed3..6534579 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,12 @@ cmake_minimum_required (VERSION 2.6) project (GREMLIN C CXX) -add_subdirectory (libs/glfw) +INCLUDE (CheckIncludeFiles) +CHECK_INCLUDE_FILES ("GL/gl.h" ENABLE_VIDEO) + +if (ENABLE_VIDEO) + add_subdirectory (libs/glfw) + add_subdirectory (libs/spark) +endif(ENABLE_VIDEO) add_subdirectory (libs/enet) -add_subdirectory (libs/spark) add_subdirectory (src) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d648626..6dafd76 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,10 +1,15 @@ -# find external software -find_package(OpenGL) +if (ENABLE_VIDEO) + # find external software + find_package(OpenGL) + + # set includes + include_directories (${GREMLIN_SOURCE_DIR}/libs/glfw/include) + include_directories (${GREMLIN_SOURCE_DIR}/libs/spark/include) + + SET(VIDEO_SOURCES Explosion oglfont) +endif(ENABLE_VIDEO) -# set includes -include_directories (${GREMLIN_SOURCE_DIR}/libs/glfw/include) include_directories (${GREMLIN_SOURCE_DIR}/libs/enet/include) -include_directories (${GREMLIN_SOURCE_DIR}/libs/spark/include) include_directories (${GREMLIN_SOURCE_DIR}/src) @@ -12,13 +17,13 @@ include_directories (${GREMLIN_SOURCE_DIR}/src) add_executable( gremlin main game - Explosion - oglfont + Time + network + ${VIDEO_SOURCES} ) -# set dependencies add_dependencies( gremlin - glfw enet spark + enet ) if (WIN32) @@ -26,10 +31,28 @@ if (WIN32) endif(WIN32) if(UNIX) - set(PLATFORM_LIBRARIES GL X11 Xrandr pthread asound) + set(PLATFORM_LIBRARIES pthread) endif(UNIX) target_link_libraries(gremlin - glfw enet spark ${OPENGL_LIBRARY} ${PLATFORM_LIBRARIES} + enet ${PLATFORM_LIBRARIES} ) +if (ENABLE_VIDEO) + # set dependencies + add_dependencies( gremlin + glfw spark + ) + + add_definitions(-DENABLE_VIDEO) + + if(UNIX) + target_link_libraries(gremlin + GL GLU X11 Xrandr + ) + endif(UNIX) + + target_link_libraries(gremlin + glfw spark + ) +endif(ENABLE_VIDEO) \ No newline at end of file diff --git a/src/Time.cpp b/src/Time.cpp new file mode 100644 index 0000000..deab3b4 --- /dev/null +++ b/src/Time.cpp @@ -0,0 +1,128 @@ +/* + * Timer.cpp + * + * Created on: 12.01.2011 + * Author: gmueller + */ + +#include "Time.h" + +#ifdef _WIN32 + +#define MEAN_AND_LEAN +#include + +static int _hasPerformanceCounter; +static unsigned int _t0_32; +static __int64 _t0_64; +static double _resolution = 0.0; +static bool _initialized = false; + +static void _init() { + + __int64 freq; + + // Check if we have a performance counter + if( QueryPerformanceFrequency( (LARGE_INTEGER *)&freq ) ) + { + // Performance counter is available => use it! + _hasPerformanceCounter = GL_TRUE; + + // Counter resolution is 1 / counter frequency + _resolution = 1.0 / (double)freq; + + // Set start time for timer + QueryPerformanceCounter( (LARGE_INTEGER *)&__t0_64 ); + } + else + { + // No performace counter available => use the tick counter + _hasPerformanceCounter = 0; + + // Counter resolution is 1 ms + _resolution = 0.001; + + // Set start time for timer + _t0_32 = timeGetTime(); + } +} + +double PerformanceTimer::get() { + if (_initialized == false) + _init(); + double t; + __int64 t_64; + + if( _hasPerformanceCounter ) { + QueryPerformanceCounter( (LARGE_INTEGER *)&t_64 ); + t = (double)(t_64 - _t0_64); + } + else + { + t = (double)(timeGetTime() - _t0_32); + } + + // Calculate the current time in seconds + return t * _resolution; +} + +void PerformanceTimer::set(double t) { + if (_initialized == false) + _init(); + __int64 t_64; + + if( _hasPerformanceCounter ) + { + QueryPerformanceCounter( (LARGE_INTEGER *)&t_64 ); + _t0_64 = t_64 - (__int64)(t/_resolution); + } + else + { + _t0_32 = timeGetTime() - (int)(t*1000.0); + } +} + +#else + +#include + +static double _resolution = 0.0; +static long long _t0 = 0; +static bool _initialized = false; + +static void _init() { + // "Resolution" is 1 us + _resolution = 1e-6; + + // Set start-time for timer + struct timeval tv; + gettimeofday(&tv, 0); + _t0 = (long long) tv.tv_sec * (long long) 1000000 + (long long) tv.tv_usec; + + _initialized = true; +} + +double PerformanceTimer::get() { + if (_initialized == false) + _init(); + struct timeval tv; + gettimeofday(&tv, 0); + long long t = (long long) tv.tv_sec * (long long) 1000000 + + (long long) tv.tv_usec; + return (double) (t - _t0) * _resolution; +} + +void PerformanceTimer::set(double t) { + if (_initialized == false) + _init(); + long long t1; + struct timeval tv; + + gettimeofday(&tv, 0); + t1 = (long long) tv.tv_sec * (long long) 1000000 + (long long) tv.tv_usec; + + // Calulate new starting time + _t0 = t1 - (long long) (t / _resolution); +} + +#endif // else _WIN32 diff --git a/src/Time.h b/src/Time.h new file mode 100644 index 0000000..1c32b9a --- /dev/null +++ b/src/Time.h @@ -0,0 +1,17 @@ +/* + * Timer.h + * + * Created on: 12.01.2011 + * Author: gmueller + */ + +#ifndef TIME_H_ +#define TIME_H_ + +class PerformanceTimer { +public: + static double get(); + static void set(double); +}; + +#endif /* TIME_H_ */ diff --git a/src/game.cpp b/src/game.cpp index b7029ed..b58a736 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -206,8 +206,9 @@ void _explode_bomb(game_t *game, bomb_t *bomb) { continue; double distance2 = pow(player->x - bomb->x, 2) + pow(player->y - bomb->y, 2) + pow(player->z - bomb->z, 2); - if (distance2 < pow(150 , 2)) { - game->explosion_callback(player->x, player->y, player->z); + if (distance2 < pow(150, 2)) { + if (game->explosion_callback) + game->explosion_callback(player->x, player->y, player->z); player->x = player->team->x + 100; player->y = player->team->y; player->z = player->team->z; @@ -258,10 +259,13 @@ void game_update_bombs(game_t *game, double dt) { if (bomb->ttl < 0) { if (bomb->status == 1) { - game->explosion_callback(bomb->x, bomb->y, bomb->z); + if (game->explosion_callback) + game->explosion_callback(bomb->x, bomb->y, bomb->z); bomb->status = 2; } else if (bomb->ttl < -0.2) { - _explode_bomb(game, bomb); + if (game->master) { + _explode_bomb(game, bomb); + } bomb->status = 0; } } diff --git a/src/game.h b/src/game.h index 97b25fa..3dfae9d 100644 --- a/src/game.h +++ b/src/game.h @@ -50,6 +50,7 @@ struct game_t { int16_t max_player_id; int master; double updateTime; + player_t *local_player; void(*explosion_callback)(double x, double y, double z); }; diff --git a/src/main.cpp b/src/main.cpp index 0343b4b..44c8955 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,19 +4,18 @@ #include #include -#include #include +#include #include "common.h" #include "game.h" #include "Explosion.h" #include "Schedule.h" #include "oglfont.h" +#include "Time.h" +#include "network.h" GLUquadricObj *quadratic; -ENetHost *host; -ENetPeer *client_peer; -player_t *local_player; Explosion explosion; void key_callback(int key, int state) { @@ -38,11 +37,6 @@ void setup_light() { } void setup_opengl() { - // Initialise GLFW - if (!glfwInit()) { - fprintf(stderr, "Failed to initialize GLFW\n"); - exit(EXIT_FAILURE); - } // Open OpenGL window if (!glfwOpenWindow(640, 480, 0, 0, 0, 0, 0, 0, GLFW_WINDOW)) { @@ -114,378 +108,6 @@ void draw_point(point_t *point) { glPopMatrix(); } -void setup_network(const char *remote) { - if (enet_initialize() != 0) { - fprintf(stderr, "An error occurred while initializing ENet.\n"); - exit(EXIT_FAILURE); - } - - if (remote == NULL) { - ENetAddress address; - - address.host = ENET_HOST_ANY; - address.port = 1234; - - host = enet_host_create(&address, 32, 2, 0, 0); - if (host == NULL) { - fprintf(stderr, - "An error occurred while trying to create an ENet server host.\n"); - exit(EXIT_FAILURE); - } - } else { - ENetAddress address; - ENetEvent event; - - host = enet_host_create(NULL, 1, 2, 57600 / 8, 14400 / 8); - if (host == NULL) { - fprintf(stderr, - "An error occurred while trying to create an ENet client host.\n"); - exit(EXIT_FAILURE); - } - - enet_address_set_host(&address, remote); - address.port = 1234; - - /* Initiate the connection, allocating the two channels 0 and 1. */ - client_peer = enet_host_connect(host, &address, 2, 0); - - if (client_peer == NULL) { - fprintf(stderr, - "No available peers for initiating an ENet connection.\n"); - exit(EXIT_FAILURE); - } - - /* Wait up to 5 seconds for the connection attempt to succeed. */ - if (enet_host_service(host, &event, 5000) > 0 && event.type - == ENET_EVENT_TYPE_CONNECT) { - puts("Connection succeeded."); - } else { - /* Either the 5 seconds are up or a disconnect event was */ - /* received. Reset the peer in the event the 5 seconds */ - /* had run out without any significant event. */ - enet_peer_reset(client_peer); - - fprintf(stderr, "Connection to %s failed.", remote); - } - } - -} - -#define MESSAGE_PLAYER_SPAWN 0 -#define MESSAGE_PLAYER_KILL 1 -#define MESSAGE_ACCEPT 2 -#define MESSAGE_PLAYER_UPDATE 3 -#define MESSAGE_PLAYER_ACCELERATE 4 -#define MESSAGE_BOMB_DROP 5 -#define MESSAGE_BOMB_UPDATE 6 -#define MESSAGE_POINT_UPDATE 7 -#define MESSAGE_TEAM_UPDATE 8 - -typedef struct message_t { - uint16_t msg_id; -} message_t; - -typedef struct player_spawn_message_t { - uint16_t msg_id; - uint8_t team_id; - uint16_t player_id; -} player_spawn_message_t; - -typedef struct player_kill_message_t { - uint16_t msg_id; - uint16_t player_id; -} player_kill_message_t; - -typedef struct accept_message_t { - uint16_t msg_id; - uint16_t player_id; -} accept_message_t; - -typedef struct player_update_message_t { - uint16_t msg_id; - uint16_t player_id; - unsigned int session; - double x, y, z; - double vx, vy, vz; - uint16_t points; -} player_update_message_t; - -typedef struct player_accelerate_message_t { - uint16_t msg_id; - uint16_t player_id; - double x, y, z; -} player_accelerate_message_t; - -typedef struct bomb_drop_meesage_t { - uint16_t msg_id; - double x, y, z; - double vx, vy, vz; - double ttl; -} bomb_drop_meesage_t; - -typedef struct bomb_update_meesage_t { - uint16_t msg_id; - uint16_t bomb_index; - double x, y, z; - double vx, vy, vz; - double ttl; -} bomb_update_meesage_t; - -typedef struct point_update_mesage_t { - uint16_t msg_id; - uint16_t point_index; - uint8_t status; - double x, y, z; -} point_update_meesage_t; - -struct team_update_message_t { - uint16_t msg_id; - uint16_t team_id; - uint16_t points; - uint16_t wins; -}; - -void send_player_updates(game_t *game) { - size_t i; - for (i = 0; i < GAME_PLAYER_COUNT; i++) { - if (game->player[i].status == 0) - continue; - player_update_message_t msg; - msg.msg_id = MESSAGE_PLAYER_UPDATE; - msg.player_id = game->player[i].id; - msg.x = game->player[i].x; - msg.y = game->player[i].y; - msg.z = game->player[i].z; - msg.vx = game->player[i].vx; - msg.vy = game->player[i].vy; - msg.vz = game->player[i].vz; - msg.points = game->player[i].points; - ENetPacket * packet = enet_packet_create(&msg, sizeof(msg), 0); - enet_host_broadcast(host, 0, packet); - } - for (i = 0; i < GAME_TEAM_COUNT; i++) { - team_update_message_t msg; - msg.msg_id = MESSAGE_TEAM_UPDATE; - msg.team_id = game->team[i].id; - msg.points = game->team[i].points; - msg.wins = game->team[i].wins; - ENetPacket * packet = enet_packet_create(&msg, sizeof(msg), 0); - enet_host_broadcast(host, 0, packet); - } -} - -void dispatch_message(enet_uint8 *data, size_t length, game_t *game) { - message_t *msg = (message_t *) data; - switch (msg->msg_id) { - case MESSAGE_PLAYER_SPAWN: { - player_spawn_message_t *sm = (player_spawn_message_t *) data; - team_t *team = game_team(game, sm->team_id); - player_t *player = game_spawn_player_id(game, team, sm->player_id); - break; - } - case MESSAGE_PLAYER_KILL: { - player_kill_message_t *sm = (player_kill_message_t *) data; - player_t *player = game_player(game, sm->player_id); - player->status = 0; - player->team = 0; - break; - } - case MESSAGE_ACCEPT: { - accept_message_t *am = (accept_message_t *) data; - local_player = game_player(game, am->player_id); - printf("Spwan as %d.%d\n", local_player->team->id, local_player->id); - break; - } - case MESSAGE_PLAYER_UPDATE: { - player_update_message_t *um = (player_update_message_t *) data; - player_t *player = game_player(game, um->player_id); - player->x = um->x + um->vx * 0.0001; - player->y = um->y + um->vy * 0.0001; - player->z = um->z + um->vz * 0.0001; - player->vx = um->vx; - player->vy = um->vy; - player->vz = um->vz; - player->points = um->points; - break; - } - case MESSAGE_POINT_UPDATE: { - point_update_mesage_t *msg = (point_update_mesage_t *) data; - point_t *p = &game->point[msg->point_index]; - p->status = msg->status; - p->x = msg->x; - p->y = msg->y; - p->z = msg->z; - break; - } - case MESSAGE_PLAYER_ACCELERATE: { - player_accelerate_message_t *um = (player_accelerate_message_t *) data; - player_t *player = game_player(game, um->player_id); - player->vx += um->x; - player->vy += um->y; - player->vz += um->z; - break; - } - case MESSAGE_BOMB_DROP: { - bomb_drop_meesage_t *m = (bomb_drop_meesage_t *) data; - bomb_t *bomb = game_spawn_bomb(game); - if (bomb == NULL) - return; - bomb->x = m->x + m->vx * 0.0001; - bomb->y = m->y + m->vy * 0.0001; - bomb->z = m->z + m->vz * 0.0001; - bomb->vx = m->vx; - bomb->vy = m->vy; - bomb->vz = m->vz; - bomb->ttl = m->ttl; - if (client_peer == NULL) { - ENetPacket * packet = enet_packet_create(data, length, - ENET_PACKET_FLAG_RELIABLE); - enet_host_broadcast(host, 0, packet); - } - break; - } - case MESSAGE_TEAM_UPDATE: { - team_update_message_t *m = (team_update_message_t *) data; - team_t *team = game_team(game, m->team_id); - if (team == NULL) - return; - team->points = m->points; - team->wins = m->wins; - break; - } - }; -} -void service_network(game_t *game) { - ENetEvent event; - - /* Wait up to 1000 milliseconds for an event. */ - while (enet_host_service(host, &event, 0) > 0) { - switch (event.type) { - case ENET_EVENT_TYPE_CONNECT: - printf("A new client connected from %x:%u.\n", - event.peer->address.host, event.peer->address.port); - { - // bring new client up to date - size_t i; - for (i = 0; i < GAME_PLAYER_COUNT; i++) { - if (game->player[i].status == 0) - continue; - // send player spawn message - player_spawn_message_t spwan_msg; - spwan_msg.msg_id = MESSAGE_PLAYER_SPAWN; - spwan_msg.team_id = game->player[i].team->id; - spwan_msg.player_id = game->player[i].id; - ENetPacket * packet = enet_packet_create(&spwan_msg, - sizeof(spwan_msg), ENET_PACKET_FLAG_RELIABLE); - enet_peer_send(event.peer, 0, packet); - } - - for (i = 0; i < GAME_POINT_COUNT; i++) { - if (game->point[i].status == 0) - continue; - point_update_mesage_t msg; - msg.msg_id = MESSAGE_POINT_UPDATE; - msg.point_index = i; - msg.status = game->point[i].status; - msg.x = game->point[i].x; - msg.y = game->point[i].y; - msg.z = game->point[i].z; - ENetPacket * packet = enet_packet_create(&msg, sizeof(msg), - ENET_PACKET_FLAG_RELIABLE); - enet_peer_send(event.peer, 0, packet); - } - - team_t *team = game_team_with_least_players(game); - player_t *player = game_spawn_player(game, team); - printf("Spwan as %d.%d\n", team->id, player->id); - event.peer->data = player; - - // send player spawn message - player_spawn_message_t spwan_msg; - spwan_msg.msg_id = MESSAGE_PLAYER_SPAWN; - spwan_msg.team_id = team->id; - spwan_msg.player_id = player->id; - ENetPacket * packet = enet_packet_create(&spwan_msg, - sizeof(spwan_msg), ENET_PACKET_FLAG_RELIABLE); - enet_host_broadcast(host, 0, packet); - - // send team and player - accept_message_t msg; - msg.msg_id = MESSAGE_ACCEPT; - msg.player_id = player->id; - packet = enet_packet_create(&msg, sizeof(msg), - ENET_PACKET_FLAG_RELIABLE); - enet_peer_send(event.peer, 0, packet); - - // send state - } - break; - - case ENET_EVENT_TYPE_RECEIVE: { - dispatch_message(event.packet->data, event.packet->dataLength, game); - enet_packet_destroy(event.packet); - break; - } - case ENET_EVENT_TYPE_DISCONNECT: - printf("%s disconected.\n", event.peer -> data); - { - /* Reset the peer's client information. */ - player_t *player = (player_t *) event.peer->data; - player->status = 0; - player->team = 0; - - // send player spawn message - player_kill_message_t msg; - msg.msg_id = MESSAGE_PLAYER_KILL; - msg.player_id = player->id; - ENetPacket * packet = enet_packet_create(&msg, sizeof(msg), - ENET_PACKET_FLAG_RELIABLE); - enet_host_broadcast(host, 0, packet); - } - event.peer->data = NULL; - break; - } - } - -} - -void accelerate(game_t *game, double x, double y, double z) { - if (local_player == 0) - return; - player_accelerate_message_t msg; - msg.msg_id = MESSAGE_PLAYER_ACCELERATE; - msg.player_id = local_player->id; - msg.x = x; - msg.y = y; - msg.z = z; - if (client_peer) { - ENetPacket * packet = enet_packet_create(&msg, sizeof(msg), - ENET_PACKET_FLAG_RELIABLE); - enet_peer_send(client_peer, 0, packet); - } else { - dispatch_message((uint8_t*) &msg, sizeof(msg), game); - } -} - -void drop_bomb(game_t *game, double rx, double ry, double rz, double ttl) { - bomb_drop_meesage_t msg; - msg.msg_id = MESSAGE_BOMB_DROP; - msg.x = local_player->x + rx * 20; - msg.y = local_player->y + ry * 20; - msg.z = local_player->z + rz * 20; - msg.vx = local_player->vx + rx * 100; - msg.vy = local_player->vy + ry * 100; - msg.vz = local_player->vz + rz * 100; - msg.ttl = ttl; - if (client_peer) { - ENetPacket * packet = enet_packet_create(&msg, sizeof(msg), - ENET_PACKET_FLAG_RELIABLE); - enet_peer_send(client_peer, 0, packet); - } else { - dispatch_message((uint8_t*) &msg, sizeof(msg), game); - } -} - void setup_explosion() { // Loads particle texture @@ -685,10 +307,36 @@ private: oglf_font_t font; void prepareFrame(double rx, double ry, double rz); - + void accelerate(double x, double y, double z); + void drop_bomb(double rx, double ry, double rz, double ttl); void loadConsoleFont(); }; +void Application::accelerate(double x, double y, double z) { + if (game.local_player == 0) + return; + player_accelerate_message_t msg; + msg.msg_id = MESSAGE_PLAYER_ACCELERATE; + msg.player_id = game.local_player->id; + msg.x = x; + msg.y = y; + msg.z = z; + send_message((uint8_t*) &msg, sizeof(msg), &game); +} + +void Application::drop_bomb(double rx, double ry, double rz, double ttl) { + bomb_drop_meesage_t msg; + msg.msg_id = MESSAGE_BOMB_DROP; + msg.x = game.local_player->x + rx * 20; + msg.y = game.local_player->y + ry * 20; + msg.z = game.local_player->z + rz * 20; + msg.vx = game.local_player->vx + rx * 100; + msg.vy = game.local_player->vy + ry * 100; + msg.vz = game.local_player->vz + rz * 100; + msg.ttl = ttl; + send_message((uint8_t*) &msg, sizeof(msg), &game); +} + void Application::loadConsoleFont() { GLuint font_id = 0; @@ -735,35 +383,48 @@ void Application::initialize(int argc, char ** argv) { server = 0; double time, last_player_update; + std::string arg1; + if (argc > 1) { + arg1 = argv[1]; + if (arg1 == "server") { + server = 1; + } else { + server = 0; + } + } else { + server = 0; + arg1 = "forge.camijo.de"; + } + + // Initialise GLFW + if (!glfwInit()) { + fprintf(stderr, "Failed to initialize GLFW\n"); + exit(EXIT_FAILURE); + } + + game_setup(&game, server, explosion_callback); + + setup_opengl(); + setup_explosion(); quadratic = gluNewQuadric(); gluQuadricNormals(quadratic, GLU_SMOOTH); gluQuadricTexture(quadratic, GL_TRUE); - if (argc > 1) { - server = 0; - } else { - server = 1; - } - - game_setup(&game, server, explosion_callback); - setup_opengl(); - setup_explosion(); - if (server) { setup_network(NULL); team_t *team = game_team(&game, 0); - local_player = game_spawn_player(&game, team); + game.local_player = game_spawn_player(&game, team); } else { - setup_network(argv[1]); + setup_network(arg1.c_str()); } size_t i; running = GL_TRUE; - last_time = glfwGetTime(); + last_time = PerformanceTimer::get(); last_player_update = last_time; last_bomb = last_time - 5.; - glfwGetMousePos(&last_x, &last_y); + glfwGetMousePos(&last_x, &last_y); accelerate_schudule.setExact(true); accelerate_schudule.setInterval(0.05); @@ -776,8 +437,9 @@ void Application::initialize(int argc, char ** argv) { void Application::update() { // Get time and mouse position - double time = glfwGetTime(); + double time = PerformanceTimer::get(); double dt = time - last_time; + int x, y; glfwGetMousePos(&x, &y); if (glfwGetMouseButton(GLFW_MOUSE_BUTTON_2) == GLFW_PRESS) { @@ -791,13 +453,11 @@ void Application::update() { last_x = x; last_y = y; - game_update(&game, dt); - service_network(&game); + game_update(&game, dt); if (server && player_update_schudule.next(time)) { send_player_updates(&game); } - double rx = cos(phi) * cos(theta); double ry = sin(theta); double rz = sin(phi) * cos(theta); @@ -805,34 +465,33 @@ void Application::update() { double t = accelerate_schudule.getInterval(); double v = 50.0 * t; if (glfwGetKey('W')) { - accelerate(&game, rx * v, ry * v, rz * v); + accelerate(rx * v, ry * v, rz * v); } else if (glfwGetKey('S')) { - accelerate(&game, rx * -v, ry * -v, rz * -v); + accelerate(rx * -v, ry * -v, rz * -v); } if (glfwGetKey('A')) { - accelerate(&game, rz * v, 0, -rx * v); + accelerate(rz * v, 0, -rx * v); } else if (glfwGetKey('D')) { - accelerate(&game, -rz * v, 0, rx * v); + accelerate(-rz * v, 0, rx * v); } if (glfwGetKey(GLFW_KEY_SPACE)) { - accelerate(&game, local_player->vx * -0.1, local_player->vy * -0.1, - local_player->vz * -0.1); + accelerate(game.local_player->vx * -0.1, game.local_player->vy + * -0.1, game.local_player->vz * -0.1); } } if (glfwGetKey(GLFW_KEY_LCTRL)) { if (time - last_bomb > 1.0) { last_bomb = time; - drop_bomb(&game, rx, ry, rz, 5.0); + drop_bomb(rx, ry, rz, 5.0); } } - //service_network(&game); - if (local_player) { - camX = local_player->x; - camY = local_player->y; - camZ = local_player->z; + if (game.local_player) { + camX = game.local_player->x; + camY = game.local_player->y; + camZ = game.local_player->z; } else { camX = 1000.0; camY = 1000.0; @@ -865,15 +524,15 @@ void Application::update() { explosion.update(dt * 1000.0, camX, camY, camZ); explosion.render(); oglf_begin(&font, width, height); - if (local_player) { + if (game.local_player) { std::stringstream sstr; - sstr << "Points: " << local_player->points; + sstr << "Points: " << game.local_player->points; oglf_print(&font, 10, 10, sstr.str().c_str()); } for (size_t i = 0; i < GAME_TEAM_COUNT; i++) { std::stringstream sstr; - if (local_player && &game.team[i] == local_player->team) { + if (game.local_player && &game.team[i] == game.local_player->team) { sstr << "Team " << i << " (yours) : " << game.team[i].points; } else { sstr << "Team " << i << " (other) : " << game.team[i].points; @@ -885,7 +544,6 @@ void Application::update() { // Swap buffers glfwSwapBuffers(); - // Check if the ESC key was pressed or the window was closed running = !glfwGetKey(GLFW_KEY_ESC) && glfwGetWindowParam(GLFW_OPENED); @@ -896,10 +554,9 @@ void Application::update() { void Application::shutdown() { gluDeleteQuadric(quadratic); - - enet_host_destroy(host); - enet_deinitialize(); oglf_destroy(&font); + + shutdown_network(); // Close OpenGL window and terminate GLFW glfwTerminate(); } diff --git a/src/network.cpp b/src/network.cpp new file mode 100644 index 0000000..38e10b2 --- /dev/null +++ b/src/network.cpp @@ -0,0 +1,300 @@ +/* + * network.cpp + * + * Created on: 12.01.2011 + * Author: gmueller + */ + +#include "network.h" + +#include +#include + +ENetHost *host = 0; +ENetPeer *client_peer = 0; + +void setup_network(const char *remote) { + if (enet_initialize() != 0) { + fprintf(stderr, "An error occurred while initializing ENet.\n"); + exit(EXIT_FAILURE); + } + + if (remote == NULL) { + fprintf(stdout, "Start server.\n"); + ENetAddress address; + + address.host = ENET_HOST_ANY; + address.port = 1234; + + host = enet_host_create(&address, 32, 2, 0, 0); + if (host == NULL) { + fprintf(stderr, + "An error occurred while trying to create an ENet server host.\n"); + exit(EXIT_FAILURE); + } + } else { + fprintf(stdout, "Start client.\n"); + ENetAddress address; + ENetEvent event; + + host = enet_host_create(NULL, 1, 2, 57600 / 8, 14400 / 8); + if (host == NULL) { + fprintf(stderr, + "An error occurred while trying to create an ENet client host.\n"); + exit(EXIT_FAILURE); + } + + enet_address_set_host(&address, remote); + address.port = 1234; + + /* Initiate the connection, allocating the two channels 0 and 1. */ + client_peer = enet_host_connect(host, &address, 2, 0); + + if (client_peer == NULL) { + fprintf(stderr, + "No available peers for initiating an ENet connection.\n"); + exit(EXIT_FAILURE); + } + + /* Wait up to 5 seconds for the connection attempt to succeed. */ + if (enet_host_service(host, &event, 5000) > 0 && event.type + == ENET_EVENT_TYPE_CONNECT) { + puts("Connection succeeded."); + } else { + /* Either the 5 seconds are up or a disconnect event was */ + /* received. Reset the peer in the event the 5 seconds */ + /* had run out without any significant event. */ + enet_peer_reset(client_peer); + + fprintf(stderr, "Connection to %s failed.", remote); + } + } + +} + +void shutdown_network() { + enet_host_destroy(host); + enet_deinitialize(); +} + +void send_player_updates(game_t *game) { + size_t i; + for (i = 0; i < GAME_PLAYER_COUNT; i++) { + if (game->player[i].status == 0) + continue; + player_update_message_t msg; + msg.msg_id = MESSAGE_PLAYER_UPDATE; + msg.player_id = game->player[i].id; + msg.x = game->player[i].x; + msg.y = game->player[i].y; + msg.z = game->player[i].z; + msg.vx = game->player[i].vx; + msg.vy = game->player[i].vy; + msg.vz = game->player[i].vz; + msg.points = game->player[i].points; + ENetPacket * packet = enet_packet_create(&msg, sizeof(msg), 0); + enet_host_broadcast(host, 0, packet); + } + for (i = 0; i < GAME_TEAM_COUNT; i++) { + team_update_message_t msg; + msg.msg_id = MESSAGE_TEAM_UPDATE; + msg.team_id = game->team[i].id; + msg.points = game->team[i].points; + msg.wins = game->team[i].wins; + ENetPacket * packet = enet_packet_create(&msg, sizeof(msg), 0); + enet_host_broadcast(host, 0, packet); + } +} + +void dispatch_message(enet_uint8 *data, size_t length, game_t *game) { + message_t *msg = (message_t *) data; + switch (msg->msg_id) { + case MESSAGE_PLAYER_SPAWN: { + player_spawn_message_t *sm = (player_spawn_message_t *) data; + team_t *team = game_team(game, sm->team_id); + player_t *player = game_spawn_player_id(game, team, sm->player_id); + break; + } + case MESSAGE_PLAYER_KILL: { + player_kill_message_t *sm = (player_kill_message_t *) data; + player_t *player = game_player(game, sm->player_id); + player->status = 0; + player->team = 0; + break; + } + case MESSAGE_ACCEPT: { + accept_message_t *am = (accept_message_t *) data; + game->local_player = game_player(game, am->player_id); + printf("Spwan as %d.%d\n", game->local_player->team->id, + game->local_player->id); + break; + } + case MESSAGE_PLAYER_UPDATE: { + player_update_message_t *um = (player_update_message_t *) data; + player_t *player = game_player(game, um->player_id); + if (player != game->local_player) { + player->x = um->x + um->vx * 0.0001; + player->y = um->y + um->vy * 0.0001; + player->z = um->z + um->vz * 0.0001; + player->vx = um->vx; + player->vy = um->vy; + player->vz = um->vz; + } else { + player->vx = um->vx + (um->x - player->x); + player->vy = um->vy + (um->y - player->y); + player->vz = um->vz + (um->z - player->z); + } + player->points = um->points; + break; + } + case MESSAGE_POINT_UPDATE: { + point_update_mesage_t *msg = (point_update_mesage_t *) data; + point_t *p = &game->point[msg->point_index]; + p->status = msg->status; + p->x = msg->x; + p->y = msg->y; + p->z = msg->z; + break; + } + case MESSAGE_PLAYER_ACCELERATE: { + player_accelerate_message_t *um = (player_accelerate_message_t *) data; + player_t *player = game_player(game, um->player_id); + player->vx += um->x; + player->vy += um->y; + player->vz += um->z; + break; + } + case MESSAGE_BOMB_DROP: { + bomb_drop_meesage_t *m = (bomb_drop_meesage_t *) data; + bomb_t *bomb = game_spawn_bomb(game); + if (bomb == NULL) + return; + bomb->x = m->x + m->vx * 0.0001; + bomb->y = m->y + m->vy * 0.0001; + bomb->z = m->z + m->vz * 0.0001; + bomb->vx = m->vx; + bomb->vy = m->vy; + bomb->vz = m->vz; + bomb->ttl = m->ttl; + if (client_peer == NULL) { + ENetPacket * packet = enet_packet_create(data, length, + ENET_PACKET_FLAG_RELIABLE); + enet_host_broadcast(host, 0, packet); + } + break; + } + case MESSAGE_TEAM_UPDATE: { + team_update_message_t *m = (team_update_message_t *) data; + team_t *team = game_team(game, m->team_id); + if (team == NULL) + return; + team->points = m->points; + team->wins = m->wins; + break; + } + }; +} + +void service_network(game_t *game) { + ENetEvent event; + + /* Wait up to 1000 milliseconds for an event. */ + while (enet_host_service(host, &event, 0) > 0) { + switch (event.type) { + case ENET_EVENT_TYPE_CONNECT: + printf("A new client connected from %x:%u.\n", + event.peer->address.host, event.peer->address.port); + { + // bring new client up to date + size_t i; + for (i = 0; i < GAME_PLAYER_COUNT; i++) { + if (game->player[i].status == 0) + continue; + // send player spawn message + player_spawn_message_t spwan_msg; + spwan_msg.msg_id = MESSAGE_PLAYER_SPAWN; + spwan_msg.team_id = game->player[i].team->id; + spwan_msg.player_id = game->player[i].id; + ENetPacket * packet = enet_packet_create(&spwan_msg, + sizeof(spwan_msg), ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(event.peer, 0, packet); + } + + for (i = 0; i < GAME_POINT_COUNT; i++) { + if (game->point[i].status == 0) + continue; + point_update_mesage_t msg; + msg.msg_id = MESSAGE_POINT_UPDATE; + msg.point_index = i; + msg.status = game->point[i].status; + msg.x = game->point[i].x; + msg.y = game->point[i].y; + msg.z = game->point[i].z; + ENetPacket * packet = enet_packet_create(&msg, sizeof(msg), + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(event.peer, 0, packet); + } + + team_t *team = game_team_with_least_players(game); + player_t *player = game_spawn_player(game, team); + printf("Spwan as %d.%d\n", team->id, player->id); + event.peer->data = player; + + // send player spawn message + player_spawn_message_t spwan_msg; + spwan_msg.msg_id = MESSAGE_PLAYER_SPAWN; + spwan_msg.team_id = team->id; + spwan_msg.player_id = player->id; + ENetPacket * packet = enet_packet_create(&spwan_msg, + sizeof(spwan_msg), ENET_PACKET_FLAG_RELIABLE); + enet_host_broadcast(host, 0, packet); + + // send team and player + accept_message_t msg; + msg.msg_id = MESSAGE_ACCEPT; + msg.player_id = player->id; + packet = enet_packet_create(&msg, sizeof(msg), + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(event.peer, 0, packet); + + // send state + } + break; + + case ENET_EVENT_TYPE_RECEIVE: { + dispatch_message(event.packet->data, event.packet->dataLength, game); + enet_packet_destroy(event.packet); + break; + } + case ENET_EVENT_TYPE_DISCONNECT: + printf("%s disconected.\n", event.peer -> data); + { + /* Reset the peer's client information. */ + player_t *player = (player_t *) event.peer->data; + player->status = 0; + player->team = 0; + + // send player spawn message + player_kill_message_t msg; + msg.msg_id = MESSAGE_PLAYER_KILL; + msg.player_id = player->id; + ENetPacket * packet = enet_packet_create(&msg, sizeof(msg), + ENET_PACKET_FLAG_RELIABLE); + enet_host_broadcast(host, 0, packet); + } + event.peer->data = NULL; + break; + } + } + +} + +void send_message(uint8_t *data, size_t length, game_t *game) { + if (client_peer) { + ENetPacket * packet = enet_packet_create(data, length, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(client_peer, 0, packet); + } else { + dispatch_message(data, length, game); + } +} diff --git a/src/network.h b/src/network.h new file mode 100644 index 0000000..dad7680 --- /dev/null +++ b/src/network.h @@ -0,0 +1,95 @@ +/* + * network.h + * + * Created on: 12.01.2011 + * Author: gmueller + */ + +#ifndef NETWORK_H_ +#define NETWORK_H_ + +#include "game.h" +#include "common.h" + +#define MESSAGE_PLAYER_SPAWN 0 +#define MESSAGE_PLAYER_KILL 1 +#define MESSAGE_ACCEPT 2 +#define MESSAGE_PLAYER_UPDATE 3 +#define MESSAGE_PLAYER_ACCELERATE 4 +#define MESSAGE_BOMB_DROP 5 +#define MESSAGE_BOMB_UPDATE 6 +#define MESSAGE_POINT_UPDATE 7 +#define MESSAGE_TEAM_UPDATE 8 + +typedef struct message_t { + uint16_t msg_id; +} message_t; + +typedef struct player_spawn_message_t { + uint16_t msg_id; + uint8_t team_id; + uint16_t player_id; +} player_spawn_message_t; + +typedef struct player_kill_message_t { + uint16_t msg_id; + uint16_t player_id; +} player_kill_message_t; + +typedef struct accept_message_t { + uint16_t msg_id; + uint16_t player_id; +} accept_message_t; + +typedef struct player_update_message_t { + uint16_t msg_id; + uint16_t player_id; + unsigned int session; + double x, y, z; + double vx, vy, vz; + uint16_t points; +} player_update_message_t; + +typedef struct player_accelerate_message_t { + uint16_t msg_id; + uint16_t player_id; + double x, y, z; +} player_accelerate_message_t; + +typedef struct bomb_drop_meesage_t { + uint16_t msg_id; + double x, y, z; + double vx, vy, vz; + double ttl; +} bomb_drop_meesage_t; + +typedef struct bomb_update_meesage_t { + uint16_t msg_id; + uint16_t bomb_index; + double x, y, z; + double vx, vy, vz; + double ttl; +} bomb_update_meesage_t; + +typedef struct point_update_mesage_t { + uint16_t msg_id; + uint16_t point_index; + uint8_t status; + double x, y, z; +} point_update_meesage_t; + +struct team_update_message_t { + uint16_t msg_id; + uint16_t team_id; + uint16_t points; + uint16_t wins; +}; + +void setup_network(const char *remote); +void shutdown_network(); +void dispatch_message(uint8_t *data, size_t length, game_t *game); +void service_network(game_t *game); +void send_player_updates(game_t *game); +void send_message(uint8_t *data, size_t length, game_t *game); + +#endif /* NETWORK_H_ */