Commit f1d8a6ce authored by nanahira's avatar nanahira

Merge branch 'develop' into server-develop

parents 80c3c567 5817414a
...@@ -2,6 +2,11 @@ ...@@ -2,6 +2,11 @@
set -x set -x
set -o errexit set -o errexit
if [ -n "$NO_AUDIO" ]; then
echo "Skipping opus build because NO_AUDIO is set"
exit 0
fi
cd miniaudio cd miniaudio
external_built_dir="$PWD/external-built" external_built_dir="$PWD/external-built"
......
...@@ -10,9 +10,9 @@ if [[ -z "$TARGET_PLATFORM" ]]; then ...@@ -10,9 +10,9 @@ if [[ -z "$TARGET_PLATFORM" ]]; then
TARGET_PLATFORM=linux TARGET_PLATFORM=linux
fi fi
#if [[ "$TARGET_PLATFORM" != "linuxarm" ]]; then if [[ "$TARGET_PLATFORM" != "linuxarm" ]]; then
ARCHIVE_FILES+=(sound) ARCHIVE_FILES+=(sound)
#fi fi
apt update && apt -y install tar git zstd apt update && apt -y install tar git zstd
mkdir dist replay mkdir dist replay
......
...@@ -1544,13 +1544,9 @@ void ClientField::UpdateDeclarableList() { ...@@ -1544,13 +1544,9 @@ void ClientField::UpdateDeclarableList() {
ancard.push_back(trycode); ancard.push_back(trycode);
return; return;
} }
bool try_cache = false;
if(pname[0] == 0) {
try_cache = true;
}
mainGame->lstANCard->clear(); mainGame->lstANCard->clear();
ancard.clear(); ancard.clear();
if(try_cache && mainGame->dInfo.announce_cache.size()) { if(pname[0] == 0 && mainGame->dInfo.announce_cache.size()) {
for(int i = 0; i < mainGame->dInfo.announce_cache.size(); ++i) { for(int i = 0; i < mainGame->dInfo.announce_cache.size(); ++i) {
unsigned int cache_code = mainGame->dInfo.announce_cache[i]; unsigned int cache_code = mainGame->dInfo.announce_cache[i];
if(dataManager.GetString(cache_code, &cstr) && dataManager.GetData(cache_code, &cd) && is_declarable(cd, declare_opcodes)) { if(dataManager.GetString(cache_code, &cstr) && dataManager.GetData(cache_code, &cd) && is_declarable(cd, declare_opcodes)) {
...@@ -1558,17 +1554,17 @@ void ClientField::UpdateDeclarableList() { ...@@ -1558,17 +1554,17 @@ void ClientField::UpdateDeclarableList() {
ancard.push_back(cache_code); ancard.push_back(cache_code);
} }
} }
if(ancard.size()) // if(ancard.size())
return; // return;
} }
for(auto cit = dataManager.strings_begin(); cit != dataManager.strings_end(); ++cit) { for(auto cit = dataManager.strings_begin(); cit != dataManager.strings_end(); ++cit) {
if(cit->second.name.find(pname) != std::wstring::npos) { if(cit->second.name.find(pname) != std::wstring::npos || mainGame->CheckRegEx(cit->second.name, pname)) {
auto cp = dataManager.GetCodePointer(cit->first); auto cp = dataManager.GetCodePointer(cit->first);
if (cp == dataManager.datas_end()) if (cp == dataManager.datas_end())
continue; continue;
//datas.alias can be double card names or alias //datas.alias can be double card names or alias
if(is_declarable(cp->second, declare_opcodes)) { if(is_declarable(cp->second, declare_opcodes)) {
if(pname == cit->second.name || mainGame->CheckRegEx(cit->second.name, pname, true)) { //exact match if(pname == cit->second.name) { //exact match
mainGame->lstANCard->insertItem(0, cit->second.name.c_str(), -1); mainGame->lstANCard->insertItem(0, cit->second.name.c_str(), -1);
ancard.insert(ancard.begin(), cit->first); ancard.insert(ancard.begin(), cit->first);
} else { } else {
......
...@@ -415,34 +415,21 @@ bool DeckManager::DeleteCategory(const wchar_t* name) { ...@@ -415,34 +415,21 @@ bool DeckManager::DeleteCategory(const wchar_t* name) {
return false; return false;
return FileSystem::DeleteDir(localname); return FileSystem::DeleteDir(localname);
} }
bool DeckManager::SaveDeckBuffer(const int deckbuf[], const wchar_t* name) { bool DeckManager::SaveReplayDeck(const ReplayDeck& deck, const wchar_t* name) {
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(name, "w"); FILE* fp = OpenDeckFile(name, "w");
if (!fp) if (!fp)
return false; return false;
int it = 0;
const int mainc = deckbuf[it];
++it;
std::fprintf(fp, "#created by ...\n#main\n"); std::fprintf(fp, "#created by ...\n#main\n");
for (int i = 0; i < mainc; ++i) { for (const auto& code : deck.main)
std::fprintf(fp, "%d\n", deckbuf[it]); std::fprintf(fp, "%u\n", code);
++it;
}
const int extrac = deckbuf[it];
++it;
std::fprintf(fp, "#extra\n"); std::fprintf(fp, "#extra\n");
for (int i = 0; i < extrac; ++i) { for (const auto& code : deck.extra)
std::fprintf(fp, "%d\n", deckbuf[it]); std::fprintf(fp, "%u\n", code);
++it;
}
const int sidec = deckbuf[it];
++it;
std::fprintf(fp, "!side\n"); std::fprintf(fp, "!side\n");
for (int i = 0; i < sidec; ++i) { for (const auto& code : deck.side)
std::fprintf(fp, "%d\n", deckbuf[it]); std::fprintf(fp, "%u\n", code);
++it;
}
std::fclose(fp); std::fclose(fp);
return true; return true;
} }
......
...@@ -51,6 +51,12 @@ struct Deck { ...@@ -51,6 +51,12 @@ struct Deck {
} }
}; };
struct ReplayDeck {
std::vector<uint32_t> main;
std::vector<uint32_t> extra;
std::vector<uint32_t> side;
};
class DeckManager { class DeckManager {
public: public:
Deck current_deck; Deck current_deck;
...@@ -72,7 +78,6 @@ public: ...@@ -72,7 +78,6 @@ public:
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);
int SaveDeckToCode(Deck &deck, unsigned char *code); int SaveDeckToCode(Deck &deck, unsigned char *code);
bool SaveDeckBuffer(const int deckbuf[], const wchar_t* name);
#endif // YGOPRO_SERVER_MODE #endif // YGOPRO_SERVER_MODE
static uint32_t LoadDeck(Deck& deck, uint32_t dbuf[], int mainc, int sidec, bool is_packlist = false); static uint32_t LoadDeck(Deck& deck, uint32_t dbuf[], int mainc, int sidec, bool is_packlist = false);
...@@ -88,6 +93,7 @@ public: ...@@ -88,6 +93,7 @@ public:
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);
static bool DeleteCategory(const wchar_t* name); static bool DeleteCategory(const wchar_t* name);
static bool SaveReplayDeck(const ReplayDeck& deck, const wchar_t* name);
#endif // YGOPRO_SERVER_MODE #endif // YGOPRO_SERVER_MODE
}; };
......
...@@ -1393,7 +1393,12 @@ void Game::DrawDeckBd() { ...@@ -1393,7 +1393,12 @@ void Game::DrawDeckBd() {
driver->draw2DRectangle(Resize(805, 160, 1020, 630), 0x400000ff, 0x400000ff, 0x40000000, 0x40000000); driver->draw2DRectangle(Resize(805, 160, 1020, 630), 0x400000ff, 0x400000ff, 0x40000000, 0x40000000);
driver->draw2DRectangleOutline(Resize(804, 159, 1020, 630)); driver->draw2DRectangleOutline(Resize(804, 159, 1020, 630));
} }
for(int i = 0; i < 9 && i + scrFilter->getPos() < (int)deckBuilder.results.size(); ++i) { #ifdef YGOPRO_USE_THUMB_LOAD_THREAD
constexpr int MAX_RESULT = 9;
#else
constexpr int MAX_RESULT = 7;
#endif
for(int i = 0; i < MAX_RESULT && i + scrFilter->getPos() < (int)deckBuilder.results.size(); ++i) {
code_pointer ptr = deckBuilder.results[i + scrFilter->getPos()]; code_pointer ptr = deckBuilder.results[i + scrFilter->getPos()];
if(i >= 7) if(i >= 7)
{ {
......
...@@ -29,7 +29,7 @@ bool ImageManager::Initial() { ...@@ -29,7 +29,7 @@ bool ImageManager::Initial() {
tUnknownFit = nullptr; tUnknownFit = nullptr;
tUnknownThumb = nullptr; tUnknownThumb = nullptr;
tBigPicture = nullptr; tBigPicture = nullptr;
#ifdef YGOPRO_USE_THUMB_LOAD_THERAD #ifdef YGOPRO_USE_THUMB_LOAD_THREAD
tLoading = nullptr; tLoading = nullptr;
tThumbLoadingThreadRunning = false; tThumbLoadingThreadRunning = false;
#endif #endif
...@@ -141,7 +141,7 @@ void ImageManager::ClearTexture() { ...@@ -141,7 +141,7 @@ void ImageManager::ClearTexture() {
driver->removeTexture(tit->second); driver->removeTexture(tit->second);
} }
for(auto tit = tThumb.begin(); tit != tThumb.end(); ++tit) { for(auto tit = tThumb.begin(); tit != tThumb.end(); ++tit) {
#ifdef YGOPRO_USE_THUMB_LOAD_THERAD #ifdef YGOPRO_USE_THUMB_LOAD_THREAD
if(tit->second && tit->second != tLoading) if(tit->second && tit->second != tLoading)
#else #else
if(tit->second) if(tit->second)
...@@ -155,7 +155,7 @@ void ImageManager::ClearTexture() { ...@@ -155,7 +155,7 @@ void ImageManager::ClearTexture() {
tMap[0].clear(); tMap[0].clear();
tMap[1].clear(); tMap[1].clear();
tThumb.clear(); tThumb.clear();
#ifdef YGOPRO_USE_THUMB_LOAD_THERAD #ifdef YGOPRO_USE_THUMB_LOAD_THREAD
tThumbLoadingMutex.lock(); tThumbLoadingMutex.lock();
tThumbLoading.clear(); tThumbLoading.clear();
while(!tThumbLoadingCodes.empty()) while(!tThumbLoadingCodes.empty())
...@@ -204,7 +204,7 @@ void ImageManager::ResizeTexture() { ...@@ -204,7 +204,7 @@ void ImageManager::ResizeTexture() {
driver->removeTexture(tUnknown); driver->removeTexture(tUnknown);
driver->removeTexture(tUnknownFit); driver->removeTexture(tUnknownFit);
driver->removeTexture(tUnknownThumb); driver->removeTexture(tUnknownThumb);
#ifdef YGOPRO_USE_THUMB_LOAD_THERAD #ifdef YGOPRO_USE_THUMB_LOAD_THREAD
driver->removeTexture(tLoading); driver->removeTexture(tLoading);
tLoading = GetTextureFromFile("textures/cover.jpg", imgWidthThumb, imgHeightThumb); tLoading = GetTextureFromFile("textures/cover.jpg", imgWidthThumb, imgHeightThumb);
#endif #endif
...@@ -407,7 +407,7 @@ irr::video::ITexture* ImageManager::GetBigPicture(int code, float zoom) { ...@@ -407,7 +407,7 @@ irr::video::ITexture* ImageManager::GetBigPicture(int code, float zoom) {
tBigPicture = texture; tBigPicture = texture;
return texture; return texture;
} }
#ifdef YGOPRO_USE_THUMB_LOAD_THERAD #ifdef YGOPRO_USE_THUMB_LOAD_THREAD
int ImageManager::LoadThumbThread() { int ImageManager::LoadThumbThread() {
while(true) { while(true) {
imageManager.tThumbLoadingMutex.lock(); imageManager.tThumbLoadingMutex.lock();
...@@ -495,11 +495,11 @@ int ImageManager::LoadThumbThread() { ...@@ -495,11 +495,11 @@ int ImageManager::LoadThumbThread() {
imageManager.tThumbLoadingMutex.unlock(); imageManager.tThumbLoadingMutex.unlock();
return 0; return 0;
} }
#endif // YGOPRO_USE_THUMB_LOAD_THERAD #endif // YGOPRO_USE_THUMB_LOAD_THREAD
irr::video::ITexture* ImageManager::GetTextureThumb(int code) { irr::video::ITexture* ImageManager::GetTextureThumb(int code) {
if(code == 0) if(code == 0)
return tUnknownThumb; return tUnknownThumb;
#ifndef YGOPRO_USE_THUMB_LOAD_THERAD #ifndef YGOPRO_USE_THUMB_LOAD_THREAD
auto tit = tThumb.find(code); auto tit = tThumb.find(code);
if(tit == tThumb.end()) { if(tit == tThumb.end()) {
char file[256]; char file[256];
...@@ -522,7 +522,7 @@ irr::video::ITexture* ImageManager::GetTextureThumb(int code) { ...@@ -522,7 +522,7 @@ irr::video::ITexture* ImageManager::GetTextureThumb(int code) {
tThumb[code] = img; tThumb[code] = img;
return (img == NULL) ? tUnknownThumb : img; return (img == NULL) ? tUnknownThumb : img;
} }
#else // YGOPRO_USE_THUMB_LOAD_THERAD #else // YGOPRO_USE_THUMB_LOAD_THREAD
imageManager.tThumbLoadingMutex.lock(); imageManager.tThumbLoadingMutex.lock();
auto lit = tThumbLoading.find(code); auto lit = tThumbLoading.find(code);
if(lit != tThumbLoading.end()) { if(lit != tThumbLoading.end()) {
...@@ -550,7 +550,7 @@ irr::video::ITexture* ImageManager::GetTextureThumb(int code) { ...@@ -550,7 +550,7 @@ irr::video::ITexture* ImageManager::GetTextureThumb(int code) {
imageManager.tThumbLoadingMutex.unlock(); imageManager.tThumbLoadingMutex.unlock();
return tLoading; return tLoading;
} }
#endif // YGOPRO_USE_THUMB_LOAD_THERAD #endif // YGOPRO_USE_THUMB_LOAD_THREAD
if(tit->second) if(tit->second)
return tit->second; return tit->second;
else else
......
...@@ -2,13 +2,13 @@ ...@@ -2,13 +2,13 @@
#define IMAGEMANAGER_H #define IMAGEMANAGER_H
#ifndef _OPENMP #ifndef _OPENMP
#define YGOPRO_USE_THUMB_LOAD_THERAD #define YGOPRO_USE_THUMB_LOAD_THREAD
#endif #endif
#include "config.h" #include "config.h"
#include "data_manager.h" #include "data_manager.h"
#include <unordered_map> #include <unordered_map>
#ifdef YGOPRO_USE_THUMB_LOAD_THERAD #ifdef YGOPRO_USE_THUMB_LOAD_THREAD
#include <queue> #include <queue>
#include <mutex> #include <mutex>
#endif #endif
...@@ -34,14 +34,14 @@ public: ...@@ -34,14 +34,14 @@ public:
irr::video::ITexture* GetBigPicture(int code, float zoom); irr::video::ITexture* GetBigPicture(int code, float zoom);
irr::video::ITexture* GetTextureThumb(int code); irr::video::ITexture* GetTextureThumb(int code);
irr::video::ITexture* GetTextureField(int code); irr::video::ITexture* GetTextureField(int code);
#ifdef YGOPRO_USE_THUMB_LOAD_THERAD #ifdef YGOPRO_USE_THUMB_LOAD_THREAD
static int LoadThumbThread(); static int LoadThumbThread();
#endif #endif
std::unordered_map<int, irr::video::ITexture*> tMap[2]; std::unordered_map<int, irr::video::ITexture*> tMap[2];
std::unordered_map<int, irr::video::ITexture*> tThumb; std::unordered_map<int, irr::video::ITexture*> tThumb;
std::unordered_map<int, irr::video::ITexture*> tFields; std::unordered_map<int, irr::video::ITexture*> tFields;
#ifdef YGOPRO_USE_THUMB_LOAD_THERAD #ifdef YGOPRO_USE_THUMB_LOAD_THREAD
std::unordered_map<int, irr::video::IImage*> tThumbLoading; std::unordered_map<int, irr::video::IImage*> tThumbLoading;
std::queue<int> tThumbLoadingCodes; std::queue<int> tThumbLoadingCodes;
std::mutex tThumbLoadingMutex; std::mutex tThumbLoadingMutex;
...@@ -54,7 +54,7 @@ public: ...@@ -54,7 +54,7 @@ public:
irr::video::ITexture* tUnknownFit; irr::video::ITexture* tUnknownFit;
irr::video::ITexture* tUnknownThumb; irr::video::ITexture* tUnknownThumb;
irr::video::ITexture* tBigPicture; irr::video::ITexture* tBigPicture;
#ifdef YGOPRO_USE_THUMB_LOAD_THERAD #ifdef YGOPRO_USE_THUMB_LOAD_THREAD
irr::video::ITexture* tLoading; irr::video::ITexture* tLoading;
#endif #endif
irr::video::ITexture* tAct; irr::video::ITexture* tAct;
......
...@@ -286,42 +286,23 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) { ...@@ -286,42 +286,23 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
if(selected == -1) if(selected == -1)
break; break;
Replay replay; Replay replay;
wchar_t ex_filename[256]{}; wchar_t replay_filename[256]{};
wchar_t namebuf[4][20]{}; wchar_t namebuf[4][20]{};
wchar_t filename[256]{}; wchar_t filename[256]{};
wchar_t replay_path[256]{}; wchar_t replay_path[256]{};
BufferIO::CopyWideString(mainGame->lstReplayList->getListItem(selected), ex_filename); BufferIO::CopyWideString(mainGame->lstReplayList->getListItem(selected), replay_filename);
myswprintf(replay_path, L"./replay/%ls", ex_filename); myswprintf(replay_path, L"./replay/%ls", replay_filename);
if (!replay.OpenReplay(replay_path)) if (!replay.OpenReplay(replay_path))
break; break;
const ReplayHeader& rh = replay.pheader; if (replay.pheader.flag & REPLAY_SINGLE_MODE)
if(rh.flag & REPLAY_SINGLE_MODE)
break; break;
int player_count = (rh.flag & REPLAY_TAG) ? 4 : 2; for (size_t i = 0; i < replay.decks.size(); ++i) {
//player name BufferIO::CopyWideString(replay.players[Replay::GetDeckPlayer(i)].c_str(), namebuf[i]);
for(int i = 0; i < player_count; ++i)
replay.ReadName(namebuf[i]);
//skip pre infos
for(int i = 0; i < 4; ++i)
replay.ReadInt32();
//deck
std::vector<int> deckbuf;
for(int i = 0; i < player_count; ++i) {
deckbuf.clear();
int main = replay.ReadInt32();
deckbuf.push_back(main);
for (int j = 0; j < main; ++j) {
deckbuf.push_back(replay.ReadInt32());
}
int extra = replay.ReadInt32();
deckbuf.push_back(extra);
for (int j = 0; j < extra; ++j) {
deckbuf.push_back(replay.ReadInt32());
}
deckbuf.push_back(0);
FileSystem::SafeFileName(namebuf[i]); FileSystem::SafeFileName(namebuf[i]);
myswprintf(filename, L"deck/%ls-%d %ls.ydk", ex_filename, i + 1, namebuf[i]); }
deckManager.SaveDeckBuffer(deckbuf.data(), filename); for (size_t i = 0; i < replay.decks.size(); ++i) {
myswprintf(filename, L"./deck/%ls-%d %ls.ydk", replay_filename, i + 1, namebuf[i]);
DeckManager::SaveReplayDeck(replay.decks[i], filename);
} }
mainGame->stACMessage->setText(dataManager.GetSysString(1335)); mainGame->stACMessage->setText(dataManager.GetSysString(1335));
mainGame->PopupElement(mainGame->wACMessage, 20); mainGame->PopupElement(mainGame->wACMessage, 20);
...@@ -536,7 +517,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) { ...@@ -536,7 +517,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
wchar_t replay_path[256]{}; wchar_t replay_path[256]{};
myswprintf(replay_path, L"./replay/%ls", mainGame->lstReplayList->getListItem(sel)); myswprintf(replay_path, L"./replay/%ls", mainGame->lstReplayList->getListItem(sel));
if (!ReplayMode::cur_replay.OpenReplay(replay_path)) { if (!ReplayMode::cur_replay.OpenReplay(replay_path)) {
mainGame->stReplayInfo->setText(L""); mainGame->stReplayInfo->setText(L"Error");
break; break;
} }
wchar_t infobuf[256]{}; wchar_t infobuf[256]{};
...@@ -548,17 +529,17 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) { ...@@ -548,17 +529,17 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
curtime = ReplayMode::cur_replay.pheader.seed; curtime = ReplayMode::cur_replay.pheader.seed;
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);
wchar_t namebuf[4][20]{}; if (ReplayMode::cur_replay.pheader.flag & REPLAY_SINGLE_MODE) {
ReplayMode::cur_replay.ReadName(namebuf[0]); wchar_t path[256]{};
ReplayMode::cur_replay.ReadName(namebuf[1]); BufferIO::DecodeUTF8(ReplayMode::cur_replay.script_name.c_str(), path);
if(ReplayMode::cur_replay.pheader.flag & REPLAY_TAG) { repinfo.append(path);
ReplayMode::cur_replay.ReadName(namebuf[2]); repinfo.append(L"\n");
ReplayMode::cur_replay.ReadName(namebuf[3]);
} }
const auto& player_names = ReplayMode::cur_replay.players;
if(ReplayMode::cur_replay.pheader.flag & REPLAY_TAG) if(ReplayMode::cur_replay.pheader.flag & REPLAY_TAG)
myswprintf(infobuf, L"%ls\n%ls\n===VS===\n%ls\n%ls\n", namebuf[0], namebuf[1], namebuf[2], namebuf[3]); 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", namebuf[0], namebuf[1]); myswprintf(infobuf, L"%ls\n===VS===\n%ls\n", player_names[0].c_str(), player_names[1].c_str());
repinfo.append(infobuf); repinfo.append(infobuf);
mainGame->ebRepStartTurn->setText(L"1"); mainGame->ebRepStartTurn->setText(L"1");
mainGame->SetStaticText(mainGame->stReplayInfo, 180, mainGame->guiFont, repinfo.c_str()); mainGame->SetStaticText(mainGame->stReplayInfo, 180, mainGame->guiFont, repinfo.c_str());
......
#include "replay.h" #include "replay.h"
#include "myfilesystem.h" #include "myfilesystem.h"
#include "network.h"
#include "lzma/LzmaLib.h" #include "lzma/LzmaLib.h"
namespace ygo { namespace ygo {
...@@ -58,9 +59,7 @@ void Replay::BeginRecord() { ...@@ -58,9 +59,7 @@ void Replay::BeginRecord() {
#ifdef YGOPRO_SERVER_MODE #ifdef YGOPRO_SERVER_MODE
} }
#endif //YGOPRO_SERVER_MODE #endif //YGOPRO_SERVER_MODE
replay_size = 0; Reset();
comp_size = 0;
is_replaying = false;
is_recording = true; is_recording = true;
} }
void Replay::WriteHeader(ReplayHeader& header) { void Replay::WriteHeader(ReplayHeader& header) {
...@@ -156,11 +155,7 @@ bool Replay::OpenReplay(const wchar_t* name) { ...@@ -156,11 +155,7 @@ bool Replay::OpenReplay(const wchar_t* name) {
if(!rfp) if(!rfp)
return false; return false;
data_position = 0; Reset();
is_recording = false;
is_replaying = false;
replay_size = 0;
comp_size = 0;
if(std::fread(&pheader, sizeof pheader, 1, rfp) < 1) { if(std::fread(&pheader, sizeof pheader, 1, rfp) < 1) {
std::fclose(rfp); std::fclose(rfp);
return false; return false;
...@@ -183,6 +178,13 @@ bool Replay::OpenReplay(const wchar_t* name) { ...@@ -183,6 +178,13 @@ bool Replay::OpenReplay(const wchar_t* name) {
comp_size = 0; comp_size = 0;
} }
is_replaying = true; is_replaying = true;
can_read = true;
if (!ReadInfo()) {
Reset();
return false;
}
info_offset = data_position;
data_position = 0;
return true; return true;
} }
bool Replay::CheckReplay(const wchar_t* name) { bool Replay::CheckReplay(const wchar_t* name) {
...@@ -222,10 +224,6 @@ bool Replay::ReadNextResponse(unsigned char resp[]) { ...@@ -222,10 +224,6 @@ bool Replay::ReadNextResponse(unsigned char resp[]) {
unsigned char len{}; unsigned char len{};
if (!ReadData(&len, sizeof len)) if (!ReadData(&len, sizeof len))
return false; return false;
if (len > SIZE_RETURN_VALUE) {
is_replaying = false;
return false;
}
if (!ReadData(resp, len)) if (!ReadData(resp, len))
return false; return false;
return true; return true;
...@@ -242,10 +240,10 @@ void Replay::ReadHeader(ReplayHeader& header) { ...@@ -242,10 +240,10 @@ void Replay::ReadHeader(ReplayHeader& header) {
header = pheader; header = pheader;
} }
bool Replay::ReadData(void* data, size_t length) { bool Replay::ReadData(void* data, size_t length) {
if(!is_replaying) if (!is_replaying || !can_read)
return false; return false;
if (data_position + length > replay_size) { if (data_position + length > replay_size) {
is_replaying = false; can_read = false;
return false; return false;
} }
if (length) if (length)
...@@ -258,6 +256,73 @@ int32_t Replay::ReadInt32() { ...@@ -258,6 +256,73 @@ int32_t Replay::ReadInt32() {
} }
void Replay::Rewind() { void Replay::Rewind() {
data_position = 0; data_position = 0;
can_read = true;
}
void Replay::Reset() {
is_recording = false;
is_replaying = false;
can_read = false;
replay_size = 0;
comp_size = 0;
data_position = 0;
info_offset = 0;
players.clear();
params = { 0 };
decks.clear();
script_name.clear();
}
void Replay::SkipInfo(){
data_position += info_offset;
}
bool Replay::ReadInfo() {
int player_count = (pheader.flag & REPLAY_TAG) ? 4 : 2;
for (int i = 0; i < player_count; ++i) {
wchar_t name[20]{};
if (!ReadName(name))
return false;
players.push_back(name);
}
if (!ReadData(&params, sizeof params))
return false;
bool is_tag1 = pheader.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) {
uint16_t slen = Read<uint16_t>();
char filename[256]{};
if (slen == 0 || slen > sizeof(filename) - 1)
return false;
if (!ReadData(filename, slen))
return false;
filename[slen] = 0;
if (std::strncmp(filename, "./single/", 9))
return false;
script_name = filename + 9;
if (script_name.find_first_of(R"(/\)") != std::string::npos)
return false;
}
else {
for (int p = 0; p < player_count; ++p) {
ReplayDeck deck;
uint32_t main = Read<uint32_t>();
if (main > MAINC_MAX)
return false;
if (main)
deck.main.resize(main);
if (!ReadData(deck.main.data(), main * sizeof(uint32_t)))
return false;
uint32_t extra = Read<uint32_t>();
if (extra > MAINC_MAX)
return false;
if (extra)
deck.extra.resize(extra);
if (!ReadData(deck.extra.data(), extra * sizeof(uint32_t)))
return false;
decks.push_back(deck);
}
}
return true;
} }
} }
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#define REPLAY_H #define REPLAY_H
#include "config.h" #include "config.h"
#include "deck_manager.h"
namespace ygo { namespace ygo {
...@@ -13,7 +14,7 @@ namespace ygo { ...@@ -13,7 +14,7 @@ namespace ygo {
#define REPLAY_UNIFORM 0x10 #define REPLAY_UNIFORM 0x10
// max size // max size
constexpr int MAX_REPLAY_SIZE = 0x20000; constexpr int MAX_REPLAY_SIZE = 0x80000;
constexpr int MAX_COMP_SIZE = UINT16_MAX + 1; constexpr int MAX_COMP_SIZE = UINT16_MAX + 1;
#ifdef YGOPRO_SERVER_MODE #ifdef YGOPRO_SERVER_MODE
...@@ -35,6 +36,13 @@ struct ReplayHeader { ...@@ -35,6 +36,13 @@ struct ReplayHeader {
uint8_t props[8]{}; uint8_t props[8]{};
}; };
struct DuelParameters {
int32_t start_lp{};
int32_t start_hand{};
int32_t draw_count{};
uint32_t duel_flag{};
};
class Replay { class Replay {
public: public:
Replay(); Replay();
...@@ -54,10 +62,20 @@ public: ...@@ -54,10 +62,20 @@ public:
void SaveReplay(const wchar_t* name); void SaveReplay(const wchar_t* name);
// play // play
bool OpenReplay(const wchar_t* name);
static bool CheckReplay(const wchar_t* name); static bool CheckReplay(const wchar_t* name);
static bool DeleteReplay(const wchar_t* name); static bool DeleteReplay(const wchar_t* name);
static bool RenameReplay(const wchar_t* oldname, const wchar_t* newname); static bool RenameReplay(const wchar_t* oldname, const wchar_t* newname);
static size_t GetDeckPlayer(size_t deck_index) {
switch (deck_index) {
case 2:
return 3;
case 3:
return 2;
default:
return deck_index;
}
}
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(ReplayHeader& header);
...@@ -70,6 +88,8 @@ public: ...@@ -70,6 +88,8 @@ public:
} }
int32_t ReadInt32(); int32_t ReadInt32();
void Rewind(); void Rewind();
void Reset();
void SkipInfo();
FILE* fp{ nullptr }; FILE* fp{ nullptr };
#ifdef _WIN32 #ifdef _WIN32
...@@ -80,12 +100,22 @@ public: ...@@ -80,12 +100,22 @@ public:
unsigned char* comp_data; unsigned char* comp_data;
size_t comp_size{}; size_t comp_size{};
std::vector<std::wstring> players; // 80 or 160 bytes
DuelParameters params; // 16 bytes
std::vector<ReplayDeck> decks; // 4 bytes, main deck, 4 bytes, extra deck
std::string script_name; // 2 bytes, script name (max: 256 bytes)
private: private:
bool ReadInfo();
unsigned char* replay_data; unsigned char* replay_data;
size_t replay_size{}; size_t replay_size{};
size_t data_position{}; size_t data_position{};
size_t info_offset{};
bool is_recording{}; bool is_recording{};
bool is_replaying{}; bool is_replaying{};
bool can_read{};
}; };
} }
......
...@@ -158,91 +158,67 @@ bool ReplayMode::StartDuel() { ...@@ -158,91 +158,67 @@ bool ReplayMode::StartDuel() {
const ReplayHeader& rh = cur_replay.pheader; const ReplayHeader& rh = cur_replay.pheader;
unsigned int seed = rh.seed; unsigned int seed = rh.seed;
std::mt19937 rnd(seed); std::mt19937 rnd(seed);
cur_replay.SkipInfo();
if(mainGame->dInfo.isTag) { if(mainGame->dInfo.isTag) {
cur_replay.ReadName(mainGame->dInfo.hostname); BufferIO::CopyWideString(cur_replay.players[0].c_str(), mainGame->dInfo.hostname);
cur_replay.ReadName(mainGame->dInfo.hostname_tag); BufferIO::CopyWideString(cur_replay.players[1].c_str(), mainGame->dInfo.hostname_tag);
cur_replay.ReadName(mainGame->dInfo.clientname_tag); BufferIO::CopyWideString(cur_replay.players[2].c_str(), mainGame->dInfo.clientname_tag);
cur_replay.ReadName(mainGame->dInfo.clientname); BufferIO::CopyWideString(cur_replay.players[3].c_str(), mainGame->dInfo.clientname);
} else { } else {
cur_replay.ReadName(mainGame->dInfo.hostname); BufferIO::CopyWideString(cur_replay.players[0].c_str(), mainGame->dInfo.hostname);
cur_replay.ReadName(mainGame->dInfo.clientname); BufferIO::CopyWideString(cur_replay.players[1].c_str(), mainGame->dInfo.clientname);
} }
pduel = create_duel(rnd()); pduel = create_duel(rnd());
int start_lp = cur_replay.ReadInt32(); mainGame->dInfo.duel_rule = cur_replay.params.duel_flag >> 16;
int start_hand = cur_replay.ReadInt32(); set_player_info(pduel, 0, cur_replay.params.start_lp, cur_replay.params.start_hand, cur_replay.params.draw_count);
int draw_count = cur_replay.ReadInt32(); set_player_info(pduel, 1, cur_replay.params.start_lp, cur_replay.params.start_hand, cur_replay.params.draw_count);
int opt = cur_replay.ReadInt32();
int duel_rule = opt >> 16;
mainGame->dInfo.duel_rule = duel_rule;
set_player_info(pduel, 0, start_lp, start_hand, draw_count);
set_player_info(pduel, 1, start_lp, start_hand, draw_count);
preload_script(pduel, "./script/special.lua"); preload_script(pduel, "./script/special.lua");
preload_script(pduel, "./script/init.lua"); preload_script(pduel, "./script/init.lua");
mainGame->dInfo.lp[0] = start_lp; mainGame->dInfo.lp[0] = cur_replay.params.start_lp;
mainGame->dInfo.lp[1] = start_lp; mainGame->dInfo.lp[1] = cur_replay.params.start_lp;
mainGame->dInfo.start_lp = start_lp; mainGame->dInfo.start_lp = cur_replay.params.start_lp;
myswprintf(mainGame->dInfo.strLP[0], L"%d", mainGame->dInfo.lp[0]); myswprintf(mainGame->dInfo.strLP[0], L"%d", mainGame->dInfo.lp[0]);
myswprintf(mainGame->dInfo.strLP[1], L"%d", mainGame->dInfo.lp[1]); myswprintf(mainGame->dInfo.strLP[1], L"%d", mainGame->dInfo.lp[1]);
mainGame->dInfo.turn = 0; mainGame->dInfo.turn = 0;
if(!mainGame->dInfo.isSingleMode) { if(!(rh.flag & REPLAY_SINGLE_MODE)) {
if(!(opt & DUEL_TAG_MODE)) { if(!(rh.flag & REPLAY_TAG)) {
int main = cur_replay.ReadInt32(); for (int i = 0; i < 2; ++i) {
for(int i = 0; i < main; ++i) for (const auto& code : cur_replay.decks[i].main)
new_card(pduel, cur_replay.ReadInt32(), 0, 0, LOCATION_DECK, 0, POS_FACEDOWN_DEFENSE); new_card(pduel, code, i, i, LOCATION_DECK, 0, POS_FACEDOWN_DEFENSE);
int extra = cur_replay.ReadInt32(); for (const auto& code : cur_replay.decks[i].extra)
for(int i = 0; i < extra; ++i) new_card(pduel, code, i, i, LOCATION_EXTRA, 0, POS_FACEDOWN_DEFENSE);
new_card(pduel, cur_replay.ReadInt32(), 0, 0, LOCATION_EXTRA, 0, POS_FACEDOWN_DEFENSE); mainGame->dField.Initial(mainGame->LocalPlayer(i), cur_replay.decks[i].main.size(), cur_replay.decks[i].extra.size());
mainGame->dField.Initial(mainGame->LocalPlayer(0), main, extra); }
main = cur_replay.ReadInt32();
for(int i = 0; i < main; ++i)
new_card(pduel, cur_replay.ReadInt32(), 1, 1, LOCATION_DECK, 0, POS_FACEDOWN_DEFENSE);
extra = cur_replay.ReadInt32();
for(int i = 0; i < extra; ++i)
new_card(pduel, cur_replay.ReadInt32(), 1, 1, LOCATION_EXTRA, 0, POS_FACEDOWN_DEFENSE);
mainGame->dField.Initial(mainGame->LocalPlayer(1), main, extra);
} else { } else {
int main = cur_replay.ReadInt32(); for (const auto& code : cur_replay.decks[0].main)
for(int i = 0; i < main; ++i) new_card(pduel, code, 0, 0, LOCATION_DECK, 0, POS_FACEDOWN_DEFENSE);
new_card(pduel, cur_replay.ReadInt32(), 0, 0, LOCATION_DECK, 0, POS_FACEDOWN_DEFENSE); for (const auto& code : cur_replay.decks[0].extra)
int extra = cur_replay.ReadInt32(); new_card(pduel, code, 0, 0, LOCATION_EXTRA, 0, POS_FACEDOWN_DEFENSE);
for(int i = 0; i < extra; ++i) mainGame->dField.Initial(mainGame->LocalPlayer(0), cur_replay.decks[0].main.size(), cur_replay.decks[0].extra.size());
new_card(pduel, cur_replay.ReadInt32(), 0, 0, LOCATION_EXTRA, 0, POS_FACEDOWN_DEFENSE); for (const auto& code : cur_replay.decks[1].main)
mainGame->dField.Initial(mainGame->LocalPlayer(0), main, extra); new_tag_card(pduel, code, 0, LOCATION_DECK);
main = cur_replay.ReadInt32(); for (const auto& code : cur_replay.decks[1].extra)
for(int i = 0; i < main; ++i) new_tag_card(pduel, code, 0, LOCATION_EXTRA);
new_tag_card(pduel, cur_replay.ReadInt32(), 0, LOCATION_DECK); for (const auto& code : cur_replay.decks[2].main)
extra = cur_replay.ReadInt32(); new_card(pduel, code, 1, 1, LOCATION_DECK, 0, POS_FACEDOWN_DEFENSE);
for(int i = 0; i < extra; ++i) for (const auto& code : cur_replay.decks[2].extra)
new_tag_card(pduel, cur_replay.ReadInt32(), 0, LOCATION_EXTRA); new_card(pduel, code, 1, 1, LOCATION_EXTRA, 0, POS_FACEDOWN_DEFENSE);
main = cur_replay.ReadInt32(); mainGame->dField.Initial(mainGame->LocalPlayer(1), cur_replay.decks[2].main.size(), cur_replay.decks[2].extra.size());
for(int i = 0; i < main; ++i) for (const auto& code : cur_replay.decks[3].main)
new_card(pduel, cur_replay.ReadInt32(), 1, 1, LOCATION_DECK, 0, POS_FACEDOWN_DEFENSE); new_tag_card(pduel, code, 1, LOCATION_DECK);
extra = cur_replay.ReadInt32(); for (const auto& code : cur_replay.decks[3].extra)
for(int i = 0; i < extra; ++i) new_tag_card(pduel, code, 1, LOCATION_EXTRA);
new_card(pduel, cur_replay.ReadInt32(), 1, 1, LOCATION_EXTRA, 0, POS_FACEDOWN_DEFENSE);
mainGame->dField.Initial(mainGame->LocalPlayer(1), main, extra);
main = cur_replay.ReadInt32();
for(int i = 0; i < main; ++i)
new_tag_card(pduel, cur_replay.ReadInt32(), 1, LOCATION_DECK);
extra = cur_replay.ReadInt32();
for(int i = 0; i < extra; ++i)
new_tag_card(pduel, cur_replay.ReadInt32(), 1, LOCATION_EXTRA);
} }
} else { } else {
char filename[256]; char filename[256]{};
auto slen = cur_replay.Read<uint16_t>(); std::snprintf(filename, sizeof filename, "./single/%s", cur_replay.script_name.c_str());
if (slen > sizeof(filename) - 1) {
return false;
}
cur_replay.ReadData(filename, slen);
filename[slen] = 0;
if(!preload_script(pduel, filename)) { if(!preload_script(pduel, filename)) {
return false; return false;
} }
} }
if (!(rh.flag & REPLAY_UNIFORM)) if (!(rh.flag & REPLAY_UNIFORM))
opt |= DUEL_OLD_REPLAY; cur_replay.params.duel_flag |= DUEL_OLD_REPLAY;
start_duel(pduel, opt); start_duel(pduel, cur_replay.params.duel_flag);
return true; return true;
} }
void ReplayMode::EndDuel() { void ReplayMode::EndDuel() {
......
...@@ -62,12 +62,10 @@ project "irrlicht" ...@@ -62,12 +62,10 @@ project "irrlicht"
"NO__IRR_COMPILE_WITH_WAD_ARCHIVE_LOADER_", "NO__IRR_COMPILE_WITH_WAD_ARCHIVE_LOADER_",
"NO_IRR_COMPILE_WITH_ZIP_ENCRYPTION_", "NO_IRR_COMPILE_WITH_ZIP_ENCRYPTION_",
"PNG_INTEL_SSE", "PNG_INTEL_SSE",
"PNG_ARM_NEON_OPT=0",
"PNG_ARM_NEON_IMPLEMENTATION=0",
} }
if IS_ARM then
defines { "PNG_ARM_NEON_OPT=0", "PNG_ARM_NEON_IMPLEMENTATION=0" }
end
files { files {
"include/*.h", "include/*.h",
"source/Irrlicht/*.cpp", "source/Irrlicht/*.cpp",
......
...@@ -118,7 +118,7 @@ project "miniaudio" ...@@ -118,7 +118,7 @@ project "miniaudio"
"external/vorbis/include", "external/vorbis/include",
} }
defines { defines {
"OPUS_BUILD", "USE_ALLOCA", "OPUS_BUILD", "USE_ALLOCA", "HAVE_LRINTF", "OP_HAVE_LRINTF",
"OPUS_X86_PRESUME_SSE", "OPUS_X86_PRESUME_SSE2", "OPUS_X86_PRESUME_SSE", "OPUS_X86_PRESUME_SSE2",
"OPUS_HAVE_RTCD", "OPUS_X86_MAY_HAVE_SSE", "OPUS_X86_MAY_HAVE_SSE4_1", "OPUS_X86_MAY_HAVE_AVX2", "OPUS_HAVE_RTCD", "OPUS_X86_MAY_HAVE_SSE", "OPUS_X86_MAY_HAVE_SSE4_1", "OPUS_X86_MAY_HAVE_AVX2",
} }
......
...@@ -12,6 +12,7 @@ USE_AUDIO = true ...@@ -12,6 +12,7 @@ USE_AUDIO = true
AUDIO_LIB = "miniaudio" AUDIO_LIB = "miniaudio"
MINIAUDIO_SUPPORT_OPUS_VORBIS = true MINIAUDIO_SUPPORT_OPUS_VORBIS = true
MINIAUDIO_BUILD_OPUS_VORBIS = os.istarget("windows") MINIAUDIO_BUILD_OPUS_VORBIS = os.istarget("windows")
IRRKLANG_PRO = false
IRRKLANG_PRO_BUILD_IKPMP3 = false IRRKLANG_PRO_BUILD_IKPMP3 = false
SERVER_MODE = true SERVER_MODE = true
...@@ -49,26 +50,6 @@ newoption { trigger = "build-irrlicht", category = "YGOPro - irrlicht", descript ...@@ -49,26 +50,6 @@ newoption { trigger = "build-irrlicht", category = "YGOPro - irrlicht", descript
newoption { trigger = "no-build-irrlicht", category = "YGOPro - irrlicht", description = "" } newoption { trigger = "no-build-irrlicht", category = "YGOPro - irrlicht", description = "" }
newoption { trigger = "irrlicht-include-dir", category = "YGOPro - irrlicht", description = "", value = "PATH" } newoption { trigger = "irrlicht-include-dir", category = "YGOPro - irrlicht", description = "", value = "PATH" }
newoption { trigger = "irrlicht-lib-dir", category = "YGOPro - irrlicht", description = "", value = "PATH" } newoption { trigger = "irrlicht-lib-dir", category = "YGOPro - irrlicht", description = "", value = "PATH" }
newoption { trigger = "no-audio", category = "YGOPro", description = "" }
newoption { trigger = "audio-lib", category = "YGOPro", description = "", value = "miniaudio, irrklang", default = AUDIO_LIB }
newoption { trigger = "miniaudio-include-dir", category = "YGOPro - miniaudio", description = "", value = "PATH" }
newoption { trigger = "miniaudio-lib-dir", category = "YGOPro - miniaudio", description = "", value = "PATH" }
newoption { trigger = "miniaudio-support-opus-vorbis", category = "YGOPro - miniaudio", description = "" }
newoption { trigger = "no-miniaudio-support-opus-vorbis", category = "YGOPro - miniaudio", description = "" }
newoption { trigger = "build-opus-vorbis", category = "YGOPro - miniaudio", description = "" }
newoption { trigger = "no-build-opus-vorbis", category = "YGOPro - miniaudio", description = "" }
newoption { trigger = "opus-include-dir", category = "YGOPro - miniaudio", description = "", value = "PATH" }
newoption { trigger = "opus-lib-dir", category = "YGOPro - miniaudio", description = "", value = "PATH" }
newoption { trigger = "vorbis-include-dir", category = "YGOPro - miniaudio", description = "", value = "PATH" }
newoption { trigger = "vorbis-lib-dir", category = "YGOPro - miniaudio", description = "", value = "PATH" }
newoption { trigger = "ogg-include-dir", category = "YGOPro - miniaudio", description = "", value = "PATH" }
newoption { trigger = "ogg-lib-dir", category = "YGOPro - miniaudio", description = "", value = "PATH" }
newoption { trigger = "use-irrklang", category = "YGOPro - irrklang", description = "Deprecated, use audio-lib=irrklang" }
newoption { trigger = "no-use-irrklang", category = "YGOPro - irrklang", description = "Deprecated, use no-audio" }
newoption { trigger = "irrklang-include-dir", category = "YGOPro - irrklang", description = "", value = "PATH" }
newoption { trigger = "irrklang-lib-dir", category = "YGOPro - irrklang", description = "", value = "PATH" }
newoption { trigger = "no-audio", category = "YGOPro", description = "" } newoption { trigger = "no-audio", category = "YGOPro", description = "" }
newoption { trigger = "audio-lib", category = "YGOPro", description = "", value = "miniaudio, irrklang", default = AUDIO_LIB } newoption { trigger = "audio-lib", category = "YGOPro", description = "", value = "miniaudio, irrklang", default = AUDIO_LIB }
......
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