spaceserver/server/connection.c

335 lines
11 KiB
C
Raw Permalink Normal View History

2023-04-30 20:52:53 +00:00
#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);
}