#include #include #include #include #include #include #include #include "StringCache.h" #include "Messages/StringCacheUpdate.h" #include #include #include #include #include #include using namespace TiltedPhoques; TEST_CASE("Encoding factory", "[encoding.factory]") { Buffer buff(1000); { AuthenticationRequest request; request.Token = "TesSt"; Buffer::Writer writer(&buff); request.Serialize(writer); Buffer::Reader reader(&buff); const ClientMessageFactory factory; auto pMessage = factory.Extract(reader); REQUIRE(pMessage); REQUIRE(pMessage->GetOpcode() == request.GetOpcode()); auto pRequest = CastUnique(std::move(pMessage)); REQUIRE(pRequest->Token == request.Token); } { PartyAcceptInviteRequest request; request.InviterId = 123456; Buffer::Writer writer(&buff); request.Serialize(writer); Buffer::Reader reader(&buff); const ClientMessageFactory factory; auto pMessage = factory.Extract(reader); REQUIRE(pMessage); REQUIRE(pMessage->GetOpcode() == request.GetOpcode()); auto pRequest = CastUnique(std::move(pMessage)); REQUIRE(pRequest->InviterId == request.InviterId); } } TEST_CASE("Static structures", "[encoding.static]") { GIVEN("GameId") { GameId sendObjects, recvObjects; sendObjects.ModId = 1456987; sendObjects.BaseId = 0x789654; { Buffer buff(1000); Buffer::Writer writer(&buff); sendObjects.Serialize(writer); Buffer::Reader reader(&buff); recvObjects.Deserialize(reader); REQUIRE(sendObjects == recvObjects); } } GIVEN("Vector3_NetQuantize") { Vector3_NetQuantize sendObjects, recvObjects; sendObjects.x = 142.56f; sendObjects.y = 45687.7f; sendObjects.z = -142.56f; { Buffer buff(1000); Buffer::Writer writer(&buff); sendObjects.Serialize(writer); Buffer::Reader reader(&buff); recvObjects.Deserialize(reader); REQUIRE(sendObjects == recvObjects); } } GIVEN("Vector2_NetQuantize") { Vector2_NetQuantize sendObjects, recvObjects; sendObjects.x = 1000.89f; sendObjects.y = -485632.75f; { Buffer buff(1000); Buffer::Writer writer(&buff); sendObjects.Serialize(writer); Buffer::Reader reader(&buff); recvObjects.Deserialize(reader); REQUIRE(sendObjects == recvObjects); } } GIVEN("Rotator2_NetQuantize") { Rotator2_NetQuantize sendObjects, recvObjects; sendObjects.x = 1.89f; sendObjects.y = TiltedPhoques::Pi * 2.0f; { Buffer buff(1000); Buffer::Writer writer(&buff); sendObjects.Serialize(writer); Buffer::Reader reader(&buff); recvObjects.Deserialize(reader); REQUIRE(sendObjects == recvObjects); } } GIVEN("Rotator2_NetQuantize needing wrap") { // This test is a bit dangerous as floating errors can lead to sendObjects != recvObjects but the difference is minuscule so we don't care abut such cases Rotator2_NetQuantize sendObjects, recvObjects; sendObjects.x = -1.87f; sendObjects.y = static_cast(TiltedPhoques::Pi) * 18.0f + 3.6f; { Buffer buff(1000); Buffer::Writer writer(&buff); sendObjects.Serialize(writer); Buffer::Reader reader(&buff); recvObjects.Deserialize(reader); REQUIRE(sendObjects == recvObjects); } } } TEST_CASE("Differential structures", "[encoding.differential]") { GIVEN("Full ActionEvent") { ActionEvent sendAction, recvAction; sendAction.ActionId = 42; sendAction.State1 = 6547; sendAction.Tick = 48; sendAction.ActorId = 12345678; sendAction.EventName = "test"; sendAction.IdleId = 87964; sendAction.State2 = 8963; sendAction.TargetEventName = "toast"; sendAction.TargetId = 963741; sendAction.Type = 4; { Buffer buff(1000); Buffer::Writer writer(&buff); sendAction.GenerateDifferential(recvAction, writer); Buffer::Reader reader(&buff); recvAction.ApplyDifferential(reader); REQUIRE(sendAction == recvAction); } { Buffer buff(1000); Buffer::Writer writer(&buff); sendAction.EventName = "Plot twist !"; sendAction.GenerateDifferential(recvAction, writer); Buffer::Reader reader(&buff); recvAction.ApplyDifferential(reader); REQUIRE(sendAction == recvAction); } } GIVEN("A single cached event name") { ActionEvent sendAction, recvAction; TP_UNUSED(StringCache::Get().Add("test")) sendAction.ActionId = 42; sendAction.State1 = 6547; sendAction.Tick = 48; sendAction.ActorId = 12345678; sendAction.EventName = "test"; sendAction.IdleId = 87964; sendAction.State2 = 8963; sendAction.TargetEventName = "toast"; sendAction.TargetId = 963741; sendAction.Type = 4; { Buffer buff(1000); Buffer::Writer writer(&buff); sendAction.GenerateDifferential(recvAction, writer); Buffer::Reader reader(&buff); recvAction.ApplyDifferential(reader); REQUIRE(sendAction == recvAction); } { Buffer buff(1000); Buffer::Writer writer(&buff); sendAction.EventName = "Plot twist !"; sendAction.GenerateDifferential(recvAction, writer); Buffer::Reader reader(&buff); recvAction.ApplyDifferential(reader); REQUIRE(sendAction == recvAction); } } GIVEN("Full Mods") { Mods sendMods, recvMods; Buffer buff(1000); Buffer::Writer writer(&buff); sendMods.ModList.push_back({"Hello", 42}); sendMods.ModList.push_back({"Hi", 14}); sendMods.ModList.push_back({"Test", 8}); sendMods.ModList.push_back({"Toast", 49}); sendMods.Serialize(writer); Buffer::Reader reader(&buff); recvMods.Deserialize(reader); REQUIRE(sendMods == recvMods); } GIVEN("AnimationVariables") { AnimationVariables vars, recvVars; vars.Booleans.resize(76); String testString("\xDE\xAD\xBE\xEF" "\xDE\xAD\xBE\xEF\x76\xB"); vars.String_to_VectorBool(testString, vars.Booleans); vars.Floats.push_back(1.f); vars.Floats.push_back(7.f); vars.Floats.push_back(12.f); vars.Floats.push_back(0.f); vars.Floats.push_back(145.f); vars.Floats.push_back(100.f); vars.Floats.push_back(-1.f); vars.Integers.push_back(0); vars.Integers.push_back(12000); vars.Integers.push_back(06); vars.Integers.push_back(7778); vars.Integers.push_back(41104539); Buffer buff(1000); { Buffer::Writer writer(&buff); vars.GenerateDiff(recvVars, writer); Buffer::Reader reader(&buff); recvVars.ApplyDiff(reader); REQUIRE(vars.Booleans == recvVars.Booleans); REQUIRE(vars.Floats == recvVars.Floats); REQUIRE(vars.Integers == recvVars.Integers); } vars.Booleans.resize(33); vars.Booleans[16] = false; vars.Booleans[17] = false; vars.Booleans[18] = false; vars.Booleans[19] = false; vars.Floats[3] = 42.f; vars.Integers[0] = 18; vars.Integers[3] = 0; { Buffer::Writer writer(&buff); vars.GenerateDiff(recvVars, writer); Buffer::Reader reader(&buff); recvVars.ApplyDiff(reader); REQUIRE(vars.Booleans == recvVars.Booleans); REQUIRE(vars.Floats == recvVars.Floats); REQUIRE(vars.Integers == recvVars.Integers); } } } TEST_CASE("Packets", "[encoding.packets]") { SECTION("AuthenticationRequest") { Buffer buff(1000); AuthenticationRequest sendMessage, recvMessage; sendMessage.Token = "TesSt"; sendMessage.UserMods.ModList.push_back({"Hello", 42}); sendMessage.UserMods.ModList.push_back({"Hi", 14}); sendMessage.UserMods.ModList.push_back({"Test", 8}); sendMessage.UserMods.ModList.push_back({"Toast", 49}); Buffer::Writer writer(&buff); sendMessage.Serialize(writer); Buffer::Reader reader(&buff); uint64_t trash; reader.ReadBits(trash, 8); // pop opcode recvMessage.DeserializeRaw(reader); REQUIRE(sendMessage == recvMessage); } SECTION("AuthenticationResponse") { Buffer buff(1000); AuthenticationResponse sendMessage, recvMessage; sendMessage.Type = AuthenticationResponse::ResponseType::kAccepted; sendMessage.UserMods.ModList.push_back({"Hello", 42}); sendMessage.UserMods.ModList.push_back({"Hi", 14}); sendMessage.UserMods.ModList.push_back({"Test", 8}); sendMessage.UserMods.ModList.push_back({"Toast", 49}); Buffer::Writer writer(&buff); sendMessage.Serialize(writer); Buffer::Reader reader(&buff); uint64_t trash; reader.ReadBits(trash, 8); // pop opcode recvMessage.DeserializeRaw(reader); REQUIRE(sendMessage == recvMessage); } SECTION("CancelAssignmentRequest") { Buffer buff(1000); CancelAssignmentRequest sendMessage, recvMessage; sendMessage.Cookie = 14523698; Buffer::Writer writer(&buff); sendMessage.Serialize(writer); Buffer::Reader reader(&buff); uint64_t trash; reader.ReadBits(trash, 8); // pop opcode recvMessage.DeserializeRaw(reader); REQUIRE(sendMessage == recvMessage); } SECTION("AssignCharacterRequest") { Buffer buff(1000); ActionEvent sendAction; sendAction.ActionId = 42; sendAction.State1 = 6547; sendAction.Tick = 48; sendAction.ActorId = 12345678; sendAction.EventName = "test"; sendAction.IdleId = 87964; sendAction.State2 = 8963; sendAction.TargetEventName = "toast"; sendAction.TargetId = 963741; sendAction.Type = 4; AssignCharacterRequest sendMessage, recvMessage; sendMessage.Cookie = 14523698; sendMessage.AppearanceBuffer = "toto"; sendMessage.CellId.BaseId = 45; sendMessage.FormId.ModId = 48; sendMessage.ReferenceId.BaseId = 456799; sendMessage.ReferenceId.ModId = 4079; sendMessage.LatestAction = sendAction; sendMessage.Position.x = -452.4f; sendMessage.Position.y = 452.4f; sendMessage.Position.z = 125452.4f; sendMessage.Rotation.x = -1.87f; sendMessage.Rotation.y = 45.35f; Buffer::Writer writer(&buff); sendMessage.Serialize(writer); Buffer::Reader reader(&buff); uint64_t trash; reader.ReadBits(trash, 8); // pop opcode recvMessage.DeserializeRaw(reader); REQUIRE(sendMessage == recvMessage); } GIVEN("ClientReferencesMoveRequest") { ClientReferencesMoveRequest sendMessage, recvMessage; auto& update = sendMessage.Updates[1]; auto& move = update.UpdatedMovement; AnimationVariables vars; vars.Booleans.resize(76); String testString("\xDE\xAD\xBE\xEF\x76\xB"); vars.String_to_VectorBool(testString, vars.Booleans); vars.Floats.push_back(1.f); vars.Floats.push_back(7.f); vars.Floats.push_back(12.f); vars.Floats.push_back(0.f); vars.Floats.push_back(145.f); vars.Floats.push_back(100.f); vars.Floats.push_back(-1.f); vars.Integers.push_back(0); vars.Integers.push_back(12000); vars.Integers.push_back(06); vars.Integers.push_back(7778); vars.Integers.push_back(41104539); move.Variables = vars; Buffer buff(1000); Buffer::Writer writer(&buff); sendMessage.Serialize(writer); Buffer::Reader reader(&buff); uint64_t trash; reader.ReadBits(trash, 8); // pop opcode recvMessage.DeserializeRaw(reader); REQUIRE(recvMessage.Updates[1].UpdatedMovement == sendMessage.Updates[1].UpdatedMovement); } } TEST_CASE("StringCache", "[encoding.string_cache]") { SECTION("Messages") { StringCacheUpdate update; update.Values.push_back("Hello"); update.Values.push_back("Bye"); Buffer buff(1000); Buffer::Writer writer(&buff); update.Serialize(writer); Buffer::Reader reader(&buff); uint64_t trash; reader.ReadBits(trash, 8); // pop opcode StringCacheUpdate recvUpdate; recvUpdate.DeserializeRaw(reader); REQUIRE(update == recvUpdate); } }