Files
dayz-dma/src/main.cpp
T

129 lines
4.5 KiB
C++

#include <atomic>
#include <chrono>
#include <filesystem>
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#include <imgui.h>
#include "Config.h"
#include "Logger.h"
#include "Overlay/GameOverlay.h"
#include "Overlay/OverlayWindow.h"
#include "Runtime/DayZRuntimeService.h"
#include "Web/WebRadarServer.h"
// Shared stop flag so the console Ctrl+C / close handler can reach it.
static std::atomic<bool>* g_stopFlag = nullptr;
static BOOL WINAPI ConsoleCtrlHandler(DWORD signal) {
if (signal == CTRL_C_EVENT || signal == CTRL_CLOSE_EVENT ||
signal == CTRL_BREAK_EVENT)
{
if (g_stopFlag) g_stopFlag->store(true);
return TRUE;
}
return FALSE;
}
int main() {
std::filesystem::create_directories("logs");
AppLogger::Init();
auto log = AppLogger::Get();
log->info("DayZ Memory Reader - Starting");
RuntimeConfig rtCfg = RuntimeConfig::Load("config/config.cfg");
DayZRuntimeService service(rtCfg);
// -------------------------------------------------------------------------
// Config — loaded from config/overlay.json (defaults if missing).
// -------------------------------------------------------------------------
static const std::string kCfgPath = "config/overlay.json";
OverlayConfig cfg = OverlayConfig::Load(kCfgPath);
// -------------------------------------------------------------------------
// Web radar server — settings come from config.
// -------------------------------------------------------------------------
WebRadarConfig webCfg;
webCfg.bindAddress = cfg.webBindAddress;
webCfg.port = cfg.webPort;
webCfg.password = cfg.webPassword;
WebRadarServer webRadar(webCfg);
webRadar.Start();
// -------------------------------------------------------------------------
// Runtime service callback: log stats + push snapshot to web radar.
// -------------------------------------------------------------------------
service.SetUpdateCallback([&log, &webRadar](const RuntimeUpdate& update) {
// Always push to the web radar (even when not yet attached) so the
// browser client sees connection/status changes immediately.
webRadar.PushSnapshot(update);
if (!update.areBaseObjectsReady) {
// Status messages are already de-duplicated inside WaitForSession.
return;
}
// Periodic heartbeat at most once every 10 seconds. Kept terse — the
// interesting per-event detail (admins detected, skeletons lost) is logged
// as it happens by the runtime service, not polled here.
using Clock = std::chrono::steady_clock;
static auto nextLog = Clock::time_point{};
auto now = Clock::now();
if (now < nextLog) return;
nextLog = now + std::chrono::seconds(10);
// Skeleton coverage: how many in-range players currently have valid bones.
size_t skelOk = 0, admins = 0;
for (const auto& p : update.players) {
if (p.skeleton.valid) ++skelOk;
if (p.isAdmin) ++admins;
}
log->info("[Live] Players={} (bones {}/{}, admins {}) Zombies={} Vehicles={} Server='{}'",
update.players.size(),
skelOk, update.players.size(), admins,
update.zombies.size(),
update.carsAndBoats.size(),
update.serverName.value_or("?"));
});
service.Start();
// Overlay polls GetLatestUpdate() each frame; no extra callback needed.
std::atomic<bool> stopFlag{false};
g_stopFlag = &stopFlag;
GameOverlay overlay(service, cfg, kCfgPath);
overlay.SetWebRadarPort(webCfg.port);
overlay.SetExitCallback([&stopFlag]() { stopFlag.store(true); });
OverlayWindow window;
window.SetResolutionOverride(cfg.overlayWidth, cfg.overlayHeight);
overlay.SetResizeCallback([&window](int w, int h) { window.ResizeTo(w, h); });
window.SetDrawCallback([&overlay](float w, float h) {
overlay.Draw(w, h);
});
window.SetInputQueryCallback([&overlay]() {
return overlay.IsMenuOpen();
});
window.SetFontReadyCallback([&overlay](ImFont* close, ImFont* lootFar) {
overlay.SetLootFonts(close, lootFar);
});
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
// Blocks until the overlay window is closed or stopFlag is set externally.
window.Run(stopFlag);
webRadar.Stop();
service.Stop();
log->info("Stopped.");
spdlog::shutdown();
return 0;
}