matjson 3/3, compiles but mod about.md dont load for some reason

This commit is contained in:
matcool 2024-11-09 15:16:24 -03:00
parent d1d34aab8f
commit 9ed55c4e7b
33 changed files with 142 additions and 141 deletions

View file

@ -236,8 +236,8 @@ if (ANDROID)
endif() endif()
set(MAT_JSON_AS_INTERFACE ON) set(MAT_JSON_AS_INTERFACE ON)
CPMAddPackage("gh:geode-sdk/json#1b182dd")
CPMAddPackage("gh:geode-sdk/result@1.1.0") CPMAddPackage("gh:geode-sdk/result@1.1.0")
CPMAddPackage("gh:geode-sdk/json#8c6c325")
CPMAddPackage("gh:fmtlib/fmt#10.2.1") CPMAddPackage("gh:fmtlib/fmt#10.2.1")
target_compile_definitions(${PROJECT_NAME} INTERFACE MAT_JSON_DYNAMIC=1) target_compile_definitions(${PROJECT_NAME} INTERFACE MAT_JSON_DYNAMIC=1)

View file

@ -41,7 +41,7 @@
#include <Geode/utils/casts.hpp> #include <Geode/utils/casts.hpp>
#ifndef GEODE_IS_MEMBER_TEST #ifndef GEODE_IS_MEMBER_TEST
#include <matjson3.hpp> #include <matjson.hpp>
#endif #endif
namespace geode { namespace geode {

View file

@ -2,7 +2,7 @@
#include "../DefaultInclude.hpp" #include "../DefaultInclude.hpp"
#include "../utils/general.hpp" #include "../utils/general.hpp"
#include <matjson3.hpp> #include <matjson.hpp>
#include "Tulip.hpp" #include "Tulip.hpp"
#include <cinttypes> #include <cinttypes>
#include <string_view> #include <string_view>

View file

@ -3,7 +3,7 @@
#include "Event.hpp" #include "Event.hpp"
#include "Loader.hpp" #include "Loader.hpp"
#include "Mod.hpp" #include "Mod.hpp"
#include <matjson3.hpp> #include <matjson.hpp>
namespace geode::ipc { namespace geode::ipc {
#ifdef GEODE_IS_WINDOWS #ifdef GEODE_IS_WINDOWS

View file

@ -8,7 +8,7 @@
#include "Types.hpp" #include "Types.hpp"
#include <atomic> #include <atomic>
#include <matjson3.hpp> #include <matjson.hpp>
#include <mutex> #include <mutex>
#include <optional> #include <optional>
#include <string_view> #include <string_view>

View file

@ -7,7 +7,7 @@
#include <ccTypes.h> #include <ccTypes.h>
#include <chrono> #include <chrono>
#include <filesystem> #include <filesystem>
#include <matjson3.hpp> #include <matjson.hpp>
#include <type_traits> #include <type_traits>
#include <fmt/core.h> #include <fmt/core.h>
// for formatting std::vector and such // for formatting std::vector and such

View file

@ -13,7 +13,7 @@
#include "Types.hpp" #include "Types.hpp"
#include "Loader.hpp" #include "Loader.hpp"
#include <matjson3.hpp> #include <matjson.hpp>
#include <matjson/stl_serialize.hpp> #include <matjson/stl_serialize.hpp>
#include <optional> #include <optional>
#include <string_view> #include <string_view>

View file

@ -4,7 +4,7 @@
#include "../utils/VersionInfo.hpp" #include "../utils/VersionInfo.hpp"
#include "Types.hpp" #include "Types.hpp"
#include <matjson3.hpp> #include <matjson.hpp>
#include <memory> #include <memory>
namespace geode { namespace geode {

View file

@ -2,7 +2,7 @@
#include "../DefaultInclude.hpp" #include "../DefaultInclude.hpp"
#include "../platform/cplatform.h" #include "../platform/cplatform.h"
#include <matjson3.hpp> #include <matjson.hpp>
#include <string> #include <string>

View file

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <matjson3.hpp> #include <matjson.hpp>
#include "../loader/Log.hpp" #include "../loader/Log.hpp"
#include <set> #include <set>
#include <variant> #include <variant>
@ -223,6 +223,13 @@ namespace geode {
* @returns The key, which is a no-op value if it didn't exist * @returns The key, which is a no-op value if it didn't exist
*/ */
JsonExpectedValue has(std::string_view key); JsonExpectedValue has(std::string_view key);
/**
* Check if this object has an optional key. Asserts that this JSON
* value is an object. If the key doesn't exist, or the value is null, returns a
* `JsonExpectValue` that does nothing
* @returns The key, which is a no-op value if it didn't exist, or was null
*/
JsonExpectedValue hasNullable(std::string_view key);
/** /**
* Check if this object has an optional key. Asserts that this JSON * Check if this object has an optional key. Asserts that this JSON
* value is an object. If the key doesn't exist, sets an error and * value is an object. If the key doesn't exist, sets an error and

View file

@ -2,7 +2,7 @@
#include "../DefaultInclude.hpp" #include "../DefaultInclude.hpp"
#include <string_view> #include <string_view>
#include <matjson3.hpp> #include <matjson.hpp>
#include <tuple> #include <tuple>
#include <Geode/Result.hpp> #include <Geode/Result.hpp>
@ -258,9 +258,9 @@ requires std::is_same_v<V, geode::VersionInfo> || std::is_same_v<V, geode::Compa
struct matjson::Serialize<V> { struct matjson::Serialize<V> {
static geode::Result<V, std::string> fromJson(Value const& value) static geode::Result<V, std::string> fromJson(Value const& value)
{ {
auto str = GEODE_UNWRAP(value.asString()); GEODE_UNWRAP_INTO(auto str, value.asString());
auto version = GEODE_UNWRAP(V::parse(str).mapErr([](auto&& err) { GEODE_UNWRAP_INTO(auto version, V::parse(str).mapErr([](auto&& err) {
return geode::Err("Invalid version format: {}", err); return fmt::format("Invalid version format: {}", err);
})); }));
return geode::Ok(version); return geode::Ok(version);
} }

View file

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <matjson3.hpp> #include <matjson.hpp>
#include "casts.hpp" #include "casts.hpp"
#include "general.hpp" #include "general.hpp"
#include "../DefaultInclude.hpp" #include "../DefaultInclude.hpp"

View file

@ -5,7 +5,7 @@
#include "../loader/Event.hpp" #include "../loader/Event.hpp"
#include "Task.hpp" #include "Task.hpp"
#include <matjson3.hpp> #include <matjson.hpp>
#include <Geode/DefaultInclude.hpp> #include <Geode/DefaultInclude.hpp>
#include <filesystem> #include <filesystem>
#include <string> #include <string>
@ -15,7 +15,7 @@ template <>
struct matjson::Serialize<std::filesystem::path> { struct matjson::Serialize<std::filesystem::path> {
static geode::Result<std::filesystem::path, std::string> fromJson(Value const& value) static geode::Result<std::filesystem::path, std::string> fromJson(Value const& value)
{ {
auto str = GEODE_UNWRAP(value.asString()); GEODE_UNWRAP_INTO(auto str, value.asString());
return geode::Ok(std::filesystem::path(str).make_preferred()); return geode::Ok(std::filesystem::path(str).make_preferred());
} }

View file

@ -9,7 +9,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <filesystem> #include <filesystem>
#include <matjson3.hpp> #include <matjson.hpp>
#include <charconv> #include <charconv>
#include <clocale> #include <clocale>
#include <type_traits> #include <type_traits>
@ -170,9 +170,8 @@ namespace geode {
template<> template<>
struct matjson::Serialize<geode::ByteVector> { struct matjson::Serialize<geode::ByteVector> {
static Value toJson(geode::ByteVector const& bytes) static Value toJson(geode::ByteVector const& bytes) {
{ return std::vector<matjson::Value>(bytes.begin(), bytes.end());
return matjson::Array(bytes.begin(), bytes.end());
} }
}; };

View file

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <Geode/loader/Loader.hpp> // another great circular dependency fix #include <Geode/loader/Loader.hpp> // another great circular dependency fix
#include <matjson3.hpp> #include <matjson.hpp>
#include <Geode/Result.hpp> #include <Geode/Result.hpp>
#include "Task.hpp" #include "Task.hpp"
#include <chrono> #include <chrono>

View file

@ -98,7 +98,7 @@ std::string_view Hook::Impl::getDisplayName() const {
} }
matjson::Value Hook::Impl::getRuntimeInfo() const { matjson::Value Hook::Impl::getRuntimeInfo() const {
auto json = matjson::Object(); matjson::Value json;
json["address"] = std::to_string(reinterpret_cast<uintptr_t>(m_address)); json["address"] = std::to_string(reinterpret_cast<uintptr_t>(m_address));
json["detour"] = std::to_string(reinterpret_cast<uintptr_t>(m_detour)); json["detour"] = std::to_string(reinterpret_cast<uintptr_t>(m_detour));
json["name"] = m_displayName; json["name"] = m_displayName;

View file

@ -1,6 +1,6 @@
#include <Geode/loader/IPC.hpp> #include <Geode/loader/IPC.hpp>
#include "IPC.hpp" #include "IPC.hpp"
#include <matjson3.hpp> #include <matjson.hpp>
#include <Geode/loader/Mod.hpp> #include <Geode/loader/Mod.hpp>
using namespace geode::prelude; using namespace geode::prelude;
@ -34,7 +34,7 @@ matjson::Value ipc::processRaw(void* rawHandle, std::string const& buffer) {
matjson::Value reply; matjson::Value reply;
auto res = matjson::Value::parse(buffer); auto res = matjson::Value::parse(buffer);
if (error.size() > 0) { if (!res) {
log::warn("Received IPC message that isn't valid JSON: {}", res.unwrapErr()); log::warn("Received IPC message that isn't valid JSON: {}", res.unwrapErr());
return reply; return reply;
} }

View file

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <string> #include <string>
#include <matjson3.hpp> #include <matjson.hpp>
namespace geode::ipc { namespace geode::ipc {
void setup(); void setup();

View file

@ -2,7 +2,7 @@
#include "FileWatcher.hpp" #include "FileWatcher.hpp"
#include <matjson3.hpp> #include <matjson.hpp>
#include <Geode/loader/Dirs.hpp> #include <Geode/loader/Dirs.hpp>
#include <Geode/loader/Loader.hpp> #include <Geode/loader/Loader.hpp>
#include <Geode/loader/Log.hpp> #include <Geode/loader/Log.hpp>

View file

@ -190,15 +190,12 @@ Result<> Mod::Impl::loadData() {
auto savedPath = m_saveDirPath / "saved.json"; auto savedPath = m_saveDirPath / "saved.json";
if (std::filesystem::exists(savedPath)) { if (std::filesystem::exists(savedPath)) {
GEODE_UNWRAP_INTO(auto data, utils::file::readString(savedPath)); GEODE_UNWRAP_INTO(auto data, utils::file::readString(savedPath));
std::string error; m_saved = GEODE_UNWRAP(matjson::parse(data).mapErr([](auto&& err) {
auto res = matjson::parse(data, error); return fmt::format("Unable to parse saved values: {}", err);
if (error.size() > 0) { }));
return Err("Unable to parse saved values: " + error); if (!m_saved.isObject()) {
}
m_saved = res.value();
if (!m_saved.is_object()) {
log::warn("saved.json was somehow not an object, forcing it to one"); log::warn("saved.json was somehow not an object, forcing it to one");
m_saved = matjson::Object(); m_saved = matjson::Value::object();
} }
} }
@ -218,11 +215,15 @@ Result<> Mod::Impl::saveData() {
// saveData is expected to be synchronous, and always called from GD thread // saveData is expected to be synchronous, and always called from GD thread
ModStateEvent(m_self, ModEventType::DataSaved).post(); ModStateEvent(m_self, ModEventType::DataSaved).post();
auto res = utils::file::writeString(m_saveDirPath / "settings.json", json.dump()); auto res = json.dump().andThen([&](auto const& str) {
return utils::file::writeString(m_saveDirPath / "settings.json", str);
});
if (!res) { if (!res) {
log::error("Unable to save settings: {}", res.unwrapErr()); log::error("Unable to save settings: {}", res.unwrapErr());
} }
auto res2 = utils::file::writeString(m_saveDirPath / "saved.json", m_saved.dump()); auto res2 = m_saved.dump().andThen([&](auto const& str) {
return utils::file::writeString(m_saveDirPath / "saved.json", str);
});
if (!res2) { if (!res2) {
log::error("Unable to save values: {}", res2.unwrapErr()); log::error("Unable to save values: {}", res2.unwrapErr());
} }
@ -387,7 +388,7 @@ Result<> Mod::Impl::uninstall(bool deleteSaveData) {
ModRequestedAction::Uninstall; ModRequestedAction::Uninstall;
// Make loader forget the mod should be disabled // Make loader forget the mod should be disabled
Mod::get()->getSaveContainer().try_erase("should-load-" + m_metadata.getID()); Mod::get()->getSaveContainer().erase("should-load-" + m_metadata.getID());
std::error_code ec; std::error_code ec;
std::filesystem::remove(m_metadata.getPath(), ec); std::filesystem::remove(m_metadata.getPath(), ec);
@ -674,14 +675,14 @@ std::string_view Mod::Impl::expandSpriteName(std::string_view name) {
ModJson Mod::Impl::getRuntimeInfo() const { ModJson Mod::Impl::getRuntimeInfo() const {
auto json = m_metadata.toJSON(); auto json = m_metadata.toJSON();
auto obj = matjson::Object(); auto obj = matjson::Value::object();
obj["hooks"] = matjson::Array(); obj["hooks"] = matjson::Value::array();
for (auto hook : m_hooks) { for (auto hook : m_hooks) {
obj["hooks"].as_array().push_back(ModJson(hook->getRuntimeInfo())); obj["hooks"].push(ModJson(hook->getRuntimeInfo()));
} }
obj["patches"] = matjson::Array(); obj["patches"] = matjson::Value::array();
for (auto patch : m_patches) { for (auto patch : m_patches) {
obj["patches"].as_array().push_back(ModJson(patch->getRuntimeInfo())); obj["patches"].push(ModJson(patch->getRuntimeInfo()));
} }
obj["loaded"] = m_enabled; obj["loaded"] = m_enabled;
obj["temp-dir"] = this->getTempDir(); obj["temp-dir"] = this->getTempDir();
@ -722,12 +723,9 @@ std::vector<LoadProblem> Mod::Impl::getProblems() const {
} }
static Result<ModMetadata> getModImplInfo() { static Result<ModMetadata> getModImplInfo() {
std::string error; auto json = GEODE_UNWRAP(matjson::parse(about::getLoaderModJson()).mapErr([](auto&& err) {
auto res = matjson::parse(about::getLoaderModJson(), error); return fmt::format("Unable to parse mod.json: {}", err);
if (error.size() > 0) { }));
return Err("Unable to parse mod.json: " + error);
}
matjson::Value json = res.value();
GEODE_UNWRAP_INTO(auto info, ModMetadata::create(json)); GEODE_UNWRAP_INTO(auto info, ModMetadata::create(json));
return Ok(info); return Ok(info);

View file

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <matjson3.hpp> #include <matjson.hpp>
#include "ModPatch.hpp" #include "ModPatch.hpp"
#include <Geode/loader/Loader.hpp> #include <Geode/loader/Loader.hpp>
#include <string_view> #include <string_view>

View file

@ -5,7 +5,7 @@
#include <Geode/utils/string.hpp> #include <Geode/utils/string.hpp>
#include <Geode/utils/general.hpp> #include <Geode/utils/general.hpp>
#include <about.hpp> #include <about.hpp>
#include <matjson3.hpp> #include <matjson.hpp>
#include <utility> #include <utility>
#include <clocale> #include <clocale>
@ -113,14 +113,14 @@ Result<ModMetadata> ModMetadata::Impl::createFromSchemaV010(ModJson const& rawJs
auto checkerRoot = fmt::format( auto checkerRoot = fmt::format(
"[{}/v0.0.0/mod.json]", "[{}/v0.0.0/mod.json]",
rawJson.contains("id") ? rawJson["id"].as_string() : "unknown.mod" rawJson.contains("id") ? GEODE_UNWRAP(rawJson["id"].asString()) : "unknown.mod"
); );
// JsonChecker did it this way too // JsonChecker did it this way too
try { try {
checkerRoot = fmt::format( checkerRoot = fmt::format(
"[{}/{}/mod.json]", "[{}/{}/mod.json]",
rawJson.contains("id") ? rawJson["id"].as_string() : "unknown.mod", rawJson.contains("id") ? GEODE_UNWRAP(rawJson["id"].asString()) : "unknown.mod",
rawJson.contains("version") ? rawJson["version"].as<VersionInfo>().toVString() : "v0.0.0" rawJson.contains("version") ? GEODE_UNWRAP(rawJson["version"].as<VersionInfo>()).toVString() : "v0.0.0"
); );
} }
catch (...) { } catch (...) { }
@ -304,10 +304,10 @@ Result<ModMetadata> ModMetadata::Impl::createFromSchemaV010(ModJson const& rawJs
Result<ModMetadata> ModMetadata::Impl::create(ModJson const& json) { Result<ModMetadata> ModMetadata::Impl::create(ModJson const& json) {
// Check mod.json target version // Check mod.json target version
auto schema = about::getLoaderVersion(); auto schema = about::getLoaderVersion();
if (json.contains("geode") && json["geode"].is_string()) { if (json.contains("geode") && json["geode"].isString()) {
GEODE_UNWRAP_INTO( GEODE_UNWRAP_INTO(
schema, schema,
VersionInfo::parse(json["geode"].as_string()).mapErr( VersionInfo::parse(GEODE_UNWRAP(json["geode"].asString())).mapErr(
[](auto const& err) { [](auto const& err) {
return fmt::format("[mod.json] has invalid target loader version: {}", err); return fmt::format("[mod.json] has invalid target loader version: {}", err);
} }
@ -355,13 +355,9 @@ Result<ModMetadata> ModMetadata::Impl::create(ModJson const& json) {
Result<ModMetadata> ModMetadata::Impl::createFromFile(std::filesystem::path const& path) { Result<ModMetadata> ModMetadata::Impl::createFromFile(std::filesystem::path const& path) {
GEODE_UNWRAP_INTO(auto read, utils::file::readString(path)); GEODE_UNWRAP_INTO(auto read, utils::file::readString(path));
std::string error; GEODE_UNWRAP_INTO(auto info, ModMetadata::create(GEODE_UNWRAP(matjson::parse(read).mapErr([&](auto const& err) {
auto res = matjson::parse(read, error); return fmt::format("Unable to parse mod.json: {}", err);
if (error.size() > 0) { }))));
return Err(std::string("Unable to parse mod.json: ") + error);
}
GEODE_UNWRAP_INTO(auto info, ModMetadata::create(res.value()));
auto impl = info.m_impl.get(); auto impl = info.m_impl.get();
@ -390,18 +386,13 @@ Result<ModMetadata> ModMetadata::Impl::createFromGeodeZip(file::Unzip& unzip) {
}) })
); );
std::string error; ModJson json = GEODE_UNWRAP(matjson::parse(std::string(jsonData.begin(), jsonData.end())).mapErr([](auto const& err) {
auto res = matjson::parse(std::string(jsonData.begin(), jsonData.end()), error); return fmt::format("Unable to parse mod.json: {}", err);
if (error.size() > 0) { }));
return Err(std::string("Unable to parse mod.json: ") + error);
}
ModJson json = res.value();
auto res2 = ModMetadata::create(json); auto info = GEODE_UNWRAP(ModMetadata::create(json).mapErr([&](auto const& err) {
if (!res2) { return fmt::format("\"{}\" - {}", unzip.getPath().string(), err);
return Err("\"" + unzip.getPath().string() + "\" - " + res2.unwrapErr()); }));
}
auto info = res2.unwrap();
auto impl = info.m_impl.get(); auto impl = info.m_impl.get();
impl->m_path = unzip.getPath(); impl->m_path = unzip.getPath();

View file

@ -124,7 +124,6 @@ public:
// Store the value in an intermediary so if `save` fails the existing // Store the value in an intermediary so if `save` fails the existing
// value loaded from disk isn't overwritten // value loaded from disk isn't overwritten
matjson::Value value; matjson::Value value;
try {
if (sett.v3->save(value)) { if (sett.v3->save(value)) {
this->savedata[key] = value; this->savedata[key] = value;
} }
@ -132,10 +131,6 @@ public:
log::error("Unable to save setting '{}' for mod {}", key, this->modID); log::error("Unable to save setting '{}' for mod {}", key, this->modID);
} }
} }
catch(matjson::JsonException const& e) {
log::error("Unable to save setting '{}' for mod {} (JSON exception): {}", key, this->modID, e.what());
}
}
} }
void createSettings() { void createSettings() {
@ -209,11 +204,11 @@ Result<> ModSettingsManager::registerCustomSettingType(std::string_view type, Se
} }
Result<> ModSettingsManager::load(matjson::Value const& json) { Result<> ModSettingsManager::load(matjson::Value const& json) {
if (json.is_object()) { if (json.isObject()) {
// Save this so when custom settings are registered they can load their // Save this so when custom settings are registered they can load their
// values properly // values properly
m_impl->savedata = json.as_object(); m_impl->savedata = json;
for (auto const& [key, _] : json.as_object()) { for (auto const& [key, _] : json) {
m_impl->loadSettingValueFromSave(key); m_impl->loadSettingValueFromSave(key);
} }
} }

View file

@ -104,7 +104,7 @@ uintptr_t Patch::Impl::getAddress() const {
} }
matjson::Value Patch::Impl::getRuntimeInfo() const { matjson::Value Patch::Impl::getRuntimeInfo() const {
auto json = matjson::Object(); auto json = matjson::Value::object();
json["address"] = std::to_string(reinterpret_cast<uintptr_t>(m_address)); json["address"] = std::to_string(reinterpret_cast<uintptr_t>(m_address));
json["original"] = m_original; json["original"] = m_original;
json["patch"] = m_patch; json["patch"] = m_patch;

View file

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <string> #include <string>
#include <matjson3.hpp> #include <matjson.hpp>
#include <Geode/loader/Event.hpp> #include <Geode/loader/Event.hpp>
namespace geode::updater { namespace geode::updater {

View file

@ -21,7 +21,11 @@ void ipcPipeThread(HANDLE pipe) {
if (ReadFile(pipe, buffer, sizeof(buffer) - 1, &read, nullptr)) { if (ReadFile(pipe, buffer, sizeof(buffer) - 1, &read, nullptr)) {
buffer[read] = '\0'; buffer[read] = '\0';
std::string reply = ipc::processRaw((void*)pipe, buffer).dump(); auto res = ipc::processRaw((void*)pipe, buffer).dump();
if (!res) {
log::warn("Failed to process IPC message: {}", res.unwrapErr());
}
std::string reply = res.unwrapOr("");
DWORD written; DWORD written;
WriteFile(pipe, reply.c_str(), reply.size(), &written, nullptr); WriteFile(pipe, reply.c_str(), reply.size(), &written, nullptr);

View file

@ -172,24 +172,23 @@ static Result<matjson::Value, ServerError> parseServerPayload(web::WebResponse c
return Err(ServerError(response.code(), "Response was not valid JSON: {}", asJson.unwrapErr())); return Err(ServerError(response.code(), "Response was not valid JSON: {}", asJson.unwrapErr()));
} }
auto json = std::move(asJson).unwrap(); auto json = std::move(asJson).unwrap();
if (!json.is_object()) { if (!json.isObject()) {
return Err(ServerError(response.code(), "Expected object, got {}", jsonTypeToString(json.type()))); return Err(ServerError(response.code(), "Expected object, got {}", jsonTypeToString(json.type())));
} }
auto obj = json.as_object(); if (!json.contains("payload")) {
if (!obj.contains("payload")) { return Err(ServerError(response.code(), "Object does not contain \"payload\" key - got {}", json.dump().unwrapOr("?")));
return Err(ServerError(response.code(), "Object does not contain \"payload\" key - got {}", json.dump()));
} }
return Ok(obj["payload"]); return Ok(json["payload"]);
} }
static ServerError parseServerError(web::WebResponse const& error) { static ServerError parseServerError(web::WebResponse const& error) {
// The server should return errors as `{ "error": "...", "payload": "" }` // The server should return errors as `{ "error": "...", "payload": "" }`
if (auto asJson = error.json()) { if (auto asJson = error.json()) {
auto json = asJson.unwrap(); auto json = asJson.unwrap();
if (json.is_object() && json.contains("error")) { if (json.isObject() && json.contains("error") && json["error"].isString()) {
return ServerError( return ServerError(
error.code(), error.code(),
"{}", json.get<std::string>("error") "{}", json["error"].asString().unwrapOr("Unknown (no error message)")
); );
} }
else { else {
@ -267,8 +266,8 @@ Result<ServerModVersion> ServerModVersion::parse(matjson::Value const& raw) {
// Verify target GD version // Verify target GD version
auto gd_obj = root.needs("gd"); auto gd_obj = root.needs("gd");
std::string gd = "0.000"; std::string gd = "0.000";
if (gd_obj.has(GEODE_PLATFORM_SHORT_IDENTIFIER)) { if (gd_obj.hasNullable(GEODE_PLATFORM_SHORT_IDENTIFIER)) {
gd = gd_obj.has(GEODE_PLATFORM_SHORT_IDENTIFIER). get<std::string>(); gd = gd_obj.hasNullable(GEODE_PLATFORM_SHORT_IDENTIFIER). get<std::string>();
} }
if (gd != "*") { if (gd != "*") {
@ -288,11 +287,11 @@ Result<ServerModVersion> ServerModVersion::parse(matjson::Value const& raw) {
res.metadata.setIsAPI(root.needs("api").get<bool>()); res.metadata.setIsAPI(root.needs("api").get<bool>());
std::vector<ModMetadata::Dependency> dependencies {}; std::vector<ModMetadata::Dependency> dependencies {};
for (auto& obj : root.has("dependencies").items()) { for (auto& obj : root.hasNullable("dependencies").items()) {
// todo: this should probably be generalized to use the same function as mod.json // todo: this should probably be generalized to use the same function as mod.json
bool onThisPlatform = !obj.has("platforms"); bool onThisPlatform = !obj.hasNullable("platforms");
for (auto& plat : obj.has("platforms").items()) { for (auto& plat : obj.hasNullable("platforms").items()) {
if (PlatformID::coveredBy(plat.get<std::string>(), GEODE_PLATFORM_TARGET)) { if (PlatformID::coveredBy(plat.get<std::string>(), GEODE_PLATFORM_TARGET)) {
onThisPlatform = true; onThisPlatform = true;
} }
@ -304,7 +303,7 @@ Result<ServerModVersion> ServerModVersion::parse(matjson::Value const& raw) {
ModMetadata::Dependency dependency; ModMetadata::Dependency dependency;
obj.needs("mod_id").mustBe<std::string>("a valid id", &ModMetadata::validateID).into(dependency.id); obj.needs("mod_id").mustBe<std::string>("a valid id", &ModMetadata::validateID).into(dependency.id);
obj.needs("version").into(dependency.version); obj.needs("version").into(dependency.version);
obj.has("importance").into(dependency.importance); obj.hasNullable("importance").into(dependency.importance);
// Check if this dependency is installed, and if so assign the `mod` member to mark that // Check if this dependency is installed, and if so assign the `mod` member to mark that
auto mod = Loader::get()->getInstalledMod(dependency.id); auto mod = Loader::get()->getInstalledMod(dependency.id);
@ -317,9 +316,9 @@ Result<ServerModVersion> ServerModVersion::parse(matjson::Value const& raw) {
res.metadata.setDependencies(dependencies); res.metadata.setDependencies(dependencies);
std::vector<ModMetadata::Incompatibility> incompatibilities {}; std::vector<ModMetadata::Incompatibility> incompatibilities {};
for (auto& obj : root.has("incompatibilities").items()) { for (auto& obj : root.hasNullable("incompatibilities").items()) {
ModMetadata::Incompatibility incompatibility; ModMetadata::Incompatibility incompatibility;
obj.has("importance").into(incompatibility.importance); obj.hasNullable("importance").into(incompatibility.importance);
auto modIdValue = obj.needs("mod_id"); auto modIdValue = obj.needs("mod_id");
@ -362,8 +361,8 @@ Result<ServerModUpdate> ServerModUpdate::parse(matjson::Value const& raw) {
root.needs("id").into(res.id); root.needs("id").into(res.id);
root.needs("version").into(res.version); root.needs("version").into(res.version);
if (root.has("replacement")) { if (root.hasNullable("replacement")) {
GEODE_UNWRAP_INTO(res.replacement, ServerModReplacement::parse(root.has("replacement").json())); GEODE_UNWRAP_INTO(res.replacement, ServerModReplacement::parse(root.hasNullable("replacement").json()));
} }
return root.ok(res); return root.ok(res);
@ -400,9 +399,9 @@ Result<ServerModMetadata> ServerModMetadata::parse(matjson::Value const& raw) {
root.needs("id").into(res.id); root.needs("id").into(res.id);
root.needs("featured").into(res.featured); root.needs("featured").into(res.featured);
root.needs("download_count").into(res.downloadCount); root.needs("download_count").into(res.downloadCount);
root.has("about").into(res.about); root.hasNullable("about").into(res.about);
root.has("changelog").into(res.changelog); root.hasNullable("changelog").into(res.changelog);
root.has("repository").into(res.repository); root.hasNullable("repository").into(res.repository);
if (root.has("created_at")) { if (root.has("created_at")) {
GEODE_UNWRAP_INTO(res.createdAt, ServerDateTime::parse(root.has("created_at").get<std::string>())); GEODE_UNWRAP_INTO(res.createdAt, ServerDateTime::parse(root.has("created_at").get<std::string>()));
} }
@ -439,7 +438,7 @@ Result<ServerModMetadata> ServerModMetadata::parse(matjson::Value const& raw) {
return Err("Mod '{}' has no (valid) versions", res.id); return Err("Mod '{}' has no (valid) versions", res.id);
} }
for (auto& item : root.has("tags").items()) { for (auto& item : root.hasNullable("tags").items()) {
res.tags.insert(item.get<std::string>()); res.tags.insert(item.get<std::string>());
} }
@ -705,16 +704,16 @@ ServerRequest<std::unordered_set<std::string>> server::getTags(bool useCache) {
return Err(payload.unwrapErr()); return Err(payload.unwrapErr());
} }
matjson::Value json = payload.unwrap(); matjson::Value json = payload.unwrap();
if (!json.is_array()) { if (!json.isArray()) {
return Err(ServerError(response->code(), "Expected a string array")); return Err(ServerError(response->code(), "Expected a string array"));
} }
std::unordered_set<std::string> tags; std::unordered_set<std::string> tags;
for (auto item : json.as_array()) { for (auto item : json) {
if (!item.is_string()) { if (!item.isString()) {
return Err(ServerError(response->code(), "Expected a string array")); return Err(ServerError(response->code(), "Expected a string array"));
} }
tags.insert(item.as_string()); tags.insert(item.asString().unwrap());
} }
return Ok(tags); return Ok(tags);
} }

View file

@ -4,7 +4,7 @@
#include <Geode/DefaultInclude.hpp> #include <Geode/DefaultInclude.hpp>
#include <Geode/utils/web.hpp> #include <Geode/utils/web.hpp>
#include <chrono> #include <chrono>
#include <matjson3.hpp> #include <matjson.hpp>
#include <vector> #include <vector>
using namespace geode::prelude; using namespace geode::prelude;

View file

@ -168,6 +168,19 @@ JsonExpectedValue JsonExpectedValue::has(std::string_view key) {
} }
return JsonExpectedValue(m_impl.get(), m_impl->scope[key], key); return JsonExpectedValue(m_impl.get(), m_impl->scope[key], key);
} }
JsonExpectedValue JsonExpectedValue::hasNullable(std::string_view key) {
if (this->hasError()) {
return JsonExpectedValue();
}
if (!this->assertIs(matjson::Type::Object)) {
return JsonExpectedValue();
}
m_impl->knownKeys.insert(std::string(key));
if (!m_impl->scope.contains(key) || m_impl->scope[key].isNull()) {
return JsonExpectedValue();
}
return JsonExpectedValue(m_impl.get(), m_impl->scope[key], key);
}
JsonExpectedValue JsonExpectedValue::needs(std::string_view key) { JsonExpectedValue JsonExpectedValue::needs(std::string_view key) {
if (this->hasError()) { if (this->hasError()) {
return JsonExpectedValue(); return JsonExpectedValue();
@ -190,7 +203,7 @@ std::vector<std::pair<std::string, JsonExpectedValue>> JsonExpectedValue::proper
return std::vector<std::pair<std::string, JsonExpectedValue>>(); return std::vector<std::pair<std::string, JsonExpectedValue>>();
} }
std::vector<std::pair<std::string, JsonExpectedValue>> res; std::vector<std::pair<std::string, JsonExpectedValue>> res;
for (auto& [k, v] : m_impl->scope.as_object()) { for (auto& [k, v] : m_impl->scope) {
res.push_back(std::make_pair(k, JsonExpectedValue(m_impl.get(), v, k))); res.push_back(std::make_pair(k, JsonExpectedValue(m_impl.get(), v, k)));
} }
return res; return res;
@ -211,7 +224,7 @@ size_t JsonExpectedValue::length() {
if (!this->assertIs(matjson::Type::Array)) { if (!this->assertIs(matjson::Type::Array)) {
return 0; return 0;
} }
return m_impl->scope.as_array().size(); return m_impl->scope.size();
} }
JsonExpectedValue JsonExpectedValue::at(size_t index) { JsonExpectedValue JsonExpectedValue::at(size_t index) {
if (this->hasError()) { if (this->hasError()) {
@ -220,15 +233,14 @@ JsonExpectedValue JsonExpectedValue::at(size_t index) {
if (!this->assertIs(matjson::Type::Array)) { if (!this->assertIs(matjson::Type::Array)) {
return JsonExpectedValue(); return JsonExpectedValue();
} }
auto& arr = m_impl->scope.as_array(); if (index >= m_impl->scope.size()) {
if (arr.size() <= index) {
this->setError( this->setError(
"array expected to have at least size {}, but its size was only {}", "array expected to have at least size {}, but its size was only {}",
index + 1, arr.size() index + 1, m_impl->scope.size()
); );
return JsonExpectedValue(); return JsonExpectedValue();
} }
return JsonExpectedValue(m_impl.get(), arr.at(index), std::to_string(index)); return JsonExpectedValue(m_impl.get(), m_impl->scope[index], std::to_string(index));
} }
std::vector<JsonExpectedValue> JsonExpectedValue::items() { std::vector<JsonExpectedValue> JsonExpectedValue::items() {
if (this->hasError()) { if (this->hasError()) {
@ -239,7 +251,7 @@ std::vector<JsonExpectedValue> JsonExpectedValue::items() {
} }
std::vector<JsonExpectedValue> res; std::vector<JsonExpectedValue> res;
size_t i = 0; size_t i = 0;
for (auto& v : m_impl->scope.as_array()) { for (auto& v : m_impl->scope) {
res.push_back(JsonExpectedValue(m_impl.get(), v, std::to_string(i++))); res.push_back(JsonExpectedValue(m_impl.get(), v, std::to_string(i++)));
} }
return res; return res;

View file

@ -4,7 +4,7 @@
#include <Geode/utils/VersionInfo.hpp> #include <Geode/utils/VersionInfo.hpp>
#include <Geode/utils/general.hpp> #include <Geode/utils/general.hpp>
#include <matjson3.hpp> #include <matjson.hpp>
using namespace geode::prelude; using namespace geode::prelude;

View file

@ -1,6 +1,6 @@
#include <Geode/modify/LoadingLayer.hpp> #include <Geode/modify/LoadingLayer.hpp>
#include <Geode/utils/cocos.hpp> #include <Geode/utils/cocos.hpp>
#include <matjson3.hpp> #include <matjson.hpp>
#include <charconv> #include <charconv>
#include <Geode/binding/CCTextInputNode.hpp> #include <Geode/binding/CCTextInputNode.hpp>
#include <Geode/binding/GameManager.hpp> #include <Geode/binding/GameManager.hpp>
@ -32,6 +32,7 @@ Result<cocos2d::ccColor3B, std::string> matjson::Serialize<ccColor3B>::fromJson(
} }
return Ok(res.unwrap()); return Ok(res.unwrap());
} }
return Err("Expected color to be array, object or hex string");
} }
matjson::Value matjson::Serialize<ccColor3B>::toJson(cocos2d::ccColor3B const& value) { matjson::Value matjson::Serialize<ccColor3B>::toJson(cocos2d::ccColor3B const& value) {
return matjson::makeObject({ return matjson::makeObject({
@ -68,6 +69,7 @@ Result<cocos2d::ccColor4B, std::string> matjson::Serialize<ccColor4B>::fromJson(
} }
return Ok(res.unwrap()); return Ok(res.unwrap());
} }
return Err("Expected color to be array, object or hex string");
} }
matjson::Value matjson::Serialize<ccColor4B>::toJson(cocos2d::ccColor4B const& value) { matjson::Value matjson::Serialize<ccColor4B>::toJson(cocos2d::ccColor4B const& value) {

View file

@ -3,7 +3,7 @@
#include <Geode/utils/file.hpp> #include <Geode/utils/file.hpp>
#include <Geode/utils/map.hpp> #include <Geode/utils/map.hpp>
#include <Geode/utils/string.hpp> #include <Geode/utils/string.hpp>
#include <matjson3.hpp> #include <matjson.hpp>
#include <fstream> #include <fstream>
#include <mz.h> #include <mz.h>
#include <mz_os.h> #include <mz_os.h>
@ -53,14 +53,10 @@ Result<std::string> utils::file::readString(std::filesystem::path const& path) {
} }
Result<matjson::Value> utils::file::readJson(std::filesystem::path const& path) { Result<matjson::Value> utils::file::readJson(std::filesystem::path const& path) {
auto str = utils::file::readString(path); auto str = GEODE_UNWRAP(utils::file::readString(path));
if (!str) return matjson::parse(str).mapErr([&](auto const& err) {
return Err(str.unwrapErr()); return fmt::format("Unable to parse JSON: {}", err);
std::string error; });
auto res = matjson::parse(str.unwrap(), error);
if (error.size())
return Err("Unable to parse JSON: " + error);
return Ok(res.value());
} }
Result<ByteVector> utils::file::readBinary(std::filesystem::path const& path) { Result<ByteVector> utils::file::readBinary(std::filesystem::path const& path) {

View file

@ -3,7 +3,7 @@
#include <filesystem> #include <filesystem>
#include <fmt/core.h> #include <fmt/core.h>
#include <fstream> #include <fstream>
#include <matjson3.hpp> #include <matjson.hpp>
#include <system_error> #include <system_error>
#define CURL_STATICLIB #define CURL_STATICLIB
#include <curl/curl.h> #include <curl/curl.h>
@ -130,12 +130,9 @@ Result<std::string> WebResponse::string() const {
} }
Result<matjson::Value> WebResponse::json() const { Result<matjson::Value> WebResponse::json() const {
GEODE_UNWRAP_INTO(auto value, this->string()); GEODE_UNWRAP_INTO(auto value, this->string());
std::string error; return matjson::parse(value).mapErr([&](auto const& err) {
auto res = matjson::parse(value, error); return fmt::format("Error parsing JSON: {}", err);
if (error.size() > 0) { });
return Err("Error parsing JSON: " + error);
}
return Ok(res.value());
} }
ByteVector WebResponse::data() const { ByteVector WebResponse::data() const {
return m_impl->m_data; return m_impl->m_data;
@ -595,7 +592,8 @@ WebRequest& WebRequest::bodyString(std::string_view str) {
} }
WebRequest& WebRequest::bodyJSON(matjson::Value const& json) { WebRequest& WebRequest::bodyJSON(matjson::Value const& json) {
this->header("Content-Type", "application/json"); this->header("Content-Type", "application/json");
std::string str = json.dump(matjson::NO_INDENTATION); // TODO: mat
std::string str = json.dump(matjson::NO_INDENTATION).unwrapOr("");
m_impl->m_body = ByteVector { str.begin(), str.end() }; m_impl->m_body = ByteVector { str.begin(), str.end() };
return *this; return *this;
} }