Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions mod.json
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,25 @@
"slider": true
},
"enable-if": "show-sent && enable-sent-cache"
},
"custom-sends-endpoint": {
"name": "Custom Sends Endpoint",
"description": "Only modify this if you're on a GDPS and host a custom SendDB instance (or something with a similar API response)",
"type": "string",
"filter": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789:/.-_%?&=[]@",
"default": ""
},
"disable-gdps-warning": {
"name": "Disable GDPS Warning",
"description": "Disable the warning you get when you're on a GDPS and have the sent indicator toggled on",
"type": "bool",
"default": false
}
},
"dependencies": {
"km7dev.server_api": {
"version": "v4.0.0",
"required": false
}
}
}
43 changes: 2 additions & 41 deletions src/hooks/LevelInfoLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ class $modify(MyLevelInfoLayer, LevelInfoLayer) {
labelContent << "Has LDM: " << (level->m_lowDetailMode ? "Yes" : "No")
<< std::endl;

if (SettingsManager::Toggles.sent) {
if (SettingsManager::Toggles.sent && (!Utils::IsOnGdps() || !SettingsManager::Other.customSendsEndpoint.empty())) {
if (level->m_stars == 0) {
if (auto cached = SettingsManager::Other.enableSentCache ? SentCacheManager::GetLevel(level->m_levelID) : std::nullopt) {
labelContent << "Sent: " << (cached.value() ? "Yes" : "No")
Expand All @@ -201,46 +201,7 @@ class $modify(MyLevelInfoLayer, LevelInfoLayer) {
auto levelID = static_cast<int>(level->m_levelID);

async::spawn(
[levelID]() -> arc::Future<Result<bool, void>> {
// First try requesting to my own cache API specifically for
// the sent state
auto req = co_await utils::web::WebRequest()
.userAgent(Utils::GetUserAgent())
.timeout(std::chrono::seconds(3))
.get(fmt::format("https://sdbc.m336.dev/level/{}", levelID));
auto body = req.json().unwrapOrDefault();
auto error = body["error"].asString().unwrapOrDefault();

// If that doesn't work, fallback to the original SendDB API
if (!req.ok() || body.size() <= 0 || error.size() > 0) {
log::warn(
"Failed requesting to the cache API ({}), fallback to the original SendDB API",
error.size() > 0 ? error : req.errorMessage()
);

req = co_await utils::web::WebRequest()
.userAgent(Utils::GetUserAgent())
.timeout(std::chrono::seconds(3))
.get(fmt::format("https://api.senddb.dev/api/v1/level/{}", levelID));
body = req.json().unwrapOrDefault();
error = req.errorMessage();

// If that still doesn't work, don't go further
if (!req.ok() || body.size() <= 0) {
log::error(
"Failed requesting to the SendDB API: {}",
error.size() > 0 ? error : req.string().unwrap()
);
co_return Err();
}

// For the SendDB API, just check if the sends object is more than 0
co_return Ok(body["sends"].size() > 0 ? true : false);
}

// For the cache, it's directly indicated in the sent boolean
co_return Ok(body["sent"].asBool().unwrap());
},
Utils::CheckIfLevelSent(levelID),
[self, levelID](Result<bool, void> result) {
if (!self->m_fields->m_label)
return;
Expand Down
34 changes: 34 additions & 0 deletions src/hooks/MenuLayer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include <Geode/modify/MenuLayer.hpp>
#include "../managers/SettingsManager.h"
#include "../utils/Utils.h"

using namespace geode::prelude;

class $modify(MenuLayer) {
bool init() {
if (!MenuLayer::init())
return false;

if (SettingsManager::Toggles.sent &&
Utils::IsOnGdps() &&
SettingsManager::Other.customSendsEndpoint.empty() &&
SettingsManager::Other.showGDPSWarning &&
!SettingsManager::ShowedGDPSWarning
) {
Notification::create(
"Level Info's sent indicator was disabled (you're on a GDPS)",
NotificationIcon::Warning,
2.f
)->show();
Notification::create(
"Change the sent indicator URL/disable this warning in its settings",
NotificationIcon::Warning,
2.f
)->show();

SettingsManager::ShowedGDPSWarning = true;
}

return true;
};
};
14 changes: 12 additions & 2 deletions src/managers/SettingsManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ CustomStruct::ToggleSettings SettingsManager::Toggles = {
CustomStruct::OtherSettings SettingsManager::Other = {
Mod::get()->getSettingValue<bool>("enable-sent-cache"),
Mod::get()->getSettingValue<int>("sent-cache-limit"),
Mod::get()->getSettingValue<int>("sent-cache-expiration") * 60
Mod::get()->getSettingValue<int>("sent-cache-expiration") * 60,
Mod::get()->getSettingValue<std::string>("custom-sends-endpoint"),
!Mod::get()->getSettingValue<bool>("disable-gdps-warning")
};

// There is DEFINITELY a better way to do this but if it works it works
Expand Down Expand Up @@ -132,4 +134,12 @@ CustomStruct::OtherSettings SettingsManager::Other = {
listenForSettingChanges<int>("sent-cache-expiration", [](int expiration) {
SettingsManager::Other.maxSentCacheExpiration = expiration * 60;
});
};
listenForSettingChanges<std::string>("custom-sends-endpoint", [](std::string url) {
SettingsManager::Other.customSendsEndpoint = url;
});
listenForSettingChanges<bool>("disable-gdps-warning", [](bool enabled) {
SettingsManager::Other.showGDPSWarning = !enabled;
});
};

bool SettingsManager::ShowedGDPSWarning = false;
2 changes: 2 additions & 0 deletions src/managers/SettingsManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ class SettingsManager {
static CustomStruct::DisplaySettings Display;
static CustomStruct::ToggleSettings Toggles;
static CustomStruct::OtherSettings Other;

static bool ShowedGDPSWarning;
};
2 changes: 2 additions & 0 deletions src/utils/CustomStruct.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ namespace CustomStruct {
bool enableSentCache;
int maxSentCacheLimit;
int maxSentCacheExpiration;
std::string customSendsEndpoint;
bool showGDPSWarning;
};

struct SentCacheEntry {
Expand Down
81 changes: 78 additions & 3 deletions src/utils/Utils.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,52 @@
#include "Utils.h"
#include <km7dev.server_api/include/ServerAPIEvents.hpp>
#include "../managers/SettingsManager.h"

using namespace geode::prelude;

std::string const& Utils::GetUserAgent() {
static const auto userAgent = "LevelInfo/" + Mod::get()->getVersion().toNonVString();
return userAgent;
std::string const& Utils::RequestUserAgent = "LevelInfo/" + Mod::get()->getVersion().toNonVString();
std::chrono::seconds const Utils::RequestTimeout = std::chrono::seconds(3);

arc::Future<Result<bool, void>> Utils::CheckIfLevelSent(int levelID) {
if (!Utils::IsOnGdps() && SettingsManager::Other.customSendsEndpoint.empty()) {
auto req = co_await utils::web::WebRequest()
.userAgent(Utils::RequestUserAgent)
.timeout(Utils::RequestTimeout)
.get(fmt::format("https://sdbc.m336.dev/level/{}", levelID));

auto body = req.json().unwrapOrDefault();
auto error = body["error"].asString().unwrapOrDefault();

if (req.ok() && body.size() > 0 && error.empty())
co_return Ok(body["sent"].asBool().unwrap());
else
log::warn(
"Failed requesting to the SendDB cache API: {}. Falling back to the original SendDB API",
error.size() > 0 ? error : req.errorMessage()
);
}

auto req = co_await utils::web::WebRequest()
.userAgent(Utils::RequestUserAgent)
.timeout(Utils::RequestTimeout)
.get(SettingsManager::Other.customSendsEndpoint.empty()
? "https://api.senddb.dev/api/v1/level/"
: SettingsManager::Other.customSendsEndpoint
+ std::to_string(levelID));

auto body = req.json().unwrapOrDefault();

if (!req.ok() || body.size() <= 0) {
auto error = req.errorMessage();

log::error(
"Failed requesting to the SendDB API: {}",
error.size() > 0 ? error : req.string().unwrap()
);
co_return Err();
}

co_return Ok(body["sends"].size() > 0 ? true : false);
};

std::unordered_map<int, std::string_view> Utils::GameVersions = {
Expand All @@ -17,6 +58,40 @@ std::unordered_map<int, std::string_view> Utils::GameVersions = {
{ 10, "1.7" }
};

// https://github.com/hiimjasmine00/jasmine-tools/blob/6b6a3b00536a341791eb0de33e53b63c49baa8df/src/jasmine.cpp#L39-L66
bool Utils::IsOnGdps() {
static const bool isOnGdps = []() -> bool {
std::string url;

if (Loader::get()->isModLoaded("km7dev.server_api")) {
url = ServerAPIEvents::getCurrentServer().url;
if (!url.empty() && url!= "NONE_REGISTERED") {
while (url.ends_with("/")) url.pop_back();
} else {
url = "";
}
}

if (url.empty()) {
static_assert(GEODE_COMP_GD_VERSION == 22081, "Incompatible GD version for GDPS check");
url = std::string(
reinterpret_cast<const char *>(base::get() +
GEODE_WINDOWS(0x558b70)
GEODE_ARM_MAC(0x77d709)
GEODE_INTEL_MAC(0x868df0)
GEODE_ANDROID64(0xeccf90)
GEODE_ANDROID32(0x96c0db)
GEODE_IOS(0x6b8cc2)
), 34
);
}

return url.find("://www.boomlings.com/database") == std::string::npos;
}();

return isOnGdps;
}

std::string_view Utils::GetGameVersion(int gameVersion) {
if (Utils::GameVersions.count(gameVersion))
return Utils::GameVersions.at(gameVersion);
Expand Down
7 changes: 6 additions & 1 deletion src/utils/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@

class Utils {
private:
static std::string const& RequestUserAgent;
static std::chrono::seconds const RequestTimeout;

static std::unordered_map<int, std::string_view> GameVersions;

public:
static std::string const& GetUserAgent();
static arc::Future<geode::Result<bool, void>> CheckIfLevelSent(int levelID);

static std::string_view GetGameVersion(int gameVersion);

static bool IsOnGdps();

static std::string FormatNumber(size_t number);
static std::string FormatTime(std::chrono::seconds seconds);

Expand Down
Loading