Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions gframe/bufferio.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <cstdint>
#include <cstring>
#include <cwchar>
#include <string>
#include <vector>

class BufferIO {
Expand Down Expand Up @@ -122,6 +123,19 @@ class BufferIO {
return true;
}
// UTF-16/UTF-32 to UTF-8
static std::string EncodeUTF8String(const std::wstring& wstr) {
if (wstr.empty())
return std::string();
std::mbstate_t state{};
const wchar_t* src = wstr.c_str();
size_t len = std::wcsrtombs(nullptr, &src, 0, &state);
if (len == static_cast<size_t>(-1))
return std::string();
std::string result(len, 0);
state = std::mbstate_t{};
std::wcsrtombs(&result[0], &src, len, &state);
return result;
}
Comment thread
mercury233 marked this conversation as resolved.
Comment on lines +126 to +139
// return: string length
static int EncodeUTF8String(const wchar_t* wsrc, char* str, size_t size) {
if (size == 0) {
Expand All @@ -135,6 +149,19 @@ class BufferIO {
return static_cast<int>(result_len);
}
// UTF-8 to UTF-16/UTF-32
static std::wstring DecodeUTF8String(const std::string& str) {
if (str.empty())
return std::wstring();
std::mbstate_t state{};
const char* src = str.c_str();
size_t len = std::mbsrtowcs(nullptr, &src, 0, &state);
if (len == static_cast<size_t>(-1))
return std::wstring();
std::wstring result(len, 0);
state = std::mbstate_t{};
std::mbsrtowcs(&result[0], &src, len, &state);
return result;
}
Comment thread
mercury233 marked this conversation as resolved.
Comment on lines +153 to +166
// return: string length
static int DecodeUTF8String(const char* src, wchar_t* wstr, size_t size) {
if (size == 0) {
Expand Down
55 changes: 55 additions & 0 deletions gframe/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@
#include <chrono>
#ifdef _WIN32
#include <timeapi.h>
#else
#include <spawn.h>
#ifdef __APPLE__
#include <crt_externs.h>
#define GetEnviron() (*_NSGetEnviron())
#else
extern char **environ;
#define GetEnviron() environ
#endif
#endif
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
Expand Down Expand Up @@ -2395,5 +2404,51 @@ void Game::SetCursor(irr::gui::ECURSOR_ICON icon) {
cursor->setActiveIcon(icon);
}
}
bool Game::SpawnAsync(const std::wstring& exePath, const std::vector<std::wstring>& args) {
#ifdef _WIN32
std::wstring cmdLine = L"\"" + exePath + L"\"";
for (const auto& arg : args) {
cmdLine += L" \"" + arg + L"\"";
}
Comment on lines +2412 to +2415

STARTUPINFOW si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));

// CreateProcessW can modify the command line buffer, so we need to create a mutable copy of it
// TODO: Move to C++17 and use cmdLine.data() directly without copying to a vector
std::vector<wchar_t> cmdBuffer(cmdLine.begin(), cmdLine.end());
cmdBuffer.push_back(L'\0');

if (!CreateProcessW(exePath.c_str(), cmdBuffer.data(), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi)) {
return false;
}

CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return true;

#else
std::string exePathUtf8 = BufferIO::EncodeUTF8String(exePath);

std::vector<std::string> utf8Args;
utf8Args.emplace_back(exePathUtf8);
for (const auto& arg : args) {
utf8Args.push_back(BufferIO::EncodeUTF8String(arg));
}
Comment on lines +2436 to +2442

std::vector<char*> execArgs;
execArgs.reserve(utf8Args.size() + 1);
for (auto& arg : utf8Args) {
execArgs.push_back(const_cast<char*>(arg.c_str()));
}
execArgs.push_back(nullptr);

pid_t pid{}; // ignore pid return value, use SIG_IGN to prevent zombie process
return posix_spawn(&pid, exePathUtf8.c_str(), nullptr, nullptr, execArgs.data(), GetEnviron()) == 0;
#endif
}

}
3 changes: 3 additions & 0 deletions gframe/game.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,9 @@ class Game {
void SetWindowsScale(float scale);
void FlashWindow();
void SetCursor(irr::gui::ECURSOR_ICON icon);

static bool SpawnAsync(const std::wstring& exePath, const std::vector<std::wstring>& args);

template<typename T>
static void DrawShadowText(irr::gui::CGUITTFont* font, const T& text, const irr::core::rect<irr::s32>& position, const irr::core::rect<irr::s32>& padding,
irr::video::SColor color = 0xffffffff, irr::video::SColor shadowcolor = 0xff000000, bool hcenter = false, bool vcenter = false, const irr::core::rect<irr::s32>* clip = nullptr);
Expand Down
4 changes: 4 additions & 0 deletions gframe/gframe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
#include <event2/thread.h>
#include <clocale>
#include <memory>
#ifndef _WIN32
#include <signal.h>
#endif

#if defined(_WIN32) && (!defined(WDK_NTDDI_VERSION) || (WDK_NTDDI_VERSION < 0x0A000005)) // Redstone 4, Version 1803, Build 17134.
#error "This program requires the Windows 10 SDK version 1803 or above to compile on Windows. Otherwise, non-ASCII characters will not be displayed or processed correctly."
Expand Down Expand Up @@ -48,6 +51,7 @@ int main(int argc, char* argv[]) {
evthread_use_windows_threads();
#else
evthread_use_pthreads();
signal(SIGCHLD, SIG_IGN);
#endif //_WIN32
ygo::Game _game;
ygo::mainGame = &_game;
Expand Down
57 changes: 10 additions & 47 deletions gframe/menu_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,6 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
if(sel == -1)
break;
mainGame->bot_mode = true;
#ifdef _WIN32
if(!NetServer::StartServer(mainGame->gameConf.serverport)) {
soundManager.PlaySoundEffect(SOUND_INFO);
mainGame->env->addMessageBox(L"", dataManager.GetSysString(1402));
Expand All @@ -331,12 +330,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
mainGame->env->addMessageBox(L"", dataManager.GetSysString(1402));
break;
}
STARTUPINFOW si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
wchar_t cmd[MAX_PATH];
std::vector<std::wstring> processArgs;
wchar_t arg1[512];
if(mainGame->botInfo[sel].select_deckfile) {
wchar_t botdeck[256];
Expand All @@ -345,51 +339,20 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
}
else
myswprintf(arg1, L"%ls", mainGame->botInfo[sel].command);
processArgs.push_back(arg1);
int flag = 0;
flag += (mainGame->chkBotHand->isChecked() ? 0x1 : 0);
myswprintf(cmd, L"Bot.exe \"%ls\" %d %d", arg1, flag, mainGame->gameConf.serverport);
if(!CreateProcessW(nullptr, cmd, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi))
{
processArgs.push_back(std::to_wstring(flag));
processArgs.push_back(std::to_wstring(mainGame->gameConf.serverport));
#ifdef _WIN32
std::wstring executableName = L"Bot.exe";
#else
std::wstring executableName = L"./bot";
#endif
if (!Game::SpawnAsync(executableName, processArgs)) {
NetServer::StopServer();
break;
}
Comment thread
mercury233 marked this conversation as resolved.
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
#else
if(fork() == 0) {
usleep(100000);
wchar_t warg1[512];
if(mainGame->botInfo[sel].select_deckfile) {
wchar_t botdeck[256];
DeckManager::GetDeckFile(botdeck, mainGame->cbBotDeckCategory->getSelected(), mainGame->cbBotDeckCategory->getText(), mainGame->cbBotDeck->getText());
myswprintf(warg1, L"%ls DeckFile='%ls'", mainGame->botInfo[sel].command, botdeck);
}
else
myswprintf(warg1, L"%ls", mainGame->botInfo[sel].command);
char arg1[512];
BufferIO::EncodeUTF8(warg1, arg1);
int flag = 0;
flag += (mainGame->chkBotHand->isChecked() ? 0x1 : 0);
char arg2[8];
mysnprintf(arg2, "%d", flag);
char arg3[8];
mysnprintf(arg3, "%d", mainGame->gameConf.serverport);
execl("./bot", "bot", arg1, arg2, arg3, nullptr);
std::exit(0);
} else {
if(!NetServer::StartServer(mainGame->gameConf.serverport)) {
soundManager.PlaySoundEffect(SOUND_INFO);
mainGame->env->addMessageBox(L"", dataManager.GetSysString(1402));
break;
}
if(!DuelClient::StartClient(0x7f000001, mainGame->gameConf.serverport)) {
NetServer::StopServer();
soundManager.PlaySoundEffect(SOUND_INFO);
mainGame->env->addMessageBox(L"", dataManager.GetSysString(1402));
break;
}
}
#endif
mainGame->btnStartBot->setEnabled(false);
mainGame->btnBotCancel->setEnabled(false);
break;
Expand Down