Merge branch 'main' into layout

This commit is contained in:
HJfod 2022-10-23 18:02:20 +03:00
commit c6919b5565
19 changed files with 512 additions and 162 deletions

View file

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

View file

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

View file

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

View file

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

View file

@ -1,8 +1,5 @@
#pragma once
#define GEODE_API extern "C"
#define GEODE_DLL
namespace geode {
using dylib_t = void*;
struct PlatformInfo {

View file

@ -1,5 +1,8 @@
#pragma once
#include "../DefaultInclude.hpp"
#include <cocos2d.h>
namespace cocos2d {
class CCArray;
class CCNode;

View file

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

View file

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

View file

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

Binary file not shown.

BIN
loader/resources/pencil.png Normal file

Binary file not shown.

After

(image error) Size: 2.9 KiB

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -20,6 +20,7 @@ protected:
void onClose(CCObject*) override;
void onApply(CCObject*);
void onResetAll(CCObject*);
void onOpenSaveDirectory(CCObject*);
public:
static ModSettingsPopup* create(Mod* mod);

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

View file

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