diff --git a/build_debug.bat b/build_debug.bat index 9143b5a..006924b 100644 --- a/build_debug.bat +++ b/build_debug.bat @@ -1,2 +1,2 @@ -set compileopts=/Fe"flight_debug" /Zi /FS /Fd"flight.pdb" /DSERVER_ADDRESS="\"127.0.0.1\"" +set compileopts=/Fe"flight_debug" /Zi /FS /Fd"flight.pdb" /DSERVER_ADDRESS="\"127.0.0.1\"" /DDEBUG_RENDERING call build_msvc.bat \ No newline at end of file diff --git a/main.c b/main.c index 961fbb5..6b40918 100644 --- a/main.c +++ b/main.c @@ -1155,6 +1155,7 @@ sapp_desc sokol_main(int argc, char* argv[]) { bool hosting = false; + stm_setup(); ma_mutex_init(&server_info.info_mutex); server_info.world_save = "debug_world.bin"; if (argc > 1) { diff --git a/server.c b/server.c index 8c60283..8b23257 100644 --- a/server.c +++ b/server.c @@ -53,7 +53,6 @@ static SpallBuffer spall_buffer; #endif - // started in a thread from host void server(void* info_raw) { @@ -71,7 +70,6 @@ void server(void* info_raw) #endif - stm_setup(); struct GameState gs = { 0 }; size_t entities_size = (sizeof(Entity) * MAX_ENTITIES); @@ -189,6 +187,8 @@ void server(void* info_raw) ENetEvent event; uint64_t last_processed_time = stm_now(); uint64_t last_saved_world_time = stm_now(); + uint64_t last_sent_audio_time = stm_now(); + float audio_time_to_send = 0.0f; float total_time = 0.0f; size_t player_to_latest_id_processed[MAX_PLAYERS] = { 0 }; char* world_save_buffer = malloc(entities_size); @@ -269,7 +269,10 @@ void server(void* info_raw) else { int64_t player_slot = (int64_t)event.peer->data; size_t length = event.packet->dataLength; - struct ClientToServer received = { .mic_data = player_voip_buffers[player_slot] }; + OpusBuffer throwaway_buffer = { 0 }; + OpusBuffer* buffer_to_fill = player_voip_buffers[player_slot]; + if (get_entity(&gs, gs.players[player_slot].entity) == NULL) buffer_to_fill = &throwaway_buffer; + struct ClientToServer received = { .mic_data = buffer_to_fill }; if (!client_to_server_deserialize(&gs, &received, event.packet->data, event.packet->dataLength)) { Log("Bad packet from client %d\n", (int)player_slot); @@ -325,7 +328,9 @@ void server(void* info_raw) entity_destroy(&gs, player_body); } opus_encoder_destroy(player_encoders[player_index]); + player_encoders[player_index] = NULL; opus_decoder_destroy(player_decoders[player_index]); + player_decoders[player_index] = NULL; gs.players[player_index].connected = false; clear_buffer(player_voip_buffers[player_index]); event.peer->data = NULL; @@ -402,6 +407,38 @@ void server(void* info_raw) { PROFILE_SCOPE("send_data") { static char lzo_working_mem[LZO1X_1_MEM_COMPRESS] = { 0 }; + + audio_time_to_send += (float)stm_sec(stm_diff(stm_now(), last_sent_audio_time)); + last_sent_audio_time = stm_now(); + int num_audio_packets = (int)floor(1.0f / (VOIP_TIME_PER_PACKET / audio_time_to_send)); + +#define MAX_AUDIO_PACKETS_TO_SEND 6 + if (num_audio_packets > MAX_AUDIO_PACKETS_TO_SEND) + { + Log("Wants %d, this is too many packets. Greater than the maximum %d\n", num_audio_packets, MAX_AUDIO_PACKETS_TO_SEND); + num_audio_packets = MAX_AUDIO_PACKETS_TO_SEND; + } + + opus_int16 decoded_audio_packets[MAX_PLAYERS][MAX_AUDIO_PACKETS_TO_SEND][VOIP_EXPECTED_FRAME_COUNT] = { 0 }; + + audio_time_to_send -= num_audio_packets * VOIP_TIME_PER_PACKET; + + // decode what everybody said + CONNECTED_PEERS(enet_host, cur) + { + int this_player_index = (int)(int64_t)cur->data; + for (int packet_i = 0; packet_i < num_audio_packets; packet_i++) + { + opus_int16* to_dump_to = decoded_audio_packets[this_player_index][packet_i]; + OpusPacket* cur_packet = pop_packet(player_voip_buffers[this_player_index]); + if (cur_packet == NULL) + opus_decode(player_decoders[this_player_index], NULL, 0, to_dump_to, VOIP_EXPECTED_FRAME_COUNT, 0); + else + opus_decode(player_decoders[this_player_index], cur_packet->data, cur_packet->length, to_dump_to, VOIP_EXPECTED_FRAME_COUNT, 0); + } + } + + // send gamestate to each player CONNECTED_PEERS(enet_host, cur) { int this_player_index = (int)(int64_t)cur->data; @@ -411,10 +448,48 @@ void server(void* info_raw) // @Speed don't recreate the packet for every peer, gets expensive copying gamestate over and over again char* bytes_buffer = malloc(sizeof * bytes_buffer * MAX_SERVER_TO_CLIENT); char* compressed_buffer = malloc(sizeof * compressed_buffer * MAX_SERVER_TO_CLIENT); + + // mix audio to be sent + OpusBuffer* buffer_to_play = calloc(1, sizeof * buffer_to_play); // @Robust no malloc, also in all other places no malloc + { + for (int packet_i = 0; packet_i < num_audio_packets; packet_i++) + { + opus_int16 to_send_to_cur[VOIP_EXPECTED_FRAME_COUNT] = { 0 }; // mix what other players said into this buffer + CONNECTED_PEERS(enet_host, other_player) + { + if (other_player != cur) + { + int other_player_index = (int)(int64_t)other_player->data; + Entity* other_player_entity = get_entity(&gs, gs.players[other_player_index].entity); + if (other_player_entity != NULL) + { + float dist = V2dist(entity_pos(this_player_entity), entity_pos(other_player_entity)); + float volume = lerp(1.0f, 0.0f, clamp01(dist / VOIP_DISTANCE_WHEN_CANT_HEAR)); + if (volume > 0.01f) + { + for (int frame_i = 0; frame_i < VOIP_EXPECTED_FRAME_COUNT; frame_i++) + { + to_send_to_cur[frame_i] += (opus_int16)((float)decoded_audio_packets[other_player_index][packet_i][frame_i]*volume); + } + } + } + } + } + OpusPacket* this_packet = push_packet(buffer_to_play); + opus_int32 ret = opus_encode(player_encoders[this_player_index], to_send_to_cur, VOIP_EXPECTED_FRAME_COUNT, this_packet->data, VOIP_PACKET_MAX_SIZE); + if (ret < 0) + { + Log("Failed to encode audio packet for player %d: opus error code %d\n", this_player_index, ret); + } + else { + this_packet->length = ret; + } + } + } ServerToClient to_send = (ServerToClient){ .cur_gs = &gs, .your_player = this_player_index, - .playback_buffer = player_voip_buffers[this_player_index], + .playback_buffer = buffer_to_play, }; size_t len = 0; @@ -444,6 +519,7 @@ void server(void* info_raw) { Log("Failed to serialize data for client %d\n", this_player_index); } + free(buffer_to_play); free(bytes_buffer); free(compressed_buffer); } @@ -464,7 +540,7 @@ void server(void* info_raw) free(entity_data); enet_host_destroy(enet_host); enet_deinitialize(); - + printf("Cleanup\n"); #ifdef PROFILING diff --git a/server_main.c b/server_main.c index d5758cd..2a65557 100644 --- a/server_main.c +++ b/server_main.c @@ -5,6 +5,7 @@ int main(int argc, char **argv) { + stm_setup(); server("world.bin"); return 0; } diff --git a/tooling.ahk b/tooling.ahk index efbab32..0332727 100644 --- a/tooling.ahk +++ b/tooling.ahk @@ -13,7 +13,7 @@ Sleep, 20 WinActivate, flightbuild If WinActive("flightbuild") { - Send, cd C:\Users\Cameron\Documents\flight{Enter} build_debug.bat && flight.exe{Enter} + Send, cd C:\Users\Cameron\Documents\flight{Enter} build_debug.bat && flight_debug.exe{Enter} } return @@ -26,6 +26,6 @@ WinKill, Flight WinActivate, flightbuild If WinActive("flightbuild") { - Send, cd C:\Users\Cameron\Documents\flight{Enter} build_debug.bat && START /B flight.exe && flight.exe --host{Enter} + Send, cd C:\Users\Cameron\Documents\flight{Enter} build_debug.bat && START /B flight_debug.exe && flight_debug.exe --host{Enter} } return \ No newline at end of file diff --git a/types.h b/types.h index 5a9e3f3..49a7d6e 100644 --- a/types.h +++ b/types.h @@ -38,8 +38,9 @@ #define VOIP_PACKET_BUFFER_SIZE 15 // audio. Must be bigger than 2 #define VOIP_EXPECTED_FRAME_COUNT 480 #define VOIP_SAMPLE_RATE 48000 -#define VOIP_TIME_PER_PACKET 1.0f / ((float)(VOIP_SAMPLE_RATE/VOIP_EXCPECTED_FRAME_COUNT)) // in seconds +#define VOIP_TIME_PER_PACKET 1.0f / ((float)(VOIP_SAMPLE_RATE/VOIP_EXPECTED_FRAME_COUNT)) // in seconds #define VOIP_PACKET_MAX_SIZE 4000 +#define VOIP_DISTANCE_WHEN_CANT_HEAR (BOX_SIZE*13.0f) #define TIMESTEP (1.0f / 60.0f) // not required to simulate at this, but this defines what tick the game is on #define TIME_BETWEEN_INPUT_PACKETS (1.0f / 20.0f) @@ -400,6 +401,23 @@ static int num_queued_packets(OpusBuffer* buff) return to_return; } +static OpusPacket* get_packet_at_index(OpusBuffer* buff, int i) +{ + OpusPacket* to_return = buff->next; + int index_at = 0; + while (index_at < i) + { + if (to_return->next == NULL) + { + Log("FAILED TO GET TO INDEX %d\n", i); + return to_return; + } + to_return = to_return->next; + index_at++; + } + return to_return; +} + // returns null if the packet was dropped, like if the buffer was too full static OpusPacket* pop_packet(OpusBuffer* buff) { @@ -516,6 +534,11 @@ static float V2distsqr(V2 from, V2 to) return V2lengthsqr(V2sub(to, from)); } +static float V2dist(V2 from, V2 to) +{ + return sqrtf(V2distsqr(from, to)); +} + static inline float clamp(float f, float minimum, float maximum) { if (f < minimum)