diff --git a/build-windows-visual-studio/sm64ex.vcxproj b/build-windows-visual-studio/sm64ex.vcxproj
index f10f95cd..b32a53cb 100644
--- a/build-windows-visual-studio/sm64ex.vcxproj
+++ b/build-windows-visual-studio/sm64ex.vcxproj
@@ -3960,6 +3960,7 @@
+
diff --git a/build-windows-visual-studio/sm64ex.vcxproj.filters b/build-windows-visual-studio/sm64ex.vcxproj.filters
index 3e368704..6d367b0c 100644
--- a/build-windows-visual-studio/sm64ex.vcxproj.filters
+++ b/build-windows-visual-studio/sm64ex.vcxproj.filters
@@ -15009,6 +15009,9 @@
Source Files\src\pc\network\packets
+
+ Source Files\src\pc\network\packets
+
diff --git a/src/game/game_init.c b/src/game/game_init.c
index f683782a..55618052 100644
--- a/src/game/game_init.c
+++ b/src/game/game_init.c
@@ -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);
diff --git a/src/game/save_file.c b/src/game/save_file.c
index 9652c97b..65fa8866 100644
--- a/src/game/save_file.c
+++ b/src/game/save_file.c
@@ -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();
}
diff --git a/src/game/save_file.h b/src/game/save_file.h
index c292a156..11a92b8d 100644
--- a/src/game/save_file.h
+++ b/src/game/save_file.h
@@ -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);
diff --git a/src/menu/file_select.c b/src/menu/file_select.c
index 4ca0454e..3fc4e87a 100644
--- a/src/menu/file_select.c
+++ b/src/menu/file_select.c
@@ -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;
}
diff --git a/src/menu/file_select.h b/src/menu/file_select.h
index 91fbb81d..7629ebbd 100644
--- a/src/menu/file_select.h
+++ b/src/menu/file_select.h
@@ -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
diff --git a/src/pc/network/network.c b/src/pc/network/network.c
index 2c86e40c..8a77ce84 100644
--- a/src/pc/network/network.c
+++ b/src/pc/network/network.c
@@ -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;
}
diff --git a/src/pc/network/network.h b/src/pc/network/network.h
index f27d9dba..dc3e8b64 100644
--- a/src/pc/network/network.h
+++ b/src/pc/network/network.h
@@ -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);
diff --git a/src/pc/network/packets/packet_custom.c b/src/pc/network/packets/packet_custom.c
index 702e8751..4a076335 100644
--- a/src/pc/network/packets/packet_custom.c
+++ b/src/pc/network/packets/packet_custom.c
@@ -1,7 +1,7 @@
#include
#include "../network.h"
-#define MAX_CUSTOM_PACKETS 32
+#define MAX_CUSTOM_PACKETS 128
struct NetworkCustomPacket {
void (*send_callback)(struct Packet* p, void* params);
diff --git a/src/pc/network/packets/packet_save_file.c b/src/pc/network/packets/packet_save_file.c
new file mode 100644
index 00000000..3b2dd129
--- /dev/null
+++ b/src/pc/network/packets/packet_save_file.c
@@ -0,0 +1,59 @@
+#include
+#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);
+}
diff --git a/src/pc/ultra_reimplementation.c b/src/pc/ultra_reimplementation.c
index 0389776b..c3776b16 100644
--- a/src/pc/ultra_reimplementation.c
+++ b/src/pc/ultra_reimplementation.c
@@ -9,6 +9,8 @@
#include
#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);