diff --git a/build-windows-visual-studio/sm64ex.vcxproj b/build-windows-visual-studio/sm64ex.vcxproj index 3c502a579..29a75f56b 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj +++ b/build-windows-visual-studio/sm64ex.vcxproj @@ -474,6 +474,7 @@ + @@ -938,6 +939,7 @@ + diff --git a/build-windows-visual-studio/sm64ex.vcxproj.filters b/build-windows-visual-studio/sm64ex.vcxproj.filters index 1a1bbc0de..c1a67ee8f 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj.filters +++ b/build-windows-visual-studio/sm64ex.vcxproj.filters @@ -4851,6 +4851,9 @@ Source Files\src\pc\network\packets + + Source Files\src\pc\djui\component\compound + @@ -5983,5 +5986,8 @@ Source Files\src\pc\network\packets + + Source Files\src\pc\djui\component\compound + \ No newline at end of file diff --git a/src/pc/djui/djui.h b/src/pc/djui/djui.h index fc8c88dc5..e3cb8fef1 100644 --- a/src/pc/djui/djui.h +++ b/src/pc/djui/djui.h @@ -23,6 +23,7 @@ #include "djui_button.h" #include "djui_inputbox.h" #include "djui_slider.h" +#include "djui_progress_bar.h" #include "djui_checkbox.h" #include "djui_flow_layout.h" #include "djui_selectionbox.h" diff --git a/src/pc/djui/djui_panel_join_message.c b/src/pc/djui/djui_panel_join_message.c index 8a1ddb530..c119b7a45 100644 --- a/src/pc/djui/djui_panel_join_message.c +++ b/src/pc/djui/djui_panel_join_message.c @@ -7,6 +7,7 @@ bool gDjuiPanelJoinMessageVisible = false; static struct DjuiText* sPanelText = NULL; static bool sDisplayingError = false; +float gDownloadProgress = 0; void djui_panel_join_message_error(char* message) { djui_panel_join_message_create(NULL); @@ -41,7 +42,7 @@ void djui_panel_join_message_create(struct DjuiBase* caller) { // don't recreate panel if it's already visible if (gDjuiPanelJoinMessageVisible) { return; } - f32 bodyHeight = 64 + 16; + f32 bodyHeight = 64 + 16 + 16; u16 directLines = 8; f32 directTextHeight = 32 * 0.8125f * directLines + 8; @@ -60,6 +61,9 @@ void djui_panel_join_message_create(struct DjuiBase* caller) { text1->base.on_render_pre = djui_panel_join_message_render_pre; sPanelText = text1; + gDownloadProgress = 0; + djui_progress_bar_create(&body->base, &gDownloadProgress, 0.0f, 1.0f); + struct DjuiButton* button1 = djui_button_create(&body->base, "Cancel"); djui_base_set_size_type(&button1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); djui_base_set_size(&button1->base, 1.0f, 64); diff --git a/src/pc/djui/djui_progress_bar.c b/src/pc/djui/djui_progress_bar.c new file mode 100644 index 000000000..375436fa8 --- /dev/null +++ b/src/pc/djui/djui_progress_bar.c @@ -0,0 +1,51 @@ +#include "djui.h" + +void djui_progress_bar_render_pre(struct DjuiBase* base, UNUSED bool* unused) { + struct DjuiProgressBar* progress = (struct DjuiProgressBar*)base; + progress->smoothValue = progress->smoothValue * 0.95f + *progress->value * 0.05f; + float min = progress->min; + float max = progress->max; + djui_base_set_size(&progress->rectValue->base, ((f32)progress->smoothValue - min) / ((f32)max - min), 1.0f); +} + +static void djui_progress_bar_set_default_style(struct DjuiBase* base) { + struct DjuiProgressBar* progress = (struct DjuiProgressBar*)base; + djui_base_set_border_color(&progress->rect->base, 173, 173, 173, 255); + djui_base_set_color(&progress->rect->base, 0, 0, 0, 0); + djui_base_set_color(&progress->rectValue->base, 200, 200, 200, 255); +} + +static void djui_progress_bar_destroy(struct DjuiBase* base) { + struct DjuiProgressBar* progress = (struct DjuiProgressBar*)base; + free(progress); +} + +struct DjuiProgressBar* djui_progress_bar_create(struct DjuiBase* parent, float* value, float min, float max) { + struct DjuiProgressBar* progress = calloc(1, sizeof(struct DjuiProgressBar)); + struct DjuiBase* base = &progress->base; + + progress->value = value; + progress->smoothValue = *value; + progress->min = min; + progress->max = max; + + djui_base_init(parent, base, NULL, djui_progress_bar_destroy); + djui_base_set_size_type(base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(base, 1.0f, 16); + base->on_render_pre = djui_progress_bar_render_pre; + + struct DjuiRect* rect = djui_rect_create(&progress->base); + djui_base_set_size_type(&rect->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE); + djui_base_set_size(&rect->base, 1.0f, 1.0f); + djui_base_set_color(&rect->base, 0, 0, 0, 0); + djui_base_set_border_width(&rect->base, 2); + progress->rect = rect; + + struct DjuiRect* rectValue = djui_rect_create(&rect->base); + djui_base_set_size_type(&rectValue->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE); + progress->rectValue = rectValue; + + djui_progress_bar_set_default_style(base); + + return progress; +} diff --git a/src/pc/djui/djui_progress_bar.h b/src/pc/djui/djui_progress_bar.h new file mode 100644 index 000000000..f191d3200 --- /dev/null +++ b/src/pc/djui/djui_progress_bar.h @@ -0,0 +1,15 @@ +#pragma once +#include "djui.h" + +#pragma pack(1) +struct DjuiProgressBar { + struct DjuiBase base; + struct DjuiRect* rect; + struct DjuiRect* rectValue; + float* value; + float smoothValue; + float min; + float max; +}; + +struct DjuiProgressBar* djui_progress_bar_create(struct DjuiBase* parent, float* value, float min, float max); diff --git a/src/pc/lua/smlua.c b/src/pc/lua/smlua.c index 4d444efbb..2d01076be 100644 --- a/src/pc/lua/smlua.c +++ b/src/pc/lua/smlua.c @@ -92,7 +92,7 @@ void smlua_init(void) { // load scripts LOG_INFO("Loading scripts:"); - for (int i = 0; i < sModEntryCount; i++) { + for (int i = 0; i < gModEntryCount; i++) { struct ModListEntry* entry = &gModEntries[i]; LOG_INFO(" %s", entry->path); smlua_load_script(entry->path); diff --git a/src/pc/mod_list.c b/src/pc/mod_list.c index 342f6981b..a3e97a615 100644 --- a/src/pc/mod_list.c +++ b/src/pc/mod_list.c @@ -7,7 +7,9 @@ #define MAX_SESSION_CHARS 7 struct ModListEntry* gModEntries = NULL; -u16 sModEntryCount = 0; +u16 gModEntryCount = 0; +u64 gModTotalSize = 0; + static char sTmpSession[MAX_SESSION_CHARS] = { 0 }; static char sTmpPath[PATH_MAX] = { 0 }; @@ -18,8 +20,8 @@ static bool acceptable_file(char* string) { void mod_list_alloc(u16 count) { mod_list_clear(); - sModEntryCount = count; - gModEntries = (struct ModListEntry*)calloc(sModEntryCount, sizeof(struct ModListEntry)); + gModEntryCount = count; + gModEntries = (struct ModListEntry*)calloc(gModEntryCount, sizeof(struct ModListEntry)); } void mod_list_add(u16 index, char* name, size_t size, bool tmpFile) { @@ -27,6 +29,7 @@ void mod_list_add(u16 index, char* name, size_t size, bool tmpFile) { struct ModListEntry* entry = &gModEntries[index]; entry->name = name; entry->size = size; + gModTotalSize += size; if (tmpFile) { snprintf(entry->path, PATH_MAX - 1, "%s/%s-%s", sTmpPath, sTmpSession, name); @@ -62,6 +65,7 @@ void mod_list_load(void) { u16 index = 0; LOG_INFO("Loading mods:"); + gModTotalSize = 0; while ((dir = readdir(d)) != NULL) { if (!acceptable_file(dir->d_name)) { continue; } LOG_INFO(" %s", dir->d_name); @@ -72,7 +76,7 @@ void mod_list_load(void) { } void mod_list_clear(void) { - for (int i = 0; i < sModEntryCount; i++) { + for (int i = 0; i < gModEntryCount; i++) { struct ModListEntry* entry = &gModEntries[i]; if (entry->name != NULL) { free(entry->name); @@ -88,7 +92,7 @@ void mod_list_clear(void) { free(gModEntries); gModEntries = NULL; } - sModEntryCount = 0; + gModEntryCount = 0; } static void mod_list_delete_tmp(void) { diff --git a/src/pc/mod_list.h b/src/pc/mod_list.h index 85021ccb9..49dbe840a 100644 --- a/src/pc/mod_list.h +++ b/src/pc/mod_list.h @@ -18,7 +18,8 @@ struct ModListEntry { bool complete; }; extern struct ModListEntry* gModEntries; -extern u16 sModEntryCount; +extern u16 gModEntryCount; +extern u64 gModTotalSize; void mod_list_alloc(u16 count); void mod_list_add(u16 index, char* name, size_t size, bool tmpFile); diff --git a/src/pc/network/packets/packet_download.c b/src/pc/network/packets/packet_download.c index 711a5fef3..fb313c3c6 100644 --- a/src/pc/network/packets/packet_download.c +++ b/src/pc/network/packets/packet_download.c @@ -8,10 +8,12 @@ static u64 sOffset[OFFSET_COUNT] = { 0 }; static bool sWaitingForOffset[OFFSET_COUNT] = { 0 }; +u64 sTotalDownloadBytes = 0; +extern float gDownloadProgress; static void network_send_next_download_request(void) { SOFT_ASSERT(gNetworkType == NT_CLIENT); - for (int i = 0; i < sModEntryCount; i++) { + for (int i = 0; i < gModEntryCount; i++) { struct ModListEntry* entry = &gModEntries[i]; if (entry->complete) { continue; } network_send_download_request(i, entry->curOffset); @@ -29,6 +31,11 @@ void network_send_download_request(u16 index, u64 offset) { packet_write(&p, &index, sizeof(u16)); packet_write(&p, &offset, sizeof(u64)); + if (index == 0 && offset == 0) { + sTotalDownloadBytes = 0; + gDownloadProgress = 0; + } + struct ModListEntry* entry = &gModEntries[index]; for (int i = 0; i < OFFSET_COUNT; i++) { sOffset[i] = offset + CHUNK_SIZE * i; @@ -47,7 +54,7 @@ void network_receive_download_request(struct Packet* p) { packet_read(p, &offset, sizeof(u64)); struct ModListEntry* entry = &gModEntries[index]; - if (index >= sModEntryCount) { + if (index >= gModEntryCount) { LOG_ERROR("Requested download of invalid index %u:%llu", index, offset); return; } @@ -62,7 +69,7 @@ void network_receive_download_request(struct Packet* p) { void network_send_download(u16 index, u64 offset) { SOFT_ASSERT(gNetworkType == NT_SERVER); - if (index >= sModEntryCount) { + if (index >= gModEntryCount) { LOG_ERROR("Requested download of invalid index %u:%llu", index, offset); return; } @@ -115,7 +122,7 @@ void network_receive_download(struct Packet* p) { packet_read(p, &chunkSize, sizeof(u16)); packet_read(p, chunk, chunkSize * sizeof(u8)); - if (index >= sModEntryCount) { + if (index >= gModEntryCount) { LOG_ERROR("Received download of invalid index %u:%llu", index, offset); return; } @@ -148,7 +155,7 @@ void network_receive_download(struct Packet* p) { } if (!found) { - LOG_ERROR("Received download of unexpected offset %llu != %llu", entry->curOffset, offset); + LOG_ERROR("Received download of unexpected offset [ %llu <-> %llu ] != %llu", entry->curOffset, entry->curOffset + CHUNK_SIZE * OFFSET_COUNT, offset); return; } @@ -156,6 +163,10 @@ void network_receive_download(struct Packet* p) { fseek(entry->fp, offset, SEEK_SET); fwrite(chunk, sizeof(u8) * chunkSize, 1, entry->fp); + // update progress + sTotalDownloadBytes += chunkSize; + gDownloadProgress = (float)sTotalDownloadBytes / (float)gModTotalSize; + if (!waiting) { // check if we're finished with this file if (sOffset[OFFSET_COUNT - 1] >= entry->size) { diff --git a/src/pc/network/packets/packet_mod_list.c b/src/pc/network/packets/packet_mod_list.c index 5b9b18aa2..debb1eebd 100644 --- a/src/pc/network/packets/packet_mod_list.c +++ b/src/pc/network/packets/packet_mod_list.c @@ -44,9 +44,9 @@ void network_send_mod_list(void) { struct Packet p = { 0 }; packet_init(&p, PACKET_MOD_LIST, true, PLMT_NONE); - packet_write(&p, &sModEntryCount, sizeof(u16)); - LOG_INFO("sent mod list (%u):", sModEntryCount); - for (int i = 0; i < sModEntryCount; i++) { + packet_write(&p, &gModEntryCount, sizeof(u16)); + LOG_INFO("sent mod list (%u):", gModEntryCount); + for (int i = 0; i < gModEntryCount; i++) { struct ModListEntry* entry = &gModEntries[i]; u16 nameLength = strlen(entry->name); packet_write(&p, &nameLength, sizeof(u16)); @@ -74,6 +74,7 @@ void network_receive_mod_list(struct Packet* p) { mod_list_alloc(modEntryCount); LOG_INFO("received mod list (%u):", modEntryCount); + gModTotalSize = 0; for (int i = 0; i < modEntryCount; i++) { u16 nameLength = 0; packet_read(p, &nameLength, sizeof(u16));