mirror of
https://github.com/araxiaonline/mod-mythic-plus.git
synced 2026-06-13 03:02:24 -04:00
Added EventProcessor for client and server communication
This commit is contained in:
27
src/Event/MpEvent.h
Normal file
27
src/Event/MpEvent.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#include <array>
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#ifndef MP_EVENTS_H
|
||||
#define MP_EVENTS_H
|
||||
|
||||
// This defines
|
||||
enum class MpEvent
|
||||
{
|
||||
None, // Default catch all for no event
|
||||
Invalid, // Used to capture identify error events
|
||||
UpgradeAdvancement,
|
||||
ResetAdvancement,
|
||||
ResetAllAdvancements
|
||||
};
|
||||
|
||||
// Mapping of Event Strings to EventNames for Event Callbacks from client
|
||||
std::unordered_map<std::string_view, MpEvent> MpEventMap = {{
|
||||
{"UpgradeAdvancement", MpEvent::UpgradeAdvancement},
|
||||
{"ResetAdvancement", MpEvent::ResetAdvancement},
|
||||
{"ResetAllAdvancements", MpEvent::ResetAllAdvancements}
|
||||
}};
|
||||
|
||||
|
||||
#endif
|
||||
0
src/Event/MpEventHandlers.cpp
Normal file
0
src/Event/MpEventHandlers.cpp
Normal file
114
src/Event/MpEventProcessor.cpp
Normal file
114
src/Event/MpEventProcessor.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
|
||||
#include "MpEventProcessor.h"
|
||||
#include "MythicPlus.h"
|
||||
#include "MpLogger.h"
|
||||
#include "Player.h"
|
||||
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
bool MpEventProcessor::ProcessMessage(Player* player, const std::string& message) {
|
||||
|
||||
if(!player) {
|
||||
MpLogger::error("Null player passed to processMessage");
|
||||
return false;
|
||||
}
|
||||
|
||||
EventParseRslt result = _parsePlayerMessage(player, message);
|
||||
MpEvent event = std::get<0>(result);
|
||||
uint32 guid = std::get<1>(result);
|
||||
std::vector<std::string> args = std::get<2>(result);
|
||||
|
||||
// If th message was not able to be parsed it is a failure
|
||||
if(event == MpEvent::Invalid) {
|
||||
MpLogger::warn("Invalid event, could not be parsed for player {} message: {}", player->GetName(), message);
|
||||
return false;
|
||||
}
|
||||
|
||||
// if the message is not from the same player who called it ignore it as it is attempt to hack the system
|
||||
if(player->GetGUID().GetCounter() != guid) {
|
||||
MpLogger::warn("Player {} sent a message {} for eventId: {} player guid does not match", player->GetName(), message, event);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the event is not registered ignore it
|
||||
if(!_eventHandlers.contains(event)) {
|
||||
MpLogger::info("No handler registered for event: {}", event);
|
||||
return false;
|
||||
}
|
||||
|
||||
return Dispatch(event, player, args);
|
||||
}
|
||||
|
||||
void MpEventProcessor::RegisterHandler(MpEvent event, std::shared_ptr<MpEventInterface> handler) {
|
||||
_eventHandlers[event] = handler;
|
||||
}
|
||||
|
||||
// This fires the execution to the actual event.
|
||||
bool MpEventProcessor::Dispatch(MpEvent event, Player* player, std::vector<std::string>& args) {
|
||||
if(!_eventHandlers.contains(event)) {
|
||||
MpLogger::warn("No handler registered for event: {}", event);
|
||||
return false;
|
||||
}
|
||||
|
||||
return _eventHandlers[event]->Execute(args);
|
||||
}
|
||||
|
||||
// Find our eventId using the string name
|
||||
MpEvent MpEventProcessor::_getEventByName(std::string_view eventName)
|
||||
{
|
||||
auto it = MpEventMap.find(eventName);
|
||||
return (it != MpEventMap.end()) ? it->second : MpEvent::None;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the incoming message into id, event, and handler arguments
|
||||
*/
|
||||
EventParseRslt MpEventProcessor::_parsePlayerMessage(Player* player, const std::string& msg)
|
||||
{
|
||||
if(msg[0] != 'p') {
|
||||
MpLogger::warn("Invalid player message format received from player {} message: {}", player->GetName(), msg);
|
||||
return EventParseRslt{MpEvent::Invalid, 0, {}};
|
||||
}
|
||||
|
||||
std::vector<std::string> handlerArgs;
|
||||
char delimiter = '|';
|
||||
|
||||
// split the protocol into valid parts
|
||||
std::vector<std::string> parts = _splitString(msg, delimiter);
|
||||
|
||||
if (parts.size() < 3) {
|
||||
MpLogger::warn("Malformed player message received from player {}: {}", player->GetName(), msg);
|
||||
return EventParseRslt{MpEvent::Invalid, 0, {}};
|
||||
}
|
||||
|
||||
MpEvent event = _getEventByName(parts[2]);
|
||||
|
||||
handlerArgs.assign(parts.begin() + 3, parts.end());
|
||||
|
||||
MpLogger::info("Player {} sent a client event message {} for event: {} eventId: {} ", player->GetName(), msg, MP_DATA_CHAT_CHANNEL, parts[2], event);
|
||||
return EventParseRslt{event, player->GetGUID().GetCounter(), std::move(handlerArgs)};
|
||||
}
|
||||
|
||||
// Split the string passed in by delimiters
|
||||
std::vector<std::string> MpEventProcessor::_splitString(const std::string& s, char delimiter) {
|
||||
std::vector<std::string> tokens;
|
||||
size_t start = 0;
|
||||
size_t end = s.find(delimiter);
|
||||
|
||||
while (end != std::string::npos) {
|
||||
if (end != start) {
|
||||
tokens.emplace_back(s.substr(start, end - start));
|
||||
}
|
||||
start = end + 1;
|
||||
end = s.find(delimiter, start);
|
||||
}
|
||||
|
||||
// Add the last token if it's not empty
|
||||
if (start < s.length()) {
|
||||
tokens.emplace_back(s.substr(start));
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
76
src/Event/MpEventProcessor.h
Normal file
76
src/Event/MpEventProcessor.h
Normal file
@@ -0,0 +1,76 @@
|
||||
#ifndef MYTHIC_PLUS_EVENT_PROCESSOR_H
|
||||
#define MYTHIC_PLUS_EVENT_PROCESSOR_H
|
||||
|
||||
#include "MpEvent.h"
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* Interface for all Mythic+ Event communication between client and server
|
||||
*/
|
||||
class MpEventInterface
|
||||
{
|
||||
public:
|
||||
MpEventInterface() {};
|
||||
virtual ~MpEventInterface() = default;
|
||||
[[nodiscard]] virtual bool Execute(std::vector<std::string>&) = 0;
|
||||
};
|
||||
|
||||
using EventParseRslt = std::tuple<MpEvent, uint32_t, std::vector<std::string>>;
|
||||
|
||||
/**
|
||||
* This class is responsible for processing events that are send from the client. Events
|
||||
* are processed FIFO and executed immidiately. This is specifically to allow AddOn or AIO
|
||||
* communication to this module without requiring additional changes to mod-eluna or the core.
|
||||
*
|
||||
* Message Body Format
|
||||
* Client Player Events
|
||||
* - p|playerGuid|action|input1|input2|input3...
|
||||
* i.e) p|5793|UpgradeAdvancement|0|10|2
|
||||
*/
|
||||
class MpEventProcessor
|
||||
{
|
||||
|
||||
public:
|
||||
static MpEventProcessor* instance() {
|
||||
static MpEventProcessor instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
MpEventProcessor() = default;
|
||||
~MpEventProcessor() = default;
|
||||
|
||||
// /* TODO */ Add generic handler later for other events if needed.
|
||||
// bool ProcessMessage(std::string_view message);
|
||||
|
||||
// Process a message from a specific player
|
||||
bool ProcessMessage(Player* player, const std::string& message);
|
||||
|
||||
// Registers a handler for a valid MpEvent specified in the MpEvent enum
|
||||
// In this design Event:Handler is 1:1
|
||||
void RegisterHandler(MpEvent event, std::shared_ptr<MpEventInterface> handler);
|
||||
|
||||
// Dispatch will execute the event handler
|
||||
bool Dispatch(MpEvent event, Player* player, std::vector<std::string>& args);
|
||||
|
||||
private:
|
||||
MpEventProcessor() {}
|
||||
~MpEventProcessor() {}
|
||||
|
||||
// List of registered handlers for event management
|
||||
std::unordered_map<MpEvent, std::shared_ptr<MpEventInterface>> _eventHandlers;
|
||||
|
||||
// Get the correct Event associated to handlers by the message strong
|
||||
MpEvent _getEventByName(std::string_view eventName);
|
||||
|
||||
// Parse a message from the player
|
||||
EventParseRslt _parsePlayerMessage(Player* player, const std::string& msg);
|
||||
|
||||
std::vector<std::string> _splitString(const std::string& s, char delimiter = '|');
|
||||
};
|
||||
|
||||
#define sMpEventProcessor MpEventProcessor::instance()
|
||||
|
||||
#endif // MYTHIC_PLUS_EVENT_PROCESSOR_H
|
||||
Reference in New Issue
Block a user