fix(entity): message handlers run in the order they registered, as the client

Handlers sat in an unordered_multimap, whose order for one message is up to
the standard library: GCC ran them newest first, so the components loaded
last answered a RequestUse first, and Windows builds could differ. They are
now kept per message in registration order: the object's own handlers, then
its components' in load order (LWOGameObject::PassMessageToComponents).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-10-02 08:19:18 -05:00
parent 260e6cb1b1
commit 9aa06f349c
2 changed files with 12 additions and 5 deletions

View File

@@ -1731,18 +1731,23 @@ int32_t Entity::GetCollisionGroup() const {
return 0;
}
// LWOGameObject::PassMessageToComponents (0x00f62500): every handler registered for the message, in registration
// order; only the ones there when the call starts (the client copies the list first; GetPosition is too hot for a copy)
bool Entity::HandleMsg(GameMessages::GameMsg& msg) const {
const auto it = m_MsgHandlers.find(msg.msgId);
if (it == m_MsgHandlers.end()) return false;
bool handled = false;
auto [beg, end] = m_MsgHandlers.equal_range(msg.msgId);
for (auto& it = beg; it != end; ++it) {
if (it->second) handled |= it->second(msg);
const auto& handlers = it->second;
for (size_t i = 0, count = handlers.size(); i < count; i++) {
if (handlers[i]) handled |= handlers[i](msg);
}
return handled;
}
void Entity::RegisterMsg(const MessageType::Game msgId, std::function<bool(GameMessages::GameMsg&)> handler) {
m_MsgHandlers.emplace(msgId, handler);
m_MsgHandlers[msgId].push_back(std::move(handler));
}
bool Entity::MsgRequestServerObjectInfo(GameMessages::RequestServerObjectInfoEvent& event) {

View File

@@ -480,7 +480,9 @@ private:
// objectID of receiver and map of notification name to script
std::map<LWOOBJID, std::map<std::string, CppScripts::Script*>> m_Subscriptions;
std::unordered_multimap<MessageType::Game, std::function<bool(GameMessages::GameMsg&)>> m_MsgHandlers;
// Each message's handlers in the order they registered: the object's own, then its components' in load order
// (LWOGameObject::registeredGameMessages)
std::unordered_map<MessageType::Game, std::vector<std::function<bool(GameMessages::GameMsg&)>>> m_MsgHandlers;
};
/**