mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-27 01:45:35 -05:00
Merge branch 'main' of https://github.com/geode-sdk/geode into main
This commit is contained in:
commit
0cfb064631
65 changed files with 1170 additions and 779 deletions
|
@ -54,8 +54,24 @@ include(cmake/GeodeFile.cmake)
|
||||||
include(cmake/Platform.cmake)
|
include(cmake/Platform.cmake)
|
||||||
include(cmake/CPM.cmake)
|
include(cmake/CPM.cmake)
|
||||||
|
|
||||||
|
CPMAddPackage("gh:geode-sdk/json#2b76460")
|
||||||
|
CPMAddPackage("gh:fmtlib/fmt#9.1.0")
|
||||||
|
CPMAddPackage("gh:gulrak/filesystem#3e5b930")
|
||||||
|
|
||||||
|
# Tulip hook (hooking)
|
||||||
|
if (PROJECT_IS_TOP_LEVEL AND NOT GEODE_BUILDING_DOCS)
|
||||||
|
set(TULIP_LINK_SOURCE ON)
|
||||||
|
endif()
|
||||||
|
CPMAddPackage("gh:geode-sdk/TulipHook#a2c16d0")
|
||||||
|
|
||||||
|
|
||||||
target_sources(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/entry.cpp)
|
target_sources(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/entry.cpp)
|
||||||
|
|
||||||
|
# Filesystem implementation in a separate target because i couldnt disable pch
|
||||||
|
add_library(GeodeFilesystemImpl ${CMAKE_CURRENT_SOURCE_DIR}/FilesystemImpl.cpp)
|
||||||
|
target_compile_features(GeodeFilesystemImpl PUBLIC cxx_std_20)
|
||||||
|
target_link_libraries(GeodeFilesystemImpl PUBLIC ghc_filesystem)
|
||||||
|
|
||||||
include(ExternalProject)
|
include(ExternalProject)
|
||||||
set(GEODE_CODEGEN_BINARY_OUT ${CMAKE_CURRENT_BINARY_DIR}/codegen)
|
set(GEODE_CODEGEN_BINARY_OUT ${CMAKE_CURRENT_BINARY_DIR}/codegen)
|
||||||
ExternalProject_Add(CodegenProject
|
ExternalProject_Add(CodegenProject
|
||||||
|
@ -103,7 +119,7 @@ endif()
|
||||||
|
|
||||||
add_library(GeodeCodegenSources ${GEODE_CODEGEN_PATH}/Geode/GeneratedSource.cpp ${GEODE_CODEGEN_PATH}/Geode/GeneratedAddress.cpp)
|
add_library(GeodeCodegenSources ${GEODE_CODEGEN_PATH}/Geode/GeneratedSource.cpp ${GEODE_CODEGEN_PATH}/Geode/GeneratedAddress.cpp)
|
||||||
target_link_directories(GeodeCodegenSources PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/loader/include/link)
|
target_link_directories(GeodeCodegenSources PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/loader/include/link)
|
||||||
target_link_libraries(GeodeCodegenSources PRIVATE ghc_filesystem fmt TulipHookInclude)
|
target_link_libraries(GeodeCodegenSources PRIVATE ghc_filesystem GeodeFilesystemImpl fmt TulipHookInclude)
|
||||||
target_include_directories(GeodeCodegenSources PRIVATE
|
target_include_directories(GeodeCodegenSources PRIVATE
|
||||||
${GEODE_CODEGEN_PATH}
|
${GEODE_CODEGEN_PATH}
|
||||||
${GEODE_LOADER_PATH}/include
|
${GEODE_LOADER_PATH}/include
|
||||||
|
@ -127,17 +143,7 @@ target_include_directories(${PROJECT_NAME} INTERFACE
|
||||||
)
|
)
|
||||||
target_link_directories(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/loader/include/link)
|
target_link_directories(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/loader/include/link)
|
||||||
|
|
||||||
CPMAddPackage("gh:geode-sdk/json#2b76460")
|
target_link_libraries(${PROJECT_NAME} INTERFACE ghc_filesystem fmt TulipHookInclude GeodeCodegenSources mat-json GeodeFilesystemImpl)
|
||||||
CPMAddPackage("gh:fmtlib/fmt#9.1.0")
|
|
||||||
CPMAddPackage("gh:gulrak/filesystem#3e5b930")
|
|
||||||
|
|
||||||
# Tulip hook (hooking)
|
|
||||||
if (PROJECT_IS_TOP_LEVEL AND NOT GEODE_BUILDING_DOCS)
|
|
||||||
set(TULIP_LINK_SOURCE ON)
|
|
||||||
endif()
|
|
||||||
CPMAddPackage("gh:geode-sdk/TulipHook#76984a4")
|
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME} INTERFACE ghc_filesystem fmt TulipHookInclude GeodeCodegenSources mat-json)
|
|
||||||
|
|
||||||
|
|
||||||
if (NOT EXISTS ${GEODE_BIN_PATH})
|
if (NOT EXISTS ${GEODE_BIN_PATH})
|
||||||
|
|
4
FilesystemImpl.cpp
Normal file
4
FilesystemImpl.cpp
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
// filesystem implementation
|
||||||
|
#undef GHC_FILESYSTEM_H
|
||||||
|
#include <ghc/fs_impl.hpp>
|
||||||
|
|
|
@ -859,7 +859,16 @@ class CreatorLayer : cocos2d::CCLayer {
|
||||||
void onChallenge(cocos2d::CCObject*) = win 0x4f1b0;
|
void onChallenge(cocos2d::CCObject*) = win 0x4f1b0;
|
||||||
void onLeaderboards(cocos2d::CCObject*) = win 0x4ed20;
|
void onLeaderboards(cocos2d::CCObject*) = win 0x4ed20;
|
||||||
void onMyLevels(cocos2d::CCObject*) = mac 0x142b70, win 0x4eaa0;
|
void onMyLevels(cocos2d::CCObject*) = mac 0x142b70, win 0x4eaa0;
|
||||||
void onSavedLevels(cocos2d::CCObject*) = mac 0x142860;
|
void onSavedLevels(cocos2d::CCObject*) = mac 0x142860, win 0x4ebe0;
|
||||||
|
void onDailyLevel(cocos2d::CCObject*) = win 0x4f170;
|
||||||
|
void onWeeklyLevel(cocos2d::CCObject*) = win 0x4f190;
|
||||||
|
void onFeaturedLevels(cocos2d::CCObject*) = win 0x4edf0;
|
||||||
|
void onFameLevels(cocos2d::CCObject*) = win 0x4ee70;
|
||||||
|
void onMapPacks(cocos2d::CCObject*) = win 0x4efb0;
|
||||||
|
void onOnlineLevels(cocos2d::CCObject*) = win 0x4ef60;
|
||||||
|
void onGauntlets(cocos2d::CCObject*) = win 0x4f0a0;
|
||||||
|
void onSecretVault(cocos2d::CCObject*) = win 0x4f1d0;
|
||||||
|
void onTreasureRoom(cocos2d::CCObject*) = win 0x4f540;
|
||||||
virtual void sceneWillResume() = win 0x4fb50;
|
virtual void sceneWillResume() = win 0x4fb50;
|
||||||
virtual bool init() = mac 0x141c10, win 0x4de40;
|
virtual bool init() = mac 0x141c10, win 0x4de40;
|
||||||
static CreatorLayer* create() = win 0x4dda0;
|
static CreatorLayer* create() = win 0x4dda0;
|
||||||
|
@ -3692,7 +3701,7 @@ class LevelEditorLayer : GJBaseGameLayer, LevelSettingsDelegate {
|
||||||
bool m_previewMode;
|
bool m_previewMode;
|
||||||
GJGroundLayer* m_groundLayer;
|
GJGroundLayer* m_groundLayer;
|
||||||
std::string m_rawLevelString;
|
std::string m_rawLevelString;
|
||||||
void* m_triggerHitbox;
|
void* m_triggerHitbox; // why are these std vector bruh
|
||||||
std::vector<GameObject*> m_objectVector;
|
std::vector<GameObject*> m_objectVector;
|
||||||
std::vector<GameObject*> m_groupVector;
|
std::vector<GameObject*> m_groupVector;
|
||||||
std::vector<cocos2d::CCArray*> m_nestedObjects;
|
std::vector<cocos2d::CCArray*> m_nestedObjects;
|
||||||
|
@ -5158,6 +5167,10 @@ class StatsCell : TableViewCell {
|
||||||
virtual void draw() = mac 0x11bf80, win 0x59d40;
|
virtual void draw() = mac 0x11bf80, win 0x59d40;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class StatsLayer : GJDropDownLayer {
|
||||||
|
static StatsLayer* create() = win 0x25BCF0;
|
||||||
|
}
|
||||||
|
|
||||||
class TableView : CCScrollLayerExt, CCScrollLayerExtDelegate {
|
class TableView : CCScrollLayerExt, CCScrollLayerExtDelegate {
|
||||||
inline TableView() {}
|
inline TableView() {}
|
||||||
inline TableView(cocos2d::CCRect rect) : CCScrollLayerExt(rect) {}
|
inline TableView(cocos2d::CCRect rect) : CCScrollLayerExt(rect) {}
|
||||||
|
|
|
@ -10,7 +10,6 @@ namespace {
|
||||||
char const* modify_start = R"GEN(#pragma once
|
char const* modify_start = R"GEN(#pragma once
|
||||||
#include <Geode/modify/Modify.hpp>
|
#include <Geode/modify/Modify.hpp>
|
||||||
#include <Geode/modify/Field.hpp>
|
#include <Geode/modify/Field.hpp>
|
||||||
#include <Geode/modify/InternalMacros.hpp>
|
|
||||||
#include <Geode/modify/Addresses.hpp>
|
#include <Geode/modify/Addresses.hpp>
|
||||||
{class_include}
|
{class_include}
|
||||||
using namespace geode::modifier;
|
using namespace geode::modifier;
|
||||||
|
@ -92,8 +91,7 @@ std::string generateModifyHeader(Root& root, ghc::filesystem::path const& single
|
||||||
if (fn->type == FunctionType::Normal && !used.count(fn->name)) {
|
if (fn->type == FunctionType::Normal && !used.count(fn->name)) {
|
||||||
used.insert(fn->name);
|
used.insert(fn->name);
|
||||||
statics += fmt::format(
|
statics += fmt::format(
|
||||||
format_strings::statics_declare_identifier,
|
format_strings::statics_declare_identifier, fmt::arg("function_name", fn->name)
|
||||||
fmt::arg("function_name", fn->name)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include <broma.hpp>
|
#include <broma.hpp>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <fmt/ranges.h>
|
#include <fmt/ranges.h>
|
||||||
#include <ghc/filesystem.hpp> // bruh
|
#include <ghc/filesystem.hpp>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
using std::istreambuf_iterator;
|
using std::istreambuf_iterator;
|
||||||
|
|
|
@ -35,11 +35,11 @@ file(GLOB SOURCES CONFIGURE_DEPENDS
|
||||||
|
|
||||||
# Obj-c sources
|
# Obj-c sources
|
||||||
file(GLOB OBJC_SOURCES
|
file(GLOB OBJC_SOURCES
|
||||||
src/platform/ios/*.mm
|
src/platform/Objcpp.mm
|
||||||
src/platform/mac/*.mm
|
|
||||||
)
|
)
|
||||||
set_source_files_properties(${OBJC_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
|
set_source_files_properties(${OBJC_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
|
||||||
|
|
||||||
|
|
||||||
# Add platform sources
|
# Add platform sources
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
|
|
||||||
|
@ -152,13 +152,13 @@ target_link_libraries(${PROJECT_NAME} z TulipHook geode-sdk mat-json)
|
||||||
# Use precompiled headers for faster builds
|
# Use precompiled headers for faster builds
|
||||||
if (NOT GEODE_DISABLE_PRECOMPILED_HEADERS)
|
if (NOT GEODE_DISABLE_PRECOMPILED_HEADERS)
|
||||||
target_precompile_headers(${PROJECT_NAME} PRIVATE
|
target_precompile_headers(${PROJECT_NAME} PRIVATE
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/DefaultInclude.hpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/Geode.hpp"
|
||||||
# "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/Utils.hpp"
|
# "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/Utils.hpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/Loader.hpp"
|
# "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/Loader.hpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/UI.hpp"
|
# "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/UI.hpp"
|
||||||
# "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/Bindings.hpp"
|
# "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/Bindings.hpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/cocos/include/cocos2d.h"
|
# "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/cocos/include/cocos2d.h"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/cocos/extensions/cocos-ext.h"
|
# "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/cocos/extensions/cocos-ext.h"
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,6 @@
|
||||||
|
|
||||||
#include "Bindings.hpp"
|
#include "Bindings.hpp"
|
||||||
#include "Loader.hpp"
|
#include "Loader.hpp"
|
||||||
#include "Utils.hpp"
|
|
||||||
// #include "Modify.hpp"
|
|
||||||
#include "UI.hpp"
|
#include "UI.hpp"
|
||||||
|
#include "Utils.hpp"
|
||||||
|
#include "modify/Modify.hpp" // doesn't include generated modify
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "modify/Field.hpp"
|
#include "modify/Modify.hpp"
|
||||||
#include "modify/InternalMacros.hpp"
|
|
||||||
|
|
||||||
#include <Geode/DefaultInclude.hpp>
|
|
||||||
#include <Geode/GeneratedModify.hpp>
|
#include <Geode/GeneratedModify.hpp>
|
||||||
|
|
||||||
using namespace geode::modifier;
|
using namespace geode::modifier;
|
|
@ -10,3 +10,4 @@
|
||||||
#include "utils/file.hpp"
|
#include "utils/file.hpp"
|
||||||
#include "utils/general.hpp"
|
#include "utils/general.hpp"
|
||||||
#include "utils/timer.hpp"
|
#include "utils/timer.hpp"
|
||||||
|
#include "utils/MiniFunction.hpp"
|
||||||
|
|
|
@ -28,6 +28,8 @@ namespace gd {
|
||||||
return std::string((char*)m_data, m_data[-1].m_len);
|
return std::string((char*)m_data, m_data[-1].m_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator<(string const& other) const;
|
||||||
|
|
||||||
bool operator==(string const& other) const;
|
bool operator==(string const& other) const;
|
||||||
string(string const& ok);
|
string(string const& ok);
|
||||||
string& operator=(char const* ok);
|
string& operator=(char const* ok);
|
||||||
|
@ -58,142 +60,6 @@ namespace gd {
|
||||||
T m_value;
|
T m_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void _rb_tree_rotate_left(_rb_tree_base* const x, _rb_tree_base*& root) {
|
|
||||||
_rb_tree_base* const y = x->m_right;
|
|
||||||
|
|
||||||
x->m_right = y->m_left;
|
|
||||||
if (y->m_left != 0) y->m_left->m_parent = x;
|
|
||||||
y->m_parent = x->m_parent;
|
|
||||||
|
|
||||||
if (x == root) root = y;
|
|
||||||
else if (x == x->m_parent->m_left) x->m_parent->m_left = y;
|
|
||||||
else x->m_parent->m_right = y;
|
|
||||||
y->m_left = x;
|
|
||||||
x->m_parent = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _rb_tree_rotate_right(_rb_tree_base* const x, _rb_tree_base*& root) {
|
|
||||||
_rb_tree_base* const y = x->m_left;
|
|
||||||
|
|
||||||
x->m_left = y->m_right;
|
|
||||||
if (y->m_right != 0) y->m_right->m_parent = x;
|
|
||||||
y->m_parent = x->m_parent;
|
|
||||||
|
|
||||||
if (x == root) root = y;
|
|
||||||
else if (x == x->m_parent->m_right) x->m_parent->m_right = y;
|
|
||||||
else x->m_parent->m_left = y;
|
|
||||||
y->m_right = x;
|
|
||||||
x->m_parent = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _rb_insert_rebalance(
|
|
||||||
bool const insert_left, _rb_tree_base* x, _rb_tree_base* p, _rb_tree_base& header
|
|
||||||
) {
|
|
||||||
_rb_tree_base*& root = header.m_parent;
|
|
||||||
|
|
||||||
x->m_parent = p;
|
|
||||||
x->m_left = 0;
|
|
||||||
x->m_right = 0;
|
|
||||||
x->m_isblack = false;
|
|
||||||
|
|
||||||
if (insert_left) {
|
|
||||||
p->m_left = x;
|
|
||||||
|
|
||||||
if (p == &header) {
|
|
||||||
header.m_parent = x;
|
|
||||||
header.m_right = x;
|
|
||||||
}
|
|
||||||
else if (p == header.m_left) {
|
|
||||||
header.m_left = x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
p->m_right = x;
|
|
||||||
|
|
||||||
if (p == header.m_right) {
|
|
||||||
header.m_right = x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (x != root && x->m_parent->m_isblack == false) {
|
|
||||||
_rb_tree_base* const xpp = x->m_parent->m_parent;
|
|
||||||
|
|
||||||
if (x->m_parent == xpp->m_left) {
|
|
||||||
_rb_tree_base* const y = xpp->m_right;
|
|
||||||
if (y && y->m_isblack == false) {
|
|
||||||
x->m_parent->m_isblack = true;
|
|
||||||
y->m_isblack = true;
|
|
||||||
xpp->m_isblack = false;
|
|
||||||
x = xpp;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (x == x->m_parent->m_right) {
|
|
||||||
x = x->m_parent;
|
|
||||||
_rb_tree_rotate_left(x, root);
|
|
||||||
}
|
|
||||||
x->m_parent->m_isblack = true;
|
|
||||||
xpp->m_isblack = false;
|
|
||||||
_rb_tree_rotate_right(xpp, root);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_rb_tree_base* const y = xpp->m_left;
|
|
||||||
if (y && y->m_isblack == false) {
|
|
||||||
x->m_parent->m_isblack = true;
|
|
||||||
y->m_isblack = true;
|
|
||||||
xpp->m_isblack = false;
|
|
||||||
x = xpp;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (x == x->m_parent->m_left) {
|
|
||||||
x = x->m_parent;
|
|
||||||
_rb_tree_rotate_right(x, root);
|
|
||||||
}
|
|
||||||
x->m_parent->m_isblack = true;
|
|
||||||
xpp->m_isblack = false;
|
|
||||||
_rb_tree_rotate_left(xpp, root);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
root->m_isblack = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static _rb_tree_base* _rb_increment(_rb_tree_base* __x) throw() {
|
|
||||||
if (__x->m_right != 0) {
|
|
||||||
__x = __x->m_right;
|
|
||||||
while (__x->m_left != 0)
|
|
||||||
__x = __x->m_left;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_rb_tree_base* __y = __x->m_parent;
|
|
||||||
while (__x == __y->m_right) {
|
|
||||||
__x = __y;
|
|
||||||
__y = __y->m_parent;
|
|
||||||
}
|
|
||||||
if (__x->m_right != __y) __x = __y;
|
|
||||||
}
|
|
||||||
return __x;
|
|
||||||
}
|
|
||||||
|
|
||||||
static _rb_tree_base* _rb_decrement(_rb_tree_base* __x) throw() {
|
|
||||||
if (!__x->m_isblack && __x->m_parent->m_parent == __x) __x = __x->m_right;
|
|
||||||
else if (__x->m_left != 0) {
|
|
||||||
_rb_tree_base* __y = __x->m_left;
|
|
||||||
while (__y->m_right != 0)
|
|
||||||
__y = __y->m_right;
|
|
||||||
__x = __y;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_rb_tree_base* __y = __x->m_parent;
|
|
||||||
while (__x == __y->m_left) {
|
|
||||||
__x = __y;
|
|
||||||
__y = __y->m_parent;
|
|
||||||
}
|
|
||||||
__x = __y;
|
|
||||||
}
|
|
||||||
return __x;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename K, typename V>
|
template <typename K, typename V>
|
||||||
class GEODE_DLL map {
|
class GEODE_DLL map {
|
||||||
protected:
|
protected:
|
||||||
|
@ -204,96 +70,25 @@ namespace gd {
|
||||||
public:
|
public:
|
||||||
typedef _rb_tree_node<std::pair<K, V>>* _tree_node;
|
typedef _rb_tree_node<std::pair<K, V>>* _tree_node;
|
||||||
|
|
||||||
std::map<K, V> std() {
|
std::map<K, V> std();
|
||||||
return (std::map<K, V>)(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
operator std::map<K, V>() {
|
operator std::map<K, V>();
|
||||||
auto iter_node = static_cast<_tree_node>(m_header.m_left);
|
|
||||||
auto end_node = static_cast<_tree_node>(&m_header);
|
|
||||||
std::map<K, V> out;
|
|
||||||
for (; iter_node != end_node;
|
|
||||||
iter_node = static_cast<_tree_node>(_rb_increment(iter_node))) {
|
|
||||||
out[iter_node->m_value.first] = iter_node->m_value.second;
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
operator std::map<K, V>() const;
|
||||||
}
|
|
||||||
|
|
||||||
operator std::map<K, V>() const {
|
void insert(_tree_node x, _tree_node p, std::pair<K, V> const& val);
|
||||||
auto iter_node = static_cast<_tree_node>(m_header.m_left);
|
|
||||||
auto end_node = (_tree_node)(&m_header);
|
|
||||||
std::map<K, V> out;
|
|
||||||
for (; iter_node != end_node;
|
|
||||||
iter_node = static_cast<_tree_node>(_rb_increment(iter_node))) {
|
|
||||||
out[iter_node->m_value.first] = iter_node->m_value.second;
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
void insert_pair(std::pair<K, V> const& val);
|
||||||
}
|
|
||||||
|
|
||||||
void insert(_tree_node x, _tree_node p, std::pair<K, V> const& val) {
|
map(std::map<K, V> input);
|
||||||
bool insert_left =
|
|
||||||
(x != 0 || p == static_cast<_tree_node>(&m_header) || val.first < p->m_value.first);
|
|
||||||
|
|
||||||
_tree_node z = new _rb_tree_node<std::pair<K, V>>();
|
void erase(_tree_node x);
|
||||||
z->m_value = val;
|
|
||||||
|
|
||||||
_rb_insert_rebalance(insert_left, z, p, m_header);
|
map(map const& lol);
|
||||||
++m_nodecount;
|
|
||||||
}
|
|
||||||
|
|
||||||
void insert_pair(std::pair<K, V> const& val) {
|
map();
|
||||||
_tree_node x = static_cast<_tree_node>(m_header.m_parent);
|
|
||||||
_tree_node y = static_cast<_tree_node>(&m_header);
|
|
||||||
bool comp = true;
|
|
||||||
while (x != 0) {
|
|
||||||
y = x;
|
|
||||||
comp = val.first < x->m_value.first;
|
|
||||||
x = comp ? static_cast<_tree_node>(x->m_left) : static_cast<_tree_node>(x->m_right);
|
|
||||||
}
|
|
||||||
auto iter = y;
|
|
||||||
|
|
||||||
if (comp) {
|
~map();
|
||||||
if (iter == static_cast<_tree_node>(m_header.m_left)) {
|
|
||||||
insert(x, y, val);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
iter = static_cast<_tree_node>(_rb_decrement(iter));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (iter->m_value.first < val.first) {
|
|
||||||
insert(x, y, val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
map(std::map<K, V> input) {
|
|
||||||
m_header.m_isblack = false;
|
|
||||||
m_header.m_parent = 0;
|
|
||||||
m_header.m_left = &m_header;
|
|
||||||
m_header.m_right = &m_header;
|
|
||||||
|
|
||||||
for (auto i : input) {
|
|
||||||
insert_pair(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void erase(_tree_node x) {
|
|
||||||
while (x != 0) {
|
|
||||||
erase(static_cast<_tree_node>(x->m_right));
|
|
||||||
auto y = static_cast<_tree_node>(x->m_left);
|
|
||||||
delete y;
|
|
||||||
x = y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
map(map const& lol) : map(std::map<K, V>(lol)) {}
|
|
||||||
|
|
||||||
map() : map(std::map<K, V>()) {}
|
|
||||||
|
|
||||||
~map() {
|
|
||||||
erase(static_cast<_tree_node>(m_header.m_parent));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// template <class Type>
|
// template <class Type>
|
||||||
|
|
|
@ -25,7 +25,7 @@ THE SOFTWARE.
|
||||||
#define __SUPPORT_ZIPUTILS_H__
|
#define __SUPPORT_ZIPUTILS_H__
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <ghc/filesystem.hpp>
|
#include <ghc/fs_fwd.hpp>
|
||||||
#include "../../platform/CCPlatformDefine.h"
|
#include "../../platform/CCPlatformDefine.h"
|
||||||
#include "../../platform/CCPlatformConfig.h"
|
#include "../../platform/CCPlatformConfig.h"
|
||||||
#include "../../include/ccMacros.h"
|
#include "../../include/ccMacros.h"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ghc/filesystem.hpp>
|
#include <ghc/fs_fwd.hpp>
|
||||||
#include "../DefaultInclude.hpp"
|
#include "../DefaultInclude.hpp"
|
||||||
|
|
||||||
namespace geode::dirs {
|
namespace geode::dirs {
|
||||||
|
|
|
@ -28,9 +28,9 @@ namespace geode {
|
||||||
// template <typename... Args>
|
// template <typename... Args>
|
||||||
// class DispatchHandler : public EventHandler<DispatchEvent<Args...>> {
|
// class DispatchHandler : public EventHandler<DispatchEvent<Args...>> {
|
||||||
// std::string m_selector;
|
// std::string m_selector;
|
||||||
// std::function<void(Args...)> m_callback;
|
// utils::MiniFunction<void(Args...)> m_callback;
|
||||||
|
|
||||||
// DispatchHandler(std::string const& name, std::function<void(Args...)> callback) :
|
// DispatchHandler(std::string const& name, utils::MiniFunction<void(Args...)> callback) :
|
||||||
// m_selector(name), m_callback(callback) {}
|
// m_selector(name), m_callback(callback) {}
|
||||||
|
|
||||||
// public:
|
// public:
|
||||||
|
@ -42,7 +42,7 @@ namespace geode {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// static DispatchHandler* create(
|
// static DispatchHandler* create(
|
||||||
// std::string const& name, std::function<void(Args...)> callback
|
// std::string const& name, utils::MiniFunction<void(Args...)> callback
|
||||||
// ) {
|
// ) {
|
||||||
// return new DispatchHandler(name, callback);
|
// return new DispatchHandler(name, callback);
|
||||||
// }
|
// }
|
||||||
|
|
|
@ -41,7 +41,7 @@ namespace geode {
|
||||||
using Callback = ListenerResult(T*);
|
using Callback = ListenerResult(T*);
|
||||||
using Event = T;
|
using Event = T;
|
||||||
|
|
||||||
ListenerResult handle(std::function<Callback> fn, T* e) {
|
ListenerResult handle(utils::MiniFunction<Callback> fn, T* e) {
|
||||||
return fn(e);
|
return fn(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -74,7 +74,7 @@ namespace geode {
|
||||||
this->enable();
|
this->enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
EventListener(std::function<Callback> fn, T filter = T())
|
EventListener(utils::MiniFunction<Callback> fn, T filter = T())
|
||||||
: m_callback(fn), m_filter(filter)
|
: m_callback(fn), m_filter(filter)
|
||||||
{
|
{
|
||||||
this->enable();
|
this->enable();
|
||||||
|
@ -106,7 +106,7 @@ namespace geode {
|
||||||
this->enable();
|
this->enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
void bind(std::function<Callback> fn) {
|
void bind(utils::MiniFunction<Callback> fn) {
|
||||||
m_callback = fn;
|
m_callback = fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ namespace geode {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::function<Callback> m_callback = nullptr;
|
utils::MiniFunction<Callback> m_callback = nullptr;
|
||||||
T m_filter;
|
T m_filter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ namespace geode {
|
||||||
std::string m_messageID;
|
std::string m_messageID;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ListenerResult handle(std::function<Callback> fn, IPCEvent* event);
|
ListenerResult handle(utils::MiniFunction<Callback> fn, IPCEvent* event);
|
||||||
IPCFilter(
|
IPCFilter(
|
||||||
std::string const& modID,
|
std::string const& modID,
|
||||||
std::string const& messageID
|
std::string const& messageID
|
||||||
|
|
|
@ -26,7 +26,7 @@ namespace geode {
|
||||||
public:
|
public:
|
||||||
using Callback = void(ModInstallEvent*);
|
using Callback = void(ModInstallEvent*);
|
||||||
|
|
||||||
ListenerResult handle(std::function<Callback> fn, ModInstallEvent* event);
|
ListenerResult handle(utils::MiniFunction<Callback> fn, ModInstallEvent* event);
|
||||||
ModInstallFilter(std::string const& id);
|
ModInstallFilter(std::string const& id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ namespace geode {
|
||||||
public:
|
public:
|
||||||
using Callback = void(IndexUpdateEvent*);
|
using Callback = void(IndexUpdateEvent*);
|
||||||
|
|
||||||
ListenerResult handle(std::function<Callback> fn, IndexUpdateEvent* event);
|
ListenerResult handle(utils::MiniFunction<Callback> fn, IndexUpdateEvent* event);
|
||||||
IndexUpdateFilter();
|
IndexUpdateFilter();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ghc/filesystem.hpp>
|
#include <ghc/fs_fwd.hpp>
|
||||||
#include "../utils/Result.hpp"
|
#include "../utils/Result.hpp"
|
||||||
|
#include "../utils/MiniFunction.hpp"
|
||||||
#include "Log.hpp"
|
#include "Log.hpp"
|
||||||
#include "ModInfo.hpp"
|
#include "ModInfo.hpp"
|
||||||
#include "Types.hpp"
|
#include "Types.hpp"
|
||||||
|
@ -10,7 +11,7 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
namespace geode {
|
namespace geode {
|
||||||
using ScheduledFunction = std::function<void GEODE_CALL(void)>;
|
using ScheduledFunction = utils::MiniFunction<void()>;
|
||||||
|
|
||||||
struct InvalidGeodeFile {
|
struct InvalidGeodeFile {
|
||||||
ghc::filesystem::path path;
|
ghc::filesystem::path path;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <Geode/utils/ranges.hpp>
|
#include <Geode/utils/ranges.hpp>
|
||||||
#include <ccTypes.h>
|
#include <ccTypes.h>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <ghc/filesystem.hpp>
|
#include <ghc/fs_fwd.hpp>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <span>
|
#include <span>
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace geode {
|
||||||
Mod* m_mod;
|
Mod* m_mod;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ListenerResult handle(std::function<Callback> fn, ModStateEvent* event);
|
ListenerResult handle(utils::MiniFunction<Callback> fn, ModStateEvent* event);
|
||||||
ModStateFilter(Mod* mod, ModEventType type);
|
ModStateFilter(Mod* mod, ModEventType type);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Types.hpp"
|
|
||||||
#include <json.hpp>
|
|
||||||
#include "../utils/VersionInfo.hpp"
|
|
||||||
#include "../utils/Result.hpp"
|
#include "../utils/Result.hpp"
|
||||||
|
#include "../utils/VersionInfo.hpp"
|
||||||
#include "Setting.hpp"
|
#include "Setting.hpp"
|
||||||
|
#include "Types.hpp"
|
||||||
|
|
||||||
|
#include <json.hpp>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace geode {
|
namespace geode {
|
||||||
namespace utils::file {
|
namespace utils::file {
|
||||||
|
@ -28,20 +30,34 @@ namespace geode {
|
||||||
* Represents all the data gatherable
|
* Represents all the data gatherable
|
||||||
* from mod.json
|
* from mod.json
|
||||||
*/
|
*/
|
||||||
struct GEODE_DLL ModInfo {
|
class GEODE_DLL ModInfo {
|
||||||
|
class Impl;
|
||||||
|
std::unique_ptr<Impl> m_impl;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ModInfo();
|
||||||
|
ModInfo(ModInfo const& other);
|
||||||
|
ModInfo(ModInfo&& other) noexcept;
|
||||||
|
ModInfo& operator=(ModInfo const& other);
|
||||||
|
ModInfo& operator=(ModInfo&& other) noexcept;
|
||||||
|
~ModInfo();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Path to the mod file
|
* Path to the mod file
|
||||||
*/
|
*/
|
||||||
ghc::filesystem::path path;
|
ghc::filesystem::path& path();
|
||||||
|
ghc::filesystem::path const& path() const;
|
||||||
/**
|
/**
|
||||||
* Name of the platform binary within
|
* Name of the platform binary within
|
||||||
* the mod zip
|
* the mod zip
|
||||||
*/
|
*/
|
||||||
std::string binaryName;
|
std::string& binaryName();
|
||||||
|
std::string const& binaryName() const;
|
||||||
/**
|
/**
|
||||||
* Mod Version. Should follow semver.
|
* Mod Version. Should follow semver.
|
||||||
*/
|
*/
|
||||||
VersionInfo version { 1, 0, 0 };
|
VersionInfo& version();
|
||||||
|
VersionInfo const& version() const;
|
||||||
/**
|
/**
|
||||||
* Human-readable ID of the Mod.
|
* Human-readable ID of the Mod.
|
||||||
* Recommended to be in the format
|
* Recommended to be in the format
|
||||||
|
@ -51,14 +67,16 @@ namespace geode {
|
||||||
* be restricted to the ASCII
|
* be restricted to the ASCII
|
||||||
* character set.
|
* character set.
|
||||||
*/
|
*/
|
||||||
std::string id;
|
std::string& id();
|
||||||
|
std::string const& id() const;
|
||||||
/**
|
/**
|
||||||
* Name of the mod. May contain
|
* Name of the mod. May contain
|
||||||
* spaces & punctuation, but should
|
* spaces & punctuation, but should
|
||||||
* be restricted to the ASCII
|
* be restricted to the ASCII
|
||||||
* character set.
|
* character set.
|
||||||
*/
|
*/
|
||||||
std::string name;
|
std::string& name();
|
||||||
|
std::string const& name() const;
|
||||||
/**
|
/**
|
||||||
* The name of the head developer.
|
* The name of the head developer.
|
||||||
* Should be a single name, like
|
* Should be a single name, like
|
||||||
|
@ -70,65 +88,79 @@ namespace geode {
|
||||||
* should be named in `m_credits`
|
* should be named in `m_credits`
|
||||||
* instead.
|
* instead.
|
||||||
*/
|
*/
|
||||||
std::string developer;
|
std::string& developer();
|
||||||
|
std::string const& developer() const;
|
||||||
/**
|
/**
|
||||||
* Short & concise description of the
|
* Short & concise description of the
|
||||||
* mod.
|
* mod.
|
||||||
*/
|
*/
|
||||||
std::optional<std::string> description;
|
std::optional<std::string>& description();
|
||||||
|
std::optional<std::string> const& description() const;
|
||||||
/**
|
/**
|
||||||
* Detailed description of the mod, writtenin Markdown (see
|
* Detailed description of the mod, writtenin Markdown (see
|
||||||
* <Geode/ui/MDTextArea.hpp>) for more info
|
* <Geode/ui/MDTextArea.hpp>) for more info
|
||||||
*/
|
*/
|
||||||
std::optional<std::string> details;
|
std::optional<std::string>& details();
|
||||||
|
std::optional<std::string> const& details() const;
|
||||||
/**
|
/**
|
||||||
* Changelog for the mod, written in Markdown (see
|
* Changelog for the mod, written in Markdown (see
|
||||||
* <Geode/ui/MDTextArea.hpp>) for more info
|
* <Geode/ui/MDTextArea.hpp>) for more info
|
||||||
*/
|
*/
|
||||||
std::optional<std::string> changelog;
|
std::optional<std::string>& changelog();
|
||||||
|
std::optional<std::string> const& changelog() const;
|
||||||
/**
|
/**
|
||||||
* Support info for the mod; this means anything to show ways to
|
* Support info for the mod; this means anything to show ways to
|
||||||
* support the mod's development, like donations. Written in Markdown
|
* support the mod's development, like donations. Written in Markdown
|
||||||
* (see MDTextArea for more info)
|
* (see MDTextArea for more info)
|
||||||
*/
|
*/
|
||||||
std::optional<std::string> supportInfo;
|
std::optional<std::string>& supportInfo();
|
||||||
|
std::optional<std::string> const& supportInfo() const;
|
||||||
/**
|
/**
|
||||||
* Git Repository of the mod
|
* Git Repository of the mod
|
||||||
*/
|
*/
|
||||||
std::optional<std::string> repository;
|
std::optional<std::string>& repository();
|
||||||
|
std::optional<std::string> const& repository() const;
|
||||||
/**
|
/**
|
||||||
* Info about where users should report issues and request help
|
* Info about where users should report issues and request help
|
||||||
*/
|
*/
|
||||||
std::optional<IssuesInfo> issues;
|
std::optional<IssuesInfo>& issues();
|
||||||
|
std::optional<IssuesInfo> const& issues() const;
|
||||||
/**
|
/**
|
||||||
* Dependencies
|
* Dependencies
|
||||||
*/
|
*/
|
||||||
std::vector<Dependency> dependencies;
|
std::vector<Dependency>& dependencies();
|
||||||
|
std::vector<Dependency> const& dependencies() const;
|
||||||
/**
|
/**
|
||||||
* Mod spritesheet names
|
* Mod spritesheet names
|
||||||
*/
|
*/
|
||||||
std::vector<std::string> spritesheets;
|
std::vector<std::string>& spritesheets();
|
||||||
|
std::vector<std::string> const& spritesheets() const;
|
||||||
/**
|
/**
|
||||||
* Mod settings
|
* Mod settings
|
||||||
* @note Not a map because insertion order must be preserved
|
* @note Not a map because insertion order must be preserved
|
||||||
*/
|
*/
|
||||||
std::vector<std::pair<std::string, Setting>> settings;
|
std::vector<std::pair<std::string, Setting>>& settings();
|
||||||
|
std::vector<std::pair<std::string, Setting>> const& settings() const;
|
||||||
/**
|
/**
|
||||||
* Whether the mod can be disabled or not
|
* Whether the mod can be disabled or not
|
||||||
*/
|
*/
|
||||||
bool supportsDisabling = true;
|
bool& supportsDisabling();
|
||||||
|
bool const& supportsDisabling() const;
|
||||||
/**
|
/**
|
||||||
* Whether the mod can be unloaded or not
|
* Whether the mod can be unloaded or not
|
||||||
*/
|
*/
|
||||||
bool supportsUnloading = false;
|
bool& supportsUnloading();
|
||||||
|
bool const& supportsUnloading() const;
|
||||||
/**
|
/**
|
||||||
* Whether this mod has to be loaded before the loading screen or not
|
* Whether this mod has to be loaded before the loading screen or not
|
||||||
*/
|
*/
|
||||||
bool needsEarlyLoad = false;
|
bool& needsEarlyLoad();
|
||||||
|
bool const& needsEarlyLoad() const;
|
||||||
/**
|
/**
|
||||||
* Whether this mod is an API or not
|
* Whether this mod is an API or not
|
||||||
*/
|
*/
|
||||||
bool isAPI = false;
|
bool& isAPI();
|
||||||
|
bool const& isAPI() const;
|
||||||
/**
|
/**
|
||||||
* Create ModInfo from an unzipped .geode package
|
* Create ModInfo from an unzipped .geode package
|
||||||
*/
|
*/
|
||||||
|
@ -147,7 +179,7 @@ namespace geode {
|
||||||
static Result<ModInfo> create(ModJson const& json);
|
static Result<ModInfo> create(ModJson const& json);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert to JSON. Essentially same as getRawJSON except dynamically
|
* Convert to JSON. Essentially same as getRawJSON except dynamically
|
||||||
* adds runtime fields like path
|
* adds runtime fields like path
|
||||||
*/
|
*/
|
||||||
ModJson toJSON() const;
|
ModJson toJSON() const;
|
||||||
|
@ -161,8 +193,8 @@ namespace geode {
|
||||||
static bool validateID(std::string const& id);
|
static bool validateID(std::string const& id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<ModJson> m_rawJSON;
|
ModJson& rawJSON();
|
||||||
|
ModJson const& rawJSON() const;
|
||||||
/**
|
/**
|
||||||
* Version is passed for backwards
|
* Version is passed for backwards
|
||||||
* compatibility if we update the mod.json
|
* compatibility if we update the mod.json
|
||||||
|
|
|
@ -15,9 +15,7 @@ namespace geode {
|
||||||
class SettingNode;
|
class SettingNode;
|
||||||
class SettingValue;
|
class SettingValue;
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
struct JsonMaybeObject;
|
struct JsonMaybeObject;
|
||||||
template <class Json>
|
|
||||||
struct JsonMaybeValue;
|
struct JsonMaybeValue;
|
||||||
|
|
||||||
struct GEODE_DLL BoolSetting final {
|
struct GEODE_DLL BoolSetting final {
|
||||||
|
@ -27,7 +25,7 @@ namespace geode {
|
||||||
std::optional<std::string> description;
|
std::optional<std::string> description;
|
||||||
bool defaultValue;
|
bool defaultValue;
|
||||||
|
|
||||||
static Result<BoolSetting> parse(JsonMaybeObject<ModJson>& obj);
|
static Result<BoolSetting> parse(JsonMaybeObject& obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GEODE_DLL IntSetting final {
|
struct GEODE_DLL IntSetting final {
|
||||||
|
@ -48,7 +46,7 @@ namespace geode {
|
||||||
bool input = true;
|
bool input = true;
|
||||||
} controls;
|
} controls;
|
||||||
|
|
||||||
static Result<IntSetting> parse(JsonMaybeObject<ModJson>& obj);
|
static Result<IntSetting> parse(JsonMaybeObject& obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GEODE_DLL FloatSetting final {
|
struct GEODE_DLL FloatSetting final {
|
||||||
|
@ -69,7 +67,7 @@ namespace geode {
|
||||||
bool input = true;
|
bool input = true;
|
||||||
} controls;
|
} controls;
|
||||||
|
|
||||||
static Result<FloatSetting> parse(JsonMaybeObject<ModJson>& obj);
|
static Result<FloatSetting> parse(JsonMaybeObject& obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GEODE_DLL StringSetting final {
|
struct GEODE_DLL StringSetting final {
|
||||||
|
@ -80,7 +78,7 @@ namespace geode {
|
||||||
ValueType defaultValue;
|
ValueType defaultValue;
|
||||||
std::optional<std::string> match;
|
std::optional<std::string> match;
|
||||||
|
|
||||||
static Result<StringSetting> parse(JsonMaybeObject<ModJson>& obj);
|
static Result<StringSetting> parse(JsonMaybeObject& obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GEODE_DLL FileSetting final {
|
struct GEODE_DLL FileSetting final {
|
||||||
|
@ -94,7 +92,7 @@ namespace geode {
|
||||||
std::vector<Filter> filters;
|
std::vector<Filter> filters;
|
||||||
} controls;
|
} controls;
|
||||||
|
|
||||||
static Result<FileSetting> parse(JsonMaybeObject<ModJson>& obj);
|
static Result<FileSetting> parse(JsonMaybeObject& obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GEODE_DLL ColorSetting final {
|
struct GEODE_DLL ColorSetting final {
|
||||||
|
@ -104,7 +102,7 @@ namespace geode {
|
||||||
std::optional<std::string> description;
|
std::optional<std::string> description;
|
||||||
ValueType defaultValue;
|
ValueType defaultValue;
|
||||||
|
|
||||||
static Result<ColorSetting> parse(JsonMaybeObject<ModJson>& obj);
|
static Result<ColorSetting> parse(JsonMaybeObject& obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GEODE_DLL ColorAlphaSetting final {
|
struct GEODE_DLL ColorAlphaSetting final {
|
||||||
|
@ -114,7 +112,7 @@ namespace geode {
|
||||||
std::optional<std::string> description;
|
std::optional<std::string> description;
|
||||||
ValueType defaultValue;
|
ValueType defaultValue;
|
||||||
|
|
||||||
static Result<ColorAlphaSetting> parse(JsonMaybeObject<ModJson>& obj);
|
static Result<ColorAlphaSetting> parse(JsonMaybeObject& obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GEODE_DLL CustomSetting final {
|
struct GEODE_DLL CustomSetting final {
|
||||||
|
@ -142,7 +140,7 @@ namespace geode {
|
||||||
public:
|
public:
|
||||||
static Result<Setting> parse(
|
static Result<Setting> parse(
|
||||||
std::string const& key,
|
std::string const& key,
|
||||||
JsonMaybeValue<ModJson>& obj
|
JsonMaybeValue& obj
|
||||||
);
|
);
|
||||||
Setting(std::string const& key, SettingKind const& kind);
|
Setting(std::string const& key, SettingKind const& kind);
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace geode {
|
||||||
public:
|
public:
|
||||||
using Callback = void(SettingValue*);
|
using Callback = void(SettingValue*);
|
||||||
|
|
||||||
ListenerResult handle(std::function<Callback> fn, SettingChangedEvent* event);
|
ListenerResult handle(utils::MiniFunction<Callback> fn, SettingChangedEvent* event);
|
||||||
/**
|
/**
|
||||||
* Listen to changes on a setting, or all settings
|
* Listen to changes on a setting, or all settings
|
||||||
* @param modID Mod whose settings to listen to
|
* @param modID Mod whose settings to listen to
|
||||||
|
@ -42,7 +42,7 @@ namespace geode {
|
||||||
public:
|
public:
|
||||||
using Callback = void(T);
|
using Callback = void(T);
|
||||||
|
|
||||||
ListenerResult handle(std::function<Callback> fn, SettingChangedEvent* event) {
|
ListenerResult handle(utils::MiniFunction<Callback> fn, SettingChangedEvent* event) {
|
||||||
if (
|
if (
|
||||||
m_modID == event->mod->getID() &&
|
m_modID == event->mod->getID() &&
|
||||||
(!m_targetKey || m_targetKey.value() == event->value->getKey())
|
(!m_targetKey || m_targetKey.value() == event->value->getKey())
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "Traits.hpp"
|
#include "Traits.hpp"
|
||||||
|
|
||||||
#include <Geode/loader/Loader.hpp>
|
#include <Geode/loader/Loader.hpp>
|
||||||
|
#include "../utils/MiniFunction.hpp"
|
||||||
#include <cocos2d.h>
|
#include <cocos2d.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -19,7 +20,7 @@ namespace geode::modifier {
|
||||||
class FieldContainer {
|
class FieldContainer {
|
||||||
private:
|
private:
|
||||||
std::vector<void*> m_containedFields;
|
std::vector<void*> m_containedFields;
|
||||||
std::vector<std::function<void(void*)>> m_destructorFunctions;
|
std::vector<utils::MiniFunction<void(void*)>> m_destructorFunctions;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~FieldContainer() {
|
~FieldContainer() {
|
||||||
|
@ -37,7 +38,7 @@ namespace geode::modifier {
|
||||||
return m_containedFields.at(index);
|
return m_containedFields.at(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* setField(size_t index, size_t size, std::function<void(void*)> destructor) {
|
void* setField(size_t index, size_t size, utils::MiniFunction<void(void*)> destructor) {
|
||||||
m_containedFields.at(index) = operator new(size);
|
m_containedFields.at(index) = operator new(size);
|
||||||
m_destructorFunctions.at(index) = destructor;
|
m_destructorFunctions.at(index) = destructor;
|
||||||
return m_containedFields.at(index);
|
return m_containedFields.at(index);
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main class implementation, it has the structure
|
|
||||||
*
|
|
||||||
* class hook0Dummy;
|
|
||||||
* template<typename>
|
|
||||||
* struct hook0 {};
|
|
||||||
* namespace {
|
|
||||||
* struct hook0Parent {};
|
|
||||||
* }
|
|
||||||
* template<>
|
|
||||||
* struct GEODE_HIDDEN hook0<hook0Parent> : Modify<hook0<hook0Parent>, MenuLayer> {
|
|
||||||
* // code stuff idk
|
|
||||||
* };
|
|
||||||
*
|
|
||||||
* I tried to make the macro as verbose as it can be but
|
|
||||||
* I am bad at this stuff
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define GEODE_MODIFY_DECLARE_ANONYMOUS(base, derived) \
|
|
||||||
derived##Dummy; \
|
|
||||||
template <class> \
|
|
||||||
struct derived {}; \
|
|
||||||
namespace { \
|
|
||||||
struct derived##Parent {}; \
|
|
||||||
} \
|
|
||||||
template <> \
|
|
||||||
struct GEODE_HIDDEN derived<derived##Parent> : geode::Modify<derived<derived##Parent>, base>
|
|
||||||
|
|
||||||
#define GEODE_MODIFY_DECLARE(base, derived) \
|
|
||||||
derived##Dummy; \
|
|
||||||
struct GEODE_HIDDEN derived : geode::Modify<derived, base>
|
|
||||||
|
|
||||||
#define GEODE_MODIFY_REDIRECT4(base, derived) GEODE_MODIFY_DECLARE(base, derived)
|
|
||||||
#define GEODE_MODIFY_REDIRECT3(base, derived) GEODE_MODIFY_DECLARE_ANONYMOUS(base, derived)
|
|
||||||
#define GEODE_MODIFY_REDIRECT2(base) GEODE_MODIFY_REDIRECT3(base, GEODE_CONCAT(hook, __LINE__))
|
|
||||||
#define GEODE_MODIFY_REDIRECT1(base) GEODE_MODIFY_REDIRECT2(base)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interfaces for the class implementation
|
|
||||||
*
|
|
||||||
* class $modify(MenuLayer) {};
|
|
||||||
* class $modify(MyMenuLayerInterface, MenuLayer) {};
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define GEODE_CRTP1(base) GEODE_MODIFY_REDIRECT1(base)
|
|
||||||
#define GEODE_CRTP2(derived, base) GEODE_MODIFY_REDIRECT4(base, derived)
|
|
||||||
#define $modify(...) \
|
|
||||||
GEODE_INVOKE(GEODE_CONCAT(GEODE_CRTP, GEODE_NUMBER_OF_ARGS(__VA_ARGS__)), __VA_ARGS__)
|
|
||||||
#define $(...) $modify(__VA_ARGS__)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get current hook class without needing to name it.
|
|
||||||
* Useful for callbacks
|
|
||||||
*/
|
|
||||||
#define $cls std::remove_pointer<decltype(this)>::type
|
|
|
@ -141,3 +141,60 @@ namespace geode {
|
||||||
static void onModify(auto& self) {}
|
static void onModify(auto& self) {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main class implementation, it has the structure
|
||||||
|
*
|
||||||
|
* class hook0Dummy;
|
||||||
|
* template<typename>
|
||||||
|
* struct hook0 {};
|
||||||
|
* namespace {
|
||||||
|
* struct hook0Parent {};
|
||||||
|
* }
|
||||||
|
* template<>
|
||||||
|
* struct GEODE_HIDDEN hook0<hook0Parent> : Modify<hook0<hook0Parent>, MenuLayer> {
|
||||||
|
* // code stuff idk
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* I tried to make the macro as verbose as it can be but
|
||||||
|
* I am bad at this stuff
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define GEODE_MODIFY_DECLARE_ANONYMOUS(base, derived) \
|
||||||
|
derived##Dummy; \
|
||||||
|
template <class> \
|
||||||
|
struct derived {}; \
|
||||||
|
namespace { \
|
||||||
|
struct derived##Parent {}; \
|
||||||
|
} \
|
||||||
|
template <> \
|
||||||
|
struct GEODE_HIDDEN derived<derived##Parent> : geode::Modify<derived<derived##Parent>, base>
|
||||||
|
|
||||||
|
#define GEODE_MODIFY_DECLARE(base, derived) \
|
||||||
|
derived##Dummy; \
|
||||||
|
struct GEODE_HIDDEN derived : geode::Modify<derived, base>
|
||||||
|
|
||||||
|
#define GEODE_MODIFY_REDIRECT4(base, derived) GEODE_MODIFY_DECLARE(base, derived)
|
||||||
|
#define GEODE_MODIFY_REDIRECT3(base, derived) GEODE_MODIFY_DECLARE_ANONYMOUS(base, derived)
|
||||||
|
#define GEODE_MODIFY_REDIRECT2(base) GEODE_MODIFY_REDIRECT3(base, GEODE_CONCAT(hook, __LINE__))
|
||||||
|
#define GEODE_MODIFY_REDIRECT1(base) GEODE_MODIFY_REDIRECT2(base)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interfaces for the class implementation
|
||||||
|
*
|
||||||
|
* class $modify(MenuLayer) {};
|
||||||
|
* class $modify(MyMenuLayerInterface, MenuLayer) {};
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define GEODE_CRTP1(base) GEODE_MODIFY_REDIRECT1(base)
|
||||||
|
#define GEODE_CRTP2(derived, base) GEODE_MODIFY_REDIRECT4(base, derived)
|
||||||
|
#define $modify(...) \
|
||||||
|
GEODE_INVOKE(GEODE_CONCAT(GEODE_CRTP, GEODE_NUMBER_OF_ARGS(__VA_ARGS__)), __VA_ARGS__)
|
||||||
|
#define $(...) $modify(__VA_ARGS__)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current hook class without needing to name it.
|
||||||
|
* Useful for callbacks
|
||||||
|
* this is a camila moment if you ask me
|
||||||
|
*/
|
||||||
|
#define $cls std::remove_pointer<decltype(this)>::type
|
||||||
|
|
|
@ -29,7 +29,7 @@ namespace geode {
|
||||||
std::optional<std::string> m_targetID;
|
std::optional<std::string> m_targetID;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ListenerResult handle(std::function<Callback> fn, AEnterLayerEvent* event);
|
ListenerResult handle(utils::MiniFunction<Callback> fn, AEnterLayerEvent* event);
|
||||||
|
|
||||||
AEnterLayerFilter(
|
AEnterLayerFilter(
|
||||||
std::optional<std::string> const& id
|
std::optional<std::string> const& id
|
||||||
|
@ -61,7 +61,7 @@ namespace geode {
|
||||||
std::optional<std::string> m_targetID;
|
std::optional<std::string> m_targetID;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ListenerResult handle(std::function<Callback> fn, EnterLayerEvent<N>* event) {
|
ListenerResult handle(utils::MiniFunction<Callback> fn, EnterLayerEvent<N>* event) {
|
||||||
if (m_targetID == event->getID()) {
|
if (m_targetID == event->getID()) {
|
||||||
fn(static_cast<T*>(event));
|
fn(static_cast<T*>(event));
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,13 +11,13 @@ namespace geode {
|
||||||
class MDPopup :
|
class MDPopup :
|
||||||
public Popup<
|
public Popup<
|
||||||
std::string const&, std::string const&, char const*, char const*,
|
std::string const&, std::string const&, char const*, char const*,
|
||||||
std::function<void(bool)>> {
|
utils::MiniFunction<void(bool)>> {
|
||||||
protected:
|
protected:
|
||||||
std::function<void(bool)> m_onClick = nullptr;
|
utils::MiniFunction<void(bool)> m_onClick = nullptr;
|
||||||
|
|
||||||
bool setup(
|
bool setup(
|
||||||
std::string const& title, std::string const& info, char const* btn1, char const* btn2,
|
std::string const& title, std::string const& info, char const* btn1, char const* btn2,
|
||||||
std::function<void(bool)> onClick
|
utils::MiniFunction<void(bool)> onClick
|
||||||
) override;
|
) override;
|
||||||
|
|
||||||
void onBtn(CCObject*);
|
void onBtn(CCObject*);
|
||||||
|
@ -27,7 +27,7 @@ namespace geode {
|
||||||
public:
|
public:
|
||||||
static MDPopup* create(
|
static MDPopup* create(
|
||||||
std::string const& title, std::string const& content, char const* btn1,
|
std::string const& title, std::string const& content, char const* btn1,
|
||||||
char const* btn2 = nullptr, std::function<void(bool)> onClick = nullptr
|
char const* btn2 = nullptr, utils::MiniFunction<void(bool)> onClick = nullptr
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,13 +14,13 @@ namespace geode {
|
||||||
protected:
|
protected:
|
||||||
std::vector<T> m_list;
|
std::vector<T> m_list;
|
||||||
size_t m_index = 0;
|
size_t m_index = 0;
|
||||||
std::function<void(T const&, size_t)> m_onChange;
|
utils::MiniFunction<void(T const&, size_t)> m_onChange;
|
||||||
cocos2d::CCLabelBMFont* m_label;
|
cocos2d::CCLabelBMFont* m_label;
|
||||||
CCMenuItemSpriteExtra* m_prevBtn;
|
CCMenuItemSpriteExtra* m_prevBtn;
|
||||||
CCMenuItemSpriteExtra* m_nextBtn;
|
CCMenuItemSpriteExtra* m_nextBtn;
|
||||||
|
|
||||||
bool init(
|
bool init(
|
||||||
float width, std::vector<T> const& list, std::function<void(T const&, size_t)> onChange
|
float width, std::vector<T> const& list, utils::MiniFunction<void(T const&, size_t)> onChange
|
||||||
) {
|
) {
|
||||||
if (!cocos2d::CCMenu::init()) return false;
|
if (!cocos2d::CCMenu::init()) return false;
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ namespace geode {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static SelectList* create(
|
static SelectList* create(
|
||||||
float width, std::vector<T> const& list, std::function<void(T const&, size_t)> onChange
|
float width, std::vector<T> const& list, utils::MiniFunction<void(T const&, size_t)> onChange
|
||||||
) {
|
) {
|
||||||
auto ret = new SelectList();
|
auto ret = new SelectList();
|
||||||
if (ret && ret->init(width, list, onChange)) {
|
if (ret && ret->init(width, list, onChange)) {
|
||||||
|
|
|
@ -122,7 +122,7 @@ namespace geode {
|
||||||
* to distinguish between bold, italic and
|
* to distinguish between bold, italic and
|
||||||
* regular text.
|
* regular text.
|
||||||
*/
|
*/
|
||||||
using Font = std::function<Label(int)>;
|
using Font = utils::MiniFunction<Label(int)>;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
cocos2d::CCPoint m_origin = cocos2d::CCPointZero;
|
cocos2d::CCPoint m_origin = cocos2d::CCPointZero;
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
namespace geode {
|
namespace geode {
|
||||||
template <class Json>
|
|
||||||
struct JsonChecker;
|
struct JsonChecker;
|
||||||
|
|
||||||
template <typename T, typename = void>
|
template <typename T, typename = void>
|
||||||
|
@ -73,31 +72,28 @@ namespace geode {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
using JsonValueValidator = std::function<bool(T const&)>;
|
using JsonValueValidator = utils::MiniFunction<bool(T const&)>;
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
struct JsonMaybeObject;
|
struct JsonMaybeObject;
|
||||||
template <class Json>
|
|
||||||
struct JsonMaybeValue;
|
struct JsonMaybeValue;
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
struct JsonMaybeSomething {
|
struct JsonMaybeSomething {
|
||||||
protected:
|
protected:
|
||||||
JsonChecker<Json>& m_checker;
|
JsonChecker& m_checker;
|
||||||
Json& m_json;
|
json::Value& m_json;
|
||||||
std::string m_hierarchy;
|
std::string m_hierarchy;
|
||||||
bool m_hasValue;
|
bool m_hasValue;
|
||||||
|
|
||||||
friend struct JsonMaybeObject<Json>;
|
friend struct JsonMaybeObject;
|
||||||
friend struct JsonMaybeValue<Json>;
|
friend struct JsonMaybeValue;
|
||||||
|
|
||||||
GEODE_DLL void setError(std::string const& error);
|
GEODE_DLL void setError(std::string const& error);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GEODE_DLL Json& json();
|
GEODE_DLL json::Value& json();
|
||||||
|
|
||||||
GEODE_DLL JsonMaybeSomething(
|
GEODE_DLL JsonMaybeSomething(
|
||||||
JsonChecker<Json>& checker, Json& json, std::string const& hierarchy, bool hasValue
|
JsonChecker& checker, json::Value& json, std::string const& hierarchy, bool hasValue
|
||||||
);
|
);
|
||||||
|
|
||||||
GEODE_DLL bool isError() const;
|
GEODE_DLL bool isError() const;
|
||||||
|
@ -106,18 +102,17 @@ namespace geode {
|
||||||
GEODE_DLL operator bool() const;
|
GEODE_DLL operator bool() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class Json>
|
struct JsonMaybeValue : public JsonMaybeSomething {
|
||||||
struct JsonMaybeValue : public JsonMaybeSomething<Json> {
|
|
||||||
bool m_inferType = true;
|
bool m_inferType = true;
|
||||||
|
|
||||||
GEODE_DLL JsonMaybeValue(
|
GEODE_DLL JsonMaybeValue(
|
||||||
JsonChecker<Json>& checker, Json& json, std::string const& hierarchy, bool hasValue
|
JsonChecker& checker, json::Value& json, std::string const& hierarchy, bool hasValue
|
||||||
);
|
);
|
||||||
|
|
||||||
GEODE_DLL JsonMaybeSomething<Json>& self();
|
GEODE_DLL JsonMaybeSomething& self();
|
||||||
|
|
||||||
template <json::Type T>
|
template <json::Type T>
|
||||||
JsonMaybeValue<Json>& as() {
|
JsonMaybeValue& as() {
|
||||||
if (this->isError()) return *this;
|
if (this->isError()) return *this;
|
||||||
if (!jsonConvertibleTo(self().m_json.type(), T)) {
|
if (!jsonConvertibleTo(self().m_json.type(), T)) {
|
||||||
this->setError(
|
this->setError(
|
||||||
|
@ -129,10 +124,10 @@ namespace geode {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
GEODE_DLL JsonMaybeValue<Json>& array();
|
GEODE_DLL JsonMaybeValue& array();
|
||||||
|
|
||||||
template <json::Type... T>
|
template <json::Type... T>
|
||||||
JsonMaybeValue<Json>& asOneOf() {
|
JsonMaybeValue& asOneOf() {
|
||||||
if (this->isError()) return *this;
|
if (this->isError()) return *this;
|
||||||
bool isOneOf = (... || jsonConvertibleTo(self().m_json.type(), T));
|
bool isOneOf = (... || jsonConvertibleTo(self().m_json.type(), T));
|
||||||
if (!isOneOf) {
|
if (!isOneOf) {
|
||||||
|
@ -146,7 +141,7 @@ namespace geode {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <json::Type T>
|
template <json::Type T>
|
||||||
JsonMaybeValue<Json>& is() {
|
JsonMaybeValue& is() {
|
||||||
if (this->isError()) return *this;
|
if (this->isError()) return *this;
|
||||||
self().m_hasValue = jsonConvertibleTo(self().m_json.type(), T);
|
self().m_hasValue = jsonConvertibleTo(self().m_json.type(), T);
|
||||||
m_inferType = false;
|
m_inferType = false;
|
||||||
|
@ -154,7 +149,7 @@ namespace geode {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
JsonMaybeValue<Json>& validate(JsonValueValidator<T> validator) {
|
JsonMaybeValue& validate(JsonValueValidator<T> validator) {
|
||||||
if (this->isError()) return *this;
|
if (this->isError()) return *this;
|
||||||
try {
|
try {
|
||||||
if (!validator(self().m_json.template as<T>())) {
|
if (!validator(self().m_json.template as<T>())) {
|
||||||
|
@ -171,35 +166,30 @@ namespace geode {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
JsonMaybeValue<Json>& validate(bool (*validator)(T const&)) {
|
JsonMaybeValue& inferType() {
|
||||||
return this->validate(std::function(validator));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
JsonMaybeValue<Json>& inferType() {
|
|
||||||
if (this->isError() || !m_inferType) return *this;
|
if (this->isError() || !m_inferType) return *this;
|
||||||
return this->as<getJsonType<T>()>();
|
return this->as<getJsonType<T>()>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
JsonMaybeValue<Json>& intoRaw(T& target) {
|
JsonMaybeValue& intoRaw(T& target) {
|
||||||
if (this->isError()) return *this;
|
if (this->isError()) return *this;
|
||||||
target = self().m_json;
|
target = self().m_json;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
JsonMaybeValue<Json>& into(T& target) {
|
JsonMaybeValue& into(T& target) {
|
||||||
return this->intoAs<T, T>(target);
|
return this->intoAs<T, T>(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
JsonMaybeValue<Json>& into(std::optional<T>& target) {
|
JsonMaybeValue& into(std::optional<T>& target) {
|
||||||
return this->intoAs<T, std::optional<T>>(target);
|
return this->intoAs<T, std::optional<T>>(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class A, class T>
|
template <class A, class T>
|
||||||
JsonMaybeValue<Json>& intoAs(T& target) {
|
JsonMaybeValue& intoAs(T& target) {
|
||||||
this->inferType<A>();
|
this->inferType<A>();
|
||||||
if (this->isError()) return *this;
|
if (this->isError()) return *this;
|
||||||
|
|
||||||
|
@ -241,7 +231,7 @@ namespace geode {
|
||||||
return T();
|
return T();
|
||||||
}
|
}
|
||||||
|
|
||||||
GEODE_DLL JsonMaybeObject<Json> obj();
|
GEODE_DLL JsonMaybeObject obj();
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
struct Iterator {
|
struct Iterator {
|
||||||
|
@ -267,48 +257,46 @@ namespace geode {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
GEODE_DLL JsonMaybeValue<Json> at(size_t i);
|
GEODE_DLL JsonMaybeValue at(size_t i);
|
||||||
|
|
||||||
GEODE_DLL Iterator<JsonMaybeValue<Json>> iterate();
|
GEODE_DLL Iterator<JsonMaybeValue> iterate();
|
||||||
|
|
||||||
GEODE_DLL Iterator<std::pair<std::string, JsonMaybeValue<Json>>> items();
|
GEODE_DLL Iterator<std::pair<std::string, JsonMaybeValue>> items();
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class Json>
|
struct JsonMaybeObject : JsonMaybeSomething {
|
||||||
struct JsonMaybeObject : JsonMaybeSomething<Json> {
|
|
||||||
std::set<std::string> m_knownKeys;
|
std::set<std::string> m_knownKeys;
|
||||||
|
|
||||||
GEODE_DLL JsonMaybeObject(
|
GEODE_DLL JsonMaybeObject(
|
||||||
JsonChecker<Json>& checker, Json& json, std::string const& hierarchy, bool hasValue
|
JsonChecker& checker, json::Value& json, std::string const& hierarchy, bool hasValue
|
||||||
);
|
);
|
||||||
|
|
||||||
GEODE_DLL JsonMaybeSomething<Json>& self();
|
GEODE_DLL JsonMaybeSomething& self();
|
||||||
|
|
||||||
GEODE_DLL void addKnownKey(std::string const& key);
|
GEODE_DLL void addKnownKey(std::string const& key);
|
||||||
|
|
||||||
GEODE_DLL Json& json();
|
GEODE_DLL json::Value& json();
|
||||||
|
|
||||||
GEODE_DLL JsonMaybeValue<Json> emptyValue();
|
GEODE_DLL JsonMaybeValue emptyValue();
|
||||||
|
|
||||||
GEODE_DLL JsonMaybeValue<Json> has(std::string const& key);
|
GEODE_DLL JsonMaybeValue has(std::string const& key);
|
||||||
|
|
||||||
GEODE_DLL JsonMaybeValue<Json> needs(std::string const& key);
|
GEODE_DLL JsonMaybeValue needs(std::string const& key);
|
||||||
|
|
||||||
GEODE_DLL void checkUnknownKeys();
|
GEODE_DLL void checkUnknownKeys();
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class Json = json::Value>
|
|
||||||
struct JsonChecker {
|
struct JsonChecker {
|
||||||
std::variant<std::monostate, std::string> m_result;
|
std::variant<std::monostate, std::string> m_result;
|
||||||
Json& m_json;
|
json::Value& m_json;
|
||||||
|
|
||||||
GEODE_DLL JsonChecker(Json& json);
|
GEODE_DLL JsonChecker(json::Value& json);
|
||||||
|
|
||||||
GEODE_DLL bool isError() const;
|
GEODE_DLL bool isError() const;
|
||||||
|
|
||||||
GEODE_DLL std::string getError() const;
|
GEODE_DLL std::string getError() const;
|
||||||
|
|
||||||
GEODE_DLL JsonMaybeValue<Json> root(std::string const& hierarchy);
|
GEODE_DLL JsonMaybeValue root(std::string const& hierarchy);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace geode::utils {
|
||||||
public:
|
public:
|
||||||
Type m_func;
|
Type m_func;
|
||||||
|
|
||||||
explicit MiniFunctionState(Type func) : m_func(std::move(func)) {}
|
explicit MiniFunctionState(Type func) : m_func(func) {}
|
||||||
|
|
||||||
Ret call(Args... args) const override {
|
Ret call(Args... args) const override {
|
||||||
return const_cast<Type&>(m_func)(args...);
|
return const_cast<Type&>(m_func)(args...);
|
||||||
|
@ -31,6 +31,38 @@ namespace geode::utils {
|
||||||
return new MiniFunctionState(*this);
|
return new MiniFunctionState(*this);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <class Type, class Ret, class... Args>
|
||||||
|
class MiniFunctionStatePointer final : public MiniFunctionStateBase<Ret, Args...> {
|
||||||
|
public:
|
||||||
|
Type m_func;
|
||||||
|
|
||||||
|
explicit MiniFunctionStatePointer(Type func) : m_func(func) {}
|
||||||
|
|
||||||
|
Ret call(Args... args) const override {
|
||||||
|
return const_cast<Type&>(*m_func)(args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
MiniFunctionStateBase<Ret, Args...>* clone() const override {
|
||||||
|
return new MiniFunctionStatePointer(*this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Type, class Ret, class Class, class... Args>
|
||||||
|
class MiniFunctionStateMemberPointer final : public MiniFunctionStateBase<Ret, Class, Args...> {
|
||||||
|
public:
|
||||||
|
Type m_func;
|
||||||
|
|
||||||
|
explicit MiniFunctionStateMemberPointer(Type func) : m_func(func) {}
|
||||||
|
|
||||||
|
Ret call(Class self, Args... args) const override {
|
||||||
|
return const_cast<Type&>(self->*m_func)(args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
MiniFunctionStateBase<Ret, Class, Args...>* clone() const override {
|
||||||
|
return new MiniFunctionStateMemberPointer(*this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <class Callable, class Ret, class... Args>
|
template <class Callable, class Ret, class... Args>
|
||||||
concept MiniFunctionCallable = requires(Callable&& func, Args... args) {
|
concept MiniFunctionCallable = requires(Callable&& func, Args... args) {
|
||||||
|
@ -49,6 +81,8 @@ namespace geode::utils {
|
||||||
public:
|
public:
|
||||||
MiniFunction() : m_state(nullptr) {}
|
MiniFunction() : m_state(nullptr) {}
|
||||||
|
|
||||||
|
MiniFunction(std::nullptr_t) : MiniFunction() {}
|
||||||
|
|
||||||
MiniFunction(MiniFunction const& other) :
|
MiniFunction(MiniFunction const& other) :
|
||||||
m_state(other.m_state ? other.m_state->clone() : nullptr) {}
|
m_state(other.m_state ? other.m_state->clone() : nullptr) {}
|
||||||
|
|
||||||
|
@ -65,6 +99,16 @@ namespace geode::utils {
|
||||||
MiniFunction(Callable&& func) :
|
MiniFunction(Callable&& func) :
|
||||||
m_state(new MiniFunctionState<std::decay_t<Callable>, Ret, Args...>(std::forward<Callable>(func))) {}
|
m_state(new MiniFunctionState<std::decay_t<Callable>, Ret, Args...>(std::forward<Callable>(func))) {}
|
||||||
|
|
||||||
|
template <class FunctionPointer>
|
||||||
|
requires(!MiniFunctionCallable<FunctionPointer, Ret, Args...> && std::is_pointer_v<FunctionPointer> && std::is_function_v<std::remove_pointer_t<FunctionPointer>>)
|
||||||
|
MiniFunction(FunctionPointer func) :
|
||||||
|
m_state(new MiniFunctionStatePointer<FunctionPointer, Ret, Args...>(func)) {}
|
||||||
|
|
||||||
|
template <class MemberFunctionPointer>
|
||||||
|
requires(std::is_member_function_pointer_v<MemberFunctionPointer>)
|
||||||
|
MiniFunction(MemberFunctionPointer func) :
|
||||||
|
m_state(new MiniFunctionStateMemberPointer<MemberFunctionPointer, Ret, Args...>(func)) {}
|
||||||
|
|
||||||
MiniFunction& operator=(MiniFunction const& other) {
|
MiniFunction& operator=(MiniFunction const& other) {
|
||||||
delete m_state;
|
delete m_state;
|
||||||
m_state = other.m_state ? other.m_state->clone() : nullptr;
|
m_state = other.m_state ? other.m_state->clone() : nullptr;
|
||||||
|
@ -79,6 +123,7 @@ namespace geode::utils {
|
||||||
}
|
}
|
||||||
|
|
||||||
Ret operator()(Args... args) const {
|
Ret operator()(Args... args) const {
|
||||||
|
if (!m_state) return Ret();
|
||||||
return m_state->call(args...);
|
return m_state->call(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include "../loader/Event.hpp"
|
#include "../loader/Event.hpp"
|
||||||
|
#include "MiniFunction.hpp"
|
||||||
|
|
||||||
// support converting ccColor3B / ccColor4B to / from json
|
// support converting ccColor3B / ccColor4B to / from json
|
||||||
|
|
||||||
|
@ -468,7 +469,7 @@ namespace geode::cocos {
|
||||||
*/
|
*/
|
||||||
GEODE_DLL cocos2d::CCScene* switchToScene(cocos2d::CCLayer* layer);
|
GEODE_DLL cocos2d::CCScene* switchToScene(cocos2d::CCLayer* layer);
|
||||||
|
|
||||||
using CreateLayerFunc = std::function<cocos2d::CCLayer*()>;
|
using CreateLayerFunc = utils::MiniFunction<cocos2d::CCLayer*()>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reload textures, overwriting the scene to return to after the loading
|
* Reload textures, overwriting the scene to return to after the loading
|
||||||
|
@ -518,7 +519,7 @@ namespace geode::cocos {
|
||||||
* there is none
|
* there is none
|
||||||
*/
|
*/
|
||||||
template <class Type = cocos2d::CCNode>
|
template <class Type = cocos2d::CCNode>
|
||||||
Type* findFirstChildRecursive(cocos2d::CCNode* node, std::function<bool(Type*)> predicate) {
|
Type* findFirstChildRecursive(cocos2d::CCNode* node, utils::MiniFunction<bool(Type*)> predicate) {
|
||||||
if (cast::safe_cast<Type*>(node) && predicate(static_cast<Type*>(node)))
|
if (cast::safe_cast<Type*>(node) && predicate(static_cast<Type*>(node)))
|
||||||
return static_cast<Type*>(node);
|
return static_cast<Type*>(node);
|
||||||
|
|
||||||
|
@ -707,7 +708,7 @@ namespace geode::cocos {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename C, typename = std::enable_if_t<std::is_pointer_v<C>>>
|
template <typename T, typename C, typename = std::enable_if_t<std::is_pointer_v<C>>>
|
||||||
static cocos2d::CCArray* vectorToCCArray(std::vector<T> const& vec, std::function<C(T)> convFunc) {
|
static cocos2d::CCArray* vectorToCCArray(std::vector<T> const& vec, utils::MiniFunction<C(T)> convFunc) {
|
||||||
auto res = cocos2d::CCArray::createWithCapacity(vec.size());
|
auto res = cocos2d::CCArray::createWithCapacity(vec.size());
|
||||||
for (auto const& item : vec)
|
for (auto const& item : vec)
|
||||||
res->addObject(convFunc(item));
|
res->addObject(convFunc(item));
|
||||||
|
@ -734,7 +735,7 @@ namespace geode::cocos {
|
||||||
template <
|
template <
|
||||||
typename K, typename V, typename C,
|
typename K, typename V, typename C,
|
||||||
typename = std::enable_if_t<std::is_same_v<C, std::string> || std::is_same_v<C, intptr_t>>>
|
typename = std::enable_if_t<std::is_same_v<C, std::string> || std::is_same_v<C, intptr_t>>>
|
||||||
static cocos2d::CCDictionary* mapToCCDict(std::map<K, V> const& map, std::function<C(K)> convFunc) {
|
static cocos2d::CCDictionary* mapToCCDict(std::map<K, V> const& map, utils::MiniFunction<C(K)> convFunc) {
|
||||||
auto res = cocos2d::CCDictionary::create();
|
auto res = cocos2d::CCDictionary::create();
|
||||||
for (auto const& [key, value] : map)
|
for (auto const& [key, value] : map)
|
||||||
res->setObject(value, convFunc(key));
|
res->setObject(value, convFunc(key));
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#include <json.hpp>
|
#include <json.hpp>
|
||||||
#include <Geode/DefaultInclude.hpp>
|
#include <Geode/DefaultInclude.hpp>
|
||||||
#include <ghc/filesystem.hpp>
|
#include <ghc/fs_fwd.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <ghc/filesystem.hpp>
|
#include <ghc/fs_fwd.hpp>
|
||||||
|
|
||||||
// for some reason std::filesystem::path doesn't have std::hash defined in C++17
|
// for some reason std::filesystem::path doesn't have std::hash defined in C++17
|
||||||
// and ghc seems to have inherited this limitation
|
// and ghc seems to have inherited this limitation
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace geode::utils::map {
|
||||||
* false if not.
|
* false if not.
|
||||||
*/
|
*/
|
||||||
template <typename T, typename R>
|
template <typename T, typename R>
|
||||||
bool contains(std::unordered_map<T, R> const& map, std::function<bool(R)> containFunc) {
|
bool contains(std::unordered_map<T, R> const& map, utils::MiniFunction<bool(R)> containFunc) {
|
||||||
for (auto const& [_, r] : map) {
|
for (auto const& [_, r] : map) {
|
||||||
if (containFunc(r)) return true;
|
if (containFunc(r)) return true;
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ namespace geode::utils::map {
|
||||||
* a pointer.
|
* a pointer.
|
||||||
*/
|
*/
|
||||||
template <class T, class R>
|
template <class T, class R>
|
||||||
R select(std::unordered_map<T, R> const& map, std::function<bool(R)> selectFunc) {
|
R select(std::unordered_map<T, R> const& map, utils::MiniFunction<bool(R)> selectFunc) {
|
||||||
for (auto const& [_, r] : map) {
|
for (auto const& [_, r] : map) {
|
||||||
if (selectFunc(r)) return r;
|
if (selectFunc(r)) return r;
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ namespace geode::utils::map {
|
||||||
*/
|
*/
|
||||||
template <class T, class R>
|
template <class T, class R>
|
||||||
std::vector<R> selectAll(
|
std::vector<R> selectAll(
|
||||||
std::unordered_map<T, R> const& map, std::function<bool(R)> selectFunc
|
std::unordered_map<T, R> const& map, utils::MiniFunction<bool(R)> selectFunc
|
||||||
) {
|
) {
|
||||||
std::vector<R> res;
|
std::vector<R> res;
|
||||||
for (auto const& [_, r] : map) {
|
for (auto const& [_, r] : map) {
|
||||||
|
@ -111,7 +111,7 @@ namespace geode::utils::map {
|
||||||
template <class T1, class V1, class T2, class V2>
|
template <class T1, class V1, class T2, class V2>
|
||||||
std::unordered_map<T2, V2> remap(
|
std::unordered_map<T2, V2> remap(
|
||||||
std::unordered_map<T1, V1> const& map,
|
std::unordered_map<T1, V1> const& map,
|
||||||
std::function<std::pair<T2, V2>(std::pair<T1, V1>)> remapFunc
|
utils::MiniFunction<std::pair<T2, V2>(std::pair<T1, V1>)> remapFunc
|
||||||
) {
|
) {
|
||||||
std::unordered_map<T2, V2> res;
|
std::unordered_map<T2, V2> res;
|
||||||
for (auto const& [t, v] : map) {
|
for (auto const& [t, v] : map) {
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../DefaultInclude.hpp"
|
#include "../DefaultInclude.hpp"
|
||||||
|
#include "MiniFunction.hpp"
|
||||||
#include <json.hpp>
|
#include <json.hpp>
|
||||||
#include "Result.hpp"
|
#include "Result.hpp"
|
||||||
#include "general.hpp"
|
#include "general.hpp"
|
||||||
|
|
||||||
#include <ghc/filesystem.hpp>
|
#include <ghc/fs_fwd.hpp>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
namespace geode::utils::web {
|
namespace geode::utils::web {
|
||||||
GEODE_DLL void openLinkInBrowser(std::string const& url);
|
GEODE_DLL void openLinkInBrowser(std::string const& url);
|
||||||
|
|
||||||
using FileProgressCallback = std::function<bool(double, double)>;
|
using FileProgressCallback = utils::MiniFunction<bool(double, double)>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Synchronously fetch data from the internet
|
* Synchronously fetch data from the internet
|
||||||
|
@ -54,11 +55,11 @@ namespace geode::utils::web {
|
||||||
class AsyncWebResponse;
|
class AsyncWebResponse;
|
||||||
class AsyncWebRequest;
|
class AsyncWebRequest;
|
||||||
|
|
||||||
using AsyncProgress = std::function<void(SentAsyncWebRequest&, double, double)>;
|
using AsyncProgress = utils::MiniFunction<void(SentAsyncWebRequest&, double, double)>;
|
||||||
using AsyncExpect = std::function<void(std::string const&)>;
|
using AsyncExpect = utils::MiniFunction<void(std::string const&)>;
|
||||||
using AsyncExpectCode = std::function<void(std::string const&, int)>;
|
using AsyncExpectCode = utils::MiniFunction<void(std::string const&, int)>;
|
||||||
using AsyncThen = std::function<void(SentAsyncWebRequest&, ByteVector const&)>;
|
using AsyncThen = utils::MiniFunction<void(SentAsyncWebRequest&, ByteVector const&)>;
|
||||||
using AsyncCancelled = std::function<void(SentAsyncWebRequest&)>;
|
using AsyncCancelled = utils::MiniFunction<void(SentAsyncWebRequest&)>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A handle to an in-progress sent asynchronous web request. Use this to
|
* A handle to an in-progress sent asynchronous web request. Use this to
|
||||||
|
@ -217,7 +218,7 @@ namespace geode::utils::web {
|
||||||
* @returns The original AsyncWebRequest, where you can specify more
|
* @returns The original AsyncWebRequest, where you can specify more
|
||||||
* aspects about the request like failure and progress callbacks
|
* aspects about the request like failure and progress callbacks
|
||||||
*/
|
*/
|
||||||
AsyncWebRequest& then(std::function<void(T)> handle);
|
AsyncWebRequest& then(utils::MiniFunction<void(T)> handle);
|
||||||
/**
|
/**
|
||||||
* Specify a callback to run after a download is finished. Runs in the
|
* Specify a callback to run after a download is finished. Runs in the
|
||||||
* GD thread, so interacting with UI is safe
|
* GD thread, so interacting with UI is safe
|
||||||
|
@ -225,7 +226,7 @@ namespace geode::utils::web {
|
||||||
* @returns The original AsyncWebRequest, where you can specify more
|
* @returns The original AsyncWebRequest, where you can specify more
|
||||||
* aspects about the request like failure and progress callbacks
|
* aspects about the request like failure and progress callbacks
|
||||||
*/
|
*/
|
||||||
AsyncWebRequest& then(std::function<void(SentAsyncWebRequest&, T)> handle);
|
AsyncWebRequest& then(utils::MiniFunction<void(SentAsyncWebRequest&, T)> handle);
|
||||||
};
|
};
|
||||||
|
|
||||||
class GEODE_DLL AsyncWebResponse {
|
class GEODE_DLL AsyncWebResponse {
|
||||||
|
@ -294,7 +295,7 @@ namespace geode::utils::web {
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
AsyncWebRequest& AsyncWebResult<T>::then(std::function<void(T)> handle) {
|
AsyncWebRequest& AsyncWebResult<T>::then(utils::MiniFunction<void(T)> handle) {
|
||||||
m_request.m_then = [converter = m_converter,
|
m_request.m_then = [converter = m_converter,
|
||||||
handle](SentAsyncWebRequest& req, ByteVector const& arr) {
|
handle](SentAsyncWebRequest& req, ByteVector const& arr) {
|
||||||
auto conv = converter(arr);
|
auto conv = converter(arr);
|
||||||
|
@ -309,7 +310,7 @@ namespace geode::utils::web {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
AsyncWebRequest& AsyncWebResult<T>::then(std::function<void(SentAsyncWebRequest&, T)> handle) {
|
AsyncWebRequest& AsyncWebResult<T>::then(utils::MiniFunction<void(SentAsyncWebRequest&, T)> handle) {
|
||||||
m_request.m_then = [converter = m_converter,
|
m_request.m_then = [converter = m_converter,
|
||||||
handle](SentAsyncWebRequest& req, ByteVector const& arr) {
|
handle](SentAsyncWebRequest& req, ByteVector const& arr) {
|
||||||
auto conv = converter(arr);
|
auto conv = converter(arr);
|
||||||
|
|
|
@ -4,16 +4,15 @@
|
||||||
|
|
||||||
USE_GEODE_NAMESPACE();
|
USE_GEODE_NAMESPACE();
|
||||||
|
|
||||||
#include <Geode/modify/InternalMacros.hpp>
|
#include <Geode/loader/Mod.hpp>
|
||||||
#include <Geode/loader/Mod.hpp>
|
#include <Geode/modify/Modify.hpp>
|
||||||
|
|
||||||
$execute {
|
$execute {
|
||||||
// this replaces the call to __dynamic_cast with a call to our own
|
// this replaces the call to __dynamic_cast with a call to our own
|
||||||
// this is needed because the transitions in cocos uses dynamic cast to check
|
// this is needed because the transitions in cocos uses dynamic cast to check
|
||||||
// layers, which fail on user layers due to typeinfo not matching
|
// layers, which fail on user layers due to typeinfo not matching
|
||||||
(void)Mod::get()->patch(
|
(void)Mod::get()->patch(
|
||||||
reinterpret_cast<void*>(base::get() + 0x603948),
|
reinterpret_cast<void*>(base::get() + 0x603948), toByteArray(&cast::typeinfoCastInternal)
|
||||||
toByteArray(&cast::typeinfoCastInternal)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
|
|
||||||
#ifdef GEODE_IS_WINDOWS
|
#ifdef GEODE_IS_WINDOWS
|
||||||
|
|
||||||
#include <Geode/modify/InternalMacros.hpp>
|
#include <Geode/loader/Mod.hpp>
|
||||||
#include <Geode/loader/Mod.hpp>
|
#include <Geode/modify/Modify.hpp>
|
||||||
|
|
||||||
USE_GEODE_NAMESPACE();
|
USE_GEODE_NAMESPACE();
|
||||||
|
|
||||||
|
@ -19,16 +19,18 @@ static void __cdecl fixedErrorHandler(int code, char const* description) {
|
||||||
fmt::format(
|
fmt::format(
|
||||||
"GLFWError #{}: {}\nPlease contact the "
|
"GLFWError #{}: {}\nPlease contact the "
|
||||||
"Geode Development Team for more information.",
|
"Geode Development Team for more information.",
|
||||||
code, description
|
code,
|
||||||
).c_str(),
|
description
|
||||||
"OpenGL Error", MB_ICONERROR
|
)
|
||||||
|
.c_str(),
|
||||||
|
"OpenGL Error",
|
||||||
|
MB_ICONERROR
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$execute {
|
$execute {
|
||||||
(void)Mod::get()->patch(
|
(void)Mod::get()->patch(
|
||||||
reinterpret_cast<void*>(geode::base::getCocos() + 0x19feec),
|
reinterpret_cast<void*>(geode::base::getCocos() + 0x19feec), toByteArray(&fixedErrorHandler)
|
||||||
toByteArray(&fixedErrorHandler)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Geode/DefaultInclude.hpp>
|
#include <Geode/DefaultInclude.hpp>
|
||||||
#include <Geode/utils/general.hpp>
|
//#include <Geode/utils/general.hpp>
|
||||||
#include <ghc/filesystem.hpp>
|
#include <Geode/utils/MiniFunction.hpp>
|
||||||
|
#include <ghc/fs_fwd.hpp>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class FileWatcher {
|
class FileWatcher {
|
||||||
public:
|
public:
|
||||||
using FileWatchCallback = std::function<void(ghc::filesystem::path)>;
|
using FileWatchCallback = geode::utils::MiniFunction<void(ghc::filesystem::path)>;
|
||||||
using ErrorCallback = std::function<void(std::string)>;
|
using ErrorCallback = geode::utils::MiniFunction<void(std::string)>;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ghc::filesystem::path m_file;
|
ghc::filesystem::path m_file;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Geode/DefaultInclude.hpp>
|
#include <Geode/DefaultInclude.hpp>
|
||||||
#include <ghc/filesystem.hpp>
|
#include <ghc/fs_fwd.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -24,7 +24,7 @@ IPCEvent::IPCEvent(
|
||||||
|
|
||||||
IPCEvent::~IPCEvent() {}
|
IPCEvent::~IPCEvent() {}
|
||||||
|
|
||||||
ListenerResult IPCFilter::handle(std::function<Callback> fn, IPCEvent* event) {
|
ListenerResult IPCFilter::handle(utils::MiniFunction<Callback> fn, IPCEvent* event) {
|
||||||
if (event->targetModID == m_modID && event->messageID == m_messageID) {
|
if (event->targetModID == m_modID && event->messageID == m_messageID) {
|
||||||
event->replyData = fn(event);
|
event->replyData = fn(event);
|
||||||
return ListenerResult::Stop;
|
return ListenerResult::Stop;
|
||||||
|
|
|
@ -17,7 +17,7 @@ ModInstallEvent::ModInstallEvent(
|
||||||
std::string const& id, const UpdateStatus status
|
std::string const& id, const UpdateStatus status
|
||||||
) : modID(id), status(status) {}
|
) : modID(id), status(status) {}
|
||||||
|
|
||||||
ListenerResult ModInstallFilter::handle(std::function<Callback> fn, ModInstallEvent* event) {
|
ListenerResult ModInstallFilter::handle(utils::MiniFunction<Callback> fn, ModInstallEvent* event) {
|
||||||
if (m_id == event->modID) {
|
if (m_id == event->modID) {
|
||||||
fn(event);
|
fn(event);
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ class SourceUpdateFilter : public EventFilter<SourceUpdateEvent> {
|
||||||
public:
|
public:
|
||||||
using Callback = void(SourceUpdateEvent*);
|
using Callback = void(SourceUpdateEvent*);
|
||||||
|
|
||||||
ListenerResult handle(std::function<Callback> fn, SourceUpdateEvent* event) {
|
ListenerResult handle(utils::MiniFunction<Callback> fn, SourceUpdateEvent* event) {
|
||||||
fn(event);
|
fn(event);
|
||||||
return ListenerResult::Propagate;
|
return ListenerResult::Propagate;
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ public:
|
||||||
IndexUpdateEvent::IndexUpdateEvent(const UpdateStatus status) : status(status) {}
|
IndexUpdateEvent::IndexUpdateEvent(const UpdateStatus status) : status(status) {}
|
||||||
|
|
||||||
ListenerResult IndexUpdateFilter::handle(
|
ListenerResult IndexUpdateFilter::handle(
|
||||||
std::function<Callback> fn,
|
utils::MiniFunction<Callback> fn,
|
||||||
IndexUpdateEvent* event
|
IndexUpdateEvent* event
|
||||||
) {
|
) {
|
||||||
fn(event);
|
fn(event);
|
||||||
|
@ -381,16 +381,16 @@ void Index::updateSourceFromLocal(IndexSourceImpl* src) {
|
||||||
}
|
}
|
||||||
auto add = addRes.unwrap();
|
auto add = addRes.unwrap();
|
||||||
// check if this major version of this item has already been added
|
// check if this major version of this item has already been added
|
||||||
if (m_items[add->info.id].count(add->info.version.getMajor())) {
|
if (m_items[add->info.id()].count(add->info.version().getMajor())) {
|
||||||
log::warn(
|
log::warn(
|
||||||
"Item {}@{} has already been added, skipping",
|
"Item {}@{} has already been added, skipping",
|
||||||
add->info.id, add->info.version
|
add->info.id(), add->info.version()
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// add new major version of this item
|
// add new major version of this item
|
||||||
m_items[add->info.id].insert({
|
m_items[add->info.id()].insert({
|
||||||
add->info.version.getMajor(),
|
add->info.version().getMajor(),
|
||||||
add
|
add
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -486,7 +486,7 @@ std::vector<IndexItemHandle> Index::getItemsByDeveloper(
|
||||||
std::vector<IndexItemHandle> res;
|
std::vector<IndexItemHandle> res;
|
||||||
for (auto& items : map::values(m_items)) {
|
for (auto& items : map::values(m_items)) {
|
||||||
if (items.size()) {
|
if (items.size()) {
|
||||||
if (items.rbegin()->second->info.developer == name) {
|
if (items.rbegin()->second->info.developer() == name) {
|
||||||
res.push_back(items.rbegin()->second);
|
res.push_back(items.rbegin()->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -510,7 +510,7 @@ IndexItemHandle Index::getItem(
|
||||||
if (version) {
|
if (version) {
|
||||||
// prefer most major version
|
// prefer most major version
|
||||||
for (auto& [_, item] : ranges::reverse(m_items.at(id))) {
|
for (auto& [_, item] : ranges::reverse(m_items.at(id))) {
|
||||||
if (version.value() == item->info.version) {
|
if (version.value() == item->info.version()) {
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -530,7 +530,7 @@ IndexItemHandle Index::getItem(
|
||||||
if (m_items.count(id)) {
|
if (m_items.count(id)) {
|
||||||
// prefer most major version
|
// prefer most major version
|
||||||
for (auto& [_, item] : ranges::reverse(m_items.at(id))) {
|
for (auto& [_, item] : ranges::reverse(m_items.at(id))) {
|
||||||
if (version.compare(item->info.version)) {
|
if (version.compare(item->info.version())) {
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -539,7 +539,7 @@ IndexItemHandle Index::getItem(
|
||||||
}
|
}
|
||||||
|
|
||||||
IndexItemHandle Index::getItem(ModInfo const& info) const {
|
IndexItemHandle Index::getItem(ModInfo const& info) const {
|
||||||
return this->getItem(info.id, info.version);
|
return this->getItem(info.id(), info.version());
|
||||||
}
|
}
|
||||||
|
|
||||||
IndexItemHandle Index::getItem(Mod* mod) const {
|
IndexItemHandle Index::getItem(Mod* mod) const {
|
||||||
|
@ -547,17 +547,17 @@ IndexItemHandle Index::getItem(Mod* mod) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Index::isUpdateAvailable(IndexItemHandle item) const {
|
bool Index::isUpdateAvailable(IndexItemHandle item) const {
|
||||||
auto installed = Loader::get()->getInstalledMod(item->info.id);
|
auto installed = Loader::get()->getInstalledMod(item->info.id());
|
||||||
if (!installed) {
|
if (!installed) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return item->info.version > installed->getVersion();
|
return item->info.version() > installed->getVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Index::areUpdatesAvailable() const {
|
bool Index::areUpdatesAvailable() const {
|
||||||
for (auto& mod : Loader::get()->getAllMods()) {
|
for (auto& mod : Loader::get()->getAllMods()) {
|
||||||
auto item = this->getItem(mod);
|
auto item = this->getItem(mod);
|
||||||
if (item && item->info.version > mod->getVersion()) {
|
if (item && item->info.version() > mod->getVersion()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -573,7 +573,7 @@ Result<IndexInstallList> Index::getInstallList(IndexItemHandle item) const {
|
||||||
|
|
||||||
IndexInstallList list;
|
IndexInstallList list;
|
||||||
list.target = item;
|
list.target = item;
|
||||||
for (auto& dep : item->info.dependencies) {
|
for (auto& dep : item->info.dependencies()) {
|
||||||
if (!dep.isResolved()) {
|
if (!dep.isResolved()) {
|
||||||
// check if this dep is available in the index
|
// check if this dep is available in the index
|
||||||
if (auto depItem = this->getItem(dep.id, dep.version)) {
|
if (auto depItem = this->getItem(dep.id, dep.version)) {
|
||||||
|
@ -595,7 +595,7 @@ Result<IndexInstallList> Index::getInstallList(IndexItemHandle item) const {
|
||||||
"reason is that the version of the dependency this mod "
|
"reason is that the version of the dependency this mod "
|
||||||
"depends on is not available. Please let the the developer "
|
"depends on is not available. Please let the the developer "
|
||||||
"({}) of the mod know!",
|
"({}) of the mod know!",
|
||||||
dep.id, dep.version.toString(), item->info.developer
|
dep.id, dep.version.toString(), item->info.developer()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -610,7 +610,7 @@ Result<IndexInstallList> Index::getInstallList(IndexItemHandle item) const {
|
||||||
void Index::installNext(size_t index, IndexInstallList const& list) {
|
void Index::installNext(size_t index, IndexInstallList const& list) {
|
||||||
auto postError = [this, list](std::string const& error) {
|
auto postError = [this, list](std::string const& error) {
|
||||||
m_runningInstallations.erase(list.target);
|
m_runningInstallations.erase(list.target);
|
||||||
ModInstallEvent(list.target->info.id, error).post();
|
ModInstallEvent(list.target->info.id(), error).post();
|
||||||
};
|
};
|
||||||
|
|
||||||
// If we're at the end of the list, move the downloaded items to mods
|
// If we're at the end of the list, move the downloaded items to mods
|
||||||
|
@ -619,12 +619,12 @@ void Index::installNext(size_t index, IndexInstallList const& list) {
|
||||||
// Move all downloaded files
|
// Move all downloaded files
|
||||||
for (auto& item : list.list) {
|
for (auto& item : list.list) {
|
||||||
// If the mod is already installed, delete the old .geode file
|
// If the mod is already installed, delete the old .geode file
|
||||||
if (auto mod = Loader::get()->getInstalledMod(item->info.id)) {
|
if (auto mod = Loader::get()->getInstalledMod(item->info.id())) {
|
||||||
auto res = mod->uninstall();
|
auto res = mod->uninstall();
|
||||||
if (!res) {
|
if (!res) {
|
||||||
return postError(fmt::format(
|
return postError(fmt::format(
|
||||||
"Unable to uninstall old version of {}: {}",
|
"Unable to uninstall old version of {}: {}",
|
||||||
item->info.id, res.unwrapErr()
|
item->info.id(), res.unwrapErr()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -632,13 +632,13 @@ void Index::installNext(size_t index, IndexInstallList const& list) {
|
||||||
// Move the temp file
|
// Move the temp file
|
||||||
try {
|
try {
|
||||||
ghc::filesystem::rename(
|
ghc::filesystem::rename(
|
||||||
dirs::getTempDir() / (item->info.id + ".index"),
|
dirs::getTempDir() / (item->info.id() + ".index"),
|
||||||
dirs::getModsDir() / (item->info.id + ".geode")
|
dirs::getModsDir() / (item->info.id() + ".geode")
|
||||||
);
|
);
|
||||||
} catch(std::exception& e) {
|
} catch(std::exception& e) {
|
||||||
return postError(fmt::format(
|
return postError(fmt::format(
|
||||||
"Unable to install {}: {}",
|
"Unable to install {}: {}",
|
||||||
item->info.id, e.what()
|
item->info.id(), e.what()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -646,7 +646,7 @@ void Index::installNext(size_t index, IndexInstallList const& list) {
|
||||||
// load mods
|
// load mods
|
||||||
Loader::get()->refreshModsList();
|
Loader::get()->refreshModsList();
|
||||||
|
|
||||||
ModInstallEvent(list.target->info.id, UpdateFinished()).post();
|
ModInstallEvent(list.target->info.id(), UpdateFinished()).post();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -657,9 +657,9 @@ void Index::installNext(size_t index, IndexInstallList const& list) {
|
||||||
};
|
};
|
||||||
|
|
||||||
auto item = list.list.at(index);
|
auto item = list.list.at(index);
|
||||||
auto tempFile = dirs::getTempDir() / (item->info.id + ".index");
|
auto tempFile = dirs::getTempDir() / (item->info.id() + ".index");
|
||||||
m_runningInstallations[list.target] = web::AsyncWebRequest()
|
m_runningInstallations[list.target] = web::AsyncWebRequest()
|
||||||
.join("install_item_" + item->info.id)
|
.join("install_item_" + item->info.id())
|
||||||
.fetch(item->download.url)
|
.fetch(item->download.url)
|
||||||
.into(tempFile)
|
.into(tempFile)
|
||||||
.then([=](auto) {
|
.then([=](auto) {
|
||||||
|
@ -669,16 +669,16 @@ void Index::installNext(size_t index, IndexInstallList const& list) {
|
||||||
return postError(fmt::format(
|
return postError(fmt::format(
|
||||||
"Binary file download for {} returned \"404 Not found\". "
|
"Binary file download for {} returned \"404 Not found\". "
|
||||||
"Report this to the Geode development team.",
|
"Report this to the Geode development team.",
|
||||||
item->info.id
|
item->info.id()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify checksum
|
// Verify checksum
|
||||||
ModInstallEvent(
|
ModInstallEvent(
|
||||||
list.target->info.id,
|
list.target->info.id(),
|
||||||
UpdateProgress(
|
UpdateProgress(
|
||||||
scaledProgress(100),
|
scaledProgress(100),
|
||||||
fmt::format("Verifying {}", item->info.id)
|
fmt::format("Verifying {}", item->info.id())
|
||||||
)
|
)
|
||||||
).post();
|
).post();
|
||||||
|
|
||||||
|
@ -687,7 +687,7 @@ void Index::installNext(size_t index, IndexInstallList const& list) {
|
||||||
"Checksum mismatch with {}! (Downloaded file did not match what "
|
"Checksum mismatch with {}! (Downloaded file did not match what "
|
||||||
"was expected. Try again, and if the download fails another time, "
|
"was expected. Try again, and if the download fails another time, "
|
||||||
"report this to the Geode development team.)",
|
"report this to the Geode development team.)",
|
||||||
item->info.id
|
item->info.id()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -697,15 +697,15 @@ void Index::installNext(size_t index, IndexInstallList const& list) {
|
||||||
.expect([postError, list, item](std::string const& err) {
|
.expect([postError, list, item](std::string const& err) {
|
||||||
postError(fmt::format(
|
postError(fmt::format(
|
||||||
"Unable to download {}: {}",
|
"Unable to download {}: {}",
|
||||||
item->info.id, err
|
item->info.id(), err
|
||||||
));
|
));
|
||||||
})
|
})
|
||||||
.progress([this, item, list, scaledProgress](auto&, double now, double total) {
|
.progress([this, item, list, scaledProgress](auto&, double now, double total) {
|
||||||
ModInstallEvent(
|
ModInstallEvent(
|
||||||
list.target->info.id,
|
list.target->info.id(),
|
||||||
UpdateProgress(
|
UpdateProgress(
|
||||||
scaledProgress(now / total * 100.0),
|
scaledProgress(now / total * 100.0),
|
||||||
fmt::format("Downloading {}", item->info.id)
|
fmt::format("Downloading {}", item->info.id())
|
||||||
)
|
)
|
||||||
).post();
|
).post();
|
||||||
})
|
})
|
||||||
|
@ -740,7 +740,7 @@ void Index::install(IndexItemHandle item) {
|
||||||
this->install(list.unwrap());
|
this->install(list.unwrap());
|
||||||
} else {
|
} else {
|
||||||
ModInstallEvent(
|
ModInstallEvent(
|
||||||
item->info.id,
|
item->info.id(),
|
||||||
UpdateFailed(list.unwrapErr())
|
UpdateFailed(list.unwrapErr())
|
||||||
).post();
|
).post();
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,25 +187,36 @@ Result<> Loader::Impl::loadData() {
|
||||||
// Mod loading
|
// Mod loading
|
||||||
|
|
||||||
Result<Mod*> Loader::Impl::loadModFromInfo(ModInfo const& info) {
|
Result<Mod*> Loader::Impl::loadModFromInfo(ModInfo const& info) {
|
||||||
if (m_mods.count(info.id)) {
|
if (m_mods.count(info.id())) {
|
||||||
return Err(fmt::format("Mod with ID '{}' already loaded", info.id));
|
return Err(fmt::format("Mod with ID '{}' already loaded", info.id()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// create Mod instance
|
// create Mod instance
|
||||||
auto mod = new Mod(info);
|
auto mod = new Mod(info);
|
||||||
auto setupRes = mod->m_impl->setup();
|
auto setupRes = mod->m_impl->setup();
|
||||||
if (!setupRes) {
|
if (!setupRes) {
|
||||||
|
// old code artifcat, idk why we are not using unique_ptr TBH
|
||||||
|
delete mod;
|
||||||
return Err(fmt::format(
|
return Err(fmt::format(
|
||||||
"Unable to setup mod '{}': {}",
|
"Unable to setup mod '{}': {}",
|
||||||
info.id, setupRes.unwrapErr()
|
info.id(), setupRes.unwrapErr()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_mods.insert({ info.id, mod });
|
m_mods.insert({ info.id(), mod });
|
||||||
|
|
||||||
mod->m_impl->m_enabled = Mod::get()->getSavedValue<bool>(
|
mod->m_impl->m_enabled = Mod::get()->getSavedValue<bool>(
|
||||||
"should-load-" + info.id, true
|
"should-load-" + info.id(), true
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// this loads the mod if its dependencies are resolved
|
||||||
|
auto dependenciesRes = mod->updateDependencies();
|
||||||
|
if (!dependenciesRes) {
|
||||||
|
delete mod;
|
||||||
|
m_mods.erase(info.id());
|
||||||
|
return Err(dependenciesRes.unwrapErr());
|
||||||
|
}
|
||||||
|
|
||||||
// add mod resources
|
// add mod resources
|
||||||
this->queueInGDThread([this, mod]() {
|
this->queueInGDThread([this, mod]() {
|
||||||
auto searchPath = dirs::getModRuntimeDir() / mod->getID() / "resources";
|
auto searchPath = dirs::getModRuntimeDir() / mod->getID() / "resources";
|
||||||
|
@ -214,9 +225,6 @@ Result<Mod*> Loader::Impl::loadModFromInfo(ModInfo const& info) {
|
||||||
this->updateModResources(mod);
|
this->updateModResources(mod);
|
||||||
});
|
});
|
||||||
|
|
||||||
// this loads the mod if its dependencies are resolved
|
|
||||||
GEODE_UNWRAP(mod->updateDependencies());
|
|
||||||
|
|
||||||
return Ok(mod);
|
return Ok(mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,7 +266,7 @@ Mod* Loader::Impl::getLoadedMod(std::string const& id) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Loader::Impl::updateModResources(Mod* mod) {
|
void Loader::Impl::updateModResources(Mod* mod) {
|
||||||
if (!mod->m_impl->m_info.spritesheets.size()) {
|
if (!mod->m_impl->m_info.spritesheets().size()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,7 +275,7 @@ void Loader::Impl::updateModResources(Mod* mod) {
|
||||||
log::debug("Adding resources for {}", mod->getID());
|
log::debug("Adding resources for {}", mod->getID());
|
||||||
|
|
||||||
// add spritesheets
|
// add spritesheets
|
||||||
for (auto const& sheet : mod->m_impl->m_info.spritesheets) {
|
for (auto const& sheet : mod->m_impl->m_info.spritesheets()) {
|
||||||
log::debug("Adding sheet {}", sheet);
|
log::debug("Adding sheet {}", sheet);
|
||||||
auto png = sheet + ".png";
|
auto png = sheet + ".png";
|
||||||
auto plist = sheet + ".plist";
|
auto plist = sheet + ".plist";
|
||||||
|
@ -277,7 +285,7 @@ void Loader::Impl::updateModResources(Mod* mod) {
|
||||||
plist == std::string(ccfu->fullPathForFilename(plist.c_str(), false))) {
|
plist == std::string(ccfu->fullPathForFilename(plist.c_str(), false))) {
|
||||||
log::warn(
|
log::warn(
|
||||||
"The resource dir of \"{}\" is missing \"{}\" png and/or plist files",
|
"The resource dir of \"{}\" is missing \"{}\" png and/or plist files",
|
||||||
mod->m_impl->m_info.id, sheet
|
mod->m_impl->m_info.id(), sheet
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -312,7 +320,7 @@ void Loader::Impl::loadModsFromDirectory(
|
||||||
}
|
}
|
||||||
// skip this entry if it's already loaded
|
// skip this entry if it's already loaded
|
||||||
if (map::contains<std::string, Mod*>(m_mods, [entry](Mod* p) -> bool {
|
if (map::contains<std::string, Mod*>(m_mods, [entry](Mod* p) -> bool {
|
||||||
return p->m_impl->m_info.path == entry.path();
|
return p->m_impl->m_info.path() == entry.path();
|
||||||
})) {
|
})) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -359,10 +367,15 @@ void Loader::Impl::refreshModsList() {
|
||||||
|
|
||||||
// load early-load mods first
|
// load early-load mods first
|
||||||
for (auto& mod : m_modsToLoad) {
|
for (auto& mod : m_modsToLoad) {
|
||||||
if (mod.needsEarlyLoad) {
|
if (mod.needsEarlyLoad()) {
|
||||||
auto load = this->loadModFromInfo(mod);
|
auto load = this->loadModFromInfo(mod);
|
||||||
if (!load) {
|
if (!load) {
|
||||||
log::error("Unable to load {}: {}", mod.id, load.unwrapErr());
|
log::error("Unable to load {}: {}", mod.id(), load.unwrapErr());
|
||||||
|
|
||||||
|
m_invalidMods.push_back(InvalidGeodeFile {
|
||||||
|
.path = mod.path(),
|
||||||
|
.reason = load.unwrapErr(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -373,10 +386,15 @@ void Loader::Impl::refreshModsList() {
|
||||||
|
|
||||||
// load the rest of the mods
|
// load the rest of the mods
|
||||||
for (auto& mod : m_modsToLoad) {
|
for (auto& mod : m_modsToLoad) {
|
||||||
if (!mod.needsEarlyLoad) {
|
if (!mod.needsEarlyLoad()) {
|
||||||
auto load = this->loadModFromInfo(mod);
|
auto load = this->loadModFromInfo(mod);
|
||||||
if (!load) {
|
if (!load) {
|
||||||
log::error("Unable to load {}: {}", mod.id, load.unwrapErr());
|
log::error("Unable to load {}: {}", mod.id(), load.unwrapErr());
|
||||||
|
|
||||||
|
m_invalidMods.push_back(InvalidGeodeFile {
|
||||||
|
.path = mod.path(),
|
||||||
|
.reason = load.unwrapErr(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -467,8 +485,8 @@ bool Loader::Impl::platformConsoleOpen() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Loader::Impl::fetchLatestGithubRelease(
|
void Loader::Impl::fetchLatestGithubRelease(
|
||||||
std::function<void(json::Value const&)> then,
|
utils::MiniFunction<void(json::Value const&)> then,
|
||||||
std::function<void(std::string const&)> expect
|
utils::MiniFunction<void(std::string const&)> expect
|
||||||
) {
|
) {
|
||||||
if (m_latestGithubRelease) {
|
if (m_latestGithubRelease) {
|
||||||
return then(m_latestGithubRelease.value());
|
return then(m_latestGithubRelease.value());
|
||||||
|
@ -700,7 +718,7 @@ void Loader::Impl::checkForLoaderUpdates() {
|
||||||
bool Loader::Impl::isNewUpdateDownloaded() const {
|
bool Loader::Impl::isNewUpdateDownloaded() const {
|
||||||
return m_isNewUpdateDownloaded;
|
return m_isNewUpdateDownloaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
json::Value Loader::Impl::processRawIPC(void* rawHandle, std::string const& buffer) {
|
json::Value Loader::Impl::processRawIPC(void* rawHandle, std::string const& buffer) {
|
||||||
json::Value reply;
|
json::Value reply;
|
||||||
|
|
||||||
|
@ -735,7 +753,7 @@ ResourceDownloadEvent::ResourceDownloadEvent(
|
||||||
) : status(status) {}
|
) : status(status) {}
|
||||||
|
|
||||||
ListenerResult ResourceDownloadFilter::handle(
|
ListenerResult ResourceDownloadFilter::handle(
|
||||||
std::function<Callback> fn,
|
utils::MiniFunction<Callback> fn,
|
||||||
ResourceDownloadEvent* event
|
ResourceDownloadEvent* event
|
||||||
) {
|
) {
|
||||||
fn(event);
|
fn(event);
|
||||||
|
@ -749,7 +767,7 @@ LoaderUpdateEvent::LoaderUpdateEvent(
|
||||||
) : status(status) {}
|
) : status(status) {}
|
||||||
|
|
||||||
ListenerResult LoaderUpdateFilter::handle(
|
ListenerResult LoaderUpdateFilter::handle(
|
||||||
std::function<Callback> fn,
|
utils::MiniFunction<Callback> fn,
|
||||||
LoaderUpdateEvent* event
|
LoaderUpdateEvent* event
|
||||||
) {
|
) {
|
||||||
fn(event);
|
fn(event);
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <Geode/utils/Result.hpp>
|
#include <Geode/utils/Result.hpp>
|
||||||
#include <Geode/utils/map.hpp>
|
#include <Geode/utils/map.hpp>
|
||||||
#include <Geode/utils/ranges.hpp>
|
#include <Geode/utils/ranges.hpp>
|
||||||
|
#include <Geode/utils/MiniFunction.hpp>
|
||||||
#include "ModImpl.hpp"
|
#include "ModImpl.hpp"
|
||||||
#include <about.hpp>
|
#include <about.hpp>
|
||||||
#include <crashlog.hpp>
|
#include <crashlog.hpp>
|
||||||
|
@ -31,7 +32,7 @@ namespace geode {
|
||||||
public:
|
public:
|
||||||
using Callback = void(ResourceDownloadEvent*);
|
using Callback = void(ResourceDownloadEvent*);
|
||||||
|
|
||||||
ListenerResult handle(std::function<Callback> fn, ResourceDownloadEvent* event);
|
ListenerResult handle(utils::MiniFunction<Callback> fn, ResourceDownloadEvent* event);
|
||||||
ResourceDownloadFilter();
|
ResourceDownloadFilter();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ namespace geode {
|
||||||
public:
|
public:
|
||||||
using Callback = void(LoaderUpdateEvent*);
|
using Callback = void(LoaderUpdateEvent*);
|
||||||
|
|
||||||
ListenerResult handle(std::function<Callback> fn, LoaderUpdateEvent* event);
|
ListenerResult handle(utils::MiniFunction<Callback> fn, LoaderUpdateEvent* event);
|
||||||
LoaderUpdateFilter();
|
LoaderUpdateFilter();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -67,7 +68,7 @@ namespace geode {
|
||||||
std::condition_variable m_earlyLoadFinishedCV;
|
std::condition_variable m_earlyLoadFinishedCV;
|
||||||
std::mutex m_earlyLoadFinishedMutex;
|
std::mutex m_earlyLoadFinishedMutex;
|
||||||
std::atomic_bool m_earlyLoadFinished = false;
|
std::atomic_bool m_earlyLoadFinished = false;
|
||||||
std::vector<std::function<void(void)>> m_gdThreadQueue;
|
std::vector<utils::MiniFunction<void(void)>> m_gdThreadQueue;
|
||||||
mutable std::mutex m_gdThreadMutex;
|
mutable std::mutex m_gdThreadMutex;
|
||||||
bool m_platformConsoleOpen = false;
|
bool m_platformConsoleOpen = false;
|
||||||
std::vector<std::pair<Hook*, Mod*>> m_internalHooks;
|
std::vector<std::pair<Hook*, Mod*>> m_internalHooks;
|
||||||
|
@ -94,8 +95,8 @@ namespace geode {
|
||||||
void downloadLoaderResources(bool useLatestRelease = false);
|
void downloadLoaderResources(bool useLatestRelease = false);
|
||||||
void downloadLoaderUpdate(std::string const& url);
|
void downloadLoaderUpdate(std::string const& url);
|
||||||
void fetchLatestGithubRelease(
|
void fetchLatestGithubRelease(
|
||||||
std::function<void(json::Value const&)> then,
|
utils::MiniFunction<void(json::Value const&)> then,
|
||||||
std::function<void(std::string const&)> expect
|
utils::MiniFunction<void(std::string const&)> expect
|
||||||
);
|
);
|
||||||
|
|
||||||
bool loadHooks();
|
bool loadHooks();
|
||||||
|
|
|
@ -12,7 +12,7 @@ Mod* ModStateEvent::getMod() const {
|
||||||
return m_mod;
|
return m_mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
ListenerResult ModStateFilter::handle(std::function<Callback> fn, ModStateEvent* event) {
|
ListenerResult ModStateFilter::handle(utils::MiniFunction<Callback> fn, ModStateEvent* event) {
|
||||||
if (event->getMod() == m_mod && event->getType() == m_type) {
|
if (event->getMod() == m_mod && event->getType() == m_type) {
|
||||||
fn(event);
|
fn(event);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,13 +28,13 @@ Mod::Impl::~Impl() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<> Mod::Impl::setup() {
|
Result<> Mod::Impl::setup() {
|
||||||
m_saveDirPath = dirs::getModsSaveDir() / m_info.id;
|
m_saveDirPath = dirs::getModsSaveDir() / m_info.id();
|
||||||
ghc::filesystem::create_directories(m_saveDirPath);
|
ghc::filesystem::create_directories(m_saveDirPath);
|
||||||
|
|
||||||
this->setupSettings();
|
this->setupSettings();
|
||||||
auto loadRes = this->loadData();
|
auto loadRes = this->loadData();
|
||||||
if (!loadRes) {
|
if (!loadRes) {
|
||||||
log::warn("Unable to load data for \"{}\": {}", m_info.id, loadRes.unwrapErr());
|
log::warn("Unable to load data for \"{}\": {}", m_info.id(), loadRes.unwrapErr());
|
||||||
}
|
}
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
@ -46,23 +46,23 @@ ghc::filesystem::path Mod::Impl::getSaveDir() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Mod::Impl::getID() const {
|
std::string Mod::Impl::getID() const {
|
||||||
return m_info.id;
|
return m_info.id();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Mod::Impl::getName() const {
|
std::string Mod::Impl::getName() const {
|
||||||
return m_info.name;
|
return m_info.name();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Mod::Impl::getDeveloper() const {
|
std::string Mod::Impl::getDeveloper() const {
|
||||||
return m_info.developer;
|
return m_info.developer();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> Mod::Impl::getDescription() const {
|
std::optional<std::string> Mod::Impl::getDescription() const {
|
||||||
return m_info.description;
|
return m_info.description();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> Mod::Impl::getDetails() const {
|
std::optional<std::string> Mod::Impl::getDetails() const {
|
||||||
return m_info.details;
|
return m_info.details();
|
||||||
}
|
}
|
||||||
|
|
||||||
ModInfo Mod::Impl::getModInfo() const {
|
ModInfo Mod::Impl::getModInfo() const {
|
||||||
|
@ -74,15 +74,15 @@ ghc::filesystem::path Mod::Impl::getTempDir() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
ghc::filesystem::path Mod::Impl::getBinaryPath() const {
|
ghc::filesystem::path Mod::Impl::getBinaryPath() const {
|
||||||
return m_tempDirName / m_info.binaryName;
|
return m_tempDirName / m_info.binaryName();
|
||||||
}
|
}
|
||||||
|
|
||||||
ghc::filesystem::path Mod::Impl::getPackagePath() const {
|
ghc::filesystem::path Mod::Impl::getPackagePath() const {
|
||||||
return m_info.path;
|
return m_info.path();
|
||||||
}
|
}
|
||||||
|
|
||||||
VersionInfo Mod::Impl::getVersion() const {
|
VersionInfo Mod::Impl::getVersion() const {
|
||||||
return m_info.version;
|
return m_info.version();
|
||||||
}
|
}
|
||||||
|
|
||||||
json::Value& Mod::Impl::getSaveContainer() {
|
json::Value& Mod::Impl::getSaveContainer() {
|
||||||
|
@ -98,11 +98,11 @@ bool Mod::Impl::isLoaded() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mod::Impl::supportsDisabling() const {
|
bool Mod::Impl::supportsDisabling() const {
|
||||||
return m_info.supportsDisabling;
|
return m_info.supportsDisabling();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mod::Impl::supportsUnloading() const {
|
bool Mod::Impl::supportsUnloading() const {
|
||||||
return m_info.supportsUnloading;
|
return m_info.supportsUnloading();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mod::Impl::wasSuccesfullyLoaded() const {
|
bool Mod::Impl::wasSuccesfullyLoaded() const {
|
||||||
|
@ -124,8 +124,6 @@ Result<> Mod::Impl::loadData() {
|
||||||
if (ghc::filesystem::exists(settingPath)) {
|
if (ghc::filesystem::exists(settingPath)) {
|
||||||
GEODE_UNWRAP_INTO(auto settingData, utils::file::readString(settingPath));
|
GEODE_UNWRAP_INTO(auto settingData, utils::file::readString(settingPath));
|
||||||
try {
|
try {
|
||||||
std::string err;
|
|
||||||
|
|
||||||
// parse settings.json
|
// parse settings.json
|
||||||
auto json = json::parse(settingData);
|
auto json = json::parse(settingData);
|
||||||
|
|
||||||
|
@ -143,7 +141,7 @@ Result<> Mod::Impl::loadData() {
|
||||||
Severity::Error,
|
Severity::Error,
|
||||||
m_self,
|
m_self,
|
||||||
"{}: Unable to load value for setting \"{}\"",
|
"{}: Unable to load value for setting \"{}\"",
|
||||||
m_info.id,
|
m_info.id(),
|
||||||
key
|
key
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -169,13 +167,15 @@ Result<> Mod::Impl::loadData() {
|
||||||
if (ghc::filesystem::exists(savedPath)) {
|
if (ghc::filesystem::exists(savedPath)) {
|
||||||
GEODE_UNWRAP_INTO(auto data, utils::file::readString(savedPath));
|
GEODE_UNWRAP_INTO(auto data, utils::file::readString(savedPath));
|
||||||
|
|
||||||
std::string err;
|
|
||||||
try {
|
try {
|
||||||
m_saved = json::parse(data);
|
m_saved = json::parse(data);
|
||||||
} catch (std::exception& err) {
|
} catch (std::exception& err) {
|
||||||
return Err(std::string("Unable to parse saved values: ") + err.what());
|
return Err(std::string("Unable to parse saved values: ") + err.what());
|
||||||
}
|
}
|
||||||
|
if (!m_saved.is_object()) {
|
||||||
|
log::warn("saved.json was somehow not an object, forcing it to one");
|
||||||
|
m_saved = json::Object();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok();
|
return Ok();
|
||||||
|
@ -229,7 +229,7 @@ Result<> Mod::Impl::saveData() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mod::Impl::setupSettings() {
|
void Mod::Impl::setupSettings() {
|
||||||
for (auto& [key, sett] : m_info.settings) {
|
for (auto& [key, sett] : m_info.settings()) {
|
||||||
if (auto value = sett.createDefaultValue()) {
|
if (auto value = sett.createDefaultValue()) {
|
||||||
m_settings.emplace(key, std::move(value));
|
m_settings.emplace(key, std::move(value));
|
||||||
}
|
}
|
||||||
|
@ -247,19 +247,19 @@ void Mod::Impl::registerCustomSetting(std::string const& key, std::unique_ptr<Se
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mod::Impl::hasSettings() const {
|
bool Mod::Impl::hasSettings() const {
|
||||||
return m_info.settings.size();
|
return m_info.settings().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> Mod::Impl::getSettingKeys() const {
|
std::vector<std::string> Mod::Impl::getSettingKeys() const {
|
||||||
std::vector<std::string> keys;
|
std::vector<std::string> keys;
|
||||||
for (auto& [key, _] : m_info.settings) {
|
for (auto& [key, _] : m_info.settings()) {
|
||||||
keys.push_back(key);
|
keys.push_back(key);
|
||||||
}
|
}
|
||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Setting> Mod::Impl::getSettingDefinition(std::string const& key) const {
|
std::optional<Setting> Mod::Impl::getSettingDefinition(std::string const& key) const {
|
||||||
for (auto& setting : m_info.settings) {
|
for (auto& setting : m_info.settings()) {
|
||||||
if (setting.first == key) {
|
if (setting.first == key) {
|
||||||
return setting.second;
|
return setting.second;
|
||||||
}
|
}
|
||||||
|
@ -275,7 +275,7 @@ SettingValue* Mod::Impl::getSetting(std::string const& key) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mod::Impl::hasSetting(std::string const& key) const {
|
bool Mod::Impl::hasSetting(std::string const& key) const {
|
||||||
for (auto& setting : m_info.settings) {
|
for (auto& setting : m_info.settings()) {
|
||||||
if (setting.first == key) {
|
if (setting.first == key) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -322,7 +322,7 @@ Result<> Mod::Impl::unloadBinary() {
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_info.supportsUnloading) {
|
if (!m_info.supportsUnloading()) {
|
||||||
return Err("Mod does not support unloading");
|
return Err("Mod does not support unloading");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,7 +375,7 @@ Result<> Mod::Impl::disable() {
|
||||||
if (!m_enabled) {
|
if (!m_enabled) {
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
if (!m_info.supportsDisabling) {
|
if (!m_info.supportsDisabling()) {
|
||||||
return Err("Mod does not support disabling");
|
return Err("Mod does not support disabling");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,15 +396,15 @@ Result<> Mod::Impl::disable() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<> Mod::Impl::uninstall() {
|
Result<> Mod::Impl::uninstall() {
|
||||||
if (m_info.supportsDisabling) {
|
if (m_info.supportsDisabling()) {
|
||||||
GEODE_UNWRAP(this->disable());
|
GEODE_UNWRAP(this->disable());
|
||||||
if (m_info.supportsUnloading) {
|
if (m_info.supportsUnloading()) {
|
||||||
GEODE_UNWRAP(this->unloadBinary());
|
GEODE_UNWRAP(this->unloadBinary());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ghc::filesystem::remove(m_info.path);
|
ghc::filesystem::remove(m_info.path());
|
||||||
}
|
}
|
||||||
catch (std::exception& e) {
|
catch (std::exception& e) {
|
||||||
return Err(
|
return Err(
|
||||||
|
@ -418,14 +418,14 @@ Result<> Mod::Impl::uninstall() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mod::Impl::isUninstalled() const {
|
bool Mod::Impl::isUninstalled() const {
|
||||||
return m_self != Mod::get() && !ghc::filesystem::exists(m_info.path);
|
return m_self != Mod::get() && !ghc::filesystem::exists(m_info.path());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dependencies
|
// Dependencies
|
||||||
|
|
||||||
Result<> Mod::Impl::updateDependencies() {
|
Result<> Mod::Impl::updateDependencies() {
|
||||||
bool hasUnresolved = false;
|
bool hasUnresolved = false;
|
||||||
for (auto& dep : m_info.dependencies) {
|
for (auto& dep : m_info.dependencies()) {
|
||||||
// set the dependency's loaded mod if such exists
|
// set the dependency's loaded mod if such exists
|
||||||
if (!dep.mod) {
|
if (!dep.mod) {
|
||||||
dep.mod = Loader::get()->getLoadedMod(dep.id);
|
dep.mod = Loader::get()->getLoadedMod(dep.id);
|
||||||
|
@ -455,20 +455,20 @@ Result<> Mod::Impl::updateDependencies() {
|
||||||
}
|
}
|
||||||
// load if there weren't any unresolved dependencies
|
// load if there weren't any unresolved dependencies
|
||||||
if (!hasUnresolved) {
|
if (!hasUnresolved) {
|
||||||
log::debug("All dependencies for {} found", m_info.id);
|
log::debug("All dependencies for {} found", m_info.id());
|
||||||
if (m_enabled) {
|
if (m_enabled) {
|
||||||
log::debug("Resolved & loading {}", m_info.id);
|
log::debug("Resolved & loading {}", m_info.id());
|
||||||
GEODE_UNWRAP(this->loadBinary());
|
GEODE_UNWRAP(this->loadBinary());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
log::debug("Resolved {}, however not loading it as it is disabled", m_info.id);
|
log::debug("Resolved {}, however not loading it as it is disabled", m_info.id());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mod::Impl::hasUnresolvedDependencies() const {
|
bool Mod::Impl::hasUnresolvedDependencies() const {
|
||||||
for (auto const& dep : m_info.dependencies) {
|
for (auto const& dep : m_info.dependencies()) {
|
||||||
if (!dep.isResolved()) {
|
if (!dep.isResolved()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -478,7 +478,7 @@ bool Mod::Impl::hasUnresolvedDependencies() const {
|
||||||
|
|
||||||
std::vector<Dependency> Mod::Impl::getUnresolvedDependencies() {
|
std::vector<Dependency> Mod::Impl::getUnresolvedDependencies() {
|
||||||
std::vector<Dependency> unresolved;
|
std::vector<Dependency> unresolved;
|
||||||
for (auto const& dep : m_info.dependencies) {
|
for (auto const& dep : m_info.dependencies()) {
|
||||||
if (!dep.isResolved()) {
|
if (!dep.isResolved()) {
|
||||||
unresolved.push_back(dep);
|
unresolved.push_back(dep);
|
||||||
}
|
}
|
||||||
|
@ -487,7 +487,7 @@ std::vector<Dependency> Mod::Impl::getUnresolvedDependencies() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mod::Impl::depends(std::string const& id) const {
|
bool Mod::Impl::depends(std::string const& id) const {
|
||||||
return utils::ranges::contains(m_info.dependencies, [id](Dependency const& t) {
|
return utils::ranges::contains(m_info.dependencies(), [id](Dependency const& t) {
|
||||||
return t.id == id;
|
return t.id == id;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -498,7 +498,7 @@ Result<> Mod::Impl::enableHook(Hook* hook) {
|
||||||
auto res = hook->enable();
|
auto res = hook->enable();
|
||||||
if (res) m_hooks.push_back(hook);
|
if (res) m_hooks.push_back(hook);
|
||||||
else {
|
else {
|
||||||
log::error("Can't enable hook {} for mod {}: {}", m_info.id, res.unwrapErr());
|
log::error("Can't enable hook {} for mod {}: {}", m_info.id(), res.unwrapErr());
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
@ -583,16 +583,16 @@ Result<> Mod::Impl::createTempDir() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create geode/temp/mod.id
|
// Create geode/temp/mod.id
|
||||||
auto tempPath = tempDir / m_info.id;
|
auto tempPath = tempDir / m_info.id();
|
||||||
if (!file::createDirectoryAll(tempPath)) {
|
if (!file::createDirectoryAll(tempPath)) {
|
||||||
return Err("Unable to create mod runtime directory");
|
return Err("Unable to create mod runtime directory");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unzip .geode file into temp dir
|
// Unzip .geode file into temp dir
|
||||||
GEODE_UNWRAP_INTO(auto unzip, file::Unzip::create(m_info.path));
|
GEODE_UNWRAP_INTO(auto unzip, file::Unzip::create(m_info.path()));
|
||||||
if (!unzip.hasEntry(m_info.binaryName)) {
|
if (!unzip.hasEntry(m_info.binaryName())) {
|
||||||
return Err(
|
return Err(
|
||||||
fmt::format("Unable to find platform binary under the name \"{}\"", m_info.binaryName)
|
fmt::format("Unable to find platform binary under the name \"{}\"", m_info.binaryName())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
GEODE_UNWRAP(unzip.extractAllTo(tempPath));
|
GEODE_UNWRAP(unzip.extractAllTo(tempPath));
|
||||||
|
@ -604,7 +604,7 @@ Result<> Mod::Impl::createTempDir() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ghc::filesystem::path Mod::Impl::getConfigDir(bool create) const {
|
ghc::filesystem::path Mod::Impl::getConfigDir(bool create) const {
|
||||||
auto dir = dirs::getModConfigDir() / m_info.id;
|
auto dir = dirs::getModConfigDir() / m_info.id();
|
||||||
if (create) {
|
if (create) {
|
||||||
(void)file::createDirectoryAll(dir);
|
(void)file::createDirectoryAll(dir);
|
||||||
}
|
}
|
||||||
|
@ -615,8 +615,8 @@ char const* Mod::Impl::expandSpriteName(char const* name) {
|
||||||
static std::unordered_map<std::string, char const*> expanded = {};
|
static std::unordered_map<std::string, char const*> expanded = {};
|
||||||
if (expanded.count(name)) return expanded[name];
|
if (expanded.count(name)) return expanded[name];
|
||||||
|
|
||||||
auto exp = new char[strlen(name) + 2 + m_info.id.size()];
|
auto exp = new char[strlen(name) + 2 + m_info.id().size()];
|
||||||
auto exps = m_info.id + "/" + name;
|
auto exps = m_info.id() + "/" + name;
|
||||||
memcpy(exp, exps.c_str(), exps.size() + 1);
|
memcpy(exp, exps.c_str(), exps.size() + 1);
|
||||||
|
|
||||||
expanded[name] = exp;
|
expanded[name] = exp;
|
||||||
|
@ -679,9 +679,9 @@ static ModInfo getModImplInfo() {
|
||||||
return ModInfo();
|
return ModInfo();
|
||||||
}
|
}
|
||||||
auto info = infoRes.unwrap();
|
auto info = infoRes.unwrap();
|
||||||
info.details = LOADER_ABOUT_MD;
|
info.details() = LOADER_ABOUT_MD;
|
||||||
info.supportInfo = SUPPORT_INFO;
|
info.supportInfo() = SUPPORT_INFO;
|
||||||
info.supportsDisabling = false;
|
info.supportsDisabling() = false;
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,18 @@
|
||||||
#include <Geode/loader/Loader.hpp>
|
#include <Geode/loader/Loader.hpp>
|
||||||
#include <Geode/loader/Mod.hpp>
|
#include <Geode/loader/Mod.hpp>
|
||||||
#include <Geode/utils/file.hpp>
|
|
||||||
#include <Geode/utils/string.hpp>
|
|
||||||
#include <json.hpp>
|
|
||||||
#include <Geode/utils/JsonValidation.hpp>
|
#include <Geode/utils/JsonValidation.hpp>
|
||||||
#include <Geode/utils/VersionInfo.hpp>
|
#include <Geode/utils/VersionInfo.hpp>
|
||||||
|
#include <Geode/utils/file.hpp>
|
||||||
|
#include <Geode/utils/string.hpp>
|
||||||
#include <about.hpp>
|
#include <about.hpp>
|
||||||
|
#include <json.hpp>
|
||||||
|
|
||||||
USE_GEODE_NAMESPACE();
|
USE_GEODE_NAMESPACE();
|
||||||
|
|
||||||
bool Dependency::isResolved() const {
|
bool Dependency::isResolved() const {
|
||||||
return
|
return !this->required ||
|
||||||
!this->required ||
|
(this->mod && this->mod->isLoaded() && this->mod->isEnabled() &&
|
||||||
(
|
this->version.compare(this->mod->getVersion()));
|
||||||
this->mod &&
|
|
||||||
this->mod->isLoaded() &&
|
|
||||||
this->mod->isEnabled() &&
|
|
||||||
this->version.compare(this->mod->getVersion())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string sanitizeDetailsData(std::string const& str) {
|
static std::string sanitizeDetailsData(std::string const& str) {
|
||||||
|
@ -26,7 +20,51 @@ static std::string sanitizeDetailsData(std::string const& str) {
|
||||||
return utils::string::replace(str, "\r", "");
|
return utils::string::replace(str, "\r", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModInfo::validateID(std::string const& id) {
|
class ModInfo::Impl {
|
||||||
|
public:
|
||||||
|
ghc::filesystem::path m_path;
|
||||||
|
std::string m_binaryName;
|
||||||
|
VersionInfo m_version{1, 0, 0};
|
||||||
|
std::string m_id;
|
||||||
|
std::string m_name;
|
||||||
|
std::string m_developer;
|
||||||
|
std::optional<std::string> m_description;
|
||||||
|
std::optional<std::string> m_details;
|
||||||
|
std::optional<std::string> m_changelog;
|
||||||
|
std::optional<std::string> m_supportInfo;
|
||||||
|
std::optional<std::string> m_repository;
|
||||||
|
std::optional<IssuesInfo> m_issues;
|
||||||
|
std::vector<Dependency> m_dependencies;
|
||||||
|
std::vector<std::string> m_spritesheets;
|
||||||
|
std::vector<std::pair<std::string, Setting>> m_settings;
|
||||||
|
bool m_supportsDisabling = true;
|
||||||
|
bool m_supportsUnloading = false;
|
||||||
|
bool m_needsEarlyLoad = false;
|
||||||
|
bool m_isAPI = false;
|
||||||
|
|
||||||
|
ModJson m_rawJSON;
|
||||||
|
|
||||||
|
static Result<ModInfo> createFromGeodeZip(utils::file::Unzip& zip);
|
||||||
|
static Result<ModInfo> createFromGeodeFile(ghc::filesystem::path const& path);
|
||||||
|
static Result<ModInfo> createFromFile(ghc::filesystem::path const& path);
|
||||||
|
static Result<ModInfo> create(ModJson const& json);
|
||||||
|
|
||||||
|
ModJson toJSON() const;
|
||||||
|
ModJson getRawJSON() const;
|
||||||
|
|
||||||
|
bool operator==(ModInfo::Impl const& other) const;
|
||||||
|
|
||||||
|
static bool validateID(std::string const& id);
|
||||||
|
|
||||||
|
static Result<ModInfo> createFromSchemaV010(ModJson const& json);
|
||||||
|
|
||||||
|
Result<> addSpecialFiles(ghc::filesystem::path const& dir);
|
||||||
|
Result<> addSpecialFiles(utils::file::Unzip& zip);
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string, std::optional<std::string>*>> getSpecialFiles();
|
||||||
|
};
|
||||||
|
|
||||||
|
bool ModInfo::Impl::validateID(std::string const& id) {
|
||||||
// ids may not be empty
|
// ids may not be empty
|
||||||
if (!id.size()) return false;
|
if (!id.size()) return false;
|
||||||
for (auto const& c : id) {
|
for (auto const& c : id) {
|
||||||
|
@ -37,49 +75,52 @@ bool ModInfo::validateID(std::string const& id) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<ModInfo> ModInfo::createFromSchemaV010(ModJson const& rawJson) {
|
Result<ModInfo> ModInfo::Impl::createFromSchemaV010(ModJson const& rawJson) {
|
||||||
ModInfo info;
|
ModInfo info;
|
||||||
|
|
||||||
info.m_rawJSON = std::make_unique<ModJson>(rawJson);
|
auto impl = info.m_impl.get();
|
||||||
|
|
||||||
JsonChecker checker(*info.m_rawJSON);
|
impl->m_rawJSON = rawJson;
|
||||||
|
|
||||||
|
JsonChecker checker(impl->m_rawJSON);
|
||||||
auto root = checker.root("[mod.json]").obj();
|
auto root = checker.root("[mod.json]").obj();
|
||||||
|
|
||||||
root.addKnownKey("geode");
|
root.addKnownKey("geode");
|
||||||
|
|
||||||
root.needs("id").validate(&ModInfo::validateID).into(info.id);
|
root.needs("id").validate(MiniFunction<bool(std::string const&)>(&ModInfo::validateID)).into(impl->m_id);
|
||||||
root.needs("version").into(info.version);
|
root.needs("version").into(impl->m_version);
|
||||||
root.needs("name").into(info.name);
|
root.needs("name").into(impl->m_name);
|
||||||
root.needs("developer").into(info.developer);
|
root.needs("developer").into(impl->m_developer);
|
||||||
root.has("description").into(info.description);
|
root.has("description").into(impl->m_description);
|
||||||
root.has("repository").into(info.repository);
|
root.has("repository").into(impl->m_repository);
|
||||||
root.has("toggleable").into(info.supportsDisabling);
|
root.has("toggleable").into(impl->m_supportsDisabling);
|
||||||
root.has("unloadable").into(info.supportsUnloading);
|
root.has("unloadable").into(impl->m_supportsUnloading);
|
||||||
root.has("early-load").into(info.needsEarlyLoad);
|
root.has("early-load").into(impl->m_needsEarlyLoad);
|
||||||
if (root.has("api")) {
|
if (root.has("api")) {
|
||||||
info.isAPI = true;
|
// TODO: figure out what got wiped with merge
|
||||||
|
// impl->isAPI = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& dep : root.has("dependencies").iterate()) {
|
for (auto& dep : root.has("dependencies").iterate()) {
|
||||||
auto obj = dep.obj();
|
auto obj = dep.obj();
|
||||||
|
|
||||||
auto depobj = Dependency {};
|
auto depobj = Dependency{};
|
||||||
obj.needs("id").validate(&ModInfo::validateID).into(depobj.id);
|
obj.needs("id").validate(MiniFunction<bool(std::string const&)>(&ModInfo::validateID)).into(depobj.id);
|
||||||
obj.needs("version").into(depobj.version);
|
obj.needs("version").into(depobj.version);
|
||||||
obj.has("required").into(depobj.required);
|
obj.has("required").into(depobj.required);
|
||||||
obj.checkUnknownKeys();
|
obj.checkUnknownKeys();
|
||||||
|
|
||||||
info.dependencies.push_back(depobj);
|
impl->m_dependencies.push_back(depobj);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& [key, value] : root.has("settings").items()) {
|
for (auto& [key, value] : root.has("settings").items()) {
|
||||||
GEODE_UNWRAP_INTO(auto sett, Setting::parse(key, value));
|
GEODE_UNWRAP_INTO(auto sett, Setting::parse(key, value));
|
||||||
info.settings.push_back({ key, sett });
|
impl->m_settings.push_back({key, sett});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto resources = root.has("resources").obj()) {
|
if (auto resources = root.has("resources").obj()) {
|
||||||
for (auto& [key, _] : resources.has("spritesheets").items()) {
|
for (auto& [key, _] : resources.has("spritesheets").items()) {
|
||||||
info.spritesheets.push_back(info.id + "/" + key);
|
impl->m_spritesheets.push_back(impl->m_id + "/" + key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,11 +128,11 @@ Result<ModInfo> ModInfo::createFromSchemaV010(ModJson const& rawJson) {
|
||||||
IssuesInfo issuesInfo;
|
IssuesInfo issuesInfo;
|
||||||
issues.needs("info").into(issuesInfo.info);
|
issues.needs("info").into(issuesInfo.info);
|
||||||
issues.has("url").intoAs<std::string>(issuesInfo.url);
|
issues.has("url").intoAs<std::string>(issuesInfo.url);
|
||||||
info.issues = issuesInfo;
|
impl->m_issues = issuesInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
// with new cli, binary name is always mod id
|
// with new cli, binary name is always mod id
|
||||||
info.binaryName = info.id + GEODE_PLATFORM_EXTENSION;
|
impl->m_binaryName = impl->m_id + GEODE_PLATFORM_EXTENSION;
|
||||||
|
|
||||||
// removed keys
|
// removed keys
|
||||||
if (root.has("datastore")) {
|
if (root.has("datastore")) {
|
||||||
|
@ -112,12 +153,13 @@ Result<ModInfo> ModInfo::createFromSchemaV010(ModJson const& rawJson) {
|
||||||
return Ok(info);
|
return Ok(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<ModInfo> ModInfo::create(ModJson const& json) {
|
Result<ModInfo> ModInfo::Impl::create(ModJson const& json) {
|
||||||
// Check mod.json target version
|
// Check mod.json target version
|
||||||
auto schema = LOADER_VERSION;
|
auto schema = LOADER_VERSION;
|
||||||
if (json.contains("geode") && json["geode"].is_string()) {
|
if (json.contains("geode") && json["geode"].is_string()) {
|
||||||
GEODE_UNWRAP_INTO(
|
GEODE_UNWRAP_INTO(
|
||||||
schema, VersionInfo::parse(json["geode"].as_string())
|
schema,
|
||||||
|
VersionInfo::parse(json["geode"].as_string())
|
||||||
.expect("[mod.json] has invalid target loader version: {error}")
|
.expect("[mod.json] has invalid target loader version: {error}")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -147,7 +189,7 @@ Result<ModInfo> ModInfo::create(ModJson const& json) {
|
||||||
|
|
||||||
// Handle mod.json data based on target
|
// Handle mod.json data based on target
|
||||||
if (schema >= VersionInfo(0, 1, 0)) {
|
if (schema >= VersionInfo(0, 1, 0)) {
|
||||||
return ModInfo::createFromSchemaV010(json);
|
return Impl::createFromSchemaV010(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err(
|
return Err(
|
||||||
|
@ -161,13 +203,15 @@ Result<ModInfo> ModInfo::create(ModJson const& json) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<ModInfo> ModInfo::createFromFile(ghc::filesystem::path const& path) {
|
Result<ModInfo> ModInfo::Impl::createFromFile(ghc::filesystem::path const& path) {
|
||||||
GEODE_UNWRAP_INTO(auto read, utils::file::readString(path));
|
GEODE_UNWRAP_INTO(auto read, utils::file::readString(path));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
GEODE_UNWRAP_INTO(auto info, ModInfo::create(json::parse(read)));
|
GEODE_UNWRAP_INTO(auto info, ModInfo::create(json::parse(read)));
|
||||||
|
|
||||||
info.path = path;
|
auto impl = info.m_impl.get();
|
||||||
|
|
||||||
|
impl->m_path = path;
|
||||||
if (path.has_parent_path()) {
|
if (path.has_parent_path()) {
|
||||||
GEODE_UNWRAP(info.addSpecialFiles(path.parent_path()));
|
GEODE_UNWRAP(info.addSpecialFiles(path.parent_path()));
|
||||||
}
|
}
|
||||||
|
@ -178,12 +222,12 @@ Result<ModInfo> ModInfo::createFromFile(ghc::filesystem::path const& path) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<ModInfo> ModInfo::createFromGeodeFile(ghc::filesystem::path const& path) {
|
Result<ModInfo> ModInfo::Impl::createFromGeodeFile(ghc::filesystem::path const& path) {
|
||||||
GEODE_UNWRAP_INTO(auto unzip, file::Unzip::create(path));
|
GEODE_UNWRAP_INTO(auto unzip, file::Unzip::create(path));
|
||||||
return ModInfo::createFromGeodeZip(unzip);
|
return ModInfo::createFromGeodeZip(unzip);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<ModInfo> ModInfo::createFromGeodeZip(file::Unzip& unzip) {
|
Result<ModInfo> ModInfo::Impl::createFromGeodeZip(file::Unzip& unzip) {
|
||||||
// Check if mod.json exists in zip
|
// Check if mod.json exists in zip
|
||||||
if (!unzip.hasEntry("mod.json")) {
|
if (!unzip.hasEntry("mod.json")) {
|
||||||
return Err("\"" + unzip.getPath().string() + "\" is missing mod.json");
|
return Err("\"" + unzip.getPath().string() + "\" is missing mod.json");
|
||||||
|
@ -208,16 +252,17 @@ Result<ModInfo> ModInfo::createFromGeodeZip(file::Unzip& unzip) {
|
||||||
return Err("\"" + unzip.getPath().string() + "\" - " + res.unwrapErr());
|
return Err("\"" + unzip.getPath().string() + "\" - " + res.unwrapErr());
|
||||||
}
|
}
|
||||||
auto info = res.unwrap();
|
auto info = res.unwrap();
|
||||||
info.path = unzip.getPath();
|
auto impl = info.m_impl.get();
|
||||||
|
impl->m_path = unzip.getPath();
|
||||||
|
|
||||||
GEODE_UNWRAP(info.addSpecialFiles(unzip).expect("Unable to add extra files: {error}"));
|
GEODE_UNWRAP(info.addSpecialFiles(unzip).expect("Unable to add extra files: {error}"));
|
||||||
|
|
||||||
return Ok(info);
|
return Ok(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<> ModInfo::addSpecialFiles(file::Unzip& unzip) {
|
Result<> ModInfo::Impl::addSpecialFiles(file::Unzip& unzip) {
|
||||||
// unzip known MD files
|
// unzip known MD files
|
||||||
for (auto& [file, target] : getSpecialFiles()) {
|
for (auto& [file, target] : this->getSpecialFiles()) {
|
||||||
if (unzip.hasEntry(file)) {
|
if (unzip.hasEntry(file)) {
|
||||||
GEODE_UNWRAP_INTO(auto data, unzip.extract(file).expect("Unable to extract \"{}\"", file));
|
GEODE_UNWRAP_INTO(auto data, unzip.extract(file).expect("Unable to extract \"{}\"", file));
|
||||||
*target = sanitizeDetailsData(std::string(data.begin(), data.end()));
|
*target = sanitizeDetailsData(std::string(data.begin(), data.end()));
|
||||||
|
@ -226,9 +271,9 @@ Result<> ModInfo::addSpecialFiles(file::Unzip& unzip) {
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<> ModInfo::addSpecialFiles(ghc::filesystem::path const& dir) {
|
Result<> ModInfo::Impl::addSpecialFiles(ghc::filesystem::path const& dir) {
|
||||||
// unzip known MD files
|
// unzip known MD files
|
||||||
for (auto& [file, target] : getSpecialFiles()) {
|
for (auto& [file, target] : this->getSpecialFiles()) {
|
||||||
if (ghc::filesystem::exists(dir / file)) {
|
if (ghc::filesystem::exists(dir / file)) {
|
||||||
auto data = file::readString(dir / file);
|
auto data = file::readString(dir / file);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
|
@ -240,25 +285,230 @@ Result<> ModInfo::addSpecialFiles(ghc::filesystem::path const& dir) {
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::optional<std::string>*>> ModInfo::getSpecialFiles() {
|
std::vector<std::pair<std::string, std::optional<std::string>*>> ModInfo::Impl::getSpecialFiles() {
|
||||||
return {
|
return {
|
||||||
{ "about.md", &this->details },
|
{"about.md", &this->m_details},
|
||||||
{ "changelog.md", &this->changelog },
|
{"changelog.md", &this->m_changelog},
|
||||||
{ "support.md", &this->supportInfo },
|
{"support.md", &this->m_supportInfo},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ModJson ModInfo::toJSON() const {
|
ModJson ModInfo::Impl::toJSON() const {
|
||||||
auto json = *m_rawJSON;
|
auto json = m_rawJSON;
|
||||||
json["path"] = this->path.string();
|
json["path"] = this->m_path.string();
|
||||||
json["binary"] = this->binaryName;
|
json["binary"] = this->m_binaryName;
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ModJson ModInfo::Impl::getRawJSON() const {
|
||||||
|
return m_rawJSON;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModInfo::Impl::operator==(ModInfo::Impl const& other) const {
|
||||||
|
return this->m_id == other.m_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
ghc::filesystem::path& ModInfo::path() {
|
||||||
|
return m_impl->m_path;
|
||||||
|
}
|
||||||
|
ghc::filesystem::path const& ModInfo::path() const {
|
||||||
|
return m_impl->m_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string& ModInfo::binaryName() {
|
||||||
|
return m_impl->m_binaryName;
|
||||||
|
}
|
||||||
|
std::string const& ModInfo::binaryName() const {
|
||||||
|
return m_impl->m_binaryName;
|
||||||
|
}
|
||||||
|
|
||||||
|
VersionInfo& ModInfo::version() {
|
||||||
|
return m_impl->m_version;
|
||||||
|
}
|
||||||
|
VersionInfo const& ModInfo::version() const {
|
||||||
|
return m_impl->m_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string& ModInfo::id() {
|
||||||
|
return m_impl->m_id;
|
||||||
|
}
|
||||||
|
std::string const& ModInfo::id() const {
|
||||||
|
return m_impl->m_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string& ModInfo::name() {
|
||||||
|
return m_impl->m_name;
|
||||||
|
}
|
||||||
|
std::string const& ModInfo::name() const {
|
||||||
|
return m_impl->m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string& ModInfo::developer() {
|
||||||
|
return m_impl->m_developer;
|
||||||
|
}
|
||||||
|
std::string const& ModInfo::developer() const {
|
||||||
|
return m_impl->m_developer;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string>& ModInfo::description() {
|
||||||
|
return m_impl->m_description;
|
||||||
|
}
|
||||||
|
std::optional<std::string> const& ModInfo::description() const {
|
||||||
|
return m_impl->m_description;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string>& ModInfo::details() {
|
||||||
|
return m_impl->m_details;
|
||||||
|
}
|
||||||
|
std::optional<std::string> const& ModInfo::details() const {
|
||||||
|
return m_impl->m_details;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string>& ModInfo::changelog() {
|
||||||
|
return m_impl->m_changelog;
|
||||||
|
}
|
||||||
|
std::optional<std::string> const& ModInfo::changelog() const {
|
||||||
|
return m_impl->m_changelog;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string>& ModInfo::supportInfo() {
|
||||||
|
return m_impl->m_supportInfo;
|
||||||
|
}
|
||||||
|
std::optional<std::string> const& ModInfo::supportInfo() const {
|
||||||
|
return m_impl->m_supportInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string>& ModInfo::repository() {
|
||||||
|
return m_impl->m_repository;
|
||||||
|
}
|
||||||
|
std::optional<std::string> const& ModInfo::repository() const {
|
||||||
|
return m_impl->m_repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<IssuesInfo>& ModInfo::issues() {
|
||||||
|
return m_impl->m_issues;
|
||||||
|
}
|
||||||
|
std::optional<IssuesInfo> const& ModInfo::issues() const {
|
||||||
|
return m_impl->m_issues;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Dependency>& ModInfo::dependencies() {
|
||||||
|
return m_impl->m_dependencies;
|
||||||
|
}
|
||||||
|
std::vector<Dependency> const& ModInfo::dependencies() const {
|
||||||
|
return m_impl->m_dependencies;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string>& ModInfo::spritesheets() {
|
||||||
|
return m_impl->m_spritesheets;
|
||||||
|
}
|
||||||
|
std::vector<std::string> const& ModInfo::spritesheets() const {
|
||||||
|
return m_impl->m_spritesheets;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string, Setting>>& ModInfo::settings() {
|
||||||
|
return m_impl->m_settings;
|
||||||
|
}
|
||||||
|
std::vector<std::pair<std::string, Setting>> const& ModInfo::settings() const {
|
||||||
|
return m_impl->m_settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool& ModInfo::supportsDisabling() {
|
||||||
|
return m_impl->m_supportsDisabling;
|
||||||
|
}
|
||||||
|
bool const& ModInfo::supportsDisabling() const {
|
||||||
|
return m_impl->m_supportsDisabling;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool& ModInfo::supportsUnloading() {
|
||||||
|
return m_impl->m_supportsUnloading;
|
||||||
|
}
|
||||||
|
bool const& ModInfo::supportsUnloading() const {
|
||||||
|
return m_impl->m_supportsUnloading;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool& ModInfo::needsEarlyLoad() {
|
||||||
|
return m_impl->m_needsEarlyLoad;
|
||||||
|
}
|
||||||
|
bool const& ModInfo::needsEarlyLoad() const {
|
||||||
|
return m_impl->m_needsEarlyLoad;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool& ModInfo::isAPI() {
|
||||||
|
return m_impl->m_isAPI;
|
||||||
|
}
|
||||||
|
bool const& ModInfo::isAPI() const {
|
||||||
|
return m_impl->m_isAPI;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<ModInfo> ModInfo::createFromGeodeZip(utils::file::Unzip& zip) {
|
||||||
|
return Impl::createFromGeodeZip(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<ModInfo> ModInfo::createFromGeodeFile(ghc::filesystem::path const& path) {
|
||||||
|
return Impl::createFromGeodeFile(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<ModInfo> ModInfo::createFromFile(ghc::filesystem::path const& path) {
|
||||||
|
return Impl::createFromFile(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<ModInfo> ModInfo::create(ModJson const& json) {
|
||||||
|
return Impl::create(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModJson ModInfo::toJSON() const {
|
||||||
|
return m_impl->toJSON();
|
||||||
|
}
|
||||||
|
|
||||||
ModJson ModInfo::getRawJSON() const {
|
ModJson ModInfo::getRawJSON() const {
|
||||||
return *m_rawJSON;
|
return m_impl->getRawJSON();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModInfo::operator==(ModInfo const& other) const {
|
bool ModInfo::operator==(ModInfo const& other) const {
|
||||||
return this->id == other.id;
|
return m_impl->operator==(*other.m_impl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ModInfo::validateID(std::string const& id) {
|
||||||
|
return Impl::validateID(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModJson& ModInfo::rawJSON() {
|
||||||
|
return m_impl->m_rawJSON;
|
||||||
|
}
|
||||||
|
ModJson const& ModInfo::rawJSON() const {
|
||||||
|
return m_impl->m_rawJSON;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<ModInfo> ModInfo::createFromSchemaV010(ModJson const& json) {
|
||||||
|
return Impl::createFromSchemaV010(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<> ModInfo::addSpecialFiles(ghc::filesystem::path const& dir) {
|
||||||
|
return m_impl->addSpecialFiles(dir);
|
||||||
|
}
|
||||||
|
Result<> ModInfo::addSpecialFiles(utils::file::Unzip& zip) {
|
||||||
|
return m_impl->addSpecialFiles(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string, std::optional<std::string>*>> ModInfo::getSpecialFiles() {
|
||||||
|
return m_impl->getSpecialFiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
ModInfo::ModInfo() : m_impl(std::make_unique<Impl>()) {}
|
||||||
|
|
||||||
|
ModInfo::ModInfo(ModInfo const& other) : m_impl(std::make_unique<Impl>(*other.m_impl)) {}
|
||||||
|
|
||||||
|
ModInfo::ModInfo(ModInfo&& other) noexcept : m_impl(std::move(other.m_impl)) {}
|
||||||
|
|
||||||
|
ModInfo& ModInfo::operator=(ModInfo const& other) {
|
||||||
|
m_impl = std::make_unique<Impl>(*other.m_impl);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModInfo& ModInfo::operator=(ModInfo&& other) noexcept {
|
||||||
|
m_impl = std::move(other.m_impl);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModInfo::~ModInfo() {}
|
|
@ -11,19 +11,19 @@
|
||||||
USE_GEODE_NAMESPACE();
|
USE_GEODE_NAMESPACE();
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
static void parseCommon(T& sett, JsonMaybeObject<ModJson>& obj) {
|
static void parseCommon(T& sett, JsonMaybeObject& obj) {
|
||||||
obj.has("name").into(sett.name);
|
obj.has("name").into(sett.name);
|
||||||
obj.has("description").into(sett.description);
|
obj.has("description").into(sett.description);
|
||||||
obj.has("default").into(sett.defaultValue);
|
obj.has("default").into(sett.defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<BoolSetting> BoolSetting::parse(JsonMaybeObject<ModJson>& obj) {
|
Result<BoolSetting> BoolSetting::parse(JsonMaybeObject& obj) {
|
||||||
BoolSetting sett;
|
BoolSetting sett;
|
||||||
parseCommon(sett, obj);
|
parseCommon(sett, obj);
|
||||||
return Ok(sett);
|
return Ok(sett);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<IntSetting> IntSetting::parse(JsonMaybeObject<ModJson>& obj) {
|
Result<IntSetting> IntSetting::parse(JsonMaybeObject& obj) {
|
||||||
IntSetting sett;
|
IntSetting sett;
|
||||||
parseCommon(sett, obj);
|
parseCommon(sett, obj);
|
||||||
obj.has("min").into(sett.min);
|
obj.has("min").into(sett.min);
|
||||||
|
@ -40,7 +40,7 @@ Result<IntSetting> IntSetting::parse(JsonMaybeObject<ModJson>& obj) {
|
||||||
return Ok(sett);
|
return Ok(sett);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<FloatSetting> FloatSetting::parse(JsonMaybeObject<ModJson>& obj) {
|
Result<FloatSetting> FloatSetting::parse(JsonMaybeObject& obj) {
|
||||||
FloatSetting sett;
|
FloatSetting sett;
|
||||||
parseCommon(sett, obj);
|
parseCommon(sett, obj);
|
||||||
obj.has("min").into(sett.min);
|
obj.has("min").into(sett.min);
|
||||||
|
@ -57,14 +57,14 @@ Result<FloatSetting> FloatSetting::parse(JsonMaybeObject<ModJson>& obj) {
|
||||||
return Ok(sett);
|
return Ok(sett);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<StringSetting> StringSetting::parse(JsonMaybeObject<ModJson>& obj) {
|
Result<StringSetting> StringSetting::parse(JsonMaybeObject& obj) {
|
||||||
StringSetting sett;
|
StringSetting sett;
|
||||||
parseCommon(sett, obj);
|
parseCommon(sett, obj);
|
||||||
obj.has("match").into(sett.match);
|
obj.has("match").into(sett.match);
|
||||||
return Ok(sett);
|
return Ok(sett);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<FileSetting> FileSetting::parse(JsonMaybeObject<ModJson>& obj) {
|
Result<FileSetting> FileSetting::parse(JsonMaybeObject& obj) {
|
||||||
FileSetting sett;
|
FileSetting sett;
|
||||||
parseCommon(sett, obj);
|
parseCommon(sett, obj);
|
||||||
if (auto controls = obj.has("control").obj()) {
|
if (auto controls = obj.has("control").obj()) {
|
||||||
|
@ -87,13 +87,13 @@ Result<FileSetting> FileSetting::parse(JsonMaybeObject<ModJson>& obj) {
|
||||||
return Ok(sett);
|
return Ok(sett);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<ColorSetting> ColorSetting::parse(JsonMaybeObject<ModJson>& obj) {
|
Result<ColorSetting> ColorSetting::parse(JsonMaybeObject& obj) {
|
||||||
ColorSetting sett;
|
ColorSetting sett;
|
||||||
parseCommon(sett, obj);
|
parseCommon(sett, obj);
|
||||||
return Ok(sett);
|
return Ok(sett);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<ColorAlphaSetting> ColorAlphaSetting::parse(JsonMaybeObject<ModJson>& obj) {
|
Result<ColorAlphaSetting> ColorAlphaSetting::parse(JsonMaybeObject& obj) {
|
||||||
ColorAlphaSetting sett;
|
ColorAlphaSetting sett;
|
||||||
parseCommon(sett, obj);
|
parseCommon(sett, obj);
|
||||||
return Ok(sett);
|
return Ok(sett);
|
||||||
|
@ -101,7 +101,7 @@ Result<ColorAlphaSetting> ColorAlphaSetting::parse(JsonMaybeObject<ModJson>& obj
|
||||||
|
|
||||||
Result<Setting> Setting::parse(
|
Result<Setting> Setting::parse(
|
||||||
std::string const& key,
|
std::string const& key,
|
||||||
JsonMaybeValue<ModJson>& value
|
JsonMaybeValue& value
|
||||||
) {
|
) {
|
||||||
auto sett = Setting();
|
auto sett = Setting();
|
||||||
sett.m_key = key;
|
sett.m_key = key;
|
||||||
|
@ -378,7 +378,7 @@ SettingChangedEvent::SettingChangedEvent(Mod* mod, SettingValue* value)
|
||||||
// SettingChangedFilter
|
// SettingChangedFilter
|
||||||
|
|
||||||
ListenerResult SettingChangedFilter::handle(
|
ListenerResult SettingChangedFilter::handle(
|
||||||
std::function<Callback> fn, SettingChangedEvent* event
|
utils::MiniFunction<Callback> fn, SettingChangedEvent* event
|
||||||
) {
|
) {
|
||||||
if (m_modID == event->mod->getID() &&
|
if (m_modID == event->mod->getID() &&
|
||||||
(!m_targetKey || m_targetKey.value() == event->value->getKey())
|
(!m_targetKey || m_targetKey.value() == event->value->getKey())
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <Geode/loader/SettingEvent.hpp>
|
#include <Geode/loader/SettingEvent.hpp>
|
||||||
#include <Geode/loader/ModJsonTest.hpp>
|
#include <Geode/loader/ModJsonTest.hpp>
|
||||||
#include <Geode/utils/JsonValidation.hpp>
|
#include <Geode/utils/JsonValidation.hpp>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
USE_GEODE_NAMESPACE();
|
USE_GEODE_NAMESPACE();
|
||||||
|
|
17
loader/src/platform/Objcpp.mm
Normal file
17
loader/src/platform/Objcpp.mm
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// Only a single objc++ file is used because since pch doesnt work, each file adds a lot to the compile times
|
||||||
|
#include <Geode/DefaultInclude.hpp>
|
||||||
|
|
||||||
|
USE_GEODE_NAMESPACE();
|
||||||
|
|
||||||
|
#if defined(GEODE_IS_MACOS)
|
||||||
|
|
||||||
|
#include "mac/crashlog.mm"
|
||||||
|
#include "mac/FileWatcher.mm"
|
||||||
|
#include "mac/util.mm"
|
||||||
|
|
||||||
|
#elif defined(GEODE_IS_IOS)
|
||||||
|
|
||||||
|
#include "ios/FileWatcher.mm"
|
||||||
|
#include "ios/util.mm"
|
||||||
|
|
||||||
|
#endif
|
|
@ -19,7 +19,7 @@ T findSymbolOrMangled(void* dylib, char const* name, char const* mangled) {
|
||||||
|
|
||||||
Result<> Mod::Impl::loadPlatformBinary() {
|
Result<> Mod::Impl::loadPlatformBinary() {
|
||||||
auto dylib =
|
auto dylib =
|
||||||
dlopen((m_tempDirName / m_info.binaryName).string().c_str(), RTLD_LAZY);
|
dlopen((m_tempDirName / m_info.binaryName()).string().c_str(), RTLD_LAZY);
|
||||||
if (dylib) {
|
if (dylib) {
|
||||||
if (m_platformInfo) {
|
if (m_platformInfo) {
|
||||||
delete m_platformInfo;
|
delete m_platformInfo;
|
||||||
|
|
|
@ -19,7 +19,7 @@ T findSymbolOrMangled(void* dylib, char const* name, char const* mangled) {
|
||||||
|
|
||||||
Result<> Mod::Impl::loadPlatformBinary() {
|
Result<> Mod::Impl::loadPlatformBinary() {
|
||||||
auto dylib =
|
auto dylib =
|
||||||
dlopen((m_tempDirName / m_info.binaryName).string().c_str(), RTLD_LAZY);
|
dlopen((m_tempDirName / m_info.binaryName()).string().c_str(), RTLD_LAZY);
|
||||||
if (dylib) {
|
if (dylib) {
|
||||||
if (m_platformInfo) {
|
if (m_platformInfo) {
|
||||||
delete m_platformInfo;
|
delete m_platformInfo;
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
#ifdef GEODE_IS_MACOS
|
#ifdef GEODE_IS_MACOS
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <ghc/filesystem.hpp>
|
#include <ghc/fs_fwd.hpp>
|
||||||
|
|
||||||
#include <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
bool crashlog::setupPlatformHandler() {
|
bool crashlog::setupPlatformHandler() {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -6,8 +6,7 @@ namespace gd {
|
||||||
namespace {
|
namespace {
|
||||||
static inline auto emptyInternalString() {
|
static inline auto emptyInternalString() {
|
||||||
return reinterpret_cast<_internal_string*>(
|
return reinterpret_cast<_internal_string*>(
|
||||||
*reinterpret_cast<uintptr_t*>(geode::base::get() + 0x6030d0) +
|
*reinterpret_cast<uintptr_t*>(geode::base::get() + 0x6030d0) + sizeof(_internal_string)
|
||||||
sizeof(_internal_string)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,11 +49,253 @@ namespace gd {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool string::operator==(string const& other) const {
|
bool string::operator<(string const& other) const {
|
||||||
if (size() != other.size()) return false;
|
return std::string(*this) < std::string(other);
|
||||||
return strcmp(c_str(), other.c_str()) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool string::operator==(string const& other) const {
|
||||||
|
return std::string(*this) == std::string(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _rb_tree_rotate_left(_rb_tree_base* const x, _rb_tree_base*& root) {
|
||||||
|
_rb_tree_base* const y = x->m_right;
|
||||||
|
|
||||||
|
x->m_right = y->m_left;
|
||||||
|
if (y->m_left != 0) y->m_left->m_parent = x;
|
||||||
|
y->m_parent = x->m_parent;
|
||||||
|
|
||||||
|
if (x == root) root = y;
|
||||||
|
else if (x == x->m_parent->m_left) x->m_parent->m_left = y;
|
||||||
|
else x->m_parent->m_right = y;
|
||||||
|
y->m_left = x;
|
||||||
|
x->m_parent = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _rb_tree_rotate_right(_rb_tree_base* const x, _rb_tree_base*& root) {
|
||||||
|
_rb_tree_base* const y = x->m_left;
|
||||||
|
|
||||||
|
x->m_left = y->m_right;
|
||||||
|
if (y->m_right != 0) y->m_right->m_parent = x;
|
||||||
|
y->m_parent = x->m_parent;
|
||||||
|
|
||||||
|
if (x == root) root = y;
|
||||||
|
else if (x == x->m_parent->m_right) x->m_parent->m_right = y;
|
||||||
|
else x->m_parent->m_left = y;
|
||||||
|
y->m_right = x;
|
||||||
|
x->m_parent = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _rb_insert_rebalance(
|
||||||
|
bool const insert_left, _rb_tree_base* x, _rb_tree_base* p, _rb_tree_base& header
|
||||||
|
) {
|
||||||
|
_rb_tree_base*& root = header.m_parent;
|
||||||
|
|
||||||
|
x->m_parent = p;
|
||||||
|
x->m_left = 0;
|
||||||
|
x->m_right = 0;
|
||||||
|
x->m_isblack = false;
|
||||||
|
|
||||||
|
if (insert_left) {
|
||||||
|
p->m_left = x;
|
||||||
|
|
||||||
|
if (p == &header) {
|
||||||
|
header.m_parent = x;
|
||||||
|
header.m_right = x;
|
||||||
|
}
|
||||||
|
else if (p == header.m_left) {
|
||||||
|
header.m_left = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p->m_right = x;
|
||||||
|
|
||||||
|
if (p == header.m_right) {
|
||||||
|
header.m_right = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (x != root && x->m_parent->m_isblack == false) {
|
||||||
|
_rb_tree_base* const xpp = x->m_parent->m_parent;
|
||||||
|
|
||||||
|
if (x->m_parent == xpp->m_left) {
|
||||||
|
_rb_tree_base* const y = xpp->m_right;
|
||||||
|
if (y && y->m_isblack == false) {
|
||||||
|
x->m_parent->m_isblack = true;
|
||||||
|
y->m_isblack = true;
|
||||||
|
xpp->m_isblack = false;
|
||||||
|
x = xpp;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (x == x->m_parent->m_right) {
|
||||||
|
x = x->m_parent;
|
||||||
|
_rb_tree_rotate_left(x, root);
|
||||||
|
}
|
||||||
|
x->m_parent->m_isblack = true;
|
||||||
|
xpp->m_isblack = false;
|
||||||
|
_rb_tree_rotate_right(xpp, root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_rb_tree_base* const y = xpp->m_left;
|
||||||
|
if (y && y->m_isblack == false) {
|
||||||
|
x->m_parent->m_isblack = true;
|
||||||
|
y->m_isblack = true;
|
||||||
|
xpp->m_isblack = false;
|
||||||
|
x = xpp;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (x == x->m_parent->m_left) {
|
||||||
|
x = x->m_parent;
|
||||||
|
_rb_tree_rotate_right(x, root);
|
||||||
|
}
|
||||||
|
x->m_parent->m_isblack = true;
|
||||||
|
xpp->m_isblack = false;
|
||||||
|
_rb_tree_rotate_left(xpp, root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
root->m_isblack = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static _rb_tree_base* _rb_increment(_rb_tree_base* __x) throw() {
|
||||||
|
if (__x->m_right != 0) {
|
||||||
|
__x = __x->m_right;
|
||||||
|
while (__x->m_left != 0)
|
||||||
|
__x = __x->m_left;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_rb_tree_base* __y = __x->m_parent;
|
||||||
|
while (__x == __y->m_right) {
|
||||||
|
__x = __y;
|
||||||
|
__y = __y->m_parent;
|
||||||
|
}
|
||||||
|
if (__x->m_right != __y) __x = __y;
|
||||||
|
}
|
||||||
|
return __x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static _rb_tree_base* _rb_decrement(_rb_tree_base* __x) throw() {
|
||||||
|
if (!__x->m_isblack && __x->m_parent->m_parent == __x) __x = __x->m_right;
|
||||||
|
else if (__x->m_left != 0) {
|
||||||
|
_rb_tree_base* __y = __x->m_left;
|
||||||
|
while (__y->m_right != 0)
|
||||||
|
__y = __y->m_right;
|
||||||
|
__x = __y;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_rb_tree_base* __y = __x->m_parent;
|
||||||
|
while (__x == __y->m_left) {
|
||||||
|
__x = __y;
|
||||||
|
__y = __y->m_parent;
|
||||||
|
}
|
||||||
|
__x = __y;
|
||||||
|
}
|
||||||
|
return __x;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class V>
|
||||||
|
std::map<K, V> map<K, V>::std() {
|
||||||
|
return (std::map<K, V>)(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class V>
|
||||||
|
map<K, V>::operator std::map<K, V>() {
|
||||||
|
auto iter_node = static_cast<_tree_node>(m_header.m_left);
|
||||||
|
auto end_node = static_cast<_tree_node>(&m_header);
|
||||||
|
std::map<K, V> out;
|
||||||
|
for (; iter_node != end_node; iter_node = static_cast<_tree_node>(_rb_increment(iter_node))) {
|
||||||
|
out[iter_node->m_value.first] = iter_node->m_value.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class V>
|
||||||
|
map<K, V>::operator std::map<K, V>() const {
|
||||||
|
auto iter_node = static_cast<_tree_node>(m_header.m_left);
|
||||||
|
auto end_node = (_tree_node)(&m_header);
|
||||||
|
std::map<K, V> out;
|
||||||
|
for (; iter_node != end_node; iter_node = static_cast<_tree_node>(_rb_increment(iter_node))) {
|
||||||
|
out[iter_node->m_value.first] = iter_node->m_value.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class V>
|
||||||
|
void map<K, V>::insert(_tree_node x, _tree_node p, std::pair<K, V> const& val) {
|
||||||
|
bool insert_left =
|
||||||
|
(x != 0 || p == static_cast<_tree_node>(&m_header) || val.first < p->m_value.first);
|
||||||
|
|
||||||
|
_tree_node z = new _rb_tree_node<std::pair<K, V>>();
|
||||||
|
z->m_value = val;
|
||||||
|
|
||||||
|
_rb_insert_rebalance(insert_left, z, p, m_header);
|
||||||
|
++m_nodecount;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class V>
|
||||||
|
void map<K, V>::insert_pair(std::pair<K, V> const& val) {
|
||||||
|
_tree_node x = static_cast<_tree_node>(m_header.m_parent);
|
||||||
|
_tree_node y = static_cast<_tree_node>(&m_header);
|
||||||
|
bool comp = true;
|
||||||
|
while (x != 0) {
|
||||||
|
y = x;
|
||||||
|
comp = val.first < x->m_value.first;
|
||||||
|
x = comp ? static_cast<_tree_node>(x->m_left) : static_cast<_tree_node>(x->m_right);
|
||||||
|
}
|
||||||
|
auto iter = y;
|
||||||
|
|
||||||
|
if (comp) {
|
||||||
|
if (iter == static_cast<_tree_node>(m_header.m_left)) {
|
||||||
|
insert(x, y, val);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
iter = static_cast<_tree_node>(_rb_decrement(iter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (iter->m_value.first < val.first) {
|
||||||
|
insert(x, y, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class V>
|
||||||
|
map<K, V>::map(std::map<K, V> input) {
|
||||||
|
m_header.m_isblack = false;
|
||||||
|
m_header.m_parent = 0;
|
||||||
|
m_header.m_left = &m_header;
|
||||||
|
m_header.m_right = &m_header;
|
||||||
|
|
||||||
|
for (auto i : input) {
|
||||||
|
insert_pair(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class V>
|
||||||
|
void map<K, V>::erase(_tree_node x) {
|
||||||
|
while (x != 0) {
|
||||||
|
erase(static_cast<_tree_node>(x->m_right));
|
||||||
|
auto y = static_cast<_tree_node>(x->m_left);
|
||||||
|
delete y;
|
||||||
|
x = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class V>
|
||||||
|
map<K, V>::map(map const& lol) : map(std::map<K, V>(lol)) {}
|
||||||
|
|
||||||
|
template <class K, class V>
|
||||||
|
map<K, V>::map() : map(std::map<K, V>()) {}
|
||||||
|
|
||||||
|
template <class K, class V>
|
||||||
|
map<K, V>::~map() {
|
||||||
|
erase(static_cast<_tree_node>(m_header.m_parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
template class map<int, int>;
|
||||||
|
template class map<gd::string, gd::string>;
|
||||||
|
template class map<gd::string, bool>;
|
||||||
|
template class map<short, bool>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
USE_GEODE_NAMESPACE();
|
USE_GEODE_NAMESPACE();
|
||||||
|
|
||||||
#include <AppKit/AppKit.h>
|
#import <AppKit/AppKit.h>
|
||||||
#include <Geode/utils/web.hpp>
|
#include <Geode/utils/web.hpp>
|
||||||
#include <Geode/utils/file.hpp>
|
#include <Geode/utils/file.hpp>
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ std::string getLastWinError() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<> Mod::Impl::loadPlatformBinary() {
|
Result<> Mod::Impl::loadPlatformBinary() {
|
||||||
auto load = LoadLibraryW((m_tempDirName / m_info.binaryName).wstring().c_str());
|
auto load = LoadLibraryW((m_tempDirName / m_info.binaryName()).wstring().c_str());
|
||||||
if (load) {
|
if (load) {
|
||||||
if (m_platformInfo) {
|
if (m_platformInfo) {
|
||||||
delete m_platformInfo;
|
delete m_platformInfo;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
USE_GEODE_NAMESPACE();
|
USE_GEODE_NAMESPACE();
|
||||||
|
|
||||||
#include "nfdwin.hpp"
|
#include "nfdwin.hpp"
|
||||||
#include <ghc/filesystem.hpp>
|
#include <ghc/fs_fwd.hpp>
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <shlwapi.h>
|
#include <shlwapi.h>
|
||||||
|
|
|
@ -14,19 +14,19 @@ void geode::openModsList() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void geode::openIssueReportPopup(Mod* mod) {
|
void geode::openIssueReportPopup(Mod* mod) {
|
||||||
if (mod->getModInfo().issues) {
|
if (mod->getModInfo().issues()) {
|
||||||
MDPopup::create(
|
MDPopup::create(
|
||||||
"Issue Report",
|
"Issue Report",
|
||||||
mod->getModInfo().issues.value().info +
|
mod->getModInfo().issues().value().info +
|
||||||
"\n\n"
|
"\n\n"
|
||||||
"If your issue relates to a <cr>game crash</c>, <cb>please include</c> the "
|
"If your issue relates to a <cr>game crash</c>, <cb>please include</c> the "
|
||||||
"latest crash log(s) from `" +
|
"latest crash log(s) from `" +
|
||||||
dirs::getCrashlogsDir().string() + "`",
|
dirs::getCrashlogsDir().string() + "`",
|
||||||
"OK", (mod->getModInfo().issues.value().url ? "Open URL" : ""),
|
"OK", (mod->getModInfo().issues().value().url ? "Open URL" : ""),
|
||||||
[mod](bool btn2) {
|
[mod](bool btn2) {
|
||||||
if (btn2) {
|
if (btn2) {
|
||||||
web::openLinkInBrowser(
|
web::openLinkInBrowser(
|
||||||
mod->getModInfo().issues.value().url.value()
|
mod->getModInfo().issues().value().url.value()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ bool DevProfilePopup::setup(std::string const& developer) {
|
||||||
|
|
||||||
// index mods
|
// index mods
|
||||||
for (auto& item : Index::get()->getItemsByDeveloper(developer)) {
|
for (auto& item : Index::get()->getItemsByDeveloper(developer)) {
|
||||||
if (Loader::get()->isModInstalled(item->info.id)) {
|
if (Loader::get()->isModInstalled(item->info.id())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
items->addObject(IndexItemCell::create(
|
items->addObject(IndexItemCell::create(
|
||||||
|
|
|
@ -49,7 +49,7 @@ bool ModInfoPopup::init(ModInfo const& info, ModListLayer* list) {
|
||||||
constexpr float logoSize = 40.f;
|
constexpr float logoSize = 40.f;
|
||||||
constexpr float logoOffset = 10.f;
|
constexpr float logoOffset = 10.f;
|
||||||
|
|
||||||
auto nameLabel = CCLabelBMFont::create(info.name.c_str(), "bigFont.fnt");
|
auto nameLabel = CCLabelBMFont::create(info.name().c_str(), "bigFont.fnt");
|
||||||
nameLabel->setAnchorPoint({ .0f, .5f });
|
nameLabel->setAnchorPoint({ .0f, .5f });
|
||||||
nameLabel->limitLabelWidth(200.f, .7f, .1f);
|
nameLabel->limitLabelWidth(200.f, .7f, .1f);
|
||||||
m_mainLayer->addChild(nameLabel, 2);
|
m_mainLayer->addChild(nameLabel, 2);
|
||||||
|
@ -57,7 +57,7 @@ bool ModInfoPopup::init(ModInfo const& info, ModListLayer* list) {
|
||||||
auto logoSpr = this->createLogo({logoSize, logoSize});
|
auto logoSpr = this->createLogo({logoSize, logoSize});
|
||||||
m_mainLayer->addChild(logoSpr);
|
m_mainLayer->addChild(logoSpr);
|
||||||
|
|
||||||
auto developerStr = "by " + info.developer;
|
auto developerStr = "by " + info.developer();
|
||||||
auto developerLabel = CCLabelBMFont::create(developerStr.c_str(), "goldFont.fnt");
|
auto developerLabel = CCLabelBMFont::create(developerStr.c_str(), "goldFont.fnt");
|
||||||
developerLabel->setScale(.5f);
|
developerLabel->setScale(.5f);
|
||||||
developerLabel->setAnchorPoint({.0f, .5f});
|
developerLabel->setAnchorPoint({.0f, .5f});
|
||||||
|
@ -78,7 +78,7 @@ bool ModInfoPopup::init(ModInfo const& info, ModListLayer* list) {
|
||||||
);
|
);
|
||||||
|
|
||||||
auto versionLabel = CCLabelBMFont::create(
|
auto versionLabel = CCLabelBMFont::create(
|
||||||
info.version.toString().c_str(),
|
info.version().toString().c_str(),
|
||||||
"bigFont.fnt"
|
"bigFont.fnt"
|
||||||
);
|
);
|
||||||
versionLabel->setAnchorPoint({ .0f, .5f });
|
versionLabel->setAnchorPoint({ .0f, .5f });
|
||||||
|
@ -94,7 +94,7 @@ bool ModInfoPopup::init(ModInfo const& info, ModListLayer* list) {
|
||||||
this->registerWithTouchDispatcher();
|
this->registerWithTouchDispatcher();
|
||||||
|
|
||||||
m_detailsArea = MDTextArea::create(
|
m_detailsArea = MDTextArea::create(
|
||||||
(info.details ? info.details.value() : "### No description provided."),
|
(info.details() ? info.details().value() : "### No description provided."),
|
||||||
{ 350.f, 137.5f }
|
{ 350.f, 137.5f }
|
||||||
);
|
);
|
||||||
m_detailsArea->setPosition(
|
m_detailsArea->setPosition(
|
||||||
|
@ -111,8 +111,8 @@ bool ModInfoPopup::init(ModInfo const& info, ModListLayer* list) {
|
||||||
m_mainLayer->addChild(m_scrollbar);
|
m_mainLayer->addChild(m_scrollbar);
|
||||||
|
|
||||||
// changelog
|
// changelog
|
||||||
if (info.changelog) {
|
if (info.changelog()) {
|
||||||
m_changelogArea = MDTextArea::create(info.changelog.value(), { 350.f, 137.5f });
|
m_changelogArea = MDTextArea::create(info.changelog().value(), { 350.f, 137.5f });
|
||||||
m_changelogArea->setPosition(
|
m_changelogArea->setPosition(
|
||||||
-5000.f, winSize.height / 2 - m_changelogArea->getScaledContentSize().height / 2 - 20.f
|
-5000.f, winSize.height / 2 - m_changelogArea->getScaledContentSize().height / 2 - 20.f
|
||||||
);
|
);
|
||||||
|
@ -155,7 +155,7 @@ bool ModInfoPopup::init(ModInfo const& info, ModListLayer* list) {
|
||||||
m_buttonMenu->addChild(m_infoBtn);
|
m_buttonMenu->addChild(m_infoBtn);
|
||||||
|
|
||||||
// repo button
|
// repo button
|
||||||
if (info.repository) {
|
if (info.repository()) {
|
||||||
auto repoBtn = CCMenuItemSpriteExtra::create(
|
auto repoBtn = CCMenuItemSpriteExtra::create(
|
||||||
CCSprite::createWithSpriteFrameName("github.png"_spr),
|
CCSprite::createWithSpriteFrameName("github.png"_spr),
|
||||||
this,
|
this,
|
||||||
|
@ -166,7 +166,7 @@ bool ModInfoPopup::init(ModInfo const& info, ModListLayer* list) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// support button
|
// support button
|
||||||
if (info.supportInfo) {
|
if (info.supportInfo()) {
|
||||||
auto supportBtn = CCMenuItemSpriteExtra::create(
|
auto supportBtn = CCMenuItemSpriteExtra::create(
|
||||||
CCSprite::createWithSpriteFrameName("gift.png"_spr),
|
CCSprite::createWithSpriteFrameName("gift.png"_spr),
|
||||||
this,
|
this,
|
||||||
|
@ -192,30 +192,30 @@ bool ModInfoPopup::init(ModInfo const& info, ModListLayer* list) {
|
||||||
|
|
||||||
void ModInfoPopup::onSupport(CCObject*) {
|
void ModInfoPopup::onSupport(CCObject*) {
|
||||||
MDPopup::create(
|
MDPopup::create(
|
||||||
"Support " + this->getModInfo().name,
|
"Support " + this->getModInfo().name(),
|
||||||
this->getModInfo().supportInfo.value(),
|
this->getModInfo().supportInfo().value(),
|
||||||
"OK"
|
"OK"
|
||||||
)->show();
|
)->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModInfoPopup::onRepository(CCObject*) {
|
void ModInfoPopup::onRepository(CCObject*) {
|
||||||
web::openLinkInBrowser(this->getModInfo().repository.value());
|
web::openLinkInBrowser(this->getModInfo().repository().value());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModInfoPopup::onInfo(CCObject*) {
|
void ModInfoPopup::onInfo(CCObject*) {
|
||||||
auto info = this->getModInfo();
|
auto info = this->getModInfo();
|
||||||
FLAlertLayer::create(
|
FLAlertLayer::create(
|
||||||
nullptr,
|
nullptr,
|
||||||
("About " + info.name).c_str(),
|
("About " + info.name()).c_str(),
|
||||||
fmt::format(
|
fmt::format(
|
||||||
"<cr>ID: {}</c>\n"
|
"<cr>ID: {}</c>\n"
|
||||||
"<cg>Version: {}</c>\n"
|
"<cg>Version: {}</c>\n"
|
||||||
"<cp>Developer: {}</c>\n"
|
"<cp>Developer: {}</c>\n"
|
||||||
"<cb>Path: {}</c>\n",
|
"<cb>Path: {}</c>\n",
|
||||||
info.id,
|
info.id(),
|
||||||
info.version.toString(),
|
info.version().toString(),
|
||||||
info.developer,
|
info.developer(),
|
||||||
info.path.string()
|
info.path().string()
|
||||||
),
|
),
|
||||||
"OK",
|
"OK",
|
||||||
nullptr,
|
nullptr,
|
||||||
|
@ -357,7 +357,7 @@ bool LocalModInfoPopup::init(Mod* mod, ModListLayer* list) {
|
||||||
m_mainLayer->addChild(m_installStatus);
|
m_mainLayer->addChild(m_installStatus);
|
||||||
|
|
||||||
m_updateVersionLabel = CCLabelBMFont::create(
|
m_updateVersionLabel = CCLabelBMFont::create(
|
||||||
("Available: " + indexItem->info.version.toString()).c_str(),
|
("Available: " + indexItem->info.version().toString()).c_str(),
|
||||||
"bigFont.fnt"
|
"bigFont.fnt"
|
||||||
);
|
);
|
||||||
m_updateVersionLabel->setScale(.35f);
|
m_updateVersionLabel->setScale(.35f);
|
||||||
|
@ -369,7 +369,7 @@ bool LocalModInfoPopup::init(Mod* mod, ModListLayer* list) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// issue report button
|
// issue report button
|
||||||
if (mod->getModInfo().issues) {
|
if (mod->getModInfo().issues()) {
|
||||||
auto issuesBtnSpr = ButtonSprite::create(
|
auto issuesBtnSpr = ButtonSprite::create(
|
||||||
"Report an Issue", "goldFont.fnt", "GJ_button_04.png", .8f
|
"Report an Issue", "goldFont.fnt", "GJ_button_04.png", .8f
|
||||||
);
|
);
|
||||||
|
@ -526,7 +526,7 @@ IndexItemInfoPopup::IndexItemInfoPopup()
|
||||||
|
|
||||||
bool IndexItemInfoPopup::init(IndexItemHandle item, ModListLayer* list) {
|
bool IndexItemInfoPopup::init(IndexItemHandle item, ModListLayer* list) {
|
||||||
m_item = item;
|
m_item = item;
|
||||||
m_installListener.setFilter(m_item->info.id);
|
m_installListener.setFilter(m_item->info.id());
|
||||||
|
|
||||||
auto winSize = CCDirector::sharedDirector()->getWinSize();
|
auto winSize = CCDirector::sharedDirector()->getWinSize();
|
||||||
|
|
||||||
|
@ -613,7 +613,7 @@ void IndexItemInfoPopup::onInstall(CCObject*) {
|
||||||
[](IndexItemHandle handle) {
|
[](IndexItemHandle handle) {
|
||||||
return fmt::format(
|
return fmt::format(
|
||||||
" - <cr>{}</c> (<cy>{}</c>)",
|
" - <cr>{}</c> (<cy>{}</c>)",
|
||||||
handle->info.name, handle->info.id
|
handle->info.name(), handle->info.id()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
|
|
@ -45,9 +45,9 @@ void ModListCell::setupInfo(
|
||||||
|
|
||||||
bool hasDesc =
|
bool hasDesc =
|
||||||
display == ModListDisplay::Expanded &&
|
display == ModListDisplay::Expanded &&
|
||||||
info.description.has_value();
|
info.description().has_value();
|
||||||
|
|
||||||
auto titleLabel = CCLabelBMFont::create(info.name.c_str(), "bigFont.fnt");
|
auto titleLabel = CCLabelBMFont::create(info.name().c_str(), "bigFont.fnt");
|
||||||
titleLabel->setAnchorPoint({ .0f, .5f });
|
titleLabel->setAnchorPoint({ .0f, .5f });
|
||||||
titleLabel->setPositionX(m_height / 2 + logoSize / 2 + 13.f);
|
titleLabel->setPositionX(m_height / 2 + logoSize / 2 + 13.f);
|
||||||
if (hasDesc && spaceForTags) {
|
if (hasDesc && spaceForTags) {
|
||||||
|
@ -66,7 +66,7 @@ void ModListCell::setupInfo(
|
||||||
this->addChild(titleLabel);
|
this->addChild(titleLabel);
|
||||||
|
|
||||||
auto versionLabel = CCLabelBMFont::create(
|
auto versionLabel = CCLabelBMFont::create(
|
||||||
info.version.toString(false).c_str(),
|
info.version().toString(false).c_str(),
|
||||||
"bigFont.fnt"
|
"bigFont.fnt"
|
||||||
);
|
);
|
||||||
versionLabel->setAnchorPoint({ .0f, .5f });
|
versionLabel->setAnchorPoint({ .0f, .5f });
|
||||||
|
@ -78,7 +78,7 @@ void ModListCell::setupInfo(
|
||||||
versionLabel->setColor({ 0, 255, 0 });
|
versionLabel->setColor({ 0, 255, 0 });
|
||||||
this->addChild(versionLabel);
|
this->addChild(versionLabel);
|
||||||
|
|
||||||
if (auto tag = info.version.getTag()) {
|
if (auto tag = info.version().getTag()) {
|
||||||
auto tagLabel = TagNode::create(
|
auto tagLabel = TagNode::create(
|
||||||
versionTagToString(tag.value()).c_str()
|
versionTagToString(tag.value()).c_str()
|
||||||
);
|
);
|
||||||
|
@ -92,7 +92,7 @@ void ModListCell::setupInfo(
|
||||||
this->addChild(tagLabel);
|
this->addChild(tagLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto creatorStr = "by " + info.developer;
|
auto creatorStr = "by " + info.developer();
|
||||||
auto creatorLabel = CCLabelBMFont::create(creatorStr.c_str(), "goldFont.fnt");
|
auto creatorLabel = CCLabelBMFont::create(creatorStr.c_str(), "goldFont.fnt");
|
||||||
creatorLabel->setScale(.43f);
|
creatorLabel->setScale(.43f);
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ void ModListCell::setupInfo(
|
||||||
descBG->setScale(.25f);
|
descBG->setScale(.25f);
|
||||||
this->addChild(descBG);
|
this->addChild(descBG);
|
||||||
|
|
||||||
m_description = CCLabelBMFont::create(info.description.value().c_str(), "chatFont.fnt");
|
m_description = CCLabelBMFont::create(info.description().value().c_str(), "chatFont.fnt");
|
||||||
m_description->setAnchorPoint({ .0f, .5f });
|
m_description->setAnchorPoint({ .0f, .5f });
|
||||||
m_description->setPosition(m_height / 2 + logoSize / 2 + 18.f, descBG->getPositionY());
|
m_description->setPosition(m_height / 2 + logoSize / 2 + 18.f, descBG->getPositionY());
|
||||||
m_description->limitLabelWidth(m_width / 2 - 10.f, .5f, .1f);
|
m_description->limitLabelWidth(m_width / 2 - 10.f, .5f, .1f);
|
||||||
|
@ -354,7 +354,7 @@ bool IndexItemCell::init(
|
||||||
void IndexItemCell::updateState() {}
|
void IndexItemCell::updateState() {}
|
||||||
|
|
||||||
std::string IndexItemCell::getDeveloper() const {
|
std::string IndexItemCell::getDeveloper() const {
|
||||||
return m_item->info.developer;
|
return m_item->info.developer();
|
||||||
}
|
}
|
||||||
|
|
||||||
CCNode* IndexItemCell::createLogo(CCSize const& size) {
|
CCNode* IndexItemCell::createLogo(CCSize const& size) {
|
||||||
|
|
|
@ -52,11 +52,11 @@ static std::optional<int> queryMatchKeywords(
|
||||||
// fuzzy match keywords
|
// fuzzy match keywords
|
||||||
if (query.keywords) {
|
if (query.keywords) {
|
||||||
bool someMatched = false;
|
bool someMatched = false;
|
||||||
WEIGHTED_MATCH(info.name, 2);
|
WEIGHTED_MATCH(info.name(), 2);
|
||||||
WEIGHTED_MATCH(info.id, 1.5);
|
WEIGHTED_MATCH(info.id(), 1.5);
|
||||||
WEIGHTED_MATCH(info.developer, 1);
|
WEIGHTED_MATCH(info.developer(), 1);
|
||||||
WEIGHTED_MATCH(info.details.value_or(""), 2);
|
WEIGHTED_MATCH(info.details().value_or(""), 2);
|
||||||
WEIGHTED_MATCH(info.description.value_or(""), 1);
|
WEIGHTED_MATCH(info.description().value_or(""), 1);
|
||||||
if (!someMatched) {
|
if (!someMatched) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ static std::optional<int> queryMatchKeywords(
|
||||||
// sorted, at least enough so that if you're scrolling it based on
|
// sorted, at least enough so that if you're scrolling it based on
|
||||||
// alphabetical order you will find the part you're looking for easily
|
// alphabetical order you will find the part you're looking for easily
|
||||||
// so it's fine
|
// so it's fine
|
||||||
weighted = -tolower(info.name[0]);
|
weighted = -tolower(info.name()[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// empty keywords always match
|
// empty keywords always match
|
||||||
|
@ -83,7 +83,7 @@ static std::optional<int> queryMatch(ModListQuery const& query, Mod* mod) {
|
||||||
static std::optional<int> queryMatch(ModListQuery const& query, IndexItemHandle item) {
|
static std::optional<int> queryMatch(ModListQuery const& query, IndexItemHandle item) {
|
||||||
// if no force visibility was provided and item is already installed, don't
|
// if no force visibility was provided and item is already installed, don't
|
||||||
// show it
|
// show it
|
||||||
if (!query.forceVisibility && Loader::get()->isModInstalled(item->info.id)) {
|
if (!query.forceVisibility && Loader::get()->isModInstalled(item->info.id())) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
// make sure all tags match
|
// make sure all tags match
|
||||||
|
|
|
@ -8,7 +8,7 @@ AEnterLayerEvent::AEnterLayerEvent(
|
||||||
) : layerID(layerID),
|
) : layerID(layerID),
|
||||||
layer(layer) {}
|
layer(layer) {}
|
||||||
|
|
||||||
ListenerResult AEnterLayerFilter::handle(std::function<Callback> fn, AEnterLayerEvent* event) {
|
ListenerResult AEnterLayerFilter::handle(utils::MiniFunction<Callback> fn, AEnterLayerEvent* event) {
|
||||||
if (m_targetID == event->layerID) {
|
if (m_targetID == event->layerID) {
|
||||||
fn(event);
|
fn(event);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ USE_GEODE_NAMESPACE();
|
||||||
|
|
||||||
bool MDPopup::setup(
|
bool MDPopup::setup(
|
||||||
std::string const& title, std::string const& info, char const* btn1Text, char const* btn2Text,
|
std::string const& title, std::string const& info, char const* btn1Text, char const* btn2Text,
|
||||||
std::function<void(bool)> onClick
|
utils::MiniFunction<void(bool)> onClick
|
||||||
) {
|
) {
|
||||||
this->setTitle(title.c_str(), "goldFont.fnt", .9f, 33.f);
|
this->setTitle(title.c_str(), "goldFont.fnt", .9f, 33.f);
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ float MDPopup::estimateHeight(std::string const& content) {
|
||||||
|
|
||||||
MDPopup* MDPopup::create(
|
MDPopup* MDPopup::create(
|
||||||
std::string const& title, std::string const& content, char const* btn1, char const* btn2,
|
std::string const& title, std::string const& content, char const* btn1, char const* btn2,
|
||||||
std::function<void(bool)> onClick
|
utils::MiniFunction<void(bool)> onClick
|
||||||
) {
|
) {
|
||||||
auto ret = new MDPopup();
|
auto ret = new MDPopup();
|
||||||
if (ret &&
|
if (ret &&
|
||||||
|
|
|
@ -2,52 +2,52 @@
|
||||||
|
|
||||||
USE_GEODE_NAMESPACE();
|
USE_GEODE_NAMESPACE();
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
Json& JsonMaybeSomething<Json>::json() {
|
json::Value& JsonMaybeSomething::json() {
|
||||||
return m_json;
|
return m_json;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
JsonMaybeSomething<Json>::JsonMaybeSomething(
|
JsonMaybeSomething::JsonMaybeSomething(
|
||||||
JsonChecker<Json>& checker, Json& json, std::string const& hierarchy, bool hasValue
|
JsonChecker& checker, json::Value& json, std::string const& hierarchy, bool hasValue
|
||||||
) :
|
) :
|
||||||
m_checker(checker),
|
m_checker(checker),
|
||||||
m_json(json), m_hierarchy(hierarchy), m_hasValue(hasValue) {}
|
m_json(json), m_hierarchy(hierarchy), m_hasValue(hasValue) {}
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
bool JsonMaybeSomething<Json>::isError() const {
|
bool JsonMaybeSomething::isError() const {
|
||||||
return m_checker.isError() || !m_hasValue;
|
return m_checker.isError() || !m_hasValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
std::string JsonMaybeSomething<Json>::getError() const {
|
std::string JsonMaybeSomething::getError() const {
|
||||||
return m_checker.getError();
|
return m_checker.getError();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
JsonMaybeSomething<Json>::operator bool() const {
|
JsonMaybeSomething::operator bool() const {
|
||||||
return !isError();
|
return !isError();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
void JsonMaybeSomething<Json>::setError(std::string const& error) {
|
void JsonMaybeSomething::setError(std::string const& error) {
|
||||||
m_checker.m_result = error;
|
m_checker.m_result = error;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
JsonMaybeValue<Json>::JsonMaybeValue(
|
|
||||||
JsonChecker<Json>& checker, Json& json, std::string const& hierarchy, bool hasValue
|
|
||||||
) :
|
|
||||||
JsonMaybeSomething<Json>(checker, json, hierarchy, hasValue) {}
|
|
||||||
|
|
||||||
template <class Json>
|
JsonMaybeValue::JsonMaybeValue(
|
||||||
JsonMaybeSomething<Json>& JsonMaybeValue<Json>::self() {
|
JsonChecker& checker, json::Value& json, std::string const& hierarchy, bool hasValue
|
||||||
return *static_cast<JsonMaybeSomething<Json>*>(this);
|
) :
|
||||||
|
JsonMaybeSomething(checker, json, hierarchy, hasValue) {}
|
||||||
|
|
||||||
|
|
||||||
|
JsonMaybeSomething& JsonMaybeValue::self() {
|
||||||
|
return *static_cast<JsonMaybeSomething*>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// template<class Json>
|
// template<class Json>
|
||||||
// template<nlohmann::detail::value_t T>
|
// template<nlohmann::detail::value_t T>
|
||||||
// JsonMaybeValue<Json>& JsonMaybeValue<Json>::as() {
|
// JsonMaybeValue& JsonMaybeValue::as() {
|
||||||
// if (this->isError()) return *this;
|
// if (this->isError()) return *this;
|
||||||
// if (!jsonConvertibleTo(self().m_json.type(), T)) {
|
// if (!jsonConvertibleTo(self().m_json.type(), T)) {
|
||||||
// this->setError(
|
// this->setError(
|
||||||
|
@ -60,15 +60,15 @@ JsonMaybeSomething<Json>& JsonMaybeValue<Json>::self() {
|
||||||
// return *this;
|
// return *this;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
JsonMaybeValue<Json>& JsonMaybeValue<Json>::array() {
|
JsonMaybeValue& JsonMaybeValue::array() {
|
||||||
this->as<value_t::Array>();
|
this->as<value_t::Array>();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// template<class Json>
|
// template<class Json>
|
||||||
// template<nlohmann::detail::value_t... T>
|
// template<nlohmann::detail::value_t... T>
|
||||||
// JsonMaybeValue<Json> JsonMaybeValue<Json>::asOneOf() {
|
// JsonMaybeValue JsonMaybeValue::asOneOf() {
|
||||||
// if (this->isError()) return *this;
|
// if (this->isError()) return *this;
|
||||||
// bool isOneOf = (... || jsonConvertibleTo(self().m_json.type(), T));
|
// bool isOneOf = (... || jsonConvertibleTo(self().m_json.type(), T));
|
||||||
// if (!isOneOf) {
|
// if (!isOneOf) {
|
||||||
|
@ -84,7 +84,7 @@ JsonMaybeValue<Json>& JsonMaybeValue<Json>::array() {
|
||||||
|
|
||||||
// template<class Json>
|
// template<class Json>
|
||||||
// template<nlohmann::detail::value_t T>
|
// template<nlohmann::detail::value_t T>
|
||||||
// JsonMaybeValue<Json> JsonMaybeValue<Json>::is() {
|
// JsonMaybeValue JsonMaybeValue::is() {
|
||||||
// if (this->isError()) return *this;
|
// if (this->isError()) return *this;
|
||||||
// self().m_hasValue = jsonConvertibleTo(self().m_json.type(), T);
|
// self().m_hasValue = jsonConvertibleTo(self().m_json.type(), T);
|
||||||
// m_inferType = false;
|
// m_inferType = false;
|
||||||
|
@ -93,7 +93,7 @@ JsonMaybeValue<Json>& JsonMaybeValue<Json>::array() {
|
||||||
|
|
||||||
// template<class Json>
|
// template<class Json>
|
||||||
// template<class T>
|
// template<class T>
|
||||||
// JsonMaybeValue<Json> JsonMaybeValue<Json>::validate(JsonValueValidator<T> validator) {
|
// JsonMaybeValue JsonMaybeValue::validate(JsonValueValidator<T> validator) {
|
||||||
// if (this->isError()) return *this;
|
// if (this->isError()) return *this;
|
||||||
// try {
|
// try {
|
||||||
// if (!validator(self().m_json.template get<T>())) {
|
// if (!validator(self().m_json.template get<T>())) {
|
||||||
|
@ -110,14 +110,14 @@ JsonMaybeValue<Json>& JsonMaybeValue<Json>::array() {
|
||||||
|
|
||||||
// template<class Json>
|
// template<class Json>
|
||||||
// template<class T>
|
// template<class T>
|
||||||
// JsonMaybeValue<Json> JsonMaybeValue<Json>::inferType() {
|
// JsonMaybeValue JsonMaybeValue::inferType() {
|
||||||
// if (this->isError() || !m_inferType) return *this;
|
// if (this->isError() || !m_inferType) return *this;
|
||||||
// return this->as<getJsonType<T>()>();
|
// return this->as<getJsonType<T>()>();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// template<class Json>
|
// template<class Json>
|
||||||
// template<class T>
|
// template<class T>
|
||||||
// JsonMaybeValue<Json> JsonMaybeValue<Json>::intoRaw(T& target) {
|
// JsonMaybeValue JsonMaybeValue::intoRaw(T& target) {
|
||||||
// if (this->isError()) return *this;
|
// if (this->isError()) return *this;
|
||||||
// target = self().m_json;
|
// target = self().m_json;
|
||||||
// return *this;
|
// return *this;
|
||||||
|
@ -125,19 +125,19 @@ JsonMaybeValue<Json>& JsonMaybeValue<Json>::array() {
|
||||||
|
|
||||||
// template<class Json>
|
// template<class Json>
|
||||||
// template<class T>
|
// template<class T>
|
||||||
// JsonMaybeValue<Json> JsonMaybeValue<Json>::into(T& target) {
|
// JsonMaybeValue JsonMaybeValue::into(T& target) {
|
||||||
// return this->intoAs<T, T>(target);
|
// return this->intoAs<T, T>(target);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// template<class Json>
|
// template<class Json>
|
||||||
// template<class T>
|
// template<class T>
|
||||||
// JsonMaybeValue<Json> JsonMaybeValue<Json>::into(std::optional<T>& target) {
|
// JsonMaybeValue JsonMaybeValue::into(std::optional<T>& target) {
|
||||||
// return this->intoAs<T, std::optional<T>>(target);
|
// return this->intoAs<T, std::optional<T>>(target);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// template<class Json>
|
// template<class Json>
|
||||||
// template<class A, class T>
|
// template<class A, class T>
|
||||||
// JsonMaybeValue<Json> JsonMaybeValue<Json>::intoAs(T& target) {
|
// JsonMaybeValue JsonMaybeValue::intoAs(T& target) {
|
||||||
// this->inferType<A>();
|
// this->inferType<A>();
|
||||||
// if (this->isError()) return *this;
|
// if (this->isError()) return *this;
|
||||||
// try {
|
// try {
|
||||||
|
@ -153,7 +153,7 @@ JsonMaybeValue<Json>& JsonMaybeValue<Json>::array() {
|
||||||
|
|
||||||
// template<class Json>
|
// template<class Json>
|
||||||
// template<class T>
|
// template<class T>
|
||||||
// T JsonMaybeValue<Json>::get() {
|
// T JsonMaybeValue::get() {
|
||||||
// this->inferType<T>();
|
// this->inferType<T>();
|
||||||
// if (this->isError()) return T();
|
// if (this->isError()) return T();
|
||||||
// try {
|
// try {
|
||||||
|
@ -167,15 +167,15 @@ JsonMaybeValue<Json>& JsonMaybeValue<Json>::array() {
|
||||||
// return T();
|
// return T();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
JsonMaybeObject<Json> JsonMaybeValue<Json>::obj() {
|
JsonMaybeObject JsonMaybeValue::obj() {
|
||||||
this->as<value_t::Object>();
|
this->as<value_t::Object>();
|
||||||
return JsonMaybeObject(self().m_checker, self().m_json, self().m_hierarchy, self().m_hasValue);
|
return JsonMaybeObject(self().m_checker, self().m_json, self().m_hierarchy, self().m_hasValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// template<class Json>
|
// template<class Json>
|
||||||
// template<class T>
|
// template<class T>
|
||||||
// struct JsonMaybeValue<Json>::Iterator {
|
// struct JsonMaybeValue::Iterator {
|
||||||
// std::vector<T> m_values;
|
// std::vector<T> m_values;
|
||||||
|
|
||||||
// using iterator = typename std::vector<T>::iterator;
|
// using iterator = typename std::vector<T>::iterator;
|
||||||
|
@ -196,8 +196,8 @@ JsonMaybeObject<Json> JsonMaybeValue<Json>::obj() {
|
||||||
// }
|
// }
|
||||||
// };
|
// };
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
JsonMaybeValue<Json> JsonMaybeValue<Json>::at(size_t i) {
|
JsonMaybeValue JsonMaybeValue::at(size_t i) {
|
||||||
this->as<value_t::Array>();
|
this->as<value_t::Array>();
|
||||||
if (this->isError()) return *this;
|
if (this->isError()) return *this;
|
||||||
|
|
||||||
|
@ -211,15 +211,15 @@ JsonMaybeValue<Json> JsonMaybeValue<Json>::at(size_t i) {
|
||||||
);
|
);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
return JsonMaybeValue<Json>(
|
return JsonMaybeValue(
|
||||||
self().m_checker, json.at(i), self().m_hierarchy + "." + std::to_string(i), self().m_hasValue
|
self().m_checker, json.at(i), self().m_hierarchy + "." + std::to_string(i), self().m_hasValue
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
typename JsonMaybeValue<Json>::template Iterator<JsonMaybeValue<Json>> JsonMaybeValue<Json>::iterate() {
|
typename JsonMaybeValue::template Iterator<JsonMaybeValue> JsonMaybeValue::iterate() {
|
||||||
this->as<value_t::Array>();
|
this->as<value_t::Array>();
|
||||||
Iterator<JsonMaybeValue<Json>> iter;
|
Iterator<JsonMaybeValue> iter;
|
||||||
if (this->isError()) return iter;
|
if (this->isError()) return iter;
|
||||||
|
|
||||||
auto& json = self().m_json.as_array();
|
auto& json = self().m_json.as_array();
|
||||||
|
@ -232,72 +232,71 @@ typename JsonMaybeValue<Json>::template Iterator<JsonMaybeValue<Json>> JsonMaybe
|
||||||
return iter;
|
return iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
typename JsonMaybeValue<Json>::template Iterator<std::pair<std::string, JsonMaybeValue<Json>>> JsonMaybeValue<
|
typename JsonMaybeValue::template Iterator<std::pair<std::string, JsonMaybeValue>> JsonMaybeValue::items() {
|
||||||
Json>::items() {
|
|
||||||
this->as<value_t::Object>();
|
this->as<value_t::Object>();
|
||||||
Iterator<std::pair<std::string, JsonMaybeValue<Json>>> iter;
|
Iterator<std::pair<std::string, JsonMaybeValue>> iter;
|
||||||
if (this->isError()) return iter;
|
if (this->isError()) return iter;
|
||||||
|
|
||||||
for (auto& [k, v] : self().m_json.as_object()) {
|
for (auto& [k, v] : self().m_json.as_object()) {
|
||||||
iter.m_values.emplace_back(
|
iter.m_values.emplace_back(
|
||||||
k,
|
k,
|
||||||
JsonMaybeValue<Json>(self().m_checker, v, self().m_hierarchy + "." + k, self().m_hasValue)
|
JsonMaybeValue(self().m_checker, v, self().m_hierarchy + "." + k, self().m_hasValue)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return iter;
|
return iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
JsonMaybeObject<Json>::JsonMaybeObject(
|
|
||||||
JsonChecker<Json>& checker, Json& json, std::string const& hierarchy, bool hasValue
|
|
||||||
) :
|
|
||||||
JsonMaybeSomething<Json>(checker, json, hierarchy, hasValue) {}
|
|
||||||
|
|
||||||
template <class Json>
|
JsonMaybeObject::JsonMaybeObject(
|
||||||
JsonMaybeSomething<Json>& JsonMaybeObject<Json>::self() {
|
JsonChecker& checker, json::Value& json, std::string const& hierarchy, bool hasValue
|
||||||
return *static_cast<JsonMaybeSomething<Json>*>(this);
|
) :
|
||||||
|
JsonMaybeSomething(checker, json, hierarchy, hasValue) {}
|
||||||
|
|
||||||
|
|
||||||
|
JsonMaybeSomething& JsonMaybeObject::self() {
|
||||||
|
return *static_cast<JsonMaybeSomething*>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
void JsonMaybeObject<Json>::addKnownKey(std::string const& key) {
|
void JsonMaybeObject::addKnownKey(std::string const& key) {
|
||||||
m_knownKeys.insert(key);
|
m_knownKeys.insert(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
Json& JsonMaybeObject<Json>::json() {
|
json::Value& JsonMaybeObject::json() {
|
||||||
return self().m_json;
|
return self().m_json;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
JsonMaybeValue<Json> JsonMaybeObject<Json>::emptyValue() {
|
JsonMaybeValue JsonMaybeObject::emptyValue() {
|
||||||
return JsonMaybeValue(self().m_checker, self().m_json, "", false);
|
return JsonMaybeValue(self().m_checker, self().m_json, "", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
JsonMaybeValue<Json> JsonMaybeObject<Json>::has(std::string const& key) {
|
JsonMaybeValue JsonMaybeObject::has(std::string const& key) {
|
||||||
this->addKnownKey(key);
|
this->addKnownKey(key);
|
||||||
if (this->isError()) return emptyValue();
|
if (this->isError()) return emptyValue();
|
||||||
if (!self().m_json.contains(key) || self().m_json[key].is_null()) {
|
if (!self().m_json.contains(key) || self().m_json[key].is_null()) {
|
||||||
return emptyValue();
|
return emptyValue();
|
||||||
}
|
}
|
||||||
return JsonMaybeValue<Json>(self().m_checker, self().m_json[key], key, true);
|
return JsonMaybeValue(self().m_checker, self().m_json[key], key, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
JsonMaybeValue<Json> JsonMaybeObject<Json>::needs(std::string const& key) {
|
JsonMaybeValue JsonMaybeObject::needs(std::string const& key) {
|
||||||
this->addKnownKey(key);
|
this->addKnownKey(key);
|
||||||
if (this->isError()) return emptyValue();
|
if (this->isError()) return emptyValue();
|
||||||
if (!self().m_json.contains(key)) {
|
if (!self().m_json.contains(key)) {
|
||||||
this->setError(self().m_hierarchy + " is missing required key \"" + key + "\"");
|
this->setError(self().m_hierarchy + " is missing required key \"" + key + "\"");
|
||||||
return emptyValue();
|
return emptyValue();
|
||||||
}
|
}
|
||||||
return JsonMaybeValue<Json>(self().m_checker, self().m_json[key], key, true);
|
return JsonMaybeValue(self().m_checker, self().m_json[key], key, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
void JsonMaybeObject<Json>::checkUnknownKeys() {
|
void JsonMaybeObject::checkUnknownKeys() {
|
||||||
for (auto& [key, _] : self().m_json.as_object()) {
|
for (auto& [key, _] : self().m_json.as_object()) {
|
||||||
if (!m_knownKeys.count(key)) {
|
if (!m_knownKeys.count(key)) {
|
||||||
log::warn("{} contains unknown key \"{}\"", self().m_hierarchy, key);
|
log::warn("{} contains unknown key \"{}\"", self().m_hierarchy, key);
|
||||||
|
@ -305,40 +304,20 @@ void JsonMaybeObject<Json>::checkUnknownKeys() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
JsonChecker<Json>::JsonChecker(Json& json) : m_json(json), m_result(std::monostate()) {}
|
|
||||||
|
|
||||||
template <class Json>
|
JsonChecker::JsonChecker(json::Value& json) : m_json(json), m_result(std::monostate()) {}
|
||||||
bool JsonChecker<Json>::isError() const {
|
|
||||||
|
|
||||||
|
bool JsonChecker::isError() const {
|
||||||
return std::holds_alternative<std::string>(m_result);
|
return std::holds_alternative<std::string>(m_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
std::string JsonChecker<Json>::getError() const {
|
std::string JsonChecker::getError() const {
|
||||||
return std::get<std::string>(m_result);
|
return std::get<std::string>(m_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Json>
|
|
||||||
JsonMaybeValue<Json> JsonChecker<Json>::root(std::string const& hierarchy) {
|
JsonMaybeValue JsonChecker::root(std::string const& hierarchy) {
|
||||||
return JsonMaybeValue(*this, m_json, hierarchy, true);
|
return JsonMaybeValue(*this, m_json, hierarchy, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace geode {
|
|
||||||
|
|
||||||
template struct JsonMaybeSomething<json::Value>;
|
|
||||||
template struct JsonMaybeSomething<json::Value const>;
|
|
||||||
//template struct JsonMaybeSomething<ModJson>;
|
|
||||||
|
|
||||||
template struct JsonMaybeValue<json::Value>;
|
|
||||||
template struct JsonMaybeValue<json::Value const>;
|
|
||||||
//template struct JsonMaybeValue<ModJson>;
|
|
||||||
|
|
||||||
template struct JsonMaybeObject<json::Value>;
|
|
||||||
template struct JsonMaybeObject<json::Value const>;
|
|
||||||
//template struct JsonMaybeObject<ModJson>;
|
|
||||||
|
|
||||||
template struct JsonChecker<json::Value>;
|
|
||||||
template struct JsonChecker<json::Value const>;
|
|
||||||
//template struct JsonChecker<ModJson>;
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in a new issue