Synchronized save files

Now when a client joins, it will request the entire 512 byte EEPROM from
the server and refuse to continue until the server replies with the
contents. Then the client will override all reads and writes to the
EEPROM/save file. Thus, a client will never overwrite their local save.

Fixes #21
This commit is contained in:
MysterD 2020-09-04 15:05:02 -07:00
parent 1289f863ca
commit 4a2c218f11
12 changed files with 129 additions and 21 deletions

View file

@ -3960,6 +3960,7 @@
<ClCompile Include="..\src\pc\network\packets\packet_read_write.c" />
<ClCompile Include="..\src\pc\network\packets\packet_reliable.c" />
<ClCompile Include="..\src\pc\network\packets\packet_reservation.c" />
<ClCompile Include="..\src\pc\network\packets\packet_save_file.c" />
<ClCompile Include="..\src\pc\network\packets\packet_spawn_objects.c" />
<ClCompile Include="..\src\pc\network\packets\packet_spawn_star.c" />
<ClCompile Include="..\src\pc\network\socket\socket.c" />

View file

@ -15009,6 +15009,9 @@
<ClCompile Include="..\src\pc\network\packets\packet_custom.c">
<Filter>Source Files\src\pc\network\packets</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_save_file.c">
<Filter>Source Files\src\pc\network\packets</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\actors\common0.h">

View file

@ -570,7 +570,7 @@ void thread5_game_loop(UNUSED void *arg) {
init_rumble_pak_scheduler_queue();
init_controllers();
create_thread_6();
save_file_load_all();
save_file_load_all(FALSE);
set_vblank_handler(2, &gGameVblankHandler, &gGameVblankQueue, (OSMesg) 1);

View file

@ -12,6 +12,7 @@
#include "thread6.h"
#include "macros.h"
#include "pc/ini.h"
#include "pc/network/network.h"
#define MENU_DATA_MAGIC 0x4849
#define SAVE_FILE_MAGIC 0x4441
@ -345,16 +346,17 @@ void save_file_do_save(s32 fileIndex) {
if (fileIndex < 0 || fileIndex >= NUM_SAVE_FILES)
return;
if (gSaveFileModified)
#ifdef TEXTSAVES
{
if (gSaveFileModified && networkType != NT_CLIENT) {
// Write to text file
write_text_save(fileIndex);
gSaveFileModified = FALSE;
gMainMenuDataModified = FALSE;
return;
}
#else
{
#endif
if (gSaveFileModified) {
// Compute checksum
add_save_block_signature(&gSaveBuffer.files[fileIndex][0],
sizeof(gSaveBuffer.files[fileIndex][0]), SAVE_FILE_MAGIC);
@ -369,7 +371,6 @@ void save_file_do_save(s32 fileIndex) {
gSaveFileModified = FALSE;
}
save_main_menu_data();
#endif
}
void save_file_erase(s32 fileIndex) {
@ -396,7 +397,18 @@ BAD_RETURN(s32) save_file_copy(s32 srcFileIndex, s32 destFileIndex) {
save_file_do_save(destFileIndex);
}
void save_file_load_all(void) {
#ifdef TEXTSAVES
static void save_file_load_textsaves(void) {
for (file = 0; file < NUM_SAVE_FILES; file++) {
read_text_save(file);
}
gSaveFileModified = TRUE;
gMainMenuDataModified = TRUE;
stub_save_file_1();
}
#endif
void save_file_load_all(u8 reload) {
s32 file;
gMainMenuDataModified = FALSE;
@ -405,19 +417,19 @@ void save_file_load_all(void) {
bzero(&gSaveBuffer, sizeof(gSaveBuffer));
#ifdef TEXTSAVES
for (file = 0; file < NUM_SAVE_FILES; file++) {
read_text_save(file);
if (!reload) {
save_file_load_textsaves();
return;
}
gSaveFileModified = TRUE;
gMainMenuDataModified = TRUE;
#else
s32 validSlots;
#endif
read_eeprom_data(&gSaveBuffer, sizeof(gSaveBuffer));
if (save_file_need_bswap(&gSaveBuffer))
save_file_bswap(&gSaveBuffer);
// Verify the main menu data and create a backup copy if only one of the slots is valid.
s32 validSlots;
validSlots = verify_save_block_signature(&gSaveBuffer.menuData[0], sizeof(gSaveBuffer.menuData[0]), MENU_DATA_MAGIC);
validSlots |= verify_save_block_signature(&gSaveBuffer.menuData[1], sizeof(gSaveBuffer.menuData[1]),MENU_DATA_MAGIC) << 1;
switch (validSlots) {
@ -448,7 +460,6 @@ void save_file_load_all(void) {
break;
}
}
#endif // TEXTSAVES
stub_save_file_1();
}

View file

@ -124,7 +124,7 @@ extern s8 gSaveFileModified;
void save_file_do_save(s32 fileIndex);
void save_file_erase(s32 fileIndex);
BAD_RETURN(s32) save_file_copy(s32 srcFileIndex, s32 destFileIndex);
void save_file_load_all(void);
void save_file_load_all(u8 reload);
void save_file_reload(void);
void save_file_collect_star_or_key(s16 coinScore, s16 starIndex);
s32 save_file_exists(s32 fileIndex);

View file

@ -382,6 +382,7 @@ void exit_join_to_network_menu(void) {
&& sCursorClickingTimer == 2) {
play_sound(SOUND_MENU_CAMERA_ZOOM_OUT, gDefaultSoundArgs);
sMainMenuButtons[MENU_BUTTON_JOIN]->oMenuButtonState = MENU_BUTTON_STATE_SHRINKING;
network_shutdown();
keyboard_stop_text_input();
}
// End exit
@ -399,7 +400,8 @@ void keyboard_exit_join_to_network_menu(void) {
}
void join_server_as_client(void) {
sCursorClickingTimer = 2;
if (networkType != NT_NONE) { return; }
char delims[] = { ' ' };
// trim whitespace
@ -420,8 +422,13 @@ void join_server_as_client(void) {
return;
}
keyboard_stop_text_input();
network_init(NT_CLIENT, textInput, port);
sSelectedFileNum = 1;
}
void joined_server_as_client(s16 fileIndex) {
if (networkType != NT_CLIENT) { return; }
sSelectedFileNum = fileIndex;
}
void render_network_mode_menu_buttons(struct Object* soundModeButton) {
@ -3054,7 +3061,7 @@ s32 lvl_init_menu_values_and_cursor_pos(UNUSED s32 arg, UNUSED s32 unused) {
sClickPos[0] = -10000;
sClickPos[1] = -10000;
sCursorClickingTimer = 0;
sSelectedFileNum = 0;
if (networkType != NT_CLIENT) { sSelectedFileNum = 0; }
sSelectedFileIndex = MENU_BUTTON_NONE;
sFadeOutText = FALSE;
sStatusMessageID = 0;
@ -3080,7 +3087,7 @@ s32 lvl_init_menu_values_and_cursor_pos(UNUSED s32 arg, UNUSED s32 unused) {
sCursorPos[1] = -24.0f;
// immediately jump in
if (networkType != NT_NONE) {
if (networkType == NT_SERVER) {
sSelectedFileNum = 1;
}

View file

@ -143,5 +143,6 @@ void bhv_menu_button_manager_loop(void);
Gfx *geo_file_select_strings_and_menu_cursor(s32 callContext, UNUSED struct GraphNode *node, UNUSED Mat4 mtx);
s32 lvl_init_menu_values_and_cursor_pos(UNUSED s32 arg, UNUSED s32 unused);
s32 lvl_update_obj_and_load_file_selected(UNUSED s32 arg, UNUSED s32 unused);
void joined_server_as_client(s16 fileIndex);
#endif // FILE_SELECT_H

View file

@ -34,6 +34,10 @@ void network_init(enum NetworkType inNetworkType, char* ip, char* port) {
txAddr.sin_port = htons(atoi(port));
txAddr.sin_addr.s_addr = inet_addr(ip);
}
if (networkType == NT_CLIENT) {
network_send_save_file_request();
}
}
void network_on_init_level(void) {
@ -108,6 +112,8 @@ void network_update(void) {
case PACKET_COLLECT_ITEM: network_receive_collect_item(&p); break;
case PACKET_RESERVATION_REQUEST: network_receive_reservation_request(&p); break;
case PACKET_RESERVATION: network_receive_reservation(&p); break;
case PACKET_SAVE_FILE_REQUEST: network_receive_save_file_request(&p); break;
case PACKET_SAVE_FILE: network_receive_save_file(&p); break;
case PACKET_CUSTOM: network_receive_custom(&p); break;
default: printf("%s received unknown packet: %d\n", NETWORKTYPESTR, p.buffer[0]);
}
@ -123,4 +129,5 @@ void network_update(void) {
void network_shutdown(void) {
if (networkType == NT_NONE) { return; }
socket_close(gSocket);
networkType = NT_NONE;
}

View file

@ -29,6 +29,8 @@ enum PacketType {
PACKET_COLLECT_ITEM,
PACKET_RESERVATION_REQUEST,
PACKET_RESERVATION,
PACKET_SAVE_FILE_REQUEST,
PACKET_SAVE_FILE,
PACKET_CUSTOM = 255,
};
@ -127,10 +129,15 @@ void network_send_collect_item(struct Object* o);
void network_receive_collect_item(struct Packet* p);
void network_send_reservation_request(void);
void network_receive_reservation_request(struct Packet* p);
void network_receive_reservation_request(UNUSED struct Packet* p);
void network_send_reservation(void);
void network_receive_reservation(struct Packet* p);
void network_send_save_file_request(void);
void network_receive_save_file_request(UNUSED struct Packet* p);
void network_send_save_file(void);
void network_receive_save_file(struct Packet* p);
u8 network_register_custom_packet(void (*send_callback)(struct Packet* p, void* params), void (*receive_callback)(struct Packet* p));
void network_send_custom(u8 customId, bool reliable, void* params);
void network_receive_custom(struct Packet* p);

View file

@ -1,7 +1,7 @@
#include <stdio.h>
#include "../network.h"
#define MAX_CUSTOM_PACKETS 32
#define MAX_CUSTOM_PACKETS 128
struct NetworkCustomPacket {
void (*send_callback)(struct Packet* p, void* params);

View file

@ -0,0 +1,59 @@
#include <stdio.h>
#include "../network.h"
#include "object_fields.h"
#include "object_constants.h"
#include "behavior_table.h"
#include "course_table.h"
#include "src/game/interaction.h"
#include "src/engine/math_util.h"
#include "src/game/save_file.h"
#include "src/menu/file_select.h"
#include "src/pc/fs/fs.h"
#include "PR/os_eeprom.h"
extern u8* gOverrideEeprom;
static u8 eeprom[512] = { 0 };
void network_send_save_file_request(void) {
assert(networkType == NT_CLIENT);
gOverrideEeprom = eeprom;
struct Packet p;
packet_init(&p, PACKET_SAVE_FILE_REQUEST, true);
network_send(&p);
}
void network_receive_save_file_request(UNUSED struct Packet* p) {
assert(networkType == NT_SERVER);
network_send_save_file();
}
void network_send_save_file(void) {
assert(networkType == NT_SERVER);
fs_file_t* fp = fs_open(SAVE_FILENAME);
if (fp != NULL) {
fs_read(fp, eeprom, 512);
fs_close(fp);
}
struct Packet p;
packet_init(&p, PACKET_SAVE_FILE, true);
packet_write(&p, &gCurrSaveFileNum, sizeof(s16));
packet_write(&p, eeprom, sizeof(u8) * 512);
network_send(&p);
}
void network_receive_save_file(struct Packet* p) {
assert(networkType == NT_CLIENT);
gOverrideEeprom = eeprom;
// find all reserved objects
packet_read(p, &gCurrSaveFileNum, sizeof(s16));
packet_read(p, eeprom, sizeof(u8) * 512);
save_file_load_all(TRUE);
joined_server_as_client(gCurrSaveFileNum);
}

View file

@ -9,6 +9,8 @@
#include <emscripten.h>
#endif
u8* gOverrideEeprom = NULL;
extern OSMgrArgs piMgrArgs;
u64 osClockRate = 62500000;
@ -124,6 +126,11 @@ s32 osEepromProbe(UNUSED OSMesgQueue *mq) {
}
s32 osEepromLongRead(UNUSED OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes) {
if (gOverrideEeprom != NULL) {
memcpy(buffer, gOverrideEeprom + address * 8, nbytes);
return 0;
}
u8 content[512];
s32 ret = -1;
@ -162,6 +169,11 @@ s32 osEepromLongRead(UNUSED OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes)
}
s32 osEepromLongWrite(UNUSED OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes) {
if (gOverrideEeprom != NULL) {
memcpy(gOverrideEeprom + address * 8, buffer, nbytes);
return 0;
}
u8 content[512] = {0};
if (address != 0 || nbytes != 512) {
osEepromLongRead(mq, 0, content, 512);