spaceserver/server/connection.c

335 lines
11 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "connection.h"
#include <stdio.h>
#include "message.h"
/************************************************************
* CONNECTION HANDLING
***********************************************************/
void srv_send_receive(SERVER_DATA* data)
{
ENetPacket *packet;
ENetEvent event;
SERVER_MESSAGE_NONE* message_none;
SERVER_MESSAGE_JOINGAME* message_list;
SERVER_MESSAGE_SENDPARTY* message_party;
SERVER_MESSAGE_GAME* message_game;
while (enet_host_service(data->enet.server, &event, 0) > 0)
{
switch(event.type)
{
case ENET_EVENT_TYPE_NONE:
break;
case ENET_EVENT_TYPE_CONNECT:
printf("Сервер: новый пользователь из %x:%hu\n", event.peer->address.host, event.peer->address.port);
SERVER_USER* user = srv_get_free_user(&data->users);
show_message_error(user, "Failed to allocate free game");
// Отсоединить пользователя
// enet_peer_disconnect_now(event.peer, 0);
user->peer = event.peer; // сохранить пир в пользователе
event.peer->data = malloc(sizeof(int));
*(int*)event.peer->data = user->id;
printf("Сервер: пользователь присоединён #%d\n", user->id);
break;
case ENET_EVENT_TYPE_RECEIVE:
{
int user_id = *(int*)event.peer->data;
switch(data->users.user[user_id]->state)
{
case STATE_NONE:
message_none = (SERVER_MESSAGE_NONE*)event.packet->data;
srv_readmessage_none(data, user_id, message_none);
break;
case STATE_LIST:
message_list = (SERVER_MESSAGE_JOINGAME*)event.packet->data;
srv_readmessage_list(data, user_id, message_list);
break;
case STATE_PARTY:
message_party = (SERVER_MESSAGE_SENDPARTY*)event.packet->data;
srv_readmessage_party(data, user_id, message_party);
break;
case STATE_GAME:
message_game = (SERVER_MESSAGE_GAME*)event.packet->data;
srv_readmessage_game(data, user_id, message_game);
break;
}
enet_packet_destroy(event.packet);
break;
}
case ENET_EVENT_TYPE_DISCONNECT:
{
int user_id = *(int*)event.peer->data;
srv_removing_from_game(data, data->users.user[user_id]);
srv_clear_user(data->users.user[user_id]);
printf("Сервер: пользователь #%d был отсоединён\n", user_id);
// сообщить пользователям об отсоединении клиента
free(event.peer->data);
event.peer->data = NULL;
break;
}
}
}
}
static void srv_readmessage_none(SERVER_DATA* data, int user_id, SERVER_MESSAGE_NONE* message)
{
SERVER_USER* user = data->users.user[user_id];
user->display_height = message->display_height;
user->display_width = message->display_width;
user->scale_factor = message->scale_factor;
user->is_creator = message->is_creator;
user->is_ready = message->is_ready;
strncpy(user->nickname, message->nickname, 40);
if(message->is_creator)
srv_create_new_game(data, user, message->game_name);
srv_change_state(data, user_id, message->state);
}
static void srv_readmessage_list(SERVER_DATA* data, int user_id, SERVER_MESSAGE_JOINGAME* message)
{
SERVER_USER* user = data->users.user[user_id];
SERVER_GAME* game = data->games.game[message->id];
ENetPacket *packet;
SERVER_MESSAGE_LIST answer;
if(game->count_connected < 3)
{
game->count_connected++;
srv_change_state(data, user_id, message->state);
user->game_id = message->id;
user->in_game = true;
for(int i = 0; i < game->user_size; i++)
if(!game->user[i])
{
game->user[i] = user;
break;
}
answer.state = message->state;
packet = enet_packet_create(&answer, sizeof(answer), ENET_PACKET_FLAG_RELIABLE);
enet_peer_send(user->peer, 0, packet);
}
}
static void srv_readmessage_party(SERVER_DATA* data, int user_id, SERVER_MESSAGE_SENDPARTY* message)
{
SERVER_USER* user = data->users.user[user_id];
switch(message->state)
{
case STATE_LIST:
if(message->kick_user)
user = data->users.user[message->user_id];
srv_removing_from_game(data, user);
user->state = message->state;
user->in_game = false;
user->is_ready = false;
user->game_id = -1;
user->is_creator = false;
srv_send_change_state(user, message->state);
break;
case STATE_PARTY:
user->is_ready = message->is_ready;
break;
case STATE_GAME:
srv_start_game(data, user);
break;
}
}
static void srv_readmessage_game(SERVER_DATA* data, int user_id, SERVER_MESSAGE_GAME* message)
{
SERVER_USER* user = data->users.user[user_id];
switch(message->state)
{
case STATE_GAME:
{
user->command.dx = message->dx;
user->command.dy = message->dy;
user->command.fire = message->fire;
break;
}
}
}
static void srv_change_state(SERVER_DATA* data, int user_id, SERVER_STATE state)
{
SERVER_USER* user = data->users.user[user_id];
user->state = state;
}
static void srv_create_new_game(SERVER_DATA* data, SERVER_USER* user, const char* game_name)
{
// Creating a new game and placing the user there
SERVER_GAME* game = srv_get_free_game(&data->games);
// Отправить сообщение в случае, если нет места для создания новой игры
show_message_error(game, "Failed to allocate free game");
user->game_id = game->id;
user->in_game = true;
game->user[0] = user;
game->count_connected++;
strncpy(game->game_name, game_name, 40);
}
static void srv_removing_from_game(SERVER_DATA* data, SERVER_USER* user)
{
if(user->in_game)
{
SERVER_GAME* game = data->games.game[user->game_id];
for(int i = 0; i < game->user_size; i++)
if(game->user[i] && game->user[i]->id == user->id)
{
game->user[i] = NULL;
--game->count_connected;
if(game->game_started)
{
for(int j = 0; j < game->objects.ship_size; j++)
if(user->id == game->objects.ships[j]->ID)
game->objects.ships[j]->active = false;
for(int j = 0; j < game->objects.bullet_size; j++)
if(user->id == game->objects.bullets[j]->ID)
game->objects.bullets[j]->active = false;
}
if(game->count_connected == 0)
{
if(game->game_started)
srv_destroy_objects(&game->objects);
srv_clear_games(game);
}
else if(user->is_creator)
{
for(int j = 0; j < game->user_size; j++)
if(game->user[j])
{
game->user[j]->is_creator = true;
game->user[j]->is_ready = true;
break;
}
}
break;
}
}
}
static void srv_start_game(SERVER_DATA* data, SERVER_USER* user)
{
if(user->in_game)
{
bool users_ready = true;
SERVER_GAME* game = data->games.game[user->game_id];
for(int i = 0; i < game->user_size; i++)
if(game->user[i])
if(!game->user[i]->is_ready)
{
users_ready = false;
break;
}
if(users_ready)
{
game->game_started = true;
srv_init_objects(game);
for(int i = 0; i < game->user_size; i++)
if(game->user[i])
{
game->user[i]->command.dx = 0;
game->user[i]->command.dy = 0;
game->user[i]->command.fire = false;
game->user[i]->state = STATE_GAME;
srv_send_change_state(game->user[i], STATE_GAME);
}
}
}
}
static void srv_send_change_state(SERVER_USER* user, SERVER_STATE state)
{
ENetPacket *packet;
SERVER_MESSAGE_PARTY message;
message.state = state;
packet = enet_packet_create(&message, sizeof(message), ENET_PACKET_FLAG_RELIABLE);
enet_peer_send(user->peer, 0, packet);
}
static void srv_init_objects(SERVER_GAME* game)
{
SERVER_OBJECTS* objects = &game->objects;
int count_users = game->count_connected;
int start_position = 0;
int position_ratio = 1; // part user position
bool start_ratio = false;
int iterator = 0;
srv_create_objects(objects, count_users, 5 * count_users, 15, 5 * count_users);
for(int i = 0; i < game->user_size; i++)
if(game->user[i] && game->user[i]->is_creator)
{
game->display_width = game->user[i]->display_width;
game->display_height = game->user[i]->display_height;
game->scale_factor = game->user[i]->scale_factor;
break;
}
start_position = game->display_height / (count_users * 2);
for(int i = 0; i < game->user_size; i++)
if(game->user[i])
{
if(start_ratio)
position_ratio += 2;
else
start_ratio = true;
srv_init_ships(objects, iterator, game->user[i]->id, 3, 1, 1, 10, 12, 0, 0, 50, 41, 46, 3, 3, 0, 250, 20, start_position * position_ratio);
for(int j = iterator++ * 5; j < iterator * 5; j++)
srv_init_bullets(objects, j, game->user[i]->id, 500, 0, 0);
}
for(int i = 0; i < objects->comet_size; i++)
srv_init_comets(objects, i, 0, 21, rand() % 2 ? 1 : -1, 35, 35, 0, 0, 2, 96, 96, 143, 250, 0, 0);
for(int i = 0; i < objects->explosion_size; i++)
srv_init_explosions(objects, i, 8, 1, 0, 0, 1, 128, 128, 31, 0, 0);
}