Commit e0abe3c8 authored by nanahira's avatar nanahira

Merge branch 'master' of github.com:Fluorohydride/ygopro into next-mt

parents ab98f48b ec24699d
......@@ -65,7 +65,7 @@ jobs:
id: premake
uses: mercury233/action-cache-download-file@v1.0.0
with:
url: https://github.com/premake/premake-core/releases/download/v5.0.0-beta6/premake-5.0.0-beta6-windows.zip
url: https://github.com/premake/premake-core/releases/download/v5.0.0-beta7/premake-5.0.0-beta7-windows.zip
filename: premake5.zip
- name: Extract premake
......@@ -99,12 +99,12 @@ jobs:
id: lua
uses: mercury233/action-cache-download-file@v1.0.0
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
run: |
tar xf ${{ steps.lua.outputs.filepath }}
move lua-5.4.7 lua
move lua-5.4.8 lua
- name: Download sqlite
id: sqlite
......@@ -258,7 +258,7 @@ jobs:
premake-version: 5.0.0-beta4
- name: ubuntu-24
os: ubuntu-24.04
premake-version: 5.0.0-beta6
premake-version: 5.0.0-beta7
- name: ubuntu-static-link
os: ubuntu-22.04
premake-version: 5.0.0-beta4
......@@ -345,12 +345,12 @@ jobs:
id: lua
uses: mercury233/action-cache-download-file@v1.0.0
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
run: |
tar xf ${{ steps.lua.outputs.filepath }}
mv lua-5.4.7 lua
mv lua-5.4.8 lua
- name: Download sqlite
if: matrix.static-link == true
......@@ -528,9 +528,17 @@ jobs:
brew install opus opusfile libvorbis
# brew install sqlite libx11 freetype libevent
- name: Install premake
- name: Download premake
id: premake
uses: mercury233/action-cache-download-file@v1.0.0
with:
url: https://github.com/premake/premake-core/releases/download/v5.0.0-beta7/premake-5.0.0-beta7-macosx.tar.gz
filename: premake5.tar.gz
- name: Extract premake
run: |
brew install premake
tar xf ${{ steps.premake.outputs.filepath }}
chmod +x ./premake5
- name: Download libevent
if: matrix.static-link == true
......@@ -571,12 +579,12 @@ jobs:
id: lua
uses: mercury233/action-cache-download-file@v1.0.0
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
run: |
tar xf ${{ steps.lua.outputs.filepath }}
mv lua-5.4.7 lua
mv lua-5.4.8 lua
- name: Download sqlite
if: matrix.static-link == true
......@@ -662,12 +670,12 @@ jobs:
- name: Use premake to generate make files (Homebrew packages)
if: matrix.static-link != true
run: |
DYLD_LIBRARY_PATH=$(brew --prefix)/lib premake5 gmake
DYLD_LIBRARY_PATH=$(brew --prefix)/lib ./premake5 gmake
- name: Use premake to generate make files (static link)
if: matrix.static-link == true
run: |
premake5 gmake ${{ matrix.cross-build-intel == true && '--mac-intel' || '' }} ${{ matrix.cross-build-arm == true && '--mac-arm' || '' }} \
./premake5 gmake ${{ matrix.cross-build-intel == true && '--mac-intel' || '' }} ${{ matrix.cross-build-arm == true && '--mac-arm' || '' }} \
--build-event \
--build-freetype \
--build-sqlite \
......@@ -684,4 +692,4 @@ jobs:
with:
name: YGOPro-${{ matrix.name }}
path: |
bin/release/YGOPro.app
bin/release/YGOPro
......@@ -394,6 +394,29 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
prev_operation = id;
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: {
switch(prev_operation) {
case BUTTON_NEW_CATEGORY: {
......@@ -470,7 +493,8 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
}
break;
}
case BUTTON_NEW_DECK: {
case BUTTON_NEW_DECK:
case BUTTON_IMPORT_DECK_CODE: {
const wchar_t* deckname = mainGame->ebDMName->getText();
wchar_t catepath[256];
DeckManager::GetCategoryPath(catepath, mainGame->cbDBCategory->getSelected(), mainGame->cbDBCategory->getText());
......@@ -478,9 +502,19 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
myswprintf(filepath, L"%ls/%ls.ydk", catepath, deckname);
bool res = false;
if(!FileSystem::IsFileExists(filepath)) {
if(prev_operation == BUTTON_NEW_DECK) {
deckManager.current_deck.main.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);
RefreshDeckList();
ChangeCategory(mainGame->lstCategories->getSelected());
......
......@@ -287,6 +287,10 @@ irr::io::IReadFile* DeckManager::OpenDeckReader(const wchar_t* file) {
#endif
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) {
current_deck.clear();
auto reader = OpenDeckReader(file);
......@@ -321,21 +325,27 @@ bool DeckManager::LoadCurrentDeck(int category_index, const wchar_t* category_na
mainGame->deckBuilder.RefreshPackListScroll();
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) {
if(!FileSystem::IsDirExists(L"./deck") && !FileSystem::MakeDir(L"./deck"))
return false;
FILE* fp = OpenDeckFile(file, "w");
if(!fp)
return false;
std::fprintf(fp, "#created by ...\n#main\n");
for(size_t i = 0; i < deck.main.size(); ++i)
std::fprintf(fp, "%u\n", deck.main[i]->first);
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::stringstream deckStream;
SaveDeck(deck, deckStream);
std::fwrite(deckStream.str().c_str(), 1, deckStream.str().length(), fp);
std::fclose(fp);
return true;
}
......
......@@ -74,6 +74,7 @@ public:
#ifndef YGOPRO_SERVER_MODE
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(std::istringstream& deckStream, bool is_packlist = false);
#endif //YGOPRO_SERVER_MODE
static uint32_t LoadDeck(Deck& deck, uint32_t dbuf[], int mainc, int sidec, bool is_packlist = false);
......@@ -85,6 +86,7 @@ public:
static FILE* OpenDeckFile(const wchar_t* file, const char* mode);
static irr::io::IReadFile* OpenDeckReader(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 CreateCategory(const wchar_t* name);
static bool RenameCategory(const wchar_t* oldname, const wchar_t* newname);
......
......@@ -715,7 +715,7 @@ void DuelClient::HandleSTOCPacketLan(unsigned char* data, int len) {
break;
}
case STOC_REPLAY: {
if (len < 1 + (int)sizeof(ReplayHeader))
if (len < 1 + (int)sizeof(ExtendedReplayHeader))
return;
mainGame->gMutex.lock();
mainGame->wPhase->setVisible(false);
......@@ -726,10 +726,10 @@ void DuelClient::HandleSTOCPacketLan(unsigned char* data, int len) {
Replay new_replay;
std::memcpy(&new_replay.pheader, prep, sizeof(new_replay.pheader));
time_t starttime;
if (new_replay.pheader.flag & REPLAY_UNIFORM)
starttime = new_replay.pheader.start_time;
if (new_replay.pheader.base.flag & REPLAY_UNIFORM)
starttime = new_replay.pheader.base.start_time;
else
starttime = new_replay.pheader.seed;
starttime = new_replay.pheader.base.seed;
wchar_t timetext[40];
std::wcsftime(timetext, sizeof timetext / sizeof timetext[0], L"%Y-%m-%d %H-%M-%S", std::localtime(&starttime));
......@@ -751,9 +751,9 @@ void DuelClient::HandleSTOCPacketLan(unsigned char* data, int len) {
mainGame->WaitFrameSignal(30);
}
if(mainGame->actionParam || !is_host) {
prep += sizeof(ReplayHeader);
std::memcpy(new_replay.comp_data, prep, len - sizeof(ReplayHeader) - 1);
new_replay.comp_size = len - sizeof(ReplayHeader) - 1;
prep += sizeof new_replay.pheader;
std::memcpy(new_replay.comp_data, prep, len - sizeof new_replay.pheader - 1);
new_replay.comp_size = len - sizeof new_replay.pheader - 1;
if(mainGame->actionParam)
new_replay.SaveReplay(mainGame->ebRSName->getText());
else
......
......@@ -679,10 +679,10 @@ bool Game::Initialize() {
wDeckEdit->setVisible(false);
btnManageDeck = env->addButton(irr::core::rect<irr::s32>(225, 5, 290, 30), wDeckEdit, BUTTON_MANAGE_DECK, dataManager.GetSysString(1328));
//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);
lstCategories = env->addListBox(irr::core::rect<irr::s32>(10, 30, 140, 320), wDeckManage, LISTBOX_CATEGORIES, true);
lstDecks = env->addListBox(irr::core::rect<irr::s32>(150, 30, 340, 320), wDeckManage, LISTBOX_DECKS, 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, 370), wDeckManage, LISTBOX_DECKS, true);
posY = 30;
btnNewCategory = env->addButton(irr::core::rect<irr::s32>(350, posY, 480, posY + 25), wDeckManage, BUTTON_NEW_CATEGORY, dataManager.GetSysString(1461));
posY += 35;
......@@ -699,6 +699,10 @@ bool Game::Initialize() {
btnMoveDeck = env->addButton(irr::core::rect<irr::s32>(350, posY, 480, posY + 25), wDeckManage, BUTTON_MOVE_DECK, dataManager.GetSysString(1467));
posY += 35;
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
wDMQuery = env->addWindow(irr::core::rect<irr::s32>(400, 200, 710, 320), false, dataManager.GetSysString(1460));
wDMQuery->getCloseButton()->setVisible(false);
......@@ -1940,7 +1944,7 @@ void Game::OnResize() {
ebDeckname->setRelativePosition(Resize(80, 65, 220, 90));
cbDBCategory->setRelativePosition(Resize(80, 5, 220, 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));
wSort->setRelativePosition(Resize(930, 132, 1020, 156));
......
......@@ -582,6 +582,8 @@ public:
irr::gui::IGUIButton* btnDMDeleteDeck;
irr::gui::IGUIButton* btnMoveDeck;
irr::gui::IGUIButton* btnCopyDeck;
irr::gui::IGUIButton* btnImportDeckCode;
irr::gui::IGUIButton* btnExportDeckCode;
irr::gui::IGUIWindow* wDMQuery;
irr::gui::IGUIStaticText* stDMMessage;
irr::gui::IGUIStaticText* stDMMessage2;
......@@ -846,6 +848,8 @@ extern unsigned int pre_seed[3];
#define LISTBOX_DECKS 340
#define BUTTON_DM_OK 341
#define BUTTON_DM_CANCEL 342
#define BUTTON_IMPORT_DECK_CODE 343
#define BUTTON_EXPORT_DECK_CODE 344
#define COMBOBOX_LFLIST 349
#define BUTTON_CLEAR_LOG 350
......
......@@ -309,7 +309,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
myswprintf(replay_path, L"./replay/%ls", replay_filename);
if (!replay.OpenReplay(replay_path))
break;
if (replay.pheader.flag & REPLAY_SINGLE_MODE)
if (replay.pheader.base.flag & REPLAY_SINGLE_MODE)
break;
for (size_t i = 0; i < replay.decks.size(); ++i) {
BufferIO::CopyWideString(replay.players[Replay::GetDeckPlayer(i)].c_str(), namebuf[i]);
......@@ -537,24 +537,25 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
wchar_t infobuf[256]{};
std::wstring repinfo;
time_t curtime;
if(temp_replay.pheader.flag & REPLAY_UNIFORM)
curtime = temp_replay.pheader.start_time;
const auto& rh = temp_replay.pheader.base;
if(temp_replay.pheader.base.flag & REPLAY_UNIFORM)
curtime = rh.start_time;
else{
curtime = temp_replay.pheader.seed;
curtime = rh.seed;
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);
}
std::wcsftime(infobuf, sizeof infobuf / sizeof infobuf[0], L"%Y/%m/%d %H:%M:%S\n", std::localtime(&curtime));
repinfo.append(infobuf);
if (temp_replay.pheader.flag & REPLAY_SINGLE_MODE) {
if (rh.flag & REPLAY_SINGLE_MODE) {
wchar_t path[256]{};
BufferIO::DecodeUTF8(temp_replay.script_name.c_str(), path);
repinfo.append(path);
repinfo.append(L"\n");
}
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());
else
myswprintf(infobuf, L"%ls\n===VS===\n%ls\n", player_names[0].c_str(), player_names[1].c_str());
......
......@@ -284,7 +284,7 @@ public:
#define STOC_LEAVE_GAME 0x14 // reserved
#define STOC_DUEL_START 0x15 // 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_CHAT 0x19 // uint16_t + uint16_t array
#define STOC_HS_PLAYER_ENTER 0x20 // STOC_HS_PlayerEnter
......
......@@ -62,7 +62,7 @@ void Replay::BeginRecord() {
Reset();
is_recording = true;
}
void Replay::WriteHeader(ReplayHeader& header) {
void Replay::WriteHeader(ExtendedReplayHeader& header) {
pheader = header;
#ifdef YGOPRO_SERVER_MODE
if(!(replay_mode & REPLAY_MODE_SAVE_IN_SERVER)) return;
......@@ -122,11 +122,11 @@ void Replay::EndRecord() {
#ifdef YGOPRO_SERVER_MODE
}
#endif
pheader.datasize = replay_size;
pheader.flag |= REPLAY_COMPRESSED;
pheader.base.datasize = replay_size;
pheader.base.flag |= REPLAY_COMPRESSED;
size_t propsize = 5;
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) {
std::memcpy(comp_data, &ret, sizeof ret);
comp_size = sizeof ret;
......@@ -157,27 +157,31 @@ bool Replay::OpenReplay(const wchar_t* name) {
Reset();
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;
else if (pheader.id != 0x31707279)
else if (pheader.base.id != REPLAY_ID_YRP1 && pheader.base.id != REPLAY_ID_YRP2)
correct_header = false;
else if (pheader.version < 0x12d0u)
else if (pheader.base.version < 0x12d0u)
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;
if (!correct_header) {
std::fclose(rfp);
return false;
}
if(pheader.flag & REPLAY_COMPRESSED) {
if (pheader.base.id == REPLAY_ID_YRP2 && std::fread(&pheader.seed_sequence, sizeof pheader.seed_sequence, 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);
std::fclose(rfp);
if (pheader.datasize > MAX_REPLAY_SIZE)
if (pheader.base.datasize > MAX_REPLAY_SIZE)
return false;
replay_size = pheader.datasize;
if (LzmaUncompress(replay_data, &replay_size, comp_data, &comp_size, pheader.props, 5) != SZ_OK)
replay_size = pheader.base.datasize;
if (LzmaUncompress(replay_data, &replay_size, comp_data, &comp_size, pheader.base.props, 5) != SZ_OK)
return false;
if (replay_size != pheader.datasize) {
if (replay_size != pheader.base.datasize) {
replay_size = 0;
return false;
}
......@@ -234,7 +238,7 @@ bool Replay::ReadName(wchar_t* data) {
BufferIO::CopyWStr(buffer, data, 20);
return true;
}
void Replay::ReadHeader(ReplayHeader& header) {
void Replay::ReadHeader(ExtendedReplayHeader& header) {
header = pheader;
}
bool Replay::ReadData(void* data, size_t length) {
......@@ -277,7 +281,7 @@ bool Replay::IsReplaying() const {
return is_replaying;
}
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) {
wchar_t name[20]{};
if (!ReadName(name))
......@@ -286,11 +290,11 @@ bool Replay::ReadInfo() {
}
if (!ReadData(&params, sizeof params))
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;
if (is_tag1 != is_tag2)
return false;
if (pheader.flag & REPLAY_SINGLE_MODE) {
if (pheader.base.flag & REPLAY_SINGLE_MODE) {
uint16_t slen = Read<uint16_t>();
char filename[256]{};
if (slen == 0 || slen > sizeof(filename) - 1)
......
......@@ -13,6 +13,9 @@ namespace ygo {
#define REPLAY_SINGLE_MODE 0x8
#define REPLAY_UNIFORM 0x10
#define REPLAY_ID_YRP1 0x31707279
#define REPLAY_ID_YRP2 0x32707279
// max size
constexpr int MAX_REPLAY_SIZE = 0x80000;
constexpr int MAX_COMP_SIZE = UINT16_MAX + 1;
......@@ -33,6 +36,15 @@ struct ReplayHeader {
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 {
int32_t start_lp{};
int32_t start_hand{};
......@@ -47,7 +59,7 @@ public:
// record
void BeginRecord();
void WriteHeader(ReplayHeader& header);
void WriteHeader(ExtendedReplayHeader& header);
void WriteData(const void* data, size_t length, bool flush = true);
template<typename T>
void Write(T data, bool flush = true) {
......@@ -74,7 +86,7 @@ public:
bool OpenReplay(const wchar_t* name);
bool ReadNextResponse(unsigned char resp[]);
bool ReadName(wchar_t* data);
void ReadHeader(ReplayHeader& header);
void ReadHeader(ExtendedReplayHeader& header);
bool ReadData(void* data, size_t length);
template<typename T>
T Read() {
......@@ -93,7 +105,7 @@ public:
HANDLE recording_fp{ nullptr };
#endif
ReplayHeader pheader;
ExtendedReplayHeader pheader;
unsigned char* comp_data;
size_t comp_size{};
......
......@@ -57,7 +57,7 @@ bool ReplayMode::ReadReplayResponse() {
return result;
}
int ReplayMode::ReplayThread() {
const ReplayHeader& rh = cur_replay.pheader;
const auto& rh = cur_replay.pheader.base;
mainGame->dInfo.Clear();
mainGame->dInfo.isFirst = true;
mainGame->dInfo.isTag = !!(rh.flag & REPLAY_TAG);
......@@ -155,9 +155,7 @@ int ReplayMode::ReplayThread() {
return 0;
}
bool ReplayMode::StartDuel() {
const ReplayHeader& rh = cur_replay.pheader;
unsigned int seed = rh.seed;
std::mt19937 rnd(seed);
const auto& rh = cur_replay.pheader.base;
cur_replay.SkipInfo();
if(rh.flag & REPLAY_TAG) {
BufferIO::CopyWideString(cur_replay.players[0].c_str(), mainGame->dInfo.hostname);
......@@ -168,7 +166,12 @@ bool ReplayMode::StartDuel() {
BufferIO::CopyWideString(cur_replay.players[0].c_str(), mainGame->dInfo.hostname);
BufferIO::CopyWideString(cur_replay.players[1].c_str(), mainGame->dInfo.clientname);
}
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->dInfo.duel_rule = cur_replay.params.duel_flag >> 16;
set_player_info(pduel, 0, cur_replay.params.start_lp, cur_replay.params.start_hand, cur_replay.params.draw_count);
set_player_info(pduel, 1, cur_replay.params.start_lp, cur_replay.params.start_hand, cur_replay.params.draw_count);
......@@ -214,8 +217,6 @@ bool ReplayMode::StartDuel() {
return false;
}
}
if (!(rh.flag & REPLAY_UNIFORM))
cur_replay.params.duel_flag |= DUEL_OLD_REPLAY;
start_duel(pduel, cur_replay.params.duel_flag);
return true;
}
......
......@@ -535,20 +535,19 @@ void SingleDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
}
dp->state = CTOS_RESPONSE;
std::random_device rd;
unsigned int seed = rd();
#ifdef YGOPRO_SERVER_MODE
if(pre_seed[duel_count] > 0) {
seed = pre_seed[duel_count];
}
ExtendedReplayHeader rh;
rh.base.id = REPLAY_ID_YRP2;
rh.base.version = PRO_VERSION;
rh.base.flag = REPLAY_UNIFORM;
rh.base.start_time = (uint32_t)std::time(nullptr);
#ifdef YGOPRO_SERVER_MODE
if(pre_seed_specified[duel_count])
memcpy(rh.seed_sequence, pre_seed[duel_count], SEED_COUNT * sizeof(uint32_t));
else
#endif
mt19937 rnd((uint_fast32_t)seed);
auto duel_seed = rnd.rand();
ReplayHeader rh;
rh.id = 0x31707279;
rh.version = PRO_VERSION;
rh.flag = REPLAY_UNIFORM;
rh.seed = seed;
rh.start_time = (unsigned int)std::time(nullptr);
for (auto& x : rh.seed_sequence)
x = rd();
mtrandom rnd(rh.seed_sequence, SEED_COUNT);
last_replay.BeginRecord();
last_replay.WriteHeader(rh);
last_replay.WriteData(players[0]->name, 40, false);
......@@ -562,7 +561,7 @@ void SingleDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
set_script_reader(DataManager::ScriptReaderEx);
set_card_reader(DataManager::CardReader);
set_message_handler(SingleDuel::MessageHandler);
pduel = create_duel(duel_seed);
pduel = create_duel_v2(rh.seed_sequence);
set_player_info(pduel, 0, host_info.start_lp, host_info.start_hand, host_info.draw_count);
set_player_info(pduel, 1, host_info.start_lp, host_info.start_hand, host_info.draw_count);
#ifdef YGOPRO_SERVER_MODE
......@@ -1796,10 +1795,10 @@ void SingleDuel::EndDuel() {
return;
last_replay.EndRecord();
char replaybuf[0x2000], *pbuf = replaybuf;
std::memcpy(pbuf, &last_replay.pheader, sizeof(ReplayHeader));
pbuf += sizeof(ReplayHeader);
std::memcpy(pbuf, &last_replay.pheader, sizeof last_replay.pheader);
pbuf += sizeof last_replay.pheader;
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]);
#ifdef YGOPRO_SERVER_MODE
if(!(replay_mode & REPLAY_MODE_WATCHER_NO_SEND)) {
......
......@@ -2,7 +2,7 @@
#include "duelclient.h"
#include "game.h"
#include "data_manager.h"
#include "../ocgcore/mtrandom.h"
#include <random>
#include <thread>
namespace ygo {
......@@ -36,12 +36,22 @@ int SingleMode::SinglePlayThread() {
mainGame->dInfo.Clear();
int opt = 0;
std::random_device rd;
unsigned int seed = rd();
mt19937 rnd((uint_fast32_t)seed);
ExtendedReplayHeader rh;
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_card_reader(DataManager::CardReader);
set_message_handler(SingleMode::MessageHandler);
pduel = create_duel(rnd.rand());
pduel = create_duel_v2(duel_seed);
set_player_info(pduel, 0, start_lp, start_hand, draw_count);
set_player_info(pduel, 1, start_lp, start_hand, draw_count);
mainGame->dInfo.lp[0] = start_lp;
......@@ -79,12 +89,6 @@ int SingleMode::SinglePlayThread() {
end_duel(pduel);
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->HideElement(mainGame->wSinglePlay);
mainGame->ClearCardInfo();
......
......@@ -511,20 +511,19 @@ void TagDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
cur_player[1] = players[3];
dp->state = CTOS_RESPONSE;
std::random_device rd;
unsigned int seed = rd();
#ifdef YGOPRO_SERVER_MODE
if(pre_seed[0] > 0) {
seed = pre_seed[0];
}
ExtendedReplayHeader rh;
rh.base.id = REPLAY_ID_YRP2;
rh.base.version = PRO_VERSION;
rh.base.flag = REPLAY_UNIFORM | REPLAY_TAG;
rh.base.start_time = (uint32_t)std::time(nullptr);
#ifdef YGOPRO_SERVER_MODE
if(pre_seed_specified[duel_count])
memcpy(rh.seed_sequence, pre_seed[duel_count], SEED_COUNT * sizeof(uint32_t));
else
#endif
mt19937 rnd((uint_fast32_t)seed);
auto duel_seed = rnd.rand();
ReplayHeader rh;
rh.id = 0x31707279;
rh.version = PRO_VERSION;
rh.flag = REPLAY_UNIFORM | REPLAY_TAG;
rh.seed = seed;
rh.start_time = (unsigned int)std::time(nullptr);
for (auto& x : rh.seed_sequence)
x = rd();
mtrandom rnd(rh.seed_sequence, SEED_COUNT);
last_replay.BeginRecord();
last_replay.WriteHeader(rh);
last_replay.WriteData(players[0]->name, 40, false);
......@@ -542,7 +541,7 @@ void TagDuel::TPResult(DuelPlayer* dp, unsigned char tp) {
set_script_reader(DataManager::ScriptReaderEx);
set_card_reader(DataManager::CardReader);
set_message_handler(TagDuel::MessageHandler);
pduel = create_duel(duel_seed);
pduel = create_duel_v2(rh.seed_sequence);
#ifdef YGOPRO_SERVER_MODE
preload_script(pduel, "./script/special.lua");
#endif
......@@ -1887,10 +1886,10 @@ void TagDuel::EndDuel() {
return;
last_replay.EndRecord();
char replaybuf[0x2000], *pbuf = replaybuf;
std::memcpy(pbuf, &last_replay.pheader, sizeof(ReplayHeader));
pbuf += sizeof(ReplayHeader);
std::memcpy(pbuf, &last_replay.pheader, sizeof last_replay.pheader);
pbuf += sizeof last_replay.pheader;
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[2]);
NetServer::ReSendToPlayer(players[3]);
......
......@@ -324,18 +324,10 @@ if os.istarget("macosx") then
if GetParam("mac-intel") then
MAC_INTEL = true
end
if MAC_ARM then
TARGET_MAC_ARM = true
elseif not MAC_INTEL then
-- automatic target arm64, need extra detect
local uname = os.outputof("uname -m")
local proctranslated = os.outputof("sysctl sysctl.proc_translated")
if uname:find("arm") or proctranslated then
print("Detected Apple Silicon Mac")
if MAC_ARM or (not MAC_INTEL and os.hostarch() == "ARM64") then
-- building on ARM CPU will target ARM automatically
TARGET_MAC_ARM = true
end
end
end
workspace "YGOPro"
......@@ -407,11 +399,7 @@ workspace "YGOPro"
targetdir "bin/debug/x64"
filter { "configurations:Release", "action:vs*" }
if linktimeoptimization then
linktimeoptimization "On"
else
flags { "LinkTimeOptimization" }
end
staticruntime "On"
disablewarnings { "4244", "4267", "4838", "4996", "6011", "6031", "6054", "6262" }
......
......@@ -493,6 +493,9 @@
!system 1475 已存在同名卡组
!system 1476 删除失败
!system 1477 卡片数:
!system 1478 导入卡组码
!system 1479 导出卡组码
!system 1480 已导出到剪贴板
!system 1481 OCG
!system 1482 TCG
!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