Skip to content

Commit

Permalink
Merge pull request #207 from geode-sdk/better-dependencies
Browse files Browse the repository at this point in the history
Better dependency, mod loading and UI handling
  • Loading branch information
altalk23 authored Aug 16, 2023
2 parents 2810ce7 + a0020cc commit 1996d88
Show file tree
Hide file tree
Showing 60 changed files with 3,889 additions and 1,344 deletions.
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,27 @@
* Fix json library not actually being dynamically exported/imported (5f65d97)
* Update TulipHook, gets rid of keystone dependency and adds stdcall support (efcbf58, 7b90903)
* Make resources.zip platform dependent (e41784e)
* Add utils::string::join (82e128b)
* Add logger nesting: log::pushNest, log::pushNest (7d74f16)
* Add "any" version to comparable versions (2b1dc17)
* Deprecate ModInfo, replaced with ModMetadata (53b52ea)
* Add utils::game::restart (7f449b9, 0e1d639)
* Rework the way dependencies and mod loading works (5200128)
* Early load loads mods before the game starts, while non-early load loads on the loading screen now (e718069)
* Add support for specifying incompatibilities (5200128, 8908235)
* Add support for specifying suggested and recommended optional dependencies (5200128)
* Add UI to select which mods to install (3707418, 73169fb, cd772bd)
* Dependencies/dependants automatically get toggled on toggle (5200128, 6ab542d)
* Add problems list (5200128, aee84c0)
* Show amount of currently loaded mods on the loading screen while they're loading (e718069, 1d5fae8)
* Improve index-related UI (73169fb)
* Remove Android and iOS filters for now
* Add filter to show non-installable mods
* API in quick popups to distinguish between pressing button 1 and the Escape key
* Add "API" label to API mods (cb8759b)
* Fix index not displaying tags (ed5b5c9)
* Change "Cancel" to say "Keep" in the remove mod data on mod uninstall dialogue (cd772bd)
* Fix typos in the word "successfully" (5200128, f316c86)
* Fix MacOS HSV button missing in `CustomizeObjectLayer` (d98cb2d)
* Make missing functions and members private (d98cb2d)
* Update Broma to latest version (0a58432)
Expand Down
5 changes: 4 additions & 1 deletion loader/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,10 @@ endif()

target_compile_definitions(${PROJECT_NAME} PUBLIC GEODE_EXPORTING MAT_JSON_EXPORTING)

target_compile_definitions(${PROJECT_NAME} PRIVATE _CRT_SECURE_NO_WARNINGS)
target_compile_definitions(${PROJECT_NAME} PRIVATE
GEODE_EXPOSE_SECRET_INTERNALS_IN_HEADERS_DO_NOT_DEFINE_PLEASE
_CRT_SECURE_NO_WARNINGS
)

# These are only needed for building source :-)
if (NOT GEODE_BUILDING_DOCS)
Expand Down
29 changes: 27 additions & 2 deletions loader/include/Geode/loader/Index.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "Types.hpp"
#include "ModInfo.hpp"
#include "ModMetadata.hpp"
#include "Event.hpp"
#include "../utils/Result.hpp"
#include "../utils/web.hpp"
Expand Down Expand Up @@ -107,12 +108,23 @@ namespace geode {

public:
ghc::filesystem::path getPath() const;
ModInfo getModInfo() const;
[[deprecated("use getMetadata instead")]] ModInfo getModInfo() const;
ModMetadata getMetadata() const;
std::string getDownloadURL() const;
std::string getPackageHash() const;
std::unordered_set<PlatformID> getAvailablePlatforms() const;
bool isFeatured() const;
std::unordered_set<std::string> getTags() const;
bool isInstalled() const;

#if defined(GEODE_EXPOSE_SECRET_INTERNALS_IN_HEADERS_DO_NOT_DEFINE_PLEASE)
void setMetadata(ModMetadata const& value);
void setDownloadURL(std::string const& value);
void setPackageHash(std::string const& value);
void setAvailablePlatforms(std::unordered_set<PlatformID> const& value);
void setIsFeatured(bool const& value);
void setTags(std::unordered_set<std::string> const& value);
#endif

IndexItem();
~IndexItem();
Expand Down Expand Up @@ -204,8 +216,15 @@ namespace geode {
* Get an item from the index by its mod.json
* @param info The mod's info
* @returns The item, or nullptr if the item was not found
* @deprecated Use the ModMetadata overload instead
*/
[[deprecated]] IndexItemHandle getItem(ModInfo const& info) const;
/**
* Get an item from the index by its mod.json
* @param info The mod's metadata
* @returns The item, or nullptr if the item was not found
*/
IndexItemHandle getItem(ModInfo const& info) const;
IndexItemHandle getItem(ModMetadata const& metadata) const;
/**
* Get an item from the index that corresponds to an installed mod
* @param mod An installed mod
Expand All @@ -224,6 +243,12 @@ namespace geode {
* Check if any of the mods on the index have updates available
*/
bool areUpdatesAvailable() const;
/**
* Checks if the mod and its required dependencies can be installed
* @param item Item to get the list for
* @returns Success if the mod and its required dependencies can be installed, an error otherwise
*/
Result<> canInstall(IndexItemHandle item) const;
/**
* Get the list of items needed to install this item (dependencies, etc.)
* @param item Item to get the list for
Expand Down
50 changes: 42 additions & 8 deletions loader/include/Geode/loader/Loader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
#include "../utils/Result.hpp"
#include "../utils/MiniFunction.hpp"
#include "Log.hpp"
#include "ModEvent.hpp"
#include "ModInfo.hpp"
#include "ModMetadata.hpp"
#include "Types.hpp"

#include <atomic>
Expand All @@ -18,6 +20,25 @@ namespace geode {
std::string reason;
};

struct LoadProblem {
enum class Type : uint8_t {
Unknown,
Suggestion,
Recommendation,
Conflict,
InvalidFile,
Duplicate,
SetupFailed,
LoadFailed,
EnableFailed,
MissingDependency,
PresentIncompatibility
};
Type type;
std::variant<ghc::filesystem::path, ModMetadata, Mod*> cause;
std::string message;
};

class LoaderImpl;

class GEODE_DLL Loader {
Expand All @@ -36,14 +57,25 @@ namespace geode {
void dispatchScheduledFunctions(Mod* mod);
friend void GEODE_CALL ::geode_implicit_load(Mod*);

Result<Mod*> loadModFromInfo(ModInfo const& info);
[[deprecated]] Result<Mod*> loadModFromInfo(ModInfo const& info);

Mod* takeNextMod();

public:
// TODO: do we want to expose all of these functions?
static Loader* get();

enum class LoadingState : uint8_t {
None,
Queue,
List,
Graph,
EarlyMods,
Mods,
Problems,
Done
};

Result<> saveData();
Result<> loadData();

Expand All @@ -52,17 +84,19 @@ namespace geode {
VersionInfo maxModVersion();
bool isModVersionSupported(VersionInfo const& version);

Result<Mod*> loadModFromFile(ghc::filesystem::path const& file);
void loadModsFromDirectory(ghc::filesystem::path const& dir, bool recursive = true);
void refreshModsList();
[[deprecated]] Result<Mod*> loadModFromFile(ghc::filesystem::path const& file);
[[deprecated]] void loadModsFromDirectory(ghc::filesystem::path const& dir, bool recursive = true);
[[deprecated]] void refreshModsList();
LoadingState getLoadingState();
bool isModInstalled(std::string const& id) const;
Mod* getInstalledMod(std::string const& id) const;
bool isModLoaded(std::string const& id) const;
Mod* getLoadedMod(std::string const& id) const;
std::vector<Mod*> getAllMods();
Mod* getModImpl();
void updateAllDependencies();
std::vector<InvalidGeodeFile> getFailedMods() const;
[[deprecated("use Mod::get instead")]] Mod* getModImpl();
[[deprecated]] void updateAllDependencies();
[[deprecated("use getProblems instead")]] std::vector<InvalidGeodeFile> getFailedMods() const;
std::vector<LoadProblem> getProblems() const;

void updateResources();
void updateResources(bool forceReload);
Expand Down
13 changes: 12 additions & 1 deletion loader/include/Geode/loader/Log.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ namespace geode {
bool operator==(Log const& l);

std::string toString(bool logTime = true) const;
std::string toString(bool logTime, uint32_t nestLevel) const;

std::vector<ComponentTrait*>& getComponents();
log_clock::time_point getTime() const;
Expand All @@ -170,6 +171,7 @@ namespace geode {
private:
static std::vector<Log>& logs();
static std::ofstream& logStream();
static uint32_t& nestLevel();

Logger() = delete;
~Logger() = delete;
Expand All @@ -179,9 +181,11 @@ namespace geode {
static void setup();

static void push(Log&& log);

static void pop(Log* log);

static void pushNest();
static void popNest();

static std::vector<Log*> list();
static void clear();
};
Expand Down Expand Up @@ -223,5 +227,12 @@ namespace geode {
void error(Args... args) {
internalLog(Severity::Error, getMod(), args...);
}

static void pushNest() {
Logger::pushNest();
}
static void popNest() {
Logger::popNest();
}
}
}
53 changes: 35 additions & 18 deletions loader/include/Geode/loader/Mod.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "../utils/general.hpp"
#include "Hook.hpp"
#include "ModInfo.hpp"
#include "ModMetadata.hpp"
#include "Setting.hpp"
#include "Types.hpp"

Expand Down Expand Up @@ -46,7 +47,6 @@ namespace geode {
std::unique_ptr<Impl> m_impl;

friend class Loader;
friend struct ModInfo;

template <class = void>
static inline GEODE_HIDDEN Mod* sharedMod = nullptr;
Expand All @@ -66,7 +66,8 @@ namespace geode {

// Protected constructor/destructor
Mod() = delete;
Mod(ModInfo const& info);
[[deprecated]] Mod(ModInfo const& info);
Mod(ModMetadata const& metadata);
~Mod();

std::string getID() const;
Expand All @@ -79,9 +80,14 @@ namespace geode {
bool isEnabled() const;
bool isLoaded() const;
bool supportsDisabling() const;
bool supportsUnloading() const;
bool wasSuccesfullyLoaded() const;
ModInfo getModInfo() const;
bool canDisable() const;
bool canEnable() const;
bool needsEarlyLoad() const;
[[deprecated]] bool supportsUnloading() const;
[[deprecated("use wasSuccessfullyLoaded instead")]] bool wasSuccesfullyLoaded() const;
bool wasSuccessfullyLoaded() const;
[[deprecated("use getMetadata instead")]] ModInfo getModInfo() const;
ModMetadata getMetadata() const;
ghc::filesystem::path getTempDir() const;
/**
* Get the path to the mod's platform binary (.dll on Windows, .dylib
Expand All @@ -94,6 +100,11 @@ namespace geode {
*/
ghc::filesystem::path getResourcesDir() const;

#if defined(GEODE_EXPOSE_SECRET_INTERNALS_IN_HEADERS_DO_NOT_DEFINE_PLEASE)
void setMetadata(ModMetadata const& metadata);
std::vector<Mod*> getDependants() const;
#endif

Result<> saveData();
Result<> loadData();

Expand Down Expand Up @@ -293,7 +304,7 @@ namespace geode {
* @returns Successful result on success,
* errorful result with info on error
*/
Result<> loadBinary();
[[deprecated]] Result<> loadBinary();

/**
* Disable & unload this mod
Expand All @@ -302,7 +313,7 @@ namespace geode {
* @returns Successful result on success,
* errorful result with info on error
*/
Result<> unloadBinary();
[[deprecated]] Result<> unloadBinary();

/**
* Enable this mod
Expand All @@ -319,10 +330,7 @@ namespace geode {
Result<> disable();

/**
* Disable & unload this mod (if supported), then delete the mod's
* .geode package. If unloading isn't supported, the mod's binary
* will stay loaded, and in all cases the Mod* instance will still
* exist and be interactable.
* Disable this mod (if supported), then delete the mod's .geode package.
* @returns Successful result on success,
* errorful result with info on error
*/
Expand All @@ -335,6 +343,16 @@ namespace geode {
*/
bool depends(std::string const& id) const;

/**
* Update the state of each of the
* dependencies. Depending on if the
* mod has unresolved dependencies,
* it will either be loaded or unloaded
* @returns Error.
* @deprecated No longer needed.
*/
[[deprecated("no longer needed")]] Result<> updateDependencies();

/**
* Check whether all the required
* dependencies for this mod have
Expand All @@ -344,21 +362,20 @@ namespace geode {
*/
bool hasUnresolvedDependencies() const;
/**
* Update the state of each of the
* dependencies. Depending on if the
* mod has unresolved dependencies,
* it will either be loaded or unloaded
* Check whether none of the
* incompatibilities with this mod are loaded
* @returns True if the mod has unresolved
* dependencies, false if not.
* incompatibilities, false if not.
*/
Result<> updateDependencies();
bool hasUnresolvedIncompatibilities() const;
/**
* Get a list of all the unresolved
* dependencies this mod has
* @returns List of all the unresolved
* dependencies
* @deprecated Use Loader::getProblems instead.
*/
std::vector<Dependency> getUnresolvedDependencies();
[[deprecated("use Loader::getProblems instead")]] std::vector<Dependency> getUnresolvedDependencies();

char const* expandSpriteName(char const* name);

Expand Down
Loading

0 comments on commit 1996d88

Please sign in to comment.