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) {
auto cur = _lfList.rend(); // 初始化迭代器,指向_lfList容器的反向末尾位置
FILE* fp = myfopen(path, "r"); auto cur = _lfList.rend();
char linebuf[256]{}; // 以只读模式打开指定路径的文件
wchar_t strBuffer[256]{}; FILE* fp = myfopen(path, "r");
if(fp) { // 定义字符缓冲区,用于存储从文件读取的单行内容
while(std::fgets(linebuf, sizeof linebuf, fp)) { char linebuf[256]{};
if(linebuf[0] == '#') // 定义宽字符缓冲区,用于存储转换后的字符串
continue; wchar_t strBuffer[256]{};
if(linebuf[0] == '!') { // 检查文件是否成功打开
auto len = std::strcspn(linebuf, "\r\n"); if(fp) {
linebuf[len] = 0; // 循环读取文件中的每一行,直到文件结束
BufferIO::DecodeUTF8(&linebuf[1], strBuffer); while(std::fgets(linebuf, sizeof linebuf, fp)) {
LFList newlist; // 跳过以#开头的注释行
newlist.listName = strBuffer; if(linebuf[0] == '#')
newlist.hash = 0x7dfcee6a; continue;
_lfList.push_back(newlist); // 处理以!开头的列表名称定义行
cur = _lfList.rbegin(); if(linebuf[0] == '!') {
continue; // 查找行中换行符或回车符的位置
} auto len = std::strcspn(linebuf, "\r\n");
if (cur == _lfList.rend()) // 在找到的位置添加字符串结束符
continue; linebuf[len] = 0;
if(linebuf[0] == '$') { // 将UTF-8编码的字符串转换为宽字符串
char* keyPos = linebuf + 1; BufferIO::DecodeUTF8(&linebuf[1], strBuffer);
keyPos += std::strspn(keyPos, " \t"); // 创建新的限制列表对象
auto keyLen = std::strcspn(keyPos, " \t\r\n"); LFList newlist;
if(!keyLen) // 设置列表名称
continue; newlist.listName = strBuffer;
char keybuf[256]; // 设置默认哈希值
if(keyLen >= sizeof keybuf) newlist.hash = 0x7dfcee6a;
keyLen = sizeof keybuf - 1; // 判断列表名称是否包含"genesys"(不区分大小写)
std::memcpy(keybuf, keyPos, keyLen); if(ContainsIgnoreCase(newlist.listName, L"Genesys")) {
keybuf[keyLen] = 0; _genesys_lfList.push_back(newlist);
keyPos += keyLen; // 更新cur迭代器,使其指向新添加的列表
keyPos += std::strspn(keyPos, " \t"); cur = _genesys_lfList.rbegin();
errno = 0; } else {
char* valuePos = keyPos; _lfList.push_back(newlist);
auto limitValue = std::strtoul(keyPos, &keyPos, 10); // 更新cur迭代器,使其指向新添加的列表
if(errno || valuePos == keyPos) cur = _lfList.rbegin();
continue; }
BufferIO::DecodeUTF8(keybuf, strBuffer); continue;
cur->credit_limits[strBuffer] = static_cast<uint32_t>(limitValue); }
continue; // 如果cur仍指向_lfList的反向末尾位置(即没有有效的列表),则跳过后续处理
} if (cur == _lfList.rend() || cur == _genesys_lfList.rend())
char* pos = linebuf; continue;
errno = 0; // 处理以$开头的信用限制定义行
char* codePos = pos; if(linebuf[0] == '$') {
auto result = std::strtoul(pos, &pos, 10); // 指向$符号后的第一个非空白字符
if(errno || result > UINT32_MAX || codePos == pos) char* keyPos = linebuf + 1;
continue; keyPos += std::strspn(keyPos, " \t");
if(*pos != ' ' && *pos != '\t') // 计算关键字的长度(到空白字符或行结束符为止)
continue; auto keyLen = std::strcspn(keyPos, " \t\r\n");
pos += std::strspn(pos, " \t"); // 如果关键字长度为0,则跳过
uint32_t code = static_cast<uint32_t>(result); if(!keyLen)
if(*pos == '$') { continue;
++pos; // 临时缓冲区,用于存储关键字
pos += std::strspn(pos, " \t"); char keybuf[256];
auto creditKeyLen = std::strcspn(pos, " \t\r\n"); // 确保关键字长度不超过缓冲区大小
if(!creditKeyLen) if(keyLen >= sizeof keybuf)
continue; keyLen = sizeof keybuf - 1;
char keybuf[256]; // 复制关键字到缓冲区
if(creditKeyLen >= sizeof keybuf) std::memcpy(keybuf, keyPos, keyLen);
creditKeyLen = sizeof keybuf - 1; // 添加字符串结束符
std::memcpy(keybuf, pos, creditKeyLen); keybuf[keyLen] = 0;
keybuf[creditKeyLen] = 0; // 移动到关键字后的第一个非空白字符
pos += creditKeyLen; keyPos += keyLen;
pos += std::strspn(pos, " \t"); keyPos += std::strspn(keyPos, " \t");
errno = 0; // 重置错误标志
char* creditValuePos = pos; errno = 0;
auto creditValue = std::strtoul(pos, &pos, 10); // 记录数值开始位置
if(errno || creditValuePos == pos) char* valuePos = keyPos;
continue; // 将字符串转换为无符号长整型
BufferIO::DecodeUTF8(keybuf, strBuffer); auto limitValue = std::strtoul(keyPos, &keyPos, 10);
cur->credits[code][strBuffer] = static_cast<uint32_t>(creditValue); // 如果转换出错或没有读取到数值,则跳过
continue; if(errno || valuePos == keyPos)
} continue;
errno = 0; // 将UTF-8编码的关键字转换为宽字符串
char* countPos = pos; BufferIO::DecodeUTF8(keybuf, strBuffer);
int count = std::strtol(pos, &pos, 10); // 在当前列表的信用限制映射中添加键值对
if(errno || countPos == pos) cur->credit_limits[strBuffer] = static_cast<uint32_t>(limitValue);
continue; continue;
if(count < 0 || count > 2) }
continue; // 从行的开始位置解析卡牌代码
cur->content[code] = count; char* pos = linebuf;
cur->hash = cur->hash ^ ((code << 18) | (code >> 14)) ^ ((code << (27 + count)) | (code >> (5 - count))); // 重置错误标志
} errno = 0;
} // 记录代码开始位置
char* codePos = pos;
// 将字符串转换为无符号长整型(卡牌代码)
auto result = std::strtoul(pos, &pos, 10);
// 如果转换出错、超出范围或没有读取到数值,则跳过
if(errno || result > UINT32_MAX || codePos == pos)
continue;
// 检查数值后是否跟有空格或制表符
if(*pos != ' ' && *pos != '\t')
continue;
// 跳过空格和制表符
pos += std::strspn(pos, " \t");
// 将结果转换为32位无符号整型
uint32_t code = static_cast<uint32_t>(result);
// 处理包含信用分的行(以$开头)
if(*pos == '$') {
// 跳过$符号
++pos;
// 跳过空白字符
pos += std::strspn(pos, " \t");
// 获取信用分键的长度
auto creditKeyLen = std::strcspn(pos, " \t\r\n");
// 如果键长度为0,则跳过
if(!creditKeyLen)
continue;
// 临时缓冲区存储信用分键
char keybuf[256];
// 确保键长度不超过缓冲区大小
if(creditKeyLen >= sizeof keybuf)
creditKeyLen = sizeof keybuf - 1;
// 复制键到缓冲区
std::memcpy(keybuf, pos, creditKeyLen);
// 添加字符串结束符
keybuf[creditKeyLen] = 0;
// 跳过键后的空白字符
pos += creditKeyLen;
pos += std::strspn(pos, " \t");
// 重置错误标志
errno = 0;
// 记录信用分数值开始位置
char* creditValuePos = pos;
// 将字符串转换为无符号长整型(信用分数值)
auto creditValue = std::strtoul(pos, &pos, 10);
// 如果转换出错或没有读取到数值,则跳过
if(errno || creditValuePos == pos)
continue;
// 将UTF-8编码的键转换为宽字符串
BufferIO::DecodeUTF8(keybuf, strBuffer);
// 在当前列表的卡牌信用分映射中添加键值对
cur->credits[code][strBuffer] = static_cast<uint32_t>(creditValue);
continue;
}
// 重置错误标志
errno = 0;
// 记录数量开始位置
char* countPos = pos;
// 将字符串转换为长整型(卡牌数量限制)
int count = std::strtol(pos, &pos, 10);
// 如果转换出错或没有读取到数值,则跳过
if(errno || countPos == pos)
continue;
// 检查数量是否在有效范围内(0-2)
if(count < 0 || count > 2)
continue;
// 将卡牌代码和数量限制添加到当前列表的内容映射中
cur->content[code] = 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;
_lfList.push_back(newlist); // 判断列表名称是否包含"genesys"(不区分大小写)
cur = _lfList.rbegin(); if(ContainsIgnoreCase(newlist.listName, L"Genesys")) {
_genesys_lfList.push_back(newlist);
cur = _genesys_lfList.rbegin();
} else {
_lfList.push_back(newlist);
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;
...@@ -206,7 +308,7 @@ void DeckManager::LoadLFListSingle(irr::io::IReadFile* reader) { ...@@ -206,7 +308,7 @@ void DeckManager::LoadLFListSingle(irr::io::IReadFile* reader) {
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)));
} }
} }
void DeckManager::LoadLFList(irr::android::InitOptions *options) { void DeckManager::LoadLFList(irr::android::InitOptions *options) {
...@@ -220,20 +322,39 @@ void DeckManager::LoadLFList(irr::android::InitOptions *options) { ...@@ -220,20 +322,39 @@ 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) {
auto lit = std::find_if(_lfList.begin(), _lfList.end(), [lfhash](const ygo::LFList& list) { // 在_lfList中搜索
return list.hash == lfhash; auto lit = std::find_if(_lfList.begin(), _lfList.end(), [lfhash](const ygo::LFList& list) {
}); return list.hash == lfhash;
if(lit != _lfList.end()) });
return lit->listName.c_str(); if(lit != _lfList.end())
return dataManager.unknown_string; 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;
} }
const LFList* DeckManager::GetLFList(unsigned int lfhash) { const LFList* DeckManager::GetLFList(unsigned int lfhash) {
auto lit = std::find_if(_lfList.begin(), _lfList.end(), [lfhash](const ygo::LFList& list) { // 在_lfList中搜索
return list.hash == lfhash; auto lit = std::find_if(_lfList.begin(), _lfList.end(), [lfhash](const ygo::LFList& list) {
}); return list.hash == lfhash;
if (lit != _lfList.end()) });
return &(*lit); if (lit != _lfList.end())
return nullptr; 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;
} }
static unsigned int checkAvail(unsigned int ot, unsigned int avail) { static unsigned int checkAvail(unsigned int ot, unsigned int avail) {
if((ot & avail) == avail) if((ot & avail) == 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