Commit 588c886b authored by mercury233's avatar mercury233

Merge branch 'master' of https://github.com/Fluorohydride/ygopro into server

parents f49949d1 c3e25993
Pipeline #36609 passed with stages
in 4 minutes and 9 seconds
...@@ -313,9 +313,7 @@ jobs: ...@@ -313,9 +313,7 @@ jobs:
- name: Use premake to generate make files - name: Use premake to generate make files
run: | run: |
./premake5 gmake \ ./premake5 gmake
--freetype-include-dir="/usr/include/freetype2" \
--opus-include-dir="/usr/include/opus"
- name: Make - name: Make
run: | run: |
...@@ -406,31 +404,9 @@ jobs: ...@@ -406,31 +404,9 @@ jobs:
cp -r premake/* . cp -r premake/* .
cp -r resource/* . cp -r resource/* .
- name: Use premake to generate make files (Intel) - name: Use premake to generate make files
if: runner.arch == 'X64' run: |
run: | DYLD_LIBRARY_PATH=$(brew --prefix)/lib ./premake5 gmake --cc=clang
./premake5 gmake \
--cc=clang \
--freetype-include-dir="/usr/local/include/freetype2" \
--opus-include-dir="/usr/local/include/opus"
- name: Use premake to generate make files (ARM64)
if: runner.arch == 'ARM64'
run: |
./premake5 gmake \
--cc=clang \
--event-include-dir="/opt/homebrew/include" \
--event-lib-dir="/opt/homebrew/lib" \
--freetype-include-dir="/opt/homebrew/include/freetype2" \
--freetype-lib-dir="/opt/homebrew/lib" \
--sqlite-include-dir="/opt/homebrew/opt/sqlite/include" \
--sqlite-lib-dir="/opt/homebrew/opt/sqlite/lib" \
--miniaudio-include-dir="/opt/homebrew/include" \
--miniaudio-lib-dir="/opt/homebrew/lib" \
--opus-include-dir="/opt/homebrew/include/opus" \
--opus-lib-dir="/opt/homebrew/lib" \
--vorbis-include-dir="/opt/homebrew/include" \
--vorbis-lib-dir="/opt/homebrew/lib"
- name: Make - name: Make
run: | run: |
......
...@@ -32,7 +32,7 @@ public: ...@@ -32,7 +32,7 @@ public:
* @brief Copy a C-style string to another C-style string. * @brief Copy a C-style string to another C-style string.
* @param src The source wide string * @param src The source wide string
* @param pstr The destination char string * @param pstr The destination char string
* @param bufsize The size of the destination buffer * @param bufsize The length of the destination buffer
* @return The length of the copied string * @return The length of the copied string
*/ */
template<typename T1, typename T2> template<typename T1, typename T2>
...@@ -62,13 +62,13 @@ public: ...@@ -62,13 +62,13 @@ public:
} }
template<size_t N> template<size_t N>
static void CopyString(const char* src, char(&dst)[N]) { static void CopyString(const char* src, char(&dst)[N]) {
dst[0] = 0; std::strncpy(dst, src, N - 1);
std::strncat(dst, src, N - 1); dst[N - 1] = 0;
} }
template<size_t N> template<size_t N>
static void CopyWideString(const wchar_t* src, wchar_t(&dst)[N]) { static void CopyWideString(const wchar_t* src, wchar_t(&dst)[N]) {
dst[0] = 0; std::wcsncpy(dst, src, N - 1);
std::wcsncat(dst, src, N - 1); dst[N - 1] = 0;
} }
template<typename T> template<typename T>
static bool CheckUTF8Byte(const T* str, int len) { static bool CheckUTF8Byte(const T* str, int len) {
......
...@@ -1262,7 +1262,12 @@ void Game::DrawDeckBd() { ...@@ -1262,7 +1262,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)
{ {
......
...@@ -1621,7 +1621,7 @@ void Game::ShowCardInfo(int code, bool resize) { ...@@ -1621,7 +1621,7 @@ void Game::ShowCardInfo(int code, bool resize) {
myswprintf(formatBuffer, L"%ls[%08d]", dataManager.GetName(code), code); myswprintf(formatBuffer, L"%ls[%08d]", dataManager.GetName(code), code);
} }
stName->setText(formatBuffer); stName->setText(formatBuffer);
if(guiFont->getDimension(formatBuffer).Width > stName->getRelativePosition().getWidth() - gameConf.textfontsize) if((int)guiFont->getDimension(formatBuffer).Width > stName->getRelativePosition().getWidth() - gameConf.textfontsize)
stName->setToolTipText(formatBuffer); stName->setToolTipText(formatBuffer);
else else
stName->setToolTipText(nullptr); stName->setToolTipText(nullptr);
......
...@@ -35,11 +35,17 @@ int main(int argc, char* argv[]) { ...@@ -35,11 +35,17 @@ int main(int argc, char* argv[]) {
#if defined __APPLE__ && !defined YGOPRO_SERVER_MODE #if defined __APPLE__ && !defined YGOPRO_SERVER_MODE
CFURLRef bundle_url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); CFURLRef bundle_url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
CFURLRef bundle_base_url = CFURLCreateCopyDeletingLastPathComponent(nullptr, bundle_url); CFURLRef bundle_base_url = CFURLCreateCopyDeletingLastPathComponent(nullptr, bundle_url);
CFStringRef bundle_ext = CFURLCopyPathExtension(bundle_url);
if (bundle_ext) {
char path[PATH_MAX];
if (CFStringCompare(bundle_ext, CFSTR("app"), kCFCompareCaseInsensitive) == kCFCompareEqualTo
&& CFURLGetFileSystemRepresentation(bundle_base_url, true, (UInt8*)path, PATH_MAX)) {
chdir(path);
}
CFRelease(bundle_ext);
}
CFRelease(bundle_url); CFRelease(bundle_url);
CFStringRef path = CFURLCopyFileSystemPath(bundle_base_url, kCFURLPOSIXPathStyle);
CFRelease(bundle_base_url); CFRelease(bundle_base_url);
chdir(CFStringGetCStringPtr(path, kCFStringEncodingUTF8));
CFRelease(path);
#endif //__APPLE__ #endif //__APPLE__
#ifdef _WIN32 #ifdef _WIN32
if (argc == 2 && (ygo::IsExtension(argv[1], ".ydk") || ygo::IsExtension(argv[1], ".yrp"))) { // open file from explorer if (argc == 2 && (ygo::IsExtension(argv[1], ".ydk") || ygo::IsExtension(argv[1], ".yrp"))) { // open file from explorer
......
#include "image_manager.h" #include "image_manager.h"
#include "game.h" #include "game.h"
#ifdef YGOPRO_USE_THUMB_LOAD_THREAD
#include <thread> #include <thread>
#endif
#ifdef _OPENMP
#include <omp.h>
#endif
namespace ygo { namespace ygo {
...@@ -17,8 +22,10 @@ bool ImageManager::Initial() { ...@@ -17,8 +22,10 @@ bool ImageManager::Initial() {
tUnknownFit = nullptr; tUnknownFit = nullptr;
tUnknownThumb = nullptr; tUnknownThumb = nullptr;
tBigPicture = nullptr; tBigPicture = nullptr;
#ifdef YGOPRO_USE_THUMB_LOAD_THREAD
tLoading = nullptr; tLoading = nullptr;
tThumbLoadingThreadRunning = false; tThumbLoadingThreadRunning = false;
#endif
tAct = driver->getTexture("textures/act.png"); tAct = driver->getTexture("textures/act.png");
tAttack = driver->getTexture("textures/attack.png"); tAttack = driver->getTexture("textures/attack.png");
tChain = driver->getTexture("textures/chain.png"); tChain = driver->getTexture("textures/chain.png");
...@@ -59,7 +66,11 @@ void ImageManager::ClearTexture() { ...@@ -59,7 +66,11 @@ 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_THREAD
if(tit->second && tit->second != tLoading) if(tit->second && tit->second != tLoading)
#else
if(tit->second)
#endif
driver->removeTexture(tit->second); driver->removeTexture(tit->second);
} }
if(tBigPicture != nullptr) { if(tBigPicture != nullptr) {
...@@ -69,12 +80,14 @@ void ImageManager::ClearTexture() { ...@@ -69,12 +80,14 @@ void ImageManager::ClearTexture() {
tMap[0].clear(); tMap[0].clear();
tMap[1].clear(); tMap[1].clear();
tThumb.clear(); tThumb.clear();
#ifdef YGOPRO_USE_THUMB_LOAD_THREAD
tThumbLoadingMutex.lock(); tThumbLoadingMutex.lock();
tThumbLoading.clear(); tThumbLoading.clear();
while(!tThumbLoadingCodes.empty()) while(!tThumbLoadingCodes.empty())
tThumbLoadingCodes.pop(); tThumbLoadingCodes.pop();
tThumbLoadingThreadRunning = false; tThumbLoadingThreadRunning = false;
tThumbLoadingMutex.unlock(); tThumbLoadingMutex.unlock();
#endif
tFields.clear(); tFields.clear();
} }
void ImageManager::RemoveTexture(int code) { void ImageManager::RemoveTexture(int code) {
...@@ -110,11 +123,13 @@ void ImageManager::ResizeTexture() { ...@@ -110,11 +123,13 @@ 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_THREAD
driver->removeTexture(tLoading); driver->removeTexture(tLoading);
tLoading = GetTextureFromFile("textures/cover.jpg", imgWidthThumb, imgHeightThumb);
#endif
tUnknown = GetTextureFromFile("textures/unknown.jpg", CARD_IMG_WIDTH, CARD_IMG_HEIGHT); tUnknown = GetTextureFromFile("textures/unknown.jpg", CARD_IMG_WIDTH, CARD_IMG_HEIGHT);
tUnknownFit = GetTextureFromFile("textures/unknown.jpg", imgWidthFit, imgHeightFit); tUnknownFit = GetTextureFromFile("textures/unknown.jpg", imgWidthFit, imgHeightFit);
tUnknownThumb = GetTextureFromFile("textures/unknown.jpg", imgWidthThumb, imgHeightThumb); tUnknownThumb = GetTextureFromFile("textures/unknown.jpg", imgWidthThumb, imgHeightThumb);
tLoading = GetTextureFromFile("textures/cover.jpg", imgWidthThumb, imgHeightThumb);
driver->removeTexture(tBackGround); driver->removeTexture(tBackGround);
tBackGround = GetTextureFromFile("textures/bg.jpg", bgWidth, bgHeight); tBackGround = GetTextureFromFile("textures/bg.jpg", bgWidth, bgHeight);
driver->removeTexture(tBackGround_menu); driver->removeTexture(tBackGround_menu);
...@@ -128,25 +143,27 @@ void ImageManager::ResizeTexture() { ...@@ -128,25 +143,27 @@ void ImageManager::ResizeTexture() {
} }
// function by Warr1024, from https://github.com/minetest/minetest/issues/2419 , modified // function by Warr1024, from https://github.com/minetest/minetest/issues/2419 , modified
void imageScaleNNAA(irr::video::IImage *src, irr::video::IImage *dest) { void imageScaleNNAA(irr::video::IImage *src, irr::video::IImage *dest) {
double sx, sy, minsx, maxsx, minsy, maxsy, area, ra, ga, ba, aa, pw, ph, pa; const irr::core::dimension2d<irr::u32> srcDim = src->getDimension();
irr::u32 dy, dx; const irr::core::dimension2d<irr::u32> destDim = dest->getDimension();
irr::video::SColor pxl;
// Cache rectsngle boundaries. // Cache scale ratios.
double sw = src->getDimension().Width * 1.0; const double rx = (double)srcDim.Width / destDim.Width;
double sh = src->getDimension().Height * 1.0; const double ry = (double)srcDim.Height / destDim.Height;
// Walk each destination image pixel. #pragma omp parallel
// Note: loop y around x for better cache locality. {
irr::core::dimension2d<irr::u32> dim = dest->getDimension(); double sx, sy, minsx, maxsx, minsy, maxsy, area, ra, ga, ba, aa, pw, ph, pa;
for(dy = 0; dy < dim.Height; dy++) irr::video::SColor pxl, npxl;
for(dx = 0; dx < dim.Width; dx++) {
// Walk each destination image pixel.
#pragma omp for schedule(dynamic)
for(irr::s32 dy = 0; dy < destDim.Height; dy++) {
for(irr::s32 dx = 0; dx < destDim.Width; dx++) {
// Calculate floating-point source rectangle bounds. // Calculate floating-point source rectangle bounds.
minsx = dx * sw / dim.Width; minsx = dx * rx;
maxsx = minsx + sw / dim.Width; maxsx = minsx + rx;
minsy = dy * sh / dim.Height; minsy = dy * ry;
maxsy = minsy + sh / dim.Height; maxsy = minsy + ry;
// Total area, and integral of r, g, b values over that area, // Total area, and integral of r, g, b values over that area,
// initialized to zero, to be summed up in next loops. // initialized to zero, to be summed up in next loops.
...@@ -157,9 +174,8 @@ void imageScaleNNAA(irr::video::IImage *src, irr::video::IImage *dest) { ...@@ -157,9 +174,8 @@ void imageScaleNNAA(irr::video::IImage *src, irr::video::IImage *dest) {
aa = 0; aa = 0;
// Loop over the integral pixel positions described by those bounds. // Loop over the integral pixel positions described by those bounds.
for(sy = floor(minsy); sy < maxsy; sy++) for(sy = floor(minsy); sy < maxsy; sy++) {
for(sx = floor(minsx); sx < maxsx; sx++) { for(sx = floor(minsx); sx < maxsx; sx++) {
// Calculate width, height, then area of dest pixel // Calculate width, height, then area of dest pixel
// that's covered by this source pixel. // that's covered by this source pixel.
pw = 1; pw = 1;
...@@ -183,21 +199,20 @@ void imageScaleNNAA(irr::video::IImage *src, irr::video::IImage *dest) { ...@@ -183,21 +199,20 @@ void imageScaleNNAA(irr::video::IImage *src, irr::video::IImage *dest) {
ba += pa * pxl.getBlue(); ba += pa * pxl.getBlue();
aa += pa * pxl.getAlpha(); aa += pa * pxl.getAlpha();
} }
}
// Set the destination image pixel to the average color. // Set the destination image pixel to the average color.
if(area > 0) { if(area > 0) {
pxl.setRed(ra / area + 0.5); npxl.set((irr::u32)(aa / area + 0.5),
pxl.setGreen(ga / area + 0.5); (irr::u32)(ra / area + 0.5),
pxl.setBlue(ba / area + 0.5); (irr::u32)(ga / area + 0.5),
pxl.setAlpha(aa / area + 0.5); (irr::u32)(ba / area + 0.5));
} else { } else {
pxl.setRed(0); npxl.set(0);
pxl.setGreen(0);
pxl.setBlue(0);
pxl.setAlpha(0);
} }
dest->setPixel(dx, dy, pxl); dest->setPixel(dx, dy, npxl);
} }
}
} // end of parallel region
} }
irr::video::ITexture* ImageManager::GetTextureFromFile(const char* file, irr::s32 width, irr::s32 height) { irr::video::ITexture* ImageManager::GetTextureFromFile(const char* file, irr::s32 width, irr::s32 height) {
if(mainGame->gameConf.use_image_scale) { if(mainGame->gameConf.use_image_scale) {
...@@ -283,6 +298,7 @@ irr::video::ITexture* ImageManager::GetBigPicture(int code, float zoom) { ...@@ -283,6 +298,7 @@ irr::video::ITexture* ImageManager::GetBigPicture(int code, float zoom) {
tBigPicture = texture; tBigPicture = texture;
return texture; return texture;
} }
#ifdef YGOPRO_USE_THUMB_LOAD_THREAD
int ImageManager::LoadThumbThread() { int ImageManager::LoadThumbThread() {
while(true) { while(true) {
imageManager.tThumbLoadingMutex.lock(); imageManager.tThumbLoadingMutex.lock();
...@@ -338,9 +354,34 @@ int ImageManager::LoadThumbThread() { ...@@ -338,9 +354,34 @@ int ImageManager::LoadThumbThread() {
imageManager.tThumbLoadingMutex.unlock(); imageManager.tThumbLoadingMutex.unlock();
return 0; return 0;
} }
#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_THREAD
auto tit = tThumb.find(code);
if(tit == tThumb.end()) {
char file[256];
std::snprintf(file, sizeof file, "expansions/pics/thumbnail/%d.jpg", code);
int width = CARD_THUMB_WIDTH * mainGame->xScale;
int height = CARD_THUMB_HEIGHT * mainGame->yScale;
irr::video::ITexture* img = GetTextureFromFile(file, width, height);
if(img == NULL) {
std::snprintf(file, sizeof file, "pics/thumbnail/%d.jpg", code);
img = GetTextureFromFile(file, width, height);
}
if(img == NULL && mainGame->gameConf.use_image_scale) {
std::snprintf(file, sizeof file, "expansions/pics/%d.jpg", code);
img = GetTextureFromFile(file, width, height);
if(img == NULL) {
std::snprintf(file, sizeof file, "pics/%d.jpg", code);
img = GetTextureFromFile(file, width, height);
}
}
tThumb[code] = img;
return (img == NULL) ? tUnknownThumb : img;
}
#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()) {
...@@ -368,6 +409,7 @@ irr::video::ITexture* ImageManager::GetTextureThumb(int code) { ...@@ -368,6 +409,7 @@ irr::video::ITexture* ImageManager::GetTextureThumb(int code) {
imageManager.tThumbLoadingMutex.unlock(); imageManager.tThumbLoadingMutex.unlock();
return tLoading; return tLoading;
} }
#endif // YGOPRO_USE_THUMB_LOAD_THREAD
if(tit->second) if(tit->second)
return tit->second; return tit->second;
else else
......
#ifndef IMAGEMANAGER_H #ifndef IMAGEMANAGER_H
#define IMAGEMANAGER_H #define IMAGEMANAGER_H
#ifndef _OPENMP
#define YGOPRO_USE_THUMB_LOAD_THREAD
#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_THREAD
#include <queue> #include <queue>
#include <mutex> #include <mutex>
#endif
namespace ygo { namespace ygo {
...@@ -21,15 +27,19 @@ public: ...@@ -21,15 +27,19 @@ 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_THREAD
static int LoadThumbThread(); static int LoadThumbThread();
#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_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;
bool tThumbLoadingThreadRunning; bool tThumbLoadingThreadRunning;
#endif
irr::IrrlichtDevice* device; irr::IrrlichtDevice* device;
irr::video::IVideoDriver* driver; irr::video::IVideoDriver* driver;
irr::video::ITexture* tCover[4]; irr::video::ITexture* tCover[4];
...@@ -37,7 +47,9 @@ public: ...@@ -37,7 +47,9 @@ 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_THREAD
irr::video::ITexture* tLoading; irr::video::ITexture* tLoading;
#endif
irr::video::ITexture* tAct; irr::video::ITexture* tAct;
irr::video::ITexture* tAttack; irr::video::ITexture* tAttack;
irr::video::ITexture* tNegated; irr::video::ITexture* tNegated;
......
...@@ -232,6 +232,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) { ...@@ -232,6 +232,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
break; break;
} }
case BUTTON_LOAD_REPLAY: { case BUTTON_LOAD_REPLAY: {
int start_turn = 1;
if(open_file) { if(open_file) {
ReplayMode::cur_replay.OpenReplay(open_file_name); ReplayMode::cur_replay.OpenReplay(open_file_name);
open_file = false; open_file = false;
...@@ -243,6 +244,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) { ...@@ -243,6 +244,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
myswprintf(replay_path, L"./replay/%ls", mainGame->lstReplayList->getListItem(selected)); myswprintf(replay_path, L"./replay/%ls", mainGame->lstReplayList->getListItem(selected));
if (!ReplayMode::cur_replay.OpenReplay(replay_path)) if (!ReplayMode::cur_replay.OpenReplay(replay_path))
break; break;
start_turn = std::wcstol(mainGame->ebRepStartTurn->getText(), nullptr, 10);
} }
mainGame->ClearCardInfo(); mainGame->ClearCardInfo();
mainGame->wCardImg->setVisible(true); mainGame->wCardImg->setVisible(true);
...@@ -257,7 +259,6 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) { ...@@ -257,7 +259,6 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
mainGame->dField.Clear(); mainGame->dField.Clear();
mainGame->HideElement(mainGame->wReplay); mainGame->HideElement(mainGame->wReplay);
mainGame->device->setEventReceiver(&mainGame->dField); mainGame->device->setEventReceiver(&mainGame->dField);
unsigned int start_turn = std::wcstol(mainGame->ebRepStartTurn->getText(), nullptr, 10);
if(start_turn == 1) if(start_turn == 1)
start_turn = 0; start_turn = 0;
ReplayMode::StartReplay(start_turn); ReplayMode::StartReplay(start_turn);
...@@ -526,27 +527,27 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) { ...@@ -526,27 +527,27 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
break; break;
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 (!temp_replay.OpenReplay(replay_path)) {
mainGame->stReplayInfo->setText(L"Error"); mainGame->stReplayInfo->setText(L"Error");
break; break;
} }
wchar_t infobuf[256]{}; wchar_t infobuf[256]{};
std::wstring repinfo; std::wstring repinfo;
time_t curtime; time_t curtime;
if(ReplayMode::cur_replay.pheader.flag & REPLAY_UNIFORM) if(temp_replay.pheader.flag & REPLAY_UNIFORM)
curtime = ReplayMode::cur_replay.pheader.start_time; curtime = temp_replay.pheader.start_time;
else else
curtime = ReplayMode::cur_replay.pheader.seed; curtime = temp_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);
if (ReplayMode::cur_replay.pheader.flag & REPLAY_SINGLE_MODE) { if (temp_replay.pheader.flag & REPLAY_SINGLE_MODE) {
wchar_t path[256]{}; wchar_t path[256]{};
BufferIO::DecodeUTF8(ReplayMode::cur_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 = ReplayMode::cur_replay.players; const auto& player_names = temp_replay.players;
if(ReplayMode::cur_replay.pheader.flag & REPLAY_TAG) if(temp_replay.pheader.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());
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#define MENU_HANDLER_H #define MENU_HANDLER_H
#include <irrlicht.h> #include <irrlicht.h>
#include "replay.h"
namespace ygo { namespace ygo {
...@@ -10,7 +11,7 @@ public: ...@@ -10,7 +11,7 @@ public:
bool OnEvent(const irr::SEvent& event) override; bool OnEvent(const irr::SEvent& event) override;
irr::s32 prev_operation{ 0 }; irr::s32 prev_operation{ 0 };
int prev_sel{ -1 }; int prev_sel{ -1 };
Replay temp_replay;
}; };
} }
......
...@@ -37,6 +37,7 @@ else ...@@ -37,6 +37,7 @@ else
kind "WindowedApp" kind "WindowedApp"
cppdialect "C++14" cppdialect "C++14"
rtti "Off" rtti "Off"
openmp "On"
files { "*.cpp", "*.h" } files { "*.cpp", "*.h" }
includedirs { "../ocgcore" } includedirs { "../ocgcore" }
...@@ -82,7 +83,7 @@ end ...@@ -82,7 +83,7 @@ end
includedirs { "../miniaudio/extras/decoders/libopus", "../miniaudio/extras/decoders/libvorbis" } includedirs { "../miniaudio/extras/decoders/libopus", "../miniaudio/extras/decoders/libvorbis" }
if not MINIAUDIO_BUILD_OPUS_VORBIS then if not MINIAUDIO_BUILD_OPUS_VORBIS then
links { "opusfile", "vorbisfile", "opus", "vorbis", "ogg" } links { "opusfile", "vorbisfile", "opus", "vorbis", "ogg" }
libdirs { OPUS_LIB_DIR, VORBIS_LIB_DIR, OGG_LIBDIR } libdirs { OPUS_LIB_DIR, OPUSFILE_LIB_DIR, VORBIS_LIB_DIR, OGG_LIB_DIR }
end end
end end
end end
...@@ -124,6 +125,7 @@ end ...@@ -124,6 +125,7 @@ end
links { "event_pthreads", "dl", "pthread" } links { "event_pthreads", "dl", "pthread" }
filter "system:macosx" filter "system:macosx"
if not SERVER_MODE then if not SERVER_MODE then
openmp "Off"
links { "z" } links { "z" }
defines { "GL_SILENCE_DEPRECATION" } defines { "GL_SILENCE_DEPRECATION" }
end end
...@@ -137,6 +139,7 @@ end ...@@ -137,6 +139,7 @@ end
filter "system:linux" filter "system:linux"
if not SERVER_MODE then if not SERVER_MODE then
links { "GL", "X11", "Xxf86vm" } links { "GL", "X11", "Xxf86vm" }
linkoptions { "-fopenmp" }
end end
if USE_AUDIO and AUDIO_LIB == "irrklang" then if USE_AUDIO and AUDIO_LIB == "irrklang" then
links { "IrrKlang" } links { "IrrKlang" }
......
...@@ -272,7 +272,11 @@ void Replay::Reset() { ...@@ -272,7 +272,11 @@ void Replay::Reset() {
script_name.clear(); script_name.clear();
} }
void Replay::SkipInfo(){ void Replay::SkipInfo(){
data_position += info_offset; if (data_position == 0)
data_position += info_offset;
}
bool Replay::IsReplaying() const {
return is_replaying;
} }
bool Replay::ReadInfo() { bool Replay::ReadInfo() {
int player_count = (pheader.flag & REPLAY_TAG) ? 4 : 2; int player_count = (pheader.flag & REPLAY_TAG) ? 4 : 2;
......
...@@ -87,6 +87,7 @@ public: ...@@ -87,6 +87,7 @@ public:
void Rewind(); void Rewind();
void Reset(); void Reset();
void SkipInfo(); void SkipInfo();
bool IsReplaying() const;
FILE* fp{ nullptr }; FILE* fp{ nullptr };
#ifdef _WIN32 #ifdef _WIN32
......
...@@ -159,7 +159,7 @@ bool ReplayMode::StartDuel() { ...@@ -159,7 +159,7 @@ bool ReplayMode::StartDuel() {
unsigned int seed = rh.seed; unsigned int seed = rh.seed;
std::mt19937 rnd(seed); std::mt19937 rnd(seed);
cur_replay.SkipInfo(); cur_replay.SkipInfo();
if(mainGame->dInfo.isTag) { 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);
BufferIO::CopyWideString(cur_replay.players[1].c_str(), mainGame->dInfo.hostname_tag); BufferIO::CopyWideString(cur_replay.players[1].c_str(), mainGame->dInfo.hostname_tag);
BufferIO::CopyWideString(cur_replay.players[2].c_str(), mainGame->dInfo.clientname_tag); BufferIO::CopyWideString(cur_replay.players[2].c_str(), mainGame->dInfo.clientname_tag);
...@@ -824,12 +824,12 @@ bool ReplayMode::ReplayAnalyze(unsigned char* msg, unsigned int len) { ...@@ -824,12 +824,12 @@ bool ReplayMode::ReplayAnalyze(unsigned char* msg, unsigned int len) {
break; break;
} }
case MSG_AI_NAME: { case MSG_AI_NAME: {
int len = BufferIO::ReadInt16(pbuf); int len = buffer_read<uint16_t>(pbuf);
pbuf += len + 1; pbuf += len + 1;
break; break;
} }
case MSG_SHOW_HINT: { case MSG_SHOW_HINT: {
int len = BufferIO::ReadInt16(pbuf); int len = buffer_read<uint16_t>(pbuf);
pbuf += len + 1; pbuf += len + 1;
break; break;
} }
......
...@@ -25,7 +25,6 @@ private: ...@@ -25,7 +25,6 @@ private:
public: public:
static Replay cur_replay; static Replay cur_replay;
public:
static bool StartReplay(int skipturn); static bool StartReplay(int skipturn);
static void StopReplay(bool is_exiting = false); static void StopReplay(bool is_exiting = false);
static void SwapField(); static void SwapField();
......
...@@ -749,21 +749,25 @@ bool SingleMode::SinglePlayAnalyze(unsigned char* msg, unsigned int len) { ...@@ -749,21 +749,25 @@ bool SingleMode::SinglePlayAnalyze(unsigned char* msg, unsigned int len) {
case MSG_AI_NAME: { case MSG_AI_NAME: {
char namebuf[128]{}; char namebuf[128]{};
wchar_t wname[20]{}; wchar_t wname[20]{};
int len = BufferIO::ReadInt16(pbuf); int name_len = buffer_read<uint16_t>(pbuf);
auto begin = pbuf; if (name_len + 1 <= (int)sizeof namebuf) {
pbuf += len + 1; std::memcpy(namebuf, pbuf, name_len);
std::memcpy(namebuf, begin, len + 1); namebuf[name_len] = 0;
}
pbuf += name_len + 1;
BufferIO::DecodeUTF8(namebuf, wname); BufferIO::DecodeUTF8(namebuf, wname);
BufferIO::CopyCharArray(wname, mainGame->dInfo.clientname); BufferIO::CopyCharArray(wname, mainGame->dInfo.clientname);
break; break;
} }
case MSG_SHOW_HINT: { case MSG_SHOW_HINT: {
char msgbuf[1024]; char msgbuf[1024]{};
wchar_t msg[1024]; wchar_t msg[1024]{};
int len = BufferIO::ReadInt16(pbuf); int msg_len = buffer_read<uint16_t>(pbuf);
auto begin = pbuf; if (msg_len + 1 <= (int)sizeof msgbuf) {
pbuf += len + 1; std::memcpy(msgbuf, pbuf, msg_len);
std::memcpy(msgbuf, begin, len + 1); msgbuf[msg_len] = 0;
}
pbuf += msg_len + 1;
BufferIO::DecodeUTF8(msgbuf, msg); BufferIO::DecodeUTF8(msgbuf, msg);
mainGame->gMutex.lock(); mainGame->gMutex.lock();
mainGame->SetStaticText(mainGame->stMessage, 310, mainGame->guiFont, msg); mainGame->SetStaticText(mainGame->stMessage, 310, mainGame->guiFont, msg);
......
...@@ -16,6 +16,7 @@ project "irrlicht" ...@@ -16,6 +16,7 @@ project "irrlicht"
"_IRR_STATIC_LIB_", "_IRR_STATIC_LIB_",
"NO_IRR_USE_NON_SYSTEM_BZLIB_", "NO_IRR_USE_NON_SYSTEM_BZLIB_",
"NO_IRR_COMPILE_WITH_BZIP2_", "NO_IRR_COMPILE_WITH_BZIP2_",
"NO_IRR_COMPILE_WITH_LZMA_",
"NO_IRR_COMPILE_WITH_CONSOLE_DEVICE_", "NO_IRR_COMPILE_WITH_CONSOLE_DEVICE_",
"NO_IRR_COMPILE_WITH_DIRECT3D_8_", "NO_IRR_COMPILE_WITH_DIRECT3D_8_",
"NO_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_", "NO_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_",
......
...@@ -123,7 +123,7 @@ project "miniaudio" ...@@ -123,7 +123,7 @@ project "miniaudio"
"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",
} }
else else
includedirs { OPUS_INCLUDE_DIR, VORBIS_INCLUDE_DIR, OGG_INCLUDE_DIR } includedirs { OPUS_INCLUDE_DIR, OPUSFILE_INCLUDE_DIR, VORBIS_INCLUDE_DIR, OGG_INCLUDE_DIR }
end end
end end
......
...@@ -52,14 +52,14 @@ newoption { trigger = "irrlicht-lib-dir", category = "YGOPro - irrlicht", descri ...@@ -52,14 +52,14 @@ newoption { trigger = "irrlicht-lib-dir", category = "YGOPro - irrlicht", descri
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 }
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 = "miniaudio-support-opus-vorbis", category = "YGOPro - miniaudio", description = "" }
newoption { trigger = "no-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 = "build-opus-vorbis", category = "YGOPro - miniaudio", description = "" }
newoption { trigger = "no-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-include-dir", category = "YGOPro - miniaudio", description = "", value = "PATH" }
newoption { trigger = "opus-lib-dir", category = "YGOPro - miniaudio", description = "", value = "PATH" } newoption { trigger = "opus-lib-dir", category = "YGOPro - miniaudio", description = "", value = "PATH" }
newoption { trigger = "opusfile-include-dir", category = "YGOPro - miniaudio", description = "", value = "PATH" }
newoption { trigger = "opusfile-lib-dir", category = "YGOPro - miniaudio", description = "", value = "PATH" }
newoption { trigger = "vorbis-include-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 = "vorbis-lib-dir", category = "YGOPro - miniaudio", description = "", value = "PATH" }
newoption { trigger = "ogg-include-dir", category = "YGOPro - miniaudio", description = "", value = "PATH" } newoption { trigger = "ogg-include-dir", category = "YGOPro - miniaudio", description = "", value = "PATH" }
...@@ -108,6 +108,14 @@ function GetParam(param) ...@@ -108,6 +108,14 @@ function GetParam(param)
return _OPTIONS[param] or os.getenv(string.upper(string.gsub(param,"-","_"))) return _OPTIONS[param] or os.getenv(string.upper(string.gsub(param,"-","_")))
end end
function FindHeaderWithSubDir(header, subdir)
local result = os.findheader(header)
if result and subdir then
result = path.join(result, subdir)
end
return result
end
function ApplyBoolean(param) function ApplyBoolean(param)
if GetParam(param) then if GetParam(param) then
defines { "YGOPRO_" .. string.upper(string.gsub(param,"-","_")) } defines { "YGOPRO_" .. string.upper(string.gsub(param,"-","_")) }
...@@ -132,7 +140,7 @@ if not BUILD_LUA then ...@@ -132,7 +140,7 @@ if not BUILD_LUA then
-- at most times you need to change this if you change BUILD_LUA to false -- at most times you need to change this if you change BUILD_LUA to false
-- make sure your lua lib is built with C++ and version >= 5.3 -- make sure your lua lib is built with C++ and version >= 5.3
LUA_LIB_NAME = GetParam("lua-lib-name") LUA_LIB_NAME = GetParam("lua-lib-name")
LUA_INCLUDE_DIR = GetParam("lua-include-dir") or os.findheader(LUA_LIB_NAME) LUA_INCLUDE_DIR = GetParam("lua-include-dir") or os.findheader("lua.h")
LUA_LIB_DIR = GetParam("lua-lib-dir") or os.findlib(LUA_LIB_NAME) LUA_LIB_DIR = GetParam("lua-lib-dir") or os.findlib(LUA_LIB_NAME)
end end
...@@ -149,7 +157,7 @@ elseif GetParam("no-build-event") then ...@@ -149,7 +157,7 @@ elseif GetParam("no-build-event") then
BUILD_EVENT = false BUILD_EVENT = false
end end
if not BUILD_EVENT then if not BUILD_EVENT then
EVENT_INCLUDE_DIR = GetParam("event-include-dir") or os.findheader("event") EVENT_INCLUDE_DIR = GetParam("event-include-dir") or os.findheader("event2/event.h")
EVENT_LIB_DIR = GetParam("event-lib-dir") or os.findlib("event") EVENT_LIB_DIR = GetParam("event-lib-dir") or os.findlib("event")
end end
...@@ -159,7 +167,7 @@ elseif GetParam("no-build-freetype") then ...@@ -159,7 +167,7 @@ elseif GetParam("no-build-freetype") then
BUILD_FREETYPE = false BUILD_FREETYPE = false
end end
if not BUILD_FREETYPE then if not BUILD_FREETYPE then
FREETYPE_INCLUDE_DIR = GetParam("freetype-include-dir") or os.findheader("freetype") FREETYPE_INCLUDE_DIR = GetParam("freetype-include-dir") or FindHeaderWithSubDir("freetype2/ft2build.h", "freetype2")
FREETYPE_LIB_DIR = GetParam("freetype-lib-dir") or os.findlib("freetype") FREETYPE_LIB_DIR = GetParam("freetype-lib-dir") or os.findlib("freetype")
end end
...@@ -169,7 +177,7 @@ elseif GetParam("no-build-sqlite") then ...@@ -169,7 +177,7 @@ elseif GetParam("no-build-sqlite") then
BUILD_SQLITE = false BUILD_SQLITE = false
end end
if not BUILD_SQLITE then if not BUILD_SQLITE then
SQLITE_INCLUDE_DIR = GetParam("sqlite-include-dir") or os.findheader("sqlite3") SQLITE_INCLUDE_DIR = GetParam("sqlite-include-dir") or os.findheader("sqlite3.h")
SQLITE_LIB_DIR = GetParam("sqlite-lib-dir") or os.findlib("sqlite3") SQLITE_LIB_DIR = GetParam("sqlite-lib-dir") or os.findlib("sqlite3")
end end
...@@ -179,7 +187,7 @@ elseif GetParam("no-build-irrlicht") then ...@@ -179,7 +187,7 @@ elseif GetParam("no-build-irrlicht") then
BUILD_IRRLICHT = false BUILD_IRRLICHT = false
end end
if not BUILD_IRRLICHT then if not BUILD_IRRLICHT then
IRRLICHT_INCLUDE_DIR = GetParam("irrlicht-include-dir") or os.findheader("irrlicht") IRRLICHT_INCLUDE_DIR = GetParam("irrlicht-include-dir") or os.findheader("irrlicht.h")
IRRLICHT_LIB_DIR = GetParam("irrlicht-lib-dir") or os.findlib("irrlicht") IRRLICHT_LIB_DIR = GetParam("irrlicht-lib-dir") or os.findlib("irrlicht")
end end
...@@ -216,12 +224,14 @@ if USE_AUDIO then ...@@ -216,12 +224,14 @@ if USE_AUDIO then
MINIAUDIO_BUILD_OPUS_VORBIS = true MINIAUDIO_BUILD_OPUS_VORBIS = true
end end
if not MINIAUDIO_BUILD_OPUS_VORBIS then if not MINIAUDIO_BUILD_OPUS_VORBIS then
OPUS_INCLUDE_DIR = GetParam("opus-include-dir") or os.findheader("opus") OPUS_INCLUDE_DIR = GetParam("opus-include-dir") or FindHeaderWithSubDir("opus/opus.h", "opus")
OPUS_LIB_DIR = GetParam("opus-lib-dir") or os.findlib("opusfile") OPUS_LIB_DIR = GetParam("opus-lib-dir") or os.findlib("opus")
VORBIS_INCLUDE_DIR = GetParam("vorbis-include-dir") or os.findheader("vorbis") OPUSFILE_INCLUDE_DIR = GetParam("opusfile-include-dir") or FindHeaderWithSubDir("opus/opusfile.h", "opus")
OPUSFILE_LIB_DIR = GetParam("opusfile-lib-dir") or os.findlib("opusfile")
VORBIS_INCLUDE_DIR = GetParam("vorbis-include-dir") or os.findheader("vorbis/vorbisfile.h")
VORBIS_LIB_DIR = GetParam("vorbis-lib-dir") or os.findlib("vorbis") VORBIS_LIB_DIR = GetParam("vorbis-lib-dir") or os.findlib("vorbis")
OGG_INCLUDE_DIR = GetParam("ogg-include-dir") or os.findheader("ogg") OGG_INCLUDE_DIR = GetParam("ogg-include-dir") or os.findheader("ogg/ogg.h")
OCG_LIB_DIR = GetParam("ogg-lib-dir") or os.findlib("ogg") OGG_LIB_DIR = GetParam("ogg-lib-dir") or os.findlib("ogg")
end end
end end
elseif AUDIO_LIB == "irrklang" then elseif AUDIO_LIB == "irrklang" then
......
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