Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose APIs for entity and item names #443

Merged
merged 1 commit into from
Oct 29, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 6 additions & 0 deletions Daybreak.GWCA/header/EntityNameModule.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#pragma once
#include "httplib.h"

namespace Daybreak::Modules::EntityNameModule {
void GetName(const httplib::Request& req, httplib::Response& res);
}
6 changes: 6 additions & 0 deletions Daybreak.GWCA/header/GameStateModule.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#pragma once
#include "httplib.h"

namespace Daybreak::Modules::GameStateModule {
void GetGameStateInfo(const httplib::Request&, httplib::Response& res);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once
#include "httplib.h"

namespace Daybreak::Modules::NameModule {
namespace Daybreak::Modules::ItemNameModule {
void GetName(const httplib::Request& req, httplib::Response& res);
}
7 changes: 7 additions & 0 deletions Daybreak.GWCA/header/Utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma once
#include <string>

namespace Daybreak::Utils {
std::string WStringToString(const std::wstring& wstr);
bool StringToInt(const std::string& str, int& outValue);
}
14 changes: 14 additions & 0 deletions Daybreak.GWCA/header/payloads/GameStatePayload.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once
#include <cstdint>
#include <json.hpp>
#include <payloads/StatePayload.h>

using json = nlohmann::json;

namespace Daybreak {
struct GameStatePayload {
std::list<StatePayload> States;
};

void to_json(json& j, const GameStatePayload& p);
}
16 changes: 16 additions & 0 deletions Daybreak.GWCA/header/payloads/StatePayload.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once
#include <cstdint>
#include <json.hpp>

using json = nlohmann::json;

namespace Daybreak {
struct StatePayload {
uint32_t Id = 0;
float PosX = 0;
float PosY = 0;
uint32_t State = 0;
};

void to_json(json& j, const StatePayload& p);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "pch.h"
#include "NameModule.h"
#include "EntityNameModule.h"
#include "payloads/NamePayload.h"
#include <GWCA/Managers/GameThreadMgr.h>
#include <GWCA/Managers/MapMgr.h>
Expand All @@ -14,25 +14,15 @@
#include <Windows.h>
#include <cstdint>
#include <limits>
#include "Utils.h"

namespace Daybreak::Modules::NameModule {
namespace Daybreak::Modules::EntityNameModule {
std::vector<std::tuple<uint32_t, std::promise<NamePayload>*, std::wstring*>> WaitingList;
std::queue<std::tuple<uint32_t, std::promise<NamePayload>>*> PromiseQueue;
std::mutex GameThreadMutex;
GW::HookEntry GameThreadHook;
volatile bool initialized = false;

std::string WStringToString(const std::wstring& wstr)
{
if (wstr.empty()) return std::string();

int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
std::string strTo(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);

return strTo;
}

std::wstring* GetAsyncName(uint32_t id) {
NamePayload namePayload;
auto agent = GW::Agents::GetAgentByID(id);
Expand Down Expand Up @@ -77,7 +67,7 @@
}
}

for (auto i = 0; i < WaitingList.size(); ) {

Check warning on line 70 in Daybreak.GWCA/source/EntityNameModule.cpp

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

'<': signed/unsigned mismatch

Check warning on line 70 in Daybreak.GWCA/source/EntityNameModule.cpp

View workflow job for this annotation

GitHub Actions / build (x86)

'<': signed/unsigned mismatch
auto item = &WaitingList[i];
auto name = std::get<2>(*item);
if (name->empty()) {
Expand All @@ -90,7 +80,7 @@
WaitingList.erase(WaitingList.begin() + i);
NamePayload payload;
payload.Id = id;
payload.Name = WStringToString(*name);
payload.Name = Daybreak::Utils::WStringToString(*name);
delete(name);
promise->set_value(payload);
}
Expand Down
15 changes: 3 additions & 12 deletions Daybreak.GWCA/source/GameModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,14 @@
#include <json.hpp>
#include <queue>
#include <algorithm>
#include "Utils.h"

namespace Daybreak::Modules::GameModule {
std::queue<std::promise<GamePayload>*> PromiseQueue;
std::mutex GameThreadMutex;
GW::HookEntry GameThreadHook;
volatile bool initialized = false;

std::string GetString(wchar_t* chars) {
if (!chars) {
return "";
}

std::string str(64, '\0');
auto length = std::wcstombs(&str[0], chars, 64);
str.resize(length);
return str;
}

std::list<QuestMetadata> GetQuestLog() {
std::list<QuestMetadata> questMetadatas;
auto questLog = GW::QuestMgr::GetQuestLog();
Expand Down Expand Up @@ -148,7 +138,7 @@
return players;
}

for (auto i = 0; i < worldContext->players.m_size; i++) {

Check warning on line 141 in Daybreak.GWCA/source/GameModule.cpp

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

'<': signed/unsigned mismatch

Check warning on line 141 in Daybreak.GWCA/source/GameModule.cpp

View workflow job for this annotation

GitHub Actions / build (x86)

'<': signed/unsigned mismatch
if (tempPlayerArray->agent_id != 0) {
players.push_back(*tempPlayerArray);
}
Expand Down Expand Up @@ -291,7 +281,8 @@
GW::Title gwTitle;
Title title;
int titleId = 0;
auto name = GetString(gwPlayer->name);
std::wstring nameString(gwPlayer->name);
auto name = Daybreak::Utils::WStringToString(nameString);
player.Name = name;

for (const auto &t : titles) {
Expand Down
104 changes: 104 additions & 0 deletions Daybreak.GWCA/source/GameStateModule.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#include "pch.h"
#include "GameStateModule.h"
#include <GWCA/Managers/GameThreadMgr.h>
#include <GWCA/Managers/AgentMgr.h>
#include <GWCA/GameEntities/Agent.h>
#include <GWCA/Managers/MapMgr.h>
#include <future>
#include <payloads/GameStatePayload.h>
#include <json.hpp>
#include <queue>
#include <algorithm>

namespace Daybreak::Modules::GameStateModule {
std::queue<std::promise<GameStatePayload>*> PromiseQueue;
std::mutex GameThreadMutex;
GW::HookEntry GameThreadHook;
volatile bool initialized = false;

std::list<GW::AgentLiving> GetLivingAgents() {
std::list<GW::AgentLiving> agentList;
const GW::AgentArray* agents_ptr = GW::Agents::GetAgentArray();
GW::AgentArray* agents = GW::Agents::GetAgentArray();
if (!agents) {
return agentList;
}

for (auto* a : *agents) {
const GW::AgentLiving* agent = a ? a->GetAsAgentLiving() : nullptr;
if (agent) {
agentList.push_back(*agent);
}
}

return agentList;
}

std::list<StatePayload> GetStates(
std::list<GW::AgentLiving> agents) {
std::list<StatePayload> states;
for (auto& agent : agents) {
StatePayload state;
state.Id = agent.agent_id;
state.PosX = agent.pos.x;
state.PosY = agent.pos.y;
state.State = agent.type_map;
states.push_back(state);
}

return states;
}

GameStatePayload GetPayload() {
GameStatePayload gamePayload;
if (!GW::Map::GetIsMapLoaded()) {
return gamePayload;
}

auto agents = GetLivingAgents();
if (agents.empty()) {
return gamePayload;
}

auto states = GetStates(agents);
gamePayload.States = states;
return gamePayload;
}

void EnsureInitialized() {
GameThreadMutex.lock();
if (!initialized) {
GW::GameThread::RegisterGameThreadCallback(&GameThreadHook, [&](GW::HookStatus*) {
while (!PromiseQueue.empty()) {
auto promise = PromiseQueue.front();
PromiseQueue.pop();
try {
auto payload = GetPayload();
promise->set_value(payload);
}
catch (...) {
GameStatePayload payload;
promise->set_value(payload);
}
}
});

initialized = true;
}

GameThreadMutex.unlock();
}

void GetGameStateInfo(const httplib::Request&, httplib::Response& res) {
auto callbackEntry = new GW::HookEntry;
auto response = new std::promise<GameStatePayload>;

EnsureInitialized();
PromiseQueue.emplace(response);
json responsePayload = response->get_future().get();

delete callbackEntry;
delete response;
res.set_content(responsePayload.dump(), "text/json");
}
}
Loading
Loading