From b19f44ec321c0a69e83677704a4be08dc880a79d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gero=20M=C3=BCller?= Date: Wed, 5 Jan 2011 15:00:09 +0100 Subject: [PATCH] working multiplayer --- src/CMakeLists.txt | 3 +- src/common.h | 19 +++ src/game.cpp | 129 +++++++++++++++++ src/game.h | 42 ++++++ src/main.cpp | 350 +++++++++++++++++++++++++++------------------ 5 files changed, 403 insertions(+), 140 deletions(-) create mode 100644 src/common.h create mode 100644 src/game.cpp create mode 100644 src/game.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3d740f1..c73a33d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,7 +9,8 @@ include_directories (${GREMLIN_SOURCE_DIR}/src) # define executable add_executable( gremlin - main.cpp + main + game ) # set dependencies diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..6074061 --- /dev/null +++ b/src/common.h @@ -0,0 +1,19 @@ +#ifndef GREMLIN_COMMON_H +#define GREMLIN_COMMON_H + +#ifdef _MSC_VER +typedef __int8 int8_t; +typedef unsigned __int8 uint8_t; +typedef __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +#include +#include +#include +#endif + +#endif \ No newline at end of file diff --git a/src/game.cpp b/src/game.cpp new file mode 100644 index 0000000..aa2a34b --- /dev/null +++ b/src/game.cpp @@ -0,0 +1,129 @@ +#include "game.h" + +#include + +void game_setup_team(team_t *team, uint8_t id) { + team->id = id; + team->color[0] = .5f + .5f * (id & (1 << 0)); + team->color[1] = .5f + .5f * (id & (1 << 1)); + team->color[2] = .5f + .5f * (id & (1 << 2)); + team->color[3] = 1.0f; + + team->x = 2000.0 * (id & (1 << 0)); + team->y = 2000.0 * (id & (1 << 1)); + team->z = 2000.0 * (id & (1 << 2)); +} + +void game_setup_player(player_t *player) { + player->id = 0; + player->status = 0; + player->team = NULL; +} + +void game_setup(game_t *game) { + size_t i; + + for (i = 0; i < GAME_TEAM_COUNT; i++) + game_setup_team(&game->team[i], i); + + for (i = 0; i < GAME_PLAYER_COUNT; i++) + game_setup_player(&game->player[i]); + + game->max_player_id = 0; +} + +player_t *_game_free_player(game_t *game) { + size_t i; + for (i = 0; i < GAME_PLAYER_COUNT; i++) { + if (game->player[i].status == 0) + return &game->player[i]; + } + return NULL; +} + +player_t *game_spawn_player(game_t *game, team_t *team) { + player_t *player = _game_free_player(game); + player->team = team; + player->id = game->max_player_id++; + player->status = 1; + player->x = team->x + 100; + player->y = team->y; + player->z = team->z; + player->vx = 0.; + player->vy = 0.; + player->vz = 0.; + return player; +} + +player_t *game_spawn_player_id(game_t *game, team_t *team, uint8_t id) { + player_t *player = _game_free_player(game); + player->team = team; + player->id = id; + if (game->max_player_id < id) + game->max_player_id = id; + player->status = 1; + player->x = team->x + 100; + player->y = team->y; + player->z = team->z; + player->vx = 0.; + player->vy = 0.; + player->vz = 0.; + return player; +} + +void game_update_players(game_t *game, double dt) { + size_t i; + for (i = 0; i < GAME_PLAYER_COUNT; i++) { + player_t *player = &game->player[i]; + if(player->status == 0) + return; + player->x += player->vx * dt; + player->y += player->vy * dt; + player->z += player->vz * dt; + } +} + + +size_t game_active_team_players(game_t *game, team_t *team) { + size_t i, count = 0; + for (i = 0; i < GAME_PLAYER_COUNT; i++) { + if(game->player[i].status == 0) + continue; + if (game->player[i].team == team) + count++; + } + return count; +} + +team_t *game_team_with_least_players(game_t *game) { + size_t i, count = -1; + team_t *team = NULL; + for (i = 0; i < GAME_TEAM_COUNT; i++) { + size_t players = game_active_team_players(game, &game->team[i]); + if (players < count) { + count = players; + team = &game->team[i]; + } + } + return team; +} + +team_t *game_team(game_t *game, uint8_t id){ + size_t i; + for (i = 0; i < GAME_TEAM_COUNT; i++) { + if (game->team[i].id == id) { + return &game->team[i]; + } + } + return NULL; +} + +player_t *game_player(game_t *game, uint8_t id){ + size_t i; + for (i = 0; i < GAME_PLAYER_COUNT; i++) { + if (game->player[i].id == id) { + return &game->player[i]; + } + } + return NULL; +} diff --git a/src/game.h b/src/game.h new file mode 100644 index 0000000..58a28f5 --- /dev/null +++ b/src/game.h @@ -0,0 +1,42 @@ +#ifndef GREMLIN_GAME_H +#define GREMLIN_GAME_H + +#include "common.h" + +typedef struct team_t team_t; +typedef struct player_t player_t; +typedef struct game_t game_t; + +#define GAME_TEAM_COUNT 8 +#define GAME_PLAYER_COUNT 64 + +struct player_t { + uint8_t id; + uint8_t status; + double x, y, z; + double rx, ry, rz, rw; + double vx, vy, vz; + team_t *team; +}; + +struct team_t { + uint8_t id; + double x, y, z; + float color[4]; +}; + +struct game_t { + team_t team[GAME_TEAM_COUNT]; + player_t player[GAME_PLAYER_COUNT]; + int32_t max_player_id; +}; + +extern void game_setup(game_t *game); +extern team_t *game_team_with_least_players(game_t *game); +extern player_t *game_spawn_player(game_t *game, team_t *team); +extern player_t *game_spawn_player_id(game_t *game, team_t *team, uint8_t id); +extern team_t *game_team(game_t *game, uint8_t id); +extern player_t *game_player(game_t *game, uint8_t id); +extern void game_update_players(game_t *game, double dt); + +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index b8647fd..dbf20c2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,26 +6,8 @@ #include #include -#define MAX_PLAYERS_PER_TEAM 8 -#define MAX_TEAMS 8 - -typedef struct team_t team_t; - -typedef struct player_t player_t; - -struct player_t { - unsigned int session; - double x, y, z; - double rx, ry, rz, rw; - double vx, vy, vz; - team_t *team; -}; - -struct team_t { - player_t players[MAX_PLAYERS_PER_TEAM]; - double x, y, z; - GLfloat color[4]; -}; +#include "common.h" +#include "game.h" GLUquadricObj *quadratic; ENetHost *host; @@ -80,98 +62,25 @@ void setup_opengl() { glfwSwapInterval(1); } -void setup_team(team_t *team, size_t id) { - team->color[0] = .5f + .5f * (id & (1 << 0)); - team->color[1] = .5f + .5f * (id & (1 << 1)); - team->color[2] = .5f + .5f * (id & (1 << 2)); - team->color[3] = 1.0f; - - team->x = 2000.0 * (id & (1 << 0)); - team->y = 2000.0 * (id & (1 << 1)); - team->z = 2000.0 * (id & (1 << 2)); - - size_t i = 0; - for (i = 0; i < MAX_PLAYERS_PER_TEAM; i++) { - team->players[i].session = 0; - team->players[i].x = team->x + i * 50.; - team->players[i].y = team->y; - team->players[i].z = team->z; - team->players[i].vx = i * 5.; - team->players[i].vy = i * 5.; - team->players[i].vz = i * 5.; - } -} - -void update_team(team_t *team, double dt) { - size_t i; - for (i = 0; i < MAX_PLAYERS_PER_TEAM; i++) { - if (team->players[i].session == 0) - continue; - team->players[i].x += team->players[i].vx * dt; - team->players[i].y += team->players[i].vy * dt; - team->players[i].z += team->players[i].vz * dt; - } -} - void draw_team(team_t *team) { size_t i = 0; glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, team->color); glMatrixMode(GL_MODELVIEW); - glPushMatrix(); glTranslated(team->x, team->y, team->z); gluSphere(quadratic, 50.f, 32, 32); glPopMatrix(); - - for (i = 0; i < MAX_PLAYERS_PER_TEAM; i++) { - if (team->players[i].session == 0) - continue; - glPushMatrix(); - glTranslated(team->players[i].x, team->players[i].y, team->players[i].z); - gluSphere(quadratic, 10.f, 32, 32); - glPopMatrix(); - } } -void spawn_player(team_t *team, size_t player) { - team->players[player].session = 1; - team->players[player].x = team->x + 100 + player * 50.; - team->players[player].y = team->y; - team->players[player].z = team->z; - team->players[player].vx = 0.; - team->players[player].vy = 0.; - team->players[player].vz = 0.; -} - -size_t active_players(team_t *team) { - size_t i, count = 0; - for (i = 0; i < MAX_PLAYERS_PER_TEAM; i++) { - if (team->players[i].session != 0) - count++; - } - return count; -} - -size_t team_with_least_players(team_t *teams) { - size_t i, count = MAX_PLAYERS_PER_TEAM + 1; - size_t team = MAX_TEAMS + 1; - for (i = 0; i < MAX_TEAMS; i++) { - size_t players = active_players(&teams[i]); - if (players < count) { - count = players; - team = i; - } - } - return team; -} - -size_t free_player(team_t *team) { - size_t i; - for (i = 0; i < MAX_PLAYERS_PER_TEAM; i++) { - if (team->players[i].session == 0) - return i; - } - return MAX_PLAYERS_PER_TEAM + 1; +void draw_player(player_t *player) { + if (player->status == 0) + return; + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, player->team->color); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glTranslated(player->x, player->y, player->z); + gluSphere(quadratic, 10.f, 32, 32); + glPopMatrix(); } void setup_network(const char *remote) { @@ -231,7 +140,66 @@ void setup_network(const char *remote) { } -void service_network(team_t *teams) { +#define MESSAGE_PLAYER_SPAWN 0 +#define MESSAGE_PLAYER_KILL 1 +#define MESSAGE_ACCEPT 2 +#define MESSAGE_PLAYER_UPDATE 3 +#define MESSAGE_PLAYER_ACCELERATE 4 + +typedef struct message_t { + uint16_t msg_id; +} message_t; + +typedef struct player_spawn_message_t { + uint16_t msg_id; + uint8_t team_id; + uint8_t player_id; +} player_spawn_message_t; + +typedef struct player_kill_message_t { + uint16_t msg_id; + uint8_t player_id; +} player_kill_message_t; + +typedef struct accept_message_t { + uint16_t msg_id; + uint8_t player_id; +} accept_message_t; + +typedef struct player_update_message_t { + uint16_t msg_id; + uint8_t player_id; + unsigned int session; + double x, y, z; + double vx, vy, vz; +} player_update_message_t; + +typedef struct player_accelerate_message_t { + uint16_t msg_id; + uint8_t player_id; + double x, y, z; +} player_accelerate_message_t; + +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; + ENetPacket * packet = enet_packet_create (&msg, sizeof(msg), 0); + enet_host_broadcast(host, 0, packet); + } +} + +void service_network(game_t *game) { ENetEvent event; /* Wait up to 1000 milliseconds for an event. */ @@ -241,37 +209,120 @@ void service_network(team_t *teams) { printf("A new client connected from %x:%u.\n", event.peer->address.host, event.peer->address.port); { - size_t team = team_with_least_players(teams); - size_t player = free_player(&teams[team]); - printf("Spwan as %d.%d\n", team, player); - /* Store any relevant client information here. */ - event.peer->data = &teams[team].players[player]; - spawn_player(&teams[team], player); + // 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); + } + + 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: + case ENET_EVENT_TYPE_RECEIVE: { +#if 0 printf( - "A packet of length %u containing %s was received from %s on channel %u.\n", - event.packet->dataLength, event.packet -> data, + "A packet of length %u was received from %s on channel %u.\n", + event.packet->dataLength, event.packet->data, event.peer->data, event.channelID); - +#endif /* Clean up the packet now that we're done using it. */ - // receive team and player - // receive update - // receive state + message_t *msg = (message_t *)event.packet->data; + switch(msg->msg_id) { + case MESSAGE_PLAYER_SPAWN: + { + player_spawn_message_t *sm = (player_spawn_message_t *)event.packet->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 *)event.packet->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 *)event.packet->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 *)event.packet->data; + player_t *player = game_player(game, um->player_id); + player->x = um->x; + player->y = um->y; + player->z = um->z; + player->vx = um->vx; + player->vy = um->vy; + player->vz = um->vz; + } + break; + case MESSAGE_PLAYER_ACCELERATE: + { + player_accelerate_message_t *um = (player_accelerate_message_t *)event.packet->data; + player_t *player = game_player(game, um->player_id); + player->vx += um->x; + player->vy += um->y; + player->vz += um->z; + } + break; + }; + enet_packet_destroy(event.packet); break; - + } case ENET_EVENT_TYPE_DISCONNECT: printf("%s disconected.\n", event.peer -> data); - + { /* Reset the peer's client information. */ - free(event.peer->data); + 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; } } @@ -281,12 +332,21 @@ void accelerate(double x, double y, double z) { local_player->vx += x; local_player->vy += y; local_player->vz += z; - // send update + if (client_peer) { + 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; + ENetPacket * packet = enet_packet_create (&msg, sizeof(msg), ENET_PACKET_FLAG_RELIABLE); + enet_peer_send (client_peer, 0, packet); + } } int main(int argc, char ** argv) { int width, height, x, y, last_x, last_y; - double time, last_time, phi = 0.0, theta = 0.0; + double time, last_time, phi = 0.0, theta = 0.0, last_player_update; GLboolean running; int server = 0; @@ -294,10 +354,10 @@ int main(int argc, char ** argv) { gluQuadricNormals(quadratic, GLU_SMOOTH); gluQuadricTexture(quadratic, GL_TRUE); - team_t teams[MAX_TEAMS]; - size_t i; - for (i = 0; i < MAX_TEAMS; i++) - setup_team(&teams[i], i); + game_t game; + + game_setup(&game); + setup_opengl(); @@ -307,12 +367,14 @@ int main(int argc, char ** argv) { } else { server = 1; setup_network(NULL); - local_player = &teams[0].players[0]; - spawn_player(&teams[0], 0); + team_t *team = game_team(&game, 0); + local_player = game_spawn_player(&game, team); } - + float plane_color[] = {0.2f, 0.3f, 0.4f, 1.0f}; + size_t i; running = GL_TRUE; last_time = glfwGetTime(); + last_player_update = last_time; glfwGetMousePos(&last_x, &last_y); while (running) { // Get time and mouse position @@ -333,15 +395,15 @@ int main(int argc, char ** argv) { double rx = cos(phi) * cos(theta); double ry = sin(theta); double rz = sin(phi) * cos(theta); - + double v = 50.0f * dt; if (glfwGetKey('W')) { - accelerate(rx * 10.0f * dt, ry * 10.0f * dt, rz * 10.0f * dt); + accelerate(rx * v, ry * v, rz * v); } else if (glfwGetKey('S')) { - accelerate(rx * -10.0f * dt, ry * -10.0f * dt, rz * -10.0f * dt); + accelerate(rx * -v, ry * -v, rz * -v); } else if (glfwGetKey('A')) { - accelerate(rz * 10.0f * dt, 0, -rx * 10.0f * dt); + accelerate(rz * v, 0, -rx * v); } else if (glfwGetKey('D')) { - accelerate(-rz * 10.0f * dt, 0, rx * 10.0f * dt); + accelerate(-rz * v, 0, rx *v); } // Get window size (may be different than the requested size) @@ -378,7 +440,7 @@ int main(int argc, char ** argv) { 0.0f, 1.0f, 0.0f); // Up-vector } - glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, teams[0].color); + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, plane_color); // Draw a textured quad glBegin(GL_QUADS); glVertex3f(-5000.0f, 5000.0f, -5000.0f); @@ -387,16 +449,26 @@ int main(int argc, char ** argv) { glVertex3f(-5000.0f, 5000.0f, 5000.0f); glEnd(); - for (i = 0; i < MAX_TEAMS; i++) - update_team(&teams[i], dt); + service_network(&game); + if (server) { + if (time > last_player_update + 0.1) + { + send_player_updates(&game); + last_player_update = time; + } + } - for (i = 0; i < MAX_TEAMS; i++) - draw_team(&teams[i]); + game_update_players(&game, dt); + + for (i = 0; i < GAME_TEAM_COUNT; i++) + draw_team(&game.team[i]); + + for (i = 0; i < GAME_PLAYER_COUNT; i++) + draw_player(&game.player[i]); // Swap buffers glfwSwapBuffers(); - service_network(teams); // Check if the ESC key was pressed or the window was closed running = !glfwGetKey(GLFW_KEY_ESC) && glfwGetWindowParam(GLFW_OPENED);