Skip to content

Commit 568d80d

Browse files
committed
feat(eventbus): Add comprehensive event hooks for all game events
Add event hooks for: - AuctionEvent (sold, expired) in AuctionHouseMgr.cpp - SpellCastEvent in Spell.cpp (player-only, disabled by default) - TradeEvent in TradeHandler.cpp - MailEvent in Mail.cpp - GuildEvent (join/leave) in Guild.cpp - ZoneChangeEvent in Player.cpp - PartyChangeEvent in Group.cpp - ItemEquipEvent in Player.cpp - LevelUpEvent in Player.cpp - ChatEvent in ChatHandler.cpp - AchievementEvent in AchievementMgr.cpp - CombatEvent in Unit.cpp - EncounterEvent in InstanceScript.cpp - SpawnEvent in Creature.cpp All events include IsEnabled() checks via AraxiaEventBusConfig. Added eventbus_integration_test.py for testing.
1 parent c3f4608 commit 568d80d

File tree

18 files changed

+1661
-171
lines changed

18 files changed

+1661
-171
lines changed

AGENTS.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,69 @@ handler.ParseCommands(command);
4545
### Key Files with Important Comments:
4646
- `src/araxiaonline/mcp/ServerTools.cpp` - GM command implementation pattern
4747
- `src/araxiaonline/mcp/AraxiaMCPServer.cpp` - MCP server architecture
48+
- `src/araxiaonline/eventbus/AraxiaEvents.h` - Event interface and concrete event classes
49+
50+
---
51+
52+
## Araxia Event Bus
53+
54+
The Event Bus is a ZeroMQ-based real-time event system that publishes game events to external consumers.
55+
56+
- **Documentation**: `/opt/trinitycore/araxia-content-tools/docs/game_engine/araxia_event_bus.md`
57+
- **Source**: `src/araxiaonline/eventbus/`
58+
- **Port**: `tcp://*:5555` (configurable)
59+
60+
### Supported Events
61+
| Category | Events |
62+
|----------|--------|
63+
| Player | login, logout, death |
64+
| Quest | accept, complete, abandon |
65+
| Combat | enter, leave |
66+
| Loot | item |
67+
| Spawn | create, delete |
68+
| Encounter | start, wipe, end |
69+
70+
### Quick Test
71+
```bash
72+
cd /opt/trinitycore/TrinityCore/src/araxiaonline/tools
73+
source .venv/bin/activate
74+
python zmq_subscriber.py
75+
```
76+
77+
**Keep the wiki page updated** when adding new event types or changing the event bus architecture.
78+
79+
---
80+
81+
## AI Testing with Scarletseer
82+
83+
**Scarletseer** is a dedicated test character for AI assistants to use for automated testing via MCP.
84+
85+
- **Character**: Scarletseer (GUID 7, Level 80 Tauren Shaman)
86+
- **Location**: Pandaria (Map 870) - Halfhill Farm area
87+
- **Documentation**: See `/opt/trinitycore/araxia-content-tools/docs/game_engine/scarletseer.md`
88+
89+
### Quick Start
90+
```
91+
mcp_session_create(owner_name="Cascade")
92+
mcp_player_login(session_id=1, character_name="Scarletseer")
93+
mcp_player_status(session_id=1) # Verify login
94+
# ... run tests ...
95+
mcp_player_logout(session_id=1)
96+
```
97+
98+
### Event Bus Testing
99+
Scarletseer can trigger events for the ZeroMQ event bus:
100+
- **Player events**: login, logout, death
101+
- **Quest events**: accept, complete, abandon
102+
- **Combat events**: enter, leave
103+
- **Loot events**: item looted
104+
- **Encounter events**: start, wipe, end (requires dungeon/raid)
105+
106+
Monitor events with: `python /opt/trinitycore/TrinityCore/src/araxiaonline/tools/zmq_subscriber.py`
107+
108+
---
109+
110+
### Building the server
111+
- Always use the max number of threads when building the server
112+
- Always use @araxiaonline/cmake_setup.sh to setup the build environment. Modify it if needed.
113+
- Please fix all compile warnings before marking a task as complete.

src/araxiaonline/CMakeLists.txt

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,26 @@
44
# Build eventbus as separate library (has ZMQ dependency)
55
add_subdirectory(eventbus)
66

7-
# Collect sources EXCLUDING eventbus (it's built as separate library)
7+
# Collect sources EXCLUDING certain directories
8+
#
9+
# IMPORTANT: CollectSourceFiles (defined in cmake/macros/AutoCollect.cmake) requires
10+
# FULL PATHS for exclusions, not just directory names. Using bare names like "eventbus"
11+
# will silently fail to exclude the directory.
12+
#
13+
# Exclusions:
14+
# - eventbus: Built as separate library with ZMQ dependency
15+
# - tools: Contains Python scripts and virtual environments (.venv)
16+
# The .venv directory contains C files from Python packages (e.g., pyzmq's
17+
# _cffi_src.c) which would cause CMake to generate a C precompiled header.
18+
# Since gamePCH.h includes C++ headers (<cstddef>, etc.), the C PCH build
19+
# fails with "cstddef file not found". Excluding tools/ prevents this.
20+
#
821
CollectSourceFiles(
922
${CMAKE_CURRENT_SOURCE_DIR}
1023
PRIVATE_SOURCES
11-
SKIP_DIRS
12-
eventbus)
24+
# Exclude - MUST be full paths, see comment above
25+
${CMAKE_CURRENT_SOURCE_DIR}/eventbus
26+
${CMAKE_CURRENT_SOURCE_DIR}/tools)
1327

1428
GroupSources(${CMAKE_CURRENT_SOURCE_DIR})
1529

src/araxiaonline/araxia.conf.dist

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,98 @@
4242
# Topics: *.player.login, *.player.logout, *.player.death
4343
# Default: 1 (enabled)
4444
#
45+
# Araxia.EventBus.EnableCombatEvents
46+
# Enable publishing of combat events (enter, leave).
47+
# Topics: *.combat.enter, *.combat.leave
48+
# Default: 1 (enabled)
49+
#
50+
# Araxia.EventBus.EnableLootEvents
51+
# Enable publishing of loot events (item looted).
52+
# Topics: *.loot.item
53+
# Default: 1 (enabled)
54+
#
55+
# Araxia.EventBus.EnableQuestEvents
56+
# Enable publishing of quest events (accept, complete, abandon).
57+
# Topics: *.quest.accept, *.quest.complete, *.quest.abandon
58+
# Default: 1 (enabled)
59+
#
60+
# Araxia.EventBus.EnableZoneEvents
61+
# Enable publishing of zone change events.
62+
# Topics: *.zone.change
63+
# Default: 1 (enabled)
64+
#
65+
# Araxia.EventBus.EnablePartyEvents
66+
# Enable publishing of party/group events (join, leave, disband).
67+
# Topics: *.party.join, *.party.leave, *.party.disband, *.party.leader_change
68+
# Default: 1 (enabled)
69+
#
70+
# Araxia.EventBus.EnableItemEvents
71+
# Enable publishing of item equip/unequip events.
72+
# Topics: *.item.equip, *.item.unequip
73+
# Default: 1 (enabled)
74+
#
75+
# Araxia.EventBus.EnableSpellEvents
76+
# Enable publishing of spell cast events.
77+
# WARNING: Very high volume! Only enable if needed.
78+
# Topics: *.spell.cast
79+
# Default: 0 (disabled)
80+
#
81+
# Araxia.EventBus.EnableLevelEvents
82+
# Enable publishing of level up events.
83+
# Topics: *.player.levelup
84+
# Default: 1 (enabled)
85+
#
86+
# Araxia.EventBus.EnableChatEvents
87+
# Enable publishing of chat events.
88+
# Topics: *.chat.say, *.chat.yell, *.chat.whisper, *.chat.party, *.chat.guild, *.chat.raid
89+
# Default: 1 (enabled)
90+
#
91+
# Araxia.EventBus.EnableAchievementEvents
92+
# Enable publishing of achievement events.
93+
# Topics: *.achievement.earned
94+
# Default: 1 (enabled)
95+
#
96+
# Araxia.EventBus.EnableAuctionEvents
97+
# Enable publishing of auction house events.
98+
# Topics: *.auction.create, *.auction.bid, *.auction.buyout, *.auction.expire, *.auction.cancel
99+
# Default: 1 (enabled)
100+
#
101+
# Araxia.EventBus.EnableMailEvents
102+
# Enable publishing of mail events.
103+
# Topics: *.mail.send, *.mail.receive
104+
# Default: 1 (enabled)
105+
#
106+
# Araxia.EventBus.EnableTradeEvents
107+
# Enable publishing of trade events.
108+
# Topics: *.trade.complete
109+
# Default: 1 (enabled)
110+
#
111+
# Araxia.EventBus.EnableGuildEvents
112+
# Enable publishing of guild events.
113+
# Topics: *.guild.join, *.guild.leave, *.guild.promote, *.guild.demote, *.guild.create, *.guild.disband
114+
# Default: 1 (enabled)
115+
#
45116
###############################################################################
46117

47118
Araxia.EventBus.PublishEndpoint = "tcp://*:5555"
48119
Araxia.EventBus.SubscribeEndpoint = "tcp://127.0.0.1:5556"
49120
Araxia.EventBus.EnableSpawnEvents = 1
50121
Araxia.EventBus.EnableEncounterEvents = 1
51122
Araxia.EventBus.EnablePlayerEvents = 1
123+
Araxia.EventBus.EnableCombatEvents = 1
124+
Araxia.EventBus.EnableLootEvents = 1
125+
Araxia.EventBus.EnableQuestEvents = 1
126+
Araxia.EventBus.EnableZoneEvents = 1
127+
Araxia.EventBus.EnablePartyEvents = 1
128+
Araxia.EventBus.EnableItemEvents = 1
129+
Araxia.EventBus.EnableSpellEvents = 0
130+
Araxia.EventBus.EnableLevelEvents = 1
131+
Araxia.EventBus.EnableChatEvents = 1
132+
Araxia.EventBus.EnableAchievementEvents = 1
133+
Araxia.EventBus.EnableAuctionEvents = 1
134+
Araxia.EventBus.EnableMailEvents = 1
135+
Araxia.EventBus.EnableTradeEvents = 1
136+
Araxia.EventBus.EnableGuildEvents = 1
52137

53138
###############################################################################
54139
#

src/araxiaonline/eventbus/AraxiaEventBus.cpp

Lines changed: 10 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -167,82 +167,21 @@ void AraxiaEventBus::Publish(const std::string& topic, const EventContext& conte
167167

168168
std::string AraxiaEventBus::ContentTypeToPrefix(ContentType type)
169169
{
170-
switch (type)
171-
{
172-
case ContentType::World: return "world";
173-
case ContentType::Dungeon: return "dungeon";
174-
case ContentType::Raid: return "raid";
175-
case ContentType::Battleground: return "bg";
176-
case ContentType::Arena: return "arena";
177-
default: return "world";
178-
}
179-
}
180-
181-
void AraxiaEventBus::PublishSpawnEvent(ContentType type, bool isCreate, uint64 guid, uint32 entry,
182-
uint32 mapId, uint32 instanceId, float x, float y, float z)
183-
{
184-
std::string prefix = ContentTypeToPrefix(type);
185-
std::string topic = prefix + ".spawn." + (isCreate ? "create" : "delete");
186-
187-
// Debug: Log spawn events to verify they're being called
188-
TC_LOG_DEBUG("araxia.eventbus", "PublishSpawnEvent: {} entry={} guid={} map={}",
189-
topic, entry, guid, mapId);
190-
191-
EventContext ctx;
192-
ctx.MapId = mapId;
193-
ctx.InstanceId = instanceId;
194-
ctx.Type = type;
195-
196-
std::ostringstream payload;
197-
payload << "{\"guid\":" << guid
198-
<< ",\"entry\":" << entry
199-
<< ",\"x\":" << x
200-
<< ",\"y\":" << y
201-
<< ",\"z\":" << z << "}";
202-
203-
Publish(topic, ctx, payload.str());
170+
// Delegate to the shared helper in AraxiaEvents.h
171+
return ::ContentTypeToPrefix(type);
204172
}
205173

206-
void AraxiaEventBus::PublishEncounterEvent(ContentType type, const std::string& eventType,
207-
uint32 encounterId, uint32 mapId, uint32 instanceId,
208-
const std::string& extraJson)
174+
void AraxiaEventBus::Publish(const IAraxiaEvent& event)
209175
{
210-
std::string prefix = ContentTypeToPrefix(type);
211-
std::string topic = prefix + ".encounter." + eventType;
212-
213-
EventContext ctx;
214-
ctx.MapId = mapId;
215-
ctx.InstanceId = instanceId;
216-
ctx.Type = type;
217-
218-
std::ostringstream payload;
219-
payload << "{\"encounter_id\":" << encounterId;
220-
221-
// Merge extra JSON if provided
222-
if (extraJson.length() > 2) // More than just "{}"
223-
{
224-
// Strip leading { from extraJson and append
225-
payload << "," << extraJson.substr(1);
226-
}
227-
else
228-
{
229-
payload << "}";
230-
}
231-
232-
Publish(topic, ctx, payload.str());
233-
}
234-
235-
void AraxiaEventBus::PublishPlayerEvent(const std::string& eventType, uint64 playerGuid,
236-
const std::string& playerName, const EventContext& context)
237-
{
238-
std::string prefix = ContentTypeToPrefix(context.Type);
239-
std::string topic = prefix + ".player." + eventType;
176+
// Early out if not initialized or this event type is disabled
177+
// Each event implements IsEnabled() to check its specific config toggle
178+
if (!IsInitialized() || !event.IsEnabled())
179+
return;
240180

241-
std::ostringstream payload;
242-
payload << "{\"player_guid\":" << playerGuid
243-
<< ",\"player_name\":\"" << playerName << "\"}";
181+
std::string topic = event.GetTopic();
182+
TC_LOG_DEBUG("araxia.eventbus", "Publish event: {}", topic);
244183

245-
Publish(topic, context, payload.str());
184+
Publish(topic, event.GetContext(), event.GetPayload());
246185
}
247186

248187
void AraxiaEventBus::Subscribe(const std::string& topicPrefix, EventHandler handler)

src/araxiaonline/eventbus/AraxiaEventBus.h

Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
*/
3838

3939
#include "Define.h"
40+
#include "AraxiaEvents.h"
4041
#include <string>
4142
#include <functional>
4243
#include <memory>
@@ -51,28 +52,6 @@ namespace zmq {
5152
class socket_t;
5253
}
5354

54-
// Content type for topic routing
55-
enum class ContentType : uint8
56-
{
57-
World = 0, // Open world (non-instanced)
58-
Dungeon = 1, // 5-man dungeon
59-
Raid = 2, // Raid instance
60-
Battleground = 3, // PvP battleground
61-
Arena = 4 // Arena
62-
};
63-
64-
// Event context for filtering
65-
struct TC_GAME_API EventContext
66-
{
67-
uint32 MapId = 0;
68-
uint32 InstanceId = 0;
69-
uint32 Difficulty = 0;
70-
uint32 ZoneId = 0;
71-
ContentType Type = ContentType::World;
72-
73-
std::string ToJson() const;
74-
};
75-
7655
// Subscription handler callback
7756
using EventHandler = std::function<void(const std::string& topic, const std::string& payload)>;
7857

@@ -89,19 +68,15 @@ class TC_GAME_API AraxiaEventBus
8968
void Shutdown();
9069
bool IsInitialized() const { return _initialized; }
9170

92-
// Publishing - generic
71+
// Publishing - event interface (preferred)
72+
// Usage: sAraxiaEventBus->Publish(SpawnEvent(...));
73+
// The event handles its own topic, payload, and config check
74+
void Publish(const IAraxiaEvent& event);
75+
76+
// Publishing - generic (for custom events)
9377
void Publish(const std::string& topic, const std::string& jsonPayload);
9478
void Publish(const std::string& topic, const EventContext& context, const std::string& jsonPayload);
9579

96-
// Publishing - typed helpers
97-
void PublishSpawnEvent(ContentType type, bool isCreate, uint64 guid, uint32 entry,
98-
uint32 mapId, uint32 instanceId, float x, float y, float z);
99-
void PublishEncounterEvent(ContentType type, const std::string& eventType,
100-
uint32 encounterId, uint32 mapId, uint32 instanceId,
101-
const std::string& extraJson = "{}");
102-
void PublishPlayerEvent(const std::string& eventType, uint64 playerGuid,
103-
const std::string& playerName, const EventContext& context);
104-
10580
// Subscribing
10681
void Subscribe(const std::string& topicPrefix, EventHandler handler);
10782
void Unsubscribe(const std::string& topicPrefix);

src/araxiaonline/eventbus/AraxiaEventBusConfig.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,39 @@ void AraxiaEventBusConfig::LoadConfig()
3434
_enableSpawnEvents = sConfigMgr->GetBoolDefault("Araxia.EventBus.EnableSpawnEvents"sv, true);
3535
_enableEncounterEvents = sConfigMgr->GetBoolDefault("Araxia.EventBus.EnableEncounterEvents"sv, true);
3636
_enablePlayerEvents = sConfigMgr->GetBoolDefault("Araxia.EventBus.EnablePlayerEvents"sv, true);
37+
_enableCombatEvents = sConfigMgr->GetBoolDefault("Araxia.EventBus.EnableCombatEvents"sv, true);
38+
_enableLootEvents = sConfigMgr->GetBoolDefault("Araxia.EventBus.EnableLootEvents"sv, true);
39+
_enableQuestEvents = sConfigMgr->GetBoolDefault("Araxia.EventBus.EnableQuestEvents"sv, true);
40+
_enableZoneEvents = sConfigMgr->GetBoolDefault("Araxia.EventBus.EnableZoneEvents"sv, true);
41+
_enablePartyEvents = sConfigMgr->GetBoolDefault("Araxia.EventBus.EnablePartyEvents"sv, true);
42+
_enableItemEvents = sConfigMgr->GetBoolDefault("Araxia.EventBus.EnableItemEvents"sv, true);
43+
_enableSpellEvents = sConfigMgr->GetBoolDefault("Araxia.EventBus.EnableSpellEvents"sv, false); // High volume
44+
_enableLevelEvents = sConfigMgr->GetBoolDefault("Araxia.EventBus.EnableLevelEvents"sv, true);
45+
_enableChatEvents = sConfigMgr->GetBoolDefault("Araxia.EventBus.EnableChatEvents"sv, true);
46+
_enableAchievementEvents = sConfigMgr->GetBoolDefault("Araxia.EventBus.EnableAchievementEvents"sv, true);
47+
_enableAuctionEvents = sConfigMgr->GetBoolDefault("Araxia.EventBus.EnableAuctionEvents"sv, true);
48+
_enableMailEvents = sConfigMgr->GetBoolDefault("Araxia.EventBus.EnableMailEvents"sv, true);
49+
_enableTradeEvents = sConfigMgr->GetBoolDefault("Araxia.EventBus.EnableTradeEvents"sv, true);
50+
_enableGuildEvents = sConfigMgr->GetBoolDefault("Araxia.EventBus.EnableGuildEvents"sv, true);
3751

3852
TC_LOG_INFO("araxia.eventbus", "EventBus config loaded:");
3953
TC_LOG_INFO("araxia.eventbus", " PublishEndpoint: {}", _publishEndpoint);
4054
TC_LOG_INFO("araxia.eventbus", " SubscribeEndpoint: {}", _subscribeEndpoint);
4155
TC_LOG_INFO("araxia.eventbus", " SpawnEvents: {}", _enableSpawnEvents ? "enabled" : "disabled");
4256
TC_LOG_INFO("araxia.eventbus", " EncounterEvents: {}", _enableEncounterEvents ? "enabled" : "disabled");
4357
TC_LOG_INFO("araxia.eventbus", " PlayerEvents: {}", _enablePlayerEvents ? "enabled" : "disabled");
58+
TC_LOG_INFO("araxia.eventbus", " CombatEvents: {}", _enableCombatEvents ? "enabled" : "disabled");
59+
TC_LOG_INFO("araxia.eventbus", " LootEvents: {}", _enableLootEvents ? "enabled" : "disabled");
60+
TC_LOG_INFO("araxia.eventbus", " QuestEvents: {}", _enableQuestEvents ? "enabled" : "disabled");
61+
TC_LOG_INFO("araxia.eventbus", " ZoneEvents: {}", _enableZoneEvents ? "enabled" : "disabled");
62+
TC_LOG_INFO("araxia.eventbus", " PartyEvents: {}", _enablePartyEvents ? "enabled" : "disabled");
63+
TC_LOG_INFO("araxia.eventbus", " ItemEvents: {}", _enableItemEvents ? "enabled" : "disabled");
64+
TC_LOG_INFO("araxia.eventbus", " SpellEvents: {}", _enableSpellEvents ? "enabled" : "disabled");
65+
TC_LOG_INFO("araxia.eventbus", " LevelEvents: {}", _enableLevelEvents ? "enabled" : "disabled");
66+
TC_LOG_INFO("araxia.eventbus", " ChatEvents: {}", _enableChatEvents ? "enabled" : "disabled");
67+
TC_LOG_INFO("araxia.eventbus", " AchievementEvents: {}", _enableAchievementEvents ? "enabled" : "disabled");
68+
TC_LOG_INFO("araxia.eventbus", " AuctionEvents: {}", _enableAuctionEvents ? "enabled" : "disabled");
69+
TC_LOG_INFO("araxia.eventbus", " MailEvents: {}", _enableMailEvents ? "enabled" : "disabled");
70+
TC_LOG_INFO("araxia.eventbus", " TradeEvents: {}", _enableTradeEvents ? "enabled" : "disabled");
71+
TC_LOG_INFO("araxia.eventbus", " GuildEvents: {}", _enableGuildEvents ? "enabled" : "disabled");
4472
}

0 commit comments

Comments
 (0)