mirror of
https://github.com/pret/pokefirered.git
synced 2026-04-24 14:57:07 -05:00
Sync save sector checks
This commit is contained in:
parent
40cbfc0722
commit
f16b6100c8
|
|
@ -129,6 +129,10 @@ extern u8 gStringVar4[];
|
|||
#define NUM_FLAG_BYTES ROUND_BITS_TO_BYTES(FLAGS_COUNT)
|
||||
#define NUM_ADDITIONAL_PHRASE_BYTES ROUND_BITS_TO_BYTES(NUM_ADDITIONAL_PHRASES)
|
||||
|
||||
// This produces an error at compile-time if expr is zero.
|
||||
// It looks like file.c:line: size of array `id' is negative
|
||||
#define STATIC_ASSERT(expr, id) typedef char id[(expr) ? 1 : -1];
|
||||
|
||||
struct Coords8
|
||||
{
|
||||
s8 x;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,10 @@
|
|||
#define SECTOR_FOOTER_SIZE 128
|
||||
#define SECTOR_SIZE (SECTOR_DATA_SIZE + SECTOR_FOOTER_SIZE)
|
||||
|
||||
#define FILE_SIGNATURE 0x08012025 // signature value to determine if a sector is in use
|
||||
#define NUM_SAVE_SLOTS 2
|
||||
|
||||
// If the sector's signature field is not this value then the sector is either invalid or empty.
|
||||
#define SECTOR_SIGNATURE 0x08012025
|
||||
|
||||
#define SPECIAL_SECTOR_SENTINEL 0xB39D
|
||||
|
||||
|
|
@ -26,12 +29,19 @@
|
|||
#define SECTOR_ID_TRAINER_TOWER_2 31
|
||||
#define SECTORS_COUNT 32
|
||||
|
||||
#define NUM_HOF_SECTORS 2
|
||||
|
||||
#define SAVE_STATUS_EMPTY 0
|
||||
#define SAVE_STATUS_OK 1
|
||||
#define SAVE_STATUS_INVALID 2
|
||||
#define SAVE_STATUS_NO_FLASH 4
|
||||
#define SAVE_STATUS_ERROR 0xFF
|
||||
|
||||
// Special sector id value for certain save functions
|
||||
// to indicate that all sectors should be used
|
||||
// instead of a specific sector.
|
||||
#define FULL_SAVE_SLOT 0xFFFF
|
||||
|
||||
enum
|
||||
{
|
||||
SAVE_NORMAL,
|
||||
|
|
@ -58,16 +68,11 @@ struct SaveSector
|
|||
u16 checksum;
|
||||
u32 signature;
|
||||
u32 counter;
|
||||
}; // size is 0x1000
|
||||
}; // size is SECTOR_SIZE (0x1000)
|
||||
|
||||
#define SECTOR_SIGNATURE_OFFSET offsetof(struct SaveSector, signature)
|
||||
#define SECTOR_COUNTER_OFFSET offsetof(struct SaveSector, counter)
|
||||
|
||||
// Special sector id value for certain save functions
|
||||
// to indicate that all sectors should be used
|
||||
// instead of a specific sector.
|
||||
#define FULL_SAVE_SLOT 0xFFFF
|
||||
|
||||
// operations for SetDamagedSectorBits
|
||||
enum
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,6 +4,12 @@
|
|||
#include "save.h"
|
||||
#include "cereader_tool.h"
|
||||
|
||||
#define SEC30_SIZE (offsetof(struct EReaderTrainerTowerSet, floors[4]))
|
||||
#define SEC31_SIZE (sizeof(struct EReaderTrainerTowerSet) - SEC30_SIZE)
|
||||
|
||||
// The trainer tower data exceeds SECTOR_DATA_SIZE. They're allowed to use the full save sector up to the counter field.
|
||||
STATIC_ASSERT(SEC30_SIZE + SEC31_SIZE <= SECTOR_COUNTER_OFFSET * 2, EReaderTrainerTowerSetFreeSpace);
|
||||
|
||||
u8 sub_815D654(void)
|
||||
{
|
||||
return (gSaveBlock1Ptr->trainerTower[0].unk9 + 1) % 256;
|
||||
|
|
@ -36,20 +42,17 @@ bool32 ValidateTrainerTowerData(struct EReaderTrainerTowerSet * ttdata)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
#define SEC30_SIZE (offsetof(struct EReaderTrainerTowerSet, floors[4]))
|
||||
#define SEC31_SIZE (sizeof(struct EReaderTrainerTowerSet) - SEC30_SIZE)
|
||||
|
||||
static bool32 CEReaderTool_SaveTrainerTower_r(struct EReaderTrainerTowerSet * ttdata, u8 * buffer)
|
||||
{
|
||||
AGB_ASSERT_EX(ttdata->dummy == 0, ABSPATH("cereader_tool.c"), 198);
|
||||
AGB_ASSERT_EX(ttdata->id == 0, ABSPATH("cereader_tool.c"), 199)
|
||||
|
||||
memset(buffer, 0, 0x1000);
|
||||
memset(buffer, 0, SECTOR_SIZE);
|
||||
memcpy(buffer, ttdata, SEC30_SIZE);
|
||||
buffer[1] = sub_815D654();
|
||||
if (TryWriteSpecialSaveSector(SECTOR_ID_TRAINER_TOWER_1, buffer) != TRUE)
|
||||
return FALSE;
|
||||
memset(buffer, 0, 0x1000);
|
||||
memset(buffer, 0, SECTOR_SIZE);
|
||||
memcpy(buffer, (u8 *)ttdata + SEC30_SIZE, SEC31_SIZE);
|
||||
if (TryWriteSpecialSaveSector(SECTOR_ID_TRAINER_TOWER_2, buffer) != TRUE)
|
||||
return FALSE;
|
||||
|
|
@ -58,7 +61,7 @@ static bool32 CEReaderTool_SaveTrainerTower_r(struct EReaderTrainerTowerSet * tt
|
|||
|
||||
bool32 CEReaderTool_SaveTrainerTower(struct EReaderTrainerTowerSet * ttdata)
|
||||
{
|
||||
u8 * buffer = AllocZeroed(0x1000);
|
||||
u8 * buffer = AllocZeroed(SECTOR_SIZE);
|
||||
bool32 result = CEReaderTool_SaveTrainerTower_r(ttdata, buffer);
|
||||
Free(buffer);
|
||||
return result;
|
||||
|
|
@ -81,7 +84,7 @@ static bool32 CEReaderTool_LoadTrainerTower_r(struct EReaderTrainerTowerSet * tt
|
|||
|
||||
bool32 CEReaderTool_LoadTrainerTower(struct EReaderTrainerTowerSet * ttdata)
|
||||
{
|
||||
void *buffer = AllocZeroed(0x1000);
|
||||
void *buffer = AllocZeroed(SECTOR_SIZE);
|
||||
bool32 success = CEReaderTool_LoadTrainerTower_r(ttdata, buffer);
|
||||
Free(buffer);
|
||||
return success;
|
||||
|
|
|
|||
|
|
@ -26,13 +26,16 @@
|
|||
#include "constants/songs.h"
|
||||
#include "constants/maps.h"
|
||||
|
||||
#define HALL_OF_FAME_MAX_TEAMS 50
|
||||
#define HALL_OF_FAME_BG_PAL RGB(22, 24, 29)
|
||||
|
||||
struct HallofFameMon
|
||||
{
|
||||
u32 tid;
|
||||
u32 personality;
|
||||
u16 species:9;
|
||||
u16 lvl:7;
|
||||
u8 nick[10];
|
||||
u8 nick[POKEMON_NAME_LENGTH];
|
||||
};
|
||||
|
||||
struct HallofFameTeam
|
||||
|
|
@ -40,6 +43,8 @@ struct HallofFameTeam
|
|||
struct HallofFameMon mon[PARTY_SIZE];
|
||||
};
|
||||
|
||||
STATIC_ASSERT(sizeof(struct HallofFameTeam) * HALL_OF_FAME_MAX_TEAMS <= SECTOR_DATA_SIZE * NUM_HOF_SECTORS, HallOfFameFreeSpace);
|
||||
|
||||
struct HofGfx
|
||||
{
|
||||
u16 state;
|
||||
|
|
@ -52,9 +57,6 @@ static EWRAM_DATA u32 sSelectedPaletteIndices = 0;
|
|||
static EWRAM_DATA struct HallofFameTeam * sHofMonPtr = NULL;
|
||||
static EWRAM_DATA struct HofGfx * sHofGfxPtr = NULL;
|
||||
|
||||
#define HALL_OF_FAME_MAX_TEAMS 50
|
||||
#define HALL_OF_FAME_BG_PAL (RGB(22, 24, 29))
|
||||
|
||||
static void Task_Hof_InitMonData(u8 taskId);
|
||||
static void Task_Hof_InitTeamSaveData(u8 taskId);
|
||||
static void Task_Hof_TrySaveData(u8 taskId);
|
||||
|
|
@ -425,12 +427,12 @@ static void Task_Hof_InitTeamSaveData(u8 taskId)
|
|||
SaveQuestLogData();
|
||||
if (!gHasHallOfFameRecords)
|
||||
{
|
||||
memset(gDecompressionBuffer, 0, 0x2000);
|
||||
memset(gDecompressionBuffer, 0, SECTOR_SIZE * NUM_HOF_SECTORS);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LoadGameSave(SAVE_HALL_OF_FAME) != SAVE_STATUS_OK)
|
||||
memset(gDecompressionBuffer, 0, 0x2000);
|
||||
memset(gDecompressionBuffer, 0, SECTOR_SIZE * NUM_HOF_SECTORS);
|
||||
}
|
||||
|
||||
for (i = 0; i < HALL_OF_FAME_MAX_TEAMS; i++, lastSavedTeam++)
|
||||
|
|
@ -747,7 +749,7 @@ void CB2_InitHofPC(void)
|
|||
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(16, 7));
|
||||
SetGpuReg(REG_OFFSET_BLDY, 0);
|
||||
CreateTask(Task_HofPC_CopySaveData, 0);
|
||||
sHofMonPtr = AllocZeroed(0x2000);
|
||||
sHofMonPtr = AllocZeroed(SECTOR_SIZE * NUM_HOF_SECTORS);
|
||||
SetMainCallback2(CB2_HofIdle);
|
||||
break;
|
||||
}
|
||||
|
|
@ -765,7 +767,7 @@ static void Task_HofPC_CopySaveData(u8 taskId)
|
|||
}
|
||||
else
|
||||
{
|
||||
CpuCopy16(gDecompressionBuffer, sHofMonPtr, 0x2000);
|
||||
CpuCopy16(gDecompressionBuffer, sHofMonPtr, SECTOR_SIZE * NUM_HOF_SECTORS);
|
||||
savedTeams = sHofMonPtr;
|
||||
for (i = 0; i < HALL_OF_FAME_MAX_TEAMS; i++, savedTeams++)
|
||||
{
|
||||
|
|
|
|||
62
src/save.c
62
src/save.c
|
|
@ -49,26 +49,32 @@ struct
|
|||
{
|
||||
u16 offset;
|
||||
u16 size;
|
||||
} static const sSaveSlotLayout[] =
|
||||
} static const sSaveSlotLayout[NUM_SECTORS_PER_SLOT] =
|
||||
{
|
||||
SAVEBLOCK_CHUNK(gSaveBlock2, 0), // SECTOR_ID_SAVEBLOCK2
|
||||
SAVEBLOCK_CHUNK(struct SaveBlock2, 0), // SECTOR_ID_SAVEBLOCK2
|
||||
|
||||
SAVEBLOCK_CHUNK(gSaveBlock1, 0), // SECTOR_ID_SAVEBLOCK1_START
|
||||
SAVEBLOCK_CHUNK(gSaveBlock1, 1),
|
||||
SAVEBLOCK_CHUNK(gSaveBlock1, 2),
|
||||
SAVEBLOCK_CHUNK(gSaveBlock1, 3), // SECTOR_ID_SAVEBLOCK1_END
|
||||
SAVEBLOCK_CHUNK(struct SaveBlock1, 0), // SECTOR_ID_SAVEBLOCK1_START
|
||||
SAVEBLOCK_CHUNK(struct SaveBlock1, 1),
|
||||
SAVEBLOCK_CHUNK(struct SaveBlock1, 2),
|
||||
SAVEBLOCK_CHUNK(struct SaveBlock1, 3), // SECTOR_ID_SAVEBLOCK1_END
|
||||
|
||||
SAVEBLOCK_CHUNK(gPokemonStorage, 0), // SECTOR_ID_PKMN_STORAGE_START
|
||||
SAVEBLOCK_CHUNK(gPokemonStorage, 1),
|
||||
SAVEBLOCK_CHUNK(gPokemonStorage, 2),
|
||||
SAVEBLOCK_CHUNK(gPokemonStorage, 3),
|
||||
SAVEBLOCK_CHUNK(gPokemonStorage, 4),
|
||||
SAVEBLOCK_CHUNK(gPokemonStorage, 5),
|
||||
SAVEBLOCK_CHUNK(gPokemonStorage, 6),
|
||||
SAVEBLOCK_CHUNK(gPokemonStorage, 7),
|
||||
SAVEBLOCK_CHUNK(gPokemonStorage, 8), // SECTOR_ID_PKMN_STORAGE_END
|
||||
SAVEBLOCK_CHUNK(struct PokemonStorage, 0), // SECTOR_ID_PKMN_STORAGE_START
|
||||
SAVEBLOCK_CHUNK(struct PokemonStorage, 1),
|
||||
SAVEBLOCK_CHUNK(struct PokemonStorage, 2),
|
||||
SAVEBLOCK_CHUNK(struct PokemonStorage, 3),
|
||||
SAVEBLOCK_CHUNK(struct PokemonStorage, 4),
|
||||
SAVEBLOCK_CHUNK(struct PokemonStorage, 5),
|
||||
SAVEBLOCK_CHUNK(struct PokemonStorage, 6),
|
||||
SAVEBLOCK_CHUNK(struct PokemonStorage, 7),
|
||||
SAVEBLOCK_CHUNK(struct PokemonStorage, 8), // SECTOR_ID_PKMN_STORAGE_END
|
||||
};
|
||||
|
||||
// These will produce an error if a save struct is larger than the space
|
||||
// alloted for it in the flash.
|
||||
STATIC_ASSERT(sizeof(struct SaveBlock2) <= SECTOR_DATA_SIZE, SaveBlock2FreeSpace);
|
||||
STATIC_ASSERT(sizeof(struct SaveBlock1) <= SECTOR_DATA_SIZE * (SECTOR_ID_SAVEBLOCK1_END - SECTOR_ID_SAVEBLOCK1_START + 1), SaveBlock1FreeSpace);
|
||||
STATIC_ASSERT(sizeof(struct PokemonStorage) <= SECTOR_DATA_SIZE * (SECTOR_ID_PKMN_STORAGE_END - SECTOR_ID_PKMN_STORAGE_START + 1), PokemonStorageFreeSpace);
|
||||
|
||||
// Sector num to begin writing save data. Sectors are rotated each time the game is saved. (possibly to avoid wear on flash memory?)
|
||||
u16 gLastWrittenSector;
|
||||
u32 gLastSaveCounter;
|
||||
|
|
@ -165,7 +171,7 @@ static u8 HandleWriteSector(u16 sectorId, const struct SaveSectorLocation *locat
|
|||
|
||||
sectorNum = gLastWrittenSector + sectorId;
|
||||
sectorNum %= NUM_SECTORS_PER_SLOT;
|
||||
sectorNum += NUM_SECTORS_PER_SLOT * (gSaveCounter % 2);
|
||||
sectorNum += NUM_SECTORS_PER_SLOT * (gSaveCounter % NUM_SAVE_SLOTS);
|
||||
|
||||
data = locations[sectorId].data;
|
||||
size = locations[sectorId].size;
|
||||
|
|
@ -176,7 +182,7 @@ static u8 HandleWriteSector(u16 sectorId, const struct SaveSectorLocation *locat
|
|||
|
||||
// fill buffer with save data
|
||||
gSaveDataBufferPtr->id = sectorId;
|
||||
gSaveDataBufferPtr->signature = FILE_SIGNATURE;
|
||||
gSaveDataBufferPtr->signature = SECTOR_SIGNATURE;
|
||||
gSaveDataBufferPtr->counter = gSaveCounter;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
|
|
@ -194,7 +200,7 @@ static u8 HandleWriteSectorNBytes(u8 sectorId, u8 *data, u16 size)
|
|||
for (i = 0; i < SECTOR_SIZE; i++)
|
||||
((char *)sector)[i] = 0;
|
||||
|
||||
sector->signature = FILE_SIGNATURE;
|
||||
sector->signature = SECTOR_SIGNATURE;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
sector->data[i] = data[i];
|
||||
|
|
@ -287,7 +293,7 @@ static u8 HandleReplaceSector(u16 sectorId, const struct SaveSectorLocation *loc
|
|||
|
||||
sectorNum = gLastWrittenSector + sectorId;
|
||||
sectorNum %= NUM_SECTORS_PER_SLOT;
|
||||
sectorNum += NUM_SECTORS_PER_SLOT * (gSaveCounter % 2);
|
||||
sectorNum += NUM_SECTORS_PER_SLOT * (gSaveCounter % NUM_SAVE_SLOTS);
|
||||
|
||||
data = locations[sectorId].data;
|
||||
size = locations[sectorId].size;
|
||||
|
|
@ -298,7 +304,7 @@ static u8 HandleReplaceSector(u16 sectorId, const struct SaveSectorLocation *loc
|
|||
|
||||
// fill buffer with save data
|
||||
gSaveDataBufferPtr->id = sectorId;
|
||||
gSaveDataBufferPtr->signature = FILE_SIGNATURE;
|
||||
gSaveDataBufferPtr->signature = SECTOR_SIGNATURE;
|
||||
gSaveDataBufferPtr->counter = gSaveCounter;
|
||||
for (i = 0; i < size; i++)
|
||||
gSaveDataBufferPtr->data[i] = data[i];
|
||||
|
|
@ -359,7 +365,7 @@ static u8 CopySectorSignatureByte(u16 sectorId, const struct SaveSectorLocation
|
|||
|
||||
sector = gLastWrittenSector + sectorId - 1;
|
||||
sector %= NUM_SECTORS_PER_SLOT;
|
||||
sector += NUM_SECTORS_PER_SLOT * (gSaveCounter % 2);
|
||||
sector += NUM_SECTORS_PER_SLOT * (gSaveCounter % NUM_SAVE_SLOTS);
|
||||
|
||||
if (ProgramFlashByte(sector, SECTOR_SIGNATURE_OFFSET, ((u8 *)gSaveDataBufferPtr)[SECTOR_SIGNATURE_OFFSET]))
|
||||
{
|
||||
|
|
@ -382,10 +388,10 @@ static u8 WriteSectorSignatureByte(u16 sectorId, const struct SaveSectorLocation
|
|||
|
||||
sector = gLastWrittenSector + sectorId - 1;
|
||||
sector %= NUM_SECTORS_PER_SLOT;
|
||||
sector += NUM_SECTORS_PER_SLOT * (gSaveCounter % 2);
|
||||
sector += NUM_SECTORS_PER_SLOT * (gSaveCounter % NUM_SAVE_SLOTS);
|
||||
|
||||
// write only the first byte of the signature, which was skipped in HandleReplaceSector
|
||||
if (ProgramFlashByte(sector, SECTOR_SIGNATURE_OFFSET, FILE_SIGNATURE & 0xFF))
|
||||
if (ProgramFlashByte(sector, SECTOR_SIGNATURE_OFFSET, SECTOR_SIGNATURE & 0xFF))
|
||||
{
|
||||
// sector is damaged, so enable the bit in gDamagedSaveSectors and restore the last written sector and save counter.
|
||||
SetDamagedSectorBits(ENABLE, sector);
|
||||
|
|
@ -421,7 +427,7 @@ static u8 CopySaveSlotData(u16 sectorId, const struct SaveSectorLocation *locati
|
|||
{
|
||||
u16 i;
|
||||
u16 checksum;
|
||||
u16 sector = NUM_SECTORS_PER_SLOT * (gSaveCounter % 2);
|
||||
u16 sector = NUM_SECTORS_PER_SLOT * (gSaveCounter % NUM_SAVE_SLOTS);
|
||||
u16 id;
|
||||
|
||||
for (i = 0; i < NUM_SECTORS_PER_SLOT; i++)
|
||||
|
|
@ -432,7 +438,7 @@ static u8 CopySaveSlotData(u16 sectorId, const struct SaveSectorLocation *locati
|
|||
gLastWrittenSector = i;
|
||||
|
||||
checksum = CalculateChecksum(gSaveDataBufferPtr->data, locations[id].size);
|
||||
if (gSaveDataBufferPtr->signature == FILE_SIGNATURE && gSaveDataBufferPtr->checksum == checksum)
|
||||
if (gSaveDataBufferPtr->signature == SECTOR_SIGNATURE && gSaveDataBufferPtr->checksum == checksum)
|
||||
{
|
||||
u16 j;
|
||||
for (j = 0; j < locations[id].size; j++)
|
||||
|
|
@ -461,7 +467,7 @@ static u8 GetSaveValidStatus(const struct SaveSectorLocation *locations)
|
|||
for (sector = 0; sector < NUM_SECTORS_PER_SLOT; sector++)
|
||||
{
|
||||
ReadFlashSector(sector, gSaveDataBufferPtr);
|
||||
if (gSaveDataBufferPtr->signature == FILE_SIGNATURE)
|
||||
if (gSaveDataBufferPtr->signature == SECTOR_SIGNATURE)
|
||||
{
|
||||
signatureValid = TRUE;
|
||||
checksum = CalculateChecksum(gSaveDataBufferPtr->data, locations[gSaveDataBufferPtr->id].size);
|
||||
|
|
@ -489,7 +495,7 @@ static u8 GetSaveValidStatus(const struct SaveSectorLocation *locations)
|
|||
for (sector = 0; sector < NUM_SECTORS_PER_SLOT; sector++)
|
||||
{
|
||||
ReadFlashSector(NUM_SECTORS_PER_SLOT + sector, gSaveDataBufferPtr);
|
||||
if (gSaveDataBufferPtr->signature == FILE_SIGNATURE)
|
||||
if (gSaveDataBufferPtr->signature == SECTOR_SIGNATURE)
|
||||
{
|
||||
signatureValid = TRUE;
|
||||
checksum = CalculateChecksum(gSaveDataBufferPtr->data, locations[gSaveDataBufferPtr->id].size);
|
||||
|
|
@ -567,7 +573,7 @@ static u8 TryLoadSaveSector(u8 sectorId, u8 *data, u16 size)
|
|||
struct SaveSector *sector = &gSaveDataBuffer;
|
||||
|
||||
ReadFlashSector(sectorId, sector);
|
||||
if (sector->signature == FILE_SIGNATURE)
|
||||
if (sector->signature == SECTOR_SIGNATURE)
|
||||
{
|
||||
u16 checksum = CalculateChecksum(sector->data, size);
|
||||
if (sector->id == checksum)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user