summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorJordan Woyak <jordan.woyak@gmail.com>2010-07-23 05:22:12 +0000
committerJordan Woyak <jordan.woyak@gmail.com>2010-07-23 05:22:12 +0000
commita3e31556787c87fd708dfd4a6a194a5d62a60c59 (patch)
tree36913cbab1c961344ba44f04f4fed399902b3432 /Source/Core
parent2e6c5b36ab895fcdb5d62d3a04ac895d1797bb05 (diff)
Added a button to the "Gecko Codes" panel to download/parse codes from geckocodes.org. Codes that require modifiers (the XXXX business) will still not work properly, though they should load/save fine. A few more code types should work now. (All non-ASM type codes should at least attempt to run :p) Hacked a param into IniFile::GetLines to disable removal of text after # chars, so codes with # in the name/notes should load fine.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5949 8ced0084-cf51-0410-be5f-012b33b47a6e
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Common/Src/IniFile.cpp20
-rw-r--r--Source/Core/Common/Src/IniFile.h2
-rw-r--r--Source/Core/Core/Src/GeckoCode.cpp340
-rw-r--r--Source/Core/Core/Src/GeckoCode.h7
-rw-r--r--Source/Core/Core/Src/GeckoCodeConfig.cpp34
-rw-r--r--Source/Core/DolphinWX/Src/CheatsWindow.cpp6
-rw-r--r--Source/Core/DolphinWX/Src/GeckoCodeDiag.cpp199
-rw-r--r--Source/Core/DolphinWX/Src/GeckoCodeDiag.h13
-rw-r--r--Source/Core/DolphinWX/Src/ISOProperties.cpp2
9 files changed, 435 insertions, 188 deletions
diff --git a/Source/Core/Common/Src/IniFile.cpp b/Source/Core/Common/Src/IniFile.cpp
index 325b87278a..85a88bc7fc 100644
--- a/Source/Core/Common/Src/IniFile.cpp
+++ b/Source/Core/Common/Src/IniFile.cpp
@@ -350,7 +350,7 @@ bool IniFile::GetKeys(const char* sectionName, std::vector<std::string>& keys) c
}
// Return a list of all lines in a section
-bool IniFile::GetLines(const char* sectionName, std::vector<std::string>& lines) const
+bool IniFile::GetLines(const char* sectionName, std::vector<std::string>& lines, const bool remove_comments) const
{
const Section* section = GetSection(sectionName);
if (!section)
@@ -360,15 +360,19 @@ bool IniFile::GetLines(const char* sectionName, std::vector<std::string>& lines)
for (std::vector<std::string>::const_iterator iter = section->lines.begin(); iter != section->lines.end(); ++iter)
{
std::string line = StripSpaces(*iter);
- int commentPos = (int)line.find('#');
- if (commentPos == 0)
- {
- continue;
- }
- if (commentPos != (int)std::string::npos)
+ if (remove_comments)
{
- line = StripSpaces(line.substr(0, commentPos));
+ int commentPos = (int)line.find('#');
+ if (commentPos == 0)
+ {
+ continue;
+ }
+
+ if (commentPos != (int)std::string::npos)
+ {
+ line = StripSpaces(line.substr(0, commentPos));
+ }
}
lines.push_back(line);
diff --git a/Source/Core/Common/Src/IniFile.h b/Source/Core/Common/Src/IniFile.h
index 05eff76cdd..3c4959f04b 100644
--- a/Source/Core/Common/Src/IniFile.h
+++ b/Source/Core/Common/Src/IniFile.h
@@ -123,7 +123,7 @@ public:
bool GetKeys(const char* sectionName, std::vector<std::string>& keys) const;
void SetLines(const char* sectionName, const std::vector<std::string> &lines);
- bool GetLines(const char* sectionName, std::vector<std::string>& lines) const;
+ bool GetLines(const char* sectionName, std::vector<std::string>& lines, const bool remove_comments = true) const;
bool DeleteKey(const char* sectionName, const char* key);
bool DeleteSection(const char* sectionName);
diff --git a/Source/Core/Core/Src/GeckoCode.cpp b/Source/Core/Core/Src/GeckoCode.cpp
index 3a06bf9177..2d283def58 100644
--- a/Source/Core/Core/Src/GeckoCode.cpp
+++ b/Source/Core/Core/Src/GeckoCode.cpp
@@ -57,7 +57,8 @@ u32 GeckoCode::Code::GetAddress() const
static Common::CriticalSection active_codes_lock;
// currently running code
-static GeckoCode::Code current_code;
+static GeckoCode::Code *codes_start = NULL, *current_code = NULL;
+static const GeckoCode::Code *codes_end = NULL;
// Functions for each code type
bool RamWriteAndFill();
@@ -91,7 +92,7 @@ void SetActiveCodes(const std::vector<GeckoCode>& gcodes)
active_codes_lock.Leave();
}
-bool RunGeckoCode(const GeckoCode& gecko_code)
+bool RunGeckoCode(GeckoCode& gecko_code)
{
static bool (*code_type_funcs[])(void) =
{ RamWriteAndFill, RegularIf, BaPoOps, FlowControl, RegisterOps, SpecialIf, AsmSwitchRange, EndCodes };
@@ -100,14 +101,11 @@ bool RunGeckoCode(const GeckoCode& gecko_code)
pointer_address = 0x80000000;
code_execution_counter = 0;
- std::vector<GeckoCode::Code>::const_iterator
- codes_iter = gecko_code.codes.begin(),
- codes_end = gecko_code.codes.end();
- for (; codes_iter != codes_end; ++codes_iter)
+ current_code = codes_start = &*gecko_code.codes.begin();
+ codes_end = &*gecko_code.codes.end();
+ for (; current_code < codes_end; ++current_code)
{
- const GeckoCode::Code& code = *codes_iter;
-
- current_code = code;
+ const GeckoCode::Code& code = *current_code;
bool result = true;
@@ -133,16 +131,12 @@ bool RunGeckoCode(const GeckoCode& gecko_code)
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.)"
+ "\n(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;
}
@@ -151,7 +145,7 @@ bool RunActiveCodes()
if (false == active_codes_lock.TryEnter())
return true;
- std::vector<GeckoCode>::const_iterator
+ std::vector<GeckoCode>::iterator
gcodes_iter = active_codes.begin(),
gcodes_end = active_codes.end();
for (; gcodes_iter!=gcodes_end; ++gcodes_iter)
@@ -167,19 +161,19 @@ bool RunActiveCodes()
}
// CT0: Direct ram write/fill
-// NOT COMPLETE, last 2 subtypes not started
+// COMPLETE, maybe
bool RamWriteAndFill()
{
- const GeckoCode::Code& code = current_code;
+ const GeckoCode::Code& code = *current_code;
u32 new_addr = code.GetAddress();
const u32& data = code.data;
- u16 count = (data >> 16) + 1;
+ u16 count = (data >> 16) + 1; // note: +1
switch (code.subtype)
{
// CST0: 8bits Write & Fill
- case 0x0 :
+ case DATATYPE_8BIT :
while (count--)
{
Memory::Write_U16((u16)data, new_addr);
@@ -188,7 +182,7 @@ bool RamWriteAndFill()
break;
// CST1: 16bits Write & Fill
- case 0x1 :
+ case DATATYPE_16BIT :
while (count--)
{
Memory::Write_U16((u16)data, new_addr);
@@ -197,23 +191,76 @@ bool RamWriteAndFill()
break;
// CST2: 32bits Write
- case 0x2 :
+ case DATATYPE_32BIT :
Memory::Write_U32((u32)data, new_addr);
break;
// CST3: String Code
case 0x3 :
- // TODO:
- return false;
+ count = code.data; // count is different from the other subtypes
+ while (count)
+ {
+ if (codes_end == ++current_code)
+ return false;
+
+ // write bytes from address
+ int byte_num = 4;
+ while (byte_num-- && count)
+ {
+ Memory::Write_U8((u8)(current_code->address >> byte_num * 8), new_addr);
+ ++new_addr;
+ --count;
+ }
+
+ // write bytes from data
+ byte_num = 4;
+ while (byte_num-- && count)
+ {
+ Memory::Write_U8((u8)(current_code->data >> byte_num * 8), new_addr);
+ ++new_addr;
+ --count;
+ }
+ }
break;
// CST4: Serial Code
case 0x4 :
{
- // TODO: complete
- // u32 new_data = data;
-
- return false;
+ if (codes_end == ++current_code)
+ return false;
+ u32 new_data = data; // starting value of data
+ const u8 data_type = current_code->address >> 28;
+ const u32 data_inc = current_code->data; // amount to increment the data
+ const u16 addr_inc = (u16)current_code->address; // amount to increment the address
+ count = (current_code->address >> 16) & 0xFFF + 1; // count is different from the other subtypes, note: +1
+ while (count--)
+ {
+ // switch inside the loop, :/ o well
+ switch (data_type)
+ {
+ case DATATYPE_8BIT :
+ Memory::Write_U8((u8)new_data, new_addr);
+ new_data = (u8)new_data + (u8)data_inc;
+ break;
+
+ case DATATYPE_16BIT :
+ Memory::Write_U16((u16)new_data, new_addr);
+ new_data = (u16)new_data + (u16)data_inc;
+ break;
+
+ case DATATYPE_32BIT :
+ Memory::Write_U32((u32)new_data, new_addr);
+ new_data += data_inc;
+ break;
+
+ // INVALID DATATYPE
+ default :
+ return false;
+ break;
+ }
+
+ new_addr += addr_inc;
+ }
}
break;
@@ -230,7 +277,7 @@ bool RamWriteAndFill()
// COMPLETE
bool RegularIf()
{
- const GeckoCode::Code& code = current_code;
+ const GeckoCode::Code& code = *current_code;
const bool is_endif = !!(code.address & 0x1);
@@ -306,7 +353,7 @@ bool RegularIf()
// NOT COMPLETE, last 2 subtypes aren't done
bool BaPoOps()
{
- const GeckoCode::Code& code = current_code;
+ const GeckoCode::Code& code = *current_code;
// base_address vs pointer (ba vs po)
u32& change_address = (code.subtype & 0x4) ? pointer_address : base_address;
@@ -360,10 +407,10 @@ bool BaPoOps()
}
// CT3 Repeat/Goto/Gosub/Return
-// NOT COMPLETE
+// COMPLETE, maybe
bool FlowControl()
{
- const GeckoCode::Code& code = current_code;
+ const GeckoCode::Code& code = *current_code;
// only the return subtype runs when code execution is off
if (false == CodeExecution() && code.subtype != 0x2)
@@ -376,10 +423,8 @@ bool FlowControl()
{
// 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; //
+ block[block_num].number = code.address & 0xFFFF;
+ block[block_num].address = (u32)(current_code - codes_start + 1);
break;
// CST1 : Execute Repeat
@@ -387,7 +432,8 @@ bool FlowControl()
if (block[block_num].number)
{
--block[block_num].number;
- // TODO: jump to code block
+ // needs -1 cause iterator gets ++ after code runs
+ current_code = codes_start + block[block_num].address - 1;
}
return false; //
break;
@@ -395,20 +441,43 @@ bool FlowControl()
// CST2 : Return
case 0x2 :
if (((code.address >> 20) & 0xF) ^ (u32)CodeExecution())
- // TODO: jump to block[block_num].number
- return false; //
+ {
+ // needs -1 cause iterator gets ++ after code runs
+ current_code = codes_start + block[block_num].address - 1;
+ }
break;
// CST3 : Goto
case 0x3 :
- // TODO:
- return false; //
+ if (((code.address >> 20) & 0xF) ^ (u32)CodeExecution())
+ {
+ GeckoCode::Code* const target_code = current_code + (s16)(code.address & 0xFFFF);
+
+ if (target_code >= codes_start && target_code < codes_end)
+ {
+ // needs -1 cause iterator gets ++ after code runs
+ current_code = target_code - 1;
+ }
+ else
+ return false; // trying to GOTO to bad address
+ }
break;
// CST4 : Gosub
case 0x4 :
- // TODO:
- return false; //
+ if (((code.address >> 20) & 0xF) ^ (u32)CodeExecution())
+ {
+ GeckoCode::Code* const target_code = current_code + (s16)(code.address & 0xFFFF);
+
+ if (target_code >= codes_start && target_code < codes_end)
+ {
+ block[block_num].address = u32(current_code - codes_start + 1);
+ // needs -1 cause iterator gets ++ after code runs
+ current_code = target_code - 1;
+ }
+ else
+ return false; // trying to GOSUB to bad address
+ }
break;
// INVALID SUBTYPE
@@ -421,10 +490,10 @@ bool FlowControl()
}
// CT4 Gecko Register Operations
-// NOT COMPLETE, need to do memory copy 1,2
+// COMPLETE, maybe
bool RegisterOps()
{
- const GeckoCode::Code& code = current_code;
+ const GeckoCode::Code& code = *current_code;
// 80TYZZZN XXXXXXXX
@@ -519,15 +588,27 @@ bool RegisterOps()
break;
// CST5 : Memory Copy 1
- case 0x5 :
- // TODO:
- return false; //
- break;
-
// CST6 : Memory Copy 2
+ case 0x5 :
case 0x6 :
- // TODO:
- return false; //
+ {
+ const u8 src_gr = (code.z & 0xF);
+ const u8 dst_gr = (code.n);
+
+ u16 count = (u16)(code.address >> 8);
+
+ // docs don't specify allowing 0xF for source and dest, but it can't hurt
+ u32 src_addr = ((0xF == src_gr) ? (code.use_po ? pointer_address : base_address) : gecko_register[src_gr]);
+ u32 dst_addr = ((0xF == dst_gr) ? (code.use_po ? pointer_address : base_address) : gecko_register[dst_gr]);
+
+ if (0x5 == code.subtype)
+ dst_addr += new_data;
+ else
+ src_addr += new_data;
+
+ while (count--)
+ Memory::Write_U8(Memory::Read_U8(src_addr++), dst_addr++);
+ }
break;
// INVALID SUBTYPE
@@ -589,8 +670,7 @@ bool MathOperation(u32& ret, const u32 left, const u32 right, const u8 type)
// 8 : asr (arithmetic shift right)
case 0x8 :
- // TODO: wuts this
- return false;
+ ret = (left >> right) | (left & 0x80000000);
break;
// TODO: these float ops good?
@@ -614,10 +694,11 @@ bool MathOperation(u32& ret, const u32 left, const u32 right, const u8 type)
}
// CT5: Special If codes (16bits)
-// NOT COMPLETE, part 2 (counter stuff) not started
+// COMPLETE, maybe (ugly)
bool SpecialIf()
{
- const GeckoCode::Code& code = current_code;
+ // counter can modify the code :/
+ GeckoCode::Code& code = *current_code;
const bool is_endif = !!(code.address & 0x1);
@@ -630,99 +711,87 @@ bool SpecialIf()
bool result = false;
+ // TODO: should these be signed? probably?
+ s16 left_val = 0, right_val = 0;
+
// 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
+ // A-______ NM00YYYY
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;
- }
+ left_val = Memory::Read_U16(((0xF == n) ? addr : gecko_register[n]) & ~y);
+ right_val = Memory::Read_U16(((0xF == m) ? addr : gecko_register[m]) & ~y);
}
else
{
// CT5 Part2 : 16bits Counter check
- // TODO:
+ // A-0ZZZZT MMMMXXXX
- switch (code.subtype)
- {
- // CST4 : 16bits (endif, then) If counter value equal
- case 0x4 :
- // TODO:
- return false; //
- break;
+ left_val = (u16)(data) & ~(u16)(data >> 16);
+ right_val = (u16)(addr >> 4);
+ }
- // CST5 : 16bits (endif, then) If counter value not equal
- case 0x5 :
- // TODO:
- return false; //
- break;
+ switch (code.subtype & 0x3)
+ {
+ // CST0 : 16bits (endif, then) If equal
+ case 0x0 :
+ result = (left_val == right_val);
+ break;
- // CST6 : 16bits (endif, then) If counter value greater
- case 0x6 :
- // TODO:
- return false; //
- break;
+ // CST1 : 16bits (endif, then) If not equal
+ case 0x1 :
+ result = (left_val != right_val);
+ break;
- // CST7 : 16bits (endif, then) If counter value lower
- case 0x7 :
- // TODO:
- return false; //
- 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 if (code.subtype & 0x4)
+ {
+ // counters get reset if code execution is off
+ code.address &= ~0x000FFFF0;
}
// if the conditional returned false, or it never ran because execution is off, increase the code execution counter
if (false == result)
++code_execution_counter;
+ else if (code.subtype & 0x4)
+ {
+ // counters gets advanced if condition was true
+ // right_val is the value of the counter
+
+ code.address &= ~0x000FFFF0;
+ code.address |= ((right_val+1) << 4);
+ }
return true;
}
// CT6 ASM Codes, On/Off switch and Address Range Check
-// NOT COMPLETE, hardly started
-// fix the logic flow in this one
+// NOT COMPLETE, asm stuff not started
+// fix the uglyness
bool AsmSwitchRange()
{
- const GeckoCode::Code& code = current_code;
-
- // only used for the last 2 subtypes
- const bool is_endif = !!(code.address & 0x1);
+ // the switch subtype modifies the code :/
+ GeckoCode::Code& code = *current_code;
// 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
@@ -730,11 +799,11 @@ bool AsmSwitchRange()
{
if (code.subtype < 0x6)
return true;
- else if (false == (1 == code_execution_counter && is_endif))
+ else if (1 != code_execution_counter)
return true;
}
- const u32& data = code.data;
+ u32& data = code.data;
switch (code.subtype)
{
@@ -752,24 +821,47 @@ bool AsmSwitchRange()
// CST3 : Create a branch
case 0x3 :
- // TODO:
+ // watever
+ //if (code.data)
return false; //
break;
// CST6 : On/Off switch
case 0x6 :
- // TODO:
- return false; //
+ // in the 1st bit of code.data, i store if code execution was previously off
+ // in the 2nd bit of code.data, i store the switch's on/off state
+ if (CodeExecution())
+ {
+ if (data & 0x1)
+ data ^= 0x2; // if code exec was previously off, flip the switch
+
+ // mark code execution as previously on
+ data &= ~0x1;
+ }
+ else
+ {
+ // mark code execution as previously off
+ data |= 0x1;
+ }
+
+ // set code execution to the state of the switch
+ code_execution_counter = !(data & 0x2);
break;
// CST7 : Address range check (If... code)
case 0x7 :
- if (code_execution_counter)
+ {
+ const bool is_endif = !!(code.address & 0x1);
+ if (is_endif)
+ --code_execution_counter;
+
+ if (CodeExecution())
{
const u32 addr = (code.use_po ? pointer_address : base_address);
- if (addr >= (data & 0xFFFF0000) && addr <= (data << 16))
- --code_execution_counter;
+ if (addr < (data & 0xFFFF0000) || addr > (data << 16))
+ ++code_execution_counter;
}
+ }
break;
// INVALID SUBTYPE
@@ -785,7 +877,7 @@ bool AsmSwitchRange()
// COMPLETE, maybe
bool EndCodes()
{
- const GeckoCode::Code& code = current_code;
+ const GeckoCode::Code& code = *current_code;
const u32& data = code.data;
const u32 x = (data & 0xFFFF0000);
@@ -802,9 +894,7 @@ bool EndCodes()
// 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
+ code_execution_counter = 0;
break;
// CST1 : Endif (+else)
diff --git a/Source/Core/Core/Src/GeckoCode.h b/Source/Core/Core/Src/GeckoCode.h
index 8073b18096..af8c17e6a2 100644
--- a/Source/Core/Core/Src/GeckoCode.h
+++ b/Source/Core/Core/Src/GeckoCode.h
@@ -18,6 +18,8 @@ namespace Gecko
struct Code
{
+ Code() : address(0), data(0) {}
+
union
{
u32 address;
@@ -50,11 +52,14 @@ namespace Gecko
//};
};
+ std::string original_line;
+
u32 GetAddress() const;
};
std::vector<Code> codes;
- std::string name, description, creator;
+ std::string name, creator;
+ std::vector<std::string> notes;
bool enabled;
};
diff --git a/Source/Core/Core/Src/GeckoCodeConfig.cpp b/Source/Core/Core/Src/GeckoCodeConfig.cpp
index 1827ca434c..f0e5a0585b 100644
--- a/Source/Core/Core/Src/GeckoCodeConfig.cpp
+++ b/Source/Core/Core/Src/GeckoCodeConfig.cpp
@@ -15,7 +15,7 @@ namespace Gecko
void LoadCodes(const IniFile& inifile, std::vector<GeckoCode>& gcodes)
{
std::vector<std::string> lines;
- inifile.GetLines(GECKO_CODE_INI_SECTION, lines);
+ inifile.GetLines(GECKO_CODE_INI_SECTION, lines, false);
GeckoCode gcode;
@@ -29,6 +29,8 @@ void LoadCodes(const IniFile& inifile, std::vector<GeckoCode>& gcodes)
std::istringstream ss(*lines_iter);
+ int read_state = 0;
+
switch ((*lines_iter)[0])
{
@@ -46,30 +48,24 @@ void LoadCodes(const IniFile& inifile, std::vector<GeckoCode>& gcodes)
gcode.name = StripSpaces(gcode.name);
// read the code creator name
std::getline(ss, gcode.creator, ']');
+ read_state = 0;
break;
- // description
+ // notes
case '*':
- ss.seekg(1);
- std::getline(ss, gcode.description);
- break;
-
- // start of code option list
- case ':':
- // TODO:
+ gcode.notes.push_back(std::string(++lines_iter->begin(), lines_iter->end()));
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
+ new_code.original_line = *lines_iter;
ss >> std::hex >> new_code.address >> new_code.data;
gcode.codes.push_back(new_code);
}
break;
-
}
}
@@ -100,10 +96,6 @@ void SaveGeckoCode(std::vector<std::string>& lines, const GeckoCode& gcode)
}
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<GeckoCode::Code>::const_iterator
@@ -112,13 +104,17 @@ void SaveGeckoCode(std::vector<std::string>& lines, const GeckoCode& gcode)
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));
+ //lines.push_back(StringFromFormat("%08X %08X", codes_iter->address, codes_iter->data));
+ lines.push_back(codes_iter->original_line);
//ss.clear();
}
- //lines.push_back("BLAH");
-
- // TODO: save the options
+ // save the notes
+ std::vector<std::string>::const_iterator
+ notes_iter = gcode.notes.begin(),
+ notes_end = gcode.notes.end();
+ for (; notes_iter!=notes_end; ++notes_iter)
+ lines.push_back(std::string("*") + *notes_iter);
}
void SaveCodes(IniFile& inifile, const std::vector<GeckoCode>& gcodes)
diff --git a/Source/Core/DolphinWX/Src/CheatsWindow.cpp b/Source/Core/DolphinWX/Src/CheatsWindow.cpp
index 1001d36a5d..83e8fef1fc 100644
--- a/Source/Core/DolphinWX/Src/CheatsWindow.cpp
+++ b/Source/Core/DolphinWX/Src/CheatsWindow.cpp
@@ -34,7 +34,7 @@ extern std::vector<ActionReplay::ARCode> arCodes;
static wxCheatsWindow *g_cheat_window;
wxCheatsWindow::wxCheatsWindow(wxWindow* const parent)
- : wxFrame(parent, wxID_ANY, wxT("Action Replay"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE)
+ : wxFrame(parent, wxID_ANY, wxT("Cheats Manager"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE)
{
::g_cheat_window = this;
@@ -201,8 +201,8 @@ CheatSearchTab::CheatSearchTab(wxWindow* const parent)
// filter types in the compare dropdown
static const wxString searches[] = {
wxT("Unknown"),
- wxT("Not Equals"),
- wxT("Equals"),
+ wxT("Not Equal"),
+ wxT("Equal"),
wxT("Greater Than"),
wxT("Less Than"),
// TODO: Implement between search.
diff --git a/Source/Core/DolphinWX/Src/GeckoCodeDiag.cpp b/Source/Core/DolphinWX/Src/GeckoCodeDiag.cpp
index 23b6d38985..1b19d27436 100644
--- a/Source/Core/DolphinWX/Src/GeckoCodeDiag.cpp
+++ b/Source/Core/DolphinWX/Src/GeckoCodeDiag.cpp
@@ -1,13 +1,20 @@
#include "GeckoCodeDiag.h"
+#ifdef _WIN32
+#define _WINSOCK2API_
+#endif
+#include <SFML/Network/Http.hpp>
+
+#include <sstream>
+
#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_notes(wxT("Notes: ")),
wxstr_creator(wxT("Creator: "));
CodeConfigPanel::CodeConfigPanel(wxWindow* const parent)
@@ -19,41 +26,40 @@ CodeConfigPanel::CodeConfigPanel(wxWindow* const parent)
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.label_notes = new wxStaticText(this, -1, wxstr_notes);
+ m_infobox.textctrl_notes = new wxTextCtrl(this, -1, wxEmptyString, wxDefaultPosition, wxSize(64, -1), wxTE_MULTILINE | wxTE_READONLY);
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);
- //}
+ sizer_infobox->Add(m_infobox.label_name, 0, wxBOTTOM, 5);
+ sizer_infobox->Add(m_infobox.label_creator, 0, wxBOTTOM, 5);
+ sizer_infobox->Add(m_infobox.label_notes, 0, wxBOTTOM, 5);
+ sizer_infobox->Add(m_infobox.textctrl_notes, 0, wxBOTTOM | wxEXPAND, 5);
+ sizer_infobox->Add(m_infobox.listbox_codes, 1, wxEXPAND, 5);
+
+ // button sizer
+ wxBoxSizer* const sizer_buttons = new wxBoxSizer(wxVERTICAL);
+ wxButton* const btn_download = new wxButton(this, -1, wxT("Download Codes (WiiRD Database)"), wxDefaultPosition, wxSize(128, -1));
+ _connect_macro_(btn_download, CodeConfigPanel::DownloadCodes, wxEVT_COMMAND_BUTTON_CLICKED, this);
+ sizer_buttons->Add(btn_download, 0, wxEXPAND);
+
+ // horizontal sizer
+ wxBoxSizer* const sizer_horz = new wxBoxSizer(wxHORIZONTAL);
+ sizer_horz->Add(sizer_infobox, 1, wxEXPAND);
+ sizer_horz->Add(sizer_buttons, 1, wxLEFT | wxALIGN_BOTTOM, 5);
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);
+ sizer_main->Add(sizer_horz, 0, wxALL | wxEXPAND, 5);
SetSizerAndFit(sizer_main);
}
-void CodeConfigPanel::LoadCodes(const IniFile& inifile)
+void CodeConfigPanel::UpdateCodeList()
{
- m_gcodes.clear();
- Gecko::LoadCodes(inifile, m_gcodes);
-
m_listbox_gcodes->Clear();
// add the codes to the listbox
std::vector<GeckoCode>::const_iterator
@@ -70,6 +76,16 @@ void CodeConfigPanel::LoadCodes(const IniFile& inifile)
UpdateInfoBox(evt);
}
+void CodeConfigPanel::LoadCodes(const IniFile& inifile, const std::string& gameid)
+{
+ m_gameid = gameid;
+
+ m_gcodes.clear();
+ Gecko::LoadCodes(inifile, m_gcodes);
+
+ UpdateCodeList();
+}
+
void CodeConfigPanel::ToggleCode(wxCommandEvent& evt)
{
const int sel = evt.GetInt(); // this right?
@@ -85,7 +101,16 @@ void CodeConfigPanel::UpdateInfoBox(wxCommandEvent&)
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()));
+
+ // notes textctrl
+ m_infobox.textctrl_notes->Clear();
+ std::vector<std::string>::const_iterator
+ notes_iter = m_gcodes[sel].notes.begin(),
+ notes_end = m_gcodes[sel].notes.end();
+ for (; notes_iter!=notes_end; ++notes_iter)
+ m_infobox.textctrl_notes->AppendText(wxString::FromAscii(notes_iter->c_str()));
+ m_infobox.textctrl_notes->ScrollLines(-99); // silly
+
m_infobox.label_creator->SetLabel(wxstr_creator + wxString::FromAscii(m_gcodes[sel].creator.c_str()));
// add codes to info listbox
@@ -98,15 +123,135 @@ void CodeConfigPanel::UpdateInfoBox(wxCommandEvent&)
else
{
m_infobox.label_name->SetLabel(wxstr_name);
- m_infobox.label_description->SetLabel(wxstr_description);
+ m_infobox.textctrl_notes->Clear();
m_infobox.label_creator->SetLabel(wxstr_creator);
}
}
-void CodeConfigPanel::ApplyChanges(wxCommandEvent&)
+//void CodeConfigPanel::ApplyChanges(wxCommandEvent&)
+//{
+// Gecko::SetActiveCodes(m_gcodes);
+//}
+
+void CodeConfigPanel::DownloadCodes(wxCommandEvent&)
{
- Gecko::SetActiveCodes(m_gcodes);
-}
+ if (m_gameid.empty())
+ return;
+
+ sf::Http::Request req;
+ req.SetURI("/txt.php?txt=" + m_gameid);
+
+ sf::Http http;
+ http.SetHost("geckocodes.org");
+ const sf::Http::Response resp = http.SendRequest(req, 5.0f);
+
+ if (sf::Http::Response::Ok == resp.GetStatus())
+ {
+ // temp vector containing parsed codes
+ std::vector<GeckoCode> gcodes;
+ // parse the codes
+ std::istringstream ss(resp.GetBody());
+
+ // debug
+ //PanicAlert("File size is %i bytes.", ss.str().size());
+
+ std::string line;
+
+ // make sure the txt file is for this game
+ // eh w/e
+ //std::getline(ss, line);
+ //if (line != m_gameid)
+ // PanicAlert("Bad code file.");
+
+ // seek past the header, get to the first code
+ std::getline(ss, line);
+ std::getline(ss, line);
+ std::getline(ss, line);
+
+ int read_state = 0;
+ GeckoCode gcode;
+
+ while ((std::getline(ss, line).good()))
+ {
+ // empty line
+ if (0 == line.size() || line == "\r" || line == "\n") // \r\n checks might not be needed
+ {
+ // add the code
+ if (gcode.codes.size())
+ gcodes.push_back(gcode);
+ gcode = GeckoCode();
+ read_state = 0;
+ continue;
+ }
+
+ switch (read_state)
+ {
+ // read new code
+ case 0 :
+ gcode.name = line; // TODO: parse creator name in []s
+ read_state = 1;
+ break;
+
+ // read code lines
+ case 1 :
+ {
+ std::istringstream ssline(line);
+ std::string addr, data;
+ ssline >> addr >> data;
+ ssline.seekg(0);
+
+ // check if this line a code, silly, but the dumb txt file comment lines can start with valid hex chars :/
+ if (8 == addr.length() && 8 == data.length())
+ {
+ GeckoCode::Code new_code;
+ new_code.original_line = line;
+ ssline >> std::hex >> new_code.address >> new_code.data;
+ gcode.codes.push_back(new_code);
+ }
+ else
+ {
+ gcode.notes.push_back(line);
+ read_state = 2; // start reading comments
+ }
+
+ }
+ break;
+
+ // read comment lines
+ case 2 :
+ // append comment line
+ gcode.notes.push_back(line);
+ break;
+
+ }
+ }
+
+ // add the last code
+ if (gcode.codes.size())
+ gcodes.push_back(gcode);
+
+ if (gcodes.size())
+ {
+ PanicAlert("Downloaded %i codes.", gcodes.size());
+
+ // append the codes to the code list
+ std::vector<GeckoCode>::const_iterator
+ gcodes_iter = gcodes.begin(),
+ gcodes_end = gcodes.end();
+ for (; gcodes_iter!= gcodes_end; ++gcodes_iter)
+ m_gcodes.push_back(*gcodes_iter);
+
+ // refresh the list
+ UpdateCodeList();
+ }
+ else
+ PanicAlert("File contained no codes.");
+ }
+ else
+ PanicAlert("Failed to download codes.");
}
+
+}
+
diff --git a/Source/Core/DolphinWX/Src/GeckoCodeDiag.h b/Source/Core/DolphinWX/Src/GeckoCodeDiag.h
index f0374f7efd..92328d5f43 100644
--- a/Source/Core/DolphinWX/Src/GeckoCodeDiag.h
+++ b/Source/Core/DolphinWX/Src/GeckoCodeDiag.h
@@ -17,22 +17,28 @@ public:
CodeConfigPanel(wxWindow* const parent);
- void LoadCodes(const IniFile& inifile);
+ void LoadCodes(const IniFile& inifile, const std::string& gameid = "");
const std::vector<GeckoCode>& GetCodes() const { return m_gcodes; }
protected:
void UpdateInfoBox(wxCommandEvent&);
void ToggleCode(wxCommandEvent& evt);
- void ApplyChanges(wxCommandEvent&);
+ void DownloadCodes(wxCommandEvent&);
+ //void ApplyChanges(wxCommandEvent&);
+
+ void UpdateCodeList();
private:
std::vector<GeckoCode> m_gcodes;
+ std::string m_gameid;
+
// wxwidgets stuff
wxCheckListBox *m_listbox_gcodes;
struct
{
- wxStaticText *label_name, *label_description, *label_creator;
+ wxStaticText *label_name, *label_notes, *label_creator;
+ wxTextCtrl *textctrl_notes;
wxListBox *listbox_codes;
} m_infobox;
@@ -43,3 +49,4 @@ private:
}
#endif
+
diff --git a/Source/Core/DolphinWX/Src/ISOProperties.cpp b/Source/Core/DolphinWX/Src/ISOProperties.cpp
index 999cabe7f7..6211c9e6b4 100644
--- a/Source/Core/DolphinWX/Src/ISOProperties.cpp
+++ b/Source/Core/DolphinWX/Src/ISOProperties.cpp
@@ -882,7 +882,7 @@ void CISOProperties::LoadGameConfig()
PatchList_Load();
ActionReplayList_Load();
- m_geckocode_panel->LoadCodes(GameIni);
+ m_geckocode_panel->LoadCodes(GameIni, OpenISO->GetUniqueID());
}
bool CISOProperties::SaveGameConfig()