mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 10:53:44 +00:00
Converts PlayAnimation, PlayNDAudioEmitter, PlayEmbeddedEffectOnAllClientsNearObject,
PlayFXEffect, StopFXEffect, BroadcastTextToChatbox, Play2DAmbientSound,
Stop2DAmbientSound, UIMessageServerToSingleClient, UIMessageServerToAllClients,
StartCelebrationEffect, DisplayMessageBox, DisplayChatBubble, ChangeIdleFlags,
SetNameBillboardState, ShowBillboardInteractIcon, PlayCinematic, EndCinematic,
SlashCommandTextFeedback, PlayEmote and SetEmoteLockState (21 old Send
functions, 23 with overloads) and the received MessageBoxRespond,
ChoiceBoxRespond, CinematicUpdate and PlayEmote to NetGameMsgs in
EffectsMessages.{h,cpp}. The high traffic messages get a constructor for their
required fields. UI messages own their AMF arguments. Every caller is switched,
the received messages are registered in GameMessageHandler's map, and the old
functions and switch cases are deleted. Handlers are copied verbatim.
No wire change and no change in recipients: functions that always broadcast
whatever address they were given are sent with Send(UNASSIGNED_SYSTEM_ADDRESS),
functions that only did SEND_PACKET use SendToClient. Quirks are kept and
documented on the structs (PlayAnimation's UTF-8 sized name, the always written
null terminator in BroadcastTextToChatbox, StartCelebrationEffect always
writing celebrationID, SetNameBillboardState having no payload).
Verified byte for byte against a frozen verbatim copy of the old functions over
an input grid, to one client and broadcast; received messages compared with the
old handlers' read sequences and every truncated payload rejected; hand
computed golden bytes; round trips; a deliberate width mutation made the tests
fail. The byte-equality helper gains a Broadcast mode for functions that
ignored their address.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
328 lines
12 KiB
C++
328 lines
12 KiB
C++
#ifndef EFFECTSMESSAGES_H
|
|
#define EFFECTSMESSAGES_H
|
|
|
|
#include "GameMessages.h"
|
|
#include "Amf3.h"
|
|
#include "eAnimationFlags.h"
|
|
#include "eCinematicEvent.h"
|
|
#include "eEndBehavior.h"
|
|
|
|
#include <string>
|
|
|
|
// Game messages for effects, audio, animations, emotes, cinematics and UI text (message boxes, chat bubbles,
|
|
// billboards, UI messages, slash command feedback).
|
|
// Field names follow the client (legouniverse.exe 1.10.64); fields are listed in wire order.
|
|
namespace GameMessages {
|
|
// Server -> client, broadcast.
|
|
struct PlayAnimation : public NetGameMsg {
|
|
PlayAnimation() : NetGameMsg(MessageType::Game::PLAY_ANIMATION) {}
|
|
PlayAnimation(const LWOOBJID _target, const std::u16string& _animationID) : PlayAnimation() {
|
|
target = _target;
|
|
animationID = _animationID;
|
|
}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
|
|
// Written as a u32 length followed by that many UTF-16 characters, where the length is the size of the
|
|
// name converted to UTF-8 (so a non-ASCII name is padded with null characters). This is what DLU has
|
|
// always sent.
|
|
std::u16string animationID{};
|
|
bool bExpectAnimToExist{ true };
|
|
bool bPlayImmediate{};
|
|
bool bTriggerOnCompleteMsg{};
|
|
float fPriority{ 0.0f }; // optional
|
|
float fScale{ 1.0f }; // optional
|
|
};
|
|
|
|
// Server -> client, broadcast.
|
|
struct PlayNDAudioEmitter : public NetGameMsg {
|
|
PlayNDAudioEmitter() : NetGameMsg(MessageType::Game::PLAY_ND_AUDIO_EMITTER) {}
|
|
PlayNDAudioEmitter(const LWOOBJID _target, const std::string& _NDAudioEventGUID) : PlayNDAudioEmitter() {
|
|
target = _target;
|
|
NDAudioEventGUID = _NDAudioEventGUID;
|
|
}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
|
|
LWOOBJID NDAudioCallbackMessageData{}; // optional
|
|
uint32_t NDAudioEmitterID{}; // optional
|
|
std::string NDAudioEventGUID{};
|
|
std::string NDAudioMetaEventName{};
|
|
bool result{};
|
|
LWOOBJID targetObjectIDForNDAudioCallbackMessages{ LWOOBJID_EMPTY }; // optional
|
|
};
|
|
|
|
// Server -> client, broadcast.
|
|
struct PlayEmbeddedEffectOnAllClientsNearObject : public NetGameMsg {
|
|
PlayEmbeddedEffectOnAllClientsNearObject() : NetGameMsg(MessageType::Game::PLAY_EMBEDDED_EFFECT_ON_ALL_CLIENTS_NEAR_OBJECT) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
|
|
std::u16string effectName{};
|
|
LWOOBJID fromObjectID{};
|
|
float radius{};
|
|
};
|
|
|
|
// Server -> client, broadcast.
|
|
struct PlayFXEffect : public NetGameMsg {
|
|
PlayFXEffect() : NetGameMsg(MessageType::Game::PLAY_FX_EFFECT) {}
|
|
PlayFXEffect(const LWOOBJID _target, const int32_t _effectID, const std::u16string& _effectType, const std::string& _name) : PlayFXEffect() {
|
|
target = _target;
|
|
effectID = _effectID;
|
|
effectType = _effectType;
|
|
name = _name;
|
|
}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
|
|
int32_t effectID{ -1 }; // optional
|
|
std::u16string effectType{};
|
|
float scale{ 1.0f }; // optional
|
|
std::string name{};
|
|
float priority{ 1.0f }; // optional
|
|
LWOOBJID secondary{ LWOOBJID_EMPTY }; // optional
|
|
bool serialize{ true };
|
|
};
|
|
|
|
// Server -> client, broadcast.
|
|
struct StopFXEffect : public NetGameMsg {
|
|
StopFXEffect() : NetGameMsg(MessageType::Game::STOP_FX_EFFECT) {}
|
|
StopFXEffect(const LWOOBJID _target, const bool _killImmediate, const std::string& _name) : StopFXEffect() {
|
|
target = _target;
|
|
killImmediate = _killImmediate;
|
|
name = _name;
|
|
}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
|
|
bool killImmediate{};
|
|
std::string name{};
|
|
};
|
|
|
|
// Server -> client, broadcast.
|
|
struct BroadcastTextToChatbox : public NetGameMsg {
|
|
BroadcastTextToChatbox() : NetGameMsg(MessageType::Game::BROADCAST_TEXT_TO_CHATBOX) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
|
|
// Name value text: u32 length, the characters, then a null character that DLU always writes (even when empty).
|
|
std::u16string attrs{};
|
|
std::u16string wsText{};
|
|
};
|
|
|
|
// Server -> client.
|
|
struct Play2DAmbientSound : public NetGameMsg {
|
|
Play2DAmbientSound() : NetGameMsg(MessageType::Game::PLAY2_D_AMBIENT_SOUND) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
|
|
std::string audioGUID{};
|
|
bool result{};
|
|
};
|
|
|
|
// Server -> client.
|
|
struct Stop2DAmbientSound : public NetGameMsg {
|
|
Stop2DAmbientSound() : NetGameMsg(MessageType::Game::STOP2_D_AMBIENT_SOUND) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
|
|
bool force{};
|
|
std::string audioGUID{};
|
|
bool result{};
|
|
};
|
|
|
|
// Server -> client.
|
|
struct UIMessageServerToSingleClient : public NetGameMsg {
|
|
UIMessageServerToSingleClient() : NetGameMsg(MessageType::Game::UI_MESSAGE_SERVER_TO_SINGLE_CLIENT) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
|
|
AMFArrayValue args{};
|
|
std::string strMessageName{};
|
|
};
|
|
|
|
// Server -> client. Broadcast, or sent to one client (DLU uses it to reach a client that may not have an
|
|
// entity yet; the target is then LWOOBJID_EMPTY).
|
|
struct UIMessageServerToAllClients : public NetGameMsg {
|
|
UIMessageServerToAllClients() : NetGameMsg(MessageType::Game::UI_MESSAGE_SERVER_TO_ALL_CLIENTS) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
|
|
AMFArrayValue args{};
|
|
std::string strMessageName{};
|
|
};
|
|
|
|
// Server -> client.
|
|
struct StartCelebrationEffect : public NetGameMsg {
|
|
StartCelebrationEffect() : NetGameMsg(MessageType::Game::START_CELEBRATION_EFFECT) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
|
|
std::u16string animation{};
|
|
LOT backgroundObject{ 11164 }; // optional
|
|
LOT cameraPathLOT{ 12458 }; // optional
|
|
float celeLeadIn{ 1.0f }; // optional
|
|
float celeLeadOut{ 0.8f }; // optional
|
|
int32_t celebrationID{ -1 }; // optional; DLU always writes it, even when it has the default value
|
|
float duration{};
|
|
uint32_t iconID{};
|
|
std::u16string mainText{};
|
|
std::string mixerProgram{};
|
|
std::string musicCue{};
|
|
std::string pathNodeName{};
|
|
std::string soundGUID{};
|
|
std::u16string subText{};
|
|
};
|
|
|
|
// Server -> client.
|
|
struct DisplayMessageBox : public NetGameMsg {
|
|
DisplayMessageBox() : NetGameMsg(MessageType::Game::DISPLAY_MESSAGE_BOX) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
|
|
bool bShow{};
|
|
LWOOBJID callbackClient{};
|
|
std::u16string identifier{};
|
|
int32_t imageID{};
|
|
std::u16string text{};
|
|
std::u16string userData{};
|
|
};
|
|
|
|
// Client -> server. Sent to the callbackClient of a DisplayMessageBox when the player presses a button.
|
|
struct MessageBoxRespond : public NetGameMsg {
|
|
MessageBoxRespond() : NetGameMsg(MessageType::Game::MESSAGE_BOX_RESPOND) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
void Handle(Entity& entity, const SystemAddress& sysAddr) override;
|
|
|
|
int32_t iButton{};
|
|
std::u16string identifier{};
|
|
std::u16string userData{};
|
|
};
|
|
|
|
// Client -> server.
|
|
struct ChoiceBoxRespond : public NetGameMsg {
|
|
ChoiceBoxRespond() : NetGameMsg(MessageType::Game::CHOICE_BOX_RESPOND) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
void Handle(Entity& entity, const SystemAddress& sysAddr) override;
|
|
|
|
std::u16string buttonIdentifier{};
|
|
int32_t iButton{};
|
|
std::u16string identifier{};
|
|
};
|
|
|
|
// Server -> client.
|
|
struct DisplayChatBubble : public NetGameMsg {
|
|
DisplayChatBubble() : NetGameMsg(MessageType::Game::DISPLAY_CHAT_BUBBLE) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
|
|
std::u16string wsText{};
|
|
};
|
|
|
|
// Server -> client, broadcast.
|
|
struct ChangeIdleFlags : public NetGameMsg {
|
|
ChangeIdleFlags() : NetGameMsg(MessageType::Game::CHANGE_IDLE_FLAGS) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
|
|
eAnimationFlags flagsOff{ eAnimationFlags::IDLE_NONE }; // optional
|
|
eAnimationFlags flagsOn{ eAnimationFlags::IDLE_NONE }; // optional
|
|
};
|
|
|
|
// Server -> client. The client's message has two bools (overrideDefault, state), but the client never reads
|
|
// them, so DLU sends no payload; the message only turns the name billboard off.
|
|
struct SetNameBillboardState : public NetGameMsg {
|
|
SetNameBillboardState() : NetGameMsg(MessageType::Game::SET_NAME_BILLBOARD_STATE) {}
|
|
};
|
|
|
|
// Server -> client. No payload.
|
|
struct ShowBillboardInteractIcon : public NetGameMsg {
|
|
ShowBillboardInteractIcon() : NetGameMsg(MessageType::Game::SHOW_BILLBOARD_INTERACT_ICON) {}
|
|
};
|
|
|
|
// Server -> client.
|
|
struct PlayCinematic : public NetGameMsg {
|
|
PlayCinematic() : NetGameMsg(MessageType::Game::PLAY_CINEMATIC) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
|
|
bool allowGhostUpdates{ true };
|
|
bool bCloseMultiInteract{ true };
|
|
bool bSendServerNotify{};
|
|
bool bUseControlledObjectForAudioListener{};
|
|
eEndBehavior endBehavior{ eEndBehavior::RETURN }; // optional
|
|
bool hidePlayerDuringCine{};
|
|
float leadIn{ -1.0f }; // optional
|
|
bool leavePlayerLockedWhenFinished{};
|
|
bool lockPlayer{ true };
|
|
std::u16string pathName{};
|
|
bool result{};
|
|
bool skipIfSamePath{};
|
|
float startTimeAdvance{};
|
|
};
|
|
|
|
// Server -> client.
|
|
struct EndCinematic : public NetGameMsg {
|
|
EndCinematic() : NetGameMsg(MessageType::Game::END_CINEMATIC) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
|
|
float leadOut{ -1.0f }; // optional
|
|
bool leavePlayerLocked{};
|
|
std::u16string pathName{};
|
|
};
|
|
|
|
// Client -> server.
|
|
struct CinematicUpdate : public NetGameMsg {
|
|
CinematicUpdate() : NetGameMsg(MessageType::Game::CINEMATIC_UPDATE) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
void Handle(Entity& entity, const SystemAddress& sysAddr) override;
|
|
|
|
eCinematicEvent event{ eCinematicEvent::STARTED }; // optional
|
|
float overallTime{ -1.0f }; // optional
|
|
std::u16string pathName{};
|
|
float pathTime{ -1.0f }; // optional
|
|
int32_t waypoint{ -1 }; // optional
|
|
};
|
|
|
|
// Server -> client.
|
|
struct SlashCommandTextFeedback : public NetGameMsg {
|
|
SlashCommandTextFeedback() : NetGameMsg(MessageType::Game::SLASH_COMMAND_TEXT_FEEDBACK) {}
|
|
SlashCommandTextFeedback(const LWOOBJID _target, const std::u16string& _text) : SlashCommandTextFeedback() {
|
|
target = _target;
|
|
text = _text;
|
|
}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
|
|
std::u16string text{};
|
|
};
|
|
|
|
// Both directions: the client asks to play an emote (handled here), and the server tells clients an object
|
|
// plays one.
|
|
struct PlayEmote : public NetGameMsg {
|
|
PlayEmote() : NetGameMsg(MessageType::Game::PLAY_EMOTE) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
void Handle(Entity& entity, const SystemAddress& sysAddr) override;
|
|
|
|
int32_t emoteID{};
|
|
LWOOBJID targetID{};
|
|
};
|
|
|
|
// Server -> client.
|
|
struct SetEmoteLockState : public NetGameMsg {
|
|
SetEmoteLockState() : NetGameMsg(MessageType::Game::SET_EMOTE_LOCK_STATE) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
|
|
bool bLock{};
|
|
int32_t emoteID{};
|
|
};
|
|
};
|
|
|
|
#endif // EFFECTSMESSAGES_H
|