Commit 647056c2 authored by nanahira's avatar nanahira

Merge branch 'patch-random-replay' of github.com:Fluorohydride/ygopro into develop

parents 280e88ba 633adaba
...@@ -99,23 +99,23 @@ jobs: ...@@ -99,23 +99,23 @@ jobs:
id: lua id: lua
uses: mercury233/action-cache-download-file@v1.0.0 uses: mercury233/action-cache-download-file@v1.0.0
with: with:
url: https://www.lua.org/ftp/lua-5.4.7.tar.gz url: https://www.lua.org/ftp/lua-5.4.8.tar.gz
- name: Extract lua - name: Extract lua
run: | run: |
tar xf ${{ steps.lua.outputs.filepath }} tar xf ${{ steps.lua.outputs.filepath }}
move lua-5.4.7 lua move lua-5.4.8 lua
- name: Download sqlite - name: Download sqlite
id: sqlite id: sqlite
uses: mercury233/action-cache-download-file@v1.0.0 uses: mercury233/action-cache-download-file@v1.0.0
with: with:
url: https://www.sqlite.org/2025/sqlite-amalgamation-3490100.zip url: https://www.sqlite.org/2025/sqlite-amalgamation-3500100.zip
- name: Extract sqlite - name: Extract sqlite
run: | run: |
7z x ${{ steps.sqlite.outputs.filepath }} 7z x ${{ steps.sqlite.outputs.filepath }}
move sqlite-amalgamation-3490100 sqlite3 move sqlite-amalgamation-3500100 sqlite3
- name: Download miniaudio - name: Download miniaudio
if: matrix.audiolib == 'miniaudio' if: matrix.audiolib == 'miniaudio'
...@@ -345,25 +345,25 @@ jobs: ...@@ -345,25 +345,25 @@ jobs:
id: lua id: lua
uses: mercury233/action-cache-download-file@v1.0.0 uses: mercury233/action-cache-download-file@v1.0.0
with: with:
url: https://www.lua.org/ftp/lua-5.4.7.tar.gz url: https://www.lua.org/ftp/lua-5.4.8.tar.gz
- name: Extract lua - name: Extract lua
run: | run: |
tar xf ${{ steps.lua.outputs.filepath }} tar xf ${{ steps.lua.outputs.filepath }}
mv lua-5.4.7 lua mv lua-5.4.8 lua
- name: Download sqlite - name: Download sqlite
if: matrix.static-link == true if: matrix.static-link == true
id: sqlite id: sqlite
uses: mercury233/action-cache-download-file@v1.0.0 uses: mercury233/action-cache-download-file@v1.0.0
with: with:
url: https://www.sqlite.org/2025/sqlite-amalgamation-3490100.zip url: https://www.sqlite.org/2025/sqlite-amalgamation-3500100.zip
- name: Extract sqlite - name: Extract sqlite
if: matrix.static-link == true if: matrix.static-link == true
run: | run: |
7z x ${{ steps.sqlite.outputs.filepath }} 7z x ${{ steps.sqlite.outputs.filepath }}
mv sqlite-amalgamation-3490100 sqlite3 mv sqlite-amalgamation-3500100 sqlite3
- name: Download miniaudio - name: Download miniaudio
run: | run: |
...@@ -579,25 +579,25 @@ jobs: ...@@ -579,25 +579,25 @@ jobs:
id: lua id: lua
uses: mercury233/action-cache-download-file@v1.0.0 uses: mercury233/action-cache-download-file@v1.0.0
with: with:
url: https://www.lua.org/ftp/lua-5.4.7.tar.gz url: https://www.lua.org/ftp/lua-5.4.8.tar.gz
- name: Extract lua - name: Extract lua
run: | run: |
tar xf ${{ steps.lua.outputs.filepath }} tar xf ${{ steps.lua.outputs.filepath }}
mv lua-5.4.7 lua mv lua-5.4.8 lua
- name: Download sqlite - name: Download sqlite
if: matrix.static-link == true if: matrix.static-link == true
id: sqlite id: sqlite
uses: mercury233/action-cache-download-file@v1.0.0 uses: mercury233/action-cache-download-file@v1.0.0
with: with:
url: https://www.sqlite.org/2025/sqlite-amalgamation-3490100.zip url: https://www.sqlite.org/2025/sqlite-amalgamation-3500100.zip
- name: Extract sqlite - name: Extract sqlite
if: matrix.static-link == true if: matrix.static-link == true
run: | run: |
7z x ${{ steps.sqlite.outputs.filepath }} 7z x ${{ steps.sqlite.outputs.filepath }}
mv sqlite-amalgamation-3490100 sqlite3 mv sqlite-amalgamation-3500100 sqlite3
- name: Download miniaudio - name: Download miniaudio
run: | run: |
......
...@@ -438,6 +438,29 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) { ...@@ -438,6 +438,29 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
prev_operation = id; prev_operation = id;
break; break;
} }
case BUTTON_IMPORT_DECK_CODE: {
time_t nowtime = std::time(nullptr);
wchar_t timetext[40];
std::wcsftime(timetext, sizeof timetext / sizeof timetext[0], L"%Y-%m-%d %H-%M-%S", std::localtime(&nowtime));
mainGame->gMutex.lock();
mainGame->stDMMessage->setText(dataManager.GetSysString(1471));
mainGame->ebDMName->setVisible(true);
mainGame->ebDMName->setText(timetext);
mainGame->PopupElement(mainGame->wDMQuery);
mainGame->gMutex.unlock();
prev_operation = id;
break;
}
case BUTTON_EXPORT_DECK_CODE: {
std::stringstream textStream;
deckManager.SaveDeck(deckManager.current_deck, textStream);
wchar_t text[0x10000];
BufferIO::DecodeUTF8(textStream.str().c_str(), text);
mainGame->env->getOSOperator()->copyToClipboard(text);
mainGame->stACMessage->setText(dataManager.GetSysString(1480));
mainGame->PopupElement(mainGame->wACMessage, 20);
break;
}
case BUTTON_DM_OK: { case BUTTON_DM_OK: {
switch(prev_operation) { switch(prev_operation) {
case BUTTON_NEW_CATEGORY: { case BUTTON_NEW_CATEGORY: {
...@@ -514,7 +537,8 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) { ...@@ -514,7 +537,8 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
} }
break; break;
} }
case BUTTON_NEW_DECK: { case BUTTON_NEW_DECK:
case BUTTON_IMPORT_DECK_CODE: {
const wchar_t* deckname = mainGame->ebDMName->getText(); const wchar_t* deckname = mainGame->ebDMName->getText();
wchar_t catepath[256]; wchar_t catepath[256];
DeckManager::GetCategoryPath(catepath, mainGame->cbDBCategory->getSelected(), mainGame->cbDBCategory->getText()); DeckManager::GetCategoryPath(catepath, mainGame->cbDBCategory->getSelected(), mainGame->cbDBCategory->getText());
...@@ -522,9 +546,19 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) { ...@@ -522,9 +546,19 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
myswprintf(filepath, L"%ls/%ls.ydk", catepath, deckname); myswprintf(filepath, L"%ls/%ls.ydk", catepath, deckname);
bool res = false; bool res = false;
if(!FileSystem::IsFileExists(filepath)) { if(!FileSystem::IsFileExists(filepath)) {
deckManager.current_deck.main.clear(); if(prev_operation == BUTTON_NEW_DECK) {
deckManager.current_deck.extra.clear(); deckManager.current_deck.main.clear();
deckManager.current_deck.side.clear(); deckManager.current_deck.extra.clear();
deckManager.current_deck.side.clear();
} else {
const wchar_t* txt = mainGame->env->getOSOperator()->getTextFromClipboard();
if(txt) {
char text[0x10000];
BufferIO::EncodeUTF8(txt, text);
std::istringstream textStream(text);
deckManager.LoadCurrentDeck(textStream);
}
}
res = DeckManager::SaveDeck(deckManager.current_deck, filepath); res = DeckManager::SaveDeck(deckManager.current_deck, filepath);
RefreshDeckList(); RefreshDeckList();
ChangeCategory(mainGame->lstCategories->getSelected()); ChangeCategory(mainGame->lstCategories->getSelected());
......
...@@ -282,6 +282,10 @@ irr::io::IReadFile* DeckManager::OpenDeckReader(const wchar_t* file) { ...@@ -282,6 +282,10 @@ irr::io::IReadFile* DeckManager::OpenDeckReader(const wchar_t* file) {
#endif #endif
return reader; return reader;
} }
bool DeckManager::LoadCurrentDeck(std::istringstream& deckStream, bool is_packlist) {
LoadDeckFromStream(current_deck, deckStream, is_packlist);
return true; // the above LoadDeck has return value but we ignore it here for now
}
bool DeckManager::LoadCurrentDeck(const wchar_t* file, bool is_packlist) { bool DeckManager::LoadCurrentDeck(const wchar_t* file, bool is_packlist) {
current_deck.clear(); current_deck.clear();
auto reader = OpenDeckReader(file); auto reader = OpenDeckReader(file);
...@@ -316,21 +320,27 @@ bool DeckManager::LoadCurrentDeck(int category_index, const wchar_t* category_na ...@@ -316,21 +320,27 @@ bool DeckManager::LoadCurrentDeck(int category_index, const wchar_t* category_na
mainGame->deckBuilder.RefreshPackListScroll(); mainGame->deckBuilder.RefreshPackListScroll();
return res; return res;
} }
void DeckManager::SaveDeck(const Deck& deck, std::stringstream& deckStream) {
deckStream << "#created by ..." << std::endl;
deckStream << "#main" << std::endl;
for(size_t i = 0; i < deck.main.size(); ++i)
deckStream << deck.main[i]->first << std::endl;
deckStream << "#extra" << std::endl;
for(size_t i = 0; i < deck.extra.size(); ++i)
deckStream << deck.extra[i]->first << std::endl;
deckStream << "!side" << std::endl;
for(size_t i = 0; i < deck.side.size(); ++i)
deckStream << deck.side[i]->first << std::endl;
}
bool DeckManager::SaveDeck(const Deck& deck, const wchar_t* file) { bool DeckManager::SaveDeck(const Deck& deck, const wchar_t* file) {
if(!FileSystem::IsDirExists(L"./deck") && !FileSystem::MakeDir(L"./deck")) if(!FileSystem::IsDirExists(L"./deck") && !FileSystem::MakeDir(L"./deck"))
return false; return false;
FILE* fp = OpenDeckFile(file, "w"); FILE* fp = OpenDeckFile(file, "w");
if(!fp) if(!fp)
return false; return false;
std::fprintf(fp, "#created by ...\n#main\n"); std::stringstream deckStream;
for(size_t i = 0; i < deck.main.size(); ++i) SaveDeck(deck, deckStream);
std::fprintf(fp, "%u\n", deck.main[i]->first); std::fwrite(deckStream.str().c_str(), 1, deckStream.str().length(), fp);
std::fprintf(fp, "#extra\n");
for(size_t i = 0; i < deck.extra.size(); ++i)
std::fprintf(fp, "%u\n", deck.extra[i]->first);
std::fprintf(fp, "!side\n");
for(size_t i = 0; i < deck.side.size(); ++i)
std::fprintf(fp, "%u\n", deck.side[i]->first);
std::fclose(fp); std::fclose(fp);
return true; return true;
} }
......
...@@ -74,6 +74,7 @@ public: ...@@ -74,6 +74,7 @@ public:
unsigned int CheckDeck(const Deck& deck, unsigned int lfhash, int rule); unsigned int CheckDeck(const Deck& deck, unsigned int lfhash, int rule);
bool LoadCurrentDeck(const wchar_t* file, bool is_packlist = false); bool LoadCurrentDeck(const wchar_t* file, bool is_packlist = false);
bool LoadCurrentDeck(int category_index, const wchar_t* category_name, const wchar_t* deckname); bool LoadCurrentDeck(int category_index, const wchar_t* category_name, const wchar_t* deckname);
bool LoadCurrentDeck(std::istringstream& deckStream, bool is_packlist = false);
wchar_t DeckFormatBuffer[128]; wchar_t DeckFormatBuffer[128];
int TypeCount(std::vector<code_pointer> list, unsigned int ctype); int TypeCount(std::vector<code_pointer> list, unsigned int ctype);
bool LoadDeckFromCode(Deck& deck, const unsigned char *code, int len); bool LoadDeckFromCode(Deck& deck, const unsigned char *code, int len);
...@@ -87,6 +88,7 @@ public: ...@@ -87,6 +88,7 @@ public:
static FILE* OpenDeckFile(const wchar_t* file, const char* mode); static FILE* OpenDeckFile(const wchar_t* file, const char* mode);
static irr::io::IReadFile* OpenDeckReader(const wchar_t* file); static irr::io::IReadFile* OpenDeckReader(const wchar_t* file);
static bool SaveDeck(const Deck& deck, const wchar_t* file); static bool SaveDeck(const Deck& deck, const wchar_t* file);
static void SaveDeck(const Deck& deck, std::stringstream& deckStream);
static bool DeleteDeck(const wchar_t* file); static bool DeleteDeck(const wchar_t* file);
static bool CreateCategory(const wchar_t* name); static bool CreateCategory(const wchar_t* name);
static bool RenameCategory(const wchar_t* oldname, const wchar_t* newname); static bool RenameCategory(const wchar_t* oldname, const wchar_t* newname);
......
...@@ -828,7 +828,7 @@ void DuelClient::HandleSTOCPacketLan(unsigned char* data, int len) { ...@@ -828,7 +828,7 @@ void DuelClient::HandleSTOCPacketLan(unsigned char* data, int len) {
break; break;
} }
case STOC_REPLAY: { case STOC_REPLAY: {
if (len < 1 + (int)sizeof(ReplayHeader)) if (len < 1 + (int)sizeof(ExtendedReplayHeader))
return; return;
mainGame->gMutex.lock(); mainGame->gMutex.lock();
mainGame->wPhase->setVisible(false); mainGame->wPhase->setVisible(false);
...@@ -839,10 +839,10 @@ void DuelClient::HandleSTOCPacketLan(unsigned char* data, int len) { ...@@ -839,10 +839,10 @@ void DuelClient::HandleSTOCPacketLan(unsigned char* data, int len) {
Replay new_replay; Replay new_replay;
std::memcpy(&new_replay.pheader, prep, sizeof(new_replay.pheader)); std::memcpy(&new_replay.pheader, prep, sizeof(new_replay.pheader));
time_t starttime; time_t starttime;
if (new_replay.pheader.flag & REPLAY_UNIFORM) if (new_replay.pheader.base.flag & REPLAY_UNIFORM)
starttime = new_replay.pheader.start_time; starttime = new_replay.pheader.base.start_time;
else else
starttime = new_replay.pheader.seed; starttime = new_replay.pheader.base.seed;
wchar_t timetext[40]; wchar_t timetext[40];
std::wcsftime(timetext, sizeof timetext / sizeof timetext[0], L"%Y-%m-%d %H-%M-%S", std::localtime(&starttime)); std::wcsftime(timetext, sizeof timetext / sizeof timetext[0], L"%Y-%m-%d %H-%M-%S", std::localtime(&starttime));
...@@ -866,9 +866,9 @@ void DuelClient::HandleSTOCPacketLan(unsigned char* data, int len) { ...@@ -866,9 +866,9 @@ void DuelClient::HandleSTOCPacketLan(unsigned char* data, int len) {
mainGame->WaitFrameSignal(30); mainGame->WaitFrameSignal(30);
} }
if(mainGame->actionParam || !is_host) { if(mainGame->actionParam || !is_host) {
prep += sizeof(ReplayHeader); prep += sizeof new_replay.pheader;
std::memcpy(new_replay.comp_data, prep, len - sizeof(ReplayHeader) - 1); std::memcpy(new_replay.comp_data, prep, len - sizeof new_replay.pheader - 1);
new_replay.comp_size = len - sizeof(ReplayHeader) - 1; new_replay.comp_size = len - sizeof new_replay.pheader - 1;
if(mainGame->actionParam) if(mainGame->actionParam)
new_replay.SaveReplay(mainGame->ebRSName->getText()); new_replay.SaveReplay(mainGame->ebRSName->getText());
else else
......
...@@ -691,10 +691,10 @@ bool Game::Initialize() { ...@@ -691,10 +691,10 @@ bool Game::Initialize() {
wDeckEdit->setVisible(false); wDeckEdit->setVisible(false);
btnManageDeck = env->addButton(irr::core::rect<irr::s32>(225, 5, 290, 30), wDeckEdit, BUTTON_MANAGE_DECK, dataManager.GetSysString(1328)); btnManageDeck = env->addButton(irr::core::rect<irr::s32>(225, 5, 290, 30), wDeckEdit, BUTTON_MANAGE_DECK, dataManager.GetSysString(1328));
//deck manage //deck manage
wDeckManage = env->addWindow(irr::core::rect<irr::s32>(310, 135, 800, 465), false, dataManager.GetSysString(1460), 0, WINDOW_DECK_MANAGE); wDeckManage = env->addWindow(irr::core::rect<irr::s32>(310, 135, 800, 515), false, dataManager.GetSysString(1460), 0, WINDOW_DECK_MANAGE);
wDeckManage->setVisible(false); wDeckManage->setVisible(false);
lstCategories = env->addListBox(irr::core::rect<irr::s32>(10, 30, 140, 320), wDeckManage, LISTBOX_CATEGORIES, true); lstCategories = env->addListBox(irr::core::rect<irr::s32>(10, 30, 140, 370), wDeckManage, LISTBOX_CATEGORIES, true);
lstDecks = env->addListBox(irr::core::rect<irr::s32>(150, 30, 340, 320), wDeckManage, LISTBOX_DECKS, true); lstDecks = env->addListBox(irr::core::rect<irr::s32>(150, 30, 340, 370), wDeckManage, LISTBOX_DECKS, true);
posY = 30; posY = 30;
btnNewCategory = env->addButton(irr::core::rect<irr::s32>(350, posY, 480, posY + 25), wDeckManage, BUTTON_NEW_CATEGORY, dataManager.GetSysString(1461)); btnNewCategory = env->addButton(irr::core::rect<irr::s32>(350, posY, 480, posY + 25), wDeckManage, BUTTON_NEW_CATEGORY, dataManager.GetSysString(1461));
posY += 35; posY += 35;
...@@ -711,6 +711,10 @@ bool Game::Initialize() { ...@@ -711,6 +711,10 @@ bool Game::Initialize() {
btnMoveDeck = env->addButton(irr::core::rect<irr::s32>(350, posY, 480, posY + 25), wDeckManage, BUTTON_MOVE_DECK, dataManager.GetSysString(1467)); btnMoveDeck = env->addButton(irr::core::rect<irr::s32>(350, posY, 480, posY + 25), wDeckManage, BUTTON_MOVE_DECK, dataManager.GetSysString(1467));
posY += 35; posY += 35;
btnCopyDeck = env->addButton(irr::core::rect<irr::s32>(350, posY, 480, posY + 25), wDeckManage, BUTTON_COPY_DECK, dataManager.GetSysString(1468)); btnCopyDeck = env->addButton(irr::core::rect<irr::s32>(350, posY, 480, posY + 25), wDeckManage, BUTTON_COPY_DECK, dataManager.GetSysString(1468));
posY += 35;
btnImportDeckCode = env->addButton(irr::core::rect<irr::s32>(350, posY, 480, posY + 25), wDeckManage, BUTTON_IMPORT_DECK_CODE, dataManager.GetSysString(1478));
posY += 35;
btnExportDeckCode = env->addButton(irr::core::rect<irr::s32>(350, posY, 480, posY + 25), wDeckManage, BUTTON_EXPORT_DECK_CODE, dataManager.GetSysString(1479));
//deck manage query //deck manage query
wDMQuery = env->addWindow(irr::core::rect<irr::s32>(400, 200, 710, 320), false, dataManager.GetSysString(1460)); wDMQuery = env->addWindow(irr::core::rect<irr::s32>(400, 200, 710, 320), false, dataManager.GetSysString(1460));
wDMQuery->getCloseButton()->setVisible(false); wDMQuery->getCloseButton()->setVisible(false);
...@@ -2253,7 +2257,7 @@ void Game::OnResize() { ...@@ -2253,7 +2257,7 @@ void Game::OnResize() {
ebDeckname->setRelativePosition(Resize(80, 65, 220, 90)); ebDeckname->setRelativePosition(Resize(80, 65, 220, 90));
cbDBCategory->setRelativePosition(Resize(80, 5, 220, 30)); cbDBCategory->setRelativePosition(Resize(80, 5, 220, 30));
btnManageDeck->setRelativePosition(Resize(225, 5, 290, 30)); btnManageDeck->setRelativePosition(Resize(225, 5, 290, 30));
wDeckManage->setRelativePosition(ResizeWin(310, 135, 800, 465)); wDeckManage->setRelativePosition(ResizeWin(310, 135, 800, 515));
scrPackCards->setRelativePosition(Resize(775, 161, 795, 629)); scrPackCards->setRelativePosition(Resize(775, 161, 795, 629));
wSort->setRelativePosition(Resize(930, 132, 1020, 156)); wSort->setRelativePosition(Resize(930, 132, 1020, 156));
......
...@@ -626,6 +626,8 @@ public: ...@@ -626,6 +626,8 @@ public:
irr::gui::IGUIButton* btnDMDeleteDeck; irr::gui::IGUIButton* btnDMDeleteDeck;
irr::gui::IGUIButton* btnMoveDeck; irr::gui::IGUIButton* btnMoveDeck;
irr::gui::IGUIButton* btnCopyDeck; irr::gui::IGUIButton* btnCopyDeck;
irr::gui::IGUIButton* btnImportDeckCode;
irr::gui::IGUIButton* btnExportDeckCode;
irr::gui::IGUIWindow* wDMQuery; irr::gui::IGUIWindow* wDMQuery;
irr::gui::IGUIStaticText* stDMMessage; irr::gui::IGUIStaticText* stDMMessage;
irr::gui::IGUIStaticText* stDMMessage2; irr::gui::IGUIStaticText* stDMMessage2;
...@@ -880,6 +882,8 @@ extern Game* mainGame; ...@@ -880,6 +882,8 @@ extern Game* mainGame;
#define LISTBOX_DECKS 340 #define LISTBOX_DECKS 340
#define BUTTON_DM_OK 341 #define BUTTON_DM_OK 341
#define BUTTON_DM_CANCEL 342 #define BUTTON_DM_CANCEL 342
#define BUTTON_IMPORT_DECK_CODE 343
#define BUTTON_EXPORT_DECK_CODE 344
#define COMBOBOX_LFLIST 349 #define COMBOBOX_LFLIST 349
#define BUTTON_CLEAR_LOG 350 #define BUTTON_CLEAR_LOG 350
......
...@@ -290,7 +290,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) { ...@@ -290,7 +290,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
myswprintf(replay_path, L"./replay/%ls", replay_filename); myswprintf(replay_path, L"./replay/%ls", replay_filename);
if (!replay.OpenReplay(replay_path)) if (!replay.OpenReplay(replay_path))
break; break;
if (replay.pheader.flag & REPLAY_SINGLE_MODE) if (replay.pheader.base.flag & REPLAY_SINGLE_MODE)
break; break;
for (size_t i = 0; i < replay.decks.size(); ++i) { for (size_t i = 0; i < replay.decks.size(); ++i) {
BufferIO::CopyWideString(replay.players[Replay::GetDeckPlayer(i)].c_str(), namebuf[i]); BufferIO::CopyWideString(replay.players[Replay::GetDeckPlayer(i)].c_str(), namebuf[i]);
...@@ -516,24 +516,25 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) { ...@@ -516,24 +516,25 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
wchar_t infobuf[256]{}; wchar_t infobuf[256]{};
std::wstring repinfo; std::wstring repinfo;
time_t curtime; time_t curtime;
if(temp_replay.pheader.flag & REPLAY_UNIFORM) const auto& rh = temp_replay.pheader.base;
curtime = temp_replay.pheader.start_time; if(temp_replay.pheader.base.flag & REPLAY_UNIFORM)
curtime = rh.start_time;
else{ else{
curtime = temp_replay.pheader.seed; curtime = rh.seed;
wchar_t version_info[256]{}; wchar_t version_info[256]{};
myswprintf(version_info, L"version 0x%X\n", temp_replay.pheader.version); myswprintf(version_info, L"version 0x%X\n", rh.version);
repinfo.append(version_info); repinfo.append(version_info);
} }
std::wcsftime(infobuf, sizeof infobuf / sizeof infobuf[0], L"%Y/%m/%d %H:%M:%S\n", std::localtime(&curtime)); std::wcsftime(infobuf, sizeof infobuf / sizeof infobuf[0], L"%Y/%m/%d %H:%M:%S\n", std::localtime(&curtime));
repinfo.append(infobuf); repinfo.append(infobuf);
if (temp_replay.pheader.flag & REPLAY_SINGLE_MODE) { if (rh.flag & REPLAY_SINGLE_MODE) {
wchar_t path[256]{}; wchar_t path[256]{};
BufferIO::DecodeUTF8(temp_replay.script_name.c_str(), path); BufferIO::DecodeUTF8(temp_replay.script_name.c_str(), path);
repinfo.append(path); repinfo.append(path);
repinfo.append(L"\n"); repinfo.append(L"\n");
} }
const auto& player_names = temp_replay.players; const auto& player_names = temp_replay.players;
if(temp_replay.pheader.flag & REPLAY_TAG) if(rh.flag & REPLAY_TAG)
myswprintf(infobuf, L"%ls\n%ls\n===VS===\n%ls\n%ls\n", player_names[0].c_str(), player_names[1].c_str(), player_names[2].c_str(), player_names[3].c_str()); myswprintf(infobuf, L"%ls\n%ls\n===VS===\n%ls\n%ls\n", player_names[0].c_str(), player_names[1].c_str(), player_names[2].c_str(), player_names[3].c_str());
else else
myswprintf(infobuf, L"%ls\n===VS===\n%ls\n", player_names[0].c_str(), player_names[1].c_str()); myswprintf(infobuf, L"%ls\n===VS===\n%ls\n", player_names[0].c_str(), player_names[1].c_str());
......
...@@ -282,7 +282,7 @@ public: ...@@ -282,7 +282,7 @@ public:
#define STOC_LEAVE_GAME 0x14 // reserved #define STOC_LEAVE_GAME 0x14 // reserved
#define STOC_DUEL_START 0x15 // no data #define STOC_DUEL_START 0x15 // no data
#define STOC_DUEL_END 0x16 // no data #define STOC_DUEL_END 0x16 // no data
#define STOC_REPLAY 0x17 // ReplayHeader + byte array #define STOC_REPLAY 0x17 // ExtendedReplayHeader + byte array
#define STOC_TIME_LIMIT 0x18 // STOC_TimeLimit #define STOC_TIME_LIMIT 0x18 // STOC_TimeLimit
#define STOC_CHAT 0x19 // uint16_t + uint16_t array #define STOC_CHAT 0x19 // uint16_t + uint16_t array
#define STOC_HS_PLAYER_ENTER 0x20 // STOC_HS_PlayerEnter #define STOC_HS_PLAYER_ENTER 0x20 // STOC_HS_PlayerEnter
......
...@@ -32,7 +32,7 @@ void Replay::BeginRecord() { ...@@ -32,7 +32,7 @@ void Replay::BeginRecord() {
Reset(); Reset();
is_recording = true; is_recording = true;
} }
void Replay::WriteHeader(ReplayHeader& header) { void Replay::WriteHeader(ExtendedReplayHeader& header) {
pheader = header; pheader = header;
#ifdef _WIN32 #ifdef _WIN32
DWORD size; DWORD size;
...@@ -77,11 +77,11 @@ void Replay::EndRecord() { ...@@ -77,11 +77,11 @@ void Replay::EndRecord() {
#else #else
std::fclose(fp); std::fclose(fp);
#endif #endif
pheader.datasize = replay_size; pheader.base.datasize = replay_size;
pheader.flag |= REPLAY_COMPRESSED; pheader.base.flag |= REPLAY_COMPRESSED;
size_t propsize = 5; size_t propsize = 5;
comp_size = MAX_COMP_SIZE; comp_size = MAX_COMP_SIZE;
int ret = LzmaCompress(comp_data, &comp_size, replay_data, replay_size, pheader.props, &propsize, 5, 0x1U << 24, 3, 0, 2, 32, 1); int ret = LzmaCompress(comp_data, &comp_size, replay_data, replay_size, pheader.base.props, &propsize, 5, 0x1U << 24, 3, 0, 2, 32, 1);
if (ret != SZ_OK) { if (ret != SZ_OK) {
std::memcpy(comp_data, &ret, sizeof ret); std::memcpy(comp_data, &ret, sizeof ret);
comp_size = sizeof ret; comp_size = sizeof ret;
...@@ -112,27 +112,31 @@ bool Replay::OpenReplay(const wchar_t* name) { ...@@ -112,27 +112,31 @@ bool Replay::OpenReplay(const wchar_t* name) {
Reset(); Reset();
bool correct_header = true; bool correct_header = true;
if (std::fread(&pheader, sizeof pheader, 1, rfp) < 1) if (std::fread(&pheader, sizeof pheader.base, 1, rfp) < 1)
correct_header = false; correct_header = false;
else if (pheader.id != 0x31707279) else if (pheader.base.id != REPLAY_ID_YRP1 && pheader.base.id != REPLAY_ID_YRP2)
correct_header = false; correct_header = false;
else if (pheader.version < 0x12d0u) else if (pheader.base.version < 0x12d0u)
correct_header = false; correct_header = false;
else if (pheader.version >= 0x1353u && !(pheader.flag & REPLAY_UNIFORM)) else if (pheader.base.version >= 0x1353u && !(pheader.base.flag & REPLAY_UNIFORM))
correct_header = false; correct_header = false;
if (!correct_header) { if (!correct_header) {
std::fclose(rfp); std::fclose(rfp);
return false; return false;
} }
if(pheader.flag & REPLAY_COMPRESSED) { if (pheader.base.id == REPLAY_ID_YRP2 && std::fread((uint8_t*)(&pheader) + sizeof pheader.base, sizeof pheader - sizeof pheader.base, 1, rfp) < 1) {
std::fclose(rfp);
return false;
}
if(pheader.base.flag & REPLAY_COMPRESSED) {
comp_size = std::fread(comp_data, 1, MAX_COMP_SIZE, rfp); comp_size = std::fread(comp_data, 1, MAX_COMP_SIZE, rfp);
std::fclose(rfp); std::fclose(rfp);
if (pheader.datasize > MAX_REPLAY_SIZE) if (pheader.base.datasize > MAX_REPLAY_SIZE)
return false; return false;
replay_size = pheader.datasize; replay_size = pheader.base.datasize;
if (LzmaUncompress(replay_data, &replay_size, comp_data, &comp_size, pheader.props, 5) != SZ_OK) if (LzmaUncompress(replay_data, &replay_size, comp_data, &comp_size, pheader.base.props, 5) != SZ_OK)
return false; return false;
if (replay_size != pheader.datasize) { if (replay_size != pheader.base.datasize) {
replay_size = 0; replay_size = 0;
return false; return false;
} }
...@@ -189,7 +193,7 @@ bool Replay::ReadName(wchar_t* data) { ...@@ -189,7 +193,7 @@ bool Replay::ReadName(wchar_t* data) {
BufferIO::CopyWStr(buffer, data, 20); BufferIO::CopyWStr(buffer, data, 20);
return true; return true;
} }
void Replay::ReadHeader(ReplayHeader& header) { void Replay::ReadHeader(ExtendedReplayHeader& header) {
header = pheader; header = pheader;
} }
bool Replay::ReadData(void* data, size_t length) { bool Replay::ReadData(void* data, size_t length) {
...@@ -232,7 +236,7 @@ bool Replay::IsReplaying() const { ...@@ -232,7 +236,7 @@ bool Replay::IsReplaying() const {
return is_replaying; return is_replaying;
} }
bool Replay::ReadInfo() { bool Replay::ReadInfo() {
int player_count = (pheader.flag & REPLAY_TAG) ? 4 : 2; int player_count = (pheader.base.flag & REPLAY_TAG) ? 4 : 2;
for (int i = 0; i < player_count; ++i) { for (int i = 0; i < player_count; ++i) {
wchar_t name[20]{}; wchar_t name[20]{};
if (!ReadName(name)) if (!ReadName(name))
...@@ -241,11 +245,11 @@ bool Replay::ReadInfo() { ...@@ -241,11 +245,11 @@ bool Replay::ReadInfo() {
} }
if (!ReadData(&params, sizeof params)) if (!ReadData(&params, sizeof params))
return false; return false;
bool is_tag1 = pheader.flag & REPLAY_TAG; bool is_tag1 = pheader.base.flag & REPLAY_TAG;
bool is_tag2 = params.duel_flag & DUEL_TAG_MODE; bool is_tag2 = params.duel_flag & DUEL_TAG_MODE;
if (is_tag1 != is_tag2) if (is_tag1 != is_tag2)
return false; return false;
if (pheader.flag & REPLAY_SINGLE_MODE) { if (pheader.base.flag & REPLAY_SINGLE_MODE) {
uint16_t slen = Read<uint16_t>(); uint16_t slen = Read<uint16_t>();
char filename[256]{}; char filename[256]{};
if (slen == 0 || slen > sizeof(filename) - 1) if (slen == 0 || slen > sizeof(filename) - 1)
......
...@@ -13,6 +13,9 @@ namespace ygo { ...@@ -13,6 +13,9 @@ namespace ygo {
#define REPLAY_SINGLE_MODE 0x8 #define REPLAY_SINGLE_MODE 0x8
#define REPLAY_UNIFORM 0x10 #define REPLAY_UNIFORM 0x10
#define REPLAY_ID_YRP1 0x31707279
#define REPLAY_ID_YRP2 0x32707279
// max size // max size
constexpr int MAX_REPLAY_SIZE = 0x80000; constexpr int MAX_REPLAY_SIZE = 0x80000;
constexpr int MAX_COMP_SIZE = UINT16_MAX + 1; constexpr int MAX_COMP_SIZE = UINT16_MAX + 1;
...@@ -27,6 +30,15 @@ struct ReplayHeader { ...@@ -27,6 +30,15 @@ struct ReplayHeader {
uint8_t props[8]{}; uint8_t props[8]{};
}; };
struct ExtendedReplayHeader {
ReplayHeader base;
uint32_t seed_sequence[SEED_COUNT]{};
uint32_t header_version{ 1 };
uint32_t value1{};
uint32_t value2{};
uint32_t value3{};
};
struct DuelParameters { struct DuelParameters {
int32_t start_lp{}; int32_t start_lp{};
int32_t start_hand{}; int32_t start_hand{};
...@@ -41,7 +53,7 @@ public: ...@@ -41,7 +53,7 @@ public:
// record // record
void BeginRecord(); void BeginRecord();
void WriteHeader(ReplayHeader& header); void WriteHeader(ExtendedReplayHeader& header);
void WriteData(const void* data, size_t length, bool flush = true); void WriteData(const void* data, size_t length, bool flush = true);
template<typename T> template<typename T>
void Write(T data, bool flush = true) { void Write(T data, bool flush = true) {
...@@ -68,7 +80,7 @@ public: ...@@ -68,7 +80,7 @@ public:
bool OpenReplay(const wchar_t* name); bool OpenReplay(const wchar_t* name);
bool ReadNextResponse(unsigned char resp[]); bool ReadNextResponse(unsigned char resp[]);
bool ReadName(wchar_t* data); bool ReadName(wchar_t* data);
void ReadHeader(ReplayHeader& header); void ReadHeader(ExtendedReplayHeader& header);
bool ReadData(void* data, size_t length); bool ReadData(void* data, size_t length);
template<typename T> template<typename T>
T Read() { T Read() {
...@@ -87,7 +99,7 @@ public: ...@@ -87,7 +99,7 @@ public:
HANDLE recording_fp{ nullptr }; HANDLE recording_fp{ nullptr };
#endif #endif
ReplayHeader pheader; ExtendedReplayHeader pheader;
unsigned char* comp_data; unsigned char* comp_data;
size_t comp_size{}; size_t comp_size{};
......
...@@ -57,7 +57,7 @@ bool ReplayMode::ReadReplayResponse() { ...@@ -57,7 +57,7 @@ bool ReplayMode::ReadReplayResponse() {
return result; return result;
} }
int ReplayMode::ReplayThread() { int ReplayMode::ReplayThread() {
const ReplayHeader& rh = cur_replay.pheader; const auto& rh = cur_replay.pheader.base;
mainGame->dInfo.Clear(); mainGame->dInfo.Clear();
mainGame->dInfo.isFirst = true; mainGame->dInfo.isFirst = true;
mainGame->dInfo.isTag = !!(rh.flag & REPLAY_TAG); mainGame->dInfo.isTag = !!(rh.flag & REPLAY_TAG);
...@@ -155,9 +155,7 @@ int ReplayMode::ReplayThread() { ...@@ -155,9 +155,7 @@ int ReplayMode::ReplayThread() {
return 0; return 0;
} }
bool ReplayMode::StartDuel() { bool ReplayMode::StartDuel() {
const ReplayHeader& rh = cur_replay.pheader; const auto& rh = cur_replay.pheader.base;
unsigned int seed = rh.seed;
std::mt19937 rnd(seed);
cur_replay.SkipInfo(); cur_replay.SkipInfo();
if(rh.flag & REPLAY_TAG) { if(rh.flag & REPLAY_TAG) {
BufferIO::CopyWideString(cur_replay.players[0].c_str(), mainGame->dInfo.hostname); BufferIO::CopyWideString(cur_replay.players[0].c_str(), mainGame->dInfo.hostname);
...@@ -168,7 +166,12 @@ bool ReplayMode::StartDuel() { ...@@ -168,7 +166,12 @@ bool ReplayMode::StartDuel() {
BufferIO::CopyWideString(cur_replay.players[0].c_str(), mainGame->dInfo.hostname); BufferIO::CopyWideString(cur_replay.players[0].c_str(), mainGame->dInfo.hostname);
BufferIO::CopyWideString(cur_replay.players[1].c_str(), mainGame->dInfo.clientname); BufferIO::CopyWideString(cur_replay.players[1].c_str(), mainGame->dInfo.clientname);
} }
pduel = create_duel(rnd()); if(rh.id == REPLAY_ID_YRP1) {
std::mt19937 rnd(rh.seed);
pduel = create_duel(rnd());
} else {
pduel = create_duel_v2(cur_replay.pheader.seed_sequence);
}
mainGame->InjectEnvToRegistry(pduel); mainGame->InjectEnvToRegistry(pduel);
set_registry_value(pduel, "duel_mode", rh.flag & REPLAY_TAG ? "tag" : "single"); set_registry_value(pduel, "duel_mode", rh.flag & REPLAY_TAG ? "tag" : "single");
set_registry_value(pduel, "start_lp", std::to_string(cur_replay.params.start_lp).c_str()); set_registry_value(pduel, "start_lp", std::to_string(cur_replay.params.start_lp).c_str());
...@@ -230,8 +233,6 @@ bool ReplayMode::StartDuel() { ...@@ -230,8 +233,6 @@ bool ReplayMode::StartDuel() {
return false; return false;
} }
} }
if (!(rh.flag & REPLAY_UNIFORM))
cur_replay.params.duel_flag |= DUEL_OLD_REPLAY;
start_duel(pduel, cur_replay.params.duel_flag); start_duel(pduel, cur_replay.params.duel_flag);
return true; return true;
} }
......
...@@ -413,15 +413,14 @@ void SingleDuel::TPResult(DuelPlayer* dp, unsigned char tp) { ...@@ -413,15 +413,14 @@ void SingleDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
} }
dp->state = CTOS_RESPONSE; dp->state = CTOS_RESPONSE;
std::random_device rd; std::random_device rd;
unsigned int seed = rd(); ExtendedReplayHeader rh;
mt19937 rnd((uint_fast32_t)seed); rh.base.id = REPLAY_ID_YRP2;
auto duel_seed = rnd.rand(); rh.base.version = PRO_VERSION;
ReplayHeader rh; rh.base.flag = REPLAY_UNIFORM;
rh.id = 0x31707279; rh.base.start_time = (uint32_t)std::time(nullptr);
rh.version = PRO_VERSION; for (auto& x : rh.seed_sequence)
rh.flag = REPLAY_UNIFORM; x = rd();
rh.seed = seed; mtrandom rnd(rh.seed_sequence, SEED_COUNT);
rh.start_time = (unsigned int)std::time(nullptr);
last_replay.BeginRecord(); last_replay.BeginRecord();
last_replay.WriteHeader(rh); last_replay.WriteHeader(rh);
last_replay.WriteData(players[0]->name, 40, false); last_replay.WriteData(players[0]->name, 40, false);
...@@ -435,7 +434,7 @@ void SingleDuel::TPResult(DuelPlayer* dp, unsigned char tp) { ...@@ -435,7 +434,7 @@ void SingleDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
set_script_reader(DataManager::ScriptReaderEx); set_script_reader(DataManager::ScriptReaderEx);
set_card_reader(DataManager::CardReader); set_card_reader(DataManager::CardReader);
set_message_handler(SingleDuel::MessageHandler); set_message_handler(SingleDuel::MessageHandler);
pduel = create_duel(duel_seed); pduel = create_duel_v2(rh.seed_sequence);
if(!registry_dump.empty()) { if(!registry_dump.empty()) {
load_registry(pduel, registry_dump.data(), (int32_t)registry_dump.size()); load_registry(pduel, registry_dump.data(), (int32_t)registry_dump.size());
} }
...@@ -1477,10 +1476,10 @@ void SingleDuel::EndDuel() { ...@@ -1477,10 +1476,10 @@ void SingleDuel::EndDuel() {
return; return;
last_replay.EndRecord(); last_replay.EndRecord();
char replaybuf[0x2000], *pbuf = replaybuf; char replaybuf[0x2000], *pbuf = replaybuf;
std::memcpy(pbuf, &last_replay.pheader, sizeof(ReplayHeader)); std::memcpy(pbuf, &last_replay.pheader, sizeof last_replay.pheader);
pbuf += sizeof(ReplayHeader); pbuf += sizeof last_replay.pheader;
std::memcpy(pbuf, last_replay.comp_data, last_replay.comp_size); std::memcpy(pbuf, last_replay.comp_data, last_replay.comp_size);
NetServer::SendBufferToPlayer(players[0], STOC_REPLAY, replaybuf, sizeof(ReplayHeader) + last_replay.comp_size); NetServer::SendBufferToPlayer(players[0], STOC_REPLAY, replaybuf, sizeof last_replay.pheader + last_replay.comp_size);
NetServer::ReSendToPlayer(players[1]); NetServer::ReSendToPlayer(players[1]);
for(auto oit = observers.begin(); oit != observers.end(); ++oit) for(auto oit = observers.begin(); oit != observers.end(); ++oit)
NetServer::ReSendToPlayer(*oit); NetServer::ReSendToPlayer(*oit);
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
#include "duelclient.h" #include "duelclient.h"
#include "game.h" #include "game.h"
#include "data_manager.h" #include "data_manager.h"
#include "../ocgcore/mtrandom.h" #include <random>
#include <thread> #include <thread>
namespace ygo { namespace ygo {
...@@ -36,12 +36,22 @@ int SingleMode::SinglePlayThread() { ...@@ -36,12 +36,22 @@ int SingleMode::SinglePlayThread() {
mainGame->dInfo.Clear(); mainGame->dInfo.Clear();
int opt = 0; int opt = 0;
std::random_device rd; std::random_device rd;
unsigned int seed = rd(); ExtendedReplayHeader rh;
mt19937 rnd((uint_fast32_t)seed); rh.base.id = REPLAY_ID_YRP2;
rh.base.version = PRO_VERSION;
rh.base.flag = REPLAY_UNIFORM | REPLAY_SINGLE_MODE;
rh.base.start_time = (uint32_t)std::time(nullptr);
for (auto& x : rh.seed_sequence)
x = rd();
std::seed_seq seed(rh.seed_sequence, rh.seed_sequence + SEED_COUNT);
std::mt19937 rnd(seed);
uint32_t duel_seed[SEED_COUNT]{};
for (auto& x : duel_seed)
x = rnd();
set_script_reader(DataManager::ScriptReaderEx); set_script_reader(DataManager::ScriptReaderEx);
set_card_reader(DataManager::CardReader); set_card_reader(DataManager::CardReader);
set_message_handler(SingleMode::MessageHandler); set_message_handler(SingleMode::MessageHandler);
pduel = create_duel(rnd.rand()); pduel = create_duel_v2(duel_seed);
mainGame->InjectEnvToRegistry(pduel); mainGame->InjectEnvToRegistry(pduel);
set_player_info(pduel, 0, start_lp, start_hand, draw_count); set_player_info(pduel, 0, start_lp, start_hand, draw_count);
set_player_info(pduel, 1, start_lp, start_hand, draw_count); set_player_info(pduel, 1, start_lp, start_hand, draw_count);
...@@ -83,12 +93,6 @@ int SingleMode::SinglePlayThread() { ...@@ -83,12 +93,6 @@ int SingleMode::SinglePlayThread() {
end_duel(pduel); end_duel(pduel);
return 0; return 0;
} }
ReplayHeader rh;
rh.id = 0x31707279;
rh.version = PRO_VERSION;
rh.flag = REPLAY_UNIFORM | REPLAY_SINGLE_MODE;
rh.seed = seed;
rh.start_time = (unsigned int)std::time(nullptr);
mainGame->gMutex.lock(); mainGame->gMutex.lock();
mainGame->HideElement(mainGame->wSinglePlay); mainGame->HideElement(mainGame->wSinglePlay);
mainGame->ClearCardInfo(); mainGame->ClearCardInfo();
......
...@@ -386,15 +386,14 @@ void TagDuel::TPResult(DuelPlayer* dp, unsigned char tp) { ...@@ -386,15 +386,14 @@ void TagDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
cur_player[1] = players[3]; cur_player[1] = players[3];
dp->state = CTOS_RESPONSE; dp->state = CTOS_RESPONSE;
std::random_device rd; std::random_device rd;
unsigned int seed = rd(); ExtendedReplayHeader rh;
mt19937 rnd((uint_fast32_t)seed); rh.base.id = REPLAY_ID_YRP2;
auto duel_seed = rnd.rand(); rh.base.version = PRO_VERSION;
ReplayHeader rh; rh.base.flag = REPLAY_UNIFORM | REPLAY_TAG;
rh.id = 0x31707279; rh.base.start_time = (uint32_t)std::time(nullptr);
rh.version = PRO_VERSION; for (auto& x : rh.seed_sequence)
rh.flag = REPLAY_UNIFORM | REPLAY_TAG; x = rd();
rh.seed = seed; mtrandom rnd(rh.seed_sequence, SEED_COUNT);
rh.start_time = (unsigned int)std::time(nullptr);
last_replay.BeginRecord(); last_replay.BeginRecord();
last_replay.WriteHeader(rh); last_replay.WriteHeader(rh);
last_replay.WriteData(players[0]->name, 40, false); last_replay.WriteData(players[0]->name, 40, false);
...@@ -412,7 +411,7 @@ void TagDuel::TPResult(DuelPlayer* dp, unsigned char tp) { ...@@ -412,7 +411,7 @@ void TagDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
set_script_reader(DataManager::ScriptReaderEx); set_script_reader(DataManager::ScriptReaderEx);
set_card_reader(DataManager::CardReader); set_card_reader(DataManager::CardReader);
set_message_handler(TagDuel::MessageHandler); set_message_handler(TagDuel::MessageHandler);
pduel = create_duel(duel_seed); pduel = create_duel_v2(rh.seed_sequence);
if(!registry_dump.empty()) { if(!registry_dump.empty()) {
load_registry(pduel, registry_dump.data(), (int32_t)registry_dump.size()); load_registry(pduel, registry_dump.data(), (int32_t)registry_dump.size());
} }
...@@ -1579,10 +1578,10 @@ void TagDuel::EndDuel() { ...@@ -1579,10 +1578,10 @@ void TagDuel::EndDuel() {
return; return;
last_replay.EndRecord(); last_replay.EndRecord();
char replaybuf[0x2000], *pbuf = replaybuf; char replaybuf[0x2000], *pbuf = replaybuf;
std::memcpy(pbuf, &last_replay.pheader, sizeof(ReplayHeader)); std::memcpy(pbuf, &last_replay.pheader, sizeof last_replay.pheader);
pbuf += sizeof(ReplayHeader); pbuf += sizeof last_replay.pheader;
std::memcpy(pbuf, last_replay.comp_data, last_replay.comp_size); std::memcpy(pbuf, last_replay.comp_data, last_replay.comp_size);
NetServer::SendBufferToPlayer(players[0], STOC_REPLAY, replaybuf, sizeof(ReplayHeader) + last_replay.comp_size); NetServer::SendBufferToPlayer(players[0], STOC_REPLAY, replaybuf, sizeof last_replay.pheader + last_replay.comp_size);
NetServer::ReSendToPlayer(players[1]); NetServer::ReSendToPlayer(players[1]);
NetServer::ReSendToPlayer(players[2]); NetServer::ReSendToPlayer(players[2]);
NetServer::ReSendToPlayer(players[3]); NetServer::ReSendToPlayer(players[3]);
......
...@@ -446,11 +446,7 @@ workspace "YGOPro" ...@@ -446,11 +446,7 @@ workspace "YGOPro"
targetdir "bin/debug/x64" targetdir "bin/debug/x64"
filter { "configurations:Release", "action:vs*" } filter { "configurations:Release", "action:vs*" }
if linktimeoptimization then linktimeoptimization "On"
linktimeoptimization "On"
else
flags { "LinkTimeOptimization" }
end
staticruntime "On" staticruntime "On"
disablewarnings { "4244", "4267", "4838", "4996", "6011", "6031", "6054", "6262" } disablewarnings { "4244", "4267", "4838", "4996", "6011", "6031", "6054", "6262" }
......
...@@ -501,6 +501,9 @@ ...@@ -501,6 +501,9 @@
!system 1475 已存在同名卡组 !system 1475 已存在同名卡组
!system 1476 删除失败 !system 1476 删除失败
!system 1477 卡片数: !system 1477 卡片数:
!system 1478 导入卡组码
!system 1479 导出卡组码
!system 1480 已导出到剪贴板
!system 1481 OCG !system 1481 OCG
!system 1482 TCG !system 1482 TCG
!system 1483 简体中文 !system 1483 简体中文
......
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