complete remake of log

This commit is contained in:
camila314 2022-10-06 16:08:44 -05:00
parent 7cca776919
commit b902a49894
28 changed files with 368 additions and 511 deletions

View file

@ -6,12 +6,10 @@
#include <variant>
#include "../utils/casts.hpp"
#include "../utils/Result.hpp"
#include "Log.hpp"
#include "Mod.hpp"
namespace geode {
class Hook;
class LogPtr;
/**
* For developing your own mods, it is
@ -49,16 +47,10 @@ namespace geode {
Result<Hook*>(Mod::*m_addFunction)(std::string const&, void*);
};
struct ScheduledLog {
std::string m_info;
Severity m_severity;
};
using ScheduledFunction = std::function<void()>;
Mod* m_mod = nullptr;
std::vector<ScheduledHook> m_scheduledHooks;
std::vector<ScheduledLog> m_scheduledLogs;
std::vector<ScheduledFunction> m_scheduledFunctions;
public:
@ -72,11 +64,6 @@ namespace geode {
return Interface::get()->m_mod;
}
[[deprecated("Use Log::get instead")]]
static inline GEODE_HIDDEN Log log() {
return Interface::get()->m_mod->log();
}
GEODE_DLL void init(Mod*);
/**
@ -113,16 +100,6 @@ namespace geode {
return Ok<Hook*>(nullptr);
}
/**
* Log an information. Equivalent to
* ```
* Mod::log() << Severity::severity << info.
* ```
* @param info Log information
* @param severity Log severity
*/
GEODE_DLL void logInfo(std::string const& info, Severity severity);
GEODE_DLL void scheduleOnLoad(ScheduledFunction function);
friend Mod* Mod::get<void>();
@ -132,10 +109,6 @@ namespace geode {
inline Mod* Mod::get<void>() {
return Interface::get()->m_mod;
}
inline Log Log::get() {
return Mod::get()->log();
}
}
inline const char* operator"" _spr(const char* str, size_t) {

View file

@ -26,8 +26,6 @@ namespace geode {
class Mod;
class Hook;
class Log;
class LogPtr;
struct ModInfo;
namespace modifier {
@ -51,7 +49,7 @@ namespace geode {
};
std::unordered_map<std::string, Mod*> m_mods;
std::vector<LogPtr*> m_logs;
std::vector<log::Log> m_logs;
std::ofstream m_logStream;
std::vector<ghc::filesystem::path> m_modDirectories;
std::vector<FailedModInfo> m_erroredMods;
@ -168,11 +166,10 @@ namespace geode {
*/
static bool isUnloading();
void pushLog(LogPtr* log);
void popLog(LogPtr* log);
std::vector<LogPtr*> getLogs() const;
std::vector<LogPtr*> getLogs(
std::initializer_list<Severity> severityFilter
void pushLog(log::Log&& log);
void popLog(log::Log* log);
std::vector<log::Log*> getLogs(
std::initializer_list<Severity> severityFilter = {}
);
/**

View file

@ -8,132 +8,123 @@
#include <fs/filesystem.hpp>
#include <ccTypes.h>
/*namespace cocos2d {
class CCObject;
class CCNode;
class CCPoint;
class CCSize;
class CCRect;
class CCArray;
}*/
GEODE_DLL std::ostream& operator<<(std::ostream& os, geode::Mod* mod);
GEODE_DLL std::ostream& operator<<(std::ostream& os, cocos2d::CCObject* obj);
GEODE_DLL std::ostream& operator<<(std::ostream& os, cocos2d::CCArray* obj);
GEODE_DLL std::ostream& operator<<(std::ostream& os, cocos2d::CCPoint const& pos);
GEODE_DLL std::ostream& operator<<(std::ostream& os, cocos2d::CCSize const& size);
GEODE_DLL std::ostream& operator<<(std::ostream& os, cocos2d::CCRect const& rect);
GEODE_DLL std::ostream& operator<<(std::ostream& os, cocos2d::ccColor3B const& color);
GEODE_DLL std::ostream& operator<<(std::ostream& os, cocos2d::ccColor4B const& color);
namespace std {
// <concepts> isn't working for me lmao
template <class From, class To>
concept convertible_to =
std::is_convertible_v<From, To> &&
requires {
static_cast<To>(std::declval<From>());
};
}
namespace geode {
class Mod;
#pragma warning(disable: 4251)
using log_clock = std::chrono::system_clock;
class Mod;
inline Mod* getMod();
struct GEODE_DLL LogMetadata {
std::string m_repr;
LogMetadata(std::string const& r) : m_repr(r) {}
LogMetadata() {}
virtual ~LogMetadata() {}
};
namespace log {
using log_clock = std::chrono::system_clock;
std::string generateLogName();
std::string generateLogName();
class Log;
class GEODE_DLL LogPtr {
protected:
Mod* m_sender = nullptr;
log_clock::time_point m_time = log_clock::now();
std::vector<LogMetadata*> m_data;
Severity m_severity = Severity::Debug;
friend class Log;
public:
LogPtr(Mod* Mod) : m_sender(Mod) {}
~LogPtr();
std::string toString(bool logTime = true) const;
std::vector<LogMetadata*> getData() const;
log_clock::time_point getTime() const;
std::string getTimeString() const;
Mod* getSender() const;
Severity getSeverity() const;
};
using ostream_fn_type = std::ostream&(*)(std::ostream&);
class GEODE_DLL Log {
protected:
LogPtr* m_logptr = nullptr;
std::stringstream m_stream;
void flush();
public:
static Log get();
inline Log(Mod* m) : m_logptr(new LogPtr(m)) {}
inline Log() : Log(nullptr) {}
Log& operator<<(ostream_fn_type);
Log& operator<<(Severity::type s);
Log& operator<<(Severity s);
struct GEODE_DLL ComponentTrait {
virtual std::string _toString() = 0;
};
template <typename T> requires requires(T b) { std::stringstream() << b; }
std::string parse(T const& thing) {
std::stringstream buf;
buf << thing;
return buf.str();
}
template <typename T>
Log& operator<<(T item) {
this->m_stream << item;
//static_assert(!std::is_same<Severity, T>::value, "didnt work :(");
return *this;
struct ComponentBase : public ComponentTrait {
T m_item;
inline ComponentBase(T const& item) : m_item(item) {}
// specialization must implement
inline std::string _toString() override { return parse(m_item); }
};
/*template <typename T> requires requires(T b) { std::stringstream() << b; }
struct Component<T> : ComponentBase<T> {
inline static std::string toString(T const& thing) {
std::stringstream buf;
buf << thing;
return buf.str();
}
};*/
class GEODE_DLL Log {
protected:
Mod* m_sender;
log_clock::time_point m_time;
std::vector<ComponentTrait*> m_components;
Severity m_severity;
public:
Log(Mod* mod, Severity sev);// : m_sender(mod), m_time(log_clock::now()), m_severity(sev) {}
Log(Log&& l) = default;
Log& operator=(Log&& l) = default;
bool operator==(Log const& l);
std::string toString(bool logTime = true) const;
void pushToLoader();
inline std::vector<ComponentTrait*>& getComponents() { return m_components; }
inline log_clock::time_point getTime() const { return m_time; }
inline Mod* getSender() const { return m_sender; }
inline Severity getSeverity() const { return m_severity; }
};
template <typename ...Args> requires requires(Args... b) { (parse(b), ...); }
void log(Severity sev, Mod* m, Args... args) {
Log l(m, sev);
(l.getComponents().push_back(new ComponentBase(args)), ...);
l.pushToLoader();
}
template <typename U, typename T>
Log& streamMeta(T t) {
static_assert(std::is_base_of<LogMetadata, U>::value, "Metadata class must derive from geode::LogMetadata");
template <typename ...Args>
void debug(Args... args) { log(Severity::Debug, getMod(), args...); }
auto md = new LogMetadata;
md->m_repr = this->m_stream.str();
this->m_logptr->m_data.push_back(md);
m_stream.str("");
template <typename ...Args>
void info(Args... args) { log(Severity::Info, getMod(), args...); }
md = new U(t);
m_stream << t;
md->m_repr = m_stream.str();
this->m_logptr->m_data.push_back(md);
m_stream.str("");
template <typename ...Args>
void notice(Args... args) { log(Severity::Notice, getMod(), args...); }
return *this;
}
template <typename ...Args>
void warn(Args... args) { log(Severity::Warning, getMod(), args...); }
~Log();
};
template <typename ...Args>
void error(Args... args) { log(Severity::Error, getMod(), args...); }
// geode-defined metadata functions
template <typename ...Args>
void critical(Args... args) { log(Severity::Critical, getMod(), args...); }
struct ModMeta : public LogMetadata {
Mod* m_mod;
ModMeta(Mod* m) : m_mod(m) {}
ModMeta(std::string const& r, Mod* m) : m_mod(m), LogMetadata(r) {}
};
struct GEODE_DLL CCObjectMeta : public LogMetadata {
cocos2d::CCObject* m_obj;
CCObjectMeta(cocos2d::CCObject* obj);
CCObjectMeta(std::string const& r, cocos2d::CCObject* obj);
~CCObjectMeta();
};
struct GEODE_DLL CCArrayMeta : public LogMetadata {
cocos2d::CCArray* m_arr;
CCArrayMeta(cocos2d::CCArray* arr);
CCArrayMeta(std::string const& r, cocos2d::CCArray* arr);
~CCArrayMeta();
};
template <typename ...Args>
void alert(Args... args) { log(Severity::Alert, getMod(), args...); }
template <typename ...Args>
void emergency(Args... args) { log(Severity::Emergency, getMod(), args...); }
// parse overload
#define FF(x) \
std::string parse(x const& thing);
FF(cocos2d::CCObject*)
FF(cocos2d::CCPoint)
FF(cocos2d::CCSize)
FF(cocos2d::CCRect)
FF(cocos2d::CCArray*)
FF(cocos2d::ccColor3B)
FF(cocos2d::ccColor4B)
FF(cocos2d::ccColor4F)
FF(Mod*)
#undef FF
}
}
GEODE_DLL geode::Log& operator<<(geode::Log&, geode::Mod*);
GEODE_DLL geode::Log& operator<<(geode::Log&, cocos2d::CCObject*);
GEODE_DLL geode::Log& operator<<(geode::Log&, cocos2d::CCArray*);

View file

@ -24,7 +24,6 @@ namespace geode {
class Hook;
class Patch;
class Loader;
class Log;
class Mod;
class Setting;
@ -365,27 +364,6 @@ namespace geode {
template<class = void>
static inline Mod* get();
/**
* Log to geode's integrated console /
* the platform debug console.
* @returns Reference to log stream. Make sure
* to end your logging with geode::endl.
*/
Log log();
/**
* Log an information. Equivalent to
* ```
* Mod::log() << Severity::severity << info.
* ```
* @param info Log infomration
* @param severity Log severity
*/
void logInfo(
std::string const& info,
Severity severity
);
/**
* Get all hooks owned by this Mod
* @returns Vector of hooks
@ -563,4 +541,14 @@ namespace geode {
const char* expandSpriteName(const char* name);
};
/**
* To bypass the need for cyclic dependencies,
* this function does the exact same as Mod::get()
* However, it can be externed, unlike Mod::get()
* @returns Same thing Mod::get() returns
*/
inline Mod* getMod() {
return Mod::get();
}
}

View file

@ -6,19 +6,18 @@
#include "../loader/Interface.hpp"
#include <iostream>
#define GEODE_APPLY_MODIFY_FOR_FUNCTION(index, convention, className, functionName) \
using base##index = wrap::functionName<Base, types::pure##index>; \
using derived##index = wrap::functionName<Derived, types::pure##index>; \
if constexpr (derived##index::uuid != nullptr && (void*)base##index::uuid != (void*)derived##index::uuid) { \
Interface::get()->logInfo( \
"Adding hook at function " #className "::" #functionName, \
Severity::Debug \
); \
Interface::get()->addHook<derived##index::value, convention>( \
#className "::" #functionName, \
(void*)addresses::address##index() \
); \
} \
#define GEODE_APPLY_MODIFY_FOR_FUNCTION(index, convention, className, functionName) \
using base##index = wrap::functionName<Base, types::pure##index>; \
using derived##index = wrap::functionName<Derived, types::pure##index>; \
if constexpr (derived##index::uuid != nullptr && (void*)base##index::uuid != (void*)derived##index::uuid) { \
log::debug( \
"Adding hook at function " #className "::" #functionName \
); \
Interface::get()->addHook<derived##index::value, convention>( \
#className "::" #functionName, \
(void*)addresses::address##index() \
); \
} \
namespace geode::modifier {

View file

@ -356,7 +356,7 @@ namespace geode {
void checkUnknownKeys() {
for (auto& [key, _] : self().m_json.items()) {
if (!m_knownKeys.count(key)) {
Log::get() << self().m_hierarchy + " contains unknown key \"" + key + "\"";
log::debug(self().m_hierarchy + " contains unknown key \"" + key + "\"");
}
}
}

View file

@ -88,7 +88,7 @@ namespace geode::addresser {
auto index = indexOf(func);
auto thunk = thunkOf(func);
Interface::get()->logInfo("[[" + utils::intToHex((void*)ins) + " + " + utils::intToHex(thunk) + "] + " + utils::intToHex(index) + "]", Severity::Debug);
log::debug("[[" + utils::intToHex((void*)ins) + " + " + utils::intToHex(thunk) + "] + " + utils::intToHex(index) + "]");
// [[this + thunk] + offset] is the f we want
auto address = *(intptr_t*)(*(intptr_t*)(reference_cast<intptr_t>(ins) + thunk) + index);
@ -167,17 +167,17 @@ namespace geode::addresser {
#else
template<typename T>
inline intptr_t getVirtual(T func) {
Interface::get()->logInfo("Get virtual function address from " + utils::intToHex(geode::cast::reference_cast<intptr_t>(func)), Severity::Debug);
log::debug("Get virtual function address from " + utils::intToHex(geode::cast::reference_cast<intptr_t>(func)));
auto addr = Addresser::addressOfVirtual(func);
Interface::get()->logInfo("The address is: " + utils::intToHex(addr), Severity::Debug);
log::debug("The address is: " + utils::intToHex(addr), Severity::Debug);
return addr;
}
template<typename T>
inline intptr_t getNonVirtual(T func) {
Interface::get()->logInfo("Get non-virtual function address from " + utils::intToHex(geode::cast::reference_cast<intptr_t>(func)), Severity::Debug);
log::debug("Get non-virtual function address from " + utils::intToHex(geode::cast::reference_cast<intptr_t>(func)));
auto addr = Addresser::addressOfNonVirtual(func);
Interface::get()->logInfo("The address is: " + utils::intToHex(addr), Severity::Debug);
log::debug("The address is: " + utils::intToHex(addr));
return addr;
}

View file

@ -176,7 +176,7 @@ namespace geode::utils::vector {
* @returns Reference to vector.
*/
template<class T>
std::vector<T>& erase(std::vector<T>& vec, T element) {
std::vector<T>& erase(std::vector<T>& vec, T& element) {
vec.erase(std::remove(vec.begin(), vec.end(), element), vec.end());
return vec;
}

View file

@ -0,0 +1,60 @@
{
"geode": "v0.2.0",
"id": "geode.loader",
"version": "v0.2.0",
"name": "Geode",
"developer": "Geode Team",
"description": "The Geode mod loader",
"repository": "https://github.com/geode-sdk/geode",
"resources": {
"fonts": {
"mdFont": {
"path": "fonts/Ubuntu-Regular.ttf",
"size": 80
},
"mdFontB": {
"path": "fonts/Ubuntu-Bold.ttf",
"size": 80
},
"mdFontI": {
"path": "fonts/Ubuntu-Italic.ttf",
"size": 80
},
"mdFontBI": {
"path": "fonts/Ubuntu-BoldItalic.ttf",
"size": 80
},
"mdFontMono": {
"path": "fonts/UbuntuMono-Regular.ttf",
"size": 80
}
},
"files": [
"images/*.png",
"sounds/*.ogg"
],
"spritesheets": {
"LogoSheet": [
"logos/*.png"
],
"APISheet": [
"*.png"
],
"BlankSheet": [
"blanks/*.png"
]
}
},
"settings": {
"show-platform-console": {
"type": "bool",
"default": false,
"name": "Show Platform Console",
"description": "Show the native console (if one exists). <cr>This setting is meant for developers</c>."
}
},
"issues": {
"info": "Post your issues on the <cp>Geode Github Repository</c>. <cy>Please follow the standard issue format</c>.",
"url": "https://github.com/geode-sdk/geode/issues/new"
}
}

View file

@ -5,16 +5,14 @@ USE_GEODE_NAMESPACE();
class $modify(AppDelegate) {
void trySaveGame() {
Loader::getInternalMod()->log() << "Saving...";
log::log(Severity::Info, Loader::getInternalMod(), "Saving...");
auto r = Loader::get()->saveSettings();
if (!r) {
Loader::getInternalMod()->logInfo(
r.error(), Severity::Error
);
log::log(Severity::Error, Loader::getInternalMod(), r.error());
}
Loader::getInternalMod()->log() << "Saved";
log::log(Severity::Info, Loader::getInternalMod(), "Saved");
return AppDelegate::trySaveGame();
}

View file

@ -317,29 +317,23 @@ void Index::addIndexItemFromFolder(ghc::filesystem::path const& dir) {
auto readJson = readJSON(dir / "index.json");
if (!readJson) {
Log::get() << Severity::Warning
<< "Error reading index.json: "
<< readJson.error() << ", skipping";
log::warn("Error reading index.json: ", readJson.error(), ", skipping");
return;
}
auto json = readJson.value();
if (!json.is_object()) {
Log::get() << Severity::Warning
<< "[index.json] is not an object, skipping";
log::warn("[index.json] is not an object, skipping");
return;
}
auto readModJson = readJSON<ModJson>(dir / "mod.json");
if (!readModJson) {
Log::get() << Severity::Warning
<< "Error reading mod.json: "
<< readModJson.error() << ", skipping";
log::warn("Error reading mod.json: ", readModJson.error(), ", skipping");
return;
}
auto info = ModInfo::create(readModJson.value());
if (!info) {
Log::get() << Severity::Warning
<< dir << ": " << info.error() << ", skipping";
log::warn(dir, ": ", info.error(), ", skipping");
return;
}
@ -352,16 +346,13 @@ void Index::addIndexItemFromFolder(ghc::filesystem::path const& dir) {
!json.contains("download") ||
!json["download"].is_object()
) {
Log::get() << Severity::Warning
<< "[index.json].download is not an object, "
"skipping";
log::warn("[index.json].download is not an object, skipping");
return;
}
#define REQUIRE_DOWNLOAD_KEY(key, type) \
if (!download.contains(key) || !download[key].is_##type()) {\
Log::get() << Severity::Warning\
<< "[index.json].download." key " is not a " #type ", skipping";\
log::warn("[index.json].download." key " is not a " #type ", skipping");\
return;\
}
@ -383,8 +374,7 @@ void Index::addIndexItemFromFolder(ghc::filesystem::path const& dir) {
if (json.contains("categories")) {
if (!json["categories"].is_array()) {
Log::get() << Severity::Warning
<< "[index.json].categories is not an array, skipping";
log::warn("[index.json].categories is not an array, skipping");
return;
}
item.m_categories = json["categories"].get<std::unordered_set<std::string>>();
@ -392,17 +382,14 @@ void Index::addIndexItemFromFolder(ghc::filesystem::path const& dir) {
}
} catch(std::exception& e) {
Log::get() << Severity::Warning
<< "[index.json] parsing error: "
<< e.what() << ", skipping";
log::warn("[index.json] parsing error: ", e.what(), ", skipping");
return;
}
m_items.push_back(item);
} else {
Log::get() << Severity::Warning << "Index directory "
<< dir << " is missing index.json, skipping";
log::warn("Index directory ", dir, " is missing index.json, skipping");
}
}

View file

@ -15,7 +15,7 @@ void InstallTicket::postProgress(
});
}
if (status == UpdateStatus::Failed || status == UpdateStatus::Finished) {
Log::get() << "Deleting InstallTicket at " << this;
log::info("Deleting InstallTicket at ", this);
// clean up own memory
delete this;
}

View file

@ -21,20 +21,18 @@ InternalLoader* InternalLoader::get() {
}
bool InternalLoader::setup() {
InternalMod::get()->log()
<< Severity::Debug << "Set up internal mod representation";
InternalMod::get()->log()
<< Severity::Debug << "Loading hooks... ";
log::log(Severity::Debug, InternalMod::get(), "Set up internal mod representation");
log::log(Severity::Debug, InternalMod::get(), "Loading hooks... ");
if (!this->loadHooks()) {
InternalMod::get()->log()
<< "There were errors loading some hooks, "
"see console for details";
log::log(
Severity::Error,
InternalMod::get(),
"There were errors loading some hooks, see console for details"
);
}
InternalMod::get()->log()
<< Severity::Debug << "Loaded hooks";
log::log(Severity::Debug, InternalMod::get(), "Loaded hooks");
return true;
}
@ -56,9 +54,9 @@ void InternalLoader::executeGDThreadQueue() {
m_gdThreadMutex.unlock();
}
void InternalLoader::logConsoleMessage(LogPtr* msg) {
void InternalLoader::logConsoleMessage(std::string const& msg) {
if (m_platformConsoleOpen) {
std::cout << msg->toString(true);
std::cout << msg;
}
}

View file

@ -47,7 +47,7 @@ public:
void queueInGDThread(std::function<void GEODE_CALL(void)> func);
void executeGDThreadQueue();
void logConsoleMessage(LogPtr*);
void logConsoleMessage(std::string const& msg);
bool platformConsoleOpen() const;
void openPlatformConsole();
void closePlatformConsole();

View file

@ -39,7 +39,7 @@ static ModInfo getInternalModInfo() {
InternalMod::InternalMod() : Mod(getInternalModInfo()) {
auto sett = this->loadSettings();
if (!sett) {
this->logInfo(sett.error(), Severity::Error);
log::log(Severity::Error, this, sett.error());
}
}

View file

@ -14,3 +14,6 @@ class InternalMod : public Mod {
public:
static InternalMod* get();
};
template <typename ...Args>
void internal_log(Severity sev, Args... args) { log::log(sev, InternalMod::get(), args...); }

View file

@ -84,10 +84,7 @@ bool InternalLoader::loadHooks() {
for (auto const& hook : internalHooks()) {
auto res = hook.mod->addHook(hook.hook);
if (!res) {
hook.mod->logInfo(
res.error(),
Severity::Error
);
log::log(Severity::Error, hook.mod, res.error());
thereWereErrors = true;
}
}

View file

@ -14,11 +14,6 @@ void Interface::init(Mod* mod) {
}
this->m_scheduledHooks.clear();
for (auto const& log : this->m_scheduledLogs) {
this->m_mod->logInfo(log.m_info, log.m_severity);
}
this->m_scheduledLogs.clear();
for (auto const& fn : this->m_scheduledFunctions) {
std::invoke(fn);
}
@ -26,16 +21,6 @@ void Interface::init(Mod* mod) {
}
}
void Interface::logInfo(
std::string const& info,
Severity severity
) {
if (this->m_mod) {
return this->m_mod->logInfo(info, severity);
}
this->m_scheduledLogs.push_back({ info, severity });
}
void Interface::scheduleOnLoad(ScheduledFunction function) {
this->m_scheduledFunctions.push_back(function);
}

View file

@ -47,7 +47,7 @@ void Loader::createDirectories() {
}
// files too
m_logStream = std::ofstream(logDir / generateLogName());
m_logStream = std::ofstream(logDir / log::generateLogName());
}
void Loader::updateResourcePaths() {
@ -75,10 +75,12 @@ void Loader::updateModResources(Mod* mod) {
ccfu->fullPathForFilename(plist.c_str(), false)
)
) {
InternalMod::get()->logInfo(
"The resource dir of \"" + mod->m_info.m_id +
"\" is missing \"" + sheet + "\" png and/or plist files",
Severity::Warning
internal_log(Severity::Warning,
"The resource dir of \"",
mod->m_info.m_id,
"\" is missing \"",
sheet,
"\" png and/or plist files"
);
} else {
CCTextureCache::sharedTextureCache()->addImage(png.c_str(), false);
@ -101,7 +103,7 @@ void Loader::updateResources() {
size_t Loader::loadModsFromDirectory(
ghc::filesystem::path const& dir, bool recursive
) {
InternalMod::get()->log() << Severity::Debug << "Searching " << dir;
internal_log(Severity::Debug, "Searching ", dir);
size_t loadedCount = 0;
for (auto const& entry : ghc::filesystem::directory_iterator(dir)) {
@ -131,9 +133,7 @@ size_t Loader::loadModsFromDirectory(
// load mod
InternalMod::get()->log()
<< Severity::Debug
<< "Loading " << entry.path().string();
internal_log(Severity::Debug, "Loading ", entry.path().string());
auto res = this->loadModFromFile(entry.path().string());
if (res && res.value()) {
@ -142,15 +142,13 @@ size_t Loader::loadModsFromDirectory(
// check for dependencies
if (!res.value()->hasUnresolvedDependencies()) {
InternalMod::get()->log()
<< "Succesfully loaded " << res.value();
internal_log(Severity::Debug, "Successfully loaded ", res.value());
} else {
InternalMod::get()->log()
<< res.value() << " has unresolved dependencies";
internal_log(Severity::Error, res.value(), " has unresolved dependencies");
}
} else {
// something went wrong
InternalMod::get()->logInfo(res.error(), Severity::Error);
internal_log(Severity::Error, res.error());
m_erroredMods.push_back({ entry.path().string(), res.error() });
}
}
@ -158,7 +156,7 @@ size_t Loader::loadModsFromDirectory(
}
size_t Loader::refreshMods() {
InternalMod::get()->log() << Severity::Debug << "Loading mods...";
internal_log(Severity::Debug, "Loading mods...");
// clear errored mods since that list will be
// reconstructed from scratch
@ -175,9 +173,7 @@ size_t Loader::refreshMods() {
loadedCount += loadModsFromDirectory(dir, true);
}
InternalMod::get()->log()
<< Severity::Debug
<< "Loaded " << loadedCount << " mods";
internal_log(Severity::Debug, "Loaded ", loadedCount, " mods");
return loadedCount;
}
@ -328,9 +324,7 @@ bool Loader::setup() {
if (m_isSetup)
return true;
InternalMod::get()->log()
<< Severity::Debug
<< "Setting up Loader...";
internal_log(Severity::Debug, "Setting up Loader...");
this->createDirectories();
this->loadSettings();
@ -342,13 +336,9 @@ bool Loader::setup() {
});
if (crashlog::setupPlatformHandler()) {
InternalMod::get()->log()
<< Severity::Debug
<< "Set up platform crash logger";
internal_log(Severity::Debug, "Set up platform crash logger");
} else {
InternalMod::get()->log()
<< Severity::Debug
<< "Unable to set up platform crash logger";
internal_log(Severity::Debug, "Unable to set up platform crash logger");
}
m_isSetup = true;
@ -364,46 +354,40 @@ Loader::~Loader() {
delete mod;
}
m_mods.clear();
for (auto const& log : m_logs) {
delete log;
}
m_logs.clear();
auto tempDir = this->getGeodeDirectory() / GEODE_TEMP_DIRECTORY;
ghc::filesystem::remove_all(tempDir);
}
void Loader::pushLog(LogPtr* logptr) {
m_logs.push_back(logptr);
void Loader::pushLog(log::Log&& log) {
m_logs.push_back(std::move(log));
InternalLoader::get()->logConsoleMessage(logptr);
std::string logStr = log.toString(true);
m_logStream << logptr->toString(true) << std::endl;
InternalLoader::get()->logConsoleMessage(logStr);
m_logStream << logStr << std::endl;
}
void Loader::popLog(LogPtr* log) {
utils::vector::erase(m_logs, log);
delete log;
void Loader::popLog(log::Log* log) {
/*for (auto i = m_logs.begin(); i < m_logs.end(); ++i) {
if (i == log) {
m_logs.erase(i);
}
}*/
utils::vector::erase(m_logs, *log);
}
std::vector<LogPtr*> Loader::getLogs() const {
return m_logs;
}
std::vector<LogPtr*> Loader::getLogs(
std::vector<log::Log*> Loader::getLogs(
std::initializer_list<Severity> severityFilter
) {
if (!severityFilter.size()) {
return m_logs;
}
std::vector<log::Log*> logs;
std::vector<LogPtr*> logs;
for (auto const& log : m_logs) {
for (auto& log : m_logs) {
if (utils::vector::contains<Severity>(
severityFilter, log->getSeverity()
)) {
logs.push_back(log);
severityFilter, log.getSeverity()
) || !severityFilter.size()) {
logs.push_back(&log);
}
}

View file

@ -5,88 +5,71 @@
#include <Geode/utils/general.hpp>
#include <Geode/utils/casts.hpp>
#include <InternalLoader.hpp>
#include <fmt/format.h>
#include <fmt/chrono.h>
#include <iomanip>
std::ostream& operator<<(std::ostream& os, Mod* mod) {
if (mod) {
os << "{ Mod, " + std::string(mod->getName()) + " }";
} else {
os << "{ Mod, null }";
}
return os;
}
std::ostream& operator<<(std::ostream& os, cocos2d::CCObject* obj) {
if (obj) {
os << "{ " + std::string(typeid(*obj).name()) + ", " + utils::intToHex(obj) + " }";
} else {
os << "{ CCObject, null }";
}
return os;
}
std::ostream& operator<<(std::ostream& os, cocos2d::CCArray* arr) {
os << "[";
if (arr && arr->count() > 0) {
auto last = arr->objectAtIndex(arr->count()-1);
for (auto obj : ccArrayToVector<cocos2d::CCObject*>(arr)) {
os << obj;
if (obj != last) os << ", ";
}
}
else os << "empty";
os << "]";
return os;
}
std::ostream& operator<<(std::ostream& os, cocos2d::CCPoint const& pos) {
os << pos.x << ", " << pos.y;
return os;
}
std::ostream& operator<<(std::ostream& os, cocos2d::CCSize const& size) {
os << size.width << " : " << size.height;
return os;
}
std::ostream& operator<<(std::ostream& os, cocos2d::CCRect const& rect) {
os << rect.origin.x << ", " << rect.origin.y << " | " << rect.size.width << " : " << rect.size.height;
return os;
}
std::ostream& operator<<(std::ostream& os, cocos2d::ccColor3B const& color) {
os << color.r << ", " << color.g << ", " << color.b;
return os;
}
std::ostream& operator<<(std::ostream& os, cocos2d::ccColor4B const& color) {
os << color.r << ", " << color.g << ", " << color.b << ", " << color.a;
return os;
}
USE_GEODE_NAMESPACE();
using namespace geode::log;
using namespace cocos2d;
log_clock::time_point LogPtr::getTime() const {
return m_time;
std::string log::parse(Mod* const& mod) {
if (mod) {
return fmt::format("{{ Mod, {} }}", mod->getName());;
} else {
return "{ Mod, null }";
}
}
std::string LogPtr::getTimeString() const {
return timePointAsString(m_time);
std::string log::parse(CCObject* const& obj) {
if (obj) {
return fmt::format("{{ {}, {} }}", typeid(*obj).name(), utils::intToHex(obj));
} else {
return "{ CCObject, null }";
}
}
Mod* LogPtr::getSender() const {
return m_sender;
std::string log::parse(CCArray* const& arr) {
std::string out = "[";
if (arr && arr->count()) {
for (int i = 0; i < arr->count(); ++i) {
out += parse(arr->objectAtIndex(i));
if (i < arr->count() - 1) out += ", ";
}
} else out += "empty";
return out + "]";
}
Severity LogPtr::getSeverity() const {
return m_severity;
std::string log::parse(CCPoint const& pt) {
return fmt::format("{}, {}", pt.x, pt.y);
}
LogPtr::~LogPtr() {}
std::string log::parse(CCSize const& sz) {
return fmt::format("{} : {}", sz.width, sz.height);
}
std::string LogPtr::toString(bool logTime) const {
std::stringstream res;
std::string log::parse(CCRect const& rect) {
return parse(rect.origin) + " | " + parse(rect.size);
}
std::string log::parse(cocos2d::ccColor3B const& col) {
return fmt::format("rgb({}, {}, {})", col.r, col.g, col.b);
}
std::string log::parse(cocos2d::ccColor4B const& col) {
return fmt::format("rgba({}, {}, {}, {})", col.r, col.g, col.b, col.a);
}
Log::Log(Mod* mod, Severity sev) : m_sender(mod), m_time(log_clock::now()), m_severity(sev) {}
bool Log::operator==(Log const& l) {
return this == &l;
}
std::string Log::toString(bool logTime) const {
std::string res;
if (logTime) {
const auto t = std::chrono::system_clock::to_time_t(this->m_time);
@ -96,109 +79,26 @@ std::string LogPtr::toString(bool logTime) const {
#else
obj = *std::localtime(&t);
#endif
res << '[' << std::put_time(&obj, "%H:%M:%S") << "] ";
}
res << '[';
if (this->m_sender) {
res << this->m_sender->getName();
} else {
res << '?';
}
res << "]:";
for (LogMetadata* i : this->m_data) {
res << ' ' << i->m_repr;
res += fmt::format("{:%H:%M:%S}", this->m_time);
}
return res.str();
res += fmt::format("[{}]:", this->m_sender ? this->m_sender->getName() : "?");
for (ComponentTrait* i : this->m_components) {
res += i->_toString();
}
return res;
}
std::vector<LogMetadata*> LogPtr::getData() const {
return m_data;
void Log::pushToLoader() {
Loader::get()->pushLog(std::move(*this));
}
std::string geode::generateLogName() {
std::string geode::log::generateLogName() {
std::stringstream tmp;
tmp << "Geode_"
<< std::chrono::duration_cast<std::chrono::seconds>(log_clock::now().time_since_epoch()).count()
<< ".log";
return tmp.str();
}
void Log::flush() {
this->m_logptr->m_data.push_back(new LogMetadata(this->m_stream.str()));
Loader::get()->pushLog(this->m_logptr);
// Loader manages this memory now
this->m_logptr = nullptr;
this->m_stream.str("");
}
Log::~Log() {
this->flush();
if (InternalLoader::get()->platformConsoleOpen()) {
std::cout << std::endl;
}
}
Log& Log::operator<<(Severity::type s) {
this->m_logptr->m_severity = s;
return *this;
}
Log& Log::operator<<(Severity s) {
this->m_logptr->m_severity = s;
return *this;
}
Log& Log::operator<<(ostream_fn_type t) {
if (t == reinterpret_cast<ostream_fn_type>(&std::endl<char, std::char_traits<char>>)) {
LogPtr* newlog = new LogPtr(*this->m_logptr);
this->flush();
this->m_logptr = newlog;
} else {
this->m_stream << t;
}
return *this;
}
Log& operator<<(Log& l, Mod* m) {
return l.streamMeta<ModMeta>(m);
}
Log& operator<<(Log& l, cocos2d::CCObject* o) {
return l.streamMeta<CCObjectMeta>(o);
}
Log& operator<<(Log& l, cocos2d::CCArray* a) {
return l.streamMeta<CCArrayMeta>(a);
}
CCObjectMeta::CCObjectMeta(cocos2d::CCObject* obj) : LogMetadata("") {
CC_SAFE_RETAIN(obj);
m_obj = obj;
}
CCObjectMeta::CCObjectMeta(std::string const& r, cocos2d::CCObject* obj) : LogMetadata(r) {
CC_SAFE_RETAIN(obj);
m_obj = obj;
}
CCObjectMeta::~CCObjectMeta() {
CC_SAFE_RELEASE(m_obj);
}
CCArrayMeta::CCArrayMeta(cocos2d::CCArray* arr) : LogMetadata("") {
CC_SAFE_RETAIN(arr);
m_arr = arr;
}
CCArrayMeta::CCArrayMeta(std::string const& r, cocos2d::CCArray* arr) : LogMetadata(r) {
CC_SAFE_RETAIN(arr);
m_arr = arr;
}
CCArrayMeta::~CCArrayMeta() {
CC_SAFE_RELEASE(m_arr);
}

View file

@ -76,10 +76,10 @@ Result<> Mod::loadSettings() {
);
}
} else {
this->logInfo(
"Encountered unknown setting \"" + key + "\" while "
"loading settings",
Severity::Warning
log::log(
Severity::Warning,
this,
"Encountered unknown setting \"" + key + "\" while loading settings"
);
}
}
@ -230,7 +230,7 @@ Result<> Mod::load() {
m_loaded = true;
if (m_loadDataFunc) {
if (!m_loadDataFunc(m_saveDirPath.string().c_str())) {
this->logInfo("Mod load data function returned false", Severity::Error);
log::log(Severity::Error, this, "Mod load data function returned false");
}
}
m_loadErrorInfo = "";
@ -249,7 +249,7 @@ Result<> Mod::unload() {
if (m_saveDataFunc) {
if (!m_saveDataFunc(m_saveDirPath.string().c_str())) {
this->logInfo("Mod save data function returned false", Severity::Error);
log::log(Severity::Error, this, "Mod save data function returned false");
}
}
@ -383,13 +383,13 @@ bool Mod::updateDependencyStates() {
auto r = dep.m_mod->load();
if (!r) {
dep.m_state = ModResolveState::Unloaded;
dep.m_mod->logInfo(r.error(), Severity::Error);
log::log(Severity::Error, dep.m_mod, r.error());
}
else {
auto r = dep.m_mod->enable();
if (!r) {
dep.m_state = ModResolveState::Disabled;
dep.m_mod->logInfo(r.error(), Severity::Error);
log::log(Severity::Error, dep.m_mod, r.error());
}
}
} else {
@ -410,22 +410,22 @@ bool Mod::updateDependencyStates() {
}
}
if (!hasUnresolved && !m_resolved) {
Log::get() << Severity::Debug << "All dependencies for " << m_info.m_id << " found";
log::debug("All dependencies for ", m_info.m_id, " found");
m_resolved = true;
if (m_enabled) {
Log::get() << Severity::Debug << "Resolved & loading " << m_info.m_id;
log::debug("Resolved & loading ", m_info.m_id);
auto r = this->load();
if (!r) {
Log::get() << Severity::Error << this << "Error loading: " << r.error();
log::error(this, " Error loading: ", r.error());
}
else {
auto r = this->enable();
if (!r) {
Log::get() << Severity::Error << this << "Error enabling: " << r.error();
log::error(this, " Error enabling: ", r.error());
}
}
} else {
Log::get() << Severity::Debug << "Resolved " << m_info.m_id << ", however not loading it as it is disabled";
log::debug("Resolved ", m_info.m_id, ", however not loading it as it is disabled");
}
}
return hasUnresolved;
@ -518,18 +518,6 @@ std::vector<Hook*> Mod::getHooks() const {
return m_hooks;
}
Log Mod::log() {
return Log(this);
}
void Mod::logInfo(
std::string const& info,
Severity severity
) {
Log l(this);
l << severity << info;
}
bool Mod::depends(std::string const& id) const {
return utils::vector::contains<Dependency>(
m_info.m_dependencies,

View file

@ -88,8 +88,8 @@ Result<ModInfo> ModInfo::createFromSchemaV010(ModJson const& rawJson) {
info.m_binaryName = info.m_id + GEODE_PLATFORM_EXTENSION;
if (root.has("binary")) {
Log::get() << "Warning: [mod.json].binary is deprecated "
"and will be removed in the future.";
log::warn("Warning: [mod.json].binary is deprecated "
"and will be removed in the future.");
}
root.has("binary").asOneOf<value_t::string, value_t::object>();

View file

@ -8,7 +8,7 @@ std::string g_lastError = "";
void geode_mod_log(void* cmod, const char* message) {
auto mod = reinterpret_cast<Mod*>(cmod);
mod->log() << message;
log::log(Severity::Debug, mod, message);
}
bool geode_mod_add_hook(void* cmod, void* address, void* detour) {

View file

@ -41,7 +41,7 @@ Result<Mod*> Loader::loadModFromFile(std::string const& path) {
auto sett = mod->loadSettings();
if (!sett) {
mod->logInfo(sett.error(), Severity::Error);
log::log(Severity::Error, mod, sett.error());
}
// enable mod if needed

View file

@ -99,9 +99,7 @@ int geodeEntry(void* platformData) {
return 1;
}
InternalMod::get()->log()
<< Severity::Debug
<< "Loaded internal Geode class";
internal_log(Severity::Debug, "Loaded internal Geode class");
// set up loader, load mods, etc.
if (!Loader::get()->setup()) {
@ -114,17 +112,13 @@ int geodeEntry(void* platformData) {
return 1;
}
InternalMod::get()->log()
<< Severity::Debug
<< "Set up loader";
internal_log(Severity::Debug, "Set up loader");
if (InternalMod::get()->getSettingValue<bool>("show-platform-console")) {
Loader::get()->openPlatformConsole();
}
InternalMod::get()->log()
<< Severity::Debug
<< "Entry done.";
internal_log(Severity::Debug, "Entry done.");
return 0;
}

View file

@ -281,7 +281,7 @@ struct MDParser {
auto isClosing = tag.front() == '/';
if (isClosing) tag = tag.substr(1);
if (tag.front() != 'c') {
Log::get() << Severity::Warning << "Unknown tag " << text;
log::warn("Unknown tag ", text);
renderer->renderString(text);
} else {
if (isClosing) {
@ -291,20 +291,18 @@ struct MDParser {
if (color) {
renderer->pushColor(color.value());
} else {
Log::get() << Severity::Warning
<< "Error parsing color: " << color.error();
log::warn("Error parsing color: ", color.error());
}
}
}
} else {
Log::get() << Severity::Warning
<< "Too short tag " << text;
log::warn("Too short tag ", text);
renderer->renderString(text);
}
} break;
default: {
Log::get() << Severity::Warning << "Unhandled text type " << type;
log::warn("Unhandled text type ", type);
} break;
}
return 0;
@ -369,7 +367,7 @@ struct MDParser {
} break;
default: {
Log::get() << Severity::Warning << "Unhandled block enter type " << type;
log::warn("Unhandled block enter type ", type);
} break;
}
return 0;
@ -451,7 +449,7 @@ struct MDParser {
case MD_BLOCKTYPE::MD_BLOCK_HR: {} break;
default: {
Log::get() << Severity::Warning << "Unhandled block leave type " << type;
log::warn("Unhandled block leave type ", type);
} break;
}
return 0;
@ -492,7 +490,7 @@ struct MDParser {
} break;
default: {
Log::get() << Severity::Warning << "Unhandled span enter type " << type;
log::warn("Unhandled span enter type ", type);
} break;
}
return 0;
@ -530,7 +528,7 @@ struct MDParser {
} break;
default: {
Log::get() << Severity::Warning << "Unhandled span leave type " << type;
log::warn("Unhandled span leave type ", type);
} break;
}
return 0;

View file

@ -458,8 +458,9 @@ void NotificationManager::push(Notification* notification) {
void NotificationManager::pop(Notification* notification) {
auto location = notification->m_location;
if (m_notifications.count(location)) {
auto ref = Ref(notification);
utils::vector::erase(
m_notifications.at(location), Ref(notification)
m_notifications.at(location), ref
);
if (!m_notifications.at(location).size()) {
m_notifications.erase(location);

View file

@ -34,7 +34,11 @@ Result<std::string> utils::file::readString(std::wstring const& path) {
#endif
Result<std::string> utils::file::readString(ghc::filesystem::path const& path) {
#if _WIN32
std::ifstream in(path.wstring(), std::ios::in | std::ios::binary);
#else
std::ifstream in(path.string(), std::ios::in | std::ios::binary);
#endif
if (in) {
std::string contents;
in.seekg(0, std::ios::end);
@ -66,7 +70,11 @@ Result<byte_array> utils::file::readBinary(std::wstring const& path) {
#endif
Result<byte_array> utils::file::readBinary(ghc::filesystem::path const& path) {
#if _WIN32
std::ifstream in(path.wstring(), std::ios::in | std::ios::binary);
#else
std::ifstream in(path.string(), std::ios::in | std::ios::binary);
#endif
if (in) {
return Ok(byte_array (std::istreambuf_iterator<char>(in), {}));
}
@ -103,7 +111,11 @@ Result<> utils::file::writeString(std::wstring const& path, std::string const& d
Result<> utils::file::writeString(ghc::filesystem::path const& path, std::string const& data) {
std::ofstream file;
#if _WIN32
file.open(path.wstring());
#else
file.open(path.string());
#endif
if (file.is_open()) {
file << data;
file.close();
@ -144,7 +156,11 @@ Result<> utils::file::writeBinary(std::wstring const& path, byte_array const& da
Result<> utils::file::writeBinary(ghc::filesystem::path const& path, byte_array const& data) {
std::ofstream file;
#if _WIN32
file.open(path.wstring(), std::ios::out | std::ios::binary);
#else
file.open(path.string(), std::ios::out | std::ios::binary);
#endif
if (file.is_open()) {
file.write(reinterpret_cast<const char*>(data.data()), data.size());
file.close();