Merge branch 'main' of https://github.com/geode-sdk/geode into main

This commit is contained in:
HJfod 2022-12-01 22:43:11 +02:00
commit a8cc48f35a
10 changed files with 132 additions and 118 deletions

View file

@ -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:

View file

@ -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;
};

View file

@ -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);

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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,

View file

@ -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;

View file

@ -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");
}

View file

@ -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);

View file

@ -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) {