Commit 12e6099d authored by fallenstardust's avatar fallenstardust

ygopro添加保存和获取最后genesys卡表的功能

读取genesys禁卡表存入_genesys_lflist
parent e2f3bbec
...@@ -7,95 +7,191 @@ namespace ygo { ...@@ -7,95 +7,191 @@ namespace ygo {
DeckManager deckManager; DeckManager deckManager;
std::vector<std::wstring> DeckManager::deckComments; std::vector<std::wstring> DeckManager::deckComments;
// 检查宽字符串是否包含指定子串(不区分大小写)
bool ContainsIgnoreCase(const std::wstring& str, const std::wstring& substr) {
if (substr.empty()) return true;
if (str.empty()) return false;
std::wstring lowerStr = str;
std::wstring lowerSubstr = substr;
// 转换为小写
std::transform(lowerStr.begin(), lowerStr.end(), lowerStr.begin(), ::towlower);
std::transform(lowerSubstr.begin(), lowerSubstr.end(), lowerSubstr.begin(), ::towlower);
// 查找子串
return lowerStr.find(lowerSubstr) != std::wstring::npos;
}
void DeckManager::LoadLFListSingle(const char* path) { void DeckManager::LoadLFListSingle(const char* path) {
// 初始化迭代器,指向_lfList容器的反向末尾位置
auto cur = _lfList.rend(); auto cur = _lfList.rend();
// 以只读模式打开指定路径的文件
FILE* fp = myfopen(path, "r"); FILE* fp = myfopen(path, "r");
// 定义字符缓冲区,用于存储从文件读取的单行内容
char linebuf[256]{}; char linebuf[256]{};
// 定义宽字符缓冲区,用于存储转换后的字符串
wchar_t strBuffer[256]{}; wchar_t strBuffer[256]{};
// 检查文件是否成功打开
if(fp) { if(fp) {
// 循环读取文件中的每一行,直到文件结束
while(std::fgets(linebuf, sizeof linebuf, fp)) { while(std::fgets(linebuf, sizeof linebuf, fp)) {
// 跳过以#开头的注释行
if(linebuf[0] == '#') if(linebuf[0] == '#')
continue; continue;
// 处理以!开头的列表名称定义行
if(linebuf[0] == '!') { if(linebuf[0] == '!') {
// 查找行中换行符或回车符的位置
auto len = std::strcspn(linebuf, "\r\n"); auto len = std::strcspn(linebuf, "\r\n");
// 在找到的位置添加字符串结束符
linebuf[len] = 0; linebuf[len] = 0;
// 将UTF-8编码的字符串转换为宽字符串
BufferIO::DecodeUTF8(&linebuf[1], strBuffer); BufferIO::DecodeUTF8(&linebuf[1], strBuffer);
// 创建新的限制列表对象
LFList newlist; LFList newlist;
// 设置列表名称
newlist.listName = strBuffer; newlist.listName = strBuffer;
// 设置默认哈希值
newlist.hash = 0x7dfcee6a; newlist.hash = 0x7dfcee6a;
// 判断列表名称是否包含"genesys"(不区分大小写)
if(ContainsIgnoreCase(newlist.listName, L"Genesys")) {
_genesys_lfList.push_back(newlist);
// 更新cur迭代器,使其指向新添加的列表
cur = _genesys_lfList.rbegin();
} else {
_lfList.push_back(newlist); _lfList.push_back(newlist);
// 更新cur迭代器,使其指向新添加的列表
cur = _lfList.rbegin(); cur = _lfList.rbegin();
}
continue; continue;
} }
if (cur == _lfList.rend()) // 如果cur仍指向_lfList的反向末尾位置(即没有有效的列表),则跳过后续处理
if (cur == _lfList.rend() || cur == _genesys_lfList.rend())
continue; continue;
// 处理以$开头的信用限制定义行
if(linebuf[0] == '$') { if(linebuf[0] == '$') {
// 指向$符号后的第一个非空白字符
char* keyPos = linebuf + 1; char* keyPos = linebuf + 1;
keyPos += std::strspn(keyPos, " \t"); keyPos += std::strspn(keyPos, " \t");
// 计算关键字的长度(到空白字符或行结束符为止)
auto keyLen = std::strcspn(keyPos, " \t\r\n"); auto keyLen = std::strcspn(keyPos, " \t\r\n");
// 如果关键字长度为0,则跳过
if(!keyLen) if(!keyLen)
continue; continue;
// 临时缓冲区,用于存储关键字
char keybuf[256]; char keybuf[256];
// 确保关键字长度不超过缓冲区大小
if(keyLen >= sizeof keybuf) if(keyLen >= sizeof keybuf)
keyLen = sizeof keybuf - 1; keyLen = sizeof keybuf - 1;
// 复制关键字到缓冲区
std::memcpy(keybuf, keyPos, keyLen); std::memcpy(keybuf, keyPos, keyLen);
// 添加字符串结束符
keybuf[keyLen] = 0; keybuf[keyLen] = 0;
// 移动到关键字后的第一个非空白字符
keyPos += keyLen; keyPos += keyLen;
keyPos += std::strspn(keyPos, " \t"); keyPos += std::strspn(keyPos, " \t");
// 重置错误标志
errno = 0; errno = 0;
// 记录数值开始位置
char* valuePos = keyPos; char* valuePos = keyPos;
// 将字符串转换为无符号长整型
auto limitValue = std::strtoul(keyPos, &keyPos, 10); auto limitValue = std::strtoul(keyPos, &keyPos, 10);
// 如果转换出错或没有读取到数值,则跳过
if(errno || valuePos == keyPos) if(errno || valuePos == keyPos)
continue; continue;
// 将UTF-8编码的关键字转换为宽字符串
BufferIO::DecodeUTF8(keybuf, strBuffer); BufferIO::DecodeUTF8(keybuf, strBuffer);
// 在当前列表的信用限制映射中添加键值对
cur->credit_limits[strBuffer] = static_cast<uint32_t>(limitValue); cur->credit_limits[strBuffer] = static_cast<uint32_t>(limitValue);
continue; continue;
} }
// 从行的开始位置解析卡牌代码
char* pos = linebuf; char* pos = linebuf;
// 重置错误标志
errno = 0; errno = 0;
// 记录代码开始位置
char* codePos = pos; char* codePos = pos;
// 将字符串转换为无符号长整型(卡牌代码)
auto result = std::strtoul(pos, &pos, 10); auto result = std::strtoul(pos, &pos, 10);
// 如果转换出错、超出范围或没有读取到数值,则跳过
if(errno || result > UINT32_MAX || codePos == pos) if(errno || result > UINT32_MAX || codePos == pos)
continue; continue;
// 检查数值后是否跟有空格或制表符
if(*pos != ' ' && *pos != '\t') if(*pos != ' ' && *pos != '\t')
continue; continue;
// 跳过空格和制表符
pos += std::strspn(pos, " \t"); pos += std::strspn(pos, " \t");
// 将结果转换为32位无符号整型
uint32_t code = static_cast<uint32_t>(result); uint32_t code = static_cast<uint32_t>(result);
// 处理包含信用分的行(以$开头)
if(*pos == '$') { if(*pos == '$') {
// 跳过$符号
++pos; ++pos;
// 跳过空白字符
pos += std::strspn(pos, " \t"); pos += std::strspn(pos, " \t");
// 获取信用分键的长度
auto creditKeyLen = std::strcspn(pos, " \t\r\n"); auto creditKeyLen = std::strcspn(pos, " \t\r\n");
// 如果键长度为0,则跳过
if(!creditKeyLen) if(!creditKeyLen)
continue; continue;
// 临时缓冲区存储信用分键
char keybuf[256]; char keybuf[256];
// 确保键长度不超过缓冲区大小
if(creditKeyLen >= sizeof keybuf) if(creditKeyLen >= sizeof keybuf)
creditKeyLen = sizeof keybuf - 1; creditKeyLen = sizeof keybuf - 1;
// 复制键到缓冲区
std::memcpy(keybuf, pos, creditKeyLen); std::memcpy(keybuf, pos, creditKeyLen);
// 添加字符串结束符
keybuf[creditKeyLen] = 0; keybuf[creditKeyLen] = 0;
// 跳过键后的空白字符
pos += creditKeyLen; pos += creditKeyLen;
pos += std::strspn(pos, " \t"); pos += std::strspn(pos, " \t");
// 重置错误标志
errno = 0; errno = 0;
// 记录信用分数值开始位置
char* creditValuePos = pos; char* creditValuePos = pos;
// 将字符串转换为无符号长整型(信用分数值)
auto creditValue = std::strtoul(pos, &pos, 10); auto creditValue = std::strtoul(pos, &pos, 10);
// 如果转换出错或没有读取到数值,则跳过
if(errno || creditValuePos == pos) if(errno || creditValuePos == pos)
continue; continue;
// 将UTF-8编码的键转换为宽字符串
BufferIO::DecodeUTF8(keybuf, strBuffer); BufferIO::DecodeUTF8(keybuf, strBuffer);
// 在当前列表的卡牌信用分映射中添加键值对
cur->credits[code][strBuffer] = static_cast<uint32_t>(creditValue); cur->credits[code][strBuffer] = static_cast<uint32_t>(creditValue);
continue; continue;
} }
// 重置错误标志
errno = 0; errno = 0;
// 记录数量开始位置
char* countPos = pos; char* countPos = pos;
// 将字符串转换为长整型(卡牌数量限制)
int count = std::strtol(pos, &pos, 10); int count = std::strtol(pos, &pos, 10);
// 如果转换出错或没有读取到数值,则跳过
if(errno || countPos == pos) if(errno || countPos == pos)
continue; continue;
// 检查数量是否在有效范围内(0-2)
if(count < 0 || count > 2) if(count < 0 || count > 2)
continue; continue;
// 将卡牌代码和数量限制添加到当前列表的内容映射中
cur->content[code] = count; cur->content[code] = count;
// 更新当前列表的哈希值(用于验证)
cur->hash = cur->hash ^ ((code << 18) | (code >> 14)) ^ ((code << (27 + count)) | (code >> (5 - count))); cur->hash = cur->hash ^ ((code << 18) | (code >> 14)) ^ ((code << (27 + count)) | (code >> (5 - count)));
} }
} }
} }
/**
* @brief 从文件中加载单个限制列表(LFList)数据
*
* 该函数解析一个包含限制列表信息的文本文件,支持以下格式:
* - 以'#'开头的行为注释行,会被跳过
* - 以'!'开头的行为列表名称定义行
* - 以'$'开头的行为信用限制定义行
* - 普通行为卡片代码和数量定义行
*
* @param reader 指向IReadFile的指针,用于读取限制列表文件内容
* @return void 无返回值
*/
void DeckManager::LoadLFListSingle(irr::io::IReadFile* reader) { void DeckManager::LoadLFListSingle(irr::io::IReadFile* reader) {
if (!reader) if (!reader)
return; return;
...@@ -137,11 +233,17 @@ void DeckManager::LoadLFListSingle(irr::io::IReadFile* reader) { ...@@ -137,11 +233,17 @@ void DeckManager::LoadLFListSingle(irr::io::IReadFile* reader) {
LFList newlist; LFList newlist;
newlist.listName = strBuffer; newlist.listName = strBuffer;
newlist.hash = 0x7dfcee6a; newlist.hash = 0x7dfcee6a;
// 判断列表名称是否包含"genesys"(不区分大小写)
if(ContainsIgnoreCase(newlist.listName, L"Genesys")) {
_genesys_lfList.push_back(newlist);
cur = _genesys_lfList.rbegin();
} else {
_lfList.push_back(newlist); _lfList.push_back(newlist);
cur = _lfList.rbegin(); cur = _lfList.rbegin();
}
continue; continue;
} }
if (cur == _lfList.rend()) if (cur == _lfList.rend() || cur == _genesys_lfList.rend())
continue; continue;
if(linebuf[0] == '$') { if(linebuf[0] == '$') {
char* keyPos = linebuf + 1; char* keyPos = linebuf + 1;
...@@ -220,19 +322,38 @@ void DeckManager::LoadLFList(irr::android::InitOptions *options) { ...@@ -220,19 +322,38 @@ void DeckManager::LoadLFList(irr::android::InitOptions *options) {
_lfList.push_back(nolimit); _lfList.push_back(nolimit);
} }
const wchar_t* DeckManager::GetLFListName(unsigned int lfhash) { const wchar_t* DeckManager::GetLFListName(unsigned int lfhash) {
// 在_lfList中搜索
auto lit = std::find_if(_lfList.begin(), _lfList.end(), [lfhash](const ygo::LFList& list) { auto lit = std::find_if(_lfList.begin(), _lfList.end(), [lfhash](const ygo::LFList& list) {
return list.hash == lfhash; return list.hash == lfhash;
}); });
if(lit != _lfList.end()) if(lit != _lfList.end())
return lit->listName.c_str(); return lit->listName.c_str();
// 在_genesys_lfList中搜索
auto glit = std::find_if(_genesys_lfList.begin(), _genesys_lfList.end(), [lfhash](const ygo::LFList& list) {
return list.hash == lfhash;
});
if(glit != _genesys_lfList.end())
return glit->listName.c_str();
return dataManager.unknown_string; return dataManager.unknown_string;
} }
const LFList* DeckManager::GetLFList(unsigned int lfhash) { const LFList* DeckManager::GetLFList(unsigned int lfhash) {
// 在_lfList中搜索
auto lit = std::find_if(_lfList.begin(), _lfList.end(), [lfhash](const ygo::LFList& list) { auto lit = std::find_if(_lfList.begin(), _lfList.end(), [lfhash](const ygo::LFList& list) {
return list.hash == lfhash; return list.hash == lfhash;
}); });
if (lit != _lfList.end()) if (lit != _lfList.end())
return &(*lit); return &(*lit);
// 在_genesys_lfList中搜索
auto glit = std::find_if(_genesys_lfList.begin(), _genesys_lfList.end(), [lfhash](const ygo::LFList& list) {
return list.hash == lfhash;
});
if (glit != _genesys_lfList.end())
return &(*glit);
return nullptr; return nullptr;
} }
static unsigned int checkAvail(unsigned int ot, unsigned int avail) { static unsigned int checkAvail(unsigned int ot, unsigned int avail) {
......
...@@ -735,7 +735,7 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) { ...@@ -735,7 +735,7 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) {
cbGenesysLFlist = irr::gui::CAndroidGUIComboBox::addAndroidComboBox(env, Resize(posX + 110, posY, posX + 230, posY + 30), wSettings, COMBOBOX_LFLIST); cbGenesysLFlist = irr::gui::CAndroidGUIComboBox::addAndroidComboBox(env, Resize(posX + 110, posY, posX + 230, posY + 30), wSettings, COMBOBOX_LFLIST);
cbGenesysLFlist->setMaxSelectionRows(6); cbGenesysLFlist->setMaxSelectionRows(6);
for(unsigned int i = 0; i < deckManager._genesys_lfList.size(); ++i) { for(unsigned int i = 0; i < deckManager._genesys_lfList.size(); ++i) {
cbLFlist->addItem(deckManager._genesys_lfList[i].listName.c_str()); cbGenesysLFlist->addItem(deckManager._genesys_lfList[i].listName.c_str());
if(!wcscmp(deckManager._genesys_lfList[i].listName.c_str(), gameConf.last_genesys_limit_list_name)) {//找到名称相同时找到对应的index值作为默认值 if(!wcscmp(deckManager._genesys_lfList[i].listName.c_str(), gameConf.last_genesys_limit_list_name)) {//找到名称相同时找到对应的index值作为默认值
gameConf.default_genesys_lflist = i; gameConf.default_genesys_lflist = i;
} }
...@@ -2031,6 +2031,9 @@ void Game::LoadConfig() { ...@@ -2031,6 +2031,9 @@ void Game::LoadConfig() {
// 获取 lastLimit 值并存储到 gameConf.last_limit_list_name // 获取 lastLimit 值并存储到 gameConf.last_limit_list_name
BufferIO::DecodeUTF8(irr::android::getLastLimit(appMain).c_str(), wstr); BufferIO::DecodeUTF8(irr::android::getLastLimit(appMain).c_str(), wstr);
BufferIO::CopyWStr(wstr, gameConf.last_limit_list_name, 64); BufferIO::CopyWStr(wstr, gameConf.last_limit_list_name, 64);
// 获取 lastGenesysLimit 值并存储到 gameConf.last_genesys_limit_list_name
BufferIO::DecodeUTF8(irr::android::getLastGenesysLimit(appMain).c_str(), wstr);
BufferIO::CopyWStr(wstr, gameConf.last_genesys_limit_list_name, 64);
ALOGW("cc game: lastLimit: %ls", wstr); ALOGW("cc game: lastLimit: %ls", wstr);
// 获取 lastCategory 值并存储到 gameConf.lastcategory // 获取 lastCategory 值并存储到 gameConf.lastcategory
BufferIO::DecodeUTF8(irr::android::getLastCategory(appMain).c_str(), wstr);; BufferIO::DecodeUTF8(irr::android::getLastCategory(appMain).c_str(), wstr);;
......
...@@ -414,6 +414,9 @@ float getYScale(ANDROID_APP app){ ...@@ -414,6 +414,9 @@ float getYScale(ANDROID_APP app){
irr::io::path getLastLimit(ANDROID_APP app) { irr::io::path getLastLimit(ANDROID_APP app) {
return getSetting(app, "lastlimit"); return getSetting(app, "lastlimit");
} }
irr::io::path getLastGenesysLimit(ANDROID_APP app) {
return getSetting(app, "lastGenesysLimit");
}
//Retrive last deck name. //Retrive last deck name.
irr::io::path getLastDeck(ANDROID_APP app) { irr::io::path getLastDeck(ANDROID_APP app) {
...@@ -506,6 +509,9 @@ irr::io::path getSetting(ANDROID_APP app, const char* key) { ...@@ -506,6 +509,9 @@ irr::io::path getSetting(ANDROID_APP app, const char* key) {
void setLastLimit(ANDROID_APP app, const char* limitname) { void setLastLimit(ANDROID_APP app, const char* limitname) {
saveSetting(app, "lastlimit", limitname); saveSetting(app, "lastlimit", limitname);
} }
void setLastGenesysLimit(ANDROID_APP app, const char* limitname) {
saveSetting(app, "lastGenesysLimit", limitname);
}
//save last deck name. //save last deck name.
void setLastDeck(ANDROID_APP app, const char* deckname) { void setLastDeck(ANDROID_APP app, const char* deckname) {
......
...@@ -161,6 +161,7 @@ extern irr::io::path getFontPath(ANDROID_APP app); ...@@ -161,6 +161,7 @@ extern irr::io::path getFontPath(ANDROID_APP app);
//Retrive last limit name. //Retrive last limit name.
extern irr::io::path getLastLimit(ANDROID_APP app); extern irr::io::path getLastLimit(ANDROID_APP app);
extern irr::io::path getLastGenesysLimit(ANDROID_APP app);
//Retrive last deck name. //Retrive last deck name.
extern irr::io::path getLastDeck(ANDROID_APP app); extern irr::io::path getLastDeck(ANDROID_APP app);
...@@ -174,6 +175,7 @@ extern irr::io::path getSetting(ANDROID_APP app, const char* key); ...@@ -174,6 +175,7 @@ extern irr::io::path getSetting(ANDROID_APP app, const char* key);
//save last limit name. //save last limit name.
extern void setLastLimit(ANDROID_APP app, const char* limitname); extern void setLastLimit(ANDROID_APP app, const char* limitname);
extern void setLastGenesysLimit(ANDROID_APP app, const char* limitname);
//save last deck name. //save last deck name.
extern void setLastDeck(ANDROID_APP app, const char* deckname); extern void setLastDeck(ANDROID_APP app, const char* deckname);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment