mirror of
https://github.com/geode-sdk/geode.git
synced 2025-02-16 16:29:43 -05:00
Merge branch 'main' of https://github.com/geode-sdk/geode into main
This commit is contained in:
commit
a8cc48f35a
10 changed files with 132 additions and 118 deletions
|
@ -311,7 +311,8 @@ namespace gd {
|
|||
}
|
||||
|
||||
vector(std::vector<T> input) {
|
||||
auto tmp = new T[input.size()];
|
||||
std::allocator<T> alloc;
|
||||
auto tmp = alloc.allocate(input.size());
|
||||
|
||||
m_start = tmp;
|
||||
m_finish = m_start + input.size();
|
||||
|
@ -323,7 +324,8 @@ namespace gd {
|
|||
}
|
||||
|
||||
vector(std::initializer_list<T> const& input) {
|
||||
auto tmp = new T[input.size()];
|
||||
std::allocator<T> alloc;
|
||||
auto tmp = alloc.allocate(input.size());
|
||||
m_start = tmp;
|
||||
m_finish = m_start + input.size();
|
||||
m_capacity_end = m_start + input.size();
|
||||
|
@ -331,11 +333,11 @@ namespace gd {
|
|||
}
|
||||
|
||||
void clear() {
|
||||
delete[] m_start;
|
||||
auto tmp = new T[0];
|
||||
m_start = tmp;
|
||||
std::allocator<T> alloc;
|
||||
alloc.deallocate(m_start, (m_finish - m_start) / 8);
|
||||
m_start = alloc.allocate(1);
|
||||
m_finish = m_start;
|
||||
m_capacity_end = m_start;
|
||||
m_capacity_end = m_start + 8;
|
||||
}
|
||||
|
||||
T& front() {
|
||||
|
@ -363,7 +365,9 @@ namespace gd {
|
|||
vector() : vector(std::vector<T>()) {}
|
||||
|
||||
~vector() {
|
||||
delete[] m_start;
|
||||
for (auto i = m_start; i != m_finish; ++i) {
|
||||
delete i;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
|
@ -5,7 +5,11 @@
|
|||
|
||||
namespace geode {
|
||||
#ifdef GEODE_IS_WINDOWS
|
||||
constexpr const char* IPC_PIPE_NAME = "\\\\.\\pipe\\GeodeIPCPipe";
|
||||
constexpr char const* IPC_PIPE_NAME = "\\\\.\\pipe\\GeodeIPCPipe";
|
||||
#endif
|
||||
|
||||
#ifdef GEODE_IS_MACOS
|
||||
constexpr char const* IPC_PORT_NAME = "GeodeIPCPipe";
|
||||
#endif
|
||||
|
||||
class IPCFilter;
|
||||
|
@ -23,27 +27,11 @@ namespace geode {
|
|||
protected:
|
||||
void* m_rawPipeHandle;
|
||||
std::string m_targetModID;
|
||||
std::optional<std::string> m_replyID;
|
||||
std::string m_messageID;
|
||||
std::string* m_replyString;
|
||||
nlohmann::json m_messageData;
|
||||
bool m_replied = false;
|
||||
|
||||
/**
|
||||
* Reply to the message. Will post a message back to the application
|
||||
* the sent this message with the reply ID and provided data.
|
||||
* You can only reply once; after the other application has received
|
||||
* the reply, it can assume the reply ID can be freed and reused for
|
||||
* other messages. Calling reply again on this message will not cause
|
||||
* a new response to be sent.
|
||||
* If reply is not explicitly called, a default response of null will
|
||||
* be posted back.
|
||||
* @param data The data to send back; will be the under the "data" key
|
||||
* in the response JSON. The structure may be anything; however, you
|
||||
* should document what kind of JSON structures applications may expect
|
||||
* from your mod.
|
||||
*/
|
||||
void reply(nlohmann::json const& data);
|
||||
|
||||
friend class IPCFilter;
|
||||
|
||||
public:
|
||||
|
@ -51,14 +39,15 @@ namespace geode {
|
|||
void* rawPipeHandle,
|
||||
std::string const& targetModID,
|
||||
std::string const& messageID,
|
||||
std::optional<std::string> const& replyID,
|
||||
nlohmann::json const& messageData
|
||||
nlohmann::json const& messageData,
|
||||
std::string* replyString = nullptr
|
||||
);
|
||||
virtual ~IPCEvent();
|
||||
|
||||
std::optional<std::string> getReplyID() const;
|
||||
std::string getTargetModID() const;
|
||||
std::string getMessageID() const;
|
||||
std::string getReplyString() const;
|
||||
void setReplyString(std::string const& reply);
|
||||
nlohmann::json getMessageData() const;
|
||||
};
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@ namespace geode::utils::file {
|
|||
GEODE_DLL Result<> writeString(ghc::filesystem::path const& path, std::string const& data);
|
||||
GEODE_DLL Result<> writeBinary(ghc::filesystem::path const& path, byte_array const& data);
|
||||
|
||||
GEODE_DLL Result<> createDirectory(ghc::filesystem::path const& path);
|
||||
GEODE_DLL Result<> createDirectoryAll(ghc::filesystem::path const& path);
|
||||
GEODE_DLL Result<bool> createDirectory(ghc::filesystem::path const& path);
|
||||
GEODE_DLL Result<bool> createDirectoryAll(ghc::filesystem::path const& path);
|
||||
GEODE_DLL Result<std::vector<std::string>> listFiles(std::string const& path);
|
||||
GEODE_DLL Result<std::vector<std::string>> listFilesRecursively(std::string const& path);
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ void CCFileUtils::addPriorityPath(const char* path) {
|
|||
|
||||
void CCFileUtils::updatePaths() {
|
||||
// add search paths that aren't in PATHS or PACKS to PATHS
|
||||
|
||||
for (auto& path : m_searchPathArray) {
|
||||
bool isKnown = false;
|
||||
for (auto& pack : PACKS) {
|
||||
|
@ -60,10 +61,12 @@ void CCFileUtils::updatePaths() {
|
|||
}
|
||||
|
||||
// clear old paths
|
||||
|
||||
m_searchPathArray.clear();
|
||||
|
||||
// make sure addSearchPath doesn't add to PACKS or PATHS
|
||||
DONT_ADD_PATHS = true;
|
||||
|
||||
// add texture packs first
|
||||
for (auto& pack : PACKS) {
|
||||
for (auto& path : pack.m_paths) {
|
||||
|
@ -75,16 +78,19 @@ void CCFileUtils::updatePaths() {
|
|||
this->addSearchPath(path.c_str());
|
||||
}
|
||||
DONT_ADD_PATHS = false;
|
||||
|
||||
}
|
||||
|
||||
#pragma warning(pop)
|
||||
|
||||
class $modify(CCFileUtils) {
|
||||
static CCFileUtils* sharedFileUtils() {
|
||||
auto doAddPaths = !s_sharedFileUtils;
|
||||
static bool doAddPaths = true;
|
||||
auto ret = CCFileUtils::sharedFileUtils();
|
||||
|
||||
if (doAddPaths) {
|
||||
s_sharedFileUtils->updatePaths();
|
||||
ret->updatePaths();
|
||||
doAddPaths = false;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "resources.hpp"
|
||||
|
||||
#include <Geode/loader/Loader.hpp>
|
||||
#include <Geode/loader/IPC.hpp>
|
||||
#include <Geode/loader/Log.hpp>
|
||||
#include <Geode/loader/Dirs.hpp>
|
||||
#include <Geode/utils/web.hpp>
|
||||
|
@ -187,3 +188,36 @@ bool InternalLoader::verifyLoaderResources() {
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string InternalLoader::processRawIPC(void* rawHandle, std::string const& buffer) {
|
||||
std::string reply;
|
||||
|
||||
try {
|
||||
std::optional<std::string> replyID = std::nullopt;
|
||||
|
||||
// parse received message
|
||||
auto json = nlohmann::json::parse(buffer);
|
||||
if (!json.contains("mod") || !json["mod"].is_string()) {
|
||||
log::warn("Received IPC message without 'mod' field");
|
||||
return reply;
|
||||
}
|
||||
if (!json.contains("message") || !json["message"].is_string()) {
|
||||
log::warn("Received IPC message without 'message' field");
|
||||
return reply;
|
||||
}
|
||||
if (json.contains("reply") && json["reply"].is_string()) {
|
||||
replyID = json["reply"];
|
||||
}
|
||||
nlohmann::json data;
|
||||
if (json.contains("data")) {
|
||||
data = json["data"];
|
||||
}
|
||||
// log::debug("Posting IPC event");
|
||||
// ! warning: if the event system is ever made asynchronous this will break!
|
||||
IPCEvent(rawHandle, json["mod"], json["message"], data, &reply).post();
|
||||
} catch(...) {
|
||||
log::warn("Received IPC message that isn't valid JSON");
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
#include <Geode/loader/Log.hpp>
|
||||
#include <Geode/utils/Result.hpp>
|
||||
#include <Geode/external/json/json.hpp>
|
||||
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
|
@ -61,11 +63,7 @@ public:
|
|||
|
||||
bool setup();
|
||||
|
||||
void postIPCReply(
|
||||
void* rawPipeHandle,
|
||||
std::string const& replyID,
|
||||
nlohmann::json const& data
|
||||
);
|
||||
static std::string processRawIPC(void* rawHandle, std::string const& buffer);
|
||||
|
||||
/**
|
||||
* Check if a one-time event has been shown to the user,
|
||||
|
|
|
@ -7,23 +7,17 @@ IPCEvent::IPCEvent(
|
|||
void* rawPipeHandle,
|
||||
std::string const& targetModID,
|
||||
std::string const& messageID,
|
||||
std::optional<std::string> const& replyID,
|
||||
nlohmann::json const& messageData
|
||||
nlohmann::json const& messageData,
|
||||
std::string* replyString
|
||||
) : m_rawPipeHandle(rawPipeHandle),
|
||||
m_targetModID(targetModID),
|
||||
m_messageID(messageID),
|
||||
m_replyID(replyID),
|
||||
m_replyString(replyString),
|
||||
m_messageData(messageData) {}
|
||||
|
||||
IPCEvent::~IPCEvent() {
|
||||
// if no handler was installed for this IPC event, reply with a default null
|
||||
// value
|
||||
this->reply(nullptr);
|
||||
}
|
||||
IPCEvent::~IPCEvent() {}
|
||||
|
||||
|
||||
std::optional<std::string> IPCEvent::getReplyID() const {
|
||||
return m_replyID;
|
||||
}
|
||||
|
||||
std::string IPCEvent::getTargetModID() const {
|
||||
return m_targetModID;
|
||||
|
@ -33,17 +27,16 @@ std::string IPCEvent::getMessageID() const {
|
|||
return m_messageID;
|
||||
}
|
||||
|
||||
nlohmann::json IPCEvent::getMessageData() const {
|
||||
return m_messageData;
|
||||
std::string IPCEvent::getReplyString() const {
|
||||
return *m_replyString;
|
||||
}
|
||||
|
||||
void IPCEvent::reply(nlohmann::json const& data) {
|
||||
if (!m_replied && m_rawPipeHandle && m_replyID.has_value()) {
|
||||
InternalLoader::get()->postIPCReply(
|
||||
m_rawPipeHandle, m_replyID.value(), data
|
||||
);
|
||||
m_replied = true;
|
||||
}
|
||||
void IPCEvent::setReplyString(std::string const& reply) {
|
||||
*m_replyString = reply;
|
||||
}
|
||||
|
||||
nlohmann::json IPCEvent::getMessageData() const {
|
||||
return m_messageData;
|
||||
}
|
||||
|
||||
ListenerResult IPCFilter::handle(std::function<Callback> fn, IPCEvent* event) {
|
||||
|
@ -51,7 +44,7 @@ ListenerResult IPCFilter::handle(std::function<Callback> fn, IPCEvent* event) {
|
|||
event->getTargetModID() == m_modID &&
|
||||
event->getMessageID() == m_messageID
|
||||
) {
|
||||
event->reply(fn(event));
|
||||
event->setReplyString(fn(event));
|
||||
return ListenerResult::Stop;
|
||||
}
|
||||
return ListenerResult::Propagate;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <Geode/loader/Log.hpp>
|
||||
#include <iostream>
|
||||
#include <InternalMod.hpp>
|
||||
#include <Geode/loader/IPC.hpp>
|
||||
|
||||
#ifdef GEODE_IS_MACOS
|
||||
|
||||
|
@ -28,14 +29,45 @@ void InternalLoader::closePlatformConsole() {
|
|||
m_platformConsoleOpen = false;
|
||||
}
|
||||
|
||||
void InternalLoader::postIPCReply(
|
||||
void* rawPipeHandle,
|
||||
std::string const& replyID,
|
||||
nlohmann::json const& data
|
||||
) {}
|
||||
CFDataRef msgPortCallback(
|
||||
CFMessagePortRef port,
|
||||
SInt32 messageID,
|
||||
CFDataRef data,
|
||||
void* info
|
||||
) {
|
||||
if(!CFDataGetLength(data))
|
||||
return NULL;
|
||||
|
||||
std::string cdata(
|
||||
reinterpret_cast<char const*>(CFDataGetBytePtr(data)),
|
||||
CFDataGetLength(data)
|
||||
);
|
||||
|
||||
std::string reply = InternalLoader::processRawIPC(port, cdata);
|
||||
return CFDataCreate(NULL, (const UInt8*)reply.data(), reply.size());
|
||||
}
|
||||
|
||||
void InternalLoader::setupIPC() {
|
||||
#warning "Set up pipes or smth for this platform"
|
||||
std::thread([]() {
|
||||
CFStringRef portName = CFStringCreateWithCString(NULL, IPC_PORT_NAME, kCFStringEncodingUTF8);
|
||||
|
||||
CFMessagePortRef localPort = CFMessagePortCreateLocal(
|
||||
NULL,
|
||||
portName,
|
||||
msgPortCallback,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
CFRunLoopSourceRef runLoopSource = CFMessagePortCreateRunLoopSource(NULL, localPort, 0);
|
||||
|
||||
CFRunLoopAddSource(
|
||||
CFRunLoopGetCurrent(),
|
||||
runLoopSource,
|
||||
kCFRunLoopCommonModes
|
||||
);
|
||||
CFRunLoopRun();
|
||||
CFRelease(localPort);
|
||||
}).detach();
|
||||
log::log(Severity::Warning, InternalMod::get(), "IPC is not supported on this platform");
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include <InternalLoader.hpp>
|
||||
#include <Geode/loader/Log.hpp>
|
||||
#include <Geode/loader/IPC.hpp>
|
||||
#include <Geode/loader/Log.hpp>
|
||||
#include <iostream>
|
||||
#include <InternalMod.hpp>
|
||||
|
||||
|
@ -39,22 +39,6 @@ void InternalLoader::closePlatformConsole() {
|
|||
m_platformConsoleOpen = false;
|
||||
}
|
||||
|
||||
void InternalLoader::postIPCReply(
|
||||
void* rawPipeHandle,
|
||||
std::string const& replyID,
|
||||
nlohmann::json const& data
|
||||
) {
|
||||
auto msgJson = nlohmann::json::object();
|
||||
msgJson["reply"] = replyID;
|
||||
msgJson["data"] = data;
|
||||
auto msg = msgJson.dump();
|
||||
|
||||
DWORD written;
|
||||
WriteFile(rawPipeHandle, msg.c_str(), msg.size(), &written, nullptr);
|
||||
|
||||
// log::debug("Sent message {}", msg);
|
||||
}
|
||||
|
||||
void ipcPipeThread(HANDLE pipe) {
|
||||
char buffer[IPC_BUFFER_SIZE * sizeof(TCHAR)];
|
||||
DWORD read;
|
||||
|
@ -64,34 +48,12 @@ void ipcPipeThread(HANDLE pipe) {
|
|||
// log::debug("Waiting for I/O");
|
||||
if (ReadFile(pipe, buffer, sizeof(buffer) - 1, &read, nullptr)) {
|
||||
buffer[read] = '\0';
|
||||
// log::debug("Got message {}", buffer);
|
||||
try {
|
||||
// parse received message
|
||||
auto json = nlohmann::json::parse(buffer);
|
||||
if (!json.contains("mod") || !json["mod"].is_string()) {
|
||||
log::warn("Received IPC message without 'mod' field");
|
||||
goto ipc_done;
|
||||
}
|
||||
if (!json.contains("message") || !json["message"].is_string()) {
|
||||
log::warn("Received IPC message without 'message' field");
|
||||
goto ipc_done;
|
||||
}
|
||||
if (json.contains("reply") && json["reply"].is_string()) {
|
||||
replyID = json["reply"];
|
||||
}
|
||||
nlohmann::json data;
|
||||
if (json.contains("data")) {
|
||||
data = json["data"];
|
||||
}
|
||||
// log::debug("Posting IPC event");
|
||||
// ! warning: if the event system is ever made asynchronous this will break!
|
||||
IPCEvent(pipe, json["mod"], json["message"], replyID, data).post();
|
||||
} catch(...) {
|
||||
log::warn("Received IPC message that isn't valid JSON");
|
||||
}
|
||||
}
|
||||
|
||||
ipc_done:
|
||||
std::string reply = InternalLoader::processRawIPC((void*)pipe, buffer);
|
||||
|
||||
DWORD written;
|
||||
WriteFile(pipe, reply.c_str(), reply.size(), &written, nullptr);
|
||||
}
|
||||
// log::debug("Connection done");
|
||||
|
||||
FlushFileBuffers(pipe);
|
||||
|
|
|
@ -74,26 +74,22 @@ Result<> utils::file::writeBinary(ghc::filesystem::path const& path, byte_array
|
|||
return Err("Unable to open file");
|
||||
}
|
||||
|
||||
Result<> utils::file::createDirectory(ghc::filesystem::path const& path) {
|
||||
Result<bool> utils::file::createDirectory(ghc::filesystem::path const& path) {
|
||||
try {
|
||||
if (ghc::filesystem::create_directory(path)) {
|
||||
return Ok();
|
||||
}
|
||||
return Ok(ghc::filesystem::create_directory(path));
|
||||
}
|
||||
catch (...) {
|
||||
return Err("Unable to create directory");
|
||||
}
|
||||
return Err("Unable to create directory");
|
||||
}
|
||||
|
||||
Result<> utils::file::createDirectoryAll(ghc::filesystem::path const& path) {
|
||||
Result<bool> utils::file::createDirectoryAll(ghc::filesystem::path const& path) {
|
||||
try {
|
||||
if (ghc::filesystem::create_directories(path)) {
|
||||
return Ok();
|
||||
}
|
||||
return Ok(ghc::filesystem::create_directories(path));
|
||||
}
|
||||
catch (...) {
|
||||
return Err("Unable to create directories");
|
||||
}
|
||||
return Err("Unable to create directories");
|
||||
}
|
||||
|
||||
Result<std::vector<std::string>> utils::file::listFiles(std::string const& path) {
|
||||
|
|
Loading…
Reference in a new issue