mirror of
https://github.com/edo9300/edopro
synced 2026-08-23 22:26:05 -04:00
221 lines
7 KiB
C++
221 lines
7 KiB
C++
#include "config.h"
|
|
#include <event2/thread.h>
|
|
#include <IrrlichtDevice.h>
|
|
#include <IGUIButton.h>
|
|
#include <IGUICheckBox.h>
|
|
#include <IGUIEditBox.h>
|
|
#include <IGUIWindow.h>
|
|
#include <IGUIEnvironment.h>
|
|
#include <ISceneManager.h>
|
|
#include <optional>
|
|
#include "client_updater.h"
|
|
#include "cli_args.h"
|
|
#include "config.h"
|
|
#include "data_handler.h"
|
|
#include "logging.h"
|
|
#include "game.h"
|
|
#include "log.h"
|
|
#include "porting.h"
|
|
#include "joystick_wrapper.h"
|
|
#include "utils_gui.h"
|
|
#include "fmt.h"
|
|
#include "curl.h"
|
|
|
|
bool is_from_discord = false;
|
|
bool open_file = false;
|
|
epro::path_string open_file_name = EPRO_TEXT("");
|
|
bool show_changelog = false;
|
|
ygo::Game* ygo::mainGame = nullptr;
|
|
ygo::ImageDownloader* ygo::gImageDownloader = nullptr;
|
|
ygo::DataManager* ygo::gDataManager = nullptr;
|
|
ygo::SoundManager* ygo::gSoundManager = nullptr;
|
|
ygo::GameConfig* ygo::gGameConfig = nullptr;
|
|
ygo::RepoManager* ygo::gRepoManager = nullptr;
|
|
ygo::DeckManager* ygo::gdeckManager = nullptr;
|
|
ygo::ClientUpdater* ygo::gClientUpdater = nullptr;
|
|
JWrapper* gJWrapper = nullptr;
|
|
|
|
namespace {
|
|
void CheckArguments(const args_t& args) {
|
|
if(args[LAUNCH_PARAM::MUTE].enabled) {
|
|
ygo::GUIUtils::SetCheckbox(ygo::mainGame->device.get(), ygo::mainGame->tabSettings.chkEnableSound, false);
|
|
ygo::GUIUtils::SetCheckbox(ygo::mainGame->device.get(), ygo::mainGame->tabSettings.chkEnableMusic, false);
|
|
}
|
|
}
|
|
|
|
inline void ThreadsStartup() {
|
|
#if EDOPRO_WINDOWS
|
|
const WORD wVersionRequested = MAKEWORD(2, 2);
|
|
WSADATA wsaData;
|
|
auto wsaret = WSAStartup(wVersionRequested, &wsaData);
|
|
if(wsaret != 0)
|
|
throw std::runtime_error(epro::format("Failed to initialize WinSock ({})!", wsaret));
|
|
if(evthread_use_windows_threads() < 0)
|
|
throw std::runtime_error("Failed initialize libevent!");
|
|
#else
|
|
if(evthread_use_pthreads() < 0)
|
|
throw std::runtime_error("Failed initialize libevent!");
|
|
#endif
|
|
auto res = curl_global_init(CURL_GLOBAL_SSL);
|
|
if(res != CURLE_OK)
|
|
throw std::runtime_error(epro::format("Curl error: ({}) {}", res, curl_easy_strerror(res)));
|
|
}
|
|
struct ThreadsCleaner {
|
|
~ThreadsCleaner() {
|
|
curl_global_cleanup();
|
|
libevent_global_shutdown();
|
|
#if EDOPRO_WINDOWS
|
|
WSACleanup();
|
|
#endif
|
|
}
|
|
};
|
|
|
|
//clang below version 11 (llvm version 8) has a bug with brace class initialization
|
|
//where it can't properly deduce the destructors of its members
|
|
//https://reviews.llvm.org/D45898
|
|
//https://bugs.llvm.org/show_bug.cgi?id=28280
|
|
//add a workaround to construct the game object indirectly
|
|
//to avoid constructing it with brace initialization
|
|
#if defined(__clang_major__) && __clang_major__ <= 10
|
|
class Game {
|
|
ygo::Game game;
|
|
public:
|
|
Game() :game() {};
|
|
ygo::Game* operator&() { return &game; }
|
|
};
|
|
#else
|
|
using Game = ygo::Game;
|
|
#endif
|
|
|
|
}
|
|
|
|
#if EDOPRO_WINDOWS
|
|
#define ADMIN_STR "administrator"
|
|
#else
|
|
#define ADMIN_STR "root"
|
|
#endif
|
|
|
|
int edopro_main(const args_t& args) {
|
|
std::puts(EDOPRO_VERSION_STRING_DEBUG);
|
|
if(ygo::Utils::IsRunningAsAdmin() && !args[LAUNCH_PARAM::WANTS_TO_RUN_AS_ADMIN].enabled) {
|
|
constexpr auto err = "Attempted to run the game as " ADMIN_STR ".\n"
|
|
"You should NEVER have to run the game with elevated priviledges.\n"
|
|
"If for some reason you REALLY want to do that, launch the game with the option \"-i-want-to-be-admin\""sv;
|
|
epro::print("{}\n", err);
|
|
ygo::GUIUtils::ShowErrorWindow("Initialization fail", err);
|
|
return EXIT_FAILURE;
|
|
}
|
|
{
|
|
const auto& workdir = args[LAUNCH_PARAM::WORK_DIR];
|
|
const epro::path_stringview dest = workdir.enabled ? workdir.argument : ygo::Utils::GetExeFolder();
|
|
if(!ygo::Utils::SetWorkingDirectory(dest)) {
|
|
const auto err = epro::format("failed to change directory to: {} ({})",
|
|
ygo::Utils::ToUTF8IfNeeded(dest), ygo::Utils::GetLastErrorString());
|
|
ygo::ErrorLog(err);
|
|
epro::print("{}\n", err);
|
|
ygo::GUIUtils::ShowErrorWindow("Initialization fail", err);
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
{
|
|
const auto& userdir = args[LAUNCH_PARAM::USER_STORAGE_DIRECTORY];
|
|
const epro::path_stringview dir = userdir.enabled ? userdir.argument : EPRO_TEXT("./");
|
|
ygo::Utils::SetUserStorageDirectory(dir);
|
|
}
|
|
ygo::Utils::SetupCrashDumpLogging();
|
|
std::optional<ThreadsCleaner> cleaner;
|
|
try {
|
|
ThreadsStartup();
|
|
cleaner.emplace();
|
|
} catch(const std::exception& e) {
|
|
epro::stringview text(e.what());
|
|
ygo::ErrorLog(text);
|
|
epro::print("{}\n", text);
|
|
ygo::GUIUtils::ShowErrorWindow("Initialization fail", text);
|
|
return EXIT_FAILURE;
|
|
}
|
|
show_changelog = args[LAUNCH_PARAM::CHANGELOG].enabled;
|
|
ygo::ClientUpdater updater(args[LAUNCH_PARAM::OVERRIDE_UPDATE_URL].argument);
|
|
ygo::gClientUpdater = &updater;
|
|
std::unique_ptr<ygo::DataHandler> data{ nullptr };
|
|
try {
|
|
data = std::make_unique<ygo::DataHandler>();
|
|
ygo::gImageDownloader = data->imageDownloader.get();
|
|
ygo::gDataManager = data->dataManager.get();
|
|
ygo::gSoundManager = data->sounds.get();
|
|
ygo::gGameConfig = data->configs.get();
|
|
ygo::gRepoManager = data->gitManager.get();
|
|
ygo::gdeckManager = data->deckManager.get();
|
|
}
|
|
catch(const std::exception& e) {
|
|
epro::stringview text(e.what());
|
|
ygo::ErrorLog(text);
|
|
epro::print("{}\n", text);
|
|
ygo::GUIUtils::ShowErrorWindow("Initialization fail", text);
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (!data->configs->noClientUpdates)
|
|
updater.CheckUpdates();
|
|
#if EDOPRO_WINDOWS
|
|
if(!data->configs->showConsole) {
|
|
FILE* fDummy;
|
|
#ifdef _MSC_VER
|
|
freopen_s(&fDummy, "NUL", "r", stdin);
|
|
freopen_s(&fDummy, "NUL", "w", stderr);
|
|
freopen_s(&fDummy, "NUL", "w", stdout);
|
|
#else
|
|
fDummy = freopen("NUL", "r", stdin);
|
|
fDummy = freopen("NUL", "w", stderr);
|
|
fDummy = freopen("NUL", "w", stdout);
|
|
#endif
|
|
FreeConsole();
|
|
}
|
|
#endif
|
|
#if EDOPRO_MACOS
|
|
porting::setupMenuBar([]{
|
|
ygo::gGameConfig->fullscreen = !ygo::gGameConfig->fullscreen;
|
|
ygo::mainGame->gSettings.chkFullscreen->setChecked(ygo::gGameConfig->fullscreen);
|
|
});
|
|
#endif
|
|
srand(static_cast<uint32_t>(time(nullptr)));
|
|
std::unique_ptr<JWrapper> joystick{ nullptr };
|
|
bool firstlaunch = true;
|
|
bool reset = false;
|
|
do {
|
|
Game _game{};
|
|
ygo::mainGame = &_game;
|
|
std::swap(data->tmp_device, ygo::mainGame->device);
|
|
try {
|
|
ygo::mainGame->Initialize();
|
|
}
|
|
catch(const std::exception& e) {
|
|
epro::stringview text(e.what());
|
|
ygo::ErrorLog(text);
|
|
epro::print("{}\n", text);
|
|
ygo::GUIUtils::ShowErrorWindow("Assets load fail", text);
|
|
return EXIT_FAILURE;
|
|
}
|
|
if(firstlaunch) {
|
|
joystick = std::make_unique<JWrapper>(ygo::mainGame->device.get());
|
|
gJWrapper = joystick.get();
|
|
firstlaunch = false;
|
|
CheckArguments(args);
|
|
}
|
|
reset = ygo::mainGame->MainLoop();
|
|
std::swap(data->tmp_device, ygo::mainGame->device);
|
|
if(reset) {
|
|
auto device = data->tmp_device;
|
|
device->setEventReceiver(nullptr);
|
|
auto driver = device->getVideoDriver();
|
|
/*the gles drivers have an additional cache, that isn't cleared when the textures are removed,
|
|
since it's not a big deal clearing them, as they'll be reused, they aren't cleared*/
|
|
/*driver->removeAllTextures();*/
|
|
driver->removeAllHardwareBuffers();
|
|
driver->removeAllOcclusionQueries();
|
|
device->getSceneManager()->clear();
|
|
auto env = device->getGUIEnvironment();
|
|
env->clear();
|
|
}
|
|
} while(reset);
|
|
return EXIT_SUCCESS;
|
|
}
|