mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-09 22:56:35 +00:00
dmnt: add theoretical 'else' support to cheat engine vm conditionals
This commit is contained in:
parent
389c3b6baa
commit
4cb4707f34
3 changed files with 32 additions and 18 deletions
|
@ -59,7 +59,7 @@ Code type 0x0 allows writing a static value to a memory address.
|
|||
### Code Type 0x1: Begin Conditional Block
|
||||
Code type 0x1 performs a comparison of the contents of memory to a static value.
|
||||
|
||||
If the condition is not met, all instructions until the appropriate conditional block terminator are skipped.
|
||||
If the condition is not met, all instructions until the appropriate End or Else conditional block terminator are skipped.
|
||||
|
||||
#### Encoding
|
||||
`1TMC00AA AAAAAAAA VVVVVVVV (VVVVVVVV)`
|
||||
|
@ -83,8 +83,12 @@ If the condition is not met, all instructions until the appropriate conditional
|
|||
### Code Type 0x2: End Conditional Block
|
||||
Code type 0x2 marks the end of a conditional block (started by Code Type 0x1 or Code Type 0x8).
|
||||
|
||||
When an Else is executed, all instructions until the appropriate End conditional block terminator are skipped.
|
||||
|
||||
#### Encoding
|
||||
`20000000`
|
||||
`2X000000`
|
||||
|
||||
+ X: End type (0 = End, 1 = Else).
|
||||
|
||||
---
|
||||
|
||||
|
|
|
@ -387,8 +387,8 @@ namespace ams::dmnt::cheat::impl {
|
|||
break;
|
||||
case CheatVmOpcodeType_EndConditionalBlock:
|
||||
{
|
||||
/* 20000000 */
|
||||
/* There's actually nothing left to process here! */
|
||||
/* 2X000000 */
|
||||
opcode.end_cond.is_else = ((first_dword >> 28) & 0xF) == 1;
|
||||
}
|
||||
break;
|
||||
case CheatVmOpcodeType_ControlLoop:
|
||||
|
@ -668,7 +668,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
return valid;
|
||||
}
|
||||
|
||||
void CheatVirtualMachine::SkipConditionalBlock() {
|
||||
void CheatVirtualMachine::SkipConditionalBlock(bool is_if) {
|
||||
if (this->condition_depth > 0) {
|
||||
/* We want to continue until we're out of the current block. */
|
||||
const size_t desired_depth = this->condition_depth - 1;
|
||||
|
@ -685,15 +685,18 @@ namespace ams::dmnt::cheat::impl {
|
|||
if (skip_opcode.begin_conditional_block) {
|
||||
this->condition_depth++;
|
||||
} else if (skip_opcode.opcode == CheatVmOpcodeType_EndConditionalBlock) {
|
||||
if (!skip_opcode.end_cond.is_else) {
|
||||
this->condition_depth--;
|
||||
} else if (is_if && this->condition_depth - 1 == desired_depth) {
|
||||
/* An if will continue to an else at the same depth. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Skipping, but this->condition_depth = 0. */
|
||||
/* This is an error condition. */
|
||||
/* However, I don't actually believe it is possible for this to happen. */
|
||||
/* I guess we'll throw a fatal error here, so as to encourage me to fix the VM */
|
||||
/* in the event that someone triggers it? I don't know how you'd do that. */
|
||||
/* This could occur with a mismatched "else" opcode, for example. */
|
||||
R_ABORT_UNLESS(ResultVirtualMachineInvalidConditionDepth());
|
||||
}
|
||||
}
|
||||
|
@ -850,16 +853,21 @@ namespace ams::dmnt::cheat::impl {
|
|||
}
|
||||
/* Skip conditional block if condition not met. */
|
||||
if (!cond_met) {
|
||||
this->SkipConditionalBlock();
|
||||
this->SkipConditionalBlock(true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CheatVmOpcodeType_EndConditionalBlock:
|
||||
if (cur_opcode.end_cond.is_else) {
|
||||
/* Skip to the end of the conditional block. */
|
||||
this->SkipConditionalBlock(false);
|
||||
} else {
|
||||
/* Decrement the condition depth. */
|
||||
/* We will assume, graciously, that mismatched conditional block ends are a nop. */
|
||||
if (this->condition_depth > 0) {
|
||||
this->condition_depth--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CheatVmOpcodeType_ControlLoop:
|
||||
if (cur_opcode.ctrl_loop.start_loop) {
|
||||
|
@ -965,7 +973,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
/* Check for keypress. */
|
||||
if ((cur_opcode.begin_keypress_cond.key_mask & kHeld) != cur_opcode.begin_keypress_cond.key_mask) {
|
||||
/* Keys not pressed. Skip conditional block. */
|
||||
this->SkipConditionalBlock();
|
||||
this->SkipConditionalBlock(true);
|
||||
}
|
||||
break;
|
||||
case CheatVmOpcodeType_PerformArithmeticRegister:
|
||||
|
@ -1164,7 +1172,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
|
||||
/* Skip conditional block if condition not met. */
|
||||
if (!cond_met) {
|
||||
this->SkipConditionalBlock();
|
||||
this->SkipConditionalBlock(true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -142,7 +142,9 @@ namespace ams::dmnt::cheat::impl {
|
|||
VmInt value;
|
||||
};
|
||||
|
||||
struct EndConditionalOpcode {};
|
||||
struct EndConditionalOpcode {
|
||||
bool is_else;
|
||||
};
|
||||
|
||||
struct ControlLoopOpcode {
|
||||
bool start_loop;
|
||||
|
@ -286,7 +288,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
size_t loop_tops[NumRegisters] = {0};
|
||||
private:
|
||||
bool DecodeNextOpcode(CheatVmOpcode *out);
|
||||
void SkipConditionalBlock();
|
||||
void SkipConditionalBlock(bool is_if);
|
||||
void ResetState();
|
||||
|
||||
/* For implementing the DebugLog opcode. */
|
||||
|
|
Loading…
Reference in a new issue