Windows support: portable local server launch + clean quit, %APPDATA% data dir, Win32 libs, MinGW/MSVC build docs
This commit is contained in:
@@ -9,18 +9,13 @@
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <csignal>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <random>
|
||||
#include <thread>
|
||||
#include <spawn.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
extern char** environ;
|
||||
|
||||
namespace bs {
|
||||
|
||||
@@ -29,15 +24,6 @@ namespace ui = hd2d::ui;
|
||||
|
||||
namespace {
|
||||
|
||||
fs::path dataDir() {
|
||||
const char* xdg = std::getenv("XDG_DATA_HOME");
|
||||
fs::path base = xdg && *xdg ? fs::path(xdg) : fs::path(std::getenv("HOME") ? std::getenv("HOME") : ".") / ".local/share";
|
||||
fs::path d = base / "brandling-safari";
|
||||
std::error_code ec;
|
||||
fs::create_directories(d, ec);
|
||||
return d;
|
||||
}
|
||||
|
||||
std::string randomToken() {
|
||||
std::random_device rd;
|
||||
static const char* hex = "0123456789abcdef";
|
||||
@@ -106,7 +92,7 @@ int keyCode(const std::string& k) {
|
||||
// ------------------------------------------------------------------ identity
|
||||
|
||||
void App::loadIdentity() {
|
||||
fs::path p = dataDir() / (opt_.profile.empty() ? "client.json" : "client-" + opt_.profile + ".json");
|
||||
fs::path p = userDataDir() / (opt_.profile.empty() ? "client.json" : "client-" + opt_.profile + ".json");
|
||||
std::ifstream f(p);
|
||||
if (f) {
|
||||
try {
|
||||
@@ -126,7 +112,7 @@ void App::loadIdentity() {
|
||||
}
|
||||
|
||||
void App::saveIdentity() {
|
||||
fs::path p = dataDir() / (opt_.profile.empty() ? "client.json" : "client-" + opt_.profile + ".json");
|
||||
fs::path p = userDataDir() / (opt_.profile.empty() ? "client.json" : "client-" + opt_.profile + ".json");
|
||||
nlohmann::json j = {{"token", token_}, {"lastHost", lastHost_}, {"lastPort", lastPort_}, {"name", savedName_}};
|
||||
std::ofstream(p) << j.dump(2);
|
||||
}
|
||||
@@ -283,38 +269,13 @@ bool App::scripted(const char* key) const { return pressed(keyCode(key)); }
|
||||
// ------------------------------------------------------------------ local server
|
||||
|
||||
bool App::startLocalServer() {
|
||||
if (serverPid_ > 0) return true;
|
||||
std::error_code ec;
|
||||
fs::path exe = fs::read_symlink("/proc/self/exe", ec);
|
||||
fs::path server = exe.parent_path() / "safari_server";
|
||||
if (ec || !fs::exists(server)) {
|
||||
message_ = "safari_server was not found next to the game";
|
||||
return false;
|
||||
}
|
||||
std::string port = std::to_string(opt_.port);
|
||||
std::string name = std::string(nameBuf_) + "'s Safari";
|
||||
std::vector<std::string> args = {server.string(), "--port", port, "--name", name};
|
||||
std::vector<char*> argv;
|
||||
for (std::string& a : args) argv.push_back(a.data());
|
||||
argv.push_back(nullptr);
|
||||
pid_t pid = 0;
|
||||
if (posix_spawn(&pid, server.c_str(), nullptr, nullptr, argv.data(), environ) != 0) {
|
||||
message_ = "could not start the local server";
|
||||
return false;
|
||||
}
|
||||
serverPid_ = int(pid);
|
||||
HD2D_LOG("started local server (pid %d) on port %s", serverPid_, port.c_str());
|
||||
usleep(250000); // let it bind before we connect (the client retries anyway)
|
||||
if (localServer_.running()) return true;
|
||||
if (!localServer_.start(opt_.port, std::string(nameBuf_) + "'s Safari", message_)) return false;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(250)); // let it bind (the client retries anyway)
|
||||
return true;
|
||||
}
|
||||
|
||||
void App::stopLocalServer() {
|
||||
if (serverPid_ <= 0) return;
|
||||
kill(pid_t(serverPid_), SIGTERM);
|
||||
int status = 0;
|
||||
for (int i = 0; i < 50 && waitpid(pid_t(serverPid_), &status, WNOHANG) == 0; ++i) usleep(100000);
|
||||
serverPid_ = -1;
|
||||
}
|
||||
void App::stopLocalServer() { localServer_.stop(); }
|
||||
|
||||
// ------------------------------------------------------------------ flow
|
||||
|
||||
@@ -345,7 +306,7 @@ void App::handleNet() {
|
||||
NetClient::State st = net_.state();
|
||||
if (st == NetClient::State::Failed && screen_ != Screen::Title && screen_ != Screen::Join) {
|
||||
// a freshly started local server may not be listening yet: retry for a few seconds
|
||||
if (screen_ == Screen::Connecting && serverPid_ > 0 && connectTimer_ < 6.0f) {
|
||||
if (screen_ == Screen::Connecting && localServer_.running() && connectTimer_ < 6.0f) {
|
||||
net_.connect(lastHost_, lastPort_, token_);
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user