diff --git a/src/engine/fox_demo.c b/src/engine/fox_demo.c index 41385906..7335c5ba 100644 --- a/src/engine/fox_demo.c +++ b/src/engine/fox_demo.c @@ -18,6 +18,7 @@ #include "assets/ast_title.h" #include "assets/ast_katina.h" #include "assets/ast_allies.h" +#include "port/hooks/Events.h" void func_demo_80048AC0(TeamId teamId) { s32 teamShield; @@ -1567,7 +1568,9 @@ void Cutscene_DropVsItem(Player* player, ObjectId itemId, Item* item) { item->obj.pos.y = player->pos.y; item->obj.pos.z = player->trueZpos; item->obj.id = itemId; - Object_SetInfo(&item->info, item->obj.id); + CALL_CANCELLABLE_EVENT(ItemDropEvent, item){ + Object_SetInfo(&item->info, item->obj.id); + } } void Cutscene_KillPlayer(Player* player) { diff --git a/src/engine/fox_enmy.c b/src/engine/fox_enmy.c index 3f4a7c55..0d184d14 100644 --- a/src/engine/fox_enmy.c +++ b/src/engine/fox_enmy.c @@ -18,6 +18,7 @@ #include "assets/ast_training.h" #include "assets/ast_versus.h" #include "assets/ast_zoness.h" +#include "port/hooks/Events.h" s32 D_enmy_Timer_80161670[4]; s32 gLastPathChange; @@ -276,7 +277,9 @@ void Item_Load(Item* this, ObjectInit* objInit) { this->obj.rot.z = objInit->rot.z; this->obj.id = objInit->id; this->width = 1.0f; - Object_SetInfo(&this->info, this->obj.id); + CALL_CANCELLABLE_EVENT(ItemDropEvent, this){ + Object_SetInfo(&this->info, this->obj.id); + } } void Effect_Effect346_Setup(Effect346* this, f32 xPos, f32 yPos, f32 zPos) { @@ -1042,7 +1045,9 @@ void Scenery_CoStoneArch_Init(CoStoneArch* this, f32* hitboxData) { item->obj.pos.y = this->obj.pos.y; item->obj.pos.z = this->obj.pos.z; item->obj.rot.y = this->obj.rot.y; - Object_SetInfo(&item->info, item->obj.id); + CALL_CANCELLABLE_EVENT(ItemDropEvent, item){ + Object_SetInfo(&item->info, item->obj.id); + } item->info.hitbox = LOAD_ASSET(hitboxData); break; } @@ -1696,7 +1701,9 @@ void func_enmy_800660F0(Actor* this) { item->obj.pos.z = this->obj.pos.z; item->timer_4A = 8; - Object_SetInfo(&item->info, item->obj.id); + CALL_CANCELLABLE_EVENT(ItemDropEvent, item){ + Object_SetInfo(&item->info, item->obj.id); + } if ((item->obj.id == OBJ_ITEM_SILVER_RING) || (item->obj.id == OBJ_ITEM_BOMB) || (item->obj.id == OBJ_ITEM_LASERS)) { diff --git a/src/engine/fox_play.c b/src/engine/fox_play.c index a0f50a41..91d91fdc 100644 --- a/src/engine/fox_play.c +++ b/src/engine/fox_play.c @@ -21,6 +21,7 @@ #include "assets/ast_versus.h" #include "assets/ast_area_6.h" #include "assets/ast_zoness.h" +#include "port/hooks/Events.h" extern float gCurrentScreenWidth; extern float gCurrentScreenHeight; @@ -7011,7 +7012,9 @@ void Play_SpawnVsItem(ObjectId objId, Item* item) { item->obj.pos.y = gScenery360[spawnIndex].obj.pos.y; item->obj.pos.z = gScenery360[spawnIndex].obj.pos.z; item->obj.id = objId; - Object_SetInfo(&item->info, item->obj.id); + CALL_CANCELLABLE_EVENT(ItemDropEvent, item){ + Object_SetInfo(&item->info, item->obj.id); + } } } } diff --git a/src/overlays/ovl_i1/fox_co.c b/src/overlays/ovl_i1/fox_co.c index 07ce439e..c0a0197a 100644 --- a/src/overlays/ovl_i1/fox_co.c +++ b/src/overlays/ovl_i1/fox_co.c @@ -8,6 +8,7 @@ #include "assets/ast_arwing.h" #include "assets/ast_corneria.h" #include "fox_co.h" +#include "port/hooks/Events.h" u8 sFightCarrier; f32 sCoGrangaWork[68]; @@ -89,7 +90,9 @@ void Corneria_Granga_SpawnItem(Boss* this, f32 x, f32 y, f32 z, ObjectId itemId) gItems[i].obj.pos.x = x; gItems[i].obj.pos.y = y; gItems[i].obj.pos.z = z; - Object_SetInfo(&gItems[i].info, gItems[i].obj.id); + CALL_CANCELLABLE_EVENT(ItemDropEvent, &gItems[i]){ + Object_SetInfo(&gItems[i].info, gItems[i].obj.id); + } break; } } @@ -593,7 +596,9 @@ void Corneria_CoGranga_1UpCheck(CoGranga* this) { gItems[i].obj.pos.z = gPlayer[0].trueZpos + dest.z; gItems[i].timer_4A = 8; - Object_SetInfo(&gItems[i].info, gItems[i].obj.id); + CALL_CANCELLABLE_EVENT(ItemDropEvent, &gItems[i]){ + Object_SetInfo(&gItems[i].info, gItems[i].obj.id); + } Effect_Effect384_Spawn(gItems[i].obj.pos.x, gItems[i].obj.pos.y, gItems[i].obj.pos.z, 5.0f, 0); break; } diff --git a/src/overlays/ovl_i3/fox_aq.c b/src/overlays/ovl_i3/fox_aq.c index b5934d5c..ddda6488 100644 --- a/src/overlays/ovl_i3/fox_aq.c +++ b/src/overlays/ovl_i3/fox_aq.c @@ -7,6 +7,7 @@ #include "global.h" #include "assets/ast_blue_marine.h" #include "assets/ast_aquas.h" +#include "port/hooks/Events.h" // #include "prevent_bss_reordering2.h" const char D_i3_801C1A30[] = "プレイヤーのすべてをクリア \n"; // Clear of all players @@ -380,7 +381,9 @@ void Aquas_SpawnItem(Vec3f* pos, ObjectId objId) { item->obj.pos.y = pos->y; item->obj.pos.z = pos->z; item->timer_4A = 2; - Object_SetInfo(&item->info, item->obj.id); + CALL_CANCELLABLE_EVENT(ItemDropEvent, item){ + Object_SetInfo(&item->info, item->obj.id); + } break; } } diff --git a/src/overlays/ovl_i6/fox_andross.c b/src/overlays/ovl_i6/fox_andross.c index 5cd2bbea..d9e5cc0f 100644 --- a/src/overlays/ovl_i6/fox_andross.c +++ b/src/overlays/ovl_i6/fox_andross.c @@ -7,6 +7,7 @@ #include "assets/ast_bg_planet.h" #include "prevent_bss_reordering.h" #include "prevent_bss_reordering2.h" +#include "port/hooks/Events.h" f32 D_i6_801A7F5C; f32 D_i6_801A7F64; @@ -154,7 +155,9 @@ void Andross_801878A8() { item->obj.pos.z = -gLevelObjects[i].zPos1; item->obj.pos.z += gLevelObjects[i].zPos2; item->obj.pos.y = gLevelObjects[i].yPos; - Object_SetInfo(&item->info, item->obj.id); + CALL_CANCELLABLE_EVENT(ItemDropEvent, item){ + Object_SetInfo(&item->info, item->obj.id); + } item++; } } @@ -235,7 +238,9 @@ void Andross_80187C5C(void) { item->obj.pos.z = -gLevelObjects[i].zPos1; item->obj.pos.z += gLevelObjects[i].zPos2; item->obj.pos.y = gLevelObjects[i].yPos; - Object_SetInfo(&item->info, item->obj.id); + CALL_CANCELLABLE_EVENT(ItemDropEvent, item){ + Object_SetInfo(&item->info, item->obj.id); + } item++; } } @@ -1632,7 +1637,9 @@ void Andross_Effect396_Update(Effect396* this) { item->obj.pos.y = this->obj.pos.y; item->obj.pos.z = this->obj.pos.z; item->timer_4A = 8; - Object_SetInfo(&item->info, item->obj.id); + CALL_CANCELLABLE_EVENT(ItemDropEvent, item){ + Object_SetInfo(&item->info, item->obj.id); + } item->unk_50 = 90.0f; break; } diff --git a/src/port/hooks/Events.h b/src/port/hooks/Events.h index 9c56592c..d4d26279 100644 --- a/src/port/hooks/Events.h +++ b/src/port/hooks/Events.h @@ -1,3 +1,4 @@ #pragma once -#include "list/PlayerShotEvent.h" +#include "list/EngineEvent.h" +#include "list/ItemEvent.h" \ No newline at end of file diff --git a/src/port/hooks/impl/EventSystem.cpp b/src/port/hooks/impl/EventSystem.cpp index f2ce527c..71eaffb5 100644 --- a/src/port/hooks/impl/EventSystem.cpp +++ b/src/port/hooks/impl/EventSystem.cpp @@ -1,35 +1,42 @@ #include "EventSystem.h" #include +#include EventSystem* EventSystem::Instance = new EventSystem(); ListenerID EventSystem::RegisterListener(EventID id, EventCallback callback, EventPriority priority) { - if(std::find_if(this->mEventListeners[id].begin(), this->mEventListeners[id].end(), [callback](EventListener listener) { + auto& listeners = this->mEventListeners[(uint8_t)((id >> 16) & 0xFF)][(uint16_t)(id & 0xFFFF)]; + + if(std::find_if(listeners.begin(), listeners.end(), [callback](EventListener listener) { return listener.function == callback; - }) != this->mEventListeners[id].end()) { + }) != listeners.end()) { throw std::runtime_error("Listener already registered"); } - this->mEventListeners[id].push_back({ priority, callback }); + listeners.push_back({ priority, callback }); // Sort by priority - std::sort(this->mEventListeners[id].begin(), this->mEventListeners[id].end(), [](EventListener a, EventListener b) { + std::sort(listeners.begin(), listeners.end(), [](EventListener a, EventListener b) { return a.priority < b.priority; }); - return this->mEventListeners[id].size() - 1; + return listeners.size() - 1; } -void EventSystem::UnregisterListener(EventID ev, ListenerID id) { - this->mEventListeners[ev].erase(this->mEventListeners[ev].begin() + id); +void EventSystem::UnregisterListener(EventID id, ListenerID listenerId) { + auto& listeners = this->mEventListeners[(uint8_t)((id >> 16) & 0xFF)][(uint16_t)(id & 0xFFFF)]; + + listeners.erase(listeners.begin() + listenerId); } void EventSystem::CallEvent(EventID id, IEvent* event) { - if (this->mEventListeners[id].empty()) { + auto& listeners = this->mEventListeners[(uint8_t)((id >> 16) & 0xFF)][(uint16_t)(id & 0xFFFF)]; + + if (listeners.empty()) { return; } - for (auto& listener : this->mEventListeners[id]) { + for (auto& listener : listeners) { listener.function(event); } } diff --git a/src/port/hooks/impl/EventSystem.h b/src/port/hooks/impl/EventSystem.h index d7f47b73..17413408 100644 --- a/src/port/hooks/impl/EventSystem.h +++ b/src/port/hooks/impl/EventSystem.h @@ -5,6 +5,7 @@ #include typedef uint16_t EventID; +typedef uint16_t NamespaceID; typedef uint32_t ListenerID; typedef enum { @@ -29,13 +30,32 @@ typedef struct { EventCallback function; } EventListener; -// ID Type -// 000000000000000 0 -#define EVENT_ID(id, type) ((id << 1) | type) +// Namespace ID Type +// 00000000XXXXXXXX 000000000000000 0 +#define EVENT_ID(namespace_, id_, type_) ((((uint32_t)(namespace_) & 0xFFFF) << 16) | (((uint32_t)(id_) & 0x7FFF) << 1) | ((uint32_t)(type_) & 0x1)) + +#define INTERNAL_EVENT_ID(id, type) EVENT_ID(0, id, type) +#define DEFINE_EVENT(id, eventName, type, ...) \ + typedef struct { \ + IEvent event; \ + __VA_ARGS__ \ + } eventName; \ + \ + static uint32_t eventName##_ID = INTERNAL_EVENT_ID(id, type); + +#define CALL_EVENT(eventType, ...) \ + eventType eventType##_ = { {false}, __VA_ARGS__ }; \ + EventSystem_CallEvent(eventType##_ID, &eventType##_); + +#define CALL_CANCELLABLE_EVENT(eventType, ...) \ + eventType eventType##_ = { {false}, __VA_ARGS__ }; \ + EventSystem_CallEvent(eventType##_ID, &eventType##_); \ + if (!eventType##_.event.cancelled) #ifdef __cplusplus #include #include +#include class EventSystem { public: @@ -44,7 +64,7 @@ public: void UnregisterListener(EventID ev, ListenerID id); void CallEvent(EventID id, IEvent* event); private: - std::array, 0xFFFF> mEventListeners; + std::unordered_map>> mEventListeners; }; #else extern ListenerID EventSystem_RegisterListener(EventID id, EventCallback callback, EventPriority priority); diff --git a/src/port/hooks/list/EngineEvent.h b/src/port/hooks/list/EngineEvent.h index 87e883f8..6b3f8f8d 100644 --- a/src/port/hooks/list/EngineEvent.h +++ b/src/port/hooks/list/EngineEvent.h @@ -2,8 +2,8 @@ #include "port/hooks/impl/EventSystem.h" -#define DISPLAY_UPDATE_EVENT_PRE EVENT_ID(1, EVENT_TYPE_PRE) -#define DISPLAY_UPDATE_EVENT_POST EVENT_ID(1, EVENT_TYPE_POST) +#define DISPLAY_UPDATE_EVENT_PRE INTERNAL_EVENT_ID(1, EVENT_TYPE_PRE) +#define DISPLAY_UPDATE_EVENT_POST INTERNAL_EVENT_ID(1, EVENT_TYPE_POST) -#define GAME_UPDATE_EVENT_PRE EVENT_ID(2, EVENT_TYPE_PRE) -#define GAME_UPDATE_EVENT_POST EVENT_ID(2, EVENT_TYPE_POST) \ No newline at end of file +#define GAME_UPDATE_EVENT_PRE INTERNAL_EVENT_ID(2, EVENT_TYPE_PRE) +#define GAME_UPDATE_EVENT_POST INTERNAL_EVENT_ID(2, EVENT_TYPE_POST) \ No newline at end of file diff --git a/src/port/hooks/list/ItemEvent.h b/src/port/hooks/list/ItemEvent.h new file mode 100644 index 00000000..70e89a14 --- /dev/null +++ b/src/port/hooks/list/ItemEvent.h @@ -0,0 +1,9 @@ +#pragma once + +#include "gfx.h" +#include "sf64object.h" +#include "port/hooks/impl/EventSystem.h" + +DEFINE_EVENT(3, ItemDropEvent, EVENT_TYPE_PRE, + Item* item; +); \ No newline at end of file