Merge branch 'main' into 1.4.0-dev

This commit is contained in:
altalk23 2023-11-21 20:31:36 +03:00
commit d5027ca6ab
15 changed files with 226 additions and 105 deletions

View file

@ -2,6 +2,7 @@ name: Build Binaries
on:
workflow_dispatch:
pull_request:
push:
branches:
- '**' # every branch

3
.gitignore vendored
View file

@ -72,3 +72,6 @@ test-docs.bat
# Ignore krita files too because we don't want our project files shaking my head
**/*.kra
# Ignore clangd cache
.cache

View file

@ -3018,6 +3018,9 @@ class GameLevelManager : cocos2d::CCNode {
void storeUserName(int userID, int accountID, gd::string str) = mac 0x2B9020, win 0xa1a70;
gd::string userNameForUserID(int id) = mac 0x2B91D0, win 0xa1c20;
void updateUserScore() = mac 0x2CB6A0, win 0xada60;
void uploadAccountComment(gd::string text) = win 0xb3250;
void uploadLevelComment(int levelID, gd::string text, int unk) = win 0xb31c0;
void uploadComment(gd::string text, CommentType type, int levelID, int unk) = win 0xb32e0;
void downloadLevel(int id, bool downloadData) = win 0xaa730;
bool hasDownloadedLevel(int id) = win 0xab830;
GJGameLevel* getSavedLevel(int id) = win 0xa2ee0;
@ -3489,6 +3492,13 @@ class GameObject : CCSpritePlus {
void loadGroupsFromString(gd::string str) = mac 0x33b380, win 0xebcb0;
static GameObject* objectFromString(gd::string, bool) = mac 0x33b720, win 0xebe50;
void playShineEffect() = mac 0x2fa9d0, win 0xeab20;
bool canRotateFree() {
return (
m_objectType != GameObjectType::Solid &&
m_objectType != GameObjectType::Breakable &&
m_objectType != GameObjectType::Slope
);
}
//void quickUpdatePosition() = mac 0x335790;
// inlined on windows
void quickUpdatePosition() {
@ -4247,7 +4257,7 @@ class LevelInfoLayer : cocos2d::CCLayer, LevelDownloadDelegate, LevelUpdateDeleg
void downloadLevel() = win 0x177d90, mac 0x161b90;
void onPlay(cocos2d::CCObject* sender) = mac 0x161840, win 0x179730;
void onBack(cocos2d::CCObject* sender) = mac 0x163810, win 0x17C110;
void onDelete(cocos2d::CCObject* sender) = mac 0x162f30, win 0x17A2B0;
void onDelete(cocos2d::CCObject* sender) = mac 0x162f30, win 0x17a1b0;
virtual void levelDownloadFinished(GJGameLevel*) = mac 0x164C00, win 0x1790C0;
virtual void levelUpdateFinished(GJGameLevel*, UpdateResponse) = mac 0x164E60, win 0x1792B0;
@ -5795,6 +5805,13 @@ class SetupTouchTogglePopup : FLAlertLayer {
void updateTargetID() = mac 0x159480;
}
[[link(android)]]
class ShareCommentLayer : FLAlertLayer, TextInputDelegate, UploadActionDelegate, UploadPopupDelegate {
static ShareCommentLayer* create(gd::string, int, CommentType, int) = win 0x24bac0;
bool init(gd::string, int, CommentType, int) = win 0x24bb90;
void onShare(CCObject*) = win 0x24c760;
}
[[link(android)]]
class SimplePlayer : cocos2d::CCSprite {
SimplePlayer() {}

View file

@ -51,6 +51,10 @@ elseif (GEODE_TARGET_PLATFORM STREQUAL "MacOS")
${GEODE_LOADER_PATH}/include/link/libfmod.dylib
)
target_compile_definitions(${PROJECT_NAME} INTERFACE
-DCommentType=CommentTypeDummy
)
set(GEODE_PLATFORM_BINARY "Geode.dylib")
elseif (GEODE_TARGET_PLATFORM STREQUAL "Win32")

View file

@ -1,5 +1,7 @@
#pragma once
#include "DefaultInclude.hpp"
// thanks pie
enum class SearchType {
Search = 0,
@ -54,6 +56,7 @@ enum class GameObjectType {
MiniSizePortal = 18,
UfoPortal = 19,
Modifier = 20,
Breakable = 21,
SecretCoin = 22,
DualPortal = 23,
SoloPortal = 24,
@ -109,6 +112,16 @@ enum class CommentError {
enum class BackupAccountError {
};
// Thanks cocoa!
#ifdef GEODE_IS_MACOS
#undef CommentType
#endif
enum class CommentType {
Level = 0,
Account = 1,
};
enum class BoomListType {
Default = 0x0,
User = 0x2,

View file

@ -64,6 +64,7 @@ namespace geode {
public:
// TODO: do we want to expose all of these functions?
static Loader* get();
enum class LoadingState : uint8_t {
@ -77,6 +78,7 @@ namespace geode {
Done
};
// TODO: return void
Result<> saveData();
Result<> loadData();

View file

@ -6,14 +6,18 @@ using namespace geode::prelude;
struct SaveLoader : Modify<SaveLoader, AppDelegate> {
void trySaveGame() {
log::info("Saving...");
log::info("Saving mod data...");
log::pushNest();
auto r = Loader::get()->saveData();
if (!r) {
log::info("{}", r.unwrapErr());
}
auto begin = std::chrono::high_resolution_clock::now();
log::info("Saved");
(void)Loader::get()->saveData();
auto end = std::chrono::high_resolution_clock::now();
auto time = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count();
log::info("Took {}s", static_cast<float>(time) / 1000.f);
log::popNest();
return AppDelegate::trySaveGame();
}

View file

@ -58,8 +58,17 @@ $execute {
}
int geodeEntry(void* platformData) {
log::Logger::setup();
log::info("Entry");
auto begin = std::chrono::high_resolution_clock::now();
// set up internal mod, settings and data
log::info("Setting up internal mod");
log::pushNest();
auto internalSetupRes = LoaderImpl::get()->setupInternalMod();
log::popNest();
if (!internalSetupRes) {
LoaderImpl::get()->platformMessageBox(
"Unable to Load Geode!",
@ -72,16 +81,20 @@ int geodeEntry(void* platformData) {
// open console
if (Mod::get()->getSettingValue<bool>("show-platform-console")) {
log::debug("Opening console");
Loader::get()->openPlatformConsole();
}
// set up loader, load mods, etc.
log::info("Setting up loader");
log::pushNest();
auto setupRes = LoaderImpl::get()->setup();
log::popNest();
if (!setupRes) {
LoaderImpl::get()->platformMessageBox(
"Unable to Load Geode!",
"There was an unknown fatal error setting up "
"the loader and Geode can not be loaded. "
"the loader and Geode can not be loaded. "
"(" + setupRes.unwrapErr() + ")"
);
LoaderImpl::get()->forceReset();
@ -94,10 +107,16 @@ int geodeEntry(void* platformData) {
// download and install new loader update in the background
if (Mod::get()->getSettingValue<bool>("auto-check-updates")) {
log::info("Starting loader update check");
LoaderImpl::get()->checkForLoaderUpdates();
}
else {
log::info("Skipped loader update check");
}
log::debug("Entry done.");
auto end = std::chrono::high_resolution_clock::now();
auto time = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count();
log::info("Entry took {}s", static_cast<float>(time) / 1000.f);
return 0;
}

View file

@ -44,28 +44,35 @@ tulip::hook::HookMetadata Hook::Impl::getHookMetadata() const {
}
Result<> Hook::Impl::enable() {
if (!m_enabled) {
if (!LoaderImpl::get()->hasHandler(m_address)) {
GEODE_UNWRAP(LoaderImpl::get()->createHandler(m_address, m_handlerMetadata));
}
GEODE_UNWRAP_INTO(auto handler, LoaderImpl::get()->getHandler(m_address));
if (m_enabled)
return Ok();
m_handle = tulip::hook::createHook(handler, m_detour, m_hookMetadata);
log::debug("Enabling hook at function {} with address {}", m_displayName, m_address);
m_enabled = true;
if (!LoaderImpl::get()->hasHandler(m_address)) {
GEODE_UNWRAP(LoaderImpl::get()->createHandler(m_address, m_handlerMetadata));
}
GEODE_UNWRAP_INTO(auto handler, LoaderImpl::get()->getHandler(m_address));
m_handle = tulip::hook::createHook(handler, m_detour, m_hookMetadata);
if (m_owner)
log::debug("Enabled {} hook at {} for {}", m_displayName, m_address, m_owner->getID());
else
log::debug("Enabled {} hook at {}", m_displayName, m_address);
m_enabled = true;
return Ok();
}
Result<> Hook::Impl::disable() {
if (m_enabled) {
GEODE_UNWRAP_INTO(auto handler, LoaderImpl::get()->getHandler(m_address));
if (!m_enabled)
return Ok();
tulip::hook::removeHook(handler, m_handle);
GEODE_UNWRAP_INTO(auto handler, LoaderImpl::get()->getHandler(m_address));
log::debug("Disabling hook at function {}", m_displayName);
m_enabled = false;
}
tulip::hook::removeHook(handler, m_handle);
log::debug("Disabled {} hook", m_displayName);
m_enabled = false;
return Ok();
}
@ -101,4 +108,4 @@ bool Hook::Impl::getAutoEnable() const {
void Hook::Impl::setAutoEnable(bool autoEnable) {
m_autoEnable = autoEnable;
}
}

View file

@ -403,6 +403,8 @@ void Index::Impl::checkForUpdates() {
void Index::Impl::updateFromLocalTree() {
log::debug("Updating local index cache");
log::pushNest();
IndexUpdateEvent(UpdateProgress(100, "Updating local cache")).post();
// delete old items
m_items.clear();
@ -442,6 +444,8 @@ void Index::Impl::updateFromLocalTree() {
// mark source as finished
m_isUpToDate = true;
IndexUpdateEvent(UpdateFinished()).post();
log::popNest();
}
void Index::update(bool force) {

View file

@ -58,33 +58,30 @@ Result<> Loader::Impl::setup() {
return Ok();
}
log::Logger::setup();
if (crashlog::setupPlatformHandler()) {
log::debug("Set up platform crash logger");
}
else {
log::debug("Unable to set up platform crash logger");
log::debug("Setting up crash handler");
log::pushNest();
if (!crashlog::setupPlatformHandler()) {
log::debug("Failed to set up crash handler");
}
log::popNest();
log::debug("Setting up Loader...");
log::debug("Set up internal mod representation");
log::debug("Loading hooks... ");
log::debug("Loading hooks");
log::pushNest();
if (!this->loadHooks()) {
return Err("There were errors loading some hooks, see console for details");
}
log::popNest();
log::debug("Loaded hooks");
log::debug("Setting up IPC...");
log::debug("Setting up IPC");
log::pushNest();
this->setupIPC();
log::popNest();
log::debug("Setting up directories");
log::pushNest();
this->createDirectories();
this->addSearchPaths();
log::popNest();
this->refreshModGraph();
@ -104,14 +101,14 @@ void Loader::Impl::updateResources() {
void Loader::Impl::updateResources(bool forceReload) {
log::debug("Adding resources");
// add mods' spritesheets
log::pushNest();
for (auto const& [_, mod] : m_mods) {
if (forceReload || !ModImpl::getImpl(mod)->m_resourcesLoaded) {
this->updateModResources(mod);
ModImpl::getImpl(mod)->m_resourcesLoaded = true;
}
if (!forceReload && ModImpl::getImpl(mod)->m_resourcesLoaded)
continue;
this->updateModResources(mod);
ModImpl::getImpl(mod)->m_resourcesLoaded = true;
}
log::popNest();
}
std::vector<Mod*> Loader::Impl::getAllMods() {
@ -161,25 +158,27 @@ bool Loader::Impl::isModVersionSupported(VersionInfo const& version) {
// Data saving
Result<> Loader::Impl::saveData() {
// save mods' data
for (auto& [id, mod] : m_mods) {
log::debug("{}", mod->getID());
log::pushNest();
auto r = mod->saveData();
if (!r) {
log::warn("Unable to save data for mod \"{}\": {}", mod->getID(), r.unwrapErr());
}
log::popNest();
}
// save loader data
GEODE_UNWRAP(Mod::get()->saveData());
return Ok();
}
Result<> Loader::Impl::loadData() {
for (auto& [_, mod] : m_mods) {
log::debug("{}", mod->getID());
log::pushNest();
auto r = mod->loadData();
if (!r) {
log::warn("Unable to load data for mod \"{}\": {}", mod->getID(), r.unwrapErr());
}
log::popNest();
}
return Ok();
}
@ -222,9 +221,9 @@ void Loader::Impl::updateModResources(Mod* mod) {
if (mod->getMetadata().getSpritesheets().empty())
return;
log::debug("Adding resources for {}", mod->getID());
log::debug("{}", mod->getID());
log::pushNest();
// add spritesheets
for (auto const& sheet : mod->getMetadata().getSpritesheets()) {
log::debug("Adding sheet {}", sheet);
auto png = sheet + ".png";
@ -243,6 +242,8 @@ void Loader::Impl::updateModResources(Mod* mod) {
CCSpriteFrameCache::get()->addSpriteFramesWithFile(plist.c_str());
}
}
log::popNest();
}
// Dependencies and refreshing
@ -432,6 +433,9 @@ void Loader::Impl::loadModGraph(Mod* node, bool early) {
return;
}
if (node->getID() == "absolllute.megahack")
log::debug("megahack creepypasta");
for (auto const& dep : node->m_impl->m_dependants) {
m_modsToLoad.push_front(dep);
}
@ -564,17 +568,17 @@ void Loader::Impl::findProblems() {
}
void Loader::Impl::refreshModGraph() {
log::info("Refreshing mod graph...");
log::info("Refreshing mod graph");
log::pushNest();
auto begin = std::chrono::high_resolution_clock::now();
if (m_isSetup) {
log::error("Cannot refresh mod graph after startup");
log::popNest();
return;
}
auto begin = std::chrono::high_resolution_clock::now();
m_problems.clear();
m_loadingState = LoadingState::Queue;
@ -707,23 +711,22 @@ bool Loader::Impl::isReadyToHook() const {
return m_readyToHook;
}
void Loader::Impl::addInternalHook(Hook* hook, Mod* mod) {
m_internalHooks.emplace_back(hook, mod);
void Loader::Impl::addUninitializedHook(Hook* hook, Mod* mod) {
m_uninitializedHooks.emplace_back(hook, mod);
}
bool Loader::Impl::loadHooks() {
m_readyToHook = true;
auto thereWereErrors = false;
for (auto const& hook : m_internalHooks) {
bool hadErrors = false;
for (auto const& hook : m_uninitializedHooks) {
auto res = hook.second->addHook(hook.first);
if (!res) {
log::internalLog(Severity::Error, hook.second, "{}", res.unwrapErr());
thereWereErrors = true;
hadErrors = true;
}
}
// free up memory
m_internalHooks.clear();
return !thereWereErrors;
m_uninitializedHooks.clear();
return !hadErrors;
}
void Loader::Impl::queueInMainThread(ScheduledFunction func) {
@ -1103,21 +1106,16 @@ void Loader::Impl::provideNextMod(Mod* mod) {
}
Mod* Loader::Impl::takeNextMod() {
if (!m_nextMod) {
m_nextMod = this->createInternalMod();
log::debug("Created internal mod {}", m_nextMod->getName());
}
auto ret = m_nextMod;
return ret;
if (!m_nextMod)
m_nextMod = this->getInternalMod();
return m_nextMod;
}
void Loader::Impl::releaseNextMod() {
m_nextMod = nullptr;
m_nextModLock.unlock();
}
Result<> Loader::Impl::createHandler(void* address, tulip::hook::HandlerMetadata const& metadata) {
if (m_handlerHandles.count(address)) {
return Err("Handler already exists at address");

View file

@ -71,7 +71,8 @@ namespace geode {
std::vector<utils::MiniFunction<void(void)>> m_gdThreadQueue;
mutable std::mutex m_gdThreadMutex;
std::vector<std::pair<Hook*, Mod*>> m_internalHooks;
bool m_platformConsoleOpen = false;
std::vector<std::pair<Hook*, Mod*>> m_uninitializedHooks;
bool m_readyToHook = false;
bool m_platformConsoleOpen = false;
@ -183,9 +184,9 @@ namespace geode {
bool isNewUpdateDownloaded() const;
bool isReadyToHook() const;
void addInternalHook(Hook* hook, Mod* mod);
void addUninitializedHook(Hook* hook, Mod* mod);
Mod* createInternalMod();
Mod* getInternalMod();
Result<> setupInternalMod();
bool userTriedToLoadDLLs() const;

View file

@ -113,6 +113,36 @@ std::string Log::toString(bool logTime, uint32_t nestLevel) const {
res += fmt::format("{:%H:%M:%S}", m_time);
}
switch (m_severity.m_value) {
case Severity::Debug:
res += " DBG";
break;
case Severity::Info:
res += " INF";
break;
case Severity::Notice:
res += " NTC";
break;
case Severity::Warning:
res += " WRN";
break;
case Severity::Error:
res += " ERR";
break;
case Severity::Critical:
res += " CRT";
break;
case Severity::Alert:
res += " ALR";
break;
case Severity::Emergency:
res += " FAT";
break;
default:
res += " UNK";
break;
}
res += fmt::format(" [{}]: ", m_sender ? m_sender->getName() : "Geode?");
for (uint32_t i = 0; i < nestLevel; i++) {

View file

@ -226,7 +226,7 @@ Result<> Mod::Impl::saveData() {
log::debug("Check covered");
for (auto& [key, value] : m_savedSettingsData.as_object()) {
log::debug("Check if {} is saved", key);
if (!coveredSettings.count(key)) {
if (!coveredSettings.contains(key)) {
json[key] = value;
}
}
@ -485,18 +485,21 @@ Result<> Mod::Impl::disableHook(Hook* hook) {
}
Result<Hook*> Mod::Impl::addHook(Hook* hook) {
m_hooks.push_back(hook);
if (LoaderImpl::get()->isReadyToHook()) {
if (this->isEnabled() && hook->getAutoEnable()) {
auto res = this->enableHook(hook);
if (!res) {
delete hook;
return Err("Can't create hook: "+ res.unwrapErr());
}
}
if (!ranges::contains(m_hooks, [&](auto const& h) { return h == hook; }))
m_hooks.push_back(hook);
if (!LoaderImpl::get()->isReadyToHook()) {
LoaderImpl::get()->addUninitializedHook(hook, m_self);
return Ok(hook);
}
else {
LoaderImpl::get()->addInternalHook(hook, m_self);
if (!this->isEnabled() || !hook->getAutoEnable())
return Ok(hook);
auto res = this->enableHook(hook);
if (!res) {
delete hook;
return Err("Can't create hook: " + res.unwrapErr());
}
return Ok(hook);
@ -683,9 +686,10 @@ static Result<ModMetadata> getModImplInfo() {
return Ok(info);
}
Mod* Loader::Impl::createInternalMod() {
Mod* Loader::Impl::getInternalMod() {
auto& mod = Mod::sharedMod<>;
if (mod) return mod;
if (mod)
return mod;
auto infoRes = getModImplInfo();
if (!infoRes) {
LoaderImpl::get()->platformMessageBox(
@ -702,6 +706,7 @@ Mod* Loader::Impl::createInternalMod() {
}
mod->m_impl->m_enabled = true;
m_mods.insert({ mod->getID(), mod });
log::debug("Created internal mod {}", mod->getName());
return mod;
}

View file

@ -20,24 +20,37 @@ void Loader::Impl::platformMessageBox(char const* title, std::string const& info
bool hasAnsiColorSupport = false;
void Loader::Impl::logConsoleMessageWithSeverity(std::string const& msg, Severity severity) {
if (m_platformConsoleOpen) {
if (hasAnsiColorSupport) {
int color = 0;
switch (severity) {
case Severity::Debug: color = 243; break;
case Severity::Info: color = 33; break;
case Severity::Warning: color = 229; break;
case Severity::Error: color = 9; break;
default: color = 7; break;
}
auto const colorStr = fmt::format("\x1b[38;5;{}m", color);
auto const newMsg = fmt::format("{}{}\x1b[0m{}", colorStr, msg.substr(0, 8), msg.substr(8));
if (!m_platformConsoleOpen)
return;
std::cout << newMsg << "\n" << std::flush;
} else {
std::cout << msg << "\n" << std::flush;
}
if (!hasAnsiColorSupport) {
std::cout << msg << "\n" << std::flush;
return;
}
int color = 0;
switch (severity) {
case Severity::Debug:
color = 243;
break;
case Severity::Info:
color = 33;
break;
case Severity::Warning:
color = 229;
break;
case Severity::Error:
color = 9;
break;
default:
color = 7;
break;
}
auto const colorStr = fmt::format("\x1b[38;5;{}m", color);
auto const newMsg = fmt::format("{}{}\x1b[0m{}", colorStr, msg.substr(0, 12),
msg.substr(12));
std::cout << newMsg << "\n" << std::flush;
}
void Loader::Impl::openPlatformConsole() {