diff --git a/Source/Core/Core/Core.vcproj b/Source/Core/Core/Core.vcproj index c932f669c9..164cac1ec5 100644 --- a/Source/Core/Core/Core.vcproj +++ b/Source/Core/Core/Core.vcproj @@ -1359,6 +1359,26 @@ > + + + + + + + + + + diff --git a/Source/Core/Core/Src/GeckoCode.cpp b/Source/Core/Core/Src/GeckoCode.cpp new file mode 100644 index 0000000000..f265331db2 --- /dev/null +++ b/Source/Core/Core/Src/GeckoCode.cpp @@ -0,0 +1,852 @@ + +#include "GeckoCode.h" + +#include "Thread.h" +#include "HW/Memmap.h" + +#include "vector" + +namespace Gecko +{ + +enum +{ + // Code Types + CODETYPE_WRITE_FILL = 0x0, + CODETYPE_IF = 0x1, + CODETYPE_BA_PO_OPS = 0x2, + CODETYPE_FLOW_CONTROL = 0x3, + CODETYPE_REGISTER_OPS = 0x4, + CODETYPE_SPECIAL_IF = 0x5, + CODETYPE_ASM_SWITCH_RANGE = 0x6, + CODETYPE_END_CODES = 0x7, + + // Data Types + DATATYPE_8BIT = 0x0, + DATATYPE_16BIT = 0x1, + DATATYPE_32BIT = 0x2, +}; + +// globals +static u32 base_address = 0; +static u32 pointer_address = 0; +static u32 gecko_register[0x10] = {0}; +static struct +{ + u32 address; + u32 number; +} block[0x10]; + +// codes execute when counter is 0 +static int code_execution_counter = 0; + +// the currently active codes +std::vector active_codes; + +// return true if code execution is on +inline bool CodeExecution() +{ + return (0 == code_execution_counter); +} + +u32 GeckoCode::Code::GetAddress() const +{ + return gcaddress + (use_po ? pointer_address : (base_address & 0xFE000000)); +} + +static Common::CriticalSection active_codes_lock; + +// currently running code +static GeckoCode::Code current_code; + +// Functions for each code type +bool RamWriteAndFill(); +bool RegularIf(); +bool BaPoOps(); +bool FlowControl(); +bool RegisterOps(); +bool SpecialIf(); +bool AsmSwitchRange(); +bool EndCodes(); + +bool MathOperation(u32& ret, const u32 left, const u32 right, const u8 type); + +void SetActiveCodes(const std::vector& gcodes) +{ + active_codes_lock.Enter(); + + active_codes.clear(); + // add enabled codes + std::vector::const_iterator + gcodes_iter = gcodes.begin(), + gcodes_end = gcodes.end(); + for (; gcodes_iter!=gcodes_end; ++gcodes_iter) + if (gcodes_iter->enabled) + { + // TODO: apply modifiers + // TODO: don't need description or creator string, just takin up memory + active_codes.push_back(*gcodes_iter); + } + + active_codes_lock.Leave(); +} + +bool RunGeckoCode(const GeckoCode& gecko_code) +{ + static bool (*code_type_funcs[])(void) = + { RamWriteAndFill, RegularIf, BaPoOps, FlowControl, RegisterOps, SpecialIf, AsmSwitchRange, EndCodes }; + + base_address = 0x80000000; + pointer_address = 0x80000000; + code_execution_counter = 0; + + std::vector::const_iterator + codes_iter = gecko_code.codes.begin(), + codes_end = gecko_code.codes.end(); + for (; codes_iter != codes_end; ++codes_iter) + { + const GeckoCode::Code& code = *codes_iter; + + current_code = code; + + bool result = true; + + switch (code.type) + { + // These codetypes run even if code_execution is off + case CODETYPE_IF : + case CODETYPE_FLOW_CONTROL : + case CODETYPE_SPECIAL_IF : + case CODETYPE_ASM_SWITCH_RANGE : + case CODETYPE_END_CODES : + result = code_type_funcs[code.type](); + break; + + // The rest of the codetypes only run if code_execution is on + default : + if (CodeExecution()) + result = code_type_funcs[code.type](); + break; + } + + // code failed + if (false == result) + { + PanicAlert("GeckoCode failed to run (CT%i CST%i) (%s)" + "(Either a bad code or the code type is not yet supported.)" + , code.type, code.subtype, gecko_code.name.c_str()); + return false; + } + + + + } + + + return true; +} + +bool RunActiveCodes() +{ + if (false == active_codes_lock.TryEnter()) + return true; + + std::vector::const_iterator + gcodes_iter = active_codes.begin(), + gcodes_end = active_codes.end(); + for (; gcodes_iter!=gcodes_end; ++gcodes_iter) + { + RunGeckoCode(*gcodes_iter); + // we don't need to stop all codes if one fails, maybe + //if (false == RunGeckoCode(*gcodes_iter)) + //return false; + } + + active_codes_lock.Leave(); + return true; +} + +// CT0: Direct ram write/fill +// NOT COMPLETE, last 2 subtypes not started +bool RamWriteAndFill() +{ + const GeckoCode::Code& code = current_code; + u32 new_addr = code.GetAddress(); + const u32& data = code.data; + + u16 count = (data >> 16) + 1; + + switch (code.subtype) + { + // CST0: 8bits Write & Fill + case 0x0 : + while (count--) + { + Memory::Write_U16((u16)data, new_addr); + ++new_addr; + } + break; + + // CST1: 16bits Write & Fill + case 0x1 : + while (count--) + { + Memory::Write_U16((u16)data, new_addr); + new_addr += 2; + } + break; + + // CST2: 32bits Write + case 0x2 : + Memory::Write_U32((u32)data, new_addr); + break; + + // CST3: String Code + case 0x3 : + // TODO: + return false; + break; + + // CST4: Serial Code + case 0x4 : + { + // TODO: complete + u32 new_data = data; + + + return false; + } + break; + + // INVALID SUBTYPE + default : + return false; + break; + } + + return true; +} + +// CT1 Regular If codes (16/32 bits) +// COMPLETE +bool RegularIf() +{ + const GeckoCode::Code& code = current_code; + + const bool is_endif = !!(code.address & 0x1); + + // if code_execution is off and this is an endif, decrease the execution counter + if (false == CodeExecution()) + { + if (is_endif) + --code_execution_counter; + } + + bool result = false; + + // if code_execution is on, execute the conditional + if (CodeExecution()) + { + const u32 new_addr = code.GetAddress() & ~0x1; + const u32& data = code.data; + + s32 read_value = 0; + s32 data_value = 0; + + // 16bit vs 32bit + if (code.subtype & 0x4) + { + // 16bits + read_value = Memory::Read_U16(new_addr) & ~(data >> 16); + data_value = (data & 0xFFFF); + } + else + { + // 32bits + read_value = Memory::Read_U32(new_addr); + data_value = data; + } + + switch (code.subtype & 0x3) + { + // CST0 : 32bits (endif, then) If equal + // CST4 : 16bits (endif, then) If equal + case 0x0 : + result = (read_value == data_value); + break; + + // CST1 : 32bits (endif, then) If not equal + // CST5 : 16bits (endif, then) If not equal + case 0x1 : + result = (read_value != data_value); + break; + + // CST2 : 32bits (endif, then) If greater + // CST6 : 16bits (endif, then) If greater + case 0x2 : + result = (read_value > data_value); + break; + + // CST3 : 32bits (endif, then) If lower + // CST7 : 16bits (endif, then) If lower + case 0x3 : + result = (read_value < data_value); + break; + } + } + + // if the conditional returned false, or it never ran because execution is off, + // increase the code execution counter + if (false == result) + ++code_execution_counter; + + return true; +} + +// CT2 Base Address/Pointer Operations +// NOT COMPLETE, last 2 subtypes aren't done +bool BaPoOps() +{ + const GeckoCode::Code& code = current_code; + + // base_address vs pointer (ba vs po) + u32& change_address = (code.subtype & 0x4) ? pointer_address : base_address; + + // 4STYZ00N XXXXXXXX + u32 new_data = code.data; + + // append grN + if (code.z) + new_data += gecko_register[code.n]; + + // append ba or po (depending on last nibble's first bit) + if (code.y) + new_data += (code.use_po ? pointer_address : base_address); + + // append to current value (not used in all subtypes, T will be 0 in those) + if (code.t) + new_data += change_address; + + switch (code.subtype & 0x3) + { + // CST0 : Load into Base Address + // CST4 : Load into Pointer + case 0x0 : + change_address = Memory::Read_U32(new_data); + break; + + // CST1 : Set Base Address to + // CST5 : Set Pointer to + case 0x1 : + change_address = new_data; + break; + + // CST2 : Save Base Address to + // CST6 : Save Pointer to + case 0x2 : + Memory::Write_U32(change_address, new_data); + break; + + // CST3 : Put next line of code location into the Base Address + // CST7 : Put grN's location into the Pointer + + // conflicting documentation, one doc says CST7 is the same as CST3 but with po + case 0x3 : + // TODO: + return false; // + break; + } + + return true; +} + +// CT3 Repeat/Goto/Gosub/Return +// NOT COMPLETE +bool FlowControl() +{ + const GeckoCode::Code& code = current_code; + + // only the return subtype runs when code execution is off + if (false == CodeExecution() && code.subtype != 0x2) + return true; + + // not all of these are used in all subtypes + const u8 block_num = (u8)(code.data & 0xF); + const s16 code_offset = (s16)code.address; + + switch (code.subtype) + { + // CST0 : Set Repeat + case 0x0 : + // TODO: store address of next code as well + block[block_num].address = code.address & 0xFFFF; + // block[block_num].number = ; + return false; // + break; + + // CST1 : Execute Repeat + case 0x1 : + if (block[block_num].number) + { + --block[block_num].number; + // TODO: jump to code block + } + return false; // + break; + + // CST2 : Return + case 0x2 : + if (((code.address >> 20) & 0xF) ^ (u32)CodeExecution()) + // TODO: jump to block[block_num].number + return false; // + break; + + // CST3 : Goto + case 0x3 : + // TODO: + return false; // + break; + + // CST4 : Gosub + case 0x4 : + // TODO: + return false; // + break; + + // INVALID SUBTYPE + default : + return false; + break; + } + + return true; +} + +// CT4 Gecko Register Operations +// NOT COMPLETE, need to do memory copy 1,2 +bool RegisterOps() +{ + const GeckoCode::Code& code = current_code; + + // 80TYZZZN XXXXXXXX + + u32 new_data = code.data; + + // append ba or po (depending on last nibble's first bit) + if (code.y) + new_data += (code.use_po ? pointer_address : base_address); + + u32& geckreg = gecko_register[code.n]; + + switch (code.subtype) + { + // CST0 : Set Gecko Register to + case 0x0 : + // append to or set register + geckreg = new_data + (code.t ? geckreg : 0); + break; + + // CST1 : Load into Gecko Register + case 0x1 : + switch (code.t) + { + // 8bit + case DATATYPE_8BIT : + geckreg = Memory::Read_U8(new_data); + break; + + // 16bit + case DATATYPE_16BIT : + geckreg = Memory::Read_U16(new_data); + break; + + // 32bit + case DATATYPE_32BIT : + geckreg = Memory::Read_U32(new_data); + break; + + // INVALID DATATYPE + default : + return false; + break; + } + break; + + // CST2 : Save Gecko Register to + case 0x2 : + switch (code.t) + { + // 8bit + case DATATYPE_8BIT : + for (u16 i = 0; i <= code.z; ++i) + Memory::Write_U8((u8)geckreg, new_data + i); + break; + + // 16bit + case DATATYPE_16BIT : + for (u16 i = 0; i <= code.z; ++i) + Memory::Write_U16((u16)geckreg, new_data + (i << 1)); + break; + + // 32bit + case DATATYPE_32BIT : + for (u16 i = 0; i <= code.z; ++i) + Memory::Write_U32((u32)geckreg, new_data + (i << 2)); + break; + + // INVALID DATATYPE + default : + return false; + break; + } + break; + + // CST3 : Gecko Register / Direct Value operations + // CST4 : Gecko Registers operations + case 0x3 : + case 0x4 : + { + // subtype 3 uses value in .data subtype 4 uses register + u32 right_val = (code.subtype & 0x1 ? code.data : gecko_register[code.data & 0xF]); + if (code.y & 0x2) + right_val = Memory::Read_U32(right_val); + + u32 left_val = geckreg; + if (code.y & 0x1) + left_val = Memory::Read_U32(left_val); + + if (false == MathOperation(geckreg, left_val, right_val, code.t)) + return false; + } + break; + + // CST5 : Memory Copy 1 + case 0x5 : + // TODO: + return false; // + break; + + // CST6 : Memory Copy 2 + case 0x6 : + // TODO: + return false; // + break; + + // INVALID SUBTYPE + default : + return false; + break; + + } + + return true; +} + +// NOT COMPLETE, at least one op needs to be coded/fixed +bool MathOperation(u32& ret, const u32 left, const u32 right, const u8 type) +{ + // ? = T : + switch (type) + { + // 0 : add (+) + case 0x0 : + ret = left + right; + break; + + // 1 : mul (*) + case 0x1 : + ret = left * right; + break; + + // 2 : or (|) + case 0x2 : + ret = left | right; + break; + + // 3 : and (&) + case 0x3 : + ret = left & right; + break; + + // 4 : xor (^) + case 0x4 : + ret = left ^ right; + break; + + // 5 : slw (<<) + case 0x5 : + ret = left << right; + break; + + // 6 : srw (>>) + case 0x6 : + ret = left >> right; + break; + + // TODO: this one good? + // 7 : rol (rotate left) + case 0x7 : + ret = (left << right) | (left >> (8 - right)); + break; + + // 8 : asr (arithmetic shift right) + case 0x8 : + // TODO: wuts this + return false; + break; + + // TODO: these float ops good? + // A : fadds (single float add) + case 0xA : + *(float*)&ret = *(float*)&left + *(float*)&right; + break; + + // B : fmuls (single float mul) + case 0xB : + *(float*)&ret = *(float*)&left * *(float*)&right; + break; + + // INVALID OPERATION TYPE + default : + return false; + break; + } + + return true; +} + +// CT5: Special If codes (16bits) +// NOT COMPLETE, part 2 (counter stuff) not started +bool SpecialIf() +{ + const GeckoCode::Code& code = current_code; + + const bool is_endif = !!(code.address & 0x1); + + // if code_execution is off and this is an endif, decrease the execution counter + if (false == CodeExecution()) + { + if (is_endif) + --code_execution_counter; + } + + bool result = false; + + // if code_execution is on, execute the conditional + if (CodeExecution()) + { + const u32 addr = code.GetAddress() & ~0x1; + const u32& data = code.data; + + // A-______ NM00YYYY + + if (code.subtype ^ 0x4) + { + // CT5 Part1 : Unknown values comparison + + const u8 n = (u8)(data >> 28); + const u8 m = (u8)((data >> 24) & 0xF); + const u16 y = (u16)data; + + // TODO: should these be signed? probably? + const s16 left_val = Memory::Read_U16(((0xF == n) ? addr : gecko_register[n]) & ~y); + const s16 right_val = Memory::Read_U16(((0xF == m) ? addr : gecko_register[m]) & ~y); + + switch (code.subtype) + { + // CST0 : 16bits (endif, then) If equal + case 0x0 : + result = (left_val == right_val); + break; + + // CST1 : 16bits (endif, then) If not equal + case 0x1 : + result = (left_val != right_val); + break; + + // CST2 : 16bits (endif, then) If greater + case 0x2 : + result = (left_val > right_val); + break; + + // CST3 : 16bits (endif, then) If lower + case 0x3 : + result = (left_val < right_val); + break; + } + } + else + { + // CT5 Part2 : 16bits Counter check + // TODO: + + const u16 z = (u16)(data >> 16); + + switch (code.subtype) + { + // CST4 : 16bits (endif, then) If counter value equal + case 0x4 : + // TODO: + return false; // + break; + + // CST5 : 16bits (endif, then) If counter value not equal + case 0x5 : + // TODO: + return false; // + break; + + // CST6 : 16bits (endif, then) If counter value greater + case 0x6 : + // TODO: + return false; // + break; + + // CST7 : 16bits (endif, then) If counter value lower + case 0x7 : + // TODO: + return false; // + break; + } + } + } + + // if the conditional returned false, or it never ran because execution is off, increase the code execution counter + if (false == result) + ++code_execution_counter; + + return true; +} + +// CT6 ASM Codes, On/Off switch and Address Range Check +// NOT COMPLETE, hardly started +// fix the logic flow in this one +bool AsmSwitchRange() +{ + const GeckoCode::Code& code = current_code; + + // only used for the last 2 subtypes + const bool is_endif = !!(code.address & 0x1); + + // only run if code_execution is set or this code is a switch or rangecheck subtype + // the switch and rangecheck run if exectution_counter is 1 (directly inside the failed if) if they are an endif + if (false == CodeExecution()) + { + if (code.subtype < 0x6) + return true; + else if (false == (1 == code_execution_counter && is_endif)) + return true; + } + + const u32& data = code.data; + + switch (code.subtype) + { + // CST0 : Execute following ASM Code + case 0x0 : + // TODO: + return false; // + break; + + // CST1 : Insert ASM code in the game + case 0x1 : + // TODO: + return false; + break; + + // CST3 : Create a branch + case 0x3 : + // TODO: + return false; // + break; + + // CST6 : On/Off switch + case 0x6 : + // TODO: + return false; // + break; + + // CST7 : Address range check (If... code) + case 0x7 : + if (code_execution_counter) + { + const u32 addr = (code.use_po ? pointer_address : base_address); + if (addr >= (data & 0xFFFF0000) && addr <= (data << 16)) + --code_execution_counter; + } + break; + + // INVALID SUBTYPE + default : + return false; + break; + } + + return true; +} + +// CT7 End of codes, Endif (Else) +// COMPLETE, maybe +bool EndCodes() +{ + const GeckoCode::Code& code = current_code; + const u32& data = code.data; + + const u32 x = (data & 0xFFFF0000); + const u32 y = (data << 16); + + // these 2 do not happen in the "CST7 : End of Code", but in that subtype they will be 0 + if (x) + base_address = x; + if (y) + pointer_address = y; + + switch (code.subtype) + { + // CST0 : Full Terminator + case 0x0 : + // clears the code execution status + // TODO: should this always stop all codes, even if execution is off? + if (CodeExecution()) + code_execution_counter = -1; // silly maybe + break; + + // CST1 : Endif (+else) + case 0x1 : + { + // apply endifs + const u8 v = (u8)code.address; + if (code_execution_counter >= v) + code_execution_counter -= v; + else + { + // too many endifs + return false; + } + + const bool is_else = !!(code.address & 0x00100000); + // apply else + if (is_else) + if (code_execution_counter <= 1) + code_execution_counter ^= 1; + } + break; + + // CST7 : End of Code + case 0x7 : + // tell the code handler that there are no more codes in the code list + // TODO: should this always stop all codes, even if execution is off? + if (CodeExecution()) + code_execution_counter = -1; // silly maybe + break; + + // INVALID SUBTYPE + default : + return false; + break; + } + + return true; +} + +} // namespace Gecko \ No newline at end of file diff --git a/Source/Core/Core/Src/GeckoCode.h b/Source/Core/Core/Src/GeckoCode.h new file mode 100644 index 0000000000..305560318b --- /dev/null +++ b/Source/Core/Core/Src/GeckoCode.h @@ -0,0 +1,66 @@ + +#ifndef __GECKOCODE_h__ +#define __GECKOCODE_h__ + +#include "Common.h" + +#include + +namespace Gecko +{ + + class GeckoCode + { + public: + + GeckoCode() : enabled(false) {} + + struct Code + { + union + { + u32 address; + + struct + { + u32 gcaddress : 25; + u32 subtype: 3; + u32 use_po : 1; + u32 type: 3; + }; + + struct + { + u32 n : 4; + u32 z : 12; + u32 y : 4; + u32 t : 4; + //u32 s : 4; + //u32 : 4; + };// subsubtype; + }; + + union + { + u32 data; + //struct + //{ + // + //}; + }; + + u32 GetAddress() const; + }; + + std::vector codes; + std::string name, description, creator; + + bool enabled; + }; + + void SetActiveCodes(const std::vector& gcodes); + bool RunActiveCodes(); + +} // namespace Gecko + +#endif \ No newline at end of file diff --git a/Source/Core/Core/Src/GeckoCodeConfig.cpp b/Source/Core/Core/Src/GeckoCodeConfig.cpp new file mode 100644 index 0000000000..a9c0822eac --- /dev/null +++ b/Source/Core/Core/Src/GeckoCodeConfig.cpp @@ -0,0 +1,141 @@ + +#include "GeckoCodeConfig.h" + +#include "StringUtil.h" + +#include +#include +#include + +#define GECKO_CODE_INI_SECTION "Gecko" + +namespace Gecko +{ + +void LoadCodes(const IniFile& inifile, std::vector& gcodes) +{ + std::vector lines; + inifile.GetLines(GECKO_CODE_INI_SECTION, lines); + + GeckoCode gcode; + + std::vector::const_iterator + lines_iter = lines.begin(), + lines_end = lines.end(); + for (; lines_iter!=lines_end; ++lines_iter) + { + if (lines_iter->empty()) + continue; + + std::istringstream ss(*lines_iter); + + switch ((*lines_iter)[0]) + { + + // enabled or disabled code + case '+' : + ss.seekg(1); + case '$' : + if (gcode.name.size()) + gcodes.push_back(gcode); + gcode = GeckoCode(); + gcode.enabled = (1 == ss.tellg()); // silly + ss.seekg(1, std::ios_base::cur); + // read the code name + std::getline(ss, gcode.name, '['); // stop at [ character (begining of contributer name) + gcode.name = StripSpaces(gcode.name); + // read the code creator name + std::getline(ss, gcode.creator, ']'); + break; + + // description + case '*': + ss.seekg(1); + std::getline(ss, gcode.description); + break; + + // start of code option list + case ':': + // TODO: + break; + + // either part of the code, or an option choice + default : + // TODO: check if we are reading an option list + { + GeckoCode::Code new_code; + // TODO: support options + ss >> std::hex >> new_code.address >> new_code.data; + gcode.codes.push_back(new_code); + } + break; + + } + + } + + // add the last code + if (gcode.name.size()) + gcodes.push_back(gcode); +} + +// used by the SaveGeckoCodes function +void SaveGeckoCode(std::vector& lines, const GeckoCode& gcode) +{ + std::string name; + + if (gcode.enabled) + name += '+'; + + // save the name + name += '$'; + name += gcode.name; + + // save the creator name + if (gcode.creator.size()) + { + name += " ["; + name += gcode.creator; + name += ']'; + } + + lines.push_back(name); + + // save the description + if (gcode.description.size()) + lines.push_back(std::string("*") + gcode.description); + + // save all the code lines + std::vector::const_iterator + codes_iter = gcode.codes.begin(), + codes_end = gcode.codes.end(); + for (; codes_iter!=codes_end; ++codes_iter) + { + //ss << std::hex << codes_iter->address << ' ' << codes_iter->data; + lines.push_back(StringFromFormat("%08X %08X", codes_iter->address, codes_iter->data)); + //ss.clear(); + } + + //lines.push_back("BLAH"); + + // TODO: save the options +} + +void SaveCodes(IniFile& inifile, const std::vector& gcodes) +{ + std::vector lines; + + std::vector::const_iterator + gcodes_iter = gcodes.begin(), + gcodes_end = gcodes.end(); + for (; gcodes_iter!=gcodes_end; ++gcodes_iter) + { + SaveGeckoCode(lines, *gcodes_iter); + } + + inifile.SetLines(GECKO_CODE_INI_SECTION, lines); +} + + + +}; \ No newline at end of file diff --git a/Source/Core/Core/Src/GeckoCodeConfig.h b/Source/Core/Core/Src/GeckoCodeConfig.h new file mode 100644 index 0000000000..ab04fab8ba --- /dev/null +++ b/Source/Core/Core/Src/GeckoCodeConfig.h @@ -0,0 +1,20 @@ + +#ifndef __GECKOCODECONFIG_h__ +#define __GECKOCODECONFIG_h__ + +#include "GeckoCode.h" + +#include "IniFile.h" + +namespace Gecko +{ + +void LoadCodes(const IniFile& inifile, std::vector& gcodes); +void SaveCodes(IniFile& inifile, const std::vector& gcodes); + + + + +}; + +#endif \ No newline at end of file diff --git a/Source/Core/Core/Src/PatchEngine.cpp b/Source/Core/Core/Src/PatchEngine.cpp index ca90c4491a..fb5f2056fa 100644 --- a/Source/Core/Core/Src/PatchEngine.cpp +++ b/Source/Core/Core/Src/PatchEngine.cpp @@ -34,6 +34,8 @@ #include "PatchEngine.h" #include "HW/Memmap.h" #include "ActionReplay.h" +#include "GeckoCode.h"; +#include "GeckoCodeConfig.h"; #include "FileUtil.h" using namespace Common; @@ -154,6 +156,12 @@ void LoadPatches(const char *gameID) if (ini.Load(filename.c_str())) { LoadPatchSection("OnFrame", onFrame, ini); ActionReplay::LoadCodes(ini, false); + + // lil silly + std::vector gcodes; + Gecko::LoadCodes(ini, gcodes); + Gecko::SetActiveCodes(gcodes); + LoadSpeedhacks("Speedhacks", speedHacks, ini); LoadDiscList("DiscList", discList, ini); } @@ -197,6 +205,8 @@ void ApplyFramePatches() void ApplyARPatches() { ActionReplay::RunAllActive(); + // w/e this can be changed later + Gecko::RunActiveCodes(); } } // namespace diff --git a/Source/Core/Core/Src/SConscript b/Source/Core/Core/Src/SConscript index 00e8224a20..493f3c5cbc 100644 --- a/Source/Core/Core/Src/SConscript +++ b/Source/Core/Core/Src/SConscript @@ -6,6 +6,8 @@ import sys files = [ "ActionReplay.cpp", "ARDecrypt.cpp", + "GeckoCode.cpp", + "GeckoCodeConfig.cpp", "ConfigManager.cpp", "Console.cpp", "Core.cpp", diff --git a/Source/Core/DolphinWX/DolphinWX.vcproj b/Source/Core/DolphinWX/DolphinWX.vcproj index 4880b09376..dad6f0f115 100644 --- a/Source/Core/DolphinWX/DolphinWX.vcproj +++ b/Source/Core/DolphinWX/DolphinWX.vcproj @@ -864,6 +864,14 @@ RelativePath=".\src\GameListCtrl.h" > + + + + diff --git a/Source/Core/DolphinWX/Src/CheatsWindow.cpp b/Source/Core/DolphinWX/Src/CheatsWindow.cpp index 1fd0925654..759a42e71c 100644 --- a/Source/Core/DolphinWX/Src/CheatsWindow.cpp +++ b/Source/Core/DolphinWX/Src/CheatsWindow.cpp @@ -20,6 +20,7 @@ #include "ActionReplay.h" #include "Core.h" #include "ConfigManager.h" +#include "VolumeHandler.h" #include "ISOProperties.h" #include "HW/Memmap.h" @@ -43,6 +44,17 @@ wxCheatsWindow::wxCheatsWindow(wxWindow* const parent) // Load Data Load_ARCodes(); + // Load Gecko Codes :/ + { + const DiscIO::IVolume* const vol = VolumeHandler::GetVolume(); + if (vol) + { + m_gameini_path = std::string(File::GetUserPath(D_GAMECONFIG_IDX)) + vol->GetUniqueID() + ".ini"; + m_gameini.Load(m_gameini_path); + m_geckocode_panel->LoadCodes(m_gameini); + } + } + Center(); Show(); } @@ -64,9 +76,6 @@ void wxCheatsWindow::Init_ChildControls() m_Label_Codename = new wxStaticText(m_Tab_Cheats, wxID_ANY, _T("Name: "), wxDefaultPosition, wxDefaultSize); m_GroupBox_Info = new wxStaticBox(m_Tab_Cheats, wxID_ANY, _T("Code Info"), wxDefaultPosition, wxDefaultSize); - - wxButton* const button_applycodes = new wxButton(m_Tab_Cheats, wxID_ANY, _T("Apply Changes"), wxDefaultPosition, wxDefaultSize); - _connect_macro_(button_applycodes, wxCheatsWindow::OnEvent_ButtonUpdateCodes_Press, wxEVT_COMMAND_BUTTON_CLICKED, this); m_Label_NumCodes = new wxStaticText(m_Tab_Cheats, wxID_ANY, _T("Number Of Codes: "), wxDefaultPosition, wxDefaultSize); m_ListBox_CodesList = new wxListBox(m_Tab_Cheats, wxID_ANY, wxDefaultPosition, wxSize(120, 150), 0, 0, wxLB_HSCROLL); @@ -76,13 +85,9 @@ void wxCheatsWindow::Init_ChildControls() sGroupBoxInfo->Add(m_Label_NumCodes, 0, wxALL, 5); sGroupBoxInfo->Add(m_ListBox_CodesList, 1, wxALL, 5); - wxBoxSizer* sB1 = new wxBoxSizer(wxVERTICAL); - sB1->Add(button_applycodes, 0, wxALL | wxEXPAND, 5); - sB1->Add(sGroupBoxInfo, 1, wxALL, 5); - wxBoxSizer* sizer_tab_cheats = new wxBoxSizer(wxHORIZONTAL); sizer_tab_cheats->Add(m_CheckListBox_CheatsList, 1, wxEXPAND | wxTOP | wxBOTTOM | wxLEFT, 10); - sizer_tab_cheats->Add(sB1, 0, wxALIGN_LEFT | wxEXPAND | wxALL, 5); + sizer_tab_cheats->Add(sGroupBoxInfo, 0, wxALIGN_LEFT | wxEXPAND | wxALL, 5); m_Tab_Cheats->SetSizerAndFit(sizer_tab_cheats); @@ -112,14 +117,19 @@ void wxCheatsWindow::Init_ChildControls() m_Tab_Log->SetSizerAndFit(sTabLog); // Add Tabs to Notebook - m_Notebook_Main->AddPage(m_Tab_Cheats, _T("Codes List")); + m_Notebook_Main->AddPage(m_Tab_Cheats, _T("AR Codes")); + m_geckocode_panel = new Gecko::CodeConfigPanel(m_Notebook_Main); + m_Notebook_Main->AddPage(m_geckocode_panel, wxT("Gecko Codes")); m_Notebook_Main->AddPage(tab_cheat_search, _T("Cheat Search")); m_Notebook_Main->AddPage(m_Tab_Log, _T("Logging")); // Button Strip + wxButton* const button_apply = new wxButton(panel, wxID_ANY, _T("Apply"), wxDefaultPosition, wxDefaultSize); + _connect_macro_(button_apply, wxCheatsWindow::OnEvent_ApplyChanges_Press, wxEVT_COMMAND_BUTTON_CLICKED, this); wxButton* const button_close = new wxButton(panel, wxID_ANY, _T("Close"), wxDefaultPosition, wxDefaultSize); _connect_macro_(button_close, wxCheatsWindow::OnEvent_ButtonClose_Press, wxEVT_COMMAND_BUTTON_CLICKED, this); wxBoxSizer* sButtons = new wxBoxSizer(wxHORIZONTAL); + sButtons->Add(button_apply, 1, wxRIGHT, 5); sButtons->Add(button_close, 1, 0, 0); wxBoxSizer* const sMain = new wxBoxSizer(wxVERTICAL); @@ -280,12 +290,23 @@ void wxCheatsWindow::OnEvent_CheatsList_ItemToggled(wxCommandEvent& WXUNUSED (ev } } -void wxCheatsWindow::OnEvent_ButtonUpdateCodes_Press(wxCommandEvent& WXUNUSED (event)) +void wxCheatsWindow::OnEvent_ApplyChanges_Press(wxCommandEvent& WXUNUSED (event)) { + // Appply AR Code changes for (size_t i = 0; i < indexList.size(); i++) { ActionReplay::SetARCode_IsActive(m_CheckListBox_CheatsList->IsChecked(indexList[i].uiIndex), indexList[i].index); } + + // Apply Gecko Code changes + Gecko::SetActiveCodes(m_geckocode_panel->GetCodes()); + + // save gameini, with changed gecko codes + if (m_gameini_path.size()) + { + Gecko::SaveCodes(m_gameini, m_geckocode_panel->GetCodes()); + m_gameini.Save(m_gameini_path); + } } void wxCheatsWindow::OnEvent_ButtonUpdateLog_Press(wxCommandEvent& WXUNUSED (event)) diff --git a/Source/Core/DolphinWX/Src/CheatsWindow.h b/Source/Core/DolphinWX/Src/CheatsWindow.h index 73b04e6dcb..a128d9edbe 100644 --- a/Source/Core/DolphinWX/Src/CheatsWindow.h +++ b/Source/Core/DolphinWX/Src/CheatsWindow.h @@ -36,6 +36,8 @@ #include "ActionReplay.h" +#include "GeckoCodeDiag.h" + #include "Filesystem.h" #include "IniFile.h" @@ -143,6 +145,10 @@ class wxCheatsWindow : public wxFrame std::vector indexList; + Gecko::CodeConfigPanel *m_geckocode_panel; + IniFile m_gameini; + std::string m_gameini_path; + void Init_ChildControls(); void Load_ARCodes(); @@ -156,8 +162,8 @@ class wxCheatsWindow : public wxFrame void OnEvent_CheatsList_ItemSelected(wxCommandEvent& event); void OnEvent_CheatsList_ItemToggled(wxCommandEvent& event); - // $ Update Active Codes Button - void OnEvent_ButtonUpdateCodes_Press(wxCommandEvent& event); + // $ Apply Changes Button + void OnEvent_ApplyChanges_Press(wxCommandEvent& event); // $ Update Log Button void OnEvent_ButtonUpdateLog_Press(wxCommandEvent& event); diff --git a/Source/Core/DolphinWX/Src/FrameTools.cpp b/Source/Core/DolphinWX/Src/FrameTools.cpp index de9efe9199..082e94ad59 100644 --- a/Source/Core/DolphinWX/Src/FrameTools.cpp +++ b/Source/Core/DolphinWX/Src/FrameTools.cpp @@ -186,7 +186,7 @@ void CFrame::CreateMenu() toolsMenu->Append(IDM_LUA, _T("New &Lua Console")); toolsMenu->Append(IDM_MEMCARD, _T("&Memcard Manager (GC)")); toolsMenu->Append(IDM_IMPORTSAVE, _T("Wii Save Import")); - toolsMenu->Append(IDM_CHEATS, _T("Action &Replay Manager")); + toolsMenu->Append(IDM_CHEATS, _T("&Cheats Manager")); toolsMenu->Append(IDM_NETPLAY, _T("Start &NetPlay")); diff --git a/Source/Core/DolphinWX/Src/GeckoCodeDiag.cpp b/Source/Core/DolphinWX/Src/GeckoCodeDiag.cpp new file mode 100644 index 0000000000..888dc503b1 --- /dev/null +++ b/Source/Core/DolphinWX/Src/GeckoCodeDiag.cpp @@ -0,0 +1,112 @@ + +#include "GeckoCodeDiag.h" + +#define _connect_macro_(b, f, c, s) (b)->Connect(wxID_ANY, (c), wxCommandEventHandler(f), (wxObject*)0, (wxEvtHandler*)s) + +namespace Gecko +{ + +static const wxString wxstr_name(wxT("Name: ")), + wxstr_description(wxT("Description: ")), + wxstr_creator(wxT("Creator: ")); + +CodeConfigPanel::CodeConfigPanel(wxWindow* const parent) + : wxPanel(parent, -1, wxDefaultPosition, wxDefaultSize) +{ + m_listbox_gcodes = new wxCheckListBox(this, -1, wxDefaultPosition, wxDefaultSize); + _connect_macro_(m_listbox_gcodes, CodeConfigPanel::UpdateInfoBox, wxEVT_COMMAND_LISTBOX_SELECTED, this); + _connect_macro_(m_listbox_gcodes, CodeConfigPanel::ToggleCode, wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, this); + + m_infobox.label_name = new wxStaticText(this, -1, wxstr_name); + m_infobox.label_creator = new wxStaticText(this, -1, wxstr_creator); + m_infobox.label_description = new wxStaticText(this, -1, wxstr_description); + m_infobox.listbox_codes = new wxListBox(this, -1, wxDefaultPosition, wxSize(-1, 64)); + + // TODO: buttons to add/edit codes + + // sizers + wxBoxSizer* const sizer_infobox = new wxBoxSizer(wxVERTICAL); + sizer_infobox->Add(m_infobox.label_name, 0, wxLEFT | wxBOTTOM, 5); + sizer_infobox->Add(m_infobox.label_creator, 0, wxLEFT | wxBOTTOM, 5); + sizer_infobox->Add(m_infobox.label_description, 0, wxLEFT | wxBOTTOM, 5); + sizer_infobox->Add(m_infobox.listbox_codes, 0, wxLEFT | wxBOTTOM, 5); + + //wxBoxSizer* const sizer_horz = new wxBoxSizer(wxHORIZONTAL); + //sizer_horz->Add(sizer_infobox, 1, 0); + + // silly + //if (show_apply_button) + //{ + // wxButton* const btn_apply = new wxButton(this, -1, wxT("Apply Changes"), wxDefaultPosition, wxSize(128, -1)); + // _connect_macro_(btn_apply, CodeConfigPanel::ApplyChanges, wxEVT_COMMAND_BUTTON_CLICKED, this); + // sizer_horz->Add(btn_apply, 0, wxALIGN_RIGHT | wxALIGN_BOTTOM); + //} + + wxBoxSizer* const sizer_main = new wxBoxSizer(wxVERTICAL); + sizer_main->Add(m_listbox_gcodes, 1, wxALL | wxEXPAND, 5); + sizer_main->Add(sizer_infobox, 0, wxALL | wxEXPAND, 5); + + SetSizerAndFit(sizer_main); +} + +void CodeConfigPanel::LoadCodes(const IniFile& inifile) +{ + m_gcodes.clear(); + Gecko::LoadCodes(inifile, m_gcodes); + + m_listbox_gcodes->Clear(); + // add the codes to the listbox + std::vector::const_iterator + gcodes_iter = m_gcodes.begin(), + gcodes_end = m_gcodes.end(); + for (; gcodes_iter!=gcodes_end; ++gcodes_iter) + { + m_listbox_gcodes->Append(wxString::FromAscii(gcodes_iter->name.c_str())); + if (gcodes_iter->enabled) + m_listbox_gcodes->Check(m_listbox_gcodes->GetCount()-1, true); + } + + wxCommandEvent evt; + UpdateInfoBox(evt); +} + +void CodeConfigPanel::ToggleCode(wxCommandEvent& evt) +{ + const int sel = evt.GetInt(); // this right? + if (sel > -1) + m_gcodes[sel].enabled = m_listbox_gcodes->IsChecked(sel); +} + +void CodeConfigPanel::UpdateInfoBox(wxCommandEvent&) +{ + m_infobox.listbox_codes->Clear(); + const int sel = m_listbox_gcodes->GetSelection(); + + if (sel > -1) + { + m_infobox.label_name->SetLabel(wxstr_name + wxString::FromAscii(m_gcodes[sel].name.c_str())); + m_infobox.label_description->SetLabel(wxstr_description + wxString::FromAscii(m_gcodes[sel].description.c_str())); + m_infobox.label_creator->SetLabel(wxstr_creator + wxString::FromAscii(m_gcodes[sel].creator.c_str())); + + // add codes to info listbox + std::vector::const_iterator + codes_iter = m_gcodes[sel].codes.begin(), + codes_end = m_gcodes[sel].codes.end(); + for (; codes_iter!=codes_end; ++codes_iter) + m_infobox.listbox_codes->Append(wxString::Format(wxT("%08X %08X"), codes_iter->address, codes_iter->data)); + } + else + { + m_infobox.label_name->SetLabel(wxstr_name); + m_infobox.label_description->SetLabel(wxstr_description); + m_infobox.label_creator->SetLabel(wxstr_creator); + } +} + +void CodeConfigPanel::ApplyChanges(wxCommandEvent&) +{ + Gecko::SetActiveCodes(m_gcodes); +} + + +} \ No newline at end of file diff --git a/Source/Core/DolphinWX/Src/GeckoCodeDiag.h b/Source/Core/DolphinWX/Src/GeckoCodeDiag.h new file mode 100644 index 0000000000..44e4836a62 --- /dev/null +++ b/Source/Core/DolphinWX/Src/GeckoCodeDiag.h @@ -0,0 +1,45 @@ + +#ifndef __GECKOCODEDIAG_h__ +#define __GECKOCODEDIAG_h__ + +#include "GeckoCode.h" +#include "GeckoCodeConfig.h" + +#include "wx/wx.h" + +namespace Gecko +{ + + +class CodeConfigPanel : public wxPanel +{ +public: + CodeConfigPanel(wxWindow* const parent); + + + void LoadCodes(const IniFile& inifile); + const std::vector& GetCodes() const { return m_gcodes; } + +protected: + void UpdateInfoBox(wxCommandEvent&); + void ToggleCode(wxCommandEvent& evt); + void ApplyChanges(wxCommandEvent&); + +private: + std::vector m_gcodes; + + // wxwidgets stuff + wxCheckListBox *m_listbox_gcodes; + struct + { + wxStaticText *label_name, *label_description, *label_creator; + wxListBox *listbox_codes; + } m_infobox; + +}; + + + +} + +#endif \ No newline at end of file diff --git a/Source/Core/DolphinWX/Src/ISOProperties.cpp b/Source/Core/DolphinWX/Src/ISOProperties.cpp index b0ac8ea0e9..999cabe7f7 100644 --- a/Source/Core/DolphinWX/Src/ISOProperties.cpp +++ b/Source/Core/DolphinWX/Src/ISOProperties.cpp @@ -24,6 +24,7 @@ #include "ISOProperties.h" #include "PatchAddEdit.h" #include "ARCodeAddEdit.h" +#include "GeckoCodeDiag.h" #include "ConfigManager.h" #include "StringUtil.h" @@ -268,6 +269,8 @@ void CISOProperties::CreateGUIControls(bool IsWad) m_Notebook->AddPage(m_PatchPage, _("Patches")); m_CheatPage = new wxPanel(m_Notebook, ID_ARCODE_PAGE, wxDefaultPosition, wxDefaultSize); m_Notebook->AddPage(m_CheatPage, _("AR Codes")); + m_geckocode_panel = new Gecko::CodeConfigPanel(m_Notebook); + m_Notebook->AddPage(m_geckocode_panel, wxT("Gecko Codes")); m_Information = new wxPanel(m_Notebook, ID_INFORMATION, wxDefaultPosition, wxDefaultSize); m_Notebook->AddPage(m_Information, _("Info")); m_Filesystem = new wxPanel(m_Notebook, ID_FILESYSTEM, wxDefaultPosition, wxDefaultSize); @@ -879,6 +882,7 @@ void CISOProperties::LoadGameConfig() PatchList_Load(); ActionReplayList_Load(); + m_geckocode_panel->LoadCodes(GameIni); } bool CISOProperties::SaveGameConfig() @@ -966,6 +970,7 @@ bool CISOProperties::SaveGameConfig() PatchList_Save(); ActionReplayList_Save(); + Gecko::SaveCodes(GameIni, m_geckocode_panel->GetCodes()); return GameIni.Save(GameIniFile.c_str()); } diff --git a/Source/Core/DolphinWX/Src/ISOProperties.h b/Source/Core/DolphinWX/Src/ISOProperties.h index ca8680905c..18759ee443 100644 --- a/Source/Core/DolphinWX/Src/ISOProperties.h +++ b/Source/Core/DolphinWX/Src/ISOProperties.h @@ -35,6 +35,7 @@ #include "IniFile.h" #include "PatchEngine.h" #include "ActionReplay.h" +#include "GeckoCodeDiag.h" class CISOProperties : public wxDialog { @@ -145,6 +146,8 @@ class CISOProperties : public wxDialog wxTreeItemId RootId; wxImageList *m_iconList; + Gecko::CodeConfigPanel *m_geckocode_panel; + enum { ID_CLOSE = 1000, diff --git a/Source/Core/DolphinWX/Src/SConscript b/Source/Core/DolphinWX/Src/SConscript index 5cafa52c17..34f496f743 100644 --- a/Source/Core/DolphinWX/Src/SConscript +++ b/Source/Core/DolphinWX/Src/SConscript @@ -23,6 +23,7 @@ if env['HAVE_WX']: files += [ 'AboutDolphin.cpp', 'ARCodeAddEdit.cpp', + 'GeckoCodeDiag.cpp', 'ConfigMain.cpp', 'Frame.cpp', 'FrameAui.cpp',