/* * network.cpp * * Created on: 12.01.2011 * Author: gmueller */ #include "Network.h" #include "btBulletDynamicsCommon.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; btVector3 v = game->player[i].body->getLinearVelocity(); btVector3 p = game->player[i].body->getWorldTransform().getOrigin(); msg.x = p.x(); msg.y = p.y(); msg.z = p.z(); msg.vx = v.x(); msg.vy = v.y(); msg.vz = v.z(); 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); std::cout << "[Network] accpeted player " << am->player_id << std::endl; break; } case MESSAGE_PLAYER_UPDATE: { player_update_message_t *um = (player_update_message_t *) data; std::cout << "[Network] update player " << um->player_id << std::endl; player_t *player = game->getPlayer(um->player_id); #if 1 btVector3 v = player->body->getLinearVelocity(); btVector3 p = player->body->getWorldTransform().getOrigin(); btVector3 v1(um->vx, um->vy, um->vz); btVector3 p1(um->x, um->y, um->z); player->body->activate(true); player->body->setLinearVelocity(v1); player->body->getWorldTransform().setOrigin((2 * p + p1) / 3); //player->body->applyCentralForce((v1 -v)/10.0); #endif #if 0 std::cout << " v:" << um->vx << " " << um->vy << " " << um -> vz << std::endl; std::cout << " p:" << um->x << " " << um->y << " " << um -> z << std::endl; double threshold = 0.1; double dx = um->x - player->x; double dy = um->y - player->y; double dz = um->z - player->z; std::cout << " d:" << dx << " " << dy << " " << dz << std::endl; if (fabs(dx) < threshold) { player->x += 0.1 * dx; } else { player->x = um->x; } if (fabs(dy) < threshold) { player->y += 0.1 * dy; } else { player->y = um->y; } if (fabs(dz) < threshold) { player->z += 0.1 * dz; } else { player->z = um->z; } player->vx = um->vx; player->vy = um->vy; player->vz = um->vz; #endif 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; player->body->activate(true); player->body->applyCentralImpulse(btVector3(um->x, um->y, 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); } }