/* * network.cpp * * Created on: 12.01.2011 * Author: gmueller */ #include "Network.h" #include #include Network::Network(Game *game) : game(game), client_peer(0) { } void Network::initialize(const std::string &hostname) { if (enet_initialize() != 0) { throw "failed to initialize enet"; } if (hostname.empty()) { std::cout << "[Network] Start server." << std::endl; ENetAddress address; address.host = ENET_HOST_ANY; address.port = 1234; host = enet_host_create(&address, 32, 2, 0, 0); if (host == NULL) { throw "An error occurred while trying to create an ENet server host."; } } else { std::cout << "[Network] Start client." << std::endl; ENetAddress address; ENetEvent event; host = enet_host_create(NULL, 1, 2, 57600 / 8, 14400 / 8); if (host == NULL) { throw "An error occurred while trying to create an ENet client host."; } std::cout << "[Network] connect to " << host << std::endl; enet_address_set_host(&address, hostname.c_str()); 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) { throw "No available peers for initiating an ENet connection."; } /* Wait up to 5 seconds for the connection attempt to succeed. */ if (enet_host_service(host, &event, 2000) > 0 && event.type == ENET_EVENT_TYPE_CONNECT) { std::cout << "[Network] connected" << host << std::endl; } 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); throw "[Network] connection failed."; } } } void Network::shutdown() { enet_host_destroy(host); enet_deinitialize(); } void Network::sendGameUpdates() { 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->teams.size(); i++) { team_update_message_t msg; msg.msg_id = MESSAGE_TEAM_UPDATE; msg.team_id = game->teams[i].id; msg.points = game->teams[i].points; msg.wins = game->teams[i].wins; ENetPacket * packet = enet_packet_create(&msg, sizeof(msg), 0); enet_host_broadcast(host, 0, packet); } enet_host_flush(host); } void Network::dispatch(enet_uint8 *data, size_t length) { 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 *team = game->getTeam(sm->team_id); player_t *player = game->spawn_player_id(team, sm->player_id); break; } case MESSAGE_PLAYER_KILL: { player_kill_message_t *sm = (player_kill_message_t *) data; player_t *player = game->getPlayer(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->getPlayer(am->player_id); break; } case MESSAGE_PLAYER_UPDATE: { player_update_message_t *um = (player_update_message_t *) data; player_t *player = game->getPlayer(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 { if (fabs(um->x - player->x) < 10.0) { player->vx = um->vx + (um->x - player->x); } else { player->x = um->x; player->vx = um->vx; } if (fabs(um->y - player->y) < 10.0) { player->vy = um->vy + (um->y - player->y); } else { player->y = um->y; player->vy = um->vy; } if (fabs(um->z - player->z) < 10.0) { player->vz = um->vz + (um->z - player->z); } else { player->z = um->z; 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->getPlayer(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(); 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 *team = game->getTeam(m->team_id); if (team == NULL) return; team->points = m->points; team->wins = m->wins; break; } }; } void Network::service(uint32_t timeout) { ENetEvent event; if (host == 0) throw "not connected"; /* Wait up to 1000 milliseconds for an event. */ while (enet_host_service(host, &event, timeout) > 0) { switch (event.type) { case ENET_EVENT_TYPE_CONNECT: { std::cout << "A new client connected from " << event.peer->address.host << " " << event.peer->address.port << std::endl; // 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 *team = game->team_with_least_players(); player_t *player = game->spawn_player(team); 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(event.packet->data, event.packet->dataLength); 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 Network::sendMessage(uint8_t *data, size_t length) { if (client_peer) { ENetPacket * packet = enet_packet_create(data, length, ENET_PACKET_FLAG_RELIABLE); enet_peer_send(client_peer, 0, packet); } else { dispatch(data, length); } }