mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2025-12-07 16:42:36 +00:00
203 lines
6.5 KiB
C
203 lines
6.5 KiB
C
#include <stdio.h>
|
|
#include "../network.h"
|
|
#include "pc/djui/djui.h"
|
|
#include "pc/mod_list.h"
|
|
#include "pc/debuglog.h"
|
|
|
|
#define CHUNK_SIZE 400
|
|
#define OFFSET_COUNT 5
|
|
|
|
static u64 sOffset[OFFSET_COUNT] = { 0 };
|
|
static bool sWaitingForOffset[OFFSET_COUNT] = { 0 };
|
|
u64 sTotalDownloadBytes = 0;
|
|
extern float gDownloadProgress;
|
|
|
|
void network_send_next_download_request(void) {
|
|
SOFT_ASSERT(gNetworkType == NT_CLIENT);
|
|
for (int i = 0; i < gModTableRemote.entryCount; i++) {
|
|
struct ModListEntry* entry = &gModTableRemote.entries[i];
|
|
if (entry->complete) { continue; }
|
|
//LOG_INFO("sending download request: %d, %d, %lld", i, entry->remoteIndex, entry->curOffset);
|
|
network_send_download_request(i, entry->remoteIndex, entry->curOffset);
|
|
return;
|
|
}
|
|
//LOG_INFO("sending join request");
|
|
network_send_join_request();
|
|
djui_panel_modlist_create(NULL);
|
|
}
|
|
|
|
void network_send_download_request(u16 clientIndex, u16 serverIndex, u64 offset) {
|
|
SOFT_ASSERT(gNetworkType == NT_CLIENT);
|
|
|
|
struct Packet p = { 0 };
|
|
packet_init(&p, PACKET_DOWNLOAD_REQUEST, true, PLMT_NONE);
|
|
|
|
packet_write(&p, &clientIndex, sizeof(u16));
|
|
packet_write(&p, &serverIndex, sizeof(u16));
|
|
packet_write(&p, &offset, sizeof(u64));
|
|
|
|
if (clientIndex == 0 && offset == 0) {
|
|
sTotalDownloadBytes = 0;
|
|
gDownloadProgress = 0;
|
|
}
|
|
|
|
struct ModListEntry* entry = &gModTableRemote.entries[clientIndex];
|
|
for (int i = 0; i < OFFSET_COUNT; i++) {
|
|
sOffset[i] = offset + CHUNK_SIZE * i;
|
|
sWaitingForOffset[i] = (sOffset[i] < entry->size);
|
|
}
|
|
|
|
network_send_to((gNetworkPlayerServer != NULL) ? gNetworkPlayerServer->localIndex : 0, &p);
|
|
}
|
|
|
|
void network_receive_download_request(struct Packet* p) {
|
|
SOFT_ASSERT(gNetworkType == NT_SERVER);
|
|
|
|
u16 clientIndex;
|
|
u16 serverIndex;
|
|
u64 offset;
|
|
packet_read(p, &clientIndex, sizeof(u16));
|
|
packet_read(p, &serverIndex, sizeof(u16));
|
|
packet_read(p, &offset, sizeof(u64));
|
|
|
|
struct ModListEntry* entry = &gModTableLocal.entries[serverIndex];
|
|
if (serverIndex >= gModTableLocal.entryCount) {
|
|
LOG_ERROR("Requested download of invalid index %u:%llu", serverIndex, offset);
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < OFFSET_COUNT; i++) {
|
|
u64 o = offset + CHUNK_SIZE * i;
|
|
if (o >= entry->size) { break; }
|
|
network_send_download(clientIndex, serverIndex, o);
|
|
}
|
|
}
|
|
|
|
void network_send_download(u16 clientIndex, u16 serverIndex, u64 offset) {
|
|
SOFT_ASSERT(gNetworkType == NT_SERVER);
|
|
|
|
if (serverIndex >= gModTableLocal.entryCount) {
|
|
LOG_ERROR("Requested download of invalid index %u:%llu", serverIndex, offset);
|
|
return;
|
|
}
|
|
|
|
struct ModListEntry* entry = &gModTableLocal.entries[serverIndex];
|
|
if (offset >= entry->size) {
|
|
LOG_ERROR("Requested download of invalid offset %u:%llu", serverIndex, offset);
|
|
return;
|
|
}
|
|
|
|
if (entry->fp == NULL) {
|
|
LOG_ERROR("Requested download of invalid file pointer %u:%llu", serverIndex, offset);
|
|
return;
|
|
}
|
|
|
|
u16 chunkSize = 400;
|
|
if ((offset + chunkSize) > entry->size) {
|
|
chunkSize = entry->size - offset;
|
|
}
|
|
|
|
u8 chunk[400] = { 0 };
|
|
fseek(entry->fp, offset, SEEK_SET);
|
|
fread(chunk, chunkSize, 1, entry->fp);
|
|
|
|
struct Packet p = { 0 };
|
|
packet_init(&p, PACKET_DOWNLOAD, true, PLMT_NONE);
|
|
|
|
packet_write(&p, &clientIndex, sizeof(u16));
|
|
packet_write(&p, &serverIndex, sizeof(u16));
|
|
packet_write(&p, &offset, sizeof(u64));
|
|
packet_write(&p, &chunkSize, sizeof(u16));
|
|
packet_write(&p, chunk, chunkSize * sizeof(u8));
|
|
|
|
network_send_to(0, &p);
|
|
}
|
|
|
|
void network_receive_download(struct Packet* p) {
|
|
SOFT_ASSERT(gNetworkType == NT_CLIENT);
|
|
if (p->localIndex != UNKNOWN_LOCAL_INDEX) {
|
|
if (gNetworkPlayerServer == NULL || gNetworkPlayerServer->localIndex != p->localIndex) {
|
|
LOG_ERROR("Received download from known local index '%d'", p->localIndex);
|
|
return;
|
|
}
|
|
}
|
|
|
|
u16 clientIndex;
|
|
u16 serverIndex;
|
|
u64 offset;
|
|
u16 chunkSize;
|
|
u8 chunk[400] = { 0 };
|
|
|
|
packet_read(p, &clientIndex, sizeof(u16));
|
|
packet_read(p, &serverIndex, sizeof(u16));
|
|
packet_read(p, &offset, sizeof(u64));
|
|
packet_read(p, &chunkSize, sizeof(u16));
|
|
packet_read(p, chunk, chunkSize * sizeof(u8));
|
|
|
|
//LOG_ERROR("Received download %u:%llu", clientIndex, offset);
|
|
|
|
if (clientIndex >= gModTableRemote.entryCount) {
|
|
LOG_ERROR("Received download of invalid index %u:%llu", clientIndex, offset);
|
|
return;
|
|
}
|
|
|
|
struct ModListEntry* entry = &gModTableRemote.entries[clientIndex];
|
|
if (offset >= entry->size) {
|
|
LOG_ERROR("Received download of invalid offset %u:%llu", clientIndex, offset);
|
|
return;
|
|
}
|
|
|
|
if (entry->fp == NULL) {
|
|
LOG_ERROR("Received download of invalid file pointer %u:%llu", clientIndex, offset);
|
|
return;
|
|
}
|
|
|
|
if ((offset + chunkSize) > entry->size) {
|
|
LOG_ERROR("Received download of invalid chunk size %u:%llu:%u", clientIndex, offset, chunkSize);
|
|
return;
|
|
}
|
|
|
|
// check if we're still waiting for chunks
|
|
bool found = false;
|
|
bool waiting = false;
|
|
for (int i = 0; i < OFFSET_COUNT; i++) {
|
|
if (sOffset[i] == offset) {
|
|
found = sWaitingForOffset[i];
|
|
sWaitingForOffset[i] = false;
|
|
}
|
|
waiting = waiting || sWaitingForOffset[i];
|
|
}
|
|
|
|
if (!found) {
|
|
LOG_ERROR("Received download of unexpected offset [ %llu <-> %llu ] != %llu", entry->curOffset, entry->curOffset + CHUNK_SIZE * OFFSET_COUNT, offset);
|
|
return;
|
|
}
|
|
|
|
// write to the file
|
|
fseek(entry->fp, offset, SEEK_SET);
|
|
fwrite(chunk, sizeof(u8) * chunkSize, 1, entry->fp);
|
|
|
|
// update progress
|
|
sTotalDownloadBytes += chunkSize;
|
|
gDownloadProgress = (float)sTotalDownloadBytes / (float)gModTableRemote.totalSize;
|
|
|
|
if (!waiting) {
|
|
// check if we're finished with this file
|
|
//LOG_INFO("Checking download of '%s': %lld, %lld", entry->name, sOffset[OFFSET_COUNT - 1] + CHUNK_SIZE, entry->size);
|
|
if (sOffset[OFFSET_COUNT - 1] + CHUNK_SIZE >= entry->size) {
|
|
LOG_INFO("Finished download of '%s'", entry->name);
|
|
fclose(entry->fp);
|
|
|
|
// parse mod header
|
|
entry->fp = fopen(entry->path, "rb");
|
|
mod_list_extract_lua_fields(entry);
|
|
fclose(entry->fp);
|
|
|
|
entry->fp = NULL;
|
|
entry->complete = true;
|
|
}
|
|
|
|
entry->curOffset += CHUNK_SIZE * OFFSET_COUNT;
|
|
network_send_next_download_request();
|
|
}
|
|
}
|