This commit is contained in:
altalk23 2022-06-02 11:40:08 +03:00
commit 7ccce257e2
9 changed files with 255 additions and 263 deletions

View file

@ -725,6 +725,7 @@ class cocos2d::CCSpriteBatchNode {
class cocos2d::CCSpriteFrame {
static auto createWithTexture(cocos2d::CCTexture2D*, cocos2d::CCRect const&, bool, cocos2d::CCPoint const&, cocos2d::CCSize const&) = mac 0x1ac7f0;
static auto createWithTexture(cocos2d::CCTexture2D*, cocos2d::CCRect const&) = mac 0x1ac5c0;
auto getTexture() = mac 0x1ad250;
}
class cocos2d::CCSpriteFrameCache {
@ -788,6 +789,8 @@ class cocos2d::CCTextFieldTTF {
class cocos2d::CCTextureCache {
auto addImage(char const*, bool) = mac 0x358120, ios 0xa8388;
auto textureForKey(char const*) = mac 0x359050;
static cocos2d::CCTextureCache* sharedTextureCache() = mac 0x356e00, ios 0xa81ec;
}

View file

@ -1525,7 +1525,7 @@ class GJBaseGameLayer : cocos2d::CCLayer, TriggerEffectDelegate {
void objectIntersectsCircle(GameObject*, GameObject*) = mac 0xb66e0, win 0x0, ios 0x0;
void objectTriggered(EffectGameObject*) = mac 0xb71b0, win 0x0, ios 0x0;
void optimizeMoveGroups() = mac 0xb96c0, win 0x0, ios 0x0;
void parentForZLayer(int, bool, int) = mac 0xb55d0, win 0x0, ios 0x0;
cocos2d::CCNode* parentForZLayer(int, bool, int) = mac 0xb55d0, win 0x0, ios 0x0;
void playerTouchedRing(PlayerObject*, GameObject*) = mac 0xb69e0, win 0x0, ios 0x0;
void processColorObject(EffectGameObject*, int, cocos2d::CCDictionary*, float, GJEffectManager*) = mac 0xb5a90, win 0x0, ios 0x0;
void processFollowActions() = mac 0xb8fd0, win 0x0, ios 0x0;
@ -1662,8 +1662,8 @@ class GJBaseGameLayer : cocos2d::CCLayer, TriggerEffectDelegate {
int m_unk2AC;
bool m_activeDualTouch;
int m_attemptClickCount;
int m_currentSection;
int m_oldSection;
int m_lastVisibleSection;
int m_firstVisibleSection;
bool m_objectsAreDisabled;
bool m_blending;
PAD = mac 0x16, win 0x8, android 0x0;
@ -2846,7 +2846,7 @@ class GameObject : CCSpritePlus {
virtual cocos2d::CCRect* getObjectRect(float, float) = mac 0x3352d0, win 0xe4a70, ios 0x0;
virtual cocos2d::CCRect* getObjectRect2(float, float) = mac 0x3354e0, win 0xe4b90, ios 0x0;
virtual cocos2d::CCRect* getObjectTextureRect() = mac 0x3355b0, win 0xe4c40, ios 0x0;
virtual void getRealPosition() = mac 0x335750, win 0xe4d90, ios 0x0;
virtual cocos2d::CCPoint getRealPosition() = mac 0x335750, win 0xe4d90, ios 0x0;
virtual void setStartPos(cocos2d::CCPoint) = mac 0x2fa520, win 0xd1390, ios 0x0;
virtual void updateStartValues() = mac 0x2fa800, win 0xd1610, ios 0x0;
virtual void customObjectSetup() = mac 0xdc1a0, win 0x0, ios 0x0;
@ -2874,10 +2874,11 @@ class GameObject : CCSpritePlus {
virtual void setOrientedRectDirty(bool) = mac 0xdc200, win 0x0, ios 0x0;
virtual GameObjectType getType() const = mac 0xdc210, win 0x989e0, ios 0x0;
virtual void setType(GameObjectType) = mac 0xdc220, win 0x989f0, ios 0x0;
virtual void getStartPos() const = mac 0xdc230, win 0x98a00, ios 0x0;
virtual cocos2d::CCPoint const& getStartPos() const = mac 0xdc230, win 0x98a00, ios 0x0;
void activatedByPlayer(GameObject*) = mac 0x342a20, win 0x0, ios 0x0;
void addColorSprite() = mac 0x2f7fe0, win 0x0, ios 0x0;
void addColorSpriteToParent(bool) = mac 0x2fb470, win 0x0, ios 0x0;
void addGlow() = mac 0x2f5c10, win 0x0, ios 0x0;
void addToTempOffset(float, float) = mac 0x335700, win 0x0, ios 0x0;
void calculateOrientedBox() = mac 0x342b20, win 0x0, ios 0x0;
void canChangeCustomColor() = mac 0x342db0, win 0x0, ios 0x0;
@ -3090,7 +3091,9 @@ class GameObject : CCSpritePlus {
int m_unk414;
PAD = mac 0xc, win 0xc, android 0x0;
cocos2d::CCPoint m_firstPosition;
PAD = mac 0x1c, win 0x1c, android 0x0;
PAD = mac 0x15, win 0x0, android 0x0;
bool m_isTriggerable;
PAD = mac 0x7, win 0x7, android 0x0;
bool m_highDetail;
ColorActionSprite* m_colorActionSpriteBase;
ColorActionSprite* m_colorActionSpriteDetail;
@ -3868,7 +3871,7 @@ class PlayLayer : GJBaseGameLayer, CCCircleWaveDelegate, DialogDelegate {
void colorObject(int, cocos2d::_ccColor3B) = mac 0x77810, win 0x0, ios 0x0;
void commitJumps() = mac 0x737e0, win 0x0, ios 0x0;
static PlayLayer* create(GJGameLevel*) = mac 0x6b590, win 0x1fb6d0, ios 0x0;
void createCheckpoint() = mac 0x7e470, win 0x20b050, ios 0x0;
CheckpointObject* createCheckpoint() = mac 0x7e470, win 0x20b050, ios 0x0;
void createObjectsFromSetup(gd::string) = mac 0x6d130, win 0x0, ios 0x0;
void createParticle(int, char const*, int, cocos2d::tCCPositionType) = mac 0x76800, win 0x0, ios 0x0;
void currencyWillExit(CurrencyRewardLayer*) = mac 0x7e070, win 0x0, ios 0x0;
@ -4008,7 +4011,7 @@ class PlayLayer : GJBaseGameLayer, CCCircleWaveDelegate, DialogDelegate {
int m_dontSaveRand;
int m_dontSaveSeed;
int unknown4d8;
bool unknown4dc;
bool m_debugPauseOff;
bool m_shouldSmoothCamera;
float unused_4e0;
cocos2d::CCObject* unknown4e8;
@ -4017,7 +4020,7 @@ class PlayLayer : GJBaseGameLayer, CCCircleWaveDelegate, DialogDelegate {
float m_somegroup4f8;
float m_groundRestriction;
float m_ceilRestriction;
bool unknown504;
bool m_fullReset;
bool unknown505;
float unknown508;
float unknown50c;
@ -4026,7 +4029,7 @@ class PlayLayer : GJBaseGameLayer, CCCircleWaveDelegate, DialogDelegate {
float unknown518;
//PAD = mac 0x19, win 0x19, android 0x0;
StartPosObject* m_startPos;
CheckpointObject* unk330;
CheckpointObject* m_startPosCheckpoint;
EndPortalObject* m_endPortal;
cocos2d::CCArray* m_checkpoints;
cocos2d::CCArray* unk33C;
@ -4048,7 +4051,7 @@ class PlayLayer : GJBaseGameLayer, CCCircleWaveDelegate, DialogDelegate {
bool unk36A;
bool unk36B;
cocos2d::CCArray* m_screenRingObjects;
cocos2d::CCParticleSystemQuad* unk370;
cocos2d::CCParticleSystemQuad* m_particleSystem;
cocos2d::CCDictionary* m_pickedUpItems;
cocos2d::CCArray* m_circleWaves;
cocos2d::CCArray* unk37C;
@ -4065,7 +4068,7 @@ class PlayLayer : GJBaseGameLayer, CCCircleWaveDelegate, DialogDelegate {
bool unknown5e4;
int m_ballFrameSeed;
float unknown5ec;
float unknown5f0;
float m_lockGroundToCamera;
float unknown5f4;
float m_levelLength;
float m_realLevelLength;
@ -4115,7 +4118,7 @@ class PlayLayer : GJBaseGameLayer, CCCircleWaveDelegate, DialogDelegate {
float m_mirrorTransition;
UILayer* m_UILayer;
GJGameLevel* m_level;
cocos2d::CCPoint m_cameraPos;
cocos2d::CCPoint m_cameraPosition;
bool m_isTestMode;
bool m_isPracticeMode;
bool unk496;
@ -4154,8 +4157,8 @@ class PlayLayer : GJBaseGameLayer, CCCircleWaveDelegate, DialogDelegate {
bool m_hasGlitter;
bool m_isBgEffectOff;
bool unk52F;
GameObject* unk530;
bool unk534;
GameObject* m_antiCheatObject;
bool m_antiCheatPassed;
bool unk535;
bool m_disableGravityEffect;
}
@ -4195,7 +4198,7 @@ class PlayerObject : GameObject, AnimatedSpriteDelegate {
virtual void setFlipX(bool) = mac 0x22e720, win 0x1fa690, ios 0x0;
virtual void setFlipY(bool) = mac 0x22e7b0, win 0x1fa740, ios 0x0;
virtual void resetObject() = mac 0x223170, win 0x1eecd0, ios 0x0;
virtual void getRealPosition() = mac 0x22d5f0, win 0x1f7e20, ios 0x0;
virtual cocos2d::CCPoint getRealPosition() = mac 0x22d5f0, win 0x1f7e20, ios 0x0;
virtual void getOrientedBox() = mac 0x22dee0, win 0x1f95d0, ios 0x0;
virtual void animationFinished(char const*) = mac 0x22e9d0, win 0x0, ios 0x0;
void activateStreak() = mac 0x21aef0, win 0x1f9080, ios 0x0;

View file

@ -5,6 +5,6 @@
#include "syntax/Field.hpp"
#include "syntax/InternalMacros.hpp"
#include "loader/GeodeLoader.hpp"
#include "loader/API.hpp"
#include "loader/Dispatcher.hpp"
using namespace geode::modifier;

View file

@ -235,8 +235,8 @@ protected:
/** weak reference to the CCSpriteBatchNode that renders the CCSprite */
CC_PROPERTY(CCParticleBatchNode*, m_pBatchNode, BatchNode);
// index of system in batch node array
CC_SYNTHESIZE(unsigned int, m_uAtlasIndex, AtlasIndex);
// RobTop removed this
///CC_SYNTHESIZE(unsigned int, m_uAtlasIndex, AtlasIndex);
//true if scaled or rotated
bool m_bTransformSystemDirty;

View file

@ -1,3 +1,5 @@
#pragma once
#include "../codegen-base/Macros.hpp"
#include "../utils/include.hpp"
#include "Mod.hpp"
@ -6,65 +8,86 @@
#include <vector>
namespace geode {
class Dispatcher;
struct GEODE_DLL dispatch_handle {
void* handle;
class Dispatcher;
struct GEODE_DLL dispatch_handle {
void* handle;
dispatch_handle() = delete;
dispatch_handle(dispatch_handle&& d) : handle(d.handle) {}
dispatch_handle(dispatch_handle const& d) : handle(d.handle) {}
dispatch_handle() = delete;
dispatch_handle(dispatch_handle const& d) : handle(d.handle) {}
template <typename T>
std::function<T> get() {
*reinterpret_cast<std::function<T>*>(this->handle);
}
template <typename T>
std::function<T> into() {
*reinterpret_cast<std::function<T>*>(this->handle);
}
template <typename R, typename ...Args>
R call(Args... args) {
return this->get<std::function<R(Args...)>>()(args...);
}
private:
dispatch_handle(void* h) : handle(h) {}
friend class Dispatcher;
};
template <typename R, typename ...Args>
R call(Args... args) {
return this->into<std::function<R(Args...)>>()(args...);
}
class GEODE_DLL Dispatcher {
protected:
std::map<dispatch_handle, std::pair<std::string, Mod*>> m_dispatchMap;
std::map<std::string, std::vector<dispatch_handle>> m_selectorMap;
// 2 maps for lookup speed
bool operator<(dispatch_handle const& b) const {
return handle < b.handle;
}
std::vector<dispatch_handle> _getHandles(std::string const& a);
std::pair<string, Mod*> _getInfo(dispatch_handle u);
bool operator==(dispatch_handle const& b) const {
return handle == b.handle;
}
private:
dispatch_handle(void* h) : handle(h) {}
void _removeFunction(dispatch_handle u);
dispatch_handle _addFunction(Mod* m, std::string const& a);
template <typename T>
static dispatch_handle from(std::function<T> f) {
return dispatch_handle(reinterpret_cast<void*>(new std::function<T>(f)));
}
friend class Dispatcher;
};
std::vector<dispatch_handle> _allHandles();
class GEODE_DLL Dispatcher {
protected:
std::map<dispatch_handle, std::pair<std::string, Mod*>> m_dispatchMap;
std::map<std::string, std::vector<dispatch_handle>> m_selectorMap;
// 2 maps for lookup speed
std::vector<dispatch_handle> getFunctions_(std::string const& a);
void addFunction_(Mod* m, std::string const& a, dispatch_handle u);
std::vector<dispatch_handle> allFunctions_();
template <typename T>
std::function<T> _fromOpaque(void* f) {
*reinterpret_cast<std::function<T>*>(f);
}
Dispatcher() {}
template <typename T>
void* _toOpaque(std::function<T> f) {
return reinterpret_cast<void*>(new std::function<T>(f));
}
public:
static Dispatcher* get();
public:
static Dispatcher* get();
template <typename T>
std::vector<std::function<T>> getSelectors(std::string_view const& a) {
return geode::vector_utils::map(_getSelectors(a), [this](std::pair<dispatch_handle, void*> selector) {
return _fromOpaque<T>(selector.second);
});
}
template <typename T>
std::vector<std::function<T>> getFunctions(std::string const& a) {
return geode::vector_utils::map(getFunctions_(a), [this](dispatch_handle fn) {
return fn.into<T>();
});
}
};
template <typename T>
std::function<T> getFunction(std::string const& a) {
return getFunctions_(a).back().into<T>();
}
template <typename T>
dispatch_handle addFunction(std::string const& a, std::function<T> f) {
dispatch_handle hdl = dispatch_handle::from(f);
addFunction_(Mod::get(), a, hdl);
return hdl;
}
template <typename T>
std::vector<dispatch_handle> allFunctions() {
return geode::vector_utils::map(allFunctions_(), [this](dispatch_handle fn) {
return fn.into<T>();
});
}
void removeFunction(dispatch_handle u);
std::pair<std::string, Mod*> getFunctionInfo(dispatch_handle u);
};
}

View file

@ -1,148 +0,0 @@
#pragma once
#include <string>
#include <typeinfo>
#include <memory>
#include <exception>
#include <map>
#include <Macros.hpp>
#include <any>
#include <variant>
#ifndef GEODE_DLL
#define GEODE_DLL
#endif
namespace geode {
class EventCenter;
class Mod;
template <typename T = std::monostate>
struct EventInfo {
std::string selector;
inline EventInfo(std::string sel) : selector(sel) {}
inline EventInfo() {}
};
template <typename T = std::monostate>
struct ConstEventInfo {
char const* selector;
inline constexpr ConstEventInfo(char const* sel) : selector(sel) {}
inline constexpr ConstEventInfo() {}
inline operator EventInfo<T>() {
return EventInfo<T>(selector);
}
};
template <typename T = std::monostate>
class Event {
protected:
EventInfo<T> m_info;
T m_object;
Mod* m_sender;
public:
inline T const& object() const {
return m_object;
}
inline std::string const& selector() const { return m_info.selector; }
inline Mod* sender() const { return m_sender; }
inline Event(EventInfo<T> inf, T obj, Mod* sender) :
m_info(inf),
m_object(obj),
m_sender(sender) {}
inline Event(std::string sel, T obj, Mod* sender) : Event(EventInfo<T>(sel), obj, sender) {}
inline Event(std::string sel, Mod* sender) : Event(sel, T(), sender) {}
inline Event(EventInfo<T> inf, Mod* sender) : Event(inf, T(), sender) {}
// Event(std::string sel) : Event(sel, Interface::get()->mod()) {}
inline Event(Event&& a) : m_info(a.m_info), m_sender(a.m_sender), m_object(std::move(a.m_object)) {}
inline operator T() { return m_object; }
friend class EventCenter;
};
template <typename T = std::monostate>
struct Observer {
EventInfo<T> m_info;
Mod* m_mod;
std::function<void(Event<T> const&)> m_callback;
template <typename U = std::monostate>
inline Observer<U>* into() {
return reinterpret_cast<Observer<U>*>(this);
}
};
class GEODE_DLL EventCenter {
public:
std::map<Mod*, std::map<std::string, std::vector<Observer<std::monostate>*>>> m_observers;
static EventCenter* shared;
public:
EventCenter();
static EventCenter* get();
template <typename T>
void send(Event<T> n, Mod* m) {
for (auto& obs : m_observers[m][n.selector()]) {
obs->template into<T>()->m_callback(n);
}
}
template <typename T>
void broadcast(Event<T> n) {
for (auto& [k, v] : m_observers) {
for (auto& obs : v[n.selector()]) {
obs->template into<T>()->m_callback(n);
}
}
}
template <typename T = std::monostate>
Observer<std::monostate>* registerObserver(Mod* m, EventInfo<T> info, std::function<void(Event<T> const&)> cb) {
Observer<T>* ob = new Observer<T>;
ob->m_info = info;
ob->m_callback = cb;
ob->m_mod = m;
m_observers[m][info.selector].push_back(ob->into());
return ob->into();
}
template <typename T = std::monostate>
Observer<std::monostate>* registerObserver(Mod* m, std::string sel, std::function<void(Event<T> const&)> cb) {
return registerObserver(m, EventInfo<T>(sel), cb);
}
template <typename T = std::monostate>
inline Observer<std::monostate>* registerObserver(std::string sel, std::function<void(Event<T> const&)> cb);
template <typename T = std::monostate>
inline Observer<std::monostate>* registerObserver(EventInfo<T> info, std::function<void(Event<T> const&)> cb);
void unregisterObserver(Observer<std::monostate>* ob);
std::vector<Observer<std::monostate>*> getObservers(std::string selector, Mod* m);
};
}
#define _$observe3(sel, T, data, ctr) \
void $_observer##ctr(geode::Event<T> const&); \
static auto $_throw##ctr = (([](){ \
geode::Interface::get()->scheduleOnLoad(+[](Mod* m) { \
geode::EventCenter::get()->registerObserver<T>( \
m, sel, $_observer##ctr \
); \
}); \
})(), 0); \
void $_observer##ctr(geode::Event<T> const& data)
#define _$observe1(sel, ctr) _$observe3(sel, std::monostate, , ctr)
#define $observe(...) GEODE_INVOKE(GEODE_CONCAT(_$observe, GEODE_NUMBER_OF_ARGS(__VA_ARGS__)), __VA_ARGS__, __COUNTER__)

View file

@ -59,15 +59,9 @@ namespace geode {
using loadfn_t = void(*)(Mod*);
struct ScheduledExport {
std::string m_selector;
std::variant<unknownmemfn_t, unknownfn_t> m_func;
};
Mod* m_mod = nullptr;
std::vector<ScheduledHook> m_scheduledHooks;
std::vector<ScheduledLog> m_scheduledLogs;
std::vector<ScheduledExport> m_scheduledExports;
std::vector<loadfn_t> m_scheduledFunctions;
public:
@ -160,17 +154,6 @@ namespace geode {
inline Log Log::get() {
return Mod::get()->log();
}
template <typename T>
inline Observer<std::monostate>* EventCenter::registerObserver(std::string sel, std::function<void(Event<T> const&)> cb) {
return registerObserver(Mod::get(), EventInfo<T>(sel), cb);
}
template <typename T>
inline Observer<std::monostate>* EventCenter::registerObserver(EventInfo<T> info, std::function<void(Event<T> const&)> cb) {
return registerObserver(Mod::get(), info, cb);
}
}
inline const char* operator"" _spr(const char* str, size_t) {

View file

@ -3,7 +3,6 @@
#include <Macros.hpp>
#include "Types.hpp"
#include "Hook.hpp"
#include "Event.hpp"
#include "../utils/types.hpp"
#include "../utils/Result.hpp"
#include "../utils/VersionInfo.hpp"
@ -335,37 +334,6 @@ namespace geode {
Severity severity
);
/**
* Exports an internal function. You can use this
* for mod interoperability.
* @param selector mod-specific string identifier
* for your function
* @param ptr pointer to your exported function
*/
template <typename T>
void exportAPIFunction(std::string const& selector, T ptr) {
EventCenter::get()->registerObserver<T*>(this, selector, [ptr](Event<T*> const& n) {
//*reinterpret_cast<T*>(n.object<void*>()) = ptr;
*n.object() = ptr;
});
}
/**
* Imports an internal function. You can use this
* for mod interoperability.
* @param selector Mod-specific string identifier
* for your function
* @param source Mod that the API function originates
* from
* @returns Pointer to the external function
*/
template <typename T>
T importAPIFunction(std::string const& selector, Mod* source) {
T out;
EventCenter::get()->send(Event(selector, &out, nullptr), source);
return out;
}
/**
* Get all hooks owned by this Mod
* @returns Vector of hooks

View file

@ -81,4 +81,164 @@ namespace geode::cocos {
* }
*/
GEODE_DLL bool fileExistsInSearchPaths(const char* filename);
template <typename T>
struct GEODE_DLL CCArrayIterator {
public:
CCArrayIterator(T* p) : m_ptr(p) {}
T* m_ptr;
T& operator*() { return *m_ptr; }
T* operator->() { return m_ptr; }
auto& operator++() {
++m_ptr;
return *this;
}
friend bool operator== (const CCArrayIterator<T>& a, const CCArrayIterator<T>& b) { return a.m_ptr == b.m_ptr; };
friend bool operator!= (const CCArrayIterator<T>& a, const CCArrayIterator<T>& b) { return a.m_ptr != b.m_ptr; };
};
template <typename T>
class CCArrayExt {
protected:
cocos2d::CCArray* m_arr;
public:
CCArrayExt() : m_arr(cocos2d::CCArray::create()) {
m_arr->retain();
}
CCArrayExt(cocos2d::CCArray* arr) : m_arr(arr) {
m_arr->retain();
}
CCArrayExt(CCArrayExt const& a) : m_arr(a.m_arr) {
m_arr->retain();
}
CCArrayExt(CCArrayExt&& a) : m_arr(a.m_arr) {
a.m_arr = nullptr;
}
~CCArrayExt() {
if (m_arr)
m_arr->release();
}
auto begin() {
return CCArrayIterator<T*>(reinterpret_cast<T*>(m_arr->data->arr));
}
auto end() {
return CCArrayIterator<T*>(reinterpret_cast<T*>(m_arr->data->arr) + m_arr->count());
}
auto size() const {
return m_arr->count();
}
T operator[](size_t index) {
return reinterpret_cast<T>(m_arr->objectAtIndex(index));
}
void push_back(T item) {
m_arr->addObject(item);
}
T pop_back() {
T ret = m_arr->lastObject();
m_arr->removeLastObject();
return ret;
}
cocos2d::CCArray* inner() {
return m_arr;
}
};
template <typename K, typename T>
struct CCDictIterator {
public:
CCDictIterator(cocos2d::CCDictElement* p) : m_ptr(p) {}
cocos2d::CCDictElement* m_ptr;
std::pair<K, T> operator*() {
if constexpr (std::is_same<K, std::string>::value) {
return { m_ptr->getStrKey(), reinterpret_cast<T>(m_ptr->getObject()) };
} else {
return { m_ptr->getIntKey(), reinterpret_cast<T>(m_ptr->getObject()) };
}
}
auto& operator++() {
m_ptr = reinterpret_cast<decltype(m_ptr)>(m_ptr->hh.next);
return *this;
}
friend bool operator== (const CCDictIterator<K, T>& a, const CCDictIterator<K, T>& b) { return a.m_ptr == b.m_ptr; };
friend bool operator!= (const CCDictIterator<K, T>& a, const CCDictIterator<K, T>& b) { return a.m_ptr != b.m_ptr; };
bool operator!= (int b) { return m_ptr != nullptr; }
};
template <typename K, typename T>
struct CCDictEntry {
K m_key;
cocos2d::CCDictionary* m_dict;
CCDictEntry(K key, cocos2d::CCDictionary* dict) : m_key(key), m_dict(dict) {}
T operator->() {
return reinterpret_cast<T>(m_dict->objectForKey(m_key));
}
operator T() {
return reinterpret_cast<T>(m_dict->objectForKey(m_key));
}
CCDictEntry& operator=(T f) {
m_dict->setObject(f, m_key);
return *this;
}
};
template <typename K, typename T>
struct CCDictionaryExt {
protected:
cocos2d::CCDictionary* m_dict;
public:
CCDictionaryExt() : m_dict(cocos2d::CCDictionary::create()) {
m_dict->retain();
}
CCDictionaryExt(cocos2d::CCDictionary* dict) : m_dict(dict) {
m_dict->retain();
}
CCDictionaryExt(CCDictionaryExt const& d) : m_dict(d.m_dict) {
m_dict->retain();
}
CCDictionaryExt(CCDictionaryExt&& d) : m_dict(d.m_dict) {
d.m_dict = nullptr;
}
~CCDictionaryExt() {
if (m_dict)
m_dict->release();
}
CCDictionaryExt const& operator=(cocos2d::CCDictionary* d) {
m_dict->release();
m_dict = d;
m_dict->retain();
}
auto begin() {
return CCDictIterator<K, T*>(m_dict->m_pElements);
}
// do not use this
auto end() {
return nullptr;
}
size_t size() { return m_dict->count(); }
auto operator[](K key) {
auto ret = reinterpret_cast<T*>(m_dict->objectForKey(key));
if (!ret)
m_dict->setObject(cocos2d::CCNode::create(), key);
return CCDictEntry<K, T*>(key, m_dict);
}
size_t count(K key) {
return m_dict->allKeys(key)->count();
}
};
}