mirror of
https://github.com/geode-sdk/geode.git
synced 2025-03-22 02:45:49 -04:00
Merge branch 'main' into layout
This commit is contained in:
commit
c6919b5565
19 changed files with 512 additions and 162 deletions
7
.github/workflows/build.yml
vendored
7
.github/workflows/build.yml
vendored
|
@ -26,7 +26,7 @@ jobs:
|
|||
os: macos-latest
|
||||
prefixes: 'PATH="/usr/local/opt/ccache/libexec:$PATH"'
|
||||
extra_flags: "-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++"
|
||||
out_paths: './bin/nightly/Geode.dylib ./bin/nightly/GeodeBootstrapper.dylib'
|
||||
out_paths: './bin/nightly/Geode.dylib ./bin/nightly/GeodeBootstrapper.dylib ./loader/include/link/libfmod.dylib'
|
||||
cli_cmd: 'chmod +x $GITHUB_WORKSPACE/cli/geode'
|
||||
|
||||
name: ${{ matrix.config.name }}
|
||||
|
@ -65,13 +65,16 @@ jobs:
|
|||
run: |
|
||||
${{ matrix.config.cli_cmd }}
|
||||
echo "${{ github.workspace }}/cli" >> $GITHUB_PATH
|
||||
|
||||
- name: Configure CMake
|
||||
run: |
|
||||
${{ matrix.config.prefixes }} cmake -B ${{ github.workspace }}/build ${{ matrix.config.extra_flags }} -DGEODE_DISABLE_CLI_CALLS=ON -DCLI_PATH="${{ github.workspace }}/cli"
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd build
|
||||
cmake --build . --config RelWithDebInfo
|
||||
|
||||
- name: Move to output folder
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}
|
||||
|
@ -133,4 +136,4 @@ jobs:
|
|||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
files: ./macOS.zip ./Windows.zip ./Headers.zip
|
||||
release: Nightly
|
||||
prerelease: true
|
||||
prerelease: true
|
||||
|
|
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -1,5 +1,15 @@
|
|||
# Geode Changelog
|
||||
|
||||
## v0.6.1
|
||||
- Add `geode::cocos::switchToScene` utility for easily switching to a layer with the default fade transition
|
||||
- Add `Mod::getPackagePath` as a replacement for `Mod::getPath`
|
||||
- Add `geode/config` directory as a standardized place for mods to add their config files
|
||||
- Add `Mod::getConfigDir` for getting a mods' config directory
|
||||
- Add open config directory button to mods with a config directory
|
||||
- Add open save directory button to mods' settings popup
|
||||
- Removed deprecation from `Result` (it still will be replaced in v1.0.0, we just got tired of the warnings)
|
||||
- `JsonChecker<nlohmann::json>` and `JsonChecker<nlohmann::ordered_json>` are now defined in-source as exported symbols to speed up compilation times
|
||||
|
||||
## v0.6.0
|
||||
|
||||
- Mod resource loading has been reworked again, with the intent of adding support for texture pack loaders
|
||||
|
|
|
@ -19,6 +19,7 @@ namespace geode {
|
|||
static constexpr std::string_view GEODE_MOD_DIRECTORY = "mods";
|
||||
static constexpr std::string_view GEODE_LOG_DIRECTORY = "log";
|
||||
static constexpr std::string_view GEODE_RESOURCE_DIRECTORY = "resources";
|
||||
static constexpr std::string_view GEODE_CONFIG_DIRECTORY = "config";
|
||||
static constexpr std::string_view GEODE_TEMP_DIRECTORY = "temp";
|
||||
static constexpr std::string_view GEODE_MOD_EXTENSION = ".geode";
|
||||
|
||||
|
@ -65,7 +66,6 @@ namespace geode {
|
|||
std::vector<FailedModInfo> m_erroredMods;
|
||||
std::vector<ghc::filesystem::path> m_texturePaths;
|
||||
LoaderSettings m_loadedSettings;
|
||||
|
||||
bool m_isSetup = false;
|
||||
static bool s_unloading;
|
||||
|
||||
|
|
|
@ -344,7 +344,9 @@ namespace geode {
|
|||
std::string getDeveloper() const;
|
||||
std::optional<std::string> getDescription() const;
|
||||
std::optional<std::string> getDetails() const;
|
||||
[[deprecated("Use Mod::getPackagePath instead")]]
|
||||
std::string getPath() const;
|
||||
ghc::filesystem::path getPackagePath() const;
|
||||
VersionInfo getVersion() const;
|
||||
bool isEnabled() const;
|
||||
bool isLoaded() const;
|
||||
|
@ -355,6 +357,14 @@ namespace geode {
|
|||
ModInfo getModInfo() const;
|
||||
ghc::filesystem::path getTempDir() const;
|
||||
ghc::filesystem::path getBinaryPath() const;
|
||||
/**
|
||||
* Get the mod's save directory path
|
||||
*/
|
||||
ghc::filesystem::path getSaveDir() const;
|
||||
/**
|
||||
* Get the mod's config directory path
|
||||
*/
|
||||
ghc::filesystem::path getConfigDir() const;
|
||||
|
||||
bool hasSettings() const;
|
||||
decltype(ModInfo::m_settings) getSettings() const;
|
||||
|
@ -506,12 +516,6 @@ namespace geode {
|
|||
*/
|
||||
Result<> uninstall();
|
||||
bool isUninstalled() const;
|
||||
|
||||
/**
|
||||
* Get the mod's save directory
|
||||
* path
|
||||
*/
|
||||
ghc::filesystem::path getSaveDir() const;
|
||||
|
||||
/**
|
||||
* Return the data store object
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#define GEODE_API extern "C"
|
||||
#define GEODE_DLL
|
||||
|
||||
namespace geode {
|
||||
using dylib_t = void*;
|
||||
struct PlatformInfo {
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "../DefaultInclude.hpp"
|
||||
#include <cocos2d.h>
|
||||
|
||||
namespace cocos2d {
|
||||
class CCArray;
|
||||
class CCNode;
|
||||
|
|
|
@ -104,47 +104,38 @@ namespace geode {
|
|||
friend struct JsonMaybeObject<Json>;
|
||||
friend struct JsonMaybeValue<Json>;
|
||||
|
||||
void setError(std::string const& error);
|
||||
GEODE_DLL void setError(std::string const& error);
|
||||
|
||||
public:
|
||||
Json& json() {
|
||||
return m_json;
|
||||
}
|
||||
GEODE_DLL Json& json();
|
||||
|
||||
JsonMaybeSomething(
|
||||
GEODE_DLL JsonMaybeSomething(
|
||||
JsonChecker<Json>& checker,
|
||||
Json& json,
|
||||
std::string const& hierarchy,
|
||||
bool hasValue
|
||||
) : m_checker(checker),
|
||||
m_json(json),
|
||||
m_hierarchy(hierarchy),
|
||||
m_hasValue(hasValue) {}
|
||||
);
|
||||
|
||||
bool isError() const;
|
||||
GEODE_DLL bool isError() const;
|
||||
|
||||
operator bool() const {
|
||||
return !isError();
|
||||
}
|
||||
GEODE_DLL operator bool() const;
|
||||
};
|
||||
|
||||
template<class Json>
|
||||
struct JsonMaybeValue : public JsonMaybeSomething<Json> {
|
||||
bool m_inferType = true;
|
||||
|
||||
JsonMaybeValue(
|
||||
GEODE_DLL JsonMaybeValue(
|
||||
JsonChecker<Json>& checker,
|
||||
Json& json,
|
||||
std::string const& hierarchy,
|
||||
bool hasValue
|
||||
) : JsonMaybeSomething<Json>(checker, json, hierarchy, hasValue) {}
|
||||
);
|
||||
|
||||
JsonMaybeSomething<Json>& self() {
|
||||
return *static_cast<JsonMaybeSomething<Json>*>(this);
|
||||
}
|
||||
GEODE_DLL JsonMaybeSomething<Json>& self();
|
||||
|
||||
template<nlohmann::detail::value_t T>
|
||||
JsonMaybeValue<Json> as() {
|
||||
JsonMaybeValue<Json>& as() {
|
||||
if (this->isError()) return *this;
|
||||
if (!jsonConvertibleTo(self().m_json.type(), T)) {
|
||||
this->setError(
|
||||
|
@ -157,13 +148,10 @@ namespace geode {
|
|||
return *this;
|
||||
}
|
||||
|
||||
JsonMaybeValue<Json> array() {
|
||||
this->as<value_t::array>();
|
||||
return *this;
|
||||
}
|
||||
GEODE_DLL JsonMaybeValue<Json>& array();
|
||||
|
||||
template<nlohmann::detail::value_t... T>
|
||||
JsonMaybeValue<Json> asOneOf() {
|
||||
JsonMaybeValue<Json>& asOneOf() {
|
||||
if (this->isError()) return *this;
|
||||
bool isOneOf = (... || jsonConvertibleTo(self().m_json.type(), T));
|
||||
if (!isOneOf) {
|
||||
|
@ -178,7 +166,7 @@ namespace geode {
|
|||
}
|
||||
|
||||
template<nlohmann::detail::value_t T>
|
||||
JsonMaybeValue<Json> is() {
|
||||
JsonMaybeValue<Json>& is() {
|
||||
if (this->isError()) return *this;
|
||||
self().m_hasValue = jsonConvertibleTo(self().m_json.type(), T);
|
||||
m_inferType = false;
|
||||
|
@ -186,7 +174,7 @@ namespace geode {
|
|||
}
|
||||
|
||||
template<class T>
|
||||
JsonMaybeValue<Json> validate(JsonValueValidator<T> validator) {
|
||||
JsonMaybeValue<Json>& validate(JsonValueValidator<T> validator) {
|
||||
if (this->isError()) return *this;
|
||||
try {
|
||||
if (!validator(self().m_json.template get<T>())) {
|
||||
|
@ -202,30 +190,30 @@ namespace geode {
|
|||
}
|
||||
|
||||
template<class T>
|
||||
JsonMaybeValue<Json> inferType() {
|
||||
JsonMaybeValue<Json>& inferType() {
|
||||
if (this->isError() || !m_inferType) return *this;
|
||||
return this->as<getJsonType<T>()>();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
JsonMaybeValue<Json> intoRaw(T& target) {
|
||||
JsonMaybeValue<Json>& intoRaw(T& target) {
|
||||
if (this->isError()) return *this;
|
||||
target = self().m_json;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
JsonMaybeValue<Json> into(T& target) {
|
||||
JsonMaybeValue<Json>& into(T& target) {
|
||||
return this->intoAs<T, T>(target);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
JsonMaybeValue<Json> into(std::optional<T>& target) {
|
||||
JsonMaybeValue<Json>& into(std::optional<T>& target) {
|
||||
return this->intoAs<T, std::optional<T>>(target);
|
||||
}
|
||||
|
||||
template<class A, class T>
|
||||
JsonMaybeValue<Json> intoAs(T& target) {
|
||||
JsonMaybeValue<Json>& intoAs(T& target) {
|
||||
this->inferType<A>();
|
||||
if (this->isError()) return *this;
|
||||
try {
|
||||
|
@ -254,7 +242,7 @@ namespace geode {
|
|||
return T();
|
||||
}
|
||||
|
||||
JsonMaybeObject<Json> obj();
|
||||
GEODE_DLL JsonMaybeObject<Json> obj();
|
||||
|
||||
template<class T>
|
||||
struct Iterator {
|
||||
|
@ -278,112 +266,37 @@ namespace geode {
|
|||
}
|
||||
};
|
||||
|
||||
JsonMaybeValue<Json> at(size_t i) {
|
||||
this->as<value_t::array>();
|
||||
if (this->isError()) return *this;
|
||||
if (self().m_json.size() <= i) {
|
||||
this->setError(
|
||||
self().m_hierarchy + ": has " +
|
||||
std::to_string(self().m_json.size()) + "items "
|
||||
", expected to have at least " + std::to_string(i + 1)
|
||||
);
|
||||
return *this;
|
||||
}
|
||||
return JsonMaybeValue<Json>(
|
||||
self().m_checker, self().m_json.at(i),
|
||||
self().m_hierarchy + "." + std::to_string(i),
|
||||
self().m_hasValue
|
||||
);
|
||||
}
|
||||
GEODE_DLL JsonMaybeValue<Json> at(size_t i);
|
||||
|
||||
Iterator<JsonMaybeValue<Json>> iterate() {
|
||||
this->as<value_t::array>();
|
||||
Iterator<JsonMaybeValue<Json>> iter;
|
||||
if (this->isError()) return iter;
|
||||
size_t i = 0;
|
||||
for (auto& obj : self().m_json) {
|
||||
iter.m_values.emplace_back(
|
||||
self().m_checker, obj,
|
||||
self().m_hierarchy + "." + std::to_string(i++),
|
||||
self().m_hasValue
|
||||
);
|
||||
}
|
||||
return iter;
|
||||
}
|
||||
GEODE_DLL Iterator<JsonMaybeValue<Json>> iterate();
|
||||
|
||||
Iterator<std::pair<std::string, JsonMaybeValue<Json>>> items() {
|
||||
this->as<value_t::object>();
|
||||
Iterator<std::pair<std::string, JsonMaybeValue<Json>>> iter;
|
||||
if (this->isError()) return iter;
|
||||
|
||||
for (auto& [k, v] : self().m_json.items()) {
|
||||
iter.m_values.emplace_back(k, JsonMaybeValue<Json>(
|
||||
self().m_checker, v,
|
||||
self().m_hierarchy + "." + k,
|
||||
self().m_hasValue
|
||||
));
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
GEODE_DLL Iterator<std::pair<std::string, JsonMaybeValue<Json>>> items();
|
||||
};
|
||||
|
||||
template<class Json>
|
||||
struct JsonMaybeObject : JsonMaybeSomething<Json> {
|
||||
std::set<std::string> m_knownKeys;
|
||||
|
||||
JsonMaybeObject(
|
||||
GEODE_DLL JsonMaybeObject(
|
||||
JsonChecker<Json>& checker,
|
||||
Json& json,
|
||||
std::string const& hierarchy,
|
||||
bool hasValue
|
||||
) : JsonMaybeSomething<Json>(checker, json, hierarchy, hasValue) {}
|
||||
);
|
||||
|
||||
JsonMaybeSomething<Json>& self() {
|
||||
return *static_cast<JsonMaybeSomething<Json>*>(this);
|
||||
}
|
||||
GEODE_DLL JsonMaybeSomething<Json>& self();
|
||||
|
||||
void addKnownKey(std::string const& key) {
|
||||
m_knownKeys.insert(key);
|
||||
}
|
||||
GEODE_DLL void addKnownKey(std::string const& key);
|
||||
|
||||
Json& json() {
|
||||
return self().m_json;
|
||||
}
|
||||
GEODE_DLL Json& json();
|
||||
|
||||
JsonMaybeValue<Json> emptyValue() {
|
||||
return JsonMaybeValue(self().m_checker, self().m_json, "", false);
|
||||
}
|
||||
GEODE_DLL JsonMaybeValue<Json> emptyValue();
|
||||
|
||||
JsonMaybeValue<Json> has(std::string const& key) {
|
||||
this->addKnownKey(key);
|
||||
if (this->isError()) return emptyValue();
|
||||
if (!self().m_json.contains(key) || self().m_json[key].is_null()) {
|
||||
return emptyValue();
|
||||
}
|
||||
return JsonMaybeValue<Json>(self().m_checker, self().m_json[key], key, true);
|
||||
}
|
||||
GEODE_DLL JsonMaybeValue<Json> has(std::string const& key);
|
||||
|
||||
JsonMaybeValue<Json> needs(std::string const& key) {
|
||||
this->addKnownKey(key);
|
||||
if (this->isError()) return emptyValue();
|
||||
if (!self().m_json.contains(key)) {
|
||||
this->setError(
|
||||
self().m_hierarchy + " is missing required key \"" + key + "\""
|
||||
);
|
||||
return emptyValue();
|
||||
}
|
||||
return JsonMaybeValue<Json>(self().m_checker, self().m_json[key], key, true);
|
||||
}
|
||||
GEODE_DLL JsonMaybeValue<Json> needs(std::string const& key);
|
||||
|
||||
void checkUnknownKeys() {
|
||||
for (auto& [key, _] : self().m_json.items()) {
|
||||
if (!m_knownKeys.count(key)) {
|
||||
// log::debug(self().m_hierarchy + " contains unknown key \"" + key + "\"");
|
||||
log::debug("{} contains unknown key \"{}\"", self().m_hierarchy, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
GEODE_DLL void checkUnknownKeys();
|
||||
};
|
||||
|
||||
template<class Json = nlohmann::json>
|
||||
|
@ -391,37 +304,13 @@ namespace geode {
|
|||
std::variant<std::monostate, std::string> m_result;
|
||||
Json& m_json;
|
||||
|
||||
JsonChecker(Json& json) : m_json(json), m_result(std::monostate()) {}
|
||||
GEODE_DLL JsonChecker(Json& json);
|
||||
|
||||
bool isError() const {
|
||||
return std::holds_alternative<std::string>(m_result);
|
||||
}
|
||||
GEODE_DLL bool isError() const;
|
||||
|
||||
std::string getError() const {
|
||||
return std::get<std::string>(m_result);
|
||||
}
|
||||
GEODE_DLL std::string getError() const;
|
||||
|
||||
JsonMaybeValue<Json> root(std::string const& hierarchy) {
|
||||
return JsonMaybeValue(*this, m_json, hierarchy, true);
|
||||
}
|
||||
GEODE_DLL JsonMaybeValue<Json> root(std::string const& hierarchy);
|
||||
};
|
||||
|
||||
template<class Json>
|
||||
void JsonMaybeSomething<Json>::setError(std::string const& error) {
|
||||
m_checker.m_result = error;
|
||||
}
|
||||
|
||||
template<class Json>
|
||||
bool JsonMaybeSomething<Json>::isError() const {
|
||||
return m_checker.isError() || !m_hasValue;
|
||||
}
|
||||
|
||||
template<class Json>
|
||||
JsonMaybeObject<Json> JsonMaybeValue<Json>::obj() {
|
||||
this->as<value_t::object>();
|
||||
return JsonMaybeObject(
|
||||
self().m_checker, self().m_json,
|
||||
self().m_hierarchy, self().m_hasValue
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace geode {
|
|||
* @authors Matcool, HJfod
|
||||
*/
|
||||
template <class T = no_result, class E = std::string>
|
||||
class [[nodiscard, deprecated("Result's implementation will be replaced with geode::NewResult later")]] Result {
|
||||
class [[nodiscard]] Result {
|
||||
protected:
|
||||
bool success;
|
||||
union {
|
||||
|
@ -131,7 +131,7 @@ namespace geode {
|
|||
* @returns Successful Result
|
||||
*/
|
||||
template <class T = no_result>
|
||||
[[nodiscard, deprecated("Result's implementation will be replaced with geode::NewResult later")]]
|
||||
[[nodiscard]]
|
||||
Result<T> Ok(T value = T()) {
|
||||
return Result<T>::ok(value);
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ namespace geode {
|
|||
* @returns Errorful Result
|
||||
*/
|
||||
template <class E = std::string>
|
||||
struct [[nodiscard, deprecated("Result's implementation will be replaced with geode::NewResult later")]] Err {
|
||||
struct [[nodiscard]] Err {
|
||||
const E _value;
|
||||
Err(const TypeIdentityType<E> value) : _value(value) {}
|
||||
template <class T>
|
||||
|
|
|
@ -123,6 +123,14 @@ namespace geode::cocos {
|
|||
*/
|
||||
GEODE_DLL cocos2d::CCRect calculateChildCoverage(cocos2d::CCNode* parent);
|
||||
|
||||
/**
|
||||
* Create a CCScene from a layer and switch to it with the default fade
|
||||
* transition
|
||||
* @param layer Layer to create a scene from
|
||||
* @returns Created scene (not the fade transition)
|
||||
*/
|
||||
GEODE_DLL cocos2d::CCScene* switchToScene(cocos2d::CCLayer* layer);
|
||||
|
||||
/**
|
||||
* Rescale node to fit inside given size
|
||||
* @param node Node to rescale
|
||||
|
|
BIN
loader/include/link/libfmod.dylib
Normal file
BIN
loader/include/link/libfmod.dylib
Normal file
Binary file not shown.
BIN
loader/resources/pencil.png
Normal file
BIN
loader/resources/pencil.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 2.9 KiB |
|
@ -35,8 +35,10 @@ void Loader::createDirectories() {
|
|||
auto logDir = this->getGeodeDirectory() / GEODE_LOG_DIRECTORY;
|
||||
auto resDir = this->getGeodeDirectory() / GEODE_RESOURCE_DIRECTORY;
|
||||
auto tempDir = this->getGeodeDirectory() / GEODE_TEMP_DIRECTORY;
|
||||
auto confDir = this->getGeodeDirectory() / GEODE_CONFIG_DIRECTORY;
|
||||
|
||||
ghc::filesystem::create_directories(resDir);
|
||||
ghc::filesystem::create_directory(confDir);
|
||||
ghc::filesystem::create_directory(modDir);
|
||||
ghc::filesystem::create_directory(logDir);
|
||||
ghc::filesystem::create_directory(tempDir);
|
||||
|
|
|
@ -491,6 +491,18 @@ std::string Mod::getPath() const {
|
|||
return m_info.m_path.string();
|
||||
}
|
||||
|
||||
ghc::filesystem::path Mod::getPackagePath() const {
|
||||
return m_info.m_path;
|
||||
}
|
||||
|
||||
ghc::filesystem::path Mod::getConfigDir() const {
|
||||
auto dir = Loader::get()->getGeodeDirectory() / GEODE_CONFIG_DIRECTORY / m_info.m_id;
|
||||
if (!ghc::filesystem::exists(dir)) {
|
||||
ghc::filesystem::create_directories(dir);
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
VersionInfo Mod::getVersion() const {
|
||||
return m_info.m_version;
|
||||
}
|
||||
|
|
|
@ -281,6 +281,28 @@ bool ModInfoLayer::init(ModObject* obj, ModListView* list) {
|
|||
);
|
||||
m_buttonMenu->addChild(settingsBtn);
|
||||
|
||||
// Check if a config directory for the mod exists
|
||||
// Mod::getConfigDir auto-creates the directory for user convenience, so
|
||||
// have to do it manually
|
||||
if (ghc::filesystem::exists(
|
||||
Loader::get()->getGeodeDirectory() /
|
||||
GEODE_CONFIG_DIRECTORY / m_mod->getID()
|
||||
)) {
|
||||
auto configSpr = CircleButtonSprite::createWithSpriteFrameName(
|
||||
"pencil.png"_spr, 1.f, CircleBaseColor::Green, CircleBaseSize::Medium2
|
||||
);
|
||||
configSpr->setScale(.65f);
|
||||
|
||||
auto configBtn = CCMenuItemSpriteExtra::create(
|
||||
configSpr, this, menu_selector(ModInfoLayer::onOpenConfigDir)
|
||||
);
|
||||
configBtn->setPosition(
|
||||
-size.width / 2 + 65.f,
|
||||
-size.height / 2 + 25.f
|
||||
);
|
||||
m_buttonMenu->addChild(configBtn);
|
||||
}
|
||||
|
||||
if (!m_mod->hasSettings()) {
|
||||
settingsSpr->setColor({ 150, 150, 150 });
|
||||
settingsBtn->setTarget(
|
||||
|
@ -543,6 +565,10 @@ void ModInfoLayer::onCancelInstall(CCObject*) {
|
|||
}
|
||||
}
|
||||
|
||||
void ModInfoLayer::onOpenConfigDir(CCObject*) {
|
||||
file::openFolder(m_mod->getConfigDir());
|
||||
}
|
||||
|
||||
void ModInfoLayer::onUninstall(CCObject*) {
|
||||
auto layer = FLAlertLayer::create(
|
||||
this,
|
||||
|
|
|
@ -57,6 +57,7 @@ protected:
|
|||
void onIssues(CCObject*);
|
||||
void onRepository(CCObject*);
|
||||
void onSupport(CCObject*);
|
||||
void onOpenConfigDir(CCObject*);
|
||||
void install();
|
||||
void uninstall();
|
||||
void updateInstallStatus(std::string const& status, uint8_t progress);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <Geode/utils/cocos.hpp>
|
||||
#include <Geode/utils/convert.hpp>
|
||||
#include <Geode/binding/ButtonSprite.hpp>
|
||||
#include <Geode/loader/Mod.hpp>
|
||||
|
||||
bool ModSettingsPopup::setup(Mod* mod) {
|
||||
m_noElasticity = true;
|
||||
|
@ -143,6 +144,20 @@ bool ModSettingsPopup::setup(Mod* mod) {
|
|||
resetBtn->setPosition(-m_size.width / 2 + 45.f, -m_size.height / 2 + 20.f);
|
||||
m_buttonMenu->addChild(resetBtn);
|
||||
|
||||
auto openDirBtnSpr = ButtonSprite::create(
|
||||
"Open Folder",
|
||||
"goldFont.fnt",
|
||||
"GJ_button_05.png",
|
||||
.7f
|
||||
);
|
||||
openDirBtnSpr->setScale(.7f);
|
||||
|
||||
auto openDirBtn = CCMenuItemSpriteExtra::create(
|
||||
openDirBtnSpr, this, menu_selector(ModSettingsPopup::onOpenSaveDirectory)
|
||||
);
|
||||
openDirBtn->setPosition(m_size.width / 2 - 53.f, -m_size.height / 2 + 20.f);
|
||||
m_buttonMenu->addChild(openDirBtn);
|
||||
|
||||
this->settingValueChanged(nullptr);
|
||||
|
||||
return true;
|
||||
|
@ -216,6 +231,10 @@ void ModSettingsPopup::onClose(CCObject* sender) {
|
|||
Popup<Mod*>::onClose(sender);
|
||||
}
|
||||
|
||||
void ModSettingsPopup::onOpenSaveDirectory(CCObject*) {
|
||||
file::openFolder(m_mod->getSaveDir());
|
||||
}
|
||||
|
||||
ModSettingsPopup* ModSettingsPopup::create(Mod* mod) {
|
||||
auto ret = new ModSettingsPopup();
|
||||
if (ret && ret->init(440.f, 290.f, mod)) {
|
||||
|
|
|
@ -20,6 +20,7 @@ protected:
|
|||
void onClose(CCObject*) override;
|
||||
void onApply(CCObject*);
|
||||
void onResetAll(CCObject*);
|
||||
void onOpenSaveDirectory(CCObject*);
|
||||
|
||||
public:
|
||||
static ModSettingsPopup* create(Mod* mod);
|
||||
|
|
366
loader/src/utils/JsonValidation.cpp
Normal file
366
loader/src/utils/JsonValidation.cpp
Normal file
|
@ -0,0 +1,366 @@
|
|||
#include <Geode/utils/JsonValidation.hpp>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
template<class Json>
|
||||
Json& JsonMaybeSomething<Json>::json() {
|
||||
return m_json;
|
||||
}
|
||||
|
||||
template<class Json>
|
||||
JsonMaybeSomething<Json>::JsonMaybeSomething(
|
||||
JsonChecker<Json>& checker,
|
||||
Json& json,
|
||||
std::string const& hierarchy,
|
||||
bool hasValue
|
||||
) : m_checker(checker),
|
||||
m_json(json),
|
||||
m_hierarchy(hierarchy),
|
||||
m_hasValue(hasValue) {}
|
||||
|
||||
template<class Json>
|
||||
bool JsonMaybeSomething<Json>::isError() const {
|
||||
return m_checker.isError() || !m_hasValue;
|
||||
}
|
||||
|
||||
template<class Json>
|
||||
JsonMaybeSomething<Json>::operator bool() const {
|
||||
return !isError();
|
||||
}
|
||||
|
||||
template<class Json>
|
||||
void JsonMaybeSomething<Json>::setError(std::string const& 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>
|
||||
JsonMaybeSomething<Json>& JsonMaybeValue<Json>::self() {
|
||||
return *static_cast<JsonMaybeSomething<Json>*>(this);
|
||||
}
|
||||
|
||||
// template<class Json>
|
||||
// template<nlohmann::detail::value_t T>
|
||||
// JsonMaybeValue<Json>& JsonMaybeValue<Json>::as() {
|
||||
// if (this->isError()) return *this;
|
||||
// if (!jsonConvertibleTo(self().m_json.type(), T)) {
|
||||
// this->setError(
|
||||
// self().m_hierarchy + ": Invalid type \"" +
|
||||
// self().m_json.type_name() + "\", expected \"" +
|
||||
// jsonValueTypeToString(T) + "\""
|
||||
// );
|
||||
// }
|
||||
// m_inferType = false;
|
||||
// return *this;
|
||||
// }
|
||||
|
||||
template<class Json>
|
||||
JsonMaybeValue<Json>& JsonMaybeValue<Json>::array() {
|
||||
this->as<value_t::array>();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// template<class Json>
|
||||
// template<nlohmann::detail::value_t... T>
|
||||
// JsonMaybeValue<Json> JsonMaybeValue<Json>::asOneOf() {
|
||||
// if (this->isError()) return *this;
|
||||
// bool isOneOf = (... || jsonConvertibleTo(self().m_json.type(), T));
|
||||
// if (!isOneOf) {
|
||||
// this->setError(
|
||||
// self().m_hierarchy + ": Invalid type \"" +
|
||||
// self().m_json.type_name() + "\", expected one of \"" +
|
||||
// (jsonValueTypeToString(T), ...) + "\""
|
||||
// );
|
||||
// }
|
||||
// m_inferType = false;
|
||||
// return *this;
|
||||
// }
|
||||
|
||||
|
||||
// template<class Json>
|
||||
// template<nlohmann::detail::value_t T>
|
||||
// JsonMaybeValue<Json> JsonMaybeValue<Json>::is() {
|
||||
// if (this->isError()) return *this;
|
||||
// self().m_hasValue = jsonConvertibleTo(self().m_json.type(), T);
|
||||
// m_inferType = false;
|
||||
// return *this;
|
||||
// }
|
||||
|
||||
|
||||
// template<class Json>
|
||||
// template<class T>
|
||||
// JsonMaybeValue<Json> JsonMaybeValue<Json>::validate(JsonValueValidator<T> validator) {
|
||||
// if (this->isError()) return *this;
|
||||
// try {
|
||||
// if (!validator(self().m_json.template get<T>())) {
|
||||
// this->setError(self().m_hierarchy + ": Invalid value format");
|
||||
// }
|
||||
// } catch(...) {
|
||||
// this->setError(
|
||||
// self().m_hierarchy + ": Invalid type \"" +
|
||||
// std::string(self().m_json.type_name()) + "\""
|
||||
// );
|
||||
// }
|
||||
// return *this;
|
||||
// }
|
||||
|
||||
|
||||
// template<class Json>
|
||||
// template<class T>
|
||||
// JsonMaybeValue<Json> JsonMaybeValue<Json>::inferType() {
|
||||
// if (this->isError() || !m_inferType) return *this;
|
||||
// return this->as<getJsonType<T>()>();
|
||||
// }
|
||||
|
||||
|
||||
// template<class Json>
|
||||
// template<class T>
|
||||
// JsonMaybeValue<Json> JsonMaybeValue<Json>::intoRaw(T& target) {
|
||||
// if (this->isError()) return *this;
|
||||
// target = self().m_json;
|
||||
// return *this;
|
||||
// }
|
||||
|
||||
|
||||
// template<class Json>
|
||||
// template<class T>
|
||||
// JsonMaybeValue<Json> JsonMaybeValue<Json>::into(T& target) {
|
||||
// return this->intoAs<T, T>(target);
|
||||
// }
|
||||
|
||||
|
||||
// template<class Json>
|
||||
// template<class T>
|
||||
// JsonMaybeValue<Json> JsonMaybeValue<Json>::into(std::optional<T>& target) {
|
||||
// return this->intoAs<T, std::optional<T>>(target);
|
||||
// }
|
||||
|
||||
|
||||
// template<class Json>
|
||||
// template<class A, class T>
|
||||
// JsonMaybeValue<Json> JsonMaybeValue<Json>::intoAs(T& target) {
|
||||
// this->inferType<A>();
|
||||
// if (this->isError()) return *this;
|
||||
// try {
|
||||
// target = self().m_json.template get<A>();
|
||||
// } catch(...) {
|
||||
// this->setError(
|
||||
// self().m_hierarchy + ": Invalid type \"" +
|
||||
// std::string(self().m_json.type_name()) + "\""
|
||||
// );
|
||||
// }
|
||||
// return *this;
|
||||
// }
|
||||
|
||||
// template<class Json>
|
||||
// template<class T>
|
||||
// T JsonMaybeValue<Json>::get() {
|
||||
// this->inferType<T>();
|
||||
// if (this->isError()) return T();
|
||||
// try {
|
||||
// return self().m_json.template get<T>();
|
||||
// } catch(...) {
|
||||
// this->setError(
|
||||
// self().m_hierarchy + ": Invalid type to get \"" +
|
||||
// std::string(self().m_json.type_name()) + "\""
|
||||
// );
|
||||
// }
|
||||
// return T();
|
||||
// }
|
||||
|
||||
template<class Json>
|
||||
JsonMaybeObject<Json> JsonMaybeValue<Json>::obj() {
|
||||
this->as<value_t::object>();
|
||||
return JsonMaybeObject(
|
||||
self().m_checker, self().m_json,
|
||||
self().m_hierarchy, self().m_hasValue
|
||||
);
|
||||
}
|
||||
|
||||
// template<class Json>
|
||||
// template<class T>
|
||||
// struct JsonMaybeValue<Json>::Iterator {
|
||||
// std::vector<T> m_values;
|
||||
|
||||
// using iterator = typename std::vector<T>::iterator;
|
||||
// using const_iterator = typename std::vector<T>::const_iterator;
|
||||
|
||||
// iterator begin() {
|
||||
// return m_values.begin();
|
||||
// }
|
||||
// iterator end() {
|
||||
// return m_values.end();
|
||||
// }
|
||||
|
||||
// const_iterator begin() const {
|
||||
// return m_values.begin();
|
||||
// }
|
||||
// const_iterator end() const {
|
||||
// return m_values.end();
|
||||
// }
|
||||
// };
|
||||
|
||||
template<class Json>
|
||||
JsonMaybeValue<Json> JsonMaybeValue<Json>::at(size_t i) {
|
||||
this->as<value_t::array>();
|
||||
if (this->isError()) return *this;
|
||||
if (self().m_json.size() <= i) {
|
||||
this->setError(
|
||||
self().m_hierarchy + ": has " +
|
||||
std::to_string(self().m_json.size()) + "items "
|
||||
", expected to have at least " + std::to_string(i + 1)
|
||||
);
|
||||
return *this;
|
||||
}
|
||||
return JsonMaybeValue<Json>(
|
||||
self().m_checker, self().m_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() {
|
||||
this->as<value_t::array>();
|
||||
Iterator<JsonMaybeValue<Json>> iter;
|
||||
if (this->isError()) return iter;
|
||||
size_t i = 0;
|
||||
for (auto& obj : self().m_json) {
|
||||
iter.m_values.emplace_back(
|
||||
self().m_checker, obj,
|
||||
self().m_hierarchy + "." + std::to_string(i++),
|
||||
self().m_hasValue
|
||||
);
|
||||
}
|
||||
return iter;
|
||||
}
|
||||
|
||||
template<class Json>
|
||||
typename JsonMaybeValue<Json>::template Iterator<std::pair<std::string, JsonMaybeValue<Json>>> JsonMaybeValue<Json>::items() {
|
||||
this->as<value_t::object>();
|
||||
Iterator<std::pair<std::string, JsonMaybeValue<Json>>> iter;
|
||||
if (this->isError()) return iter;
|
||||
|
||||
for (auto& [k, v] : self().m_json.items()) {
|
||||
iter.m_values.emplace_back(k, JsonMaybeValue<Json>(
|
||||
self().m_checker, v,
|
||||
self().m_hierarchy + "." + k,
|
||||
self().m_hasValue
|
||||
));
|
||||
}
|
||||
|
||||
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>
|
||||
JsonMaybeSomething<Json>& JsonMaybeObject<Json>::self() {
|
||||
return *static_cast<JsonMaybeSomething<Json>*>(this);
|
||||
}
|
||||
|
||||
template <class Json>
|
||||
void JsonMaybeObject<Json>::addKnownKey(std::string const& key) {
|
||||
m_knownKeys.insert(key);
|
||||
}
|
||||
|
||||
template <class Json>
|
||||
Json& JsonMaybeObject<Json>::json() {
|
||||
return self().m_json;
|
||||
}
|
||||
|
||||
template <class Json>
|
||||
JsonMaybeValue<Json> JsonMaybeObject<Json>::emptyValue() {
|
||||
return JsonMaybeValue(self().m_checker, self().m_json, "", false);
|
||||
}
|
||||
|
||||
template <class Json>
|
||||
JsonMaybeValue<Json> JsonMaybeObject<Json>::has(std::string const& key) {
|
||||
this->addKnownKey(key);
|
||||
if (this->isError()) return emptyValue();
|
||||
if (!self().m_json.contains(key) || self().m_json[key].is_null()) {
|
||||
return emptyValue();
|
||||
}
|
||||
return JsonMaybeValue<Json>(self().m_checker, self().m_json[key], key, true);
|
||||
}
|
||||
|
||||
template <class Json>
|
||||
JsonMaybeValue<Json> JsonMaybeObject<Json>::needs(std::string const& key) {
|
||||
this->addKnownKey(key);
|
||||
if (this->isError()) return emptyValue();
|
||||
if (!self().m_json.contains(key)) {
|
||||
this->setError(
|
||||
self().m_hierarchy + " is missing required key \"" + key + "\""
|
||||
);
|
||||
return emptyValue();
|
||||
}
|
||||
return JsonMaybeValue<Json>(self().m_checker, self().m_json[key], key, true);
|
||||
}
|
||||
|
||||
template <class Json>
|
||||
void JsonMaybeObject<Json>::checkUnknownKeys() {
|
||||
for (auto& [key, _] : self().m_json.items()) {
|
||||
if (!m_knownKeys.count(key)) {
|
||||
// log::debug(self().m_hierarchy + " contains unknown key \"" + key + "\"");
|
||||
log::debug("{} contains unknown key \"{}\"", self().m_hierarchy, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Json>
|
||||
JsonChecker<Json>::JsonChecker(Json& json) : m_json(json), m_result(std::monostate()) {}
|
||||
|
||||
template <class Json>
|
||||
bool JsonChecker<Json>::isError() const {
|
||||
return std::holds_alternative<std::string>(m_result);
|
||||
}
|
||||
|
||||
template <class Json>
|
||||
std::string JsonChecker<Json>::getError() const {
|
||||
return std::get<std::string>(m_result);
|
||||
}
|
||||
|
||||
template <class Json>
|
||||
JsonMaybeValue<Json> JsonChecker<Json>::root(std::string const& hierarchy) {
|
||||
return JsonMaybeValue(*this, m_json, hierarchy, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace geode {
|
||||
|
||||
template struct JsonMaybeSomething<nlohmann::json>;
|
||||
template struct JsonMaybeSomething<nlohmann::json const>;
|
||||
template struct JsonMaybeSomething<ModJson>;
|
||||
|
||||
|
||||
template struct JsonMaybeValue<nlohmann::json>;
|
||||
template struct JsonMaybeValue<nlohmann::json const>;
|
||||
template struct JsonMaybeValue<ModJson>;
|
||||
|
||||
|
||||
template struct JsonMaybeObject<nlohmann::json>;
|
||||
template struct JsonMaybeObject<nlohmann::json const>;
|
||||
template struct JsonMaybeObject<ModJson>;
|
||||
|
||||
|
||||
template struct JsonChecker<nlohmann::json>;
|
||||
template struct JsonChecker<nlohmann::json const>;
|
||||
template struct JsonChecker<ModJson>;
|
||||
|
||||
}
|
|
@ -99,3 +99,12 @@ bool geode::cocos::fileExistsInSearchPaths(const char* filename) {
|
|||
auto utils = CCFileUtils::sharedFileUtils();
|
||||
return utils->isFileExist(utils->fullPathForFilename(filename, false));
|
||||
}
|
||||
|
||||
CCScene* geode::cocos::switchToScene(CCLayer* layer) {
|
||||
auto scene = CCScene::create();
|
||||
scene->addChild(layer);
|
||||
CCDirector::get()->replaceScene(CCTransitionFade::create(
|
||||
.5f, scene
|
||||
));
|
||||
return scene;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue