mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 10:53:44 +00:00
refactor: remaining game messages as structs, switch removed
Every game message still written or read by hand is now a NetGameMsg with Serialize and Deserialize, in per-domain files: - MovementMessages: teleport, platforms (resync and its request), orient to angle, node rotation lock, gravity scale, jetpack mode, control scheme, respawn checkpoint, rails (set/start, ready, cancel, arrived), mount inventory ID, dismount complete, possession ack, ghost reference override and position, camera cycling (eCameraTargetCyclingMode moves here). - ZoneMessages: player loaded (the old PLAYER_LOADED case), ready for updates, player ready, restore to post load stats, server done loading, invalid zone transfer list, zone summary display/dismissed, level processing complete, object world state, and the localized announcement WorldMigration wrote by hand. - PlayerMessages: chat mode, GM level, LEGO score, currency, reputation, GM invis, pickup currency, zone and player statistics, chat commands, bug reports, verify ack. - ObjectMessages: fire event client/server side, notify client (zone) object, notify object, script network vars, failed preconditions, terminate interaction, set name, request use, request server object info. - QuickBuildMessages: notify state, enable, cancel. - ActivityMessages gains match response/update/request, leaderboard request and data, shooting gallery score/rotation/fire, activity state change. - MissionMessages gains MissionDialogueCancelled (a no-op, as before). The wire structs left in GameMessages.h move to their domains (tooltip and emote to Effects, loot and item use to Inventory, model build to Building, behavior sound to Property, skill sets to Skill) and gain the missing direction. The dismount logic moves to PossessorComponent::OnDismountComplete. Every inbound message is registered in the GameMessageHandler map; the switch is gone, and GameMessages.cpp only holds the GameMsg/NetGameMsg base code. Call sites build the structs (NotifyClientObject, TerminateInteraction, Teleport, PlatformResync, FireEventClientSide, NotifyObject and NotifyClientZoneObject get convenience constructors like PlayFXEffect). Dead senders are dropped: SendSetShootingGalleryParams (no callers, field order was a guess), SendTeamPickupItem (the struct already existed), SendRequestActivitySummaryLeaderboardData (the struct covers it). Verified with RemainingMessagesTests: every old Send* function is frozen verbatim in Legacy/RemainingMessagesLegacy.h and compared byte for byte (same bits, destination and broadcast flag) over grids of inputs; every old Handle* read sequence is frozen as a Read* oracle and compared with the struct's Deserialize; round trips, truncation and a golden packet. PlayerLoaded (0x00dc36f0), SetGMLevel (0x00dd6230), MissionDialogueCancelled (0x00d9cc10) and LocalizedAnnouncementServerToSingleClient (0x00f23c50) were checked against the client. Behaviour notes: an inbound message that fails to deserialize is dropped, so ParseChatMessage over MAX_MESSAGE_LENGTH is dropped instead of truncated, and PLAYER_LOADED / READY_FOR_UPDATES / MISSION_DIALOGUE_CANCELLED now read their (unused) client fields. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
41
tests/dGameTests/LegacyPacketMacros.h
Normal file
41
tests/dGameTests/LegacyPacketMacros.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef LEGACYPACKETMACROS_H
|
||||
#define LEGACYPACKETMACROS_H
|
||||
|
||||
// FROZEN - DO NOT EDIT.
|
||||
// The packet macros and the free BitStreamUtils::WriteHeader the hand written packet code used (dCommonVars.h and
|
||||
// dNet/BitStreamUtils.h before the struct conversion). They were removed from the server once every packet became a
|
||||
// struct; the frozen oracles in the Legacy/ folders still use them, verbatim.
|
||||
|
||||
#include "BitStream.h"
|
||||
#include "BitStreamUtils.h"
|
||||
#include "Game.h"
|
||||
#include "MessageIdentifiers.h"
|
||||
#include "MessageType/Client.h"
|
||||
#include "ServiceType.h"
|
||||
#include "dServer.h"
|
||||
|
||||
#ifndef HEADER_SIZE
|
||||
#define HEADER_SIZE 8
|
||||
#endif
|
||||
#ifndef CBITSTREAM
|
||||
#define CBITSTREAM RakNet::BitStream bitStream;
|
||||
#define CINSTREAM RakNet::BitStream inStream(packet->data, packet->length, false);
|
||||
#define CINSTREAM_SKIP_HEADER CINSTREAM if (inStream.GetNumberOfUnreadBits() >= BYTES_TO_BITS(HEADER_SIZE)) inStream.IgnoreBytes(HEADER_SIZE); else inStream.IgnoreBits(inStream.GetNumberOfUnreadBits());
|
||||
#define CMSGHEADER BitStreamUtils::WriteHeader(bitStream, ServiceType::CLIENT, MessageType::Client::GAME_MSG);
|
||||
#define SEND_PACKET Game::server->Send(bitStream, sysAddr, false);
|
||||
#define SEND_PACKET_BROADCAST Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
||||
#endif
|
||||
|
||||
#ifndef BITSTREAMUTILS_HAS_WRITEHEADER
|
||||
namespace BitStreamUtils {
|
||||
template<typename T>
|
||||
void WriteHeader(RakNet::BitStream& bitStream, ServiceType connectionType, T internalPacketID) {
|
||||
bitStream.Write<MessageID>(ID_USER_PACKET_ENUM);
|
||||
bitStream.Write<ServiceType>(connectionType);
|
||||
bitStream.Write(static_cast<uint32_t>(internalPacketID));
|
||||
bitStream.Write<uint8_t>(0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // LEGACYPACKETMACROS_H
|
||||
@@ -10,6 +10,7 @@ SET(DGAMEMESSAGES_TESTS
|
||||
"PetMessagesTests.cpp"
|
||||
"PropertyMessagesTests.cpp"
|
||||
"RacingMessagesTests.cpp"
|
||||
"RemainingMessagesTests.cpp"
|
||||
"SkillMessagesTests.cpp"
|
||||
"UnSmashTests.cpp"
|
||||
"VendorMessagesTests.cpp"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "GameMessages.h"
|
||||
#include "InventoryMessages.h"
|
||||
#include "GameDependencies.h"
|
||||
#include "PacketTestUtils.h"
|
||||
#include "Entity.h"
|
||||
|
||||
1230
tests/dGameTests/dGameMessagesTests/Legacy/RemainingMessagesLegacy.h
Normal file
1230
tests/dGameTests/dGameMessagesTests/Legacy/RemainingMessagesLegacy.h
Normal file
File diff suppressed because it is too large
Load Diff
724
tests/dGameTests/dGameMessagesTests/RemainingMessagesTests.cpp
Normal file
724
tests/dGameTests/dGameMessagesTests/RemainingMessagesTests.cpp
Normal file
@@ -0,0 +1,724 @@
|
||||
#include "ActivityMessages.h"
|
||||
#include "GameDependencies.h"
|
||||
#include "GameMessageTestUtils.h"
|
||||
#include "Legacy/RemainingMessagesLegacy.h"
|
||||
#include "MovementMessages.h"
|
||||
#include "ObjectMessages.h"
|
||||
#include "PlayerMessages.h"
|
||||
#include "QuickBuildMessages.h"
|
||||
#include "ZoneMessages.h"
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
// Byte equality of the movement, zone, player, object, quickbuild and remaining activity game messages with the
|
||||
// frozen hand written functions they replaced (Legacy/RemainingMessagesLegacy.h).
|
||||
using namespace GameMessageTestUtils;
|
||||
|
||||
namespace {
|
||||
const std::vector<std::u16string> g_WStrings = { u"", u"ZonePlayer", u"é中", std::u16string(300, u'x') };
|
||||
const std::vector<std::string> g_Strings = { "", "base", "\xff\x80z", std::string(300, 'y') };
|
||||
const std::vector<LWOOBJID> g_Ids = { LWOOBJID_EMPTY, 0x1000000000000001LL, 0x0102030405060708LL };
|
||||
const std::vector<int32_t> g_Ints = { 0, -1, 1, 10, std::numeric_limits<int32_t>::max(), std::numeric_limits<int32_t>::min() };
|
||||
const std::vector<float> g_Floats = { 0.0f, 1.0f, 10.0f, 15.0f, -2.5f };
|
||||
const std::vector<NiPoint3> g_Points = { NiPoint3Constant::ZERO, NiPoint3(1.0f, 0.0f, -3.5f), NiPoint3(-100.0f, 25.0f, 1e6f) };
|
||||
const std::vector<NiQuaternion> g_Rotations = { QuatUtils::IDENTITY, NiQuaternion(0.5f, 0.5f, -0.5f, 0.5f), NiQuaternion(1.0f, 0.0f, 1.0f, 0.0f) };
|
||||
|
||||
bool Bit(uint32_t mask, int i) { return (mask >> i) & 1; }
|
||||
|
||||
// Compares every packet (bytes, destination, broadcast flag) the legacy call and the struct send.
|
||||
void ExpectSameSends(const std::function<void()>& legacySend, const std::function<void()>& structSend) {
|
||||
const auto legacyPackets = Capture(legacySend);
|
||||
const auto newPackets = Capture(structSend);
|
||||
ASSERT_FALSE(legacyPackets.empty());
|
||||
ASSERT_EQ(newPackets.size(), 1);
|
||||
for (const auto& legacyPacket : legacyPackets) EXPECT_PACKET_EQ(FromCapture(legacyPacket), FromCapture(newPackets[0]));
|
||||
EXPECT_EQ(legacyPackets[0].broadcast, newPackets[0].broadcast);
|
||||
EXPECT_EQ(legacyPackets[0].sysAddr, newPackets[0].sysAddr);
|
||||
}
|
||||
|
||||
// The broadcast-only legacy functions compared with Send(UNASSIGNED).
|
||||
void ExpectSameAsLegacyBroadcast(const std::function<void()>& legacySend, const GameMessages::NetGameMsg& msg) {
|
||||
ExpectSameSends(legacySend, [&] { msg.Send(UNASSIGNED_SYSTEM_ADDRESS); });
|
||||
}
|
||||
|
||||
// Reads msg's payload with a legacy read sequence and checks it consumed every bit.
|
||||
template<typename Result>
|
||||
Result ReadWithLegacy(const GameMessages::NetGameMsg& msg, const std::function<Result(RakNet::BitStream&)>& read) {
|
||||
RakNet::BitStream wire;
|
||||
msg.Serialize(wire);
|
||||
RakNet::BitStream legacyStream(wire.GetData(), wire.GetNumberOfBytesUsed(), false);
|
||||
auto result = read(legacyStream);
|
||||
EXPECT_EQ(legacyStream.GetReadOffset(), wire.GetNumberOfBitsUsed());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
class RemainingMessagesTests : public GameDependenciesTest {
|
||||
protected:
|
||||
void SetUp() override { SetUpDependencies(); }
|
||||
void TearDown() override { TearDownDependencies(); }
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------- Movement
|
||||
|
||||
TEST_F(RemainingMessagesTests, TeleportMatchesLegacy) {
|
||||
for (const auto target : g_Targets) {
|
||||
for (const auto& pos : g_Points) {
|
||||
for (const auto& rot : g_Rotations) {
|
||||
for (const bool setRotation : { false, true }) {
|
||||
GameMessages::Teleport msg(target, pos, rot, setRotation);
|
||||
for (const auto& address : g_Addresses) {
|
||||
ExpectSameSends([&] { LegacyGameMessages::SendTeleport(target, pos, rot, address, setRotation); }, [&] { msg.SendToClient(address); });
|
||||
}
|
||||
const auto copy = RoundTrip(msg);
|
||||
EXPECT_EQ(copy.pos, pos);
|
||||
EXPECT_EQ(copy.bIgnoreY, pos.y == 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RemainingMessagesTests, StartPathingAndPlatformResyncMatchLegacy) {
|
||||
for (const LOT lot : { 999, 12341, 9483, 11306, 6267 }) {
|
||||
info.lot = lot;
|
||||
Entity entity(0x1000000000000001LL, info);
|
||||
ExpectSameAsLegacyBroadcast([&] { LegacyGameMessages::SendStartPathing(&entity); }, [&] { GameMessages::StartPathing msg; msg.target = entity.GetObjectID(); return msg; }());
|
||||
for (uint32_t mask = 0; mask < 4; mask++) {
|
||||
for (const auto state : { eMovementPlatformState::Moving, eMovementPlatformState::Stationary, eMovementPlatformState::Stopped }) {
|
||||
for (const int32_t index : { 0, 1, 5 }) {
|
||||
GameMessages::PlatformResync msg(entity, Bit(mask, 0), index, index + 1, index + 2, state, Bit(mask, 1));
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) {
|
||||
LegacyGameMessages::SendPlatformResync(&entity, address, Bit(mask, 0), index, index + 1, index + 2, state, Bit(mask, 1));
|
||||
}, msg);
|
||||
RoundTrip(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GameMessages::PlatformResync rotated;
|
||||
rotated.qUnexpectedRotation = NiQuaternion(0.5f, 0.5f, -0.5f, 0.5f);
|
||||
const auto copy = RoundTrip(rotated);
|
||||
EXPECT_EQ(copy.qUnexpectedRotation, rotated.qUnexpectedRotation);
|
||||
}
|
||||
|
||||
TEST_F(RemainingMessagesTests, SmallMovementMessagesMatchLegacy) {
|
||||
for (const auto target : g_Targets) {
|
||||
Entity entity(target, info);
|
||||
for (const float value : g_Floats) {
|
||||
for (const bool relative : { false, true }) {
|
||||
GameMessages::OrientToAngle orient;
|
||||
orient.target = target;
|
||||
orient.bRelativeToCurrent = relative;
|
||||
orient.fAngle = value;
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendOrientToAngle(target, relative, value, address); }, orient);
|
||||
RoundTrip(orient);
|
||||
}
|
||||
GameMessages::SetGravityScale gravity;
|
||||
gravity.target = target;
|
||||
gravity.scale = value;
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendSetGravityScale(target, value, address); }, gravity, SendMode::SendToClient);
|
||||
RoundTrip(gravity);
|
||||
}
|
||||
for (const auto& name : g_Strings) {
|
||||
GameMessages::LockNodeRotation lock;
|
||||
lock.target = target;
|
||||
lock.nodeName = name;
|
||||
ExpectSameAsLegacyBroadcast([&] { LegacyGameMessages::SendLockNodeRotation(&entity, name); }, lock);
|
||||
EXPECT_EQ(RoundTrip(lock).nodeName, name);
|
||||
}
|
||||
for (const auto id : g_Ids) {
|
||||
GameMessages::SetMountInventoryID mount;
|
||||
mount.target = target;
|
||||
mount.inventoryMountID = id;
|
||||
ExpectSameAsLegacyBroadcast([&] { LegacyGameMessages::SendSetMountInventoryID(&entity, id, UNASSIGNED_SYSTEM_ADDRESS); }, mount);
|
||||
RoundTrip(mount);
|
||||
}
|
||||
for (const auto scheme : { eControlScheme::SCHEME_A, eControlScheme::SCHEME_D, static_cast<eControlScheme>(9) }) {
|
||||
GameMessages::SetPlayerControlScheme msg;
|
||||
msg.target = target;
|
||||
msg.iScheme = scheme;
|
||||
ExpectSameSends([&] { LegacyGameMessages::SendSetPlayerControlScheme(&entity, scheme); }, [&] { msg.SendToClient(entity.GetSystemAddress()); });
|
||||
RoundTrip(msg);
|
||||
}
|
||||
for (const auto& pos : g_Points) {
|
||||
for (const auto& rot : g_Rotations) {
|
||||
GameMessages::PlayerReachedRespawnCheckpoint msg;
|
||||
msg.target = target;
|
||||
msg.pos = pos;
|
||||
msg.rot = rot;
|
||||
ExpectSameSends([&] { LegacyGameMessages::SendPlayerReachedRespawnCheckpoint(&entity, pos, rot); }, [&] { msg.SendToClient(entity.GetSystemAddress()); });
|
||||
EXPECT_EQ(RoundTrip(msg).rot, rot);
|
||||
}
|
||||
}
|
||||
for (const auto mode : { eCameraTargetCyclingMode::ALLOW_CYCLE_TEAMMATES, eCameraTargetCyclingMode::DISALLOW_CYCLING }) {
|
||||
for (const auto id : g_Ids) {
|
||||
for (const bool force : { false, true }) {
|
||||
GameMessages::ForceCameraTargetCycle msg;
|
||||
msg.target = target;
|
||||
msg.bForceCycling = force;
|
||||
msg.cyclingMode = mode;
|
||||
msg.optionalTargetID = id;
|
||||
ExpectSameSends([&] { LegacyGameMessages::SendForceCameraTargetCycle(&entity, force, mode, id); }, [&] { msg.SendToClient(entity.GetSystemAddress()); });
|
||||
RoundTrip(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto mode : { eCyclingMode::ALLOW_CYCLE_TEAMMATES, eCyclingMode::DISALLOW_CYCLING }) {
|
||||
for (const bool deadOnly : { false, true }) {
|
||||
GameMessages::PlayerSetCameraCyclingMode msg;
|
||||
msg.target = target;
|
||||
msg.bAllowCyclingWhileDeadOnly = deadOnly;
|
||||
msg.cyclingMode = mode;
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendPlayerSetCameraCyclingMode(target, address, deadOnly, mode); }, msg, SendMode::SendToClient);
|
||||
RoundTrip(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RemainingMessagesTests, SetJetPackModeMatchesLegacy) {
|
||||
Entity entity(0x0102030405060708LL, info);
|
||||
for (uint32_t mask = 0; mask < 8; mask++) {
|
||||
for (const int32_t effect : { -1, 167 }) {
|
||||
for (const float speed : g_Floats) {
|
||||
for (const int32_t warning : { -1, 5 }) {
|
||||
GameMessages::SetJetPackMode msg;
|
||||
msg.target = entity.GetObjectID();
|
||||
msg.bUse = Bit(mask, 0);
|
||||
msg.bBypassChecks = Bit(mask, 1);
|
||||
msg.bDoHover = Bit(mask, 2);
|
||||
msg.effectID = effect;
|
||||
msg.fAirspeed = speed;
|
||||
msg.fMaxAirspeed = speed;
|
||||
msg.fVertVel = speed;
|
||||
msg.iWarningEffectID = warning;
|
||||
ExpectSameAsLegacyBroadcast([&] { LegacyGameMessages::SendSetJetPackMode(&entity, Bit(mask, 0), Bit(mask, 1), Bit(mask, 2), effect, speed, speed, speed, warning); }, msg);
|
||||
RoundTrip(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RemainingMessagesTests, RailMovementMatchesLegacy) {
|
||||
for (const auto target : g_Targets) {
|
||||
for (const auto& path : g_WStrings) {
|
||||
for (const uint32_t start : { 0u, 3u }) {
|
||||
for (const int32_t component : { -1, 0, 42 }) {
|
||||
for (const auto activator : g_Ids) {
|
||||
for (uint32_t mask = 0; mask < 2; mask++) {
|
||||
GameMessages::SetRailMovement set;
|
||||
set.target = target;
|
||||
set.pathGoForward = Bit(mask, 0);
|
||||
set.pathName = path;
|
||||
set.pathStart = start;
|
||||
set.railActivatorComponentID = component;
|
||||
set.railActivatorObjectID = activator;
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendSetRailMovement(target, Bit(mask, 0), path, start, address, component, activator); }, set);
|
||||
EXPECT_EQ(RoundTrip(set).pathName, path);
|
||||
}
|
||||
for (uint32_t mask = 0; mask < 256; mask += 37) {
|
||||
GameMessages::StartRailMovement msg;
|
||||
msg.target = target;
|
||||
msg.pathName = path;
|
||||
msg.startSound = u"start";
|
||||
msg.loopSound = path;
|
||||
msg.stopSound = u"";
|
||||
msg.pathStart = start;
|
||||
msg.goForward = Bit(mask, 0);
|
||||
msg.bDamageImmune = Bit(mask, 1);
|
||||
msg.bNoAggro = Bit(mask, 2);
|
||||
msg.bNotifyActor = Bit(mask, 3);
|
||||
msg.bShowNameBillboard = Bit(mask, 4);
|
||||
msg.bCameraLocked = Bit(mask, 5);
|
||||
msg.bCollisionEnabled = Bit(mask, 6);
|
||||
msg.bUseDB = Bit(mask, 7);
|
||||
msg.railActivatorComponentID = component;
|
||||
msg.railActivatorObjectID = activator;
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) {
|
||||
LegacyGameMessages::SendStartRailMovement(target, path, u"start", path, u"", address, start, Bit(mask, 0), Bit(mask, 1), Bit(mask, 2),
|
||||
Bit(mask, 3), Bit(mask, 4), Bit(mask, 5), Bit(mask, 6), Bit(mask, 7), component, activator);
|
||||
}, msg);
|
||||
RoundTrip(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RemainingMessagesTests, InboundMovementMatchesLegacy) {
|
||||
for (const auto id : g_Ids) {
|
||||
GameMessages::DismountComplete dismount;
|
||||
dismount.mountID = id;
|
||||
EXPECT_EQ(ReadWithLegacy<LWOOBJID>(dismount, LegacyGameMessages::ReadDismountComplete), id);
|
||||
EXPECT_EQ(RoundTrip(dismount).mountID, id);
|
||||
ExpectTruncatedFails(dismount);
|
||||
|
||||
GameMessages::AcknowledgePossession ack;
|
||||
ack.possessedObjID = id;
|
||||
EXPECT_EQ(ReadWithLegacy<LWOOBJID>(ack, LegacyGameMessages::ReadAcknowledgePossession), id);
|
||||
EXPECT_EQ(RoundTrip(ack).possessedObjID, id);
|
||||
ExpectTruncatedFails(ack);
|
||||
}
|
||||
for (const bool value : { false, true }) {
|
||||
GameMessages::ToggleGhostReferenceOverride toggle;
|
||||
toggle.bOverride = value;
|
||||
EXPECT_EQ(ReadWithLegacy<bool>(toggle, LegacyGameMessages::ReadToggleGhostReferenceOverride), value);
|
||||
ExpectTruncatedFails(toggle);
|
||||
|
||||
GameMessages::CancelRailMovement cancel;
|
||||
cancel.bImmediate = value;
|
||||
EXPECT_EQ(ReadWithLegacy<bool>(cancel, LegacyGameMessages::ReadCancelRailMovement), value);
|
||||
ExpectTruncatedFails(cancel);
|
||||
}
|
||||
for (const auto& pos : g_Points) {
|
||||
GameMessages::SetGhostReferencePosition ghost;
|
||||
ghost.pos = pos;
|
||||
EXPECT_EQ(ReadWithLegacy<NiPoint3>(ghost, LegacyGameMessages::ReadSetGhostReferencePosition), pos);
|
||||
ExpectTruncatedFails(ghost);
|
||||
}
|
||||
for (const auto& path : g_WStrings) {
|
||||
for (const int32_t waypoint : g_Ints) {
|
||||
GameMessages::PlayerRailArrivedNotification arrived;
|
||||
arrived.pathName = path;
|
||||
arrived.waypointNumber = waypoint;
|
||||
const auto legacy = ReadWithLegacy<LegacyGameMessages::LegacyRailArrived>(arrived, LegacyGameMessages::ReadPlayerRailArrivedNotification);
|
||||
EXPECT_EQ(legacy.pathName, path);
|
||||
EXPECT_EQ(legacy.waypointNumber, waypoint);
|
||||
RoundTrip(arrived);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- Zone
|
||||
|
||||
TEST_F(RemainingMessagesTests, ZoneMessagesMatchLegacy) {
|
||||
for (const auto target : g_Targets) {
|
||||
Entity entity(target, info);
|
||||
GameMessages::PlayerReady ready;
|
||||
ready.target = target;
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendPlayerReady(&entity, address); }, ready, SendMode::SendToClient);
|
||||
GameMessages::RestoreToPostLoadStats restore;
|
||||
restore.target = target;
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendRestoreToPostLoadStats(&entity, address); }, restore, SendMode::SendToClient);
|
||||
GameMessages::ServerDoneLoadingAllObjects done;
|
||||
done.target = target;
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendServerDoneLoadingAllObjects(&entity, address); }, done, SendMode::SendToClient);
|
||||
|
||||
for (const auto& url : g_WStrings) {
|
||||
for (uint32_t mask = 0; mask < 4; mask++) {
|
||||
GameMessages::InvalidZoneTransferList list;
|
||||
list.target = target;
|
||||
list.customerFeedbackURL = url;
|
||||
list.invalidMapTransferList = u"1000,1001";
|
||||
list.bCustomerFeedbackOnExit = Bit(mask, 0);
|
||||
list.bCustomerFeedbackOnInvalidMapTransfer = Bit(mask, 1);
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendInvalidZoneTransferList(&entity, address, url, u"1000,1001", Bit(mask, 0), Bit(mask, 1)); }, list, SendMode::SendToClient);
|
||||
RoundTrip(list);
|
||||
}
|
||||
GameMessages::LocalizedAnnouncementServerToSingleClient announcement;
|
||||
announcement.target = target;
|
||||
announcement.body = url;
|
||||
announcement.title = u"UI_TITLE";
|
||||
ExpectSameSends([&] { LegacyGameMessages::SendLocalizedAnnouncement(&entity, url, u"UI_TITLE"); }, [&] { announcement.SendToClient(entity.GetSystemAddress()); });
|
||||
EXPECT_EQ(RoundTrip(announcement).body, url);
|
||||
}
|
||||
for (const auto sender : g_Ids) {
|
||||
for (uint32_t mask = 0; mask < 4; mask++) {
|
||||
GameMessages::DisplayZoneSummary summary;
|
||||
summary.target = target;
|
||||
summary.isPropertyMap = Bit(mask, 0);
|
||||
summary.isZoneStart = Bit(mask, 1);
|
||||
summary.sender = sender;
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendDisplayZoneSummary(target, address, Bit(mask, 0), Bit(mask, 1), sender); }, summary);
|
||||
RoundTrip(summary);
|
||||
}
|
||||
GameMessages::ZoneSummaryDismissed dismissed;
|
||||
dismissed.playerID = sender;
|
||||
EXPECT_EQ(ReadWithLegacy<LWOOBJID>(dismissed, LegacyGameMessages::ReadZoneSummaryDismissed), sender);
|
||||
ExpectTruncatedFails(dismissed);
|
||||
}
|
||||
for (const auto state : { eObjectWorldState::INWORLD, eObjectWorldState::ATTACHED, eObjectWorldState::INVENTORY }) {
|
||||
GameMessages::ChangeObjectWorldState msg;
|
||||
msg.target = target;
|
||||
msg.newState = state;
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendChangeObjectWorldState(target, state, address); }, msg);
|
||||
RoundTrip(msg);
|
||||
}
|
||||
}
|
||||
// Name-value text: a null terminator follows non-empty text and is not counted.
|
||||
GameMessages::LocalizedAnnouncementServerToSingleClient withParams;
|
||||
withParams.bodyParams = u"name=0:Bob";
|
||||
withParams.titleParams = u"x=1:2";
|
||||
const auto copy = RoundTrip(withParams);
|
||||
EXPECT_EQ(copy.bodyParams, withParams.bodyParams);
|
||||
EXPECT_EQ(copy.titleParams, withParams.titleParams);
|
||||
ExpectTruncatedFails(withParams);
|
||||
}
|
||||
|
||||
TEST_F(RemainingMessagesTests, ZoneGoldenBytes) {
|
||||
GameMessages::DisplayZoneSummary summary;
|
||||
summary.target = 0x0102030405060708LL;
|
||||
summary.isZoneStart = true;
|
||||
summary.sender = 0x1122334455667788LL;
|
||||
// header 53 05 00 0c 00 00 00 00, target, msgId 1043 (u16), bits 0 1 1 then the sender
|
||||
EXPECT_PACKET_EQ(FromHex("5305000c00000000" "0807060504030201" "1304" "710eeccaa886644220", 211), StructPacket(summary));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- Player
|
||||
|
||||
TEST_F(RemainingMessagesTests, PlayerMessagesMatchLegacy) {
|
||||
for (const auto target : g_Targets) {
|
||||
Entity entity(target, info);
|
||||
for (const auto level : { eGameMasterLevel::CIVILIAN, eGameMasterLevel::DEVELOPER, eGameMasterLevel::OPERATOR }) {
|
||||
GameMessages::UpdateChatMode chat;
|
||||
chat.target = target;
|
||||
chat.level = level;
|
||||
ExpectSameAsLegacyBroadcast([&] { LegacyGameMessages::SendChatModeUpdate(target, level); }, chat);
|
||||
RoundTrip(chat);
|
||||
GameMessages::SetGMLevel gm;
|
||||
gm.target = target;
|
||||
gm.level = level;
|
||||
ExpectSameAsLegacyBroadcast([&] { LegacyGameMessages::SendGMLevelBroadcast(target, level); }, gm);
|
||||
RoundTrip(gm);
|
||||
}
|
||||
for (const int64_t value : { 0LL, -5LL, 123456789012LL }) {
|
||||
for (const auto source : { eLootSourceType::NONE, eLootSourceType::MISSION, eLootSourceType::PICKUP }) {
|
||||
GameMessages::ModifyLEGOScore score;
|
||||
score.target = target;
|
||||
score.score = value;
|
||||
score.sourceType = source;
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendModifyLEGOScore(&entity, address, value, source); }, score, SendMode::SendToClient);
|
||||
RoundTrip(score);
|
||||
for (const int32_t smallValue : { 0, 7 }) {
|
||||
GameMessages::SetCurrency currency;
|
||||
currency.target = target;
|
||||
currency.currency = value;
|
||||
currency.lootType = smallValue;
|
||||
currency.sourceID = smallValue;
|
||||
currency.sourceLOT = smallValue;
|
||||
currency.sourceTradeID = smallValue;
|
||||
currency.sourceType = source;
|
||||
ExpectSameSends([&] { LegacyGameMessages::SendSetCurrency(&entity, value, smallValue, smallValue, smallValue, smallValue, true, source); }, [&] { currency.SendToClient(entity.GetSystemAddress()); });
|
||||
RoundTrip(currency);
|
||||
}
|
||||
}
|
||||
GameMessages::UpdateReputation reputation;
|
||||
reputation.target = target;
|
||||
reputation.reputation = value;
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendUpdateReputation(target, value, address); }, reputation, SendMode::SendToClient);
|
||||
RoundTrip(reputation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RemainingMessagesTests, InboundPlayerMessagesMatchLegacy) {
|
||||
for (const uint32_t amount : { 0u, 1u, 0xffffffffu }) {
|
||||
GameMessages::PickupCurrency pickup;
|
||||
pickup.currency = amount;
|
||||
EXPECT_EQ(ReadWithLegacy<unsigned int>(pickup, LegacyGameMessages::ReadPickupCurrency), amount);
|
||||
ExpectTruncatedFails(pickup);
|
||||
}
|
||||
for (const auto& name : g_WStrings) {
|
||||
for (const int32_t value : g_Ints) {
|
||||
for (const LWOMAPID zone : { LWOMAPID_INVALID, LWOMAPID{ 1100 } }) {
|
||||
GameMessages::ModifyPlayerZoneStatistic stat;
|
||||
stat.bSet = value > 0;
|
||||
stat.statName = name;
|
||||
stat.statValue = value;
|
||||
stat.zoneID = zone;
|
||||
const auto legacy = ReadWithLegacy<LegacyGameMessages::LegacyZoneStatistic>(stat, LegacyGameMessages::ReadModifyPlayerZoneStatistic);
|
||||
EXPECT_EQ(legacy.set, stat.bSet);
|
||||
EXPECT_EQ(legacy.statisticsName, name);
|
||||
EXPECT_EQ(legacy.value, value);
|
||||
EXPECT_EQ(legacy.zone, zone);
|
||||
RoundTrip(stat);
|
||||
}
|
||||
}
|
||||
GameMessages::ParseChatMessage chat;
|
||||
chat.iClientState = 3;
|
||||
chat.wsString = name;
|
||||
const auto legacyChat = ReadWithLegacy<LegacyGameMessages::LegacyParseChatMessage>(chat, LegacyGameMessages::ReadParseChatMessage);
|
||||
EXPECT_EQ(legacyChat.iClientState, 3);
|
||||
EXPECT_EQ(legacyChat.wsString, name);
|
||||
RoundTrip(chat);
|
||||
|
||||
GameMessages::ReportBug report;
|
||||
report.body = name;
|
||||
report.clientVersion = "1.10.64";
|
||||
report.otherPlayerID = "0";
|
||||
report.selection = "selection";
|
||||
const auto legacyReport = ReadWithLegacy<LegacyGameMessages::LegacyBugReport>(report, LegacyGameMessages::ReadReportBug);
|
||||
std::string narrowed;
|
||||
for (const auto character : name) narrowed.push_back(static_cast<char>(character));
|
||||
EXPECT_EQ(legacyReport.body, narrowed);
|
||||
EXPECT_EQ(legacyReport.clientVersion, "1.10.64");
|
||||
EXPECT_EQ(legacyReport.otherPlayer, "0");
|
||||
EXPECT_EQ(legacyReport.selection, "selection");
|
||||
RoundTrip(report);
|
||||
}
|
||||
for (const int32_t id : g_Ints) {
|
||||
for (const int64_t value : { int64_t{ 1 }, int64_t{ 0 }, int64_t{ -7 }, int64_t{ 1 } << 40 }) {
|
||||
GameMessages::UpdatePlayerStatistic stat;
|
||||
stat.updateID = id;
|
||||
stat.updateValue = value;
|
||||
const auto legacy = ReadWithLegacy<LegacyGameMessages::LegacyPlayerStatistic>(stat, LegacyGameMessages::ReadUpdatePlayerStatistic);
|
||||
EXPECT_EQ(legacy.updateID, id);
|
||||
EXPECT_EQ(legacy.updateValue, value);
|
||||
ExpectTruncatedFails(stat);
|
||||
}
|
||||
}
|
||||
for (const auto& bytes : g_Strings) {
|
||||
for (const uint32_t handle : { 0u, 9u }) {
|
||||
GameMessages::VerifyAck ack;
|
||||
ack.bDifferent = handle != 0;
|
||||
ack.sBitStream = bytes;
|
||||
ack.uiHandle = handle;
|
||||
const auto legacy = ReadWithLegacy<LegacyGameMessages::LegacyVerifyAck>(ack, LegacyGameMessages::ReadVerifyAck);
|
||||
EXPECT_EQ(legacy.bDifferent, ack.bDifferent);
|
||||
EXPECT_EQ(legacy.sBitStream, bytes);
|
||||
EXPECT_EQ(legacy.uiHandle, handle);
|
||||
RoundTrip(ack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- Objects and scripts
|
||||
|
||||
TEST_F(RemainingMessagesTests, NotifyMessagesMatchLegacy) {
|
||||
for (const auto target : g_Targets) {
|
||||
for (const auto& name : g_WStrings) {
|
||||
for (const int32_t param : g_Ints) {
|
||||
for (const auto& paramStr : g_Strings) {
|
||||
GameMessages::NotifyClientObject notify(target, name, param, -param, target, paramStr);
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendNotifyClientObject(target, name, param, -param, target, paramStr, address); }, notify);
|
||||
EXPECT_EQ(RoundTrip(notify).paramStr, paramStr);
|
||||
GameMessages::NotifyClientZoneObject zoneNotify(target, name, param, -param, target, paramStr);
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendNotifyClientZoneObject(target, name, param, -param, target, paramStr, address); }, zoneNotify);
|
||||
RoundTrip(zoneNotify);
|
||||
}
|
||||
GameMessages::NotifyObject notifyObject(target, 0x1000000000000001LL, name, param, param / 2);
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendNotifyObject(target, 0x1000000000000001LL, name, address, param, param / 2); }, notifyObject);
|
||||
RoundTrip(notifyObject);
|
||||
GameMessages::NotifyClientFailedPrecondition precondition;
|
||||
precondition.target = target;
|
||||
precondition.failedReason = name;
|
||||
precondition.preconditionID = param;
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendNotifyClientFailedPrecondition(target, address, name, param); }, precondition);
|
||||
RoundTrip(precondition);
|
||||
}
|
||||
for (const auto object : g_Ids) {
|
||||
// The old function never wrote param1 or param2 (both flags always 0), whatever it was given.
|
||||
GameMessages::FireEventClientSide fire(target, name, object, 0x0102030405060708LL);
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendFireEventClientSide(target, address, name, object, 5, 6, 0x0102030405060708LL); }, fire, SendMode::SendToClient);
|
||||
RoundTrip(fire);
|
||||
}
|
||||
GameMessages::SetName setName;
|
||||
setName.target = target;
|
||||
setName.name = name;
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendSetName(target, name, address); }, setName);
|
||||
RoundTrip(setName);
|
||||
}
|
||||
Entity entity(target, info);
|
||||
for (const auto& data : g_Strings) {
|
||||
GameMessages::ScriptNetworkVarUpdate scriptVar;
|
||||
scriptVar.target = target;
|
||||
scriptVar.tableOfVars = GeneralUtils::ASCIIToUTF16(data);
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendSetNetworkScriptVar(&entity, address, data); }, scriptVar);
|
||||
RoundTrip(scriptVar);
|
||||
}
|
||||
for (const auto type : { eTerminateType::RANGE, eTerminateType::USER, eTerminateType::FROM_INTERACTION }) {
|
||||
for (const auto terminator : g_Ids) {
|
||||
GameMessages::TerminateInteraction terminate(target, type, terminator);
|
||||
ExpectSameAsLegacyBroadcast([&] { LegacyGameMessages::SendTerminateInteraction(target, type, terminator); }, terminate);
|
||||
RoundTrip(terminate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RemainingMessagesTests, FireEventServerSideMatchesLegacy) {
|
||||
for (const auto& args : g_WStrings) {
|
||||
for (const int32_t param : g_Ints) {
|
||||
for (const auto sender : g_Ids) {
|
||||
GameMessages::FireEventServerSide fire;
|
||||
fire.args = args;
|
||||
fire.param1 = param;
|
||||
fire.param2 = -1;
|
||||
fire.param3 = param / 3;
|
||||
fire.senderID = sender;
|
||||
const auto legacy = ReadWithLegacy<LegacyGameMessages::LegacyFireEventServerSide>(fire, LegacyGameMessages::ReadFireEventServerSide);
|
||||
EXPECT_EQ(legacy.args, args);
|
||||
EXPECT_EQ(legacy.param1, param);
|
||||
EXPECT_EQ(legacy.param2, -1);
|
||||
EXPECT_EQ(legacy.param3, param / 3);
|
||||
EXPECT_EQ(legacy.senderID, sender);
|
||||
RoundTrip(fire);
|
||||
}
|
||||
}
|
||||
}
|
||||
GameMessages::FireEventServerSide fire;
|
||||
fire.args = u"ZonePlayer";
|
||||
fire.param3 = 1100;
|
||||
ExpectTruncatedFails(fire);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- Quickbuild
|
||||
|
||||
TEST_F(RemainingMessagesTests, QuickBuildMessagesMatchLegacy) {
|
||||
for (const auto target : g_Targets) {
|
||||
Entity entity(target, info);
|
||||
for (const auto player : g_Ids) {
|
||||
for (const auto state : { eQuickBuildState::OPEN, eQuickBuildState::COMPLETED, eQuickBuildState::BUILDING }) {
|
||||
GameMessages::RebuildNotifyState notify;
|
||||
notify.target = target;
|
||||
notify.prevState = eQuickBuildState::RESETTING;
|
||||
notify.state = state;
|
||||
notify.player = player;
|
||||
ExpectSameAsLegacyBroadcast([&] { LegacyGameMessages::SendQuickBuildNotifyState(&entity, eQuickBuildState::RESETTING, state, player); }, notify);
|
||||
RoundTrip(notify);
|
||||
}
|
||||
for (uint32_t mask = 0; mask < 8; mask++) {
|
||||
for (const auto reason : { eQuickBuildFailReason::NOT_GIVEN, eQuickBuildFailReason::CANCELED_EARLY, eQuickBuildFailReason::OUT_OF_IMAGINATION }) {
|
||||
for (const float duration : g_Floats) {
|
||||
GameMessages::EnableRebuild enable;
|
||||
enable.target = target;
|
||||
enable.bEnable = Bit(mask, 0);
|
||||
enable.bFail = Bit(mask, 1);
|
||||
enable.bSuccess = Bit(mask, 2);
|
||||
enable.eFailReason = reason;
|
||||
enable.fDuration = duration;
|
||||
enable.user = player;
|
||||
ExpectSameAsLegacyBroadcast([&] { LegacyGameMessages::SendEnableQuickBuild(&entity, Bit(mask, 0), Bit(mask, 1), Bit(mask, 2), reason, duration, player); }, enable);
|
||||
RoundTrip(enable);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const bool early : { false, true }) {
|
||||
GameMessages::RebuildCancel cancel;
|
||||
cancel.bEarlyRelease = early;
|
||||
cancel.userID = player;
|
||||
const auto legacy = ReadWithLegacy<LegacyGameMessages::LegacyQuickBuildCancel>(cancel, LegacyGameMessages::ReadQuickBuildCancel);
|
||||
EXPECT_EQ(legacy.bEarlyRelease, early);
|
||||
EXPECT_EQ(legacy.userID, player);
|
||||
ExpectTruncatedFails(cancel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- Activities
|
||||
|
||||
TEST_F(RemainingMessagesTests, ActivityMessagesMatchLegacy) {
|
||||
for (const auto target : g_Targets) {
|
||||
Entity entity(target, info);
|
||||
for (const int32_t value : g_Ints) {
|
||||
GameMessages::MatchResponse response;
|
||||
response.target = target;
|
||||
response.response = value;
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendMatchResponse(&entity, address, value); }, response, SendMode::SendToClient);
|
||||
RoundTrip(response);
|
||||
}
|
||||
for (const auto& data : g_Strings) {
|
||||
for (const auto type : { eMatchUpdate::PLAYER_ADDED, eMatchUpdate::PHASE_WAIT_READY }) {
|
||||
GameMessages::MatchUpdate update;
|
||||
update.target = target;
|
||||
update.data = data;
|
||||
update.type = type;
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendMatchUpdate(&entity, address, data, type); }, update, SendMode::SendToClient);
|
||||
EXPECT_EQ(RoundTrip(update).data, data);
|
||||
|
||||
GameMessages::MatchRequest request;
|
||||
request.activator = target;
|
||||
request.playerChoices = data;
|
||||
request.type = 1;
|
||||
request.value = static_cast<int32_t>(type);
|
||||
const auto legacy = ReadWithLegacy<LegacyGameMessages::LegacyMatchRequest>(request, LegacyGameMessages::ReadMatchRequest);
|
||||
EXPECT_EQ(legacy.activator, target);
|
||||
EXPECT_EQ(legacy.playerChoices, data);
|
||||
EXPECT_EQ(legacy.type, 1);
|
||||
EXPECT_EQ(legacy.value, request.value);
|
||||
RoundTrip(request);
|
||||
}
|
||||
}
|
||||
for (const auto& pos : g_Points) {
|
||||
for (const int32_t score : { 0, 1500, -1 }) {
|
||||
GameMessages::NotifyClientShootingGalleryScore galleryScore;
|
||||
galleryScore.target = target;
|
||||
galleryScore.addTime = 2.5f;
|
||||
galleryScore.score = score;
|
||||
galleryScore.targetID = 0x1000000000000001LL;
|
||||
galleryScore.targetPos = pos;
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendNotifyClientShootingGalleryScore(target, address, 2.5f, score, 0x1000000000000001LL, pos); }, galleryScore);
|
||||
RoundTrip(galleryScore);
|
||||
}
|
||||
GameMessages::UpdateShootingGalleryRotation rotation;
|
||||
rotation.angle = 1.25f;
|
||||
rotation.facing = pos;
|
||||
rotation.muzzlePos = NiPoint3(1.0f, 2.0f, 3.0f);
|
||||
const auto legacy = ReadWithLegacy<LegacyGameMessages::LegacyShootingGalleryRotation>(rotation, LegacyGameMessages::ReadUpdateShootingGalleryRotation);
|
||||
EXPECT_EQ(legacy.angle, 1.25f);
|
||||
EXPECT_EQ(legacy.facing, pos);
|
||||
EXPECT_EQ(legacy.muzzlePos, rotation.muzzlePos);
|
||||
ExpectTruncatedFails(rotation);
|
||||
}
|
||||
for (const auto& text : g_WStrings) {
|
||||
GameMessages::ActivityStateChangeRequest change;
|
||||
change.objectID = target;
|
||||
change.value1 = 4;
|
||||
change.value2 = -4;
|
||||
change.stringValue = text;
|
||||
const auto legacy = ReadWithLegacy<LegacyGameMessages::LegacyActivityStateChangeRequest>(change, LegacyGameMessages::ReadActivityStateChangeRequest);
|
||||
EXPECT_EQ(legacy.objectID, target);
|
||||
EXPECT_EQ(legacy.value1, 4);
|
||||
EXPECT_EQ(legacy.value2, -4);
|
||||
EXPECT_EQ(legacy.stringValue, text);
|
||||
RoundTrip(change);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RemainingMessagesTests, LeaderboardMessagesMatchLegacy) {
|
||||
for (const int32_t gameID : { 0, 1864 }) {
|
||||
for (const int32_t queryType : { 0, 1, 2 }) {
|
||||
for (const int32_t end : { 10, 0 }) {
|
||||
for (const int32_t start : { 0, 5 }) {
|
||||
for (const bool weekly : { false, true }) {
|
||||
GameMessages::RequestActivitySummaryLeaderboardData msg;
|
||||
msg.target = 0x0102030405060708LL;
|
||||
msg.gameID = gameID;
|
||||
msg.queryType = queryType;
|
||||
msg.resultsEnd = end;
|
||||
msg.resultsStart = start;
|
||||
msg.weekly = weekly;
|
||||
msg.targetID = 0x0102030405060708LL;
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) {
|
||||
LegacyGameMessages::SendRequestActivitySummaryLeaderboardData(0x0102030405060708LL, 0x0102030405060708LL, address, gameID, queryType, end, start, weekly);
|
||||
}, msg, SendMode::SendToClient);
|
||||
const auto legacy = ReadWithLegacy<LegacyGameMessages::LegacyLeaderboardRequest>(msg, LegacyGameMessages::ReadRequestActivitySummaryLeaderboardData);
|
||||
EXPECT_EQ(legacy.gameID, gameID);
|
||||
EXPECT_EQ(static_cast<int32_t>(legacy.queryType), queryType);
|
||||
EXPECT_EQ(legacy.resultsEnd, end);
|
||||
EXPECT_EQ(legacy.resultsStart, start);
|
||||
EXPECT_EQ(legacy.weekly, weekly);
|
||||
RoundTrip(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Leaderboard leaderboard(1864, Leaderboard::InfoType::Top, false, 0x1000000000000001LL, 10, Leaderboard::Type::ShootingGallery);
|
||||
GameMessages::SendActivitySummaryLeaderboardData data;
|
||||
data.target = 0x1000000000000001LL;
|
||||
data.leaderboard = &leaderboard;
|
||||
ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendActivitySummaryLeaderboardData(0x1000000000000001LL, &leaderboard, address); }, data, SendMode::SendToClient);
|
||||
}
|
||||
Reference in New Issue
Block a user