mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-27 01:45:35 -05:00
Compare commits
9 commits
50be1dacc3
...
7ae4b1573e
Author | SHA1 | Date | |
---|---|---|---|
|
7ae4b1573e | ||
|
cb8d7571dd | ||
|
227adb0484 | ||
|
9ef6b9eb71 | ||
|
dd95b87353 | ||
|
f90461fbb7 | ||
|
555ebe3eb3 | ||
|
bd6bfb661f | ||
|
03e8220dfe |
11 changed files with 150 additions and 33 deletions
|
@ -1,5 +1,10 @@
|
||||||
# Geode Changelog
|
# Geode Changelog
|
||||||
|
|
||||||
|
## v4.0.0
|
||||||
|
* Make chosen display type in mod list be saved between startups (07d92a3)
|
||||||
|
* Fix `Task::all` not returning results in order (227adb0)
|
||||||
|
* Fix bugs with changing display type (555ebe3, f90461f)
|
||||||
|
|
||||||
## v4.0.0-beta.2
|
## v4.0.0-beta.2
|
||||||
* Add grid view to mod list (7bcf50d, 1ff24f0)
|
* Add grid view to mod list (7bcf50d, 1ff24f0)
|
||||||
* Add safe mode tip to windows crashlog window (38f3385)
|
* Add safe mode tip to windows crashlog window (38f3385)
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
4.0.0-beta.2
|
4.0.0
|
||||||
|
|
|
@ -114,7 +114,6 @@
|
||||||
namespace geode {
|
namespace geode {
|
||||||
class PlatformID {
|
class PlatformID {
|
||||||
public:
|
public:
|
||||||
// todo in v4: make these flags and add archless Mac and Android as well as Desktop and Mobile and remove Linux
|
|
||||||
enum {
|
enum {
|
||||||
Unknown = 0b000000,
|
Unknown = 0b000000,
|
||||||
Windows = 0b000001,
|
Windows = 0b000001,
|
||||||
|
@ -184,11 +183,11 @@ namespace geode {
|
||||||
/**
|
/**
|
||||||
* Returns the list of platforms covered by this string name. For
|
* Returns the list of platforms covered by this string name. For
|
||||||
* example, "android" would return both Android32 and Android64
|
* example, "android" would return both Android32 and Android64
|
||||||
* todo in v4: deprecate this as the flagged version deals with this
|
* todo in v5: deprecate this as the flagged version deals with this
|
||||||
*/
|
*/
|
||||||
static GEODE_DLL std::vector<PlatformID> getCovered(std::string_view str);
|
static GEODE_DLL std::vector<PlatformID> getCovered(std::string_view str);
|
||||||
|
|
||||||
// todo in v4: this does not need to be constexpr in the header. dllexport it
|
// todo in v5: this does not need to be constexpr in the header. dllexport it
|
||||||
static constexpr char const* toString(Type lp) {
|
static constexpr char const* toString(Type lp) {
|
||||||
switch (lp) {
|
switch (lp) {
|
||||||
case Unknown: return "Unknown";
|
case Unknown: return "Unknown";
|
||||||
|
@ -203,7 +202,7 @@ namespace geode {
|
||||||
return "Undefined";
|
return "Undefined";
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo in v4: this does not need to be constexpr in the header. dllexport it
|
// todo in v5: this does not need to be constexpr in the header. dllexport it
|
||||||
static constexpr char const* toShortString(Type lp, bool ignoreArch = false) {
|
static constexpr char const* toShortString(Type lp, bool ignoreArch = false) {
|
||||||
switch (lp) {
|
switch (lp) {
|
||||||
case Unknown: return "unknown";
|
case Unknown: return "unknown";
|
||||||
|
|
|
@ -13,12 +13,6 @@ namespace geode {
|
||||||
virtual void updateColor(cocos2d::ccColor4B const& color) {}
|
virtual void updateColor(cocos2d::ccColor4B const& color) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// todo in v4: maybe use events over the delegate?
|
|
||||||
// thing with events is that if you just filter via ColorPickPopup* it
|
|
||||||
// won't work unless you automatically detach the filter when closing the
|
|
||||||
// popup (otherwise opening another popup really quickly will just be
|
|
||||||
// allocated into the same memory and now the old filter is catching the
|
|
||||||
// new popup too)
|
|
||||||
class GEODE_DLL ColorPickPopup :
|
class GEODE_DLL ColorPickPopup :
|
||||||
public Popup<cocos2d::ccColor4B const&, bool>,
|
public Popup<cocos2d::ccColor4B const&, bool>,
|
||||||
public cocos2d::extension::ColorPickerDelegate,
|
public cocos2d::extension::ColorPickerDelegate,
|
||||||
|
|
41
loader/include/Geode/ui/OverlayManager.hpp
Normal file
41
loader/include/Geode/ui/OverlayManager.hpp
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../DefaultInclude.hpp"
|
||||||
|
|
||||||
|
#include <cocos2d.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <span>
|
||||||
|
#include <Geode/utils/cocos.hpp>
|
||||||
|
|
||||||
|
namespace geode
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Because cocos only allows for one notification node (a node drawn last, above the fps counter and everything),
|
||||||
|
I added this, a simple class to add nodes to a general notification node so that mods dont interfere with each other.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class GEODE_DLL OverlayManager : private cocos2d::CCNode
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::vector<cocos2d::CCNode*> nodes;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// @brief Get the overlay manager instance, and if it doesnt exist, sets the notification node to it
|
||||||
|
static OverlayManager* get();
|
||||||
|
|
||||||
|
/// @brief Adds a node to the overlay manager, overlays are sorted by ZOrder, the higher the order is the later it draws. This will retain the node
|
||||||
|
void addNode(cocos2d::CCNode* node);
|
||||||
|
|
||||||
|
/// @brief Removes a node from the overlay manager, stopping it from being drawn. This will release the node
|
||||||
|
void removeNode(cocos2d::CCNode* node);
|
||||||
|
|
||||||
|
/// @brief Util to get the highest ZOrder of all nodes
|
||||||
|
int getHighestOverlayZOrder();
|
||||||
|
|
||||||
|
/// @brief Util to get the lowest ZOrder of all nodes
|
||||||
|
int getLowestOverlayZOrder();
|
||||||
|
|
||||||
|
/// @brief Gets all the overlays
|
||||||
|
std::vector<cocos2d::CCNode*> getOverlays();
|
||||||
|
};
|
||||||
|
};
|
|
@ -539,12 +539,18 @@ namespace geode {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Make sure the taskResults vector is large enough to fit all the
|
||||||
|
// results. By default, any cancelled Task becomes nullptr.
|
||||||
|
// Order of results must be preserved so when a Task finishes, it
|
||||||
|
// replaces the nullptr in the results vector at its place
|
||||||
|
static_cast<Waiting*>(task.m_handle->m_extraData->ptr)->taskResults.resize(tasks.size());
|
||||||
|
|
||||||
// Store the task count in case some tasks finish immediately during the loop
|
// Store the task count in case some tasks finish immediately during the loop
|
||||||
static_cast<Waiting*>(task.m_handle->m_extraData->ptr)->taskCount = tasks.size();
|
static_cast<Waiting*>(task.m_handle->m_extraData->ptr)->taskCount = tasks.size();
|
||||||
|
|
||||||
// Make sure to only give a weak pointer to avoid circular references!
|
// Make sure to only give a weak pointer to avoid circular references!
|
||||||
// (Tasks should NEVER own themselves!!)
|
// (Tasks should NEVER own themselves!!)
|
||||||
auto markAsDone = [handle = std::weak_ptr(task.m_handle)](T* result) {
|
auto markAsDone = [handle = std::weak_ptr(task.m_handle)](size_t index, T* result) {
|
||||||
auto lock = handle.lock();
|
auto lock = handle.lock();
|
||||||
|
|
||||||
// If this task handle has expired, consider the task cancelled
|
// If this task handle has expired, consider the task cancelled
|
||||||
|
@ -556,13 +562,21 @@ namespace geode {
|
||||||
// Get the waiting handle from the task handle
|
// Get the waiting handle from the task handle
|
||||||
auto waiting = static_cast<Waiting*>(lock->m_extraData->ptr);
|
auto waiting = static_cast<Waiting*>(lock->m_extraData->ptr);
|
||||||
|
|
||||||
|
// Mark the task as done by decrementing amount of tasks left
|
||||||
|
// (making sure not to underflow, even though that should 100%
|
||||||
|
// be impossible and if that happened something has gone
|
||||||
|
// extremely catastrophically wrong)
|
||||||
|
if (waiting->taskCount > 0) {
|
||||||
|
waiting->taskCount -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
// SAFETY: The lifetime of result pointer is the same as the task that
|
// SAFETY: The lifetime of result pointer is the same as the task that
|
||||||
// produced that pointer, so as long as we have an owning reference to
|
// produced that pointer, so as long as we have an owning reference to
|
||||||
// the tasks through `taskListeners` we can be sure `result` is valid
|
// the tasks through `taskListeners` we can be sure `result` is valid
|
||||||
waiting->taskResults.push_back(result);
|
waiting->taskResults[index] = result;
|
||||||
|
|
||||||
// If all tasks are done, finish
|
// If all tasks are done, finish
|
||||||
if (waiting->taskResults.size() >= waiting->taskCount) {
|
if (waiting->taskCount == 0) {
|
||||||
// SAFETY: The task results' lifetimes are tied to the tasks
|
// SAFETY: The task results' lifetimes are tied to the tasks
|
||||||
// which could have their only owner be `waiting->taskListeners`,
|
// which could have their only owner be `waiting->taskListeners`,
|
||||||
// but since Waiting is owned by the returned AllTask it should
|
// but since Waiting is owned by the returned AllTask it should
|
||||||
|
@ -572,15 +586,17 @@ namespace geode {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Iterate the tasks & start listening to them using
|
// Iterate the tasks & start listening to them using
|
||||||
|
size_t index = 0;
|
||||||
for (auto& taskToWait : tasks) {
|
for (auto& taskToWait : tasks) {
|
||||||
static_cast<Waiting*>(task.m_handle->m_extraData->ptr)->taskListeners.emplace_back(taskToWait.map(
|
static_cast<Waiting*>(task.m_handle->m_extraData->ptr)->taskListeners.emplace_back(taskToWait.map(
|
||||||
[markAsDone](auto* result) {
|
[index, markAsDone](auto* result) {
|
||||||
markAsDone(result);
|
markAsDone(index, result);
|
||||||
return std::monostate();
|
return std::monostate();
|
||||||
},
|
},
|
||||||
[](auto*) { return std::monostate(); },
|
[](auto*) { return std::monostate(); },
|
||||||
[markAsDone]() { markAsDone(nullptr); }
|
[index, markAsDone]() { markAsDone(index, nullptr); }
|
||||||
));
|
));
|
||||||
|
index += 1;
|
||||||
}
|
}
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,16 +172,6 @@ ModSettingsManager::ModSettingsManager(ModMetadata const& metadata)
|
||||||
auto root = checkJson(json, "setting");
|
auto root = checkJson(json, "setting");
|
||||||
root.needs("type").into(setting.type);
|
root.needs("type").into(setting.type);
|
||||||
if (root) {
|
if (root) {
|
||||||
if (setting.type == "custom") {
|
|
||||||
log::warn(
|
|
||||||
"Setting \"{}\" in mod {} has the old \"custom\" type - "
|
|
||||||
"this type has been deprecated and will be removed in Geode v4.0.0. "
|
|
||||||
"Use the new \"custom:type-name-here\" syntax for defining custom "
|
|
||||||
"setting types - see more in "
|
|
||||||
"https://docs.geode-sdk.org/mods/settings/#custom-settings",
|
|
||||||
key, m_impl->modID
|
|
||||||
);
|
|
||||||
}
|
|
||||||
m_impl->settings.emplace(key, setting);
|
m_impl->settings.emplace(key, setting);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -15,9 +15,9 @@ static size_t getDisplayPageSize(ModListSource* src, ModListDisplay display) {
|
||||||
|
|
||||||
$execute {
|
$execute {
|
||||||
listenForSettingChanges("infinite-local-mods-list", [](bool value) {
|
listenForSettingChanges("infinite-local-mods-list", [](bool value) {
|
||||||
InstalledModListSource::get(InstalledModListType::All)->reset();
|
InstalledModListSource::get(InstalledModListType::All)->clearCache();
|
||||||
InstalledModListSource::get(InstalledModListType::OnlyErrors)->reset();
|
InstalledModListSource::get(InstalledModListType::OnlyErrors)->clearCache();
|
||||||
InstalledModListSource::get(InstalledModListType::OnlyOutdated)->reset();
|
InstalledModListSource::get(InstalledModListType::OnlyOutdated)->clearCache();
|
||||||
// Updates is technically a server mod list :-) So I left it out here
|
// Updates is technically a server mod list :-) So I left it out here
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -601,6 +601,16 @@ void ModList::updateDisplay(ModListDisplay display) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure list isn't too small
|
||||||
|
// NOTE: Do NOT call `updateLayout` on m_list, it'll undo this!
|
||||||
|
if (m_list->m_contentLayer->getContentHeight() < m_list->getContentHeight()) {
|
||||||
|
auto diff = m_list->getContentHeight() - m_list->m_contentLayer->getContentHeight();
|
||||||
|
m_list->m_contentLayer->setContentHeight(m_list->getContentHeight());
|
||||||
|
for (auto child : CCArrayExt<CCNode*>(m_list->m_contentLayer->getChildren())) {
|
||||||
|
child->setPositionY(child->getPositionY() + diff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Preserve relative scroll position
|
// Preserve relative scroll position
|
||||||
m_list->m_contentLayer->setPositionY((
|
m_list->m_contentLayer->setPositionY((
|
||||||
m_list->m_contentLayer->getContentHeight() - m_list->getContentHeight()
|
m_list->m_contentLayer->getContentHeight() - m_list->getContentHeight()
|
||||||
|
|
|
@ -64,7 +64,7 @@ std::optional<size_t> ModListSource::getItemCount() const {
|
||||||
void ModListSource::setPageSize(size_t size) {
|
void ModListSource::setPageSize(size_t size) {
|
||||||
if (m_pageSize != size) {
|
if (m_pageSize != size) {
|
||||||
m_pageSize = size;
|
m_pageSize = size;
|
||||||
this->reset();
|
this->clearCache();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
62
loader/src/ui/nodes/OverlayManager.cpp
Normal file
62
loader/src/ui/nodes/OverlayManager.cpp
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
#include <Geode/ui/OverlayManager.hpp>
|
||||||
|
|
||||||
|
using namespace geode::prelude;
|
||||||
|
|
||||||
|
OverlayManager* OverlayManager::get()
|
||||||
|
{
|
||||||
|
static OverlayManager* instance;
|
||||||
|
|
||||||
|
if (!instance)
|
||||||
|
{
|
||||||
|
instance = new OverlayManager();
|
||||||
|
|
||||||
|
CCDirector::get()->setNotificationNode(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayManager::addNode(CCNode* node)
|
||||||
|
{
|
||||||
|
this->addChild(node);
|
||||||
|
|
||||||
|
nodes.push_back(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayManager::removeNode(CCNode* node)
|
||||||
|
{
|
||||||
|
this->removeChild(node);
|
||||||
|
|
||||||
|
std::erase(nodes, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
int OverlayManager::getHighestOverlayZOrder()
|
||||||
|
{
|
||||||
|
int z = INT_MIN;
|
||||||
|
|
||||||
|
for (auto node : nodes)
|
||||||
|
{
|
||||||
|
if (node->getZOrder() > z)
|
||||||
|
z = node->getZOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
int OverlayManager::getLowestOverlayZOrder()
|
||||||
|
{
|
||||||
|
int z = INT_MAX;
|
||||||
|
|
||||||
|
for (auto node : nodes)
|
||||||
|
{
|
||||||
|
if (node->getZOrder() < z)
|
||||||
|
z = node->getZOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<CCNode*> OverlayManager::getOverlays()
|
||||||
|
{
|
||||||
|
return nodes;
|
||||||
|
}
|
|
@ -6,7 +6,7 @@
|
||||||
using namespace geode::prelude;
|
using namespace geode::prelude;
|
||||||
|
|
||||||
PlatformID PlatformID::from(const char* str) {
|
PlatformID PlatformID::from(const char* str) {
|
||||||
// todo in v4: this should just be
|
// todo in v5: this should just be
|
||||||
// "win" -> Windows
|
// "win" -> Windows
|
||||||
// "mac", "mac-intel", "mac-arm" -> Mac
|
// "mac", "mac-intel", "mac-arm" -> Mac
|
||||||
// "ios" -> iOS
|
// "ios" -> iOS
|
||||||
|
@ -38,7 +38,7 @@ PlatformID PlatformID::from(const char* str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlatformID::coveredBy(const char* str, PlatformID t) {
|
bool PlatformID::coveredBy(const char* str, PlatformID t) {
|
||||||
// todo in v4: this is ridiculously inefficient currently - in v4 just use a flag check!
|
// todo in v5: this is ridiculously inefficient currently - in v5 just use a flag check!
|
||||||
return ranges::contains(getCovered(str), t);
|
return ranges::contains(getCovered(str), t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue