mirror of
https://github.com/HarbourMasters/SpaghettiKart
synced 2026-07-08 14:37:09 -04:00
Better controller pak with File deletion menu
Co-authored-by: Dario <dariosamo@gmail.com> Co-authored-by: Mr-Wiseguy <mrwiseguyromhacking@gmail.com>
This commit is contained in:
+11
-11
@@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <libultraship.h>
|
||||
#include "World.h"
|
||||
|
||||
class Rulesets {
|
||||
public:
|
||||
virtual void PreLoad();
|
||||
virtual void PreInit();
|
||||
virtual void PostInit();
|
||||
};
|
||||
#pragma once
|
||||
|
||||
#include <libultraship.h>
|
||||
#include "World.h"
|
||||
|
||||
class Rulesets {
|
||||
public:
|
||||
virtual void PreLoad();
|
||||
virtual void PreInit();
|
||||
virtual void PostInit();
|
||||
};
|
||||
|
||||
@@ -0,0 +1,371 @@
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
#include <libultraship.h>
|
||||
#include <libultraship/libultra.h>
|
||||
#include <save.h>
|
||||
|
||||
#define MAX_FILES 16
|
||||
#define EXT_NAME_SIZE 4
|
||||
#define GAME_NAME_SIZE 16
|
||||
|
||||
typedef struct ControllerPak {
|
||||
std::fstream header;
|
||||
std::fstream file;
|
||||
} ControllerPak;
|
||||
|
||||
void Pfs_PakHeader_Write(u32* file_size, u32* game_code, u16* company_code, u8* ext_name, u8* game_name, u8 fileIndex) {
|
||||
ControllerPak pak;
|
||||
|
||||
pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out);
|
||||
|
||||
if (!pak.header.good()) {
|
||||
assert(false);
|
||||
}
|
||||
if (!pak.header.is_open()) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
/* Set file parameters to header */
|
||||
u32 seek = fileIndex * sizeof(OSPfsState);
|
||||
|
||||
// file_size
|
||||
pak.header.seekp(seek + 0x0, std::ios::beg);
|
||||
pak.header.write((char*) file_size, 4);
|
||||
// game_code
|
||||
pak.header.seekp(seek + 0x4, std::ios::beg);
|
||||
pak.header.write((char*) game_code, 4);
|
||||
// company_code
|
||||
pak.header.seekp(seek + 0x08, std::ios::beg);
|
||||
pak.header.write((char*) company_code, 2);
|
||||
// ext_name
|
||||
pak.header.seekp(seek + 0x0C, std::ios::beg);
|
||||
pak.header.write((char*) ext_name, EXT_NAME_SIZE);
|
||||
// game_name
|
||||
pak.header.seekp(seek + 0x10, std::ios::beg);
|
||||
pak.header.write((char*) game_name, GAME_NAME_SIZE);
|
||||
|
||||
pak.header.close();
|
||||
}
|
||||
|
||||
void Pfs_PakHeader_Read(u32* file_size, u32* game_code, u16* company_code, char* ext_name, char* game_name,
|
||||
u8 fileIndex) {
|
||||
ControllerPak pak;
|
||||
|
||||
pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out);
|
||||
|
||||
if (!pak.header.good()) {
|
||||
assert(false);
|
||||
}
|
||||
if (!pak.header.is_open()) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
/* Set file parameters to header */
|
||||
u32 seek = fileIndex * sizeof(OSPfsState);
|
||||
|
||||
// file_size
|
||||
pak.header.seekg(seek + 0x0, std::ios::beg);
|
||||
pak.header.read((char*) file_size, 4);
|
||||
// game_code
|
||||
pak.header.seekg(seek + 0x4, std::ios::beg);
|
||||
pak.header.read((char*) game_code, 4);
|
||||
// company_code
|
||||
pak.header.seekg(seek + 0x08, std::ios::beg);
|
||||
pak.header.read((char*) company_code, 2);
|
||||
// ext_name
|
||||
pak.header.seekg(seek + 0x0C, std::ios::beg);
|
||||
pak.header.read((char*) ext_name, EXT_NAME_SIZE);
|
||||
// game_name
|
||||
pak.header.seekg(seek + 0x10, std::ios::beg);
|
||||
pak.header.read((char*) game_name, GAME_NAME_SIZE);
|
||||
|
||||
pak.header.close();
|
||||
}
|
||||
|
||||
extern "C" s32 osPfsIsPlug(OSMesgQueue* queue, u8* pattern) {
|
||||
*pattern = 1;
|
||||
return PFS_NO_ERROR;
|
||||
}
|
||||
|
||||
extern "C" s32 osPfsInit(OSMesgQueue* queue, OSPfs* pfs, int channel) {
|
||||
pfs->queue = queue;
|
||||
pfs->channel = channel;
|
||||
pfs->status = PFS_INITIALIZED;
|
||||
|
||||
ControllerPak pak;
|
||||
|
||||
// If a header file doesn't exist, create it.
|
||||
if (!std::filesystem::exists("controllerPak_header.sav")) {
|
||||
pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out | std::ios::trunc);
|
||||
pak.header.close();
|
||||
}
|
||||
|
||||
return PFS_NO_ERROR;
|
||||
}
|
||||
|
||||
extern "C" s32 osPfsFreeBlocks(OSPfs* pfs, s32* bytes_not_used) {
|
||||
ControllerPak pak;
|
||||
|
||||
pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out);
|
||||
|
||||
if (!pak.header.good()) {
|
||||
assert(false);
|
||||
}
|
||||
if (!pak.header.is_open()) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
s32 usedSpace = 0;
|
||||
for (size_t i = 0; i < MAX_FILES; i++) {
|
||||
u32 file_size = 0;
|
||||
u32 game_code = 0;
|
||||
u16 company_code = 0;
|
||||
char ext_name[EXT_NAME_SIZE] = { 0 };
|
||||
char game_name[GAME_NAME_SIZE] = { 0 };
|
||||
|
||||
Pfs_PakHeader_Read(&file_size, &game_code, &company_code, ext_name, game_name, i);
|
||||
|
||||
if ((company_code == 0) || (game_code == 0)) {
|
||||
continue;
|
||||
} else {
|
||||
usedSpace += file_size >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
pak.header.close();
|
||||
|
||||
*bytes_not_used = (123 - usedSpace) << 8;
|
||||
|
||||
return PFS_NO_ERROR;
|
||||
}
|
||||
|
||||
extern "C" s32 osPfsAllocateFile(OSPfs* pfs, u16 company_code, u32 game_code, u8* game_name, u8* ext_name,
|
||||
int file_size_in_bytes, s32* file_no) {
|
||||
|
||||
if ((company_code == 0) || (game_code == 0)) {
|
||||
return PFS_ERR_INVALID;
|
||||
}
|
||||
|
||||
ControllerPak pak;
|
||||
|
||||
/* Search for a free slot */
|
||||
u8 freeFileIndex = 0;
|
||||
for (size_t i = 0; i < MAX_FILES; i++) {
|
||||
u32 file_size_ = 0;
|
||||
u32 game_code_ = 0;
|
||||
u16 company_code_ = 0;
|
||||
char ext_name_[EXT_NAME_SIZE] = { 0 };
|
||||
char game_name_[GAME_NAME_SIZE] = { 0 };
|
||||
|
||||
Pfs_PakHeader_Read(&file_size_, &game_code_, &company_code_, ext_name_, game_name_, i);
|
||||
|
||||
if ((company_code_ == 0) || (game_code_ == 0)) {
|
||||
freeFileIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (freeFileIndex == MAX_FILES) {
|
||||
return PFS_DIR_FULL;
|
||||
}
|
||||
|
||||
Pfs_PakHeader_Write((u32*) &file_size_in_bytes, &game_code, &company_code, ext_name, game_name, freeFileIndex);
|
||||
|
||||
/* Create empty file */
|
||||
char filename[100];
|
||||
sprintf(filename, "controllerPak_file_%d.sav", freeFileIndex);
|
||||
pak.file.open(filename, std::ios::binary | std::ios::in | std::ios::out | std::ios::trunc);
|
||||
|
||||
file_size_in_bytes = (file_size_in_bytes + 31) & ~31;
|
||||
|
||||
char* zero_block = (char*) malloc(file_size_in_bytes);
|
||||
for (size_t i = 0; i < file_size_in_bytes; i++) {
|
||||
zero_block[i] = 0;
|
||||
}
|
||||
|
||||
pak.file.seekp(0, std::ios::beg);
|
||||
pak.file.write(zero_block, file_size_in_bytes);
|
||||
|
||||
free(zero_block);
|
||||
|
||||
pak.file.close();
|
||||
|
||||
*file_no = freeFileIndex;
|
||||
|
||||
return PFS_NO_ERROR;
|
||||
}
|
||||
|
||||
extern "C" s32 osPfsFileState(OSPfs* pfs, s32 file_no, OSPfsState* state) {
|
||||
u32 file_size = 0;
|
||||
u32 game_code = 0;
|
||||
u16 company_code = 0;
|
||||
char ext_name[EXT_NAME_SIZE] = { 0 };
|
||||
char game_name[GAME_NAME_SIZE] = { 0 };
|
||||
|
||||
// should pass the state of the requested file_no to the incoming state pointer,
|
||||
// games call this function 16 times, once per file
|
||||
// fills the incoming state with the information inside the header of the pak.
|
||||
|
||||
char filename[100];
|
||||
sprintf(filename, "controllerPak_file_%d.sav", file_no);
|
||||
if (!std::filesystem::exists(filename)) {
|
||||
return PFS_ERR_INVALID;
|
||||
}
|
||||
|
||||
/* Read game info from pak */
|
||||
Pfs_PakHeader_Read(&file_size, &game_code, &company_code, ext_name, game_name, file_no);
|
||||
|
||||
state->file_size = file_size;
|
||||
state->company_code = game_code;
|
||||
state->game_code = game_code;
|
||||
|
||||
for (size_t j = 0; j < GAME_NAME_SIZE; j++) {
|
||||
state->game_name[j] = game_name[j];
|
||||
}
|
||||
for (size_t j = 0; j < EXT_NAME_SIZE; j++) {
|
||||
state->ext_name[j] = ext_name[j];
|
||||
}
|
||||
|
||||
return PFS_NO_ERROR;
|
||||
}
|
||||
|
||||
extern "C" s32 osPfsFindFile(OSPfs* pfs, u16 company_code, u32 game_code, u8* game_name, u8* ext_name, s32* file_no) {
|
||||
ControllerPak pak;
|
||||
|
||||
for (size_t i = 0; i < MAX_FILES; i++) {
|
||||
u32 file_size_ = 0;
|
||||
u32 game_code_ = 0;
|
||||
u16 company_code_ = 0;
|
||||
char ext_name_[EXT_NAME_SIZE] = { 0 };
|
||||
char game_name_[GAME_NAME_SIZE] = { 0 };
|
||||
|
||||
Pfs_PakHeader_Read(&file_size_, &game_code_, &company_code_, ext_name_, game_name_, i);
|
||||
|
||||
if ((company_code_ == 0) || (game_code_ == 0)) {
|
||||
continue;
|
||||
} else {
|
||||
if ((game_code == game_code_) && (company_code == company_code_) &&
|
||||
(strcmp((const char*) game_name, (const char*) game_name_) == 0) &&
|
||||
strcmp((const char*) ext_name, (const char*) ext_name_) == 0) {
|
||||
// File found
|
||||
*file_no = i;
|
||||
return PFS_NO_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// File not found
|
||||
return PFS_ERR_INVALID;
|
||||
}
|
||||
|
||||
extern "C" s32 osPfsReadWriteFile(OSPfs* pfs, s32 file_no, u8 flag, int offset, int size_in_bytes, u8* data_buffer) {
|
||||
ControllerPak pak;
|
||||
|
||||
char filename[100];
|
||||
sprintf(filename, "controllerPak_file_%d.sav", file_no);
|
||||
pak.file.open(filename, std::ios::binary | std::ios::in | std::ios::out);
|
||||
|
||||
if (!std::filesystem::exists(filename)) {
|
||||
return PFS_ERR_INVALID;
|
||||
}
|
||||
if (!pak.file.good()) {
|
||||
return PFS_ERR_INVALID;
|
||||
}
|
||||
if (!pak.file.is_open()) {
|
||||
return PFS_ERR_INVALID;
|
||||
}
|
||||
|
||||
if (flag == 0) {
|
||||
pak.file.seekg(offset, std::ios::beg);
|
||||
pak.file.read((char*) data_buffer, size_in_bytes);
|
||||
} else {
|
||||
pak.file.seekp(offset, std::ios::beg);
|
||||
pak.file.write((char*) data_buffer, size_in_bytes);
|
||||
}
|
||||
|
||||
pak.file.close();
|
||||
|
||||
return PFS_NO_ERROR;
|
||||
}
|
||||
|
||||
extern "C" s32 osPfsNumFiles(OSPfs* pfs, s32* max_files, s32* files_used) {
|
||||
u8 files = 0;
|
||||
for (size_t i = 0; i < MAX_FILES; i++) {
|
||||
u32 file_size = 0;
|
||||
u32 game_code = 0;
|
||||
u16 company_code = 0;
|
||||
char ext_name[EXT_NAME_SIZE] = { 0 };
|
||||
char game_name[GAME_NAME_SIZE] = { 0 };
|
||||
|
||||
Pfs_PakHeader_Read(&file_size, &game_code, &company_code, ext_name, game_name, i);
|
||||
|
||||
if ((company_code != 0) || (game_code != 0)) {
|
||||
files++;
|
||||
}
|
||||
}
|
||||
|
||||
*files_used = files;
|
||||
*max_files = MAX_FILES;
|
||||
|
||||
return PFS_NO_ERROR;
|
||||
}
|
||||
|
||||
extern "C" s32 osPfsDeleteFile(OSPfs* pfs, u16 company_code, u32 game_code, u8* game_name, u8* ext_name) {
|
||||
if (company_code == 0 || game_code == 0) {
|
||||
return PFS_ERR_INVALID;
|
||||
}
|
||||
|
||||
ControllerPak pak;
|
||||
|
||||
for (int i = 0; i < MAX_FILES; i++) {
|
||||
u32 file_size_ = 0;
|
||||
u32 game_code_ = 0;
|
||||
u16 company_code_ = 0;
|
||||
char ext_name_[4] = { 0 };
|
||||
char game_name_[16] = { 0 };
|
||||
|
||||
Pfs_PakHeader_Read(&file_size_, &game_code_, &company_code_, ext_name_, game_name_, i);
|
||||
|
||||
if ((company_code_ == 0) || (game_code_ == 0)) {
|
||||
continue;
|
||||
} else {
|
||||
if ((game_code == game_code_) && (strcmp((const char*) game_name, (const char*) game_name_) == 0) &&
|
||||
strcmp((const char*) ext_name, (const char*) ext_name_) == 0) {
|
||||
// File found
|
||||
|
||||
pak.header.open("controllerPak_header.sav", std::ios::binary | std::ios::in | std::ios::out);
|
||||
|
||||
if (!pak.header.good()) {
|
||||
assert(false);
|
||||
}
|
||||
if (!pak.header.is_open()) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
u32 seek = i * sizeof(OSPfsState);
|
||||
|
||||
// Zero out the header for this file.
|
||||
u8* zero_block = (u8*) malloc(sizeof(OSPfsState));
|
||||
for (size_t i = 0; i < sizeof(OSPfsState); i++) {
|
||||
zero_block[i] = 0;
|
||||
}
|
||||
pak.header.seekp(seek + 0x0, std::ios::beg);
|
||||
pak.header.write((char*) zero_block, sizeof(OSPfsState));
|
||||
|
||||
free(zero_block);
|
||||
|
||||
pak.header.close();
|
||||
|
||||
char filename[100];
|
||||
sprintf(filename, "controllerPak_file_%d.sav", i);
|
||||
remove(filename);
|
||||
|
||||
return PFS_NO_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// File not found
|
||||
return PFS_ERR_INVALID;
|
||||
}
|
||||
+5
-4
@@ -33,7 +33,9 @@ s8 sControllerPak2State = BAD;
|
||||
// default time trial records in little endian form
|
||||
const u8 D_800F2E60[4] = { 0xc0, 0x27, 0x09, 0x00 };
|
||||
// osPfsFindFile -> gGameName ("MARIOKART64" in nosFont)
|
||||
const u8 gGameName[] = "MARIOKART64";
|
||||
const u8 gGameName[] = {
|
||||
0x26, 0x1a, 0x2b, 0x22, 0x28, 0x24, 0x1a, 0x2b, 0x2d, 0x16, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
// ext_name param to osPfsFindFile (four total bytes, but only one is setable)
|
||||
const u8 gExtCode[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
@@ -867,9 +869,8 @@ s32 func_800B64EC(s32 arg0) {
|
||||
}
|
||||
|
||||
sPlayerGhostReplay = (u32*) &D_802BFB80.arraySize8[0][D_80162DC8][3];
|
||||
temp_v0 =
|
||||
osPfsReadWriteFile(&gControllerPak1FileHandle, gControllerPak1FileNote, PFS_READ,
|
||||
(arg0 * (sizeof(u8) * 0x1000)) + 0x100, sizeof(u8) * 0x1000, (u8*) sPlayerGhostReplay);
|
||||
temp_v0 = osPfsReadWriteFile(&gControllerPak1FileHandle, gControllerPak1FileNote, PFS_READ,
|
||||
(arg0 * (sizeof(u8) * 0x1000)) + 0x100, sizeof(u8) * 0x1000, (u8*) sPlayerGhostReplay);
|
||||
if (temp_v0 == 0) {
|
||||
// clang-format off
|
||||
phi_s1 = (u8 *) &D_8018EE10[arg0]; temp_s0 = 0; while (1) {
|
||||
|
||||
-81
@@ -63,84 +63,3 @@ void osSpTaskYield(void) {
|
||||
|
||||
OSYieldResult osSpTaskYielded(OSTask* task) {
|
||||
}
|
||||
|
||||
s32 osPfsDeleteFile(OSPfs* pfs, u16 company_code, u32 game_code, u8* game_name, u8* ext_name) {
|
||||
char filename[1024];
|
||||
sprintf(filename, "channel_%d_%hu_%hd_%s.sav", pfs->channel, company_code, game_code, game_name);
|
||||
remove(filename);
|
||||
return PFS_NO_ERROR;
|
||||
}
|
||||
|
||||
s32 osPfsReadWriteFile(OSPfs* pfs, s32 file_no, u8 flag, int offset, int size_in_bytes, u8* data_buffer) {
|
||||
if (flag == PFS_READ) {
|
||||
fseek(openFile[file_no].file, offset, SEEK_SET);
|
||||
fread(data_buffer, size_in_bytes, 1, openFile[file_no].file);
|
||||
} else {
|
||||
fseek(openFile[file_no].file, offset, SEEK_SET);
|
||||
fwrite(data_buffer, size_in_bytes, 1, openFile[file_no].file);
|
||||
}
|
||||
return PFS_NO_ERROR;
|
||||
}
|
||||
|
||||
s32 osPfsAllocateFile(OSPfs* pfs, u16 company_code, u32 game_code, u8* game_name, u8* ext_name, int file_size_in_bytes,
|
||||
s32* file_no) {
|
||||
char filename[1024];
|
||||
sprintf(filename, "channel_%d_%hu_%hd_%s.sav", pfs->channel, company_code, game_code, game_name);
|
||||
*file_no = fileIndex++;
|
||||
openFile[*file_no].file = fopen(filename, "w+");
|
||||
fwrite("\0", 1, file_size_in_bytes, openFile[*file_no].file);
|
||||
openFile[*file_no].state.company_code = company_code;
|
||||
openFile[*file_no].state.game_code = game_code;
|
||||
strcpy(openFile[*file_no].state.game_name, game_name);
|
||||
strcpy(openFile[*file_no].state.ext_name, ext_name);
|
||||
return PFS_NO_ERROR;
|
||||
}
|
||||
|
||||
s32 osPfsIsPlug(OSMesgQueue* queue, u8* pattern) {
|
||||
*pattern = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
s32 osPfsInit(OSMesgQueue* queue, OSPfs* pfs, int channel) {
|
||||
pfs->queue = queue;
|
||||
pfs->channel = channel;
|
||||
pfs->status = 0;
|
||||
pfs->status |= PFS_INITIALIZED;
|
||||
return PFS_NO_ERROR;
|
||||
}
|
||||
|
||||
s32 osPfsNumFiles(OSPfs* pfs, s32* max_files, s32* files_used) {
|
||||
*max_files = 16;
|
||||
*files_used = fileIndex;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 osPfsFileState(OSPfs* pfs, s32 file_no, OSPfsState* state) {
|
||||
}
|
||||
|
||||
s32 osPfsFreeBlocks(OSPfs* pfs, s32* bytes_not_used) {
|
||||
*bytes_not_used = 0x1000;
|
||||
return PFS_NO_ERROR;
|
||||
}
|
||||
|
||||
s32 osPfsFindFile(OSPfs* pfs, u16 company_code, u32 game_code, u8* game_name, u8* ext_name, s32* file_no) {
|
||||
char filename[1024];
|
||||
sprintf(filename, "channel_%d_%hu_%hd_%s.sav", pfs->channel, company_code, game_code, game_name);
|
||||
for (size_t i = 0; i < 16; i++) {
|
||||
if (openFile[i].state.game_code == game_code && openFile[i].state.company_code == company_code &&
|
||||
strcmp(openFile[i].state.game_name, game_name) == 0 && strcmp(openFile[i].state.ext_name, ext_name) == 0) {
|
||||
*file_no = i;
|
||||
return PFS_NO_ERROR;
|
||||
}
|
||||
}
|
||||
*file_no = fileIndex++;
|
||||
openFile[*file_no].file = fopen(filename, "r+");
|
||||
if (openFile[*file_no].file == NULL) {
|
||||
openFile[*file_no].file = fopen(filename, "w+");
|
||||
}
|
||||
openFile[*file_no].state.company_code = company_code;
|
||||
openFile[*file_no].state.game_code = game_code;
|
||||
strcpy(openFile[*file_no].state.game_name, game_name);
|
||||
strcpy(openFile[*file_no].state.ext_name, ext_name);
|
||||
return PFS_NO_ERROR;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user