Merge branch 'main' of https://github.com/geode-sdk/geode into tulip-hook

This commit is contained in:
altalk23 2022-12-26 21:35:29 +03:00
commit 9e30870c79
30 changed files with 401 additions and 1023 deletions

View file

@ -961,6 +961,9 @@ class cocos2d::extension::CCControlColourPicker {
auto ccTouchBegan(cocos2d::CCTouch*, cocos2d::CCEvent*) = mac 0x1aae10;
auto init() = mac 0x1aa400;
static auto colourPicker() = mac 0x1aaa30;
cocos2d::ccColor3B const& getColorValue() const {
return m_rgb;
}
}

View file

@ -744,10 +744,10 @@ class ColorSelectLiveOverlay : FLAlertLayer {
class ColorSelectPopup : FLAlertLayer, cocos2d::extension::ColorPickerDelegate, TextInputDelegate, GJSpecialColorSelectDelegate {
virtual void colorValueChanged(cocos2d::ccColor3B color) = mac 0x423520, win 0x46ee0;
ColorSelectPopup() {}
bool init(EffectGameObject* triggerObj, cocos2d::CCArray* triggerObjs, ColorAction* colorAction) = mac 0x41ee70, win 0x43ae0;
void updateColorValue() = win 0x46f30;
void updateCopyColorTextInputLabel() = win 0x479c0;
void updateCopyColorTextInputLabel() = win 0x479c0, mac 0x422ed0;
void closeColorSelect(cocos2d::CCObject* sender) = mac 0x421af0, win 0x46d80;
cocos2d::extension::CCControlColourPicker* m_colorPicker;
@ -1078,14 +1078,12 @@ class EditButtonBar : cocos2d::CCNode {
}
class EditLevelLayer : cocos2d::CCLayer, FLAlertLayerProtocol, TextInputDelegate, UploadActionDelegate, UploadPopupDelegate, SetIDPopupDelegate {
static void scene(GJGameLevel* level) {
static cocos2d::CCScene* scene(GJGameLevel* level) {
auto scene = cocos2d::CCScene::create();
scene->addChild(EditLevelLayer::create(level));
cocos2d::CCDirector::sharedDirector()->replaceScene(
cocos2d::CCTransitionFade::create(.5f, scene)
);
AppDelegate::get()->m_runningScene = scene;
return scene;
}
static EditLevelLayer* create(GJGameLevel* level) = mac 0xe1e50, win 0x6f530, ios 0x82420;
@ -1463,6 +1461,7 @@ class EndLevelLayer {
static EndLevelLayer* create() = mac 0x2787d0, win 0x94b50;
void onMenu(cocos2d::CCObject* sender) = mac 0x27a500, win 0x96c10;
void onEdit(cocos2d::CCObject* sender) = mac 0x27a640, win 0x96d30;
}
class EndPortalObject : GameObject {
@ -3532,14 +3531,12 @@ class LeaderboardsLayer : cocos2d::CCLayer {
}
class LevelBrowserLayer : cocos2d::CCLayer {
static void scene(GJSearchObject* search) {
static cocos2d::CCScene* scene(GJSearchObject* search) {
auto scene = cocos2d::CCScene::create();
scene->addChild(LevelBrowserLayer::create(search));
cocos2d::CCDirector::sharedDirector()->pushScene(
cocos2d::CCTransitionFade::create(.5f, scene)
);
AppDelegate::get()->m_runningScene = scene;
return scene;
}
bool init(GJSearchObject* search) = mac 0x2513f0, win 0x15a040;
@ -3593,13 +3590,10 @@ class LevelEditorLayer : GJBaseGameLayer, LevelSettingsDelegate {
}
static cocos2d::CCScene* scene(GJGameLevel* level) {
auto scene = cocos2d::CCScene::create();
scene->addChild(LevelEditorLayer::create(level));
scene->setObjType(cocos2d::kCCObjectTypeLevelEditorLayer);
cocos2d::CCDirector::sharedDirector()->replaceScene(
cocos2d::CCTransitionFade::create(0.5f, scene)
);
scene->setObjType(cocos2d::CCObjectType::LevelEditorLayer);
AppDelegate::get()->m_runningScene = scene;
return scene;
}
@ -3690,6 +3684,9 @@ class LevelEditorLayer : GJBaseGameLayer, LevelSettingsDelegate {
void updateToggledGroups() = mac 0x9bb10;
void updateVisibility(float) = mac 0x92c70, win 0x1632b0;
void groupStickyObjects(cocos2d::CCArray* objects) = mac 0x99dd0, win 0x164860;
void ungroupStickyObjects(cocos2d::CCArray* objects) = mac 0x99ee0, win 0x164950;
void setStartPosObject(StartPosObject* obj) {
CC_SAFE_RETAIN(obj);
CC_SAFE_RELEASE(m_currentStartPos);
@ -3955,6 +3952,7 @@ class LoadingLayer : cocos2d::CCLayer {
static cocos2d::CCScene* scene(bool fromReload) {
auto scene = cocos2d::CCScene::create();
scene->addChild(LoadingLayer::create(fromReload));
return scene;
}
@ -4302,7 +4300,16 @@ class PlayLayer : GJBaseGameLayer, CCCircleWaveDelegate, CurrencyRewardDelegate,
void resume() = mac 0x80480, win 0x20d5c0;
void resumeAndRestart() = mac 0x80400, win 0x20d4c0;
void saveRecordAction(bool, PlayerObject*) = mac 0x78750, win 0x20ad40;
static cocos2d::CCScene* scene(GJGameLevel*) = mac 0x6b500, win 0x1fb690;
static cocos2d::CCScene* scene(GJGameLevel* level) {
auto scene = cocos2d::CCScene::create();
scene->addChild(PlayLayer::create(level));
scene->setObjType(cocos2d::CCObjectType::PlayLayer);
AppDelegate::get()->m_runningScene = scene;
return scene;
}
void setupLevelStart(LevelSettingsObject*) = mac 0x6f560, win 0x1fb780;
void setupReplay(gd::string) = mac 0x7e1e0;
void shakeCamera(float, float, float) = mac 0x744a0, win 0x1ff210;
@ -4769,7 +4776,7 @@ class PlayerObject : GameObject, AnimatedSpriteDelegate {
PAD = mac 0x24, win 0x24;
float m_decelerationRate;
PAD = mac 0x14, win 0x14;
GameObject* m_unk59C;
GameObject* m_snappedObject;
PAD = mac 0x10, win 0x8;
GJRobotSprite* m_robotSprite;
GJSpiderSprite* m_spiderSprite;
@ -4821,7 +4828,7 @@ class PlayerObject : GameObject, AnimatedSpriteDelegate {
cocos2d::CCLayer* m_unk65C;
bool m_isSliding;
bool m_isRising;
bool m_unk662;
bool m_isLocked;
cocos2d::CCPoint m_lastGroundedPos;
cocos2d::CCArray* m_touchingRings;
GameObject* m_lastActivatedPortal;
@ -5014,11 +5021,12 @@ class SetupPickupTriggerPopup : FLAlertLayer {
}
class SetupPulsePopup : FLAlertLayer, cocos2d::extension::ColorPickerDelegate, TextInputDelegate, GJSpecialColorSelectDelegate {
virtual void colorValueChanged(cocos2d::ccColor3B color) = win 0x242660;
virtual void colorValueChanged(cocos2d::ccColor3B color) = win 0x242660, mac 0x1ec680;
SetupPulsePopup() {}
bool init(EffectGameObject* triggerObj, cocos2d::CCArray* triggerObjs) = win 0x23e980;
bool init(EffectGameObject* triggerObj, cocos2d::CCArray* triggerObjs) = win 0x23e980, mac 0x1e7010;
void updateColorValue() = win 0x2426b0;
void onSelectPulseMode(cocos2d::CCObject*) = win 0x241420;
void onSelectPulseMode(cocos2d::CCObject*) = win 0x241420, mac 0x1eb020;
void updatePulseMode() = win 0x242cf0;

View file

@ -1,12 +0,0 @@
cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
project(Broma LANGUAGES C CXX)
add_library(Broma ${CMAKE_CURRENT_SOURCE_DIR}/src/broma.cpp)
target_compile_features(Broma PRIVATE cxx_std_17)
target_include_directories(Broma PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_compile_definitions(Broma PUBLIC TAO_PEGTL_GHC_FILESYSTEM=1)
target_link_libraries(Broma taocpp::pegtl ghc_filesystem)

View file

@ -1,138 +0,0 @@
#include <string>
#include <vector>
#include <variant>
#include <map>
#include <algorithm>
#include <iostream>
enum class Platform {
Mac,
iOS,
Windows,
Android
};
struct PlatformNumber {
size_t mac = 0;
size_t ios = 0;
size_t win = 0;
size_t android = 0;
};
struct Type {
bool is_struct = false;
std::string name;
bool operator==(Type const& t) const {
return name == t.name;
}
};
enum class FunctionType {
Normal,
Ctor,
Dtor
};
struct FunctionBegin {
Type ret;
FunctionType type = FunctionType::Normal;
std::vector<std::pair<Type, std::string>> args;
bool is_const = false;
bool is_virtual = false;
bool is_static = false;
std::string docs;
std::string name;
inline bool operator==(FunctionBegin const& f) const {
if (name != f.name || is_const != f.is_const || args.size() != f.args.size())
return false;
for (size_t i = 0; i < args.size(); ++i) {
if (!(args[i].first == f.args[i].first))
return false;
}
std::cout << f.ret.name << " " << f.name << "\n";
return true;
}
};
struct MemberField {
std::string name;
Type type;
size_t count = 0;
};
struct PadField {
PlatformNumber amount;
};
struct FunctionBindField {
FunctionBegin beginning;
PlatformNumber binds;
};
struct OutOfLineField {
FunctionBegin beginning;
std::string inner;
};
struct InlineField {
std::string inner;
};
struct Class;
struct Field {
size_t field_id;
std::string parent;
std::variant<InlineField, OutOfLineField, FunctionBindField, PadField, MemberField> inner;
template <typename T>
T* get_as() {
return std::get_if<T>(&inner);
}
template <typename T>
T const* get_as() const {
return std::get_if<T>(&inner);
}
inline FunctionBegin* get_fn() {
if (auto fn = get_as<OutOfLineField>()) {
return &fn->beginning;
} else if (auto fn = get_as<FunctionBindField>()) {
return &fn->beginning;
} else return nullptr;
}
};
struct Class {
std::string name;
std::vector<std::string> superclasses;
std::vector<std::string> depends;
std::vector<Field> fields;
inline bool operator==(Class const& c) const {
return name == c.name;
}
inline bool operator==(std::string const& n) const {
return name == n;
}
};
struct Root {
std::vector<Class> classes;
inline Class* operator[](std::string const& name) {
auto it = std::find_if(classes.begin(), classes.end(), [name](Class& cls) {
return cls.name == name;
});
if (it == classes.end())
return nullptr;
return &*it;
}
};

View file

@ -1,5 +0,0 @@
#include "ast.hpp"
namespace broma {
Root parse_file(std::string const& fname);
}

View file

@ -1,40 +0,0 @@
#pragma once
#include <tao/pegtl.hpp>
using namespace tao::pegtl;
#include "basic_components.hpp"
#include "state.hpp"
namespace broma {
template <typename Name, typename ...Parse>
struct basic_attribute : seq<
Name,
one<'('>,
if_then_else<
at<one<')'>>,
success,
seq<Parse...>
>,
one<')'>
> {};
struct docs_attribute : basic_attribute<TAO_PEGTL_KEYWORD("docs"), string_literal> {};
struct depends_attribute : basic_attribute<TAO_PEGTL_KEYWORD("depends"), tagged_rule<depends_attribute, qualified>> {};
struct attribute :
if_must<ascii::string<'[', '['>,
sor<docs_attribute, depends_attribute>,
ascii::string<']', ']'>
> {};
template <>
struct run_action<tagged_rule<depends_attribute, qualified>> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_class.depends.push_back(input.string());
}
};
} // namespace broma

View file

@ -1,68 +0,0 @@
#pragma once
#include <tao/pegtl.hpp>
using namespace tao::pegtl;
namespace broma {
struct comment :
disable<sor<
seq<ascii::string<'/', '/'>, until<eolf>>,
seq<ascii::string<'/', '*'>, until<seq<ascii::string<'*', '/'>>>>
>> {};
struct ignore : sor<comment, one<'\n', '\t', '\r', ' '>> {};
struct sep : star<ignore> {};
struct whitespace : plus<ignore> {};
template <typename ...Args>
struct pad_space : seq<Args..., whitespace> {};
template <typename ...Args>
struct rpad_space : seq<whitespace, Args...> {};
template <typename R, typename ...S>
struct if_then_must : if_then_else<R, must<S...>, seq<S...>> {};
template <char Quote>
struct basic_literal : if_must<one<Quote>, until<one<Quote>>> {};
struct string_literal : sor<basic_literal<'"'>, basic_literal<'\''>> {};
struct brace_end;
struct brace_start : seq<one<'{'>, brace_end> {};
struct brace_end : until<one<'}'>, sor<string_literal, brace_start, any>> {};
struct template_end;
struct template_start : seq<one<'<'>, template_end> {};
struct template_end : until<one<'>'>, sor<string_literal, template_start, any>> {};
template <typename T, typename ...Args>
struct tagged_rule : seq<Args...> {};
template <typename T>
struct rule_begin : success {};
#define $named_rule(name, ...) tagged_rule<TAO_PEGTL_INTERNAL_STRING(ascii::string, name), __VA_ARGS__>
#define $keyword(name) struct keyword_##name : TAO_PEGTL_KEYWORD(#name) {}
$keyword(const);
$keyword(static);
$keyword(virtual);
$keyword(inline);
$keyword(class);
$keyword(struct);
$keyword(unsigned);
$keyword(mac);
$keyword(win);
$keyword(ios);
$keyword(android);
$keyword(PAD);
struct qualified : list<seq<identifier, opt<template_start>>, ascii::string<':', ':'>> {};
// point of no return: '0x'
struct hex : if_must<ascii::string<'0', 'x'>, plus<ascii::xdigit>> {};
struct platform : sor<keyword_mac, keyword_win, keyword_ios, keyword_android> {};
} // namespace broma

View file

@ -1,83 +0,0 @@
#pragma once
#include <tao/pegtl.hpp>
using namespace tao::pegtl;
#include "basic_components.hpp"
#include "state.hpp"
#include <sstream>
namespace broma {
struct bind :
seq<rule_begin<bind>, opt_must<
one<'='>,
sep,
list<opt<
sep,
sor<keyword_mac, keyword_win, keyword_ios, keyword_android>,
sep,
tagged_rule<bind, hex>
>, one<','>>,
sep
>, one<';'>> {};
template <>
struct run_action<rule_begin<bind>> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_bind = PlatformNumber();
}
};
template <>
struct run_action<tagged_rule<bind, hex>> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
size_t out = std::stoul(input.string(), nullptr, 16);
switch (scratch->wip_bind_platform) {
case Platform::Mac:
scratch->wip_bind.mac = out;
break;
case Platform::iOS:
scratch->wip_bind.ios = out;
break;
case Platform::Windows:
scratch->wip_bind.win = out;
break;
case Platform::Android:
scratch->wip_bind.android = out;
break;
}
}
};
template <>
struct run_action<keyword_mac> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_bind_platform = Platform::Mac;
}
};
template <>
struct run_action<keyword_ios> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_bind_platform = Platform::iOS;
}
};
template <>
struct run_action<keyword_win> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_bind_platform = Platform::Windows;
}
};
template <>
struct run_action<keyword_android> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_bind_platform = Platform::Android;
}
};
} // namespace broma

View file

@ -1,129 +0,0 @@
#include <tao/pegtl.hpp>
#include <iostream>
#include "attribute.hpp"
#include "basic_components.hpp"
#include "function.hpp"
#include "member.hpp"
#include "state.hpp"
#include "post_process.hpp"
#include "preprocessor.hpp"
using namespace tao::pegtl;
namespace broma {
struct inline_expr :
if_must<
keyword_inline,
if_then_else<
at<rematch<until<eolf>, until<one<'{'>>>>,
until<brace_start>,
until<eolf>
>
> {};
template <>
struct run_action<inline_expr> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
InlineField inf;
inf.inner = input.string();
scratch->wip_field.inner = inf;
}
};
struct field : sor<inline_expr, pad_expr, member_expr, bind_expr, ool_expr> {};
template <>
struct run_action<field> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_field.parent = scratch->wip_class.name;
static size_t index = 0;
scratch->wip_field.field_id = index++;
scratch->wip_class.fields.push_back(scratch->wip_field);
}
};
struct class_statement :
seq<
opt<attribute>,
sep,
must<keyword_class>,
whitespace,
must<$named_rule("class name", qualified)>,
sep,
opt_must<
one<':'>,
sep,
list<seq<
sep,
$named_rule("superclass", qualified),
sep
>, one<','>>
>,
one<'{'>,
sep,
until<one<'}'>, sep, must<field>, sep>
> {};
template <>
struct run_action<$named_rule("superclass", qualified)> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
if (scratch->wip_class.name == input.string())
throw parse_error("Class subclasses itself", input.position());
scratch->wip_class.superclasses.push_back(input.string());
scratch->wip_class.depends.push_back(input.string());
}
};
template <>
struct run_action<$named_rule("class name", qualified)> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_class.name = input.string();
if (std::find(root->classes.begin(), root->classes.end(), input.string()) != root->classes.end()) {
scratch->errors.push_back(parse_error("Class duplicate!", input.position()));
}
}
};
template <>
struct run_action<class_statement> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
root->classes.push_back(std::move(scratch->wip_class));
//std::cout << "class end\n";
scratch->wip_class = Class();
}
};
struct root_grammar : until<eof, sep, must<sor<include_expr, class_statement>>, sep> {};
Root parse_file(std::string const& fname) {
file_input<> input(fname);
Root root;
ScratchData scratch;
parse<must<root_grammar>, run_action>(input, &root, &scratch);
post_process(root);
if (scratch.errors.size()) {
std::cerr << "[Broma] errors found on parsing: \n";
for (auto& e : scratch.errors) {
std::cerr << "\t" << e.what() << "\n";
}
//abort();
}
return root;
}
} // namespace broma

View file

@ -1,152 +0,0 @@
#pragma once
#include <tao/pegtl.hpp>
using namespace tao::pegtl;
#include "basic_components.hpp"
#include "attribute.hpp"
#include "type.hpp"
#include "bind.hpp"
#include "state.hpp"
namespace broma {
struct function_begin :
seq<rule_begin<function_begin>, opt<attribute>, sep, sor<
// ctor, dtor
seq<
$named_rule("structor", success),
opt<pad_space<keyword_virtual>>,
opt<tagged_rule<function_begin, one<'~'>>>,
tagged_rule<function_begin, identifier>,
arg_list
>,
// not ctor, dtor
if_then_must<
sor<keyword_static, keyword_virtual>,
$named_rule("fn_normal", success),
sep,
tagged_rule<function_begin, type>,
sep,
tagged_rule<function_begin, identifier>,
arg_list,
sep,
opt<tagged_rule<function_begin, keyword_const>>
>
>> {};
template <>
struct run_action<rule_begin<function_begin>> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_fn_begin = FunctionBegin();
}
};
template <>
struct run_action<function_begin> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
for (auto& f : scratch->wip_class.fields) {
if (auto fn = f.get_fn()) {
if (*fn == scratch->wip_fn_begin) {
scratch->errors.push_back(parse_error("Function duplicate!", input.position()));
}
}
}
}
};
template <>
struct run_action<tagged_rule<function_begin, identifier>> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_fn_begin.name = input.string();
if (scratch->wip_fn_begin.type == FunctionType::Dtor)
scratch->wip_fn_begin.name = "~" + scratch->wip_fn_begin.name;
}
};
template <>
struct run_action<tagged_rule<function_begin, keyword_const>> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_fn_begin.is_const = true;
}
};
template <>
struct run_action<tagged_rule<function_begin, type>> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_fn_begin.ret = scratch->wip_type;
}
};
template <>
struct run_action<$named_rule("fn_normal", success)> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_fn_begin.type = FunctionType::Normal;
}
};
template <>
struct run_action<$named_rule("structor", success)> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_fn_begin.type = FunctionType::Ctor;
}
};
template <>
struct run_action<keyword_static> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_fn_begin.is_static = true;
}
};
template <>
struct run_action<tagged_rule<function_begin, one<'~'>>> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_fn_begin.type = FunctionType::Dtor;
}
};
template <>
struct run_action<keyword_virtual> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_fn_begin.is_virtual = true;
}
};
struct ool_expr : seq<function_begin, sep, tagged_rule<ool_expr, brace_start>> {};
template <>
struct run_action<tagged_rule<ool_expr, brace_start>> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
OutOfLineField f;
f.beginning = scratch->wip_fn_begin;
f.inner = input.string();
scratch->wip_field.inner = f;
}
};
struct bind_expr : seq<function_begin, sep, bind> {};
template <>
struct run_action<bind_expr> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
FunctionBindField f;
f.beginning = scratch->wip_fn_begin;
f.binds = scratch->wip_bind;
scratch->wip_field.inner = f;
}
};
} // namespace broma

View file

@ -1,68 +0,0 @@
#pragma once
#include <tao/pegtl.hpp>
using namespace tao::pegtl;
#include "type.hpp"
#include "bind.hpp"
#include "state.hpp"
namespace broma {
struct member_expr :
seq<
rule_begin<member_expr>,
type,
whitespace,
tagged_rule<member_expr, identifier>,
sep,
opt<array>,
sep,
one<';'>
> {};
template <>
struct run_action<rule_begin<member_expr>> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
MemberField f;
scratch->wip_field.inner = f;
}
};
template <>
struct run_action<tagged_rule<member_expr, identifier>> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_field.get_as<MemberField>()->name = input.string();
}
};
template <>
struct run_action<member_expr> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_field.get_as<MemberField>()->type = scratch->wip_type;
}
};
struct pad_expr : seq<keyword_PAD, sep, bind> {};
template <>
struct run_action<keyword_PAD> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
PadField f;
PlatformNumber p;
scratch->wip_field.inner = f;
scratch->wip_bind = p;
}
};
template <>
struct run_action<pad_expr> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_field.get_as<PadField>()->amount = scratch->wip_bind;
}
};
} // namespace broma

View file

@ -1,25 +0,0 @@
#pragma once
#include "state.hpp"
#include <algorithm>
#include <iostream>
namespace broma {
inline void sortClass(Class cls, Root& root, std::vector<Class>& output) {
root.classes.erase(std::remove(root.classes.begin(), root.classes.end(), cls), root.classes.end());
for (auto name : cls.depends) {
if (root[name])
sortClass(*root[name], root, output);
}
output.push_back(cls);
}
inline void post_process(Root& root) {
std::vector<Class> out;
while (root.classes.size())
sortClass(root.classes[0], root, out);
root.classes = out;
}
}

View file

@ -1,20 +0,0 @@
#include "basic_components.hpp"
#include "state.hpp"
namespace broma {
struct include_name : until<at<one<'>'>>> {};
struct include_expr : seq<ascii::string<'#', 'i', 'n', 'c', 'l', 'u', 'd', 'e'>, sep, one<'<'>, include_name, one<'>'>> {};
struct root_grammar;
template <>
struct run_action<include_name> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
file_input<> file_input(input.string());
parse<root_grammar, broma::run_action>(file_input, root, scratch);
}
};
} // namespace broma

View file

@ -1,20 +0,0 @@
#pragma once
#include <tao/pegtl.hpp>
#include <ast.hpp>
namespace broma {
template <typename Rule>
struct run_action {};
struct ScratchData {
Class wip_class;
Field wip_field;
PlatformNumber wip_bind;
Platform wip_bind_platform;
Type wip_type;
FunctionBegin wip_fn_begin;
std::vector<tao::pegtl::parse_error> errors;
};
} // namespace broma

View file

@ -1,103 +0,0 @@
#pragma once
#include <tao/pegtl.hpp>
using namespace tao::pegtl;
#include "basic_components.hpp"
#include "state.hpp"
namespace broma {
struct type_content :
if_then_must<
pad_space<sor<keyword_const, keyword_struct>>,
sor<pad_space<keyword_const>, pad_space<keyword_struct>, success>,
if_then_else<pad_space<keyword_unsigned>, opt<qualified>, qualified>,
opt<rpad_space<keyword_const>>,
star<seq<sep, one<'&', '*'>>>
> {};
struct type : seq<rule_begin<type>, sep, type_content> {};
template <>
struct run_action<rule_begin<type>> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_type = Type();
}
};
template <>
struct run_action<keyword_struct> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_type.is_struct = true;
}
};
template <>
struct run_action<type_content> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_type.name = input.string();
}
};
struct array : if_must<one<'['>, tagged_rule<array, plus<ascii::digit>>, one<']'>> {};
template <>
struct run_action<tagged_rule<array, plus<ascii::digit>>> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_field.get_as<MemberField>()->count = std::stoul(input.string(), nullptr, 10);
}
};
struct arg_name : opt<identifier> {};
struct arg_list :
seq<
rule_begin<arg_list>,
one<'('>,
if_then_else<
at<one<')'>>,
success,
list<seq<
sep,
tagged_rule<arg_list, type>,
sep,
arg_name,
sep
>, one<','>>
>,
one<')'>
> {};
template <>
struct run_action<rule_begin<arg_list>> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_fn_begin.args.clear();
}
};
template <>
struct run_action<tagged_rule<arg_list, type>> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
scratch->wip_fn_begin.args.push_back({scratch->wip_type, ""});
}
};
template <>
struct run_action<arg_name> {
template <typename T>
static void apply(T& input, Root* root, ScratchData* scratch) {
if (input.string() == "")
scratch->wip_fn_begin.args.back().second = std::string("p") + std::to_string(scratch->wip_fn_begin.args.size() - 1);
else
scratch->wip_fn_begin.args.back().second = input.string();
}
};
} // namespace broma

View file

@ -4,10 +4,7 @@ project(Codegen LANGUAGES C CXX)
include(../cmake/CPM.cmake)
CPMAddPackage("gh:fmtlib/fmt#9.1.0")
CPMAddPackage("gh:gulrak/filesystem#3e5b930")
CPMAddPackage("gh:matcool/PEGTL#8faeb5d")
add_subdirectory(Broma)
CPMAddPackage("gh:camila314/Broma#1.0.0")
file(GLOB SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp
@ -16,7 +13,7 @@ file(GLOB SOURCES
add_executable(${PROJECT_NAME} ${SOURCES})
target_compile_features(Codegen PUBLIC cxx_std_17)
target_link_libraries(Codegen PRIVATE fmt::fmt Broma ghc_filesystem)
target_link_libraries(Codegen PRIVATE fmt::fmt Broma)
target_include_directories(Codegen PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src
)

View file

@ -48,11 +48,12 @@ NS_CC_BEGIN
*/
RT_ADD(
typedef enum {
kCCObjectTypePlayLayer = 5,
kCCObjectTypeLevelEditorLayer = 6,
kCCObjectTypeMenuLayer = 15,
} CCObjectType;
// please someone tell we why in higher being(s)'s name rob did this
enum class CCObjectType {
PlayLayer = 5,
LevelEditorLayer = 6,
MenuLayer = 15,
};
)
class CCZone;
@ -156,8 +157,6 @@ public:
inline void setObjType(CCObjectType type) {
m_eObjType = type;
}
//i have no idea if vtable function order matters so
)
friend class CCAutoreleasePool;

View file

@ -90,6 +90,22 @@ namespace geode {
this->enable();
}
EventListener(EventListener&& other)
: m_callback(std::move(other.m_callback)),
m_filter(std::move(other.m_filter))
{
other.disable();
this->enable();
}
EventListener(EventListener const& other)
: m_callback(other.m_callback),
m_filter(other.m_filter)
{
other.disable();
this->enable();
}
void bind(std::function<Callback> fn) {
m_callback = fn;
}

View file

@ -1,14 +1,20 @@
#pragma once
#include "Traits.hpp"
#include <cocos2d.h>
#include <Geode/loader/Loader.hpp>
#include <cocos2d.h>
#include <vector>
namespace cocos2d {
class CCNode;
}
namespace geode {
template <class, class>
class Modify;
}
namespace geode::modifier {
class FieldContainer {
private:
@ -41,37 +47,42 @@ namespace geode::modifier {
return node->getFieldContainer();
}
};
GEODE_DLL size_t getFieldIndexForClass(size_t hash);
template <class Parent, class Base>
class FieldIntermediate {
using Intermediate = Modify<Parent, Base>;
// Padding used for guaranteeing any member of parents
// will be in between sizeof(Intermediate) and sizeof(Parent)
uintptr_t m_padding;
public:
// the constructor that constructs the fields.
// we construct the Parent first,
static void fieldConstructor(void* offsetField) {
std::array<std::byte, sizeof(Parent)> parentContainer;
auto parent = new (parentContainer.data()) Parent();
parent->Base::~Base();
parent->Intermediate::~Intermediate();
std::memcpy(
offsetField, std::launder(&parentContainer[sizeof(Base)]),
sizeof(Parent) - sizeof(Base)
offsetField,
std::launder(&parentContainer[sizeof(Intermediate)]),
sizeof(Parent) - sizeof(Intermediate)
);
}
static void fieldDestructor(void* offsetField) {
std::array<std::byte, sizeof(Parent)> parentContainer;
auto parent = new (parentContainer.data()) Base();
auto parent = new (parentContainer.data()) Intermediate();
std::memcpy(
std::launder(&parentContainer[sizeof(Base)]), offsetField,
sizeof(Parent) - sizeof(Base)
std::launder(&parentContainer[sizeof(Intermediate)]),
offsetField,
sizeof(Parent) - sizeof(Intermediate)
);
static_cast<Parent*>(parent)->Parent::~Parent();
@ -80,23 +91,31 @@ namespace geode::modifier {
template <class = std::enable_if_t<true>>
Parent* operator->() {
// get the this pointer of the base
auto node =
reinterpret_cast<Parent*>(reinterpret_cast<std::byte*>(this) - sizeof(Base));
// field intermediate is the first member of Modify
// meaning we canget the base from ourself
auto node = reinterpret_cast<Parent*>(reinterpret_cast<std::byte*>(this) - sizeof(Base));
static_assert(sizeof(Base) == offsetof(Parent, m_fields), "offsetof not correct");
// generating the container if it doesn't exist
auto container = FieldContainer::from(node);
// the index is global across all mods, so the
// function is defined in the loader source
static size_t index = getFieldIndexForClass(typeid(Base).hash_code());
// this pointer is offset
// the fields are actually offset from their original
// offset, this is done to save on allocation and space
auto offsetField = container->getField(index);
if (!offsetField) {
offsetField = container->setField(
index, sizeof(Parent) - sizeof(Base), &FieldIntermediate::fieldDestructor
index, sizeof(Parent) - sizeof(Intermediate), &FieldIntermediate::fieldDestructor
);
FieldIntermediate::fieldConstructor(offsetField);
}
return reinterpret_cast<Parent*>(
reinterpret_cast<std::byte*>(offsetField) - sizeof(Base)
reinterpret_cast<std::byte*>(offsetField) - sizeof(Intermediate)
);
}
};

View file

@ -82,6 +82,17 @@ namespace geode {
static inline auto s_applyRef = &Modify::s_apply;
public:
// abusing the internal stuff
// basically we dont want modify to invoke base ctors and dtors
// we already have utilities for these, which are ccdestructor
// and the monostate constructor
Modify() : Base(std::monostate(), sizeof(Base)) {}
~Modify() {
cocos2d::CCDestructor::lock(this) = true;
}
Modify(Modify const&) = delete;
Modify(Modify&&) = delete;
modifier::FieldIntermediate<Derived, Base> m_fields;
static void onModify(auto& self) {}

View file

@ -17,29 +17,19 @@ See [Documentation](https://geode-sdk.github.io/docs) for info about developing
Developed by
* [PoweredByPie](https://github.com/poweredbypie/)
* [Mat](https://github.com/matcool/)
* [HJfod](user:104257)
* [Camila314](https://github.com/camila314/)
* [Alk1m123](https://github.com/altalk23/)
* [FireCubez](https://github.com/FireCubez)
* [fig](https://github.com/FigmentBoy)
Using
* [Cocos2d-x](https://github.com/cocos2d/cocos2d-x/tree/cocos2d-x-2.2.3)
* [FMOD](https://www.fmod.com/)
* [fmt](https://fmt.dev/latest/index.html)
* [PEGTL](https://github.com/taocpp/PEGTL)
* [md4c](https://github.com/mity/md4c)
Special thanks to [RobTop Games](https://twitter.com/RobTopGames/) for making this amazing game and providing us and so many others with hours of entertainment <3

View file

@ -21,15 +21,16 @@ struct CustomLoadingLayer : Modify<CustomLoadingLayer, LoadingLayer> {
auto count = Loader::get()->getAllMods().size();
auto label =
CCLabelBMFont::create(fmt::format("Geode: Loaded {} mods", count).c_str(), "goldFont.fnt");
auto label = CCLabelBMFont::create(
fmt::format("Geode: Loaded {} mods", count).c_str(),
"goldFont.fnt"
);
label->setPosition(winSize.width / 2, 30.f);
label->setScale(.45f);
label->setID("geode-loaded-info");
this->addChild(label);
// for some reason storing the listener as a field caused the
// destructor for the field not to be run
// fields have unpredictable destructors
this->addChild(EventListenerNode<ResourceDownloadFilter>::create(
this, &CustomLoadingLayer::updateResourcesProgress
));
@ -62,10 +63,12 @@ struct CustomLoadingLayer : Modify<CustomLoadingLayer, LoadingLayer> {
[&](UpdateFailed const& error) {
LoaderImpl::get()->platformMessageBox(
"Error updating resources",
"Unable to update Geode resources: " +
error + ".\n"
"You will have to install resources manually by downloading resources.zip "
"from the latest release on GitHub: "
"https://github.com/geode-sdk/geode/releases/latest.\n"
"The game will be loaded as normal, but please be aware "
"that it may very likely crash."
"that it is very likely to crash. "
);
this->setUpdateText("Resource Download Failed");
m_fields->m_updatingResources = false;

View file

@ -0,0 +1,69 @@
#include <Geode/modify/EditLevelLayer.hpp>
#include <Geode/Bindings.hpp>
#include <Geode/utils/cocos.hpp>
#include "AddIDs.hpp"
USE_GEODE_NAMESPACE();
$register_ids(EditLevelLayer) {
setIDs(this, 0,
"background",
"bottom-left-art",
"bottom-right-art",
"level-name-background",
"level-name-input",
"description-background",
"description-input",
"description-text-area",
"level-action-menu",
"level-length",
"level-song",
"level-verified",
"version-label",
"level-id-label",
"right-side-menu",
"back-button-menu",
"info-button-menu"
);
if (auto menu = this->getChildByID("level-action-menu")) {
setIDs(menu, 0,
"edit-button",
"play-button",
"share-button"
);
}
if (auto menu = this->getChildByID("right-side-menu")) {
setIDs(menu, 0,
"delete-button",
"help-button",
"duplicate-button",
"move-to-top-button",
"folder-button"
);
detachAndCreateMenu(menu,
"folder-menu",
ColumnLayout::create(),
menu->getChildByID("folder-button")
);
}
if (auto menu = this->getChildByID("back-button-menu"))
setIDSafe(menu, 0, "back-button");
if (auto menu = this->getChildByID("info-button-menu"))
setIDSafe(menu, 0, "info-button");
}
class $modify(EditLevelLayer) {
bool init(GJGameLevel* l) {
if (!EditLevelLayer::init(l))
return false;
NodeIDs::get()->provide(this);
return true;
}
};

View file

@ -1,4 +1,4 @@
#include <Geode/Modify.hpp>
#include <Geode/modify/EditorUI.hpp>
#include <Geode/Bindings.hpp>
#include <Geode/utils/cocos.hpp>
#include "AddIDs.hpp"

View file

@ -1,4 +1,4 @@
#include <Geode/Modify.hpp>
#include <Geode/modify/GJGarageLayer.hpp>
#include <Geode/Bindings.hpp>
#include <Geode/utils/cocos.hpp>
#include "AddIDs.hpp"

View file

@ -6,71 +6,75 @@
USE_GEODE_NAMESPACE();
$register_ids(LevelSettingsLayer) {
bool startPos = m_mainLayer->getChildrenCount() < 10;
if (startPos) {
setIDSafe(m_mainLayer, 0, "back-button");
}
if (auto menu = getChildOfType<CCMenu>(m_mainLayer, 0)) {
menu->setID("song-select-menu");
setIDs(menu, 0,
"bg-color-button",
"g-color-button",
"g2-color-button",
"line-color-button",
"obj-color-button",
"more-color-button",
"3dl-color-button",
"bg-quick-edit-button",
"g-quick-edit-button",
"g2-quick-edit-button",
"line-quick-edit-button",
"cube-button",
"ship-button",
"ball-button",
"ufo-button",
"wave-button",
"robot-button",
"spider-button",
"background-select-button",
"ground-select-button",
"mini-toggle",
"dual-toggle",
"font-button",
"ok-button",
"2-player-toggle",
"2-player-help-button",
"prev-song-button",
"next-song-button",
"normal-song-button",
"custom-song-button",
"select-custom-song-button",
"new-song-button",
"half-speed-button",
"normal-speed-button",
"2x-speed-button",
"3x-speed-button",
"4x-speed-button"
);
detachAndCreateMenu(
this,
"color-button-menu",
RowLayout::create(),
menu->getChildByID("bg-color-button"),
menu->getChildByID("g-color-button"),
menu->getChildByID("g2-color-button"),
menu->getChildByID("line-color-button"),
menu->getChildByID("obj-color-button"),
menu->getChildByID("3dl-color-button"),
menu->getChildByID("more-color-button")
);
detachAndCreateMenu(
this,
"color-quick-edit-menu",
RowLayout::create(),
menu->getChildByID("bg-quick-edit-button"),
menu->getChildByID("g-quick-edit-button"),
menu->getChildByID("g2-quick-edit-button"),
menu->getChildByID("line-quick-edit-button")
);
if (startPos) {
setIDs(menu, 0,
"cube-button",
"ship-button",
"ball-button",
"ufo-button",
"wave-button",
"robot-button",
"spider-button",
"mini-toggle",
"dual-toggle",
"ok-button",
"flip-gravity-toggle",
"half-speed-button",
"normal-speed-button",
"2x-speed-button",
"3x-speed-button",
"4x-speed-button"
);
} else {
setIDs(menu, 0,
"bg-color-button",
"g-color-button",
"g2-color-button",
"line-color-button",
"obj-color-button",
"more-color-button",
"3dl-color-button",
"bg-quick-edit-button",
"g-quick-edit-button",
"g2-quick-edit-button",
"line-quick-edit-button",
"cube-button",
"ship-button",
"ball-button",
"ufo-button",
"wave-button",
"robot-button",
"spider-button",
"background-select-button",
"ground-select-button",
"mini-toggle",
"dual-toggle",
"font-button",
"ok-button",
"2-player-toggle",
"2-player-help-button",
"prev-song-button",
"next-song-button",
"normal-song-button",
"custom-song-button",
"select-custom-song-button",
"new-song-button",
"half-speed-button",
"normal-speed-button",
"2x-speed-button",
"3x-speed-button",
"4x-speed-button"
);
}
detachAndCreateMenu(
this,
@ -85,14 +89,6 @@ $register_ids(LevelSettingsLayer) {
menu->getChildByID("spider-button")
);
detachAndCreateMenu(
this,
"scenery-selection-menu",
ColumnLayout::create(),
menu->getChildByID("background-select-button"),
menu->getChildByID("ground-select-button")
);
detachAndCreateMenu(
this,
"right-toggle-menu",
@ -101,21 +97,6 @@ $register_ids(LevelSettingsLayer) {
menu->getChildByID("dual-toggle")
);
detachAndCreateMenu(
this,
"font-button-menu",
RowLayout::create()->setAlignment(Alignment::End),
menu->getChildByID("font-button")
);
detachAndCreateMenu(
this,
"2-player-menu",
ColumnLayout::create(),
menu->getChildByID("2-player-help-button"),
menu->getChildByID("2-player-toggle")
);
detachAndCreateMenu(
this,
"speed-selection-menu",
@ -126,6 +107,61 @@ $register_ids(LevelSettingsLayer) {
menu->getChildByID("3x-speed-button"),
menu->getChildByID("4x-speed-button")
);
if (startPos) {
detachAndCreateMenu(
this,
"flip-gravity-menu",
ColumnLayout::create(),
menu->getChildByID("flip-gravity-toggle")
);
} else {
detachAndCreateMenu(
this,
"color-button-menu",
RowLayout::create(),
menu->getChildByID("bg-color-button"),
menu->getChildByID("g-color-button"),
menu->getChildByID("g2-color-button"),
menu->getChildByID("line-color-button"),
menu->getChildByID("obj-color-button"),
menu->getChildByID("3dl-color-button"),
menu->getChildByID("more-color-button")
);
detachAndCreateMenu(
this,
"color-quick-edit-menu",
RowLayout::create(),
menu->getChildByID("bg-quick-edit-button"),
menu->getChildByID("g-quick-edit-button"),
menu->getChildByID("g2-quick-edit-button"),
menu->getChildByID("line-quick-edit-button")
);
detachAndCreateMenu(
this,
"scenery-selection-menu",
ColumnLayout::create(),
menu->getChildByID("background-select-button"),
menu->getChildByID("ground-select-button")
);
detachAndCreateMenu(
this,
"2-player-menu",
ColumnLayout::create(),
menu->getChildByID("2-player-help-button"),
menu->getChildByID("2-player-toggle")
);
detachAndCreateMenu(
this,
"font-button-menu",
RowLayout::create()->setAlignment(Alignment::End),
menu->getChildByID("font-button")
);
}
}
setIDs(m_mainLayer, 2,
@ -156,7 +192,7 @@ class $modify(LevelSettingsLayer) {
if (!LevelSettingsLayer::init(levelSettings, editor))
return false;
NodeIDs::get()->provide(this);
//NodeIDs::get()->provide(this);
return true;
}

View file

@ -0,0 +1,78 @@
#include <Geode/modify/PauseLayer.hpp>
#include <Geode/Bindings.hpp>
#include <Geode/utils/cocos.hpp>
#include "AddIDs.hpp"
USE_GEODE_NAMESPACE();
$register_ids(PauseLayer) {
setIDs(this, 0,
"background",
"level-name",
"normal-progress-bar",
"practice-progress-bar",
"normal-progress-label",
"practice-progress-label",
"normal-mode-label",
"practice-mode-label",
"center-button-menu",
"auto-retry-label",
"auto-checkpoints-label",
"show-progress-bar-label"
);
if (auto menu = this->getChildByID("center-button-menu")) {
int start_idx = 0;
if (menu->getChildrenCount() == 5) {
setIDSafe(menu, 0, "edit-button");
start_idx = 1;
}
setIDs(menu, start_idx,
"practice-button",
"play-button",
"exit-button"
);
if (menu->getChildrenCount() == 4)
setIDSafe(menu, start_idx + 3, "retry-button");
}
// Record toggle on mobile
if (auto label = typeinfo_cast<CCLabelBMFont*>(getChild(this, 12))) {
setIDSafe(this, 12, "record-label");
}
if (auto menu = getChildOfType<CCMenu>(this, 1)) {
menu->setID("toggle-menu");
setIDs(menu, 0,
"auto-retry-toggle",
"auto-checkpoints-toggle",
"show-progress-bar-toggle"
);
if (menu->getChildrenCount() == 4)
setIDSafe(menu, 3, "record-toggle");
}
setIDs(this, this->getChildrenCount() - 4,
"music-slider",
"sfx-slider",
"music-label",
"sfx-label"
);
}
class $modify(PauseLayer) {
void customSetup() {
PauseLayer::customSetup();
NodeIDs::get()->provide(this);
}
};

View file

@ -1,4 +1,4 @@
#include <Geode/Modify.hpp>
#include <Geode/modify/UILayer.hpp>
#include <Geode/Bindings.hpp>
#include <Geode/utils/cocos.hpp>
#include "AddIDs.hpp"

View file

@ -1,4 +1,5 @@
#include <Geode/binding/ProfilePage.hpp>
#include <Geode/binding/CCContentLayer.hpp>
#include <Geode/loader/Mod.hpp>
#include <Geode/ui/MDTextArea.hpp>
#include <Geode/utils/casts.hpp>
@ -446,6 +447,7 @@ struct MDParser {
case MD_BLOCKTYPE::MD_BLOCK_UL:
{
renderer->popIndent();
renderer->breakLine();
}
break;
@ -488,6 +490,7 @@ struct MDParser {
case MD_BLOCKTYPE::MD_BLOCK_LI:
{
renderer->breakLine();
}
break;

View file

@ -228,11 +228,17 @@ SentAsyncWebRequest::Impl::Impl(SentAsyncWebRequest* self, AsyncWebRequest const
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, utils::fetch::writeBytes);
}
curl_easy_setopt(curl, CURLOPT_URL, m_url.c_str());
// No need to verify SSL, we trust our domains :-)
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
// Github User Agent
curl_easy_setopt(curl, CURLOPT_USERAGENT, "github_api/1.0");
// Track progress
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
// Follow redirects
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
// Fail if response code is 4XX or 5XX
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
curl_slist* headers = nullptr;
for (auto& header : m_httpHeaders) {
@ -272,6 +278,7 @@ SentAsyncWebRequest::Impl::Impl(SentAsyncWebRequest* self, AsyncWebRequest const
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &data);
auto res = curl_easy_perform(curl);
if (res != CURLE_OK) {
curl_easy_cleanup(curl);
return this->error("Fetch failed: " + std::string(curl_easy_strerror(res)));
}
curl_easy_cleanup(curl);
@ -344,14 +351,16 @@ bool SentAsyncWebRequest::Impl::finished() const {
void SentAsyncWebRequest::Impl::error(std::string const& error) {
auto lock = std::unique_lock(m_statusMutex);
m_statusCV.wait(lock, [this]() {
return bool(m_paused);
return !m_paused;
});
Loader::get()->queueInGDThread([this, error]() {
std::lock_guard _(m_mutex);
for (auto& expect : m_expects) {
expect(error);
{
std::lock_guard _(m_mutex);
for (auto& expect : m_expects) {
expect(error);
}
}
std::lock_guard __(RUNNING_REQUESTS_MUTEX);
std::lock_guard _(RUNNING_REQUESTS_MUTEX);
RUNNING_REQUESTS.erase(m_id);
});
}