cheats: don't update the cheat list when adding one fails

The operation should fail or succeed completely.
Issue #871
This commit is contained in:
Flyinghead 2023-01-15 11:16:40 +01:00
parent 13428ba696
commit 8aadf5b097
1 changed files with 182 additions and 176 deletions

View File

@ -623,200 +623,206 @@ void CheatManager::addGameSharkCheat(const std::string& name, const std::string&
Cheat conditionCheat; Cheat conditionCheat;
unsigned conditionLimit = 0; unsigned conditionLimit = 0;
for (unsigned i = 0; i < codes.size(); i++) const size_t prevSize = cheats.size();
{ try {
if (i < conditionLimit) for (unsigned i = 0; i < codes.size(); i++)
cheats.push_back(conditionCheat);
Cheat cheat{};
cheat.description = name;
u32 code = (codes[i] & 0xff000000) >> 24;
switch (code)
{ {
case 0: if (i < conditionLimit)
case 1: cheats.push_back(conditionCheat);
case 2: Cheat cheat{};
cheat.description = name;
u32 code = (codes[i] & 0xff000000) >> 24;
switch (code)
{ {
// 8/16/32-bit write case 0:
if (i + 1 >= codes.size()) case 1:
throw FlycastException("Missing value"); case 2:
cheat.type = Cheat::Type::setValue;
cheat.size = code == 0 ? 8 : code == 1 ? 16 : 32;
cheat.address = codes[i] & 0x00ffffff;
cheat.value = codes[++i];
cheats.push_back(cheat);
}
break;
case 3:
{
u32 subcode = (codes[i] & 0x00ff0000) >> 16;
switch (subcode)
{ {
case 0: // 8/16/32-bit write
if (i + 1 >= codes.size())
throw FlycastException("Missing value");
cheat.type = Cheat::Type::setValue;
cheat.size = code == 0 ? 8 : code == 1 ? 16 : 32;
cheat.address = codes[i] & 0x00ffffff;
cheat.value = codes[++i];
cheats.push_back(cheat);
}
break;
case 3:
{
u32 subcode = (codes[i] & 0x00ff0000) >> 16;
switch (subcode)
{ {
// Group write case 0:
int count = codes[i] & 0xffff;
if (i + count + 1 >= codes.size())
throw FlycastException("Missing values");
cheat.type = Cheat::Type::setValue;
cheat.size = 32;
cheat.address = codes[++i] & 0x00ffffff;
for (int j = 0; j < count; j++)
{ {
if (j == 1) // Group write
cheat.description += " (cont'd)"; int count = codes[i] & 0xffff;
if (i + count + 1 >= codes.size())
throw FlycastException("Missing values");
cheat.type = Cheat::Type::setValue;
cheat.size = 32;
cheat.address = codes[++i] & 0x00ffffff;
for (int j = 0; j < count; j++)
{
if (j == 1)
cheat.description += " (cont'd)";
cheat.value = codes[++i];
cheats.push_back(cheat);
cheat.address += 4;
if (j < count - 1 && i < conditionLimit)
cheats.push_back(conditionCheat);
}
}
break;
case 1:
case 2:
{
// 8-bit inc/decrement
if (i + 1 >= codes.size())
throw FlycastException("Missing value");
cheat.type = subcode == 1 ? Cheat::Type::increase : Cheat::Type::decrease;
cheat.size = 8;
cheat.value = codes[i] & 0xff;
cheat.address = codes[++i] & 0x00ffffff;
cheats.push_back(cheat);
}
break;
case 3:
case 4:
{
// 16-bit inc/decrement
if (i + 1 >= codes.size())
throw FlycastException("Missing value");
cheat.type = subcode == 3 ? Cheat::Type::increase : Cheat::Type::decrease;
cheat.size = 16;
cheat.value = codes[i] & 0xffff;
cheat.address = codes[++i] & 0x00ffffff;
cheats.push_back(cheat);
}
break;
case 5:
case 6:
{
// 32-bit inc/decrement
if (i + 2 >= codes.size())
throw FlycastException("Missing address or value");
cheat.type = subcode == 5 ? Cheat::Type::increase : Cheat::Type::decrease;
cheat.size = 32;
cheat.address = codes[++i] & 0x00ffffff;
cheat.value = codes[++i]; cheat.value = codes[++i];
cheats.push_back(cheat); cheats.push_back(cheat);
cheat.address += 4;
if (j < count - 1 && i < conditionLimit)
cheats.push_back(conditionCheat);
} }
break;
default:
throw FlycastException("Unsupported cheat type");
} }
break;
case 1:
case 2:
{
// 8-bit inc/decrement
if (i + 1 >= codes.size())
throw FlycastException("Missing value");
cheat.type = subcode == 1 ? Cheat::Type::increase : Cheat::Type::decrease;
cheat.size = 8;
cheat.value = codes[i] & 0xff;
cheat.address = codes[++i] & 0x00ffffff;
cheats.push_back(cheat);
}
break;
case 3:
case 4:
{
// 16-bit inc/decrement
if (i + 1 >= codes.size())
throw FlycastException("Missing value");
cheat.type = subcode == 3 ? Cheat::Type::increase : Cheat::Type::decrease;
cheat.size = 16;
cheat.value = codes[i] & 0xffff;
cheat.address = codes[++i] & 0x00ffffff;
cheats.push_back(cheat);
}
break;
case 5:
case 6:
{
// 32-bit inc/decrement
if (i + 2 >= codes.size())
throw FlycastException("Missing address or value");
cheat.type = subcode == 5 ? Cheat::Type::increase : Cheat::Type::decrease;
cheat.size = 32;
cheat.address = codes[++i] & 0x00ffffff;
cheat.value = codes[++i];
cheats.push_back(cheat);
}
break;
default:
throw FlycastException("Unsupported cheat type");
} }
} break;
break; case 4:
case 4:
{
// 32-bit repeat write
if (i + 2 >= codes.size())
throw FlycastException("Missing count or value");
cheat.type = Cheat::Type::setValue;
cheat.size = 32;
cheat.address = codes[i] & 0x00ffffff;
cheat.repeatCount = codes[++i] >> 16;
cheat.repeatAddressIncrement = codes[i] & 0xffff;
cheat.value = codes[++i];
cheats.push_back(cheat);
}
break;
case 5:
{
// copy bytes
if (i + 2 >= codes.size())
throw FlycastException("Missing count or destination address");
cheat.type = Cheat::Type::copy;
cheat.size = 8;
cheat.address = codes[i] & 0x00ffffff;
cheat.destAddress = codes[++i] & 0x00ffffff;
cheat.repeatCount = codes[++i];
cheats.push_back(cheat);
}
break;
// TODO 7 change decryption type
// TODO 0xb delay applying codes
// TODO 0xc global enable test
case 0xd:
{
// enable next code if eq/neq/lt/gt
if (i + 1 >= codes.size())
throw FlycastException("Missing count or destination address");
cheat.size = 16;
cheat.address = codes[i] & 0x00ffffff;
switch (codes[++i] >> 16)
{ {
case 0: // 32-bit repeat write
cheat.type = Cheat::Type::runNextIfEq; if (i + 2 >= codes.size())
break; throw FlycastException("Missing count or value");
case 1: cheat.type = Cheat::Type::setValue;
cheat.type = Cheat::Type::runNextIfNeq; cheat.size = 32;
break; cheat.address = codes[i] & 0x00ffffff;
case 2: cheat.repeatCount = codes[++i] >> 16;
cheat.type = Cheat::Type::runNextIfLt; cheat.repeatAddressIncrement = codes[i] & 0xffff;
break; cheat.value = codes[++i];
case 3: cheats.push_back(cheat);
cheat.type = Cheat::Type::runNextIfGt;
break;
default:
throw FlycastException("Unsupported conditional code");
} }
cheat.value = codes[i] & 0xffff; break;
cheats.push_back(cheat); case 5:
}
break;
case 0xe:
{
// multiline enable codes if eq/neq/lt/gt
if (i + 1 >= codes.size())
throw FlycastException("Missing test address");
cheat.size = 16;
cheat.value = codes[i] & 0xffff;
conditionLimit = i + 1 + ((codes[i] >> 16) & 0xff);
switch (codes[++i] >> 24)
{ {
case 0: // copy bytes
cheat.type = Cheat::Type::runNextIfEq; if (i + 2 >= codes.size())
break; throw FlycastException("Missing count or destination address");
case 1: cheat.type = Cheat::Type::copy;
cheat.type = Cheat::Type::runNextIfNeq; cheat.size = 8;
break; cheat.address = codes[i] & 0x00ffffff;
case 2: cheat.destAddress = codes[++i] & 0x00ffffff;
cheat.type = Cheat::Type::runNextIfLt; cheat.repeatCount = codes[++i];
break; cheats.push_back(cheat);
case 3:
cheat.type = Cheat::Type::runNextIfGt;
break;
default:
throw FlycastException("Unsupported conditional code");
} }
cheat.address = codes[i] & 0x00ffffff; break;
conditionCheat = cheat; // TODO 7 change decryption type
// TODO 0xb delay applying codes
// TODO 0xc global enable test
case 0xd:
{
// enable next code if eq/neq/lt/gt
if (i + 1 >= codes.size())
throw FlycastException("Missing count or destination address");
cheat.size = 16;
cheat.address = codes[i] & 0x00ffffff;
switch (codes[++i] >> 16)
{
case 0:
cheat.type = Cheat::Type::runNextIfEq;
break;
case 1:
cheat.type = Cheat::Type::runNextIfNeq;
break;
case 2:
cheat.type = Cheat::Type::runNextIfLt;
break;
case 3:
cheat.type = Cheat::Type::runNextIfGt;
break;
default:
throw FlycastException("Unsupported conditional code");
}
cheat.value = codes[i] & 0xffff;
cheats.push_back(cheat);
}
break;
case 0xe:
{
// multiline enable codes if eq/neq/lt/gt
if (i + 1 >= codes.size())
throw FlycastException("Missing test address");
cheat.size = 16;
cheat.value = codes[i] & 0xffff;
conditionLimit = i + 1 + ((codes[i] >> 16) & 0xff);
switch (codes[++i] >> 24)
{
case 0:
cheat.type = Cheat::Type::runNextIfEq;
break;
case 1:
cheat.type = Cheat::Type::runNextIfNeq;
break;
case 2:
cheat.type = Cheat::Type::runNextIfLt;
break;
case 3:
cheat.type = Cheat::Type::runNextIfGt;
break;
default:
throw FlycastException("Unsupported conditional code");
}
cheat.address = codes[i] & 0x00ffffff;
conditionCheat = cheat;
}
break;
default:
throw FlycastException("Unsupported cheat type");
} }
break;
default:
throw FlycastException("Unsupported cheat type");
} }
}
setActive(!cheats.empty());
#ifndef LIBRETRO #ifndef LIBRETRO
std::string path = cfgLoadStr("cheats", gameId, ""); std::string path = cfgLoadStr("cheats", gameId, "");
if (path == "") if (path == "")
{ {
path = get_game_save_prefix() + ".cht"; path = get_game_save_prefix() + ".cht";
cfgSaveStr("cheats", gameId, path); cfgSaveStr("cheats", gameId, path);
} }
saveCheatFile(path); saveCheatFile(path);
#endif #endif
setActive(!cheats.empty());
} catch (...) {
cheats.erase(cheats.begin() + prevSize, cheats.end());
throw;
}
} }
void CheatManager::saveCheatFile(const std::string& filename) void CheatManager::saveCheatFile(const std::string& filename)