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) {