mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-11-14 07:47:13 +00:00
Main's model behaviors (every rotation, DoDamage, OnTimer, OnStartup, MoveBackToStart, moves along the model's local axes), raw terrain reading with scene lookups and scene tools, property model and brick by brick fixes and the chat server's player count fix, merged onto this branch's structures: - game messages stay structs; the angular velocity messages join them and the handler sets a message's target - strips own their speed again and the block names, moves and rotations stay in the shared action table (PropertyBehaviorActions, which the dashboard's behavior player reads; it now lists rotations too) - the zone keeps reading its file through ZoneFile and takes the boundaries from it, then loads the raw terrain as main does; the old dNavigation terrain reader is gone - the show all response stays a struct and logs a player count mismatch as main does - the property management component tells models who sent a chat message Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
312 lines
12 KiB
C++
312 lines
12 KiB
C++
#include "Action.h"
|
|
#include "Amf3.h"
|
|
#include "AMFDeserialize.h"
|
|
#include "ClientPackets.h"
|
|
#include "GameMessages.h"
|
|
#include "GameDependencies.h"
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
// Message includes
|
|
#include "AddActionMessage.h"
|
|
#include "AddStripMessage.h"
|
|
#include "AddMessage.h"
|
|
#include "MigrateActionsMessage.h"
|
|
#include "MoveToInventoryMessage.h"
|
|
#include "MergeStripsMessage.h"
|
|
#include "RearrangeStripMessage.h"
|
|
#include "RemoveActionsMessage.h"
|
|
#include "RemoveStripMessage.h"
|
|
#include "RenameMessage.h"
|
|
#include "SplitStripMessage.h"
|
|
#include "UpdateActionMessage.h"
|
|
#include "UpdateStripUiMessage.h"
|
|
|
|
class GameMessageTests: public GameDependenciesTest {
|
|
protected:
|
|
void SetUp() override {
|
|
SetUpDependencies();
|
|
}
|
|
void TearDown() override {
|
|
TearDownDependencies();
|
|
}
|
|
std::string ReadFromFile(std::string filename) {
|
|
std::ifstream file(filename, std::ios::binary);
|
|
std::string readFile;
|
|
while (file.good()) {
|
|
char readCharacter = file.get();
|
|
readFile.push_back(readCharacter);
|
|
}
|
|
return readFile;
|
|
}
|
|
std::unique_ptr<AMFArrayValue> ReadArrayFromBitStream(RakNet::BitStream& inStream) {
|
|
AMFDeserialize des;
|
|
AMFBaseValue* readArray = des.Read(inStream).release();
|
|
EXPECT_EQ(readArray->GetValueType(), eAmf::Array);
|
|
return std::unique_ptr<AMFArrayValue>{ static_cast<AMFArrayValue*>(readArray) };
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Tests that the serialization struct BlueprintLoadItemResponse is serialized correctly
|
|
*
|
|
*/
|
|
TEST_F(GameMessageTests, SendBlueprintLoadItemResponse) {
|
|
ClientPackets::BlueprintLoadItemResponse response;
|
|
response.success = true;
|
|
response.itemId = 515;
|
|
response.destItemId = 990;
|
|
response.Send(UNASSIGNED_SYSTEM_ADDRESS);
|
|
auto* bitStream = static_cast<dServerMock*>(Game::server)->GetMostRecentBitStream();
|
|
ASSERT_NE(bitStream, nullptr);
|
|
ASSERT_EQ(bitStream->GetNumberOfUnreadBits(), 200);
|
|
// First read in the packets' header
|
|
uint8_t rakNetPacketId{};
|
|
uint16_t remoteServiceType{};
|
|
uint32_t packetId{};
|
|
uint8_t always0{};
|
|
|
|
bitStream->Read(rakNetPacketId);
|
|
bitStream->Read(remoteServiceType);
|
|
bitStream->Read(packetId);
|
|
bitStream->Read(always0);
|
|
ASSERT_EQ(rakNetPacketId, 0x53);
|
|
ASSERT_EQ(remoteServiceType, 0x5);
|
|
ASSERT_EQ(packetId, 0x17);
|
|
ASSERT_EQ(always0, 0x00);
|
|
|
|
// Next read in packet data
|
|
|
|
uint8_t bSuccess{}; // unsigned bool
|
|
LWOOBJID previousId{};
|
|
LWOOBJID newId{};
|
|
bitStream->Read(bSuccess);
|
|
bitStream->Read(previousId);
|
|
bitStream->Read(newId);
|
|
ASSERT_EQ(bSuccess, static_cast<uint8_t>(true));
|
|
ASSERT_EQ(previousId, 515);
|
|
ASSERT_EQ(newId, 990);
|
|
|
|
ASSERT_EQ(bitStream->GetNumberOfUnreadBits(), 0);
|
|
}
|
|
|
|
/**
|
|
* @brief PlaceModelResponse is laid out as the client's PlaceModelResponse::Deserialize (0x00dc0170) reads it: every
|
|
* field optional, the rotation a w, x, y, z quaternion
|
|
*/
|
|
TEST_F(GameMessageTests, SendPlaceModelResponse) {
|
|
const NiQuaternion rotation = NiQuaternion(0.5f, 0.1f, 0.2f, 0.3f); // w, x, y, z
|
|
GameMessages::SendPlaceModelResponse(77, UNASSIGNED_SYSTEM_ADDRESS, NiPoint3(1.0f, 2.0f, 3.0f), LWOOBJID_EMPTY, 14, rotation);
|
|
auto* bitStream = static_cast<dServerMock*>(Game::server)->GetMostRecentBitStream();
|
|
ASSERT_NE(bitStream, nullptr);
|
|
bitStream->IgnoreBits(64); // packet header
|
|
|
|
LWOOBJID objectId{};
|
|
MessageType::Game messageId{};
|
|
bitStream->Read(objectId);
|
|
bitStream->Read(messageId);
|
|
EXPECT_EQ(objectId, 77);
|
|
EXPECT_EQ(messageId, MessageType::Game::PLACE_MODEL_RESPONSE);
|
|
|
|
bool hasPosition{}, hasPlaque{}, hasResponse{}, hasRotation{};
|
|
NiPoint3 position{};
|
|
int32_t response{};
|
|
float w{}, x{}, y{}, z{};
|
|
bitStream->Read(hasPosition);
|
|
bitStream->Read(position);
|
|
bitStream->Read(hasPlaque);
|
|
bitStream->Read(hasResponse);
|
|
bitStream->Read(response);
|
|
bitStream->Read(hasRotation);
|
|
bitStream->Read(w);
|
|
bitStream->Read(x);
|
|
bitStream->Read(y);
|
|
bitStream->Read(z);
|
|
EXPECT_TRUE(hasPosition);
|
|
EXPECT_EQ(position, NiPoint3(1.0f, 2.0f, 3.0f));
|
|
EXPECT_FALSE(hasPlaque);
|
|
EXPECT_TRUE(hasResponse);
|
|
EXPECT_EQ(response, 14);
|
|
EXPECT_TRUE(hasRotation);
|
|
EXPECT_FLOAT_EQ(w, rotation.w);
|
|
EXPECT_FLOAT_EQ(x, rotation.x);
|
|
EXPECT_FLOAT_EQ(y, rotation.y);
|
|
EXPECT_FLOAT_EQ(z, rotation.z);
|
|
EXPECT_EQ(bitStream->GetNumberOfUnreadBits(), 0);
|
|
}
|
|
|
|
TEST_F(GameMessageTests, ControlBehaviorAddStrip) {
|
|
auto data = ReadFromFile("addStrip");
|
|
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
|
|
|
|
const auto arr = ReadArrayFromBitStream(inStream);
|
|
AddStripMessage addStrip(*arr);
|
|
|
|
ASSERT_FLOAT_EQ(addStrip.GetPosition().GetX(), 50.65);
|
|
ASSERT_FLOAT_EQ(addStrip.GetPosition().GetY(), 178.05);
|
|
ASSERT_EQ(addStrip.GetActionContext().GetStripId(), 0);
|
|
ASSERT_EQ(static_cast<uint32_t>(addStrip.GetActionContext().GetStateId()), 0);
|
|
ASSERT_EQ(addStrip.GetBehaviorId(), BehaviorMessageBase::DefaultBehaviorId);
|
|
ASSERT_EQ(addStrip.GetActionsToAdd().front().GetType(), "DropImagination");
|
|
ASSERT_EQ(addStrip.GetActionsToAdd().front().GetValueParameterName(), "Amount");
|
|
ASSERT_EQ(addStrip.GetActionsToAdd().front().GetValueParameterString(), "");
|
|
ASSERT_FLOAT_EQ(addStrip.GetActionsToAdd().front().GetValueParameterDouble(), 1.0);
|
|
}
|
|
|
|
TEST_F(GameMessageTests, ControlBehaviorRemoveStrip) {
|
|
auto data = ReadFromFile("removeStrip");
|
|
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
|
|
|
|
const auto arr = ReadArrayFromBitStream(inStream);
|
|
RemoveStripMessage removeStrip(*arr);
|
|
|
|
ASSERT_EQ(static_cast<int32_t>(removeStrip.GetActionContext().GetStripId()), 1);
|
|
ASSERT_EQ(static_cast<int32_t>(removeStrip.GetActionContext().GetStateId()), 0);
|
|
ASSERT_EQ(removeStrip.GetBehaviorId(), BehaviorMessageBase::DefaultBehaviorId);
|
|
}
|
|
|
|
TEST_F(GameMessageTests, ControlBehaviorMergeStrips) {
|
|
auto data = ReadFromFile("mergeStrips");
|
|
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
|
|
|
|
const auto arr = ReadArrayFromBitStream(inStream);
|
|
MergeStripsMessage mergeStrips(*arr);
|
|
|
|
ASSERT_EQ(mergeStrips.GetSourceActionContext().GetStripId(), 2);
|
|
ASSERT_EQ(mergeStrips.GetDestinationActionContext().GetStripId(), 0);
|
|
ASSERT_EQ(static_cast<uint32_t>(mergeStrips.GetSourceActionContext().GetStateId()), 0);
|
|
ASSERT_EQ(static_cast<uint32_t>(mergeStrips.GetDestinationActionContext().GetStateId()), 0);
|
|
ASSERT_EQ(mergeStrips.GetDstActionIndex(), 0);
|
|
ASSERT_EQ(mergeStrips.GetBehaviorId(), BehaviorMessageBase::DefaultBehaviorId);
|
|
}
|
|
|
|
TEST_F(GameMessageTests, ControlBehaviorSplitStrip) {
|
|
auto data = ReadFromFile("splitStrip");
|
|
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
|
|
|
|
const auto arr = ReadArrayFromBitStream(inStream);
|
|
SplitStripMessage splitStrip(*arr);
|
|
|
|
ASSERT_EQ(splitStrip.GetBehaviorId(), -1);
|
|
ASSERT_FLOAT_EQ(splitStrip.GetPosition().GetX(), 275.65);
|
|
ASSERT_FLOAT_EQ(splitStrip.GetPosition().GetY(), 28.7);
|
|
ASSERT_EQ(splitStrip.GetSourceActionContext().GetStripId(), 0);
|
|
ASSERT_EQ(splitStrip.GetDestinationActionContext().GetStripId(), 2);
|
|
ASSERT_EQ(static_cast<uint32_t>(splitStrip.GetSourceActionContext().GetStateId()), 0);
|
|
ASSERT_EQ(static_cast<uint32_t>(splitStrip.GetDestinationActionContext().GetStateId()), 0);
|
|
ASSERT_EQ(splitStrip.GetSrcActionIndex(), 1);
|
|
}
|
|
|
|
TEST_F(GameMessageTests, ControlBehaviorUpdateStripUI) {
|
|
auto data = ReadFromFile("updateStripUI");
|
|
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
|
|
|
|
const auto arr = ReadArrayFromBitStream(inStream);
|
|
UpdateStripUiMessage updateStripUi(*arr);
|
|
|
|
ASSERT_FLOAT_EQ(updateStripUi.GetPosition().GetX(), 116.65);
|
|
ASSERT_FLOAT_EQ(updateStripUi.GetPosition().GetY(), 35.35);
|
|
ASSERT_EQ(updateStripUi.GetActionContext().GetStripId(), 0);
|
|
ASSERT_EQ(static_cast<uint32_t>(updateStripUi.GetActionContext().GetStateId()), 0);
|
|
ASSERT_EQ(updateStripUi.GetBehaviorId(), BehaviorMessageBase::DefaultBehaviorId);
|
|
}
|
|
|
|
TEST_F(GameMessageTests, ControlBehaviorAddAction) {
|
|
auto data = ReadFromFile("addAction");
|
|
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
|
|
|
|
const auto arr = ReadArrayFromBitStream(inStream);
|
|
AddActionMessage addAction(*arr);
|
|
|
|
ASSERT_EQ(addAction.GetActionIndex(), 3);
|
|
ASSERT_EQ(addAction.GetActionContext().GetStripId(), 0);
|
|
ASSERT_EQ(static_cast<uint32_t>(addAction.GetActionContext().GetStateId()), 0);
|
|
ASSERT_EQ(addAction.GetAction().GetType(), "DoDamage");
|
|
ASSERT_EQ(addAction.GetAction().GetValueParameterName(), "");
|
|
ASSERT_EQ(addAction.GetAction().GetValueParameterString(), "");
|
|
ASSERT_EQ(addAction.GetAction().GetValueParameterDouble(), 0.0);
|
|
ASSERT_EQ(addAction.GetBehaviorId(), BehaviorMessageBase::DefaultBehaviorId);
|
|
}
|
|
|
|
TEST_F(GameMessageTests, ControlBehaviorMigrateActions) {
|
|
auto data = ReadFromFile("migrateActions");
|
|
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
|
|
|
|
const auto arr = ReadArrayFromBitStream(inStream);
|
|
MigrateActionsMessage migrateActions(*arr);
|
|
|
|
ASSERT_EQ(migrateActions.GetSrcActionIndex(), 1);
|
|
ASSERT_EQ(migrateActions.GetDstActionIndex(), 2);
|
|
ASSERT_EQ(migrateActions.GetSourceActionContext().GetStripId(), 1);
|
|
ASSERT_EQ(migrateActions.GetDestinationActionContext().GetStripId(), 0);
|
|
ASSERT_EQ(static_cast<uint32_t>(migrateActions.GetSourceActionContext().GetStateId()), 0);
|
|
ASSERT_EQ(static_cast<uint32_t>(migrateActions.GetDestinationActionContext().GetStateId()), 0);
|
|
ASSERT_EQ(migrateActions.GetBehaviorId(), BehaviorMessageBase::DefaultBehaviorId);
|
|
}
|
|
|
|
TEST_F(GameMessageTests, ControlBehaviorRearrangeStrip) {
|
|
auto data = ReadFromFile("rearrangeStrip");
|
|
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
|
|
|
|
const auto arr = ReadArrayFromBitStream(inStream);
|
|
RearrangeStripMessage rearrangeStrip(*arr);
|
|
|
|
ASSERT_EQ(rearrangeStrip.GetSrcActionIndex(), 2);
|
|
ASSERT_EQ(rearrangeStrip.GetDstActionIndex(), 1);
|
|
ASSERT_EQ(rearrangeStrip.GetActionContext().GetStripId(), 0);
|
|
ASSERT_EQ(rearrangeStrip.GetBehaviorId(), BehaviorMessageBase::DefaultBehaviorId);
|
|
ASSERT_EQ(static_cast<uint32_t>(rearrangeStrip.GetActionContext().GetStateId()), 0);
|
|
}
|
|
|
|
TEST_F(GameMessageTests, ControlBehaviorAdd) {
|
|
auto data = ReadFromFile("add");
|
|
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
|
|
|
|
const auto arr = ReadArrayFromBitStream(inStream);
|
|
AddMessage add(*arr, LWOOBJID_EMPTY);
|
|
|
|
ASSERT_EQ(add.GetBehaviorId(), 10446);
|
|
ASSERT_EQ(add.GetBehaviorIndex(), 0);
|
|
}
|
|
|
|
TEST_F(GameMessageTests, ControlBehaviorRemoveActions) {
|
|
auto data = ReadFromFile("removeActions");
|
|
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
|
|
|
|
const auto arr = ReadArrayFromBitStream(inStream);
|
|
RemoveActionsMessage removeActions(*arr);
|
|
|
|
ASSERT_EQ(removeActions.GetBehaviorId(), -1);
|
|
ASSERT_EQ(removeActions.GetActionIndex(), 1);
|
|
ASSERT_EQ(removeActions.GetActionContext().GetStripId(), 0);
|
|
ASSERT_EQ(static_cast<uint32_t>(removeActions.GetActionContext().GetStateId()), 0);
|
|
}
|
|
|
|
TEST_F(GameMessageTests, ControlBehaviorRename) {
|
|
auto data = ReadFromFile("rename");
|
|
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
|
|
|
|
const auto arr = ReadArrayFromBitStream(inStream);
|
|
RenameMessage rename(*arr);
|
|
|
|
ASSERT_EQ(rename.GetName(), "test");
|
|
ASSERT_EQ(rename.GetBehaviorId(), BehaviorMessageBase::DefaultBehaviorId);
|
|
}
|
|
|
|
TEST_F(GameMessageTests, ControlBehaviorUpdateAction) {
|
|
auto data = ReadFromFile("updateAction");
|
|
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
|
|
|
|
const auto arr = ReadArrayFromBitStream(inStream);
|
|
UpdateActionMessage updateAction(*arr);
|
|
|
|
ASSERT_EQ(updateAction.GetAction().GetType(), "FlyDown");
|
|
ASSERT_EQ(updateAction.GetAction().GetValueParameterName(), "Distance");
|
|
ASSERT_EQ(updateAction.GetAction().GetValueParameterString(), "");
|
|
ASSERT_EQ(updateAction.GetAction().GetValueParameterDouble(), 50.0);
|
|
ASSERT_EQ(updateAction.GetBehaviorId(), BehaviorMessageBase::DefaultBehaviorId);
|
|
ASSERT_EQ(updateAction.GetActionIndex(), 1);
|
|
ASSERT_EQ(updateAction.GetActionContext().GetStripId(), 0);
|
|
ASSERT_EQ(static_cast<uint32_t>(updateAction.GetActionContext().GetStateId()), 0);
|
|
}
|