Files
DarkflameServer/tests/dGameTests/dGameMessagesTests/Legacy/EffectsMessagesLegacy.h
Aaron Kimbrell 542f0a89f0 refactor: remove the packet macros, WriteHeader and PacketUtils
Nothing in the server writes or reads a packet by hand any more, so the
helpers for doing so go:
- CBITSTREAM, CMSGHEADER, CINSTREAM, CINSTREAM_SKIP_HEADER, SEND_PACKET,
  SEND_PACKET_BROADCAST and HEADER_SIZE leave dCommonVars.h;
- the free BitStreamUtils::WriteHeader (LUBitStream::WriteHeader writes the
  same bytes) and the unused PacketUtils::SavePacket are deleted.
The last raw reads are replaced: WorldServer builds its input stream
directly, the master packet logs read the header with
LUBitStream::ReadHeader instead of peeking at packet->data[1] and [3], and
MessageInspector reads a sent game message's header with the new
NetGameMsg::ReadPacketHeader (the counterpart of WritePacket) instead of
memcmp/memcpy. packet->data[0] is still compared with RakNet's own
connection IDs.

The frozen oracles keep using the macros verbatim through the test-only
tests/dGameTests/LegacyPacketMacros.h; the HeaderSkip tests, which only
tested CINSTREAM_SKIP_HEADER, are removed.

docs/PacketArchitecture.md: "where we are" now describes the final state
and what still touches raw bytes (RakNet IDs, replica headers, behavior bit
streams), and a new section collects the known wire discrepancies found
during the conversion, with client addresses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:30:56 -05:00

609 lines
18 KiB
C++

#ifndef EFFECTSMESSAGESLEGACY_H
#define EFFECTSMESSAGESLEGACY_H
// FROZEN ORACLE - DO NOT EDIT.
// Verbatim copies of the hand written GameMessages functions that EffectsMessages.h replaced
// (dGame/dGameMessages/GameMessages.cpp, branched from origin/main 129199e4). Only the namespace changed.
// The Read* functions are the read sequences of the replaced GameMessages::Handle* functions.
#include "LegacyPacketMacros.h"
#include "Amf3.h"
#include "AmfSerialize.h"
#include "BitStreamUtils.h"
#include "dCommonVars.h"
#include "dServer.h"
#include "eAnimationFlags.h"
#include "eCinematicEvent.h"
#include "eEndBehavior.h"
#include "Entity.h"
#include "Game.h"
#include "GeneralUtils.h"
#include "Logger.h"
#include "MessageType/Client.h"
#include "MessageType/Game.h"
#include "ServiceType.h"
#include <cmath>
#include <string>
namespace LegacyGameMessages {
// Declared in GameMessages.h in the original; the Entity* overload forwards to it.
inline void SendPlayFXEffect(const LWOOBJID& entity, int32_t effectID, const std::u16string& effectType, const std::string& name, LWOOBJID secondary, float priority, float scale, bool serialize);
inline void SendPlayAnimation(Entity* entity, const std::u16string& animationName, float fPriority, float fScale) {
if (!entity) {
LOG("Trying to play animation, but entity var is nullptr!");
return;
}
//Stolen from the old DLU codebase as the new one's autogenerated code doesn't work properly for animationIDs longer than 6 characters.
CBITSTREAM;
CMSGHEADER;
std::string sAnimationID = GeneralUtils::UTF16ToWTF8(animationName);
uint32_t animationIDLength = sAnimationID.size();
bool bExpectAnimToExist = true;
bool bPlayImmediate = false;
bool bTriggerOnCompleteMsg = false;
bitStream.Write(entity->GetObjectID());
bitStream.Write(MessageType::Game::PLAY_ANIMATION);
bitStream.Write(animationIDLength);
bitStream.Write(LUWString(animationName, animationIDLength));
bitStream.Write(bExpectAnimToExist);
bitStream.Write(bPlayImmediate);
bitStream.Write(bTriggerOnCompleteMsg);
bitStream.Write(fPriority != 0.0f);
if (fPriority != 0.0f) bitStream.Write(fPriority);
bitStream.Write(fScale != 1.0f);
if (fScale != 1.0f) bitStream.Write(fScale);
SEND_PACKET_BROADCAST;
}
inline void SendPlayNDAudioEmitter(Entity* entity, const SystemAddress& sysAddr, std::string audioGUID) {
CBITSTREAM;
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write(MessageType::Game::PLAY_ND_AUDIO_EMITTER);
bitStream.Write0(); // callback message data {lwoobjid}
bitStream.Write0(); // audio emitterid {uint32_t}
uint32_t length = audioGUID.size();
bitStream.Write(length);
for (uint32_t k = 0; k < length; k++) {
bitStream.Write<char>(audioGUID[k]);
}
bitStream.Write<uint32_t>(0); // size of NDAudioMetaEventName (then print the string like the guid)
bitStream.Write0(); // result {bool}
bitStream.Write0(); // m_TargetObjectIDForNDAudioCallbackMessages {lwoobjid}
SEND_PACKET_BROADCAST;
}
inline void SendPlayEmbeddedEffectOnAllClientsNearObject(Entity* entity, std::u16string effectName, const LWOOBJID& fromObjectID, float radius) {
CBITSTREAM;
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write(MessageType::Game::PLAY_EMBEDDED_EFFECT_ON_ALL_CLIENTS_NEAR_OBJECT);
bitStream.Write<uint32_t>(effectName.length());
for (uint32_t k = 0; k < effectName.length(); k++) {
bitStream.Write<uint16_t>(effectName[k]);
}
bitStream.Write(fromObjectID);
bitStream.Write(radius);
SEND_PACKET_BROADCAST;
}
inline void SendPlayFXEffect(Entity* entity, int32_t effectID, const std::u16string& effectType, const std::string& name, LWOOBJID secondary, float priority, float scale, bool serialize) {
SendPlayFXEffect(entity->GetObjectID(), effectID, effectType, name, secondary, priority, scale, serialize);
}
inline void SendPlayFXEffect(const LWOOBJID& entity, int32_t effectID, const std::u16string& effectType, const std::string& name, LWOOBJID secondary, float priority, float scale, bool serialize) {
CBITSTREAM;
CMSGHEADER;
bitStream.Write(entity);
bitStream.Write(MessageType::Game::PLAY_FX_EFFECT);
bitStream.Write(effectID != -1);
if (effectID != -1) bitStream.Write(effectID);
bitStream.Write<uint32_t>(effectType.size());
for (const auto& k : effectType) {
bitStream.Write<uint16_t>(k);
}
bitStream.Write(scale != 1.0f);
if (scale != 1.0f) bitStream.Write(scale);
bitStream.Write<uint32_t>(name.size());
for (const auto& k : name) {
bitStream.Write(k);
}
bitStream.Write(priority != 1.0);
if (priority != 1.0) bitStream.Write(priority);
bitStream.Write(secondary != LWOOBJID_EMPTY);
if (secondary != LWOOBJID_EMPTY) bitStream.Write(secondary);
bitStream.Write(serialize);
SEND_PACKET_BROADCAST;
}
inline void SendStopFXEffect(Entity* entity, bool killImmediate, std::string name) {
CBITSTREAM;
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write(MessageType::Game::STOP_FX_EFFECT);
bitStream.Write(killImmediate);
bitStream.Write<uint32_t>(name.size());
bitStream.Write(name.c_str(), name.size());
SEND_PACKET_BROADCAST;
}
inline void SendBroadcastTextToChatbox(Entity* entity, const SystemAddress& sysAddr, const std::u16string& attrs, const std::u16string& wsText) {
CBITSTREAM;
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write(MessageType::Game::BROADCAST_TEXT_TO_CHATBOX);
bitStream.Write<uint32_t>(attrs.size());
for (uint32_t i = 0; i < attrs.size(); ++i) {
bitStream.Write<uint16_t>(attrs[i]);
}
bitStream.Write<uint16_t>(0x00); // Null Terminator
uint32_t wsTextLength = wsText.size();
bitStream.Write(wsTextLength);
for (uint32_t k = 0; k < wsTextLength; k++) {
bitStream.Write<uint16_t>(wsText[k]);
}
SEND_PACKET_BROADCAST;
}
inline void SendPlay2DAmbientSound(Entity* entity, std::string audioGUID, bool result) {
CBITSTREAM;
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write(MessageType::Game::PLAY2_D_AMBIENT_SOUND);
uint32_t audioGUIDSize = audioGUID.size();
bitStream.Write(audioGUIDSize);
for (uint32_t k = 0; k < audioGUIDSize; k++) {
bitStream.Write<char>(audioGUID[k]);
}
bitStream.Write(result);
SystemAddress sysAddr = entity->GetSystemAddress();
SEND_PACKET;
}
inline void SendStop2DAmbientSound(Entity* entity, bool force, std::string audioGUID, bool result) {
CBITSTREAM;
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write(MessageType::Game::STOP2_D_AMBIENT_SOUND);
uint32_t audioGUIDSize = audioGUID.size();
bitStream.Write(force);
bitStream.Write(audioGUIDSize);
for (uint32_t k = 0; k < audioGUIDSize; k++) {
bitStream.Write<char>(audioGUID[k]);
}
bitStream.Write(result);
SystemAddress sysAddr = entity->GetSystemAddress();
SEND_PACKET;
}
inline void SendUIMessageServerToSingleClient(Entity* entity, const SystemAddress& sysAddr, const std::string& message, AMFBaseValue& args) {
CBITSTREAM;
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write(MessageType::Game::UI_MESSAGE_SERVER_TO_SINGLE_CLIENT);
bitStream.Write<AMFBaseValue&>(args);
uint32_t strMessageNameLength = message.size();
bitStream.Write(strMessageNameLength);
for (uint32_t k = 0; k < strMessageNameLength; k++) {
bitStream.Write<char>(message[k]);
}
SEND_PACKET;
}
inline void SendUIMessageServerToSingleClient(const std::string& message, AMFBaseValue& args, const SystemAddress& sysAddr) {
CBITSTREAM;
CMSGHEADER;
LWOOBJID empty = 0;
bitStream.Write(empty);
bitStream.Write(MessageType::Game::UI_MESSAGE_SERVER_TO_ALL_CLIENTS); // This is intentional to allow the server to send a ui message to a client via their system address.
bitStream.Write<AMFBaseValue&>(args);
uint32_t strMessageNameLength = message.size();
bitStream.Write(strMessageNameLength);
for (uint32_t k = 0; k < strMessageNameLength; k++) {
bitStream.Write<char>(message[k]);
}
SEND_PACKET;
}
inline void SendUIMessageServerToAllClients(const std::string& message, AMFBaseValue& args) {
CBITSTREAM;
CMSGHEADER;
LWOOBJID empty = 0;
bitStream.Write(empty);
bitStream.Write(MessageType::Game::UI_MESSAGE_SERVER_TO_ALL_CLIENTS);
bitStream.Write<AMFBaseValue&>(args);
uint32_t strMessageNameLength = message.size();
bitStream.Write(strMessageNameLength);
for (uint32_t k = 0; k < strMessageNameLength; k++) {
bitStream.Write<char>(message[k]);
}
SEND_PACKET_BROADCAST;
}
inline void SendStartCelebrationEffect(Entity* entity, const SystemAddress& sysAddr, int celebrationID) {
CBITSTREAM;
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write(MessageType::Game::START_CELEBRATION_EFFECT);
bitStream.Write<uint32_t>(0); //animation
bitStream.Write0(); //No custom bg obj
bitStream.Write0(); //custom path
bitStream.Write0(); //leadin
bitStream.Write0(); //leadout
bitStream.Write1();
bitStream.Write(celebrationID);
bitStream.Write<float>(0.0f); //duration
bitStream.Write<uint32_t>(0); //icon
bitStream.Write<uint32_t>(0); //text
bitStream.Write<uint32_t>(0); //mixer
bitStream.Write<uint32_t>(0); //cue
bitStream.Write<uint32_t>(0); //pathnodename
bitStream.Write<uint32_t>(0); //soundguid
bitStream.Write<uint32_t>(0); //subtext
SEND_PACKET;
}
inline void SendDisplayMessageBox(LWOOBJID objectId, bool bShow, LWOOBJID callbackClient, const std::u16string& identifier, int32_t imageID, const std::u16string& text, const std::u16string& userData, const SystemAddress& sysAddr) {
CBITSTREAM;
CMSGHEADER;
bitStream.Write(objectId);
bitStream.Write(MessageType::Game::DISPLAY_MESSAGE_BOX);
bitStream.Write(bShow);
bitStream.Write(callbackClient);
bitStream.Write<uint32_t>(identifier.size());
for (const auto character : identifier) {
bitStream.Write(character);
}
bitStream.Write(imageID);
bitStream.Write<uint32_t>(text.size());
for (const auto character : text) {
bitStream.Write(character);
}
bitStream.Write<uint32_t>(userData.size());
for (const auto character : userData) {
bitStream.Write(character);
}
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST;
SEND_PACKET;
}
inline void SendDisplayChatBubble(LWOOBJID objectId, const std::u16string& text, const SystemAddress& sysAddr) {
// MessageType::Game::DISPLAY_CHAT_BUBBLE
CBITSTREAM;
CMSGHEADER;
bitStream.Write(objectId);
bitStream.Write(MessageType::Game::DISPLAY_CHAT_BUBBLE);
bitStream.Write<uint32_t>(text.size());
for (const auto character : text) {
bitStream.Write(character);
}
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST;
SEND_PACKET;
}
inline void SendChangeIdleFlags(LWOOBJID objectId, eAnimationFlags flagsOn, eAnimationFlags flagsOff, const SystemAddress& sysAddr) {
CBITSTREAM;
CMSGHEADER;
bitStream.Write(objectId);
bitStream.Write(MessageType::Game::CHANGE_IDLE_FLAGS);
bitStream.Write<bool>(flagsOff != eAnimationFlags::IDLE_NONE);
if (flagsOff != eAnimationFlags::IDLE_NONE) bitStream.Write(flagsOff);
bitStream.Write<bool>(flagsOn != eAnimationFlags::IDLE_NONE);
if (flagsOn != eAnimationFlags::IDLE_NONE) bitStream.Write(flagsOn);
SEND_PACKET_BROADCAST;
}
inline void SendSetNamebillboardState(const SystemAddress& sysAddr, LWOOBJID objectId) {
CBITSTREAM;
CMSGHEADER;
bitStream.Write(objectId);
bitStream.Write(MessageType::Game::SET_NAME_BILLBOARD_STATE);
// Technically these bits would be written, however the client does not
// contain a deserialize method to actually deserialize, so we are leaving it out.
// As such this GM only turns the billboard off.
// bitStream.Write(overrideDefault);
// bitStream.Write(state);
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST
else SEND_PACKET
}
inline void SendShowBillboardInteractIcon(const SystemAddress& sysAddr, LWOOBJID objectId) {
CBITSTREAM;
CMSGHEADER;
bitStream.Write(objectId);
bitStream.Write(MessageType::Game::SHOW_BILLBOARD_INTERACT_ICON);
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST
else SEND_PACKET
}
inline void SendPlayCinematic(LWOOBJID objectId, std::u16string pathName, const SystemAddress& sysAddr,
bool allowGhostUpdates, bool bCloseMultiInteract, bool bSendServerNotify, bool bUseControlledObjectForAudioListener,
eEndBehavior endBehavior, bool hidePlayerDuringCine, float leadIn, bool leavePlayerLockedWhenFinished,
bool lockPlayer, bool result, bool skipIfSamePath, float startTimeAdvance) {
CBITSTREAM;
CMSGHEADER;
bitStream.Write(objectId);
bitStream.Write(MessageType::Game::PLAY_CINEMATIC);
bitStream.Write(allowGhostUpdates);
bitStream.Write(bCloseMultiInteract);
bitStream.Write(bSendServerNotify);
bitStream.Write(bUseControlledObjectForAudioListener);
bitStream.Write(endBehavior != eEndBehavior::RETURN);
if (endBehavior != eEndBehavior::RETURN) bitStream.Write(endBehavior);
bitStream.Write(hidePlayerDuringCine);
bitStream.Write(leadIn != -1);
if (leadIn != -1) bitStream.Write(leadIn);
bitStream.Write(leavePlayerLockedWhenFinished);
bitStream.Write(lockPlayer);
bitStream.Write<uint32_t>(pathName.size());
for (char16_t c : pathName) {
bitStream.Write(c);
}
bitStream.Write(result);
bitStream.Write(skipIfSamePath);
bitStream.Write(startTimeAdvance);
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST;
SEND_PACKET;
}
inline void SendEndCinematic(LWOOBJID objectId, std::u16string pathName, const SystemAddress& sysAddr,
float leadOut, bool leavePlayerLocked) {
CBITSTREAM;
CMSGHEADER;
bitStream.Write(objectId);
bitStream.Write(MessageType::Game::END_CINEMATIC);
bitStream.Write(leadOut != -1);
if (leadOut != -1) bitStream.Write(leadOut);
bitStream.Write(leavePlayerLocked);
bitStream.Write<uint32_t>(pathName.size());
for (uint32_t i = 0; i < pathName.size(); i++) {
bitStream.Write(pathName[i]);
}
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST;
SEND_PACKET;
}
inline void SendSlashCommandFeedbackText(Entity* entity, std::u16string text) {
CBITSTREAM;
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write(MessageType::Game::SLASH_COMMAND_TEXT_FEEDBACK);
bitStream.Write<uint32_t>(text.size());
bitStream.Write(text);
auto sysAddr = entity->GetSystemAddress();
SEND_PACKET;
}
inline void SendPlayEmote(LWOOBJID objectId, int32_t emoteID, LWOOBJID target, const SystemAddress& sysAddr) {
CBITSTREAM;
CMSGHEADER;
bitStream.Write(objectId);
bitStream.Write(MessageType::Game::PLAY_EMOTE);
bitStream.Write(emoteID);
bitStream.Write(target);
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST;
SEND_PACKET;
}
inline void SendSetEmoteLockState(Entity* entity, bool bLock, int emoteID) {
CBITSTREAM;
CMSGHEADER;
bitStream.Write(entity->GetObjectID());
bitStream.Write(MessageType::Game::SET_EMOTE_LOCK_STATE);
bitStream.Write(bLock);
bitStream.Write(emoteID);
SystemAddress sysAddr = entity->GetSystemAddress();
SEND_PACKET;
}
struct LegacyMessageBoxResponse { bool ok{}; int32_t iButton{}; std::u16string identifier; std::u16string userData; };
inline LegacyMessageBoxResponse ReadMessageBoxResponse(RakNet::BitStream& inStream) {
int32_t iButton;
uint32_t identifierLength;
std::u16string identifier;
uint32_t userDataLength;
std::u16string userData;
inStream.Read(iButton);
inStream.Read(identifierLength);
if (identifierLength > MAX_MESSAGE_LENGTH) return {};
for (size_t i = 0; i < identifierLength; i++) {
char16_t character;
inStream.Read(character);
identifier.push_back(character);
}
inStream.Read(userDataLength);
if (userDataLength > MAX_MESSAGE_LENGTH) return {};
for (size_t i = 0; i < userDataLength; i++) {
char16_t character;
inStream.Read(character);
userData.push_back(character);
}
return { true, iButton, identifier, userData };
}
struct LegacyChoiceBoxRespond { bool ok{}; int32_t iButton{}; std::u16string buttonIdentifier; std::u16string identifier; };
inline LegacyChoiceBoxRespond ReadChoiceBoxRespond(RakNet::BitStream& inStream) {
int32_t iButton;
uint32_t buttonIdentifierLength;
std::u16string buttonIdentifier;
uint32_t identifierLength;
std::u16string identifier;
inStream.Read(buttonIdentifierLength);
if (buttonIdentifierLength > MAX_MESSAGE_LENGTH) return {};
for (size_t i = 0; i < buttonIdentifierLength; i++) {
char16_t character;
inStream.Read(character);
buttonIdentifier.push_back(character);
}
inStream.Read(iButton);
inStream.Read(identifierLength);
if (identifierLength > MAX_MESSAGE_LENGTH) return {};
for (size_t i = 0; i < identifierLength; i++) {
char16_t character;
inStream.Read(character);
identifier.push_back(character);
}
return { true, iButton, buttonIdentifier, identifier };
}
struct LegacyCinematicUpdate { eCinematicEvent event; float_t overallTime; std::u16string pathName; float_t pathTime; int32_t waypoint; };
inline LegacyCinematicUpdate ReadCinematicUpdate(RakNet::BitStream& inStream) {
eCinematicEvent event;
if (!inStream.ReadBit()) {
event = eCinematicEvent::STARTED;
} else {
inStream.Read<eCinematicEvent>(event);
}
float_t overallTime;
if (!inStream.ReadBit()) {
overallTime = -1.0f;
} else {
inStream.Read<float_t>(overallTime);
}
uint32_t pathNameLength;
inStream.Read(pathNameLength);
std::u16string pathName;
for (size_t i = 0; i < pathNameLength; i++) {
char16_t character;
inStream.Read(character);
pathName.push_back(character);
}
float_t pathTime;
if (!inStream.ReadBit()) {
pathTime = -1.0f;
} else {
inStream.Read<float_t>(pathTime);
}
int32_t waypoint;
if (!inStream.ReadBit()) {
waypoint = -1;
} else {
inStream.Read<int32_t>(waypoint);
}
return { event, overallTime, pathName, pathTime, waypoint };
}
struct LegacyPlayEmote { int32_t emoteID; LWOOBJID targetID; };
inline LegacyPlayEmote ReadPlayEmote(RakNet::BitStream& inStream) {
int32_t emoteID;
LWOOBJID targetID;
inStream.Read(emoteID);
inStream.Read(targetID);
return { emoteID, targetID };
}
}
#endif // EFFECTSMESSAGESLEGACY_H