Skip to content

Commit cded6b6

Browse files
authored
Merge branch 'Fluorohydride:master' into patch-card
2 parents 012d3c3 + e0d69a3 commit cded6b6

27 files changed

Lines changed: 216 additions & 127 deletions

.github/workflows/build.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ jobs:
429429
name:
430430
- ubuntu-22
431431
- ubuntu-24
432+
- ubuntu-26
432433
- ubuntu-static-link
433434
- ubuntu-arm-static-link
434435
include:
@@ -437,6 +438,8 @@ jobs:
437438
apt-outdated: true
438439
- name: ubuntu-24
439440
os: ubuntu-24.04
441+
- name: ubuntu-26
442+
os: ubuntu-26.04
440443
- name: ubuntu-static-link
441444
os: ubuntu-22.04
442445
static-link: true
@@ -635,8 +638,7 @@ jobs:
635638
- name: Install dependencies
636639
if: matrix.static-link != true
637640
run: |
638-
brew install libevent opus opusfile libvorbis zlib
639-
# brew install sqlite libx11 freetype libjpeg-turbo libpng xz
641+
brew install libevent opus opusfile libvorbis zlib sqlite libx11 freetype libjpeg-turbo libpng xz
640642
641643
- name: Install NASM
642644
if: matrix.static-link == true

gframe/bufferio.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <cstdint>
55
#include <cstring>
66
#include <cwchar>
7+
#include <string>
78
#include <vector>
89

910
class BufferIO {
@@ -122,6 +123,20 @@ class BufferIO {
122123
return true;
123124
}
124125
// UTF-16/UTF-32 to UTF-8
126+
static std::string EncodeUTF8String(const std::wstring& wstr) {
127+
if (wstr.empty())
128+
return std::string();
129+
std::mbstate_t state{};
130+
const wchar_t* src = wstr.c_str();
131+
size_t len = std::wcsrtombs(nullptr, &src, 0, &state);
132+
if (len == static_cast<size_t>(-1))
133+
return std::string();
134+
std::string result(len, '\0');
135+
state = std::mbstate_t{};
136+
src = wstr.c_str();
137+
std::wcsrtombs(&result[0], &src, len, &state);
138+
return result;
139+
}
125140
// return: string length
126141
static int EncodeUTF8String(const wchar_t* wsrc, char* str, size_t size) {
127142
if (size == 0) {
@@ -135,6 +150,20 @@ class BufferIO {
135150
return static_cast<int>(result_len);
136151
}
137152
// UTF-8 to UTF-16/UTF-32
153+
static std::wstring DecodeUTF8String(const std::string& str) {
154+
if (str.empty())
155+
return std::wstring();
156+
std::mbstate_t state{};
157+
const char* src = str.c_str();
158+
size_t len = std::mbsrtowcs(nullptr, &src, 0, &state);
159+
if (len == static_cast<size_t>(-1))
160+
return std::wstring();
161+
std::wstring result(len, L'\0');
162+
state = std::mbstate_t{};
163+
src = str.c_str();
164+
std::mbsrtowcs(&result[0], &src, len, &state);
165+
return result;
166+
}
138167
// return: string length
139168
static int DecodeUTF8String(const char* src, wchar_t* wstr, size_t size) {
140169
if (size == 0) {

gframe/deck_con.cpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,7 @@ void DeckBuilder::Initialize() {
8080
mainGame->btnSideSort->setVisible(false);
8181
mainGame->btnSideReload->setVisible(false);
8282
if (mainGame->gameConf.use_lflist) {
83-
if (mainGame->gameConf.default_lflist >= 0 && mainGame->gameConf.default_lflist < (int)deckManager._lfList.size()) {
84-
filterList = &deckManager._lfList[mainGame->gameConf.default_lflist];
85-
}
86-
else {
87-
mainGame->gameConf.default_lflist = 0;
88-
filterList = &deckManager._lfList.front();
89-
}
83+
filterList = &deckManager._lfList[mainGame->gameConf.default_lflist];
9084
}
9185
else {
9286
filterList = &deckManager._lfList.back();

gframe/deck_con.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,4 @@ class DeckBuilder: public irr::IEventReceiver {
9191

9292
}
9393

94-
#endif //DECK_CON
94+
#endif //DECK_CON_H

gframe/drawing.cpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include <algorithm>
12
#include "game.h"
23
#ifdef __APPLE__
34
#include <OpenGL/gl.h>
@@ -587,9 +588,9 @@ void Game::DrawMisc() {
587588
driver->draw2DRectangle(0xa0000000, Resize(689, 8, 992, 51));
588589
driver->draw2DRectangleOutline(Resize(689, 8, 992, 51), 0xffff8080);
589590
}
590-
if(dInfo.start_lp) {
591+
if(dInfo.start_lp > 0) {
591592
constexpr float maxBarWidth = 292.0f;
592-
auto maxLP = dInfo.isTag ? dInfo.start_lp / 2 : dInfo.start_lp;
593+
auto maxLP = dInfo.isTag ? std::max(dInfo.start_lp / 2, 1) : dInfo.start_lp;
593594
if(dInfo.lp[0] > maxLP) {
594595
auto layerCount = dInfo.lp[0] / maxLP;
595596
auto partialLP = dInfo.lp[0] % maxLP;
@@ -855,7 +856,7 @@ void Game::DrawSpec() {
855856
if(showcard) {
856857
switch(showcard) {
857858
case 1: {
858-
driver->draw2DImage(imageManager.GetTexture(showcardcode, true), ResizeCardHint(574, 150));
859+
driver->draw2DImage(imageManager.GetTexture(showcardcode, true), ResizeCardHint(574, 150), true);
859860
driver->draw2DImage(imageManager.tMask, ResizeCardMid(574, 150, 574 + (showcarddif > CARD_IMG_WIDTH ? CARD_IMG_WIDTH : showcarddif), 150 + CARD_IMG_HEIGHT, midx, midy),
860861
irr::core::recti(CARD_IMG_HEIGHT - showcarddif, 0, CARD_IMG_HEIGHT - (showcarddif > CARD_IMG_WIDTH ? showcarddif - CARD_IMG_WIDTH : 0), CARD_IMG_HEIGHT), 0, 0, true);
861862
showcarddif += 15;
@@ -866,7 +867,7 @@ void Game::DrawSpec() {
866867
break;
867868
}
868869
case 2: {
869-
driver->draw2DImage(imageManager.GetTexture(showcardcode, true), ResizeCardHint(574, 150));
870+
driver->draw2DImage(imageManager.GetTexture(showcardcode, true), ResizeCardHint(574, 150), true);
870871
driver->draw2DImage(imageManager.tMask, ResizeCardMid(574 + showcarddif, 150, 574 + CARD_IMG_WIDTH, 150 + CARD_IMG_HEIGHT, midx, midy),
871872
irr::core::recti(0, 0, CARD_IMG_WIDTH - showcarddif, CARD_IMG_HEIGHT), 0, 0, true);
872873
showcarddif += 15;
@@ -876,7 +877,7 @@ void Game::DrawSpec() {
876877
break;
877878
}
878879
case 3: {
879-
driver->draw2DImage(imageManager.GetTexture(showcardcode, true), ResizeCardHint(574, 150));
880+
driver->draw2DImage(imageManager.GetTexture(showcardcode, true), ResizeCardHint(574, 150), true);
880881
driver->draw2DImage(imageManager.tNegated, ResizeCardMid(536 + showcarddif, 141 + showcarddif, 792 - showcarddif, 397 - showcarddif, midx, midy), irr::core::recti(0, 0, 128, 128), 0, 0, true);
881882
if(showcarddif < 64)
882883
showcarddif += 4;
@@ -907,7 +908,7 @@ void Game::DrawSpec() {
907908
break;
908909
}
909910
case 6: {
910-
driver->draw2DImage(imageManager.GetTexture(showcardcode, true), ResizeCardHint(574, 150));
911+
driver->draw2DImage(imageManager.GetTexture(showcardcode, true), ResizeCardHint(574, 150), true);
911912
driver->draw2DImage(imageManager.tNumber, ResizeCardMid(536 + showcarddif, 141 + showcarddif, 792 - showcarddif, 397 - showcarddif, midx, midy),
912913
irr::core::recti((showcardp % 5) * 64, (showcardp / 5) * 64, (showcardp % 5 + 1) * 64, (showcardp / 5 + 1) * 64), 0, 0, true);
913914
if(showcarddif < 64)
@@ -940,8 +941,8 @@ void Game::DrawSpec() {
940941
}
941942
case 100: {
942943
if(showcardp < 60) {
943-
driver->draw2DImage(imageManager.tHand[(showcardcode >> 16) & 0x3], irr::core::vector2di((615 + 44.5) * xScale - 44.5, (showcarddif + 64) * yScale - 64));
944-
driver->draw2DImage(imageManager.tHand[showcardcode & 0x3], irr::core::vector2di((615 + 44.5) * xScale - 44.5, (540 - showcarddif + 64) * yScale - 64));
944+
driver->draw2DImage(imageManager.tHand[(showcardcode >> 16) & 0x3], irr::core::vector2di((615 + 44.5) * xScale - 44.5, (showcarddif + 64) * yScale - 64), true);
945+
driver->draw2DImage(imageManager.tHand[showcardcode & 0x3], irr::core::vector2di((615 + 44.5) * xScale - 44.5, (540 - showcarddif + 64) * yScale - 64), true);
945946
float dy = -0.333333f * showcardp + 10;
946947
showcardp++;
947948
if(showcardp < 30)
@@ -1183,7 +1184,7 @@ void Game::DrawThumb(const CardDataC* cp, irr::core::vector2di pos, const LFList
11831184
limitloc = irr::core::recti(pos.X, pos.Y, pos.X + 20 * xScale, pos.Y + 20 * yScale);
11841185
otloc = irr::core::recti(pos.X + 7, pos.Y + 50 * yScale, pos.X + 37 * xScale, pos.Y + 65 * yScale);
11851186
}
1186-
driver->draw2DImage(img, dragloc, irr::core::rect<irr::s32>(0, 0, size.Width, size.Height));
1187+
driver->draw2DImage(img, dragloc, irr::core::rect<irr::s32>(0, 0, size.Width, size.Height), 0, 0, true);
11871188
auto lfit = lflist->content.find(lcode);
11881189
if (lfit != lflist->content.end()) {
11891190
switch(lfit->second) {

gframe/duelclient.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ namespace {
3333
wchar_t event_string[256]{};
3434
std::mt19937 rnd{};
3535
std::uniform_real_distribution<float> real_dist{};
36+
unsigned char duel_client_read[SIZE_NETWORK_BUFFER]{};
3637

3738
bool is_refreshing{};
3839
int match_kill{};
@@ -110,7 +111,6 @@ void DuelClient::ClientRead(bufferevent* bev, void* ctx) {
110111
size_t len = evbuffer_get_length(input);
111112
if (len < 2)
112113
return;
113-
unsigned char* duel_client_read = new unsigned char[SIZE_NETWORK_BUFFER];
114114
uint16_t packet_len = 0;
115115
while (len >= 2) {
116116
evbuffer_copyout(input, &packet_len, sizeof packet_len);
@@ -121,7 +121,6 @@ void DuelClient::ClientRead(bufferevent* bev, void* ctx) {
121121
HandleSTOCPacketLan(&duel_client_read[2], read_len - 2);
122122
len -= packet_len + 2;
123123
}
124-
delete[] duel_client_read;
125124
}
126125
void DuelClient::ClientEvent(bufferevent* bev, short events, void* ctx) {
127126
if (events & BEV_EVENT_CONNECTED) {
@@ -246,14 +245,13 @@ void DuelClient::ClientEvent(bufferevent* bev, short events, void* ctx) {
246245
event_base_loopexit(client_base, 0);
247246
}
248247
}
249-
int DuelClient::ClientThread() {
248+
void DuelClient::ClientThread() {
250249
event_base_dispatch(client_base);
251250
bufferevent_free(client_bev);
252251
event_base_free(client_base);
253252
client_bev = 0;
254253
client_base = 0;
255254
connect_state = 0;
256-
return 0;
257255
}
258256
void DuelClient::HandleSTOCPacketLan(unsigned char* data, size_t len) {
259257
unsigned char* pdata = data;

gframe/duelclient.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class DuelClient {
2020
static void StopClient(bool is_exiting = false);
2121
static void ClientRead(bufferevent* bev, void* ctx);
2222
static void ClientEvent(bufferevent* bev, short events, void* ctx);
23-
static int ClientThread();
23+
static void ClientThread();
2424
static void HandleSTOCPacketLan(unsigned char* data, size_t len);
2525
static bool ClientAnalyze(unsigned char* msg, size_t len);
2626
static void SwapField();

gframe/event_handler.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1978,7 +1978,7 @@ bool ClientField::OnCommonEvent(const irr::SEvent& event) {
19781978
switch(id) {
19791979
case LISTBOX_LOG: {
19801980
int sel = mainGame->lstLog->getSelected();
1981-
if(sel != -1 && (int)mainGame->logParam.size() >= sel && mainGame->logParam[sel]) {
1981+
if(sel >= 0 && (int)mainGame->logParam.size() > sel && mainGame->logParam[sel] > 0) {
19821982
mainGame->ShowCardInfo(mainGame->logParam[sel]);
19831983
}
19841984
return true;
@@ -1991,7 +1991,7 @@ bool ClientField::OnCommonEvent(const irr::SEvent& event) {
19911991
switch(id) {
19921992
case LISTBOX_LOG: {
19931993
int sel = mainGame->lstLog->getSelected();
1994-
if(sel != -1 && (int)mainGame->logParam.size() >= sel && mainGame->logParam[sel]) {
1994+
if(sel >= 0 && (int)mainGame->logParam.size() > sel && mainGame->logParam[sel] > 0) {
19951995
mainGame->wInfos->setActiveTab(0);
19961996
}
19971997
return true;

gframe/game.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,15 @@
1414
#include <chrono>
1515
#ifdef _WIN32
1616
#include <timeapi.h>
17+
#else
18+
#include <spawn.h>
19+
#ifdef __APPLE__
20+
#include <crt_externs.h>
21+
#define GetEnviron() (*_NSGetEnviron())
22+
#else
23+
extern char **environ;
24+
#define GetEnviron() environ
25+
#endif
1726
#endif
1827
#ifdef __APPLE__
1928
#include <CoreFoundation/CoreFoundation.h>
@@ -92,6 +101,8 @@ bool Game::Initialize() {
92101
device->getLogger()->setLogLevel(irr::ELOG_LEVEL::ELL_ERROR);
93102
#endif
94103
deckManager.LoadLFList();
104+
if(gameConf.default_lflist >= (int)deckManager._lfList.size() || gameConf.default_lflist < 0)
105+
gameConf.default_lflist = 0;
95106
driver = device->getVideoDriver();
96107
driver->setTextureCreationFlag(irr::video::ETCF_CREATE_MIP_MAPS, false);
97108
driver->setTextureCreationFlag(irr::video::ETCF_OPTIMIZED_FOR_QUALITY, true);
@@ -517,6 +528,7 @@ bool Game::Initialize() {
517528
for(int i = 0; i < 3; ++i) {
518529
btnHand[i] = env->addButton(irr::core::rect<irr::s32>(10 + 105 * i, 10, 105 + 105 * i, 144), wHand, BUTTON_HAND1 + i, L"");
519530
btnHand[i]->setImage(imageManager.tHand[i]);
531+
btnHand[i]->setUseAlphaChannel(true);
520532
}
521533
//
522534
wFTSelect = env->addWindow(irr::core::rect<irr::s32>(550, 240, 780, 340), false, L"");
@@ -576,11 +588,15 @@ bool Game::Initialize() {
576588
wPosSelect->getCloseButton()->setVisible(false);
577589
wPosSelect->setVisible(false);
578590
btnPSAU = env->addButton(irr::core::rect<irr::s32>(27, 35, 164, 172), wPosSelect, BUTTON_POS_AU);
591+
btnPSAU->setUseAlphaChannel(true);
579592
btnPSAD = env->addButton(irr::core::rect<irr::s32>(27, 35, 164, 172), wPosSelect, BUTTON_POS_AD);
593+
btnPSAD->setUseAlphaChannel(true);
580594
btnFacedownImgInfo[btnPSAD] = {0, false};
581595
btnPSAD->setVisible(false); // PSAD = PoSition Attack face-Down, is not allowed in the rules, so the width of wPosSelect only support 3 buttons
582596
btnPSDU = env->addButton(irr::core::rect<irr::s32>(169, 35, 306, 172), wPosSelect, BUTTON_POS_DU);
597+
btnPSDU->setUseAlphaChannel(true);
583598
btnPSDD = env->addButton(irr::core::rect<irr::s32>(311, 35, 448, 172), wPosSelect, BUTTON_POS_DD);
599+
btnPSDD->setUseAlphaChannel(true);
584600
btnFacedownImgInfo[btnPSDD] = {0, true};
585601
//card select
586602
wCardSelect = env->addWindow(irr::core::rect<irr::s32>(320, 100, 1000, 400), false, L"");
@@ -591,6 +607,7 @@ bool Game::Initialize() {
591607
stCardPos[i]->setBackgroundColor(0xffffffff);
592608
stCardPos[i]->setTextAlignment(irr::gui::EGUIA_CENTER, irr::gui::EGUIA_CENTER);
593609
btnCardSelect[i] = env->addButton(irr::core::rect<irr::s32>(30 + 125 * i, 55, 150 + 125 * i, 225), wCardSelect, BUTTON_CARD_0 + i);
610+
btnCardSelect[i]->setUseAlphaChannel(true);
594611
}
595612
scrCardList = env->addScrollBar(true, irr::core::rect<irr::s32>(30, 235, 650, 255), wCardSelect, SCROLL_CARD_SELECT);
596613
btnSelectOK = env->addButton(irr::core::rect<irr::s32>(300, 265, 380, 290), wCardSelect, BUTTON_CARD_SEL_OK, dataManager.GetSysString(1211));
@@ -603,6 +620,7 @@ bool Game::Initialize() {
603620
stDisplayPos[i]->setBackgroundColor(0xffffffff);
604621
stDisplayPos[i]->setTextAlignment(irr::gui::EGUIA_CENTER, irr::gui::EGUIA_CENTER);
605622
btnCardDisplay[i] = env->addButton(irr::core::rect<irr::s32>(30 + 125 * i, 55, 150 + 125 * i, 225), wCardDisplay, BUTTON_DISPLAY_0 + i);
623+
btnCardDisplay[i]->setUseAlphaChannel(true);
606624
}
607625
scrDisplayList = env->addScrollBar(true, irr::core::rect<irr::s32>(30, 235, 650, 255), wCardDisplay, SCROLL_CARD_DISPLAY);
608626
btnDisplayOK = env->addButton(irr::core::rect<irr::s32>(300, 265, 380, 290), wCardDisplay, BUTTON_CARD_DISP_OK, dataManager.GetSysString(1211));
@@ -2398,5 +2416,50 @@ void Game::SetCursor(irr::gui::ECURSOR_ICON icon) {
23982416
cursor->setActiveIcon(icon);
23992417
}
24002418
}
2419+
bool Game::SpawnAsync(const std::wstring& exePath, const std::vector<std::wstring>& args) {
2420+
#ifdef _WIN32
2421+
std::wstring cmdLine = L"\"" + exePath + L"\"";
2422+
for (const auto& arg : args) {
2423+
cmdLine += L" \"" + arg + L"\"";
2424+
}
2425+
2426+
STARTUPINFOW si;
2427+
PROCESS_INFORMATION pi;
2428+
ZeroMemory(&si, sizeof(si));
2429+
si.cb = sizeof(si);
2430+
ZeroMemory(&pi, sizeof(pi));
2431+
2432+
// CreateProcessW can modify the command line buffer, so we need to create a mutable copy of it
2433+
// TODO: Move to C++17 and use cmdLine.data() directly without copying to a vector
2434+
std::vector<wchar_t> cmdBuffer(cmdLine.begin(), cmdLine.end());
2435+
cmdBuffer.push_back(L'\0');
2436+
2437+
if (!CreateProcessW(exePath.c_str(), cmdBuffer.data(), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi)) {
2438+
return false;
2439+
}
2440+
2441+
CloseHandle(pi.hThread);
2442+
CloseHandle(pi.hProcess);
2443+
return true;
2444+
#else
2445+
std::string exePathUTF8 = BufferIO::EncodeUTF8String(exePath);
2446+
2447+
std::vector<std::string> utf8Args;
2448+
utf8Args.emplace_back(exePathUTF8);
2449+
for (const auto& arg : args) {
2450+
utf8Args.push_back(BufferIO::EncodeUTF8String(arg));
2451+
}
2452+
2453+
std::vector<char*> execArgs;
2454+
execArgs.reserve(utf8Args.size() + 1);
2455+
for (auto& arg : utf8Args) {
2456+
execArgs.push_back(const_cast<char*>(arg.c_str()));
2457+
}
2458+
execArgs.push_back(nullptr);
2459+
2460+
pid_t pid{}; // ignore pid return value, use SIG_IGN to prevent zombie process
2461+
return posix_spawn(&pid, exePathUTF8.c_str(), nullptr, nullptr, execArgs.data(), GetEnviron()) == 0;
2462+
#endif
2463+
}
24012464

24022465
}

gframe/game.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,9 @@ class Game {
265265
void SetWindowsScale(float scale);
266266
void FlashWindow();
267267
void SetCursor(irr::gui::ECURSOR_ICON icon);
268+
269+
static bool SpawnAsync(const std::wstring& exePath, const std::vector<std::wstring>& args);
270+
268271
template<typename T>
269272
static void DrawShadowText(irr::gui::CGUITTFont* font, const T& text, const irr::core::rect<irr::s32>& position, const irr::core::rect<irr::s32>& padding,
270273
irr::video::SColor color = 0xffffffff, irr::video::SColor shadowcolor = 0xff000000, bool hcenter = false, bool vcenter = false, const irr::core::rect<irr::s32>* clip = nullptr);

0 commit comments

Comments
 (0)