diff --git a/loader/include/Geode/hook-core/Hook.hpp b/loader/include/Geode/hook-core/Hook.hpp
index 5bf488d3..abc3db28 100644
--- a/loader/include/Geode/hook-core/Hook.hpp
+++ b/loader/include/Geode/hook-core/Hook.hpp
@@ -47,7 +47,7 @@ namespace geode::core {
 
         inline Result<> remove(HookHandle const& handle) {
             impl::removeHook(handle);
-            return Ok<>();
+            return Ok();
         }
     }
 }
\ No newline at end of file
diff --git a/loader/include/Geode/loader/Setting.hpp b/loader/include/Geode/loader/Setting.hpp
index 59078be0..05fb66d2 100644
--- a/loader/include/Geode/loader/Setting.hpp
+++ b/loader/include/Geode/loader/Setting.hpp
@@ -81,7 +81,7 @@ namespace geode {
 #define GEODE_INT_PARSE_SETTING_IMPL(obj, func, ...)              \
     if constexpr (std::is_base_of_v<__VA_ARGS__, Class>) {        \
         auto r = std::static_pointer_cast<Class>(res)->func(obj); \
-        if (!r) return Err(r.error());                            \
+        if (!r) return Err(r.unwrapErr());                        \
     }
 
 #define GEODE_INT_CONSTRAIN_SETTING_CAN_IMPL(func, ...)    \
diff --git a/loader/include/Geode/utils/NewResult.hpp b/loader/include/Geode/utils/NewResult.hpp
deleted file mode 100644
index 84eed72d..00000000
--- a/loader/include/Geode/utils/NewResult.hpp
+++ /dev/null
@@ -1,277 +0,0 @@
-#pragma once
-
-#include "../DefaultInclude.hpp"
-
-#include <string>
-#include <string_view>
-#include <variant>
-
-namespace geode {
-    namespace {
-        struct AnyType {
-            explicit AnyType() = delete;
-        };
-
-        template <class V, class RV>
-        concept ConvertibleToResult =
-            std::is_convertible_v<std::remove_reference_t<V>, std::remove_reference_t<RV>> ||
-            std::is_same_v<std::remove_reference_t<V>, std::remove_reference_t<RV>>;
-
-        using DefaultValue = std::monostate;
-        using DefaultError = std::string;
-    }
-
-    template <class T = DefaultValue, class E = DefaultError>
-    class [[nodiscard]] NewResult {
-    public:
-        using value_type = std::remove_reference_t<T>;
-        using error_type = std::remove_reference_t<E>;
-
-        // for some reason doing requires causes errors with pch...
-        static_assert(
-            std::is_copy_constructible_v<value_type> || std::is_move_constructible_v<value_type>,
-            "T must be copiable or movable!"
-        );
-        static_assert(
-            std::is_copy_constructible_v<error_type> || std::is_move_constructible_v<error_type>,
-            "E must be copiable or movable!"
-        );
-
-    protected:
-        std::variant<value_type, error_type> m_value;
-
-    public:
-        bool isOk() const {
-            return std::holds_alternative<value_type>(m_value);
-        }
-
-        bool isErr() const {
-            return std::holds_alternative<error_type>(m_value);
-        }
-
-        explicit NewResult(value_type const& value
-        ) requires std::is_copy_constructible_v<value_type> : m_value(value) {}
-
-        explicit NewResult(value_type&& value) requires std::is_move_constructible_v<value_type> :
-            m_value(std::forward<value_type>(value)) {}
-
-        explicit NewResult(error_type const& value
-        ) requires std::is_copy_constructible_v<error_type> : m_value(value) {}
-
-        explicit NewResult(error_type&& value) requires std::is_move_constructible_v<error_type> :
-            m_value(std::forward<error_type>(value)) {}
-
-        NewResult(NewResult<T, E> const& other) requires std::is_copy_constructible_v<value_type> &&
-            std::is_copy_constructible_v<error_type>
-        = default;
-
-        NewResult(NewResult<T, E>&& other
-        ) requires(!std::is_copy_constructible_v<value_type> || !std::is_copy_constructible_v<error_type>) =
-            default;
-
-        template <class T2, class E2>
-        requires ConvertibleToResult<T2, T> && ConvertibleToResult<E2, E> NewResult(
-            NewResult<T2, E2> const& other
-        )
-
-        requires std::is_copy_constructible_v<value_type> &&
-            std::is_copy_constructible_v<error_type> :
-            m_value(other.isOk() ? other.unwrap() : other.unwrapErr()) {}
-
-        template <class T2, class E2>
-        requires ConvertibleToResult<T2, T> && ConvertibleToResult<E2, E> NewResult(
-            NewResult<T2, E2>&& other
-        )
-
-        requires(!std::is_copy_constructible_v<value_type> || !std::is_copy_constructible_v<error_type>) :
-            m_value(other.isOk() ? other.unwrap() : other.unwrapErr()) {}
-
-        template <class T2>
-        requires ConvertibleToResult<T2, T> NewResult(NewResult<T2, AnyType> const& other)
-
-        requires std::is_copy_constructible_v<value_type> &&
-            std::is_copy_constructible_v<error_type> : NewResult(value_type(other.unwrap())) {}
-
-        template <class E2>
-        requires ConvertibleToResult<E2, E> NewResult(NewResult<AnyType, E2> const& other)
-
-        requires std::is_copy_constructible_v<value_type> &&
-            std::is_copy_constructible_v<error_type> :
-            m_value(std::forward<E2>(other.unwrapErr())) {}
-
-        template <class T2>
-        requires ConvertibleToResult<T2, T> NewResult(NewResult<T2, AnyType>&& other)
-
-        requires(!std::is_copy_constructible_v<value_type> || !std::is_copy_constructible_v<error_type>) :
-            m_value(other.unwrap()) {}
-
-        template <class E2>
-        requires ConvertibleToResult<E2, E> NewResult(NewResult<AnyType, E2>&& other)
-
-        requires(!std::is_copy_constructible_v<value_type> || !std::is_copy_constructible_v<error_type>) :
-            NewResult(std::forward<error_type>(other.unwrapErr())) {}
-
-        value_type unwrap() const requires std::is_copy_constructible_v<value_type> {
-            return std::get<value_type>(m_value);
-        }
-
-        value_type&& unwrap() requires(!std::is_copy_constructible_v<value_type>) {
-            return std::move(std::get<value_type>(m_value));
-        }
-
-        error_type unwrapErr() const requires std::is_copy_constructible_v<error_type> {
-            return std::get<error_type>(m_value);
-        }
-
-        error_type&& unwrapErr() requires(!std::is_copy_constructible_v<error_type>) {
-            return std::move(std::get<error_type>(m_value));
-        }
-
-        explicit operator bool() const
-            requires(!std::is_same_v<T, bool> && !std::is_same_v<E, bool>) {
-            return this->isOk();
-        }
-    };
-
-    template <class T>
-    class [[nodiscard]] NewResult<T, T> {
-    public:
-        using value_type = std::remove_reference_t<T>;
-        using error_type = std::remove_reference_t<T>;
-
-        // for some reason doing requires causes errors with pch...
-        static_assert(
-            std::is_copy_constructible_v<value_type> || std::is_move_constructible_v<value_type>,
-            "T must be copiable or movable!"
-        );
-
-    protected:
-        bool m_success;
-        value_type m_value;
-
-    public:
-        bool isOk() const {
-            return m_success;
-        }
-
-        bool isErr() const {
-            return !m_success;
-        }
-
-        explicit NewResult(value_type const& value, bool success) requires
-            std::is_copy_constructible_v<value_type> :
-            m_value(value),
-            m_success(success) {}
-
-        explicit NewResult(value_type&& value, bool success) requires
-            std::is_move_constructible_v<value_type> :
-            m_value(std::forward<value_type>(value)),
-            m_success(success) {}
-
-        NewResult(NewResult<T, T> const& other) requires std::is_copy_constructible_v<value_type>
-        = default;
-
-        NewResult(NewResult<T, T>&& other
-        ) requires(!std::is_copy_constructible_v<value_type>) = default;
-
-        template <class T2, class E2>
-        requires ConvertibleToResult<T2, T> && ConvertibleToResult<E2, T> NewResult(
-            NewResult<T2, E2> const& other
-        )
-
-        requires std::is_copy_constructible_v<value_type> :
-            m_value(other.isOk() ? other.unwrap() : other.unwrapErr()),
-            m_success(other.isOk()) {}
-
-        template <class T2, class E2>
-        requires ConvertibleToResult<T2, T> && ConvertibleToResult<E2, T> NewResult(
-            NewResult<T2, E2>&& other
-        )
-
-        requires(!std::is_copy_constructible_v<value_type>) :
-            m_value(other.isOk() ? other.unwrap() : other.unwrapErr()), m_success(other.isOk()) {}
-
-        template <class T2>
-        requires ConvertibleToResult<T2, T> NewResult(NewResult<T2, AnyType> const& other)
-
-        requires std::is_copy_constructible_v<value_type> :
-            NewResult(value_type(other.unwrap()), true) {}
-
-        template <class T2>
-        requires ConvertibleToResult<T2, T> NewResult(NewResult<T2, AnyType>&& other)
-
-        requires(!std::is_copy_constructible_v<value_type>) :
-            NewResult(std::forward<value_type>(other.unwrap()), true) {}
-
-        template <class E2>
-        requires ConvertibleToResult<E2, T> NewResult(NewResult<AnyType, E2> const& other)
-
-        requires std::is_copy_constructible_v<value_type> :
-            NewResult(error_type(other.unwrapErr()), false) {}
-
-        template <class E2>
-        requires ConvertibleToResult<E2, T> NewResult(NewResult<AnyType, E2>&& other)
-
-        requires(!std::is_copy_constructible_v<value_type>) :
-            NewResult(std::forward<error_type>(other.unwrapErr()), false) {}
-
-        value_type unwrap() const requires std::is_copy_constructible_v<value_type> {
-            return m_value;
-        }
-
-        value_type&& unwrap() requires(!std::is_copy_constructible_v<value_type>) {
-            return std::move(m_value);
-        }
-
-        error_type unwrapErr() const requires std::is_copy_constructible_v<error_type> {
-            return m_value;
-        }
-
-        error_type&& unwrapErr() requires(!std::is_copy_constructible_v<error_type>) {
-            return std::move(m_value);
-        }
-
-        explicit operator bool() const requires(!std::is_same_v<T, bool>) {
-            return this->isOk();
-        }
-    };
-
-    template <class T = DefaultValue, class E = AnyType>
-
-    requires std::is_copy_constructible_v<T> NewResult<T, E> NewOk(T value = T()) {
-        return NewResult<T, E>(value);
-    }
-
-    template <class T = DefaultValue, class E = AnyType>
-
-    requires(!std::is_copy_constructible_v<T>) NewResult<T, E> NewOk(T&& value) {
-        return NewResult<T, E>(std::forward<T>(value));
-    }
-
-    template <class E = DefaultError, class T = AnyType>
-
-    requires std::is_copy_constructible_v<E> NewResult<T, E> NewErr(E error = E()) {
-        return NewResult<T, E>(error);
-    }
-
-    template <class E = DefaultError, class T = AnyType>
-
-    requires(!std::is_copy_constructible_v<E>) NewResult<T, E> NewErr(E&& error) {
-        return NewResult<T, E>(std::forward<E>(error));
-    }
-
-#define GEODE_UNWRAP_INTO(into, ...)                                     \
-    auto GEODE_CONCAT(res_, __LINE__) = (__VA_ARGS__);                   \
-    if (GEODE_CONCAT(res_, __LINE__).isErr()) {                          \
-        return Err(std::move(GEODE_CONCAT(res_, __LINE__).unwrapErr())); \
-    }                                                                    \
-    into = std::move(GEODE_CONCAT(res_, __LINE__).unwrap())
-
-#define GEODE_UNWRAP(...)                                                    \
-    {                                                                        \
-        auto GEODE_CONCAT(res_, __LINE__) = (__VA_ARGS__);                   \
-        if (GEODE_CONCAT(res_, __LINE__).isErr()) {                          \
-            return Err(std::move(GEODE_CONCAT(res_, __LINE__).unwrapErr())); \
-        }                                                                    \
-    }
-}
diff --git a/loader/include/Geode/utils/Result.hpp b/loader/include/Geode/utils/Result.hpp
index 1f7971cc..11b4c816 100644
--- a/loader/include/Geode/utils/Result.hpp
+++ b/loader/include/Geode/utils/Result.hpp
@@ -1,176 +1,303 @@
 #pragma once
 
-#include "NewResult.hpp"
-#include "types.hpp"
+#include "../DefaultInclude.hpp"
 
-#include <Geode/DefaultInclude.hpp>
+#include <string>
 #include <string_view>
+#include <variant>
+#include <fmt/format.h>
 
 namespace geode {
-    /**
-     * @struct no_result
-     * The default value of a Result.
-     * Represents a Result that has no
-     * data to carry on Success, but
-     * may still return extended
-     * error information on failure.
-     */
-    struct no_result {};
-
-    /**
-     * @class Result
-     * Represents an optional value with an
-     * associated error state and -information.
-     * Use the Ok<T> and Err<T> classes to
-     * create Result(s).
-     * @param T Success result value type
-     * @param E Error message type
-     * @authors Matcool, HJfod
-     */
-    template <class T = no_result, class E = std::string>
-    class [[nodiscard]] Result {
-    protected:
-        bool success;
-
-        union {
-            T my_value;
-            E error_msg;
+    namespace {
+        struct AnyType {
+            explicit AnyType() = delete;
         };
 
-        Result(const T value) : success(true), my_value(value) {}
+        template <class V, class RV>
+        concept ConvertibleToResult =
+            std::is_convertible_v<std::remove_reference_t<V>, std::remove_reference_t<RV>> ||
+            std::is_same_v<std::remove_reference_t<V>, std::remove_reference_t<RV>>;
 
-        Result(const E error, int dummy) : success(false), error_msg(error) {}
-
-    public:
-        /**
-         * Destructor
-         */
-        ~Result() {
-            if (success) {
-                if (std::is_destructible<T>::value) {
-                    my_value.~T();
-                }
-            }
-            else {
-                if (std::is_destructible<E>::value) {
-                    error_msg.~E();
-                }
-            }
-        }
-
-        /**
-         * Copy another Result of the same type
-         */
-        Result(Result<T, E> const& other) {
-            if (other.success) {
-                this->success = true;
-                new (&this->my_value) T(other.value());
-            }
-            else {
-                this->success = false;
-                new (&this->error_msg) E(other.error());
-            }
-        }
-
-        /**
-         * Copy another Result of a convertible type
-         */
-        template <class T2, class E2>
-        Result(Result<T2, E2> const& other) {
-            if (other.is_value()) {
-                this->success = true;
-                if constexpr (!std::is_same<T, no_result>::value) {
-                    new (&this->my_value) T(other.value());
-                }
-            }
-            else {
-                this->success = false;
-                new (&this->error_msg) E(other.error());
-            }
-        }
-
-        /**
-         * Check if Result was errorful
-         * @returns True if errorful
-         */
-        bool is_error() const {
-            return !success;
-        }
-
-        /**
-         * Check if Result was succesful
-         * @returns True if succesful
-         */
-        bool is_value() const {
-            return success;
-        }
-
-        /**
-         * Get the success value of a Result
-         * @returns Value
-         */
-        auto value() const {
-            return my_value;
-        }
-
-        /**
-         * Get the error message of a Result
-         * @returns Error
-         */
-        auto error() const {
-            return error_msg;
-        }
-
-        /**
-         * Convert to bool
-         * @example if (result) { <handle success> } else { <handle failure> }
-         */
-        explicit operator bool() const {
-            return this->success;
-        }
-
-        /**
-         * Create a success result
-         * @param value Value
-         */
-        static auto ok(const T value) {
-            return Result<T>(value);
-        }
-
-        /**
-         * Create an error result
-         * @param error Error information
-         */
-        static auto err(E error) {
-            return Result<T>(error, 0);
-        }
-    };
-
-    /**
-     * Create a succesful Result with a value
-     * @param value The value. If none is provided, the type will be no_result
-     * @returns Successful Result
-     */
-    template <class T = no_result>
-    [[nodiscard]] Result<T> Ok(T value = T()) {
-        return Result<T>::ok(value);
+        using DefaultValue = std::monostate;
+        using DefaultError = std::string;
     }
 
-    /**
-     * @class Err
-     * Create an errorful Result with an error message
-     * @param value Error message
-     * @returns Errorful Result
-     */
-    template <class E = std::string>
-    struct [[nodiscard]] Err {
-        const E _value;
+    template <class T = DefaultValue, class E = DefaultError>
+    class [[nodiscard]] Result {
+    public:
+        using value_type = std::remove_reference_t<T>;
+        using error_type = std::remove_reference_t<E>;
 
-        Err(TypeIdentityType<E> const value) : _value(value) {}
+        // for some reason doing requires causes errors with pch...
+        static_assert(
+            std::is_copy_constructible_v<value_type> || std::is_move_constructible_v<value_type>,
+            "T must be copiable or movable!"
+        );
+        static_assert(
+            std::is_copy_constructible_v<error_type> || std::is_move_constructible_v<error_type>,
+            "E must be copiable or movable!"
+        );
 
-        template <class T>
-        operator Result<T, E>() const {
-            return Result<T, E>::err(_value);
+    protected:
+        std::variant<value_type, error_type> m_value;
+
+    public:
+        bool isOk() const {
+            return std::holds_alternative<value_type>(m_value);
+        }
+
+        bool isErr() const {
+            return std::holds_alternative<error_type>(m_value);
+        }
+
+        template<class ... Args>
+        Result<T, std::string> expect(const char* str, Args&&... args) {
+            if (isErr()) {
+                return Result(fmt::format(str, std::forward<Args>(args)...));
+            } else {
+                return this;
+            }
+        }
+
+        explicit Result(value_type const& value
+        ) requires std::is_copy_constructible_v<value_type> : m_value(value) {}
+
+        explicit Result(value_type&& value) requires std::is_move_constructible_v<value_type> :
+            m_value(std::forward<value_type>(value)) {}
+
+        explicit Result(error_type const& value
+        ) requires std::is_copy_constructible_v<error_type> : m_value(value) {}
+
+        explicit Result(error_type&& value) requires std::is_move_constructible_v<error_type> :
+            m_value(std::forward<error_type>(value)) {}
+
+        Result(Result<T, E> const& other) requires std::is_copy_constructible_v<value_type> &&
+            std::is_copy_constructible_v<error_type>
+        = default;
+
+        Result(Result<T, E>&& other
+        ) requires(!std::is_copy_constructible_v<value_type> || !std::is_copy_constructible_v<error_type>) =
+            default;
+
+        template <class T2, class E2>
+        requires ConvertibleToResult<T2, T> && ConvertibleToResult<E2, E> Result(
+            Result<T2, E2> const& other
+        )
+
+        requires std::is_copy_constructible_v<value_type> &&
+            std::is_copy_constructible_v<error_type>
+        {
+            if (other.isOk()) {
+                m_value = other.unwrap();
+            } else {
+                m_value = other.unwrapErr();
+            }
+        }
+
+        template <class T2, class E2>
+        requires ConvertibleToResult<T2, T> && ConvertibleToResult<E2, E> Result(
+            Result<T2, E2>&& other
+        )
+
+        requires(!std::is_copy_constructible_v<value_type> || !std::is_copy_constructible_v<error_type>) :
+            m_value(other.isOk() ? other.unwrap() : other.unwrapErr()) {}
+
+        template <class T2>
+        requires ConvertibleToResult<T2, T> Result(Result<T2, AnyType> const& other)
+
+        requires std::is_copy_constructible_v<value_type> &&
+            std::is_copy_constructible_v<error_type> : Result(value_type(other.unwrap())) {}
+
+        template <class E2>
+        requires ConvertibleToResult<E2, E> Result(Result<AnyType, E2> const& other)
+
+        requires std::is_copy_constructible_v<value_type> &&
+            std::is_copy_constructible_v<error_type> :
+            m_value(std::forward<E2>(other.unwrapErr())) {}
+
+        template <class T2>
+        requires ConvertibleToResult<T2, T> Result(Result<T2, AnyType>&& other)
+
+        requires(!std::is_copy_constructible_v<value_type> || !std::is_copy_constructible_v<error_type>) :
+            m_value(other.unwrap()) {}
+
+        template <class E2>
+        requires ConvertibleToResult<E2, E> Result(Result<AnyType, E2>&& other)
+
+        requires(!std::is_copy_constructible_v<value_type> || !std::is_copy_constructible_v<error_type>) :
+            Result(std::forward<error_type>(other.unwrapErr())) {}
+
+        value_type unwrap() const requires std::is_copy_constructible_v<value_type> {
+            return std::get<value_type>(m_value);
+        }
+
+        value_type&& unwrap() requires(!std::is_copy_constructible_v<value_type>) {
+            return std::move(std::get<value_type>(m_value));
+        }
+
+        error_type unwrapErr() const requires std::is_copy_constructible_v<error_type> {
+            return std::get<error_type>(m_value);
+        }
+
+        error_type&& unwrapErr() requires(!std::is_copy_constructible_v<error_type>) {
+            return std::move(std::get<error_type>(m_value));
+        }
+
+        explicit operator bool() const
+            requires(!std::is_same_v<T, bool> && !std::is_same_v<E, bool>) {
+            return this->isOk();
         }
     };
+
+    template <class T>
+    class [[nodiscard]] Result<T, T> {
+    public:
+        using value_type = std::remove_reference_t<T>;
+        using error_type = std::remove_reference_t<T>;
+
+        // for some reason doing requires causes errors with pch...
+        static_assert(
+            std::is_copy_constructible_v<value_type> || 
+            std::is_move_constructible_v<value_type>,
+            "T must be copiable or movable!"
+        );
+
+    protected:
+        bool m_success;
+        value_type m_value;
+
+    public:
+        bool isOk() const {
+            return m_success;
+        }
+
+        bool isErr() const {
+            return !m_success;
+        }
+
+        template<class ... Args>
+        Result<T, std::string> expect(const char* str, Args&&... args) {
+            if (isErr()) {
+                return Result(fmt::format(str, std::forward<Args>(args)...), false);
+            } else {
+                return *this;
+            }
+        }
+
+        explicit Result(value_type const& value, bool success) requires
+            std::is_copy_constructible_v<value_type> :
+            m_value(value),
+            m_success(success) {}
+
+        explicit Result(value_type&& value, bool success) requires
+            std::is_move_constructible_v<value_type> :
+            m_value(std::forward<value_type>(value)),
+            m_success(success) {}
+
+        Result(Result<T, T> const& other) requires std::is_copy_constructible_v<value_type>
+        = default;
+
+        Result(Result<T, T>&& other
+        ) requires(!std::is_copy_constructible_v<value_type>) = default;
+
+        template <class T2, class E2>
+        requires ConvertibleToResult<T2, T> && ConvertibleToResult<E2, T> Result(
+            Result<T2, E2> const& other
+        )
+
+        requires std::is_copy_constructible_v<value_type> :
+            m_value(other.isOk() ? other.unwrap() : other.unwrapErr()),
+            m_success(other.isOk()) {}
+
+        template <class T2, class E2>
+        requires ConvertibleToResult<T2, T> && ConvertibleToResult<E2, T> Result(
+            Result<T2, E2>&& other
+        )
+
+        requires(!std::is_copy_constructible_v<value_type>) :
+            m_value(other.isOk() ? other.unwrap() : other.unwrapErr()), m_success(other.isOk()) {}
+
+        template <class T2>
+        requires ConvertibleToResult<T2, T> Result(Result<T2, AnyType> const& other)
+
+        requires std::is_copy_constructible_v<value_type> :
+            Result(value_type(other.unwrap()), true) {}
+
+        template <class T2>
+        requires ConvertibleToResult<T2, T> Result(Result<T2, AnyType>&& other)
+
+        requires(!std::is_copy_constructible_v<value_type>) :
+            Result(std::forward<value_type>(other.unwrap()), true) {}
+
+        template <class E2>
+        requires ConvertibleToResult<E2, T> Result(Result<AnyType, E2> const& other)
+
+        requires std::is_copy_constructible_v<value_type> :
+            Result(error_type(other.unwrapErr()), false) {}
+
+        template <class E2>
+        requires ConvertibleToResult<E2, T> Result(Result<AnyType, E2>&& other)
+
+        requires(!std::is_copy_constructible_v<value_type>) :
+            Result(std::forward<error_type>(other.unwrapErr()), false) {}
+
+        value_type unwrap() const requires std::is_copy_constructible_v<value_type> {
+            return m_value;
+        }
+
+        value_type&& unwrap() requires(!std::is_copy_constructible_v<value_type>) {
+            return std::move(m_value);
+        }
+
+        error_type unwrapErr() const requires std::is_copy_constructible_v<error_type> {
+            return m_value;
+        }
+
+        error_type&& unwrapErr() requires(!std::is_copy_constructible_v<error_type>) {
+            return std::move(m_value);
+        }
+
+        explicit operator bool() const requires(!std::is_same_v<T, bool>) {
+            return this->isOk();
+        }
+    };
+
+    template <class T = DefaultValue, class E = AnyType>
+
+    requires std::is_copy_constructible_v<T> Result<T, E> Ok(T value = T()) {
+        return Result<T, E>(value);
+    }
+
+    template <class T = DefaultValue, class E = AnyType>
+
+    requires(!std::is_copy_constructible_v<T>) Result<T, E> Ok(T&& value) {
+        return Result<T, E>(std::forward<T>(value));
+    }
+
+    template <class E = DefaultError, class T = AnyType>
+
+    requires std::is_copy_constructible_v<E> Result<T, E> Err(E error = E()) {
+        return Result<T, E>(error);
+    }
+
+    template <class E = DefaultError, class T = AnyType>
+
+    requires(!std::is_copy_constructible_v<E>) Result<T, E> Err(E&& error) {
+        return Result<T, E>(std::forward<E>(error));
+    }
+
+#define GEODE_UNWRAP_INTO(into, ...)                                            \
+    auto GEODE_CONCAT(unwrap_res_, __LINE__) = (__VA_ARGS__);                   \
+    if (GEODE_CONCAT(unwrap_res_, __LINE__).isErr()) {                          \
+        return Err(std::move(GEODE_CONCAT(unwrap_res_, __LINE__).unwrapErr())); \
+    }                                                                           \
+    into = std::move(GEODE_CONCAT(unwrap_res_, __LINE__).unwrap())
+
+#define GEODE_UNWRAP(...)                                                           \
+    {                                                                               \
+        auto GEODE_CONCAT(unwrap_res_, __LINE__) = (__VA_ARGS__);                   \
+        if (GEODE_CONCAT(unwrap_res_, __LINE__).isErr()) {                          \
+            return Err(std::move(GEODE_CONCAT(unwrap_res_, __LINE__).unwrapErr())); \
+        }                                                                           \
+    }
 }
diff --git a/loader/include/Geode/utils/fetch.hpp b/loader/include/Geode/utils/fetch.hpp
index b9fd6f60..0950bd25 100644
--- a/loader/include/Geode/utils/fetch.hpp
+++ b/loader/include/Geode/utils/fetch.hpp
@@ -3,6 +3,7 @@
 #include "../DefaultInclude.hpp"
 #include "Result.hpp"
 #include "json.hpp"
+#include "types.hpp"
 
 #include <fs/filesystem.hpp>
 #include <mutex>
@@ -46,10 +47,10 @@ namespace geode::utils::web {
      */
     template <class Json = nlohmann::json>
     Result<Json> fetchJSON(std::string const& url) {
-        auto res = fetch(url);
-        if (!res) return Err(res.error());
+        std::string res;
+        GEODE_UNWRAP_INTO(res, fetch(url));
         try {
-            return Ok(Json::parse(res.value()));
+            return Ok(Json::parse(res));
         }
         catch (std::exception& e) {
             return Err(e.what());
@@ -309,10 +310,10 @@ namespace geode::utils::web {
                             handle](SentAsyncWebRequest& req, byte_array const& arr) {
             auto conv = converter(arr);
             if (conv) {
-                handle(conv.value());
+                handle(conv.unwrap());
             }
             else {
-                req.error("Unable to convert value: " + conv.error());
+                req.error("Unable to convert value: " + conv.unwrapErr());
             }
         };
         return m_request;
diff --git a/loader/src/hooks/save.cpp b/loader/src/hooks/save.cpp
index 6c67759f..dc486006 100644
--- a/loader/src/hooks/save.cpp
+++ b/loader/src/hooks/save.cpp
@@ -10,7 +10,7 @@ struct SaveLoader : Modify<SaveLoader, AppDelegate> {
 
         auto r = Loader::get()->saveData();
         if (!r) {
-            log::log(Severity::Error, Loader::getInternalMod(), "{}", r.error());
+            log::log(Severity::Error, Loader::getInternalMod(), "{}", r.unwrapErr());
         }
 
         log::log(Severity::Info, Loader::getInternalMod(), "Saved");
diff --git a/loader/src/index/Index.cpp b/loader/src/index/Index.cpp
index a073ae0f..32bf78f2 100644
--- a/loader/src/index/Index.cpp
+++ b/loader/src/index/Index.cpp
@@ -20,12 +20,12 @@
 
 template <class Json = nlohmann::json>
 static Result<Json> readJSON(ghc::filesystem::path const& path) {
-    auto indexJsonData = utils::file::readString(path);
-    if (!indexJsonData) {
-        return Err("Unable to read " + path.string());
-    }
+    GEODE_UNWRAP_INTO(
+        std::string indexJsonData,
+        utils::file::readString(path).expect("Unable to read {}", path.string())
+    );
     try {
-        return Ok(Json::parse(indexJsonData.value()));
+        return Ok(Json::parse(indexJsonData));
     }
     catch (std::exception& e) {
         return Err("Error parsing JSON: " + std::string(e.what()));
@@ -110,7 +110,7 @@ void Index::updateIndex(IndexUpdateCallback callback, bool force) {
     if (ghc::filesystem::exists(indexDir / "current")) {
         auto data = utils::file::readString(indexDir / "current");
         if (data) {
-            currentCommitSHA = data.value();
+            currentCommitSHA = data.unwrap();
         }
     }
 
@@ -128,7 +128,7 @@ void Index::updateIndex(IndexUpdateCallback callback, bool force) {
             if (upcomingCommitSHA == "") {
                 auto err = this->updateIndexFromLocalCache();
                 if (!err) {
-                    RETURN_ERROR(err.error());
+                    RETURN_ERROR(err.unwrapErr());
                 }
                 
                 m_upToDate = true;
@@ -162,13 +162,13 @@ void Index::updateIndex(IndexUpdateCallback callback, bool force) {
                         // unzip new index
                         auto unzip = file::unzipTo(indexDir / "index.zip", indexDir);
                         if (!unzip) {
-                            RETURN_ERROR(unzip.error());
+                            RETURN_ERROR(unzip.unwrapErr());
                         }
 
                         // update index
                         auto err = this->updateIndexFromLocalCache();
                         if (!err) {
-                            RETURN_ERROR(err.error());
+                            RETURN_ERROR(err.unwrapErr());
                         }
 
                         m_upToDate = true;
@@ -190,7 +190,7 @@ void Index::updateIndex(IndexUpdateCallback callback, bool force) {
             else {
                 auto err = this->updateIndexFromLocalCache();
                 if (!err) {
-                    RETURN_ERROR(err.error());
+                    RETURN_ERROR(err.unwrapErr());
                 }
 
                 m_upToDate = true;
@@ -214,10 +214,10 @@ void Index::addIndexItemFromFolder(ghc::filesystem::path const& dir) {
     if (ghc::filesystem::exists(dir / "index.json")) {
         auto readJson = readJSON(dir / "index.json");
         if (!readJson) {
-            log::warn("Error reading index.json: {}, skipping", readJson.error());
+            log::warn("Error reading index.json: {}, skipping", readJson.unwrapErr());
             return;
         }
-        auto json = readJson.value();
+        auto json = readJson.unwrap();
         if (!json.is_object()) {
             log::warn("[index.json] is not an object, skipping");
             return;
@@ -225,10 +225,10 @@ void Index::addIndexItemFromFolder(ghc::filesystem::path const& dir) {
 
         auto infoRes = ModInfo::createFromFile(dir / "mod.json");
         if (!infoRes) {
-            log::warn("{}: {}, skipping", dir, infoRes.error());
+            log::warn("{}: {}, skipping", dir, infoRes.unwrapErr());
             return;
         }
-        auto info = infoRes.value();
+        auto info = infoRes.unwrap();
 
         // make sure only latest version is present in index
         auto old = std::find_if(m_items.begin(), m_items.end(), [info](IndexItem const& item) {
@@ -283,7 +283,7 @@ void Index::addIndexItemFromFolder(ghc::filesystem::path const& dir) {
                     log::warn("[index.json].categories is not an array, skipping");
                     return;
                 }
-                item.m_categories = json["categories"].get<std::unordered_set<std::string>>();
+                item.m_categories = json["categories"].template get<std::unordered_set<std::string>>();
                 m_categories.insert(item.m_categories.begin(), item.m_categories.end());
             }
         }
@@ -305,7 +305,7 @@ Result<> Index::updateIndexFromLocalCache() {
 
     // load geode.json (index settings)
     if (auto baseIndexJson = readJSON(baseIndexDir / "geode.json")) {
-        auto json = baseIndexJson.value();
+        auto json = baseIndexJson.unwrap();
         auto checker = JsonChecker(json);
         checker.root("[index/geode.json]").obj().has("featured").into(m_featured);
     }
@@ -440,11 +440,8 @@ Result<InstallHandle> Index::installItems(std::vector<IndexItem> const& items) {
                 "the Geode developers - this should not happen, ever."
             );
         }
-        auto list = checkDependenciesForItem(item);
-        if (!list) {
-            return Err(list.error());
-        }
-        ranges::push(ids, list.value());
+        GEODE_UNWRAP_INTO(auto list, checkDependenciesForItem(item));
+        ranges::push(ids, list);
     }
     auto ret = std::make_shared<InstallItems>(std::unordered_set(ids.begin(), ids.end()));
     m_installations.insert(ret);
@@ -636,7 +633,7 @@ InstallItems::CallbackID InstallItems::start(ItemInstallCallback callback, bool
                 .then([this, replaceFiles, item, inst, indexDir, tempFile](auto) {
                     // check for 404
                     auto notFound = utils::file::readString(tempFile);
-                    if (notFound && notFound.value() == "Not Found") {
+                    if (notFound && notFound.unwrap() == "Not Found") {
                         try {
                             ghc::filesystem::remove(tempFile);
                         }
diff --git a/loader/src/internal/InternalLoader.cpp b/loader/src/internal/InternalLoader.cpp
index 23eeb19e..e5ad867e 100644
--- a/loader/src/internal/InternalLoader.cpp
+++ b/loader/src/internal/InternalLoader.cpp
@@ -110,7 +110,7 @@ void InternalLoader::downloadLoaderResources(IndexUpdateCallback callback) {
             if (!unzip) {
                 if (callback)
                     callback(
-                        UpdateStatus::Failed, "Unable to unzip new resources: " + unzip.error(), 0
+                        UpdateStatus::Failed, "Unable to unzip new resources: " + unzip.unwrapErr(), 0
                     );
                 return;
             }
diff --git a/loader/src/internal/InternalMod.cpp b/loader/src/internal/InternalMod.cpp
index b3002bd9..c814fd2a 100644
--- a/loader/src/internal/InternalMod.cpp
+++ b/loader/src/internal/InternalMod.cpp
@@ -12,17 +12,17 @@ static ModInfo getInternalModInfo() {
     try {
         auto json = ModJson::parse(LOADER_MOD_JSON);
         auto infoRes = ModInfo::create(json);
-        if (infoRes.is_error()) {
+        if (infoRes.isErr()) {
             InternalLoader::platformMessageBox(
                 "Fatal Internal Error",
-                "Unable to parse loader mod.json: \"" + infoRes.error() +
+                "Unable to parse loader mod.json: \"" + infoRes.unwrapErr() +
                     "\"\n"
                     "This is a fatal internal error in the loader, please "
                     "contact Geode developers immediately!"
             );
             exit(1);
         }
-        auto info = infoRes.value();
+        auto info = infoRes.unwrap();
         info.m_details = LOADER_ABOUT_MD;
         info.m_supportInfo = SUPPORT_INFO;
         info.m_supportsDisabling = false;
@@ -50,7 +50,7 @@ InternalMod::InternalMod() : Mod(getInternalModInfo()) {
 
     auto sett = this->loadSettings();
     if (!sett) {
-        log::log(Severity::Error, this, "{}", sett.error());
+        log::log(Severity::Error, this, "{}", sett.unwrapErr());
     }
 }
 
diff --git a/loader/src/load/Hook.cpp b/loader/src/load/Hook.cpp
index 6997d148..d673a6e6 100644
--- a/loader/src/load/Hook.cpp
+++ b/loader/src/load/Hook.cpp
@@ -33,18 +33,18 @@ Result<> Mod::enableHook(Hook* hook) {
             log::debug("Enabling hook at function {}", hook->m_displayName);
             this->m_hooks.push_back(hook);
             hook->m_enabled = true;
-            hook->m_handle = res.value();
-            return Ok<>();
+            hook->m_handle = res.unwrap();
+            return Ok();
         }
         else {
-            return Err<>(
+            return Err(
                 "Unable to create hook at " +
                 std::to_string(reinterpret_cast<uintptr_t>(hook->m_address))
             );
         }
-        return Err<>("Hook already has a handle");
+        return Err("Hook already has a handle");
     }
-    return Ok<>();
+    return Ok();
 }
 
 Result<> Mod::disableHook(Hook* hook) {
@@ -52,11 +52,11 @@ Result<> Mod::disableHook(Hook* hook) {
         if (geode::core::hook::remove(hook->m_handle)) {
             log::debug("Disabling hook at function {}", hook->m_displayName);
             hook->m_enabled = false;
-            return Ok<>();
+            return Ok();
         }
-        return Err<>("Unable to remove hook");
+        return Err("Unable to remove hook");
     }
-    return Ok<>();
+    return Ok();
 }
 
 Result<> Mod::removeHook(Hook* hook) {
@@ -73,7 +73,7 @@ Result<Hook*> Mod::addHook(Hook* hook) {
         auto res = this->enableHook(hook);
         if (!res) {
             delete hook;
-            return Err<>("Can't create hook");
+            return Err("Can't create hook");
         }
     }
     else {
@@ -88,7 +88,7 @@ bool InternalLoader::loadHooks() {
     for (auto const& hook : internalHooks()) {
         auto res = hook.mod->addHook(hook.hook);
         if (!res) {
-            log::log(Severity::Error, hook.mod, "{}", res.error());
+            log::log(Severity::Error, hook.mod, "{}", res.unwrapErr());
             thereWereErrors = true;
         }
     }
diff --git a/loader/src/load/Loader.cpp b/loader/src/load/Loader.cpp
index f124ea11..00445cfc 100644
--- a/loader/src/load/Loader.cpp
+++ b/loader/src/load/Loader.cpp
@@ -184,17 +184,17 @@ size_t Loader::loadModsFromDirectory(
             loadedCount++;
 
             // check for dependencies
-            if (!res.value()->hasUnresolvedDependencies()) {
-                log::debug("Successfully loaded {}", res.value());
+            if (!res.unwrap()->hasUnresolvedDependencies()) {
+                log::debug("Successfully loaded {}", res.unwrap());
             }
             else {
-                log::error("{} has unresolved dependencies", res.value());
+                log::error("{} has unresolved dependencies", res.unwrap());
             }
         }
         else {
             // something went wrong
-            log::error("{}", res.error());
-            m_erroredMods.push_back({ entry.path().string(), res.error() });
+            log::error("{}", res.unwrapErr());
+            m_erroredMods.push_back({ entry.path().string(), res.unwrapErr() });
         }
     }
 
@@ -213,8 +213,8 @@ size_t Loader::refreshMods() {
             auto res = this->loadModFromFile(path.string());
             if (!res) {
                 // something went wrong
-                log::error("{}", res.error());
-                m_erroredMods.push_back({ path.string(), res.error() });
+                log::error("{}", res.unwrapErr());
+                m_erroredMods.push_back({ path.string(), res.unwrapErr() });
             }
         }
     }
@@ -245,7 +245,7 @@ Result<> Loader::saveData() {
     for (auto& [_, mod] : m_mods) {
         auto r = mod->saveData();
         if (!r) {
-            log::warn("Unable to save data for mod \"{}\": {}", mod->getID(), r.error());
+            log::warn("Unable to save data for mod \"{}\": {}", mod->getID(), r.unwrapErr());
         }
     }
     return Ok();
@@ -257,7 +257,7 @@ Result<> Loader::loadData() {
     for (auto& [_, mod] : m_mods) {
         auto r = mod->loadData();
         if (!r) {
-            log::warn("Unable to load data for mod \"{}\": {}", mod->getID(), r.error());
+            log::warn("Unable to load data for mod \"{}\": {}", mod->getID(), r.unwrapErr());
         }
     }
     return Ok();
@@ -277,10 +277,7 @@ Result<> Loader::saveSettings() {
     json["early-load"] = m_loadedSettings.m_earlyLoadMods;
 
     // save loader settings
-    auto saveIS = InternalMod::get()->saveSettings();
-    if (!saveIS) {
-        return Err(saveIS.error());
-    }
+    GEODE_UNWRAP(InternalMod::get()->saveSettings());
 
     // save info alerts
     InternalLoader::get()->saveInfoAlerts(json);
@@ -298,12 +295,9 @@ Result<> Loader::loadSettings() {
     }
 
     // read mods.json
-    auto read = utils::file::readString(path);
-    if (!read) {
-        return read;
-    }
+    GEODE_UNWRAP_INTO(auto read, utils::file::readString(path));
     try {
-        auto json = nlohmann::json::parse(read.value());
+        auto json = nlohmann::json::parse(read);
         auto checker = JsonChecker(json);
         auto root = checker.root("[loader settings]").obj();
         root.has("early-load").into(m_loadedSettings.m_earlyLoadMods);
@@ -400,7 +394,7 @@ bool Loader::setup() {
     this->createDirectories();
     auto sett = this->loadData();
     if (!sett) {
-        log::warn("Unable to load loader settings: {}", sett.error());
+        log::warn("Unable to load loader settings: {}", sett.unwrapErr());
     }
     this->refreshMods();
 
diff --git a/loader/src/load/Mod.cpp b/loader/src/load/Mod.cpp
index 3ad11f18..9705447d 100644
--- a/loader/src/load/Mod.cpp
+++ b/loader/src/load/Mod.cpp
@@ -57,11 +57,10 @@ Result<> Mod::loadSettings() {
     // Check if settings exist
     auto settPath = m_saveDirPath / "settings.json";
     if (ghc::filesystem::exists(settPath)) {
-        auto settData = utils::file::readString(settPath);
-        if (!settData) return settData;
+        GEODE_UNWRAP_INTO(auto settData, utils::file::readString(settPath));
         try {
             // parse settings.json
-            auto data = nlohmann::json::parse(settData.value());
+            auto data = nlohmann::json::parse(settData);
             JsonChecker checker(data);
             auto root = checker.root("[settings.json]");
 
@@ -91,10 +90,9 @@ Result<> Mod::loadSettings() {
     // Saved values
     auto savedPath = m_saveDirPath / "saved.json";
     if (ghc::filesystem::exists(savedPath)) {
-        auto data = utils::file::readString(savedPath);
-        if (!data) return data;
+        GEODE_UNWRAP_INTO(auto data, utils::file::readString(savedPath));
         try {
-            m_saved = nlohmann::json::parse(data.value());
+            m_saved = nlohmann::json::parse(data);
         } catch(std::exception& e) {
             return Err(std::string("Unable to parse saved values: ") + e.what());
         }
@@ -106,10 +104,9 @@ Result<> Mod::loadSettings() {
         m_dataStore = m_info.m_defaultDataStore;
     }
     else {
-        auto dsData = utils::file::readString(dsPath);
-        if (!dsData) return dsData;
+        GEODE_UNWRAP_INTO(auto dsData, utils::file::readString(dsPath));
         try {
-            m_dataStore = nlohmann::json::parse(dsData.value());
+            m_dataStore = nlohmann::json::parse(dsData);
         }
         catch (std::exception& e) {
             return Err(std::string("Unable to parse datastore: ") + e.what());
@@ -190,11 +187,11 @@ Result<> Mod::createTempDir() {
     ZipFile unzip(m_info.m_path.string());
 
     if (!unzip.isLoaded()) {
-        return Err<>("Unable to unzip " + m_info.m_path.string());
+        return Err("Unable to unzip " + m_info.m_path.string());
     }
 
     if (!unzip.fileExists(m_info.m_binaryName)) {
-        return Err<>(
+        return Err(
             "Unable to find platform binary under the name \"" + m_info.m_binaryName + "\""
         );
     }
@@ -202,13 +199,13 @@ Result<> Mod::createTempDir() {
     auto tempDir = Loader::get()->getGeodeDirectory() / GEODE_TEMP_DIRECTORY;
     if (!ghc::filesystem::exists(tempDir)) {
         if (!ghc::filesystem::create_directory(tempDir)) {
-            return Err<>("Unable to create temp directory for mods!");
+            return Err("Unable to create temp directory for mods!");
         }
     }
 
     auto tempPath = ghc::filesystem::path(tempDir) / m_info.m_id;
     if (!ghc::filesystem::exists(tempPath) && !ghc::filesystem::create_directories(tempPath)) {
-        return Err<>("Unable to create temp directory");
+        return Err("Unable to create temp directory");
     }
     m_tempDirName = tempPath;
 
@@ -217,7 +214,7 @@ Result<> Mod::createTempDir() {
         if (path.has_parent_path()) {
             if (!ghc::filesystem::exists(tempPath / path.parent_path()) &&
                 !ghc::filesystem::create_directories(tempPath / path.parent_path())) {
-                return Err<>(
+                return Err(
                     "Unable to create directories \"" + path.parent_path().string() + "\""
                 );
             }
@@ -225,37 +222,37 @@ Result<> Mod::createTempDir() {
         unsigned long size;
         auto data = unzip.getFileData(file, &size);
         if (!data || !size) {
-            return Err<>("Unable to read \"" + std::string(file) + "\"");
+            return Err("Unable to read \"" + std::string(file) + "\"");
         }
         auto wrt = utils::file::writeBinary(tempPath / file, byte_array(data, data + size));
-        if (!wrt) return Err<>("Unable to write \"" + file + "\": " + wrt.error());
+        if (!wrt) return Err("Unable to write \"" + file + "\": " + wrt.unwrapErr());
     }
 
     m_addResourcesToSearchPath = true;
 
-    return Ok<>(tempPath);
+    return Ok();
 }
 
 Result<> Mod::load() {
     if (m_loaded) {
-        return Ok<>();
+        return Ok();
     }
 #define RETURN_LOAD_ERR(str)           \
     {                                  \
         m_loadErrorInfo = str;         \
-        return Err<>(m_loadErrorInfo); \
+        return Err(m_loadErrorInfo); \
     }
 
     if (!m_tempDirName.string().size()) {
         auto err = this->createTempDir();
-        if (!err) RETURN_LOAD_ERR("Unable to create temp directory: " + err.error());
+        if (!err) RETURN_LOAD_ERR("Unable to create temp directory: " + err.unwrapErr());
     }
 
     if (this->hasUnresolvedDependencies()) {
         RETURN_LOAD_ERR("Mod has unresolved dependencies");
     }
     auto err = this->loadPlatformBinary();
-    if (!err) RETURN_LOAD_ERR(err.error());
+    if (!err) RETURN_LOAD_ERR(err.unwrapErr());
     if (m_implicitLoadFunc) {
         auto r = m_implicitLoadFunc(this);
         if (!r) {
@@ -279,20 +276,20 @@ Result<> Mod::load() {
     ModStateEvent(this, ModEventType::Loaded).post();
     auto loadRes = this->loadData();
     if (!loadRes) {
-        log::warn("Unable to load data for \"{}\": {}", m_info.m_id, loadRes.error());
+        log::warn("Unable to load data for \"{}\": {}", m_info.m_id, loadRes.unwrapErr());
     }
     m_loadErrorInfo = "";
     Loader::get()->updateAllDependencies();
-    return Ok<>();
+    return Ok();
 }
 
 Result<> Mod::unload() {
     if (!m_loaded) {
-        return Ok<>();
+        return Ok();
     }
 
     if (!m_info.m_supportsUnloading) {
-        return Err<>("Mod does not support unloading");
+        return Err("Mod does not support unloading");
     }
     
     auto saveRes = this->saveData();
@@ -314,7 +311,7 @@ Result<> Mod::unload() {
 
     for (auto const& patch : m_patches) {
         if (!patch->restore()) {
-            return Err<>("Unable to restore patch at " + std::to_string(patch->getAddress()));
+            return Err("Unable to restore patch at " + std::to_string(patch->getAddress()));
         }
         delete patch;
     }
@@ -326,17 +323,17 @@ Result<> Mod::unload() {
     }
     m_loaded = false;
     Loader::get()->updateAllDependencies();
-    return Ok<>();
+    return Ok();
 }
 
 Result<> Mod::enable() {
     if (!m_loaded) {
-        return Err<>("Mod is not loaded");
+        return Err("Mod is not loaded");
     }
 
     if (m_enableFunc) {
         if (!m_enableFunc()) {
-            return Err<>("Mod enable function returned false");
+            return Err("Mod enable function returned false");
         }
     }
 
@@ -349,23 +346,23 @@ Result<> Mod::enable() {
 
     for (auto const& patch : m_patches) {
         if (!patch->apply()) {
-            return Err<>("Unable to apply patch at " + std::to_string(patch->getAddress()));
+            return Err("Unable to apply patch at " + std::to_string(patch->getAddress()));
         }
     }
 
     m_enabled = true;
 
-    return Ok<>();
+    return Ok();
 }
 
 Result<> Mod::disable() {
     if (!m_info.m_supportsDisabling) {
-        return Err<>("Mod does not support disabling");
+        return Err("Mod does not support disabling");
     }
 
     if (m_disableFunc) {
         if (!m_disableFunc()) {
-            return Err<>("Mod disable function returned false");
+            return Err("Mod disable function returned false");
         }
     }
 
@@ -378,13 +375,13 @@ Result<> Mod::disable() {
 
     for (auto const& patch : m_patches) {
         if (!patch->restore()) {
-            return Err<>("Unable to restore patch at " + std::to_string(patch->getAddress()));
+            return Err("Unable to restore patch at " + std::to_string(patch->getAddress()));
         }
     }
 
     m_enabled = false;
 
-    return Ok<>();
+    return Ok();
 }
 
 Result<> Mod::uninstall() {
@@ -397,13 +394,13 @@ Result<> Mod::uninstall() {
         }
     }
     if (!ghc::filesystem::remove(m_info.m_path)) {
-        return Err<>(
+        return Err(
             "Unable to delete mod's .geode file! "
             "This might be due to insufficient permissions - "
             "try running GD as administrator."
         );
     }
-    return Ok<>();
+    return Ok();
 }
 
 bool Mod::isUninstalled() const {
@@ -435,13 +432,13 @@ bool Mod::updateDependencyStates() {
                     auto r = dep.m_mod->load();
                     if (!r) {
                         dep.m_state = ModResolveState::Unloaded;
-                        log::log(Severity::Error, dep.m_mod, "{}", r.error());
+                        log::log(Severity::Error, dep.m_mod, "{}", r.unwrapErr());
                     }
                     else {
                         auto r = dep.m_mod->enable();
                         if (!r) {
                             dep.m_state = ModResolveState::Disabled;
-                            log::log(Severity::Error, dep.m_mod, "{}", r.error());
+                            log::log(Severity::Error, dep.m_mod, "{}", r.unwrapErr());
                         }
                     }
                 }
@@ -471,12 +468,12 @@ bool Mod::updateDependencyStates() {
             log::debug("Resolved & loading {}", m_info.m_id);
             auto r = this->load();
             if (!r) {
-                log::error("{} Error loading: {}", this, r.error());
+                log::error("{} Error loading: {}", this, r.unwrapErr());
             }
             else {
                 auto r = this->enable();
                 if (!r) {
-                    log::error("{} Error enabling: {}", this, r.error());
+                    log::error("{} Error enabling: {}", this, r.unwrapErr());
                 }
             }
         }
diff --git a/loader/src/load/ModInfo.cpp b/loader/src/load/ModInfo.cpp
index fc032c2b..f090cd5e 100644
--- a/loader/src/load/ModInfo.cpp
+++ b/loader/src/load/ModInfo.cpp
@@ -17,12 +17,6 @@ Result<ModInfo> ModInfo::createFromSchemaV010(ModJson const& rawJson) {
     auto json = rawJson;
     info.m_rawJSON = rawJson;
 
-#define PROPAGATE(err)                         \
-    {                                          \
-        auto err__ = err;                      \
-        if (!err__) return Err(err__.error()); \
-    }
-
     JsonChecker checker(json);
     auto root = checker.root("[mod.json]").obj();
 
@@ -59,9 +53,7 @@ Result<ModInfo> ModInfo::createFromSchemaV010(ModJson const& rawJson) {
     }
 
     for (auto& [key, value] : root.has("settings").items()) {
-        auto settRes = Setting::parse(key, value.json());
-        PROPAGATE(settRes);
-        auto sett = settRes.value();
+        GEODE_UNWRAP_INTO(auto sett, Setting::parse(key, value.json()));
         sett->m_modID = info.m_id;
         info.m_settings.push_back({ key, sett });
     }
@@ -180,18 +172,12 @@ Result<ModInfo> ModInfo::create(ModJson const& json) {
 
 Result<ModInfo> ModInfo::createFromFile(ghc::filesystem::path const& path) {
     try {
-        auto read = utils::file::readString(path);
-        if (!read) return Err(read.error());
+        GEODE_UNWRAP_INTO(auto read, utils::file::readString(path));
         try {
-            auto res = ModInfo::create(ModJson::parse(read.value()));
-            if (!res) return res;
-            auto info = res.value();
+            GEODE_UNWRAP_INTO(auto info, ModInfo::create(ModJson::parse(read)));
             info.m_path = path;
             if (path.has_parent_path()) {
-                auto err = info.addSpecialFiles(path.parent_path());
-                if (!err) {
-                    return Err(err.error());
-                }
+                GEODE_UNWRAP(info.addSpecialFiles(path.parent_path()));
             }
             return Ok(info);
         }
@@ -207,11 +193,11 @@ Result<ModInfo> ModInfo::createFromFile(ghc::filesystem::path const& path) {
 Result<ModInfo> ModInfo::createFromGeodeFile(ghc::filesystem::path const& path) {
     ZipFile unzip(path.string());
     if (!unzip.isLoaded()) {
-        return Err<>("\"" + path.string() + "\": Unable to unzip");
+        return Err("\"" + path.string() + "\": Unable to unzip");
     }
     // Check if mod.json exists in zip
     if (!unzip.fileExists("mod.json")) {
-        return Err<>("\"" + path.string() + "\" is missing mod.json");
+        return Err("\"" + path.string() + "\" is missing mod.json");
     }
     // Read mod.json & parse if possible
     unsigned long readSize = 0;
@@ -225,7 +211,7 @@ Result<ModInfo> ModInfo::createFromGeodeFile(ghc::filesystem::path const& path)
     }
     catch (std::exception const& e) {
         delete[] read;
-        return Err<>(e.what());
+        return Err(e.what());
     }
 
     delete[] read;
@@ -240,15 +226,12 @@ Result<ModInfo> ModInfo::createFromGeodeFile(ghc::filesystem::path const& path)
 
     auto res = ModInfo::create(json);
     if (!res) {
-        return Err("\"" + path.string() + "\" - " + res.error());
+        return Err("\"" + path.string() + "\" - " + res.unwrapErr());
     }
-    auto info = res.value();
+    auto info = res.unwrap();
     info.m_path = path;
 
-    auto err = info.addSpecialFiles(unzip);
-    if (!err) {
-        return Err(err.error());
-    }
+    GEODE_UNWRAP(info.addSpecialFiles(unzip));
 
     return Ok(info);
 }
@@ -276,9 +259,9 @@ Result<> ModInfo::addSpecialFiles(ghc::filesystem::path const& dir) {
         if (ghc::filesystem::exists(dir / file)) {
             auto data = file::readString(dir / file);
             if (!data) {
-                return Err("Unable to read \"" + file + "\": " + data.error());
+                return Err("Unable to read \"" + file + "\": " + data.unwrapErr());
             }
-            *target = sanitizeDetailsData(data.value());
+            *target = sanitizeDetailsData(data.unwrap());
         }
     }
     return Ok();
diff --git a/loader/src/load/Patch.cpp b/loader/src/load/Patch.cpp
index 4147e860..d3d73811 100644
--- a/loader/src/load/Patch.cpp
+++ b/loader/src/load/Patch.cpp
@@ -26,7 +26,7 @@ Result<Patch*> Mod::patch(void* address, byte_array data) {
     p->m_patch = data;
     if (!p->apply()) {
         delete p;
-        return Err<>("Unable to enable patch at " + std::to_string(p->getAddress()));
+        return Err("Unable to enable patch at " + std::to_string(p->getAddress()));
     }
     m_patches.push_back(p);
     return Ok<Patch*>(p);
@@ -36,9 +36,9 @@ Result<> Mod::unpatch(Patch* patch) {
     if (patch->restore()) {
         ranges::remove(m_patches, patch);
         delete patch;
-        return Ok<>();
+        return Ok();
     }
-    return Err<>("Unable to restore patch!");
+    return Err("Unable to restore patch!");
 }
 
 bool Patch::apply() {
diff --git a/loader/src/load/ios/Mod.mm b/loader/src/load/ios/Mod.mm
index f7cbde72..dd2ca74a 100644
--- a/loader/src/load/ios/Mod.mm
+++ b/loader/src/load/ios/Mod.mm
@@ -38,7 +38,7 @@ Result<> Mod::loadPlatformBinary() {
         );
 
         if (!this->m_implicitLoadFunc && !this->m_loadFunc) {
-            return Err<>(
+            return Err(
                 "Unable to find mod entry point (lacking both implicit & explicit definition)"
             );
         }
@@ -48,10 +48,10 @@ Result<> Mod::loadPlatformBinary() {
         }
         this->m_platformInfo = new PlatformInfo { dylib };
 
-        return Ok<>();
+        return Ok();
     }
     std::string err = (char const*)dlerror();
-    return Err<>("Unable to load the DYLIB: dlerror returned (" + err + ")");
+    return Err("Unable to load the DYLIB: dlerror returned (" + err + ")");
 }
 
 Result<> Mod::unloadPlatformBinary() {
@@ -67,10 +67,10 @@ Result<> Mod::unloadPlatformBinary() {
         this->m_saveDataFunc = nullptr;
         this->m_loadDataFunc = nullptr;
         this->m_settingUpdatedFunc = nullptr;
-        return Ok<>();
+        return Ok();
     }
     else {
-        return Err<>("Unable to free library");
+        return Err("Unable to free library");
     }
 }
 
diff --git a/loader/src/load/load.cpp b/loader/src/load/load.cpp
index f26a4819..55585a0e 100644
--- a/loader/src/load/load.cpp
+++ b/loader/src/load/load.cpp
@@ -19,30 +19,27 @@ bool Mod::validateID(std::string const& id) {
 
 Result<Mod*> Loader::loadModFromFile(std::string const& path) {
     // load mod.json
-    auto res = ModInfo::createFromGeodeFile(path);
-    if (!res) {
-        return Err(res.error());
-    }
+    GEODE_UNWRAP_INTO(auto json, ModInfo::createFromGeodeFile(path));
 
     // check that a duplicate has not been loaded
-    if (m_mods.count(res.value().m_id)) {
-        return Err("Mod with ID \"" + res.value().m_id + "\" has already been loaded!");
+    if (m_mods.count(json.m_id)) {
+        return Err("Mod with ID \"" + json.m_id + "\" has already been loaded!");
     }
 
     // create and set up Mod instance
-    auto mod = new Mod(res.value());
+    auto mod = new Mod(json);
     mod->m_saveDirPath =
-        Loader::get()->getGeodeSaveDirectory() / GEODE_MOD_DIRECTORY / res.value().m_id;
+        Loader::get()->getGeodeSaveDirectory() / GEODE_MOD_DIRECTORY / json.m_id;
     ghc::filesystem::create_directories(mod->m_saveDirPath);
 
     auto sett = mod->loadSettings();
     if (!sett) {
-        log::log(Severity::Error, mod, "{}", sett.error());
+        log::log(Severity::Error, mod, "{}", sett.unwrapErr());
     }
 
     // enable mod if needed
     mod->m_enabled = Loader::get()->shouldLoadMod(mod->m_info.m_id);
-    m_mods.insert({ res.value().m_id, mod });
+    m_mods.insert({ json.m_id, mod });
     mod->updateDependencyStates();
 
     // add mod resources
diff --git a/loader/src/load/mac/Mod.cpp b/loader/src/load/mac/Mod.cpp
index 735c53f0..6341058d 100644
--- a/loader/src/load/mac/Mod.cpp
+++ b/loader/src/load/mac/Mod.cpp
@@ -38,7 +38,7 @@ Result<> Mod::loadPlatformBinary() {
         );
 
         if (!this->m_implicitLoadFunc && !this->m_loadFunc) {
-            return Err<>(
+            return Err(
                 "Unable to find mod entry point (lacking both implicit & explicit definition)"
             );
         }
@@ -48,10 +48,10 @@ Result<> Mod::loadPlatformBinary() {
         }
         this->m_platformInfo = new PlatformInfo { dylib };
 
-        return Ok<>();
+        return Ok();
     }
     std::string err = (char const*)dlerror();
-    return Err<>("Unable to load the DYLIB: dlerror returned (" + err + ")");
+    return Err("Unable to load the DYLIB: dlerror returned (" + err + ")");
 }
 
 Result<> Mod::unloadPlatformBinary() {
@@ -67,10 +67,10 @@ Result<> Mod::unloadPlatformBinary() {
         this->m_saveDataFunc = nullptr;
         this->m_loadDataFunc = nullptr;
         this->m_settingUpdatedFunc = nullptr;
-        return Ok<>();
+        return Ok();
     }
     else {
-        return Err<>("Unable to free library");
+        return Err("Unable to free library");
     }
 }
 
diff --git a/loader/src/load/windows/Mod.cpp b/loader/src/load/windows/Mod.cpp
index c75b8d81..684ebad7 100644
--- a/loader/src/load/windows/Mod.cpp
+++ b/loader/src/load/windows/Mod.cpp
@@ -91,7 +91,7 @@ Result<> Mod::loadPlatformBinary() {
         );
 
         if (!this->m_implicitLoadFunc && !this->m_loadFunc) {
-            return Err<>(
+            return Err(
                 "Unable to find mod entry point (lacking both implicit & explicit definition)"
             );
         }
@@ -101,9 +101,9 @@ Result<> Mod::loadPlatformBinary() {
         }
         this->m_platformInfo = new PlatformInfo { load };
 
-        return Ok<>();
+        return Ok();
     }
-    return Err<>("Unable to load the DLL: " + getLastWinError());
+    return Err("Unable to load the DLL: " + getLastWinError());
 }
 
 Result<> Mod::unloadPlatformBinary() {
@@ -113,10 +113,10 @@ Result<> Mod::unloadPlatformBinary() {
         this->m_implicitLoadFunc = nullptr;
         this->m_unloadFunc = nullptr;
         this->m_loadFunc = nullptr;
-        return Ok<>();
+        return Ok();
     }
     else {
-        return Err<>("Unable to free the DLL: " + getLastWinError());
+        return Err("Unable to free the DLL: " + getLastWinError());
     }
 }
 
diff --git a/loader/src/ui/internal/dev/HookListView.cpp b/loader/src/ui/internal/dev/HookListView.cpp
index 094cd70e..063328c3 100644
--- a/loader/src/ui/internal/dev/HookListView.cpp
+++ b/loader/src/ui/internal/dev/HookListView.cpp
@@ -2,7 +2,10 @@
 
 #include <Geode/binding/StatsCell.hpp>
 #include <Geode/binding/TableView.hpp>
+#include <Geode/binding/FLAlertLayer.hpp>
+#include <Geode/binding/CCMenuItemToggler.hpp>
 #include <Geode/utils/casts.hpp>
+#include <Geode/loader/Mod.hpp>
 
 HookCell::HookCell(char const* name, CCSize size) : TableViewCell(name, size.width, size.height) {}
 
@@ -19,36 +22,36 @@ void HookCell::updateBGColor(int index) {
 void HookCell::onEnable(CCObject* pSender) {
     auto toggle = as<CCMenuItemToggler*>(pSender);
     if (!toggle->isToggled()) {
-        auto res = this->m_mod->enableHook(this->m_hook);
+        auto res = m_mod->enableHook(m_hook);
         if (!res) {
             FLAlertLayer::create(
-                nullptr, "Error Enabling Hook", std::string(res.error()), "OK", nullptr, 280.f
+                nullptr, "Error Enabling Hook", std::string(res.unwrapErr()), "OK", nullptr, 280.f
             )
                 ->show();
         }
     }
     else {
-        auto res = this->m_mod->disableHook(this->m_hook);
+        auto res = m_mod->disableHook(m_hook);
         if (!res) {
             FLAlertLayer::create(
-                nullptr, "Error Disabling Hook", std::string(res.error()), "OK", nullptr, 280.f
+                nullptr, "Error Disabling Hook", std::string(res.unwrapErr()), "OK", nullptr, 280.f
             )
                 ->show();
         }
     }
-    toggle->toggle(!this->m_hook->isEnabled());
+    toggle->toggle(!m_hook->isEnabled());
 }
 
 void HookCell::loadFromHook(Hook* hook, Mod* Mod) {
-    this->m_hook = hook;
-    this->m_mod = Mod;
+    m_hook = hook;
+    m_mod = Mod;
 
-    this->m_mainLayer->setVisible(true);
-    this->m_backgroundLayer->setOpacity(255);
+    m_mainLayer->setVisible(true);
+    m_backgroundLayer->setOpacity(255);
 
     auto menu = CCMenu::create();
-    menu->setPosition(this->m_width - this->m_height, this->m_height / 2);
-    this->m_mainLayer->addChild(menu);
+    menu->setPosition(m_width - m_height, m_height / 2);
+    m_mainLayer->addChild(menu);
 
     auto enableBtn =
         CCMenuItemToggler::createWithStandardSprites(this, menu_selector(HookCell::onEnable), .6f);
@@ -79,10 +82,10 @@ void HookCell::loadFromHook(Hook* hook, Mod* Mod) {
     if (hook->getDisplayName() != "") moduleName << hook->getDisplayName();
     else moduleName << "0x" << std::hex << hook->getAddress();
     auto label = CCLabelBMFont::create(moduleName.str().c_str(), "chatFont.fnt");
-    label->setPosition(this->m_height / 2, this->m_height / 2);
+    label->setPosition(m_height / 2, m_height / 2);
     label->setScale(.7f);
     label->setAnchorPoint({ .0f, .5f });
-    this->m_mainLayer->addChild(label);
+    m_mainLayer->addChild(label);
 }
 
 HookCell* HookCell::create(char const* key, CCSize size) {
@@ -95,25 +98,25 @@ HookCell* HookCell::create(char const* key, CCSize size) {
 }
 
 void HookListView::setupList() {
-    this->m_itemSeparation = 30.0f;
+    m_itemSeparation = 30.0f;
 
-    if (!this->m_entries->count()) return;
+    if (!m_entries->count()) return;
 
-    this->m_tableView->reloadData();
+    m_tableView->reloadData();
 
-    if (this->m_entries->count() == 1)
-        this->m_tableView->moveToTopWithOffset(this->m_itemSeparation);
+    if (m_entries->count() == 1)
+        m_tableView->moveToTopWithOffset(m_itemSeparation);
 
-    this->m_tableView->moveToTop();
+    m_tableView->moveToTop();
 }
 
 TableViewCell* HookListView::getListCell(char const* key) {
-    return HookCell::create(key, CCSize { this->m_width, this->m_itemSeparation });
+    return HookCell::create(key, CCSize { m_width, m_itemSeparation });
 }
 
 void HookListView::loadCell(TableViewCell* cell, unsigned int index) {
     as<HookCell*>(cell)->loadFromHook(
-        as<HookItem*>(this->m_entries->objectAtIndex(index))->m_hook, this->m_mod
+        as<HookItem*>(m_entries->objectAtIndex(index))->m_hook, m_mod
     );
     as<HookCell*>(cell)->updateBGColor(index);
 }
diff --git a/loader/src/ui/internal/info/ModInfoLayer.cpp b/loader/src/ui/internal/info/ModInfoLayer.cpp
index 72058096..ea9ae553 100644
--- a/loader/src/ui/internal/info/ModInfoLayer.cpp
+++ b/loader/src/ui/internal/info/ModInfoLayer.cpp
@@ -448,12 +448,12 @@ void ModInfoLayer::onEnableMod(CCObject* pSender) {
     if (as<CCMenuItemToggler*>(pSender)->isToggled()) {
         auto res = m_mod->load();
         if (!res) {
-            FLAlertLayer::create(nullptr, "Error Loading Mod", res.error(), "OK", nullptr)->show();
+            FLAlertLayer::create(nullptr, "Error Loading Mod", res.unwrapErr(), "OK", nullptr)->show();
         }
         else {
             auto res = m_mod->enable();
             if (!res) {
-                FLAlertLayer::create(nullptr, "Error Enabling Mod", res.error(), "OK", nullptr)
+                FLAlertLayer::create(nullptr, "Error Enabling Mod", res.unwrapErr(), "OK", nullptr)
                     ->show();
             }
         }
@@ -461,7 +461,7 @@ void ModInfoLayer::onEnableMod(CCObject* pSender) {
     else {
         auto res = m_mod->disable();
         if (!res) {
-            FLAlertLayer::create(nullptr, "Error Disabling Mod", res.error(), "OK", nullptr)
+            FLAlertLayer::create(nullptr, "Error Disabling Mod", res.unwrapErr(), "OK", nullptr)
                 ->show();
         }
     }
@@ -476,9 +476,11 @@ void ModInfoLayer::onRepository(CCObject*) {
 void ModInfoLayer::onInstallMod(CCObject*) {
     auto ticketRes = Index::get()->installItem(Index::get()->getKnownItem(m_info.m_id));
     if (!ticketRes) {
-        return FLAlertLayer::create("Unable to install", ticketRes.error(), "OK")->show();
+        return FLAlertLayer::create(
+            "Unable to install", ticketRes.unwrapErr(), "OK"
+        )->show();
     }
-    m_installation = ticketRes.value();
+    m_installation = ticketRes.unwrap();
 
     createQuickPopup(
         "Install",
@@ -626,7 +628,9 @@ void ModInfoLayer::install() {
 void ModInfoLayer::uninstall() {
     auto res = m_mod->uninstall();
     if (!res) {
-        return FLAlertLayer::create("Uninstall failed :(", res.error(), "OK")->show();
+        return FLAlertLayer::create(
+            "Uninstall failed :(", res.unwrapErr(), "OK"
+        )->show();
     }
     auto layer = FLAlertLayer::create(
         this, "Uninstall complete",
diff --git a/loader/src/ui/internal/list/ModListView.cpp b/loader/src/ui/internal/list/ModListView.cpp
index b705923c..89c1b05d 100644
--- a/loader/src/ui/internal/list/ModListView.cpp
+++ b/loader/src/ui/internal/list/ModListView.cpp
@@ -8,6 +8,7 @@
 #include <Geode/binding/CCMenuItemSpriteExtra.hpp>
 #include <Geode/binding/StatsCell.hpp>
 #include <Geode/binding/TableView.hpp>
+#include <Geode/binding/CCMenuItemToggler.hpp>
 #include <Geode/loader/Mod.hpp>
 #include <Geode/utils/casts.hpp>
 #include <Geode/utils/cocos.hpp>
@@ -18,9 +19,9 @@
 template <class T>
 static bool tryOrAlert(Result<T> const& res, char const* title) {
     if (!res) {
-        FLAlertLayer::create(title, res.error(), "OK")->show();
+        FLAlertLayer::create(title, res.unwrapErr(), "OK")->show();
     }
-    return res.is_value();
+    return res.isOk();
 }
 
 ModCell::ModCell(char const* name, CCSize size) : TableViewCell(name, size.width, size.height) {}
diff --git a/loader/src/ui/internal/settings/GeodeSettingNode.cpp b/loader/src/ui/internal/settings/GeodeSettingNode.cpp
index f26b8f0a..d2bd15a1 100644
--- a/loader/src/ui/internal/settings/GeodeSettingNode.cpp
+++ b/loader/src/ui/internal/settings/GeodeSettingNode.cpp
@@ -120,10 +120,12 @@ void FileSettingNode::onPickFile(CCObject*) {
     auto setting = std::static_pointer_cast<FileSetting>(m_setting);
     if (auto path = file::pickFile(
             file::PickMode::OpenFile,
-            { file::geodeRoot(),
-              setting->getFileFilters().value_or(std::vector<file::FilePickOptions::Filter>()) }
+            {
+                file::geodeRoot(),
+                setting->getFileFilters().value_or(std::vector<file::FilePickOptions::Filter>())
+            }
         )) {
-        m_uncommittedValue = path.value();
+        m_uncommittedValue = path.unwrap();
         this->valueChanged(true);
     }
 }
diff --git a/loader/src/ui/internal/settings/GeodeSettingNode.hpp b/loader/src/ui/internal/settings/GeodeSettingNode.hpp
index 8ecb456f..a12e7e99 100644
--- a/loader/src/ui/internal/settings/GeodeSettingNode.hpp
+++ b/loader/src/ui/internal/settings/GeodeSettingNode.hpp
@@ -162,7 +162,7 @@ namespace {
             auto isValid = std::static_pointer_cast<T>(m_setting)->isValidValue(m_uncommittedValue);
             if (!isValid) {
                 m_errorLabel->setVisible(true);
-                m_errorLabel->setString(isValid.error().c_str());
+                m_errorLabel->setString(isValid.unwrapErr().c_str());
             }
             else {
                 m_errorLabel->setVisible(false);
diff --git a/loader/src/ui/nodes/ColorPickPopup.cpp b/loader/src/ui/nodes/ColorPickPopup.cpp
index 51ff57a0..3bfee86e 100644
--- a/loader/src/ui/nodes/ColorPickPopup.cpp
+++ b/loader/src/ui/nodes/ColorPickPopup.cpp
@@ -209,9 +209,9 @@ void ColorPickPopup::textChanged(CCTextInputNode* input) {
             case TAG_HEX_INPUT:
                 {
                     if (auto color = cc3bFromHexString(input->getString())) {
-                        m_color.r = color.value().r;
-                        m_color.g = color.value().g;
-                        m_color.b = color.value().b;
+                        m_color.r = color.unwrap().r;
+                        m_color.g = color.unwrap().g;
+                        m_color.b = color.unwrap().b;
                     }
                 }
                 break;
diff --git a/loader/src/ui/nodes/MDTextArea.cpp b/loader/src/ui/nodes/MDTextArea.cpp
index 1df6f9b9..a3650afd 100644
--- a/loader/src/ui/nodes/MDTextArea.cpp
+++ b/loader/src/ui/nodes/MDTextArea.cpp
@@ -303,10 +303,10 @@ struct MDParser {
                             else {
                                 auto color = colorForIdentifier(tag);
                                 if (color) {
-                                    renderer->pushColor(color.value());
+                                    renderer->pushColor(color.unwrap());
                                 }
                                 else {
-                                    log::warn("Error parsing color: {}", color.error());
+                                    log::warn("Error parsing color: {}", color.unwrapErr());
                                 }
                             }
                         }
diff --git a/loader/src/utils/convert.cpp b/loader/src/utils/convert.cpp
index 5a68c093..007fed17 100644
--- a/loader/src/utils/convert.cpp
+++ b/loader/src/utils/convert.cpp
@@ -42,10 +42,10 @@ void cocos2d::from_json(nlohmann::json const& json, ccColor3B& color) {
         auto c = cc3bFromHexString(str);
         if (!c) {
             throw nlohmann::json::type_error::create(
-                0, "Invalid color hex string: " + c.error(), json
+                0, "Invalid color hex string: " + c.unwrapErr(), json
             );
         }
-        color = c.value();
+        color = c.unwrap();
     }
     // bad
     else {
@@ -98,10 +98,10 @@ void cocos2d::from_json(nlohmann::json const& json, ccColor4B& color) {
         auto c = cc4bFromHexString(str);
         if (!c) {
             throw nlohmann::json::type_error::create(
-                0, "Invalid color hex string: " + c.error(), json
+                0, "Invalid color hex string: " + c.unwrapErr(), json
             );
         }
-        color = c.value();
+        color = c.unwrap();
     }
     // bad
     else {
diff --git a/loader/src/utils/fetch.cpp b/loader/src/utils/fetch.cpp
index c1416660..9264877f 100644
--- a/loader/src/utils/fetch.cpp
+++ b/loader/src/utils/fetch.cpp
@@ -367,26 +367,26 @@ AsyncWebRequest::~AsyncWebRequest() {
 
 AsyncWebResult<std::monostate> AsyncWebResponse::into(std::ostream& stream) {
     m_request.m_target = &stream;
-    return this->as(+[](byte_array const&) {
+    return this->as(+[](byte_array const&) -> Result<std::monostate> {
         return Ok(std::monostate());
     });
 }
 
 AsyncWebResult<std::monostate> AsyncWebResponse::into(ghc::filesystem::path const& path) {
     m_request.m_target = path;
-    return this->as(+[](byte_array const&) {
+    return this->as(+[](byte_array const&) -> Result<std::monostate> {
         return Ok(std::monostate());
     });
 }
 
 AsyncWebResult<std::string> AsyncWebResponse::text() {
-    return this->as(+[](byte_array const& bytes) {
+    return this->as(+[](byte_array const& bytes) -> Result<std::string> {
         return Ok(std::string(bytes.begin(), bytes.end()));
     });
 }
 
 AsyncWebResult<byte_array> AsyncWebResponse::bytes() {
-    return this->as(+[](byte_array const& bytes) {
+    return this->as(+[](byte_array const& bytes) -> Result<byte_array> {
         return Ok(bytes);
     });
 }
diff --git a/loader/src/utils/file.cpp b/loader/src/utils/file.cpp
index 9b8759d8..971c6e9f 100644
--- a/loader/src/utils/file.cpp
+++ b/loader/src/utils/file.cpp
@@ -1,6 +1,7 @@
 #include <Geode/utils/file.hpp>
 #include <Geode/utils/string.hpp>
 #include <fstream>
+#include <../support/zip_support/ZipUtils.h>
 
 USE_GEODE_NAMESPACE();
 
@@ -89,10 +90,10 @@ Result<> utils::file::writeString(std::string const& path, std::string const& da
         file << data;
         file.close();
 
-        return Ok<>();
+        return Ok();
     }
     file.close();
-    return Err<>("Unable to open file");
+    return Err("Unable to open file");
 }
 
 #if _WIN32
@@ -103,10 +104,10 @@ Result<> utils::file::writeString(std::wstring const& path, std::string const& d
         file << data;
         file.close();
 
-        return Ok<>();
+        return Ok();
     }
     file.close();
-    return Err<>("Unable to open file");
+    return Err("Unable to open file");
 }
 #endif
 
@@ -121,10 +122,10 @@ Result<> utils::file::writeString(ghc::filesystem::path const& path, std::string
         file << data;
         file.close();
 
-        return Ok<>();
+        return Ok();
     }
     file.close();
-    return Err<>("Unable to open file");
+    return Err("Unable to open file");
 }
 
 Result<> utils::file::writeBinary(std::string const& path, byte_array const& data) {
@@ -134,10 +135,10 @@ Result<> utils::file::writeBinary(std::string const& path, byte_array const& dat
         file.write(reinterpret_cast<char const*>(data.data()), data.size());
         file.close();
 
-        return Ok<>();
+        return Ok();
     }
     file.close();
-    return Err<>("Unable to open file");
+    return Err("Unable to open file");
 }
 
 #if _WIN32
@@ -148,10 +149,10 @@ Result<> utils::file::writeBinary(std::wstring const& path, byte_array const& da
         file.write(reinterpret_cast<char const*>(data.data()), data.size());
         file.close();
 
-        return Ok<>();
+        return Ok();
     }
     file.close();
-    return Err<>("Unable to open file");
+    return Err("Unable to open file");
 }
 #endif
 
@@ -166,74 +167,74 @@ Result<> utils::file::writeBinary(ghc::filesystem::path const& path, byte_array
         file.write(reinterpret_cast<char const*>(data.data()), data.size());
         file.close();
 
-        return Ok<>();
+        return Ok();
     }
     file.close();
-    return Err<>("Unable to open file");
+    return Err("Unable to open file");
 }
 
 Result<> utils::file::createDirectory(std::string const& path) {
     try {
         if (ghc::filesystem::create_directory(path)) {
-            return Ok<>();
+            return Ok();
         }
     }
     catch (...) {
     }
-    return Err<>("Unable to create directory");
+    return Err("Unable to create directory");
 }
 
 Result<> utils::file::createDirectory(ghc::filesystem::path const& path) {
     try {
         if (ghc::filesystem::create_directory(path)) {
-            return Ok<>();
+            return Ok();
         }
     }
     catch (...) {
     }
-    return Err<>("Unable to create directory");
+    return Err("Unable to create directory");
 }
 
 Result<> utils::file::createDirectoryAll(std::string const& path) {
     try {
         if (ghc::filesystem::create_directories(path)) {
-            return Ok<>();
+            return Ok();
         }
     }
     catch (...) {
     }
-    return Err<>("Unable to create directories");
+    return Err("Unable to create directories");
 }
 
 Result<> utils::file::createDirectoryAll(ghc::filesystem::path const& path) {
     try {
         if (ghc::filesystem::create_directories(path)) {
-            return Ok<>();
+            return Ok();
         }
     }
     catch (...) {
     }
-    return Err<>("Unable to create directories");
+    return Err("Unable to create directories");
 }
 
 Result<std::vector<std::string>> utils::file::listFiles(std::string const& path) {
-    if (!ghc::filesystem::exists(path)) return Err<>("Directory does not exist");
+    if (!ghc::filesystem::exists(path)) return Err("Directory does not exist");
 
     std::vector<std::string> res;
     for (auto const& file : ghc::filesystem::directory_iterator(path)) {
         res.push_back(file.path().string());
     }
-    return Ok<>(res);
+    return Ok(res);
 }
 
 Result<std::vector<std::string>> utils::file::listFilesRecursively(std::string const& path) {
-    if (!ghc::filesystem::exists(path)) return Err<>("Directory does not exist");
+    if (!ghc::filesystem::exists(path)) return Err("Directory does not exist");
 
     std::vector<std::string> res;
     for (auto const& file : ghc::filesystem::recursive_directory_iterator(path)) {
         res.push_back(file.path().string());
     }
-    return Ok<>(res);
+    return Ok(res);
 }
 
 Result<> utils::file::unzipTo(ghc::filesystem::path const& from, ghc::filesystem::path const& to) {
@@ -274,7 +275,7 @@ Result<> utils::file::unzipTo(ghc::filesystem::path const& from, ghc::filesystem
         }
         auto wrt = utils::file::writeBinary(to / file, byte_array(data, data + size));
         if (!wrt) {
-            return Err("Unable to write \"" + (to / file).string() + "\": " + wrt.error());
+            return Err("Unable to write \"" + (to / file).string() + "\": " + wrt.unwrapErr());
         }
     }
 
diff --git a/loader/src/utils/windows/nfdwin.cpp b/loader/src/utils/windows/nfdwin.cpp
index e3609a6e..fdf0819c 100644
--- a/loader/src/utils/windows/nfdwin.cpp
+++ b/loader/src/utils/windows/nfdwin.cpp
@@ -235,11 +235,7 @@ Result<> nfdPick(
                     Holder _([&]() {
                         shellItems->Release();
                     });
-                    auto res = convShellItems(shellItems);
-                    if (!res) {
-                        return Err(res.error());
-                    }
-                    *reinterpret_cast<Paths*>(result) = res.value();
+                    GEODE_UNWRAP_INTO(*reinterpret_cast<Paths*>(result), convShellItems(shellItems));
                     return Ok();
                 } break;
 
diff --git a/loader/src/utils/windows/util.cpp b/loader/src/utils/windows/util.cpp
index 683f8d8a..840827f0 100644
--- a/loader/src/utils/windows/util.cpp
+++ b/loader/src/utils/windows/util.cpp
@@ -89,13 +89,10 @@ Result<ghc::filesystem::path> utils::file::pickFile(
         TURN_INTO_NFDMODE(OpenFile);
         TURN_INTO_NFDMODE(SaveFile);
         TURN_INTO_NFDMODE(OpenFolder);
-        default: return Err("Unknown open mode");
+        default: return Err<std::string>("Unknown open mode");
     }
     ghc::filesystem::path path;
-    auto r = nfdPick(nfdMode, options, &path);
-    if (!r) {
-        return Err(r.error());
-    }
+    GEODE_UNWRAP(nfdPick(nfdMode, options, &path));
     return Ok(path);
 }
 
@@ -103,10 +100,7 @@ Result<std::vector<ghc::filesystem::path>> utils::file::pickFiles(
     file::FilePickOptions const& options
 ) {
     std::vector<ghc::filesystem::path> paths;
-    auto r = nfdPick(NFDMode::OpenFolder, options, &paths);
-    if (!r) {
-        return Err(r.error());
-    }
+    GEODE_UNWRAP(nfdPick(NFDMode::OpenFolder, options, &paths));
     return Ok(paths);
 }