General AMF cleanup (#663)

* General AMF cleanup

Proper memory management as well as style cleanup

* General optimizations

Fix AMFArray so values are properly deleted when you leave the scope it was created in.
Add bounds check for deletion so you don't double delete.
Remove all AMFdeletions that are contained in an array since the array now manages its own memory and deletes it when it is no longer needed.

* Better tests and fix de-serialize

Fix de-serialize to be correct and implement a test to check this

* Update AMFDeserializeTests.cpp

* Update AMFFormat.cpp
This commit is contained in:
David Markowitz 2022-07-21 22:26:09 -07:00 committed by GitHub
parent 5523b6aafc
commit 6a38b67ed5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 303 additions and 389 deletions

View File

@ -127,21 +127,23 @@ AMFValue* AMFDeserialize::ReadAmfDouble(RakNet::BitStream* inStream) {
AMFValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream* inStream) { AMFValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream* inStream) {
auto arrayValue = new AMFArrayValue(); auto arrayValue = new AMFArrayValue();
// Read size of dense array
auto sizeOfDenseArray = (ReadU29(inStream) >> 1); auto sizeOfDenseArray = (ReadU29(inStream) >> 1);
if (sizeOfDenseArray >= 1) {
char valueType; // Then read Key'd portion
inStream->Read(valueType); // Unused
for (uint32_t i = 0; i < sizeOfDenseArray; i++) {
arrayValue->PushBackValue(Read(inStream));
}
} else {
while (true) { while (true) {
auto key = ReadString(inStream); auto key = ReadString(inStream);
// No more values when we encounter an empty string // No more values when we encounter an empty string
if (key.size() == 0) break; if (key.size() == 0) break;
arrayValue->InsertValue(key, Read(inStream)); arrayValue->InsertValue(key, Read(inStream));
} }
// Finally read dense portion
for (uint32_t i = 0; i < sizeOfDenseArray; i++) {
arrayValue->PushBackValue(Read(inStream));
} }
return arrayValue; return arrayValue;
} }

View File

@ -108,6 +108,14 @@ _AMFArrayList_::iterator AMFArrayValue::GetDenseIteratorEnd() {
return this->dense.end(); return this->dense.end();
} }
AMFArrayValue::~AMFArrayValue() {
for (auto valueToDelete : GetDenseArray()) {
if (valueToDelete) delete valueToDelete;
}
for (auto valueToDelete : GetAssociativeMap()) {
if (valueToDelete.second) delete valueToDelete.second;
}
}
// AMFObject Constructor // AMFObject Constructor
AMFObjectValue::AMFObjectValue(std::vector<std::pair<std::string, AMFValueType>> traits) { AMFObjectValue::AMFObjectValue(std::vector<std::pair<std::string, AMFValueType>> traits) {
@ -155,3 +163,9 @@ _AMFObjectTraits_::iterator AMFObjectValue::GetTraitsIteratorEnd() {
uint32_t AMFObjectValue::GetTraitArrayCount() { uint32_t AMFObjectValue::GetTraitArrayCount() {
return (uint32_t)this->traits.size(); return (uint32_t)this->traits.size();
} }
AMFObjectValue::~AMFObjectValue() {
for (auto valueToDelete = GetTraitsIteratorBegin(); valueToDelete != GetTraitsIteratorEnd(); valueToDelete++) {
if (valueToDelete->second.second) delete valueToDelete->second.second;
}
}

View File

@ -59,6 +59,7 @@ public:
\return The AMF value type \return The AMF value type
*/ */
virtual AMFValueType GetValueType() = 0; virtual AMFValueType GetValueType() = 0;
virtual ~AMFValue() {};
}; };
//! A typedef for a pointer to an AMF value //! A typedef for a pointer to an AMF value
@ -233,6 +234,7 @@ public:
}; };
//! The array value AMF type //! The array value AMF type
// This object will manage it's own memory map and list. Do not delete its values.
class AMFArrayValue : public AMFValue { class AMFArrayValue : public AMFValue {
private: private:
_AMFArrayMap_ associative; //!< The array map (associative part) _AMFArrayMap_ associative; //!< The array map (associative part)
@ -245,6 +247,7 @@ private:
AMFValueType GetValueType() { return AMFArray; } AMFValueType GetValueType() { return AMFArray; }
public: public:
~AMFArrayValue() override;
//! Inserts an item into the array map for a specific key //! Inserts an item into the array map for a specific key
/*! /*!
\param key The key to set \param key The key to set
@ -332,6 +335,7 @@ private:
\return The AMF value type \return The AMF value type
*/ */
AMFValueType GetValueType() { return AMFObject; } AMFValueType GetValueType() { return AMFObject; }
~AMFObjectValue() override;
public: public:
//! Constructor //! Constructor

View File

@ -37,6 +37,12 @@ void RakNet::BitStream::Write<AMFValue*>(AMFValue* value) {
break; break;
} }
case AMFDouble: {
AMFDoubleValue* v = (AMFDoubleValue*)value;
this->Write(*v);
break;
}
case AMFString: { case AMFString: {
AMFStringValue* v = (AMFStringValue*)value; AMFStringValue* v = (AMFStringValue*)value;
this->Write(*v); this->Write(*v);
@ -56,15 +62,17 @@ void RakNet::BitStream::Write<AMFValue*>(AMFValue* value) {
} }
case AMFArray: { case AMFArray: {
AMFArrayValue* v = (AMFArrayValue*)value; this->Write((AMFArrayValue*)value);
this->Write(*v);
break; break;
} }
} }
} }
} }
// A private function to write an value to a RakNet::BitStream /**
* A private function to write an value to a RakNet::BitStream
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteUInt29(RakNet::BitStream* bs, uint32_t v) { void WriteUInt29(RakNet::BitStream* bs, uint32_t v) {
unsigned char b4 = (unsigned char)v; unsigned char b4 = (unsigned char)v;
if (v < 0x00200000) { if (v < 0x00200000) {
@ -102,79 +110,50 @@ void WriteUInt29(RakNet::BitStream* bs, uint32_t v) {
bs->Write(b4); bs->Write(b4);
} }
// Writes a flag number to a RakNet::BitStream /**
* Writes a flag number to a RakNet::BitStream
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteFlagNumber(RakNet::BitStream* bs, uint32_t v) { void WriteFlagNumber(RakNet::BitStream* bs, uint32_t v) {
v = (v << 1) | 0x01; v = (v << 1) | 0x01;
WriteUInt29(bs, v); WriteUInt29(bs, v);
} }
// Writes an AMFString to a RakNet::BitStream /**
* Writes an AMFString to a RakNet::BitStream
*
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteAMFString(RakNet::BitStream* bs, const std::string& str) { void WriteAMFString(RakNet::BitStream* bs, const std::string& str) {
WriteFlagNumber(bs, (uint32_t)str.size()); WriteFlagNumber(bs, (uint32_t)str.size());
bs->Write(str.c_str(), (uint32_t)str.size()); bs->Write(str.c_str(), (uint32_t)str.size());
} }
// Writes an AMF U16 to a RakNet::BitStream /**
* Writes an U16 to a bitstream
*
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteAMFU16(RakNet::BitStream* bs, uint16_t value) { void WriteAMFU16(RakNet::BitStream* bs, uint16_t value) {
unsigned char b2; bs->Write(value);
b2 = (unsigned char)value;
value = value >> 8;
bs->Write((unsigned char)value);
bs->Write(b2);
} }
// Writes an AMF U32 to RakNet::BitStream /**
* Writes an U32 to a bitstream
*
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteAMFU32(RakNet::BitStream* bs, uint32_t value) { void WriteAMFU32(RakNet::BitStream* bs, uint32_t value) {
unsigned char b2; bs->Write(value);
unsigned char b3;
unsigned char b4;
b4 = (unsigned char)value;
value = value >> 8;
b3 = (unsigned char)value;
value = value >> 8;
b2 = (unsigned char)value;
value = value >> 8;
bs->Write((unsigned char)value);
bs->Write(b2);
bs->Write(b3);
bs->Write(b4);
} }
// Writes an AMF U64 to RakNet::BitStream /**
* Writes an U64 to a bitstream
*
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteAMFU64(RakNet::BitStream* bs, uint64_t value) { void WriteAMFU64(RakNet::BitStream* bs, uint64_t value) {
unsigned char b2; bs->Write(value);
unsigned char b3;
unsigned char b4;
unsigned char b5;
unsigned char b6;
unsigned char b7;
unsigned char b8;
b8 = (unsigned char)value;
value = value >> 8;
b7 = (unsigned char)value;
value = value >> 8;
b6 = (unsigned char)value;
value = value >> 8;
b5 = (unsigned char)value;
value = value >> 8;
b4 = (unsigned char)value;
value = value >> 8;
b3 = (unsigned char)value;
value = value >> 8;
b2 = (unsigned char)value;
value = value >> 8;
bs->Write((unsigned char)value);
bs->Write(b2);
bs->Write(b3);
bs->Write(b4);
bs->Write(b5);
bs->Write(b6);
bs->Write(b7);
bs->Write(b8);
} }
@ -243,13 +222,13 @@ void RakNet::BitStream::Write<AMFDateValue>(AMFDateValue value) {
// Writes an AMFArrayValue to BitStream // Writes an AMFArrayValue to BitStream
template<> template<>
void RakNet::BitStream::Write<AMFArrayValue>(AMFArrayValue value) { void RakNet::BitStream::Write<AMFArrayValue*>(AMFArrayValue* value) {
this->Write(AMFArray); this->Write(AMFArray);
uint32_t denseSize = value.GetDenseValueSize(); uint32_t denseSize = value->GetDenseValueSize();
WriteFlagNumber(this, denseSize); WriteFlagNumber(this, denseSize);
_AMFArrayMap_::iterator it = value.GetAssociativeIteratorValueBegin(); _AMFArrayMap_::iterator it = value->GetAssociativeIteratorValueBegin();
_AMFArrayMap_::iterator end = value.GetAssociativeIteratorValueEnd(); _AMFArrayMap_::iterator end = value->GetAssociativeIteratorValueEnd();
while (it != end) { while (it != end) {
WriteAMFString(this, it->first); WriteAMFString(this, it->first);
@ -260,8 +239,8 @@ void RakNet::BitStream::Write<AMFArrayValue>(AMFArrayValue value) {
this->Write(AMFNull); this->Write(AMFNull);
if (denseSize > 0) { if (denseSize > 0) {
_AMFArrayList_::iterator it2 = value.GetDenseIteratorBegin(); _AMFArrayList_::iterator it2 = value->GetDenseIteratorBegin();
_AMFArrayList_::iterator end2 = value.GetDenseIteratorEnd(); _AMFArrayList_::iterator end2 = value->GetDenseIteratorEnd();
while (it2 != end2) { while (it2 != end2) {
this->Write(*it2); this->Write(*it2);

View File

@ -7,7 +7,7 @@
#include <BitStream.h> #include <BitStream.h>
/*! /*!
\file AMFBitStream.hpp \file AMFFormat_BitStream.h
\brief A class that implements native writing of AMF values to RakNet::BitStream \brief A class that implements native writing of AMF values to RakNet::BitStream
*/ */
@ -88,5 +88,5 @@ namespace RakNet {
\param value The value to write \param value The value to write
*/ */
template <> template <>
void RakNet::BitStream::Write<AMFArrayValue>(AMFArrayValue value); void RakNet::BitStream::Write<AMFArrayValue*>(AMFArrayValue* value);
} } // namespace RakNet

View File

@ -234,10 +234,8 @@ void DestroyableComponent::SetMaxHealth(float value, bool playAnim) {
AMFArrayValue args; AMFArrayValue args;
args.InsertValue("amount", amount); args.InsertValue("amount", amount);
args.InsertValue("type", type); args.InsertValue("type", type);
GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", &args);
delete amount; GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", &args);
delete type;
} }
EntityManager::Instance()->SerializeEntity(m_Parent); EntityManager::Instance()->SerializeEntity(m_Parent);
@ -283,9 +281,6 @@ void DestroyableComponent::SetMaxArmor(float value, bool playAnim) {
args.InsertValue("type", type); args.InsertValue("type", type);
GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", &args); GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", &args);
delete amount;
delete type;
} }
EntityManager::Instance()->SerializeEntity(m_Parent); EntityManager::Instance()->SerializeEntity(m_Parent);
@ -328,10 +323,8 @@ void DestroyableComponent::SetMaxImagination(float value, bool playAnim) {
AMFArrayValue args; AMFArrayValue args;
args.InsertValue("amount", amount); args.InsertValue("amount", amount);
args.InsertValue("type", type); args.InsertValue("type", type);
GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", &args);
delete amount; GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", &args);
delete type;
} }
EntityManager::Instance()->SerializeEntity(m_Parent); EntityManager::Instance()->SerializeEntity(m_Parent);
} }

View File

@ -40,8 +40,6 @@ void PropertyEntranceComponent::OnUse(Entity* entity) {
args.InsertValue("state", state); args.InsertValue("state", state);
GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "pushGameState", &args); GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "pushGameState", &args);
delete state;
} }
void PropertyEntranceComponent::OnEnterProperty(Entity* entity, uint32_t index, bool returnToZone, const SystemAddress& sysAddr) void PropertyEntranceComponent::OnEnterProperty(Entity* entity, uint32_t index, bool returnToZone, const SystemAddress& sysAddr)

View File

@ -4978,12 +4978,9 @@ void GameMessages::HandleFireEventServerSide(RakNet::BitStream* inStream, Entity
} }
if (args == u"toggleMail") { if (args == u"toggleMail") {
AMFFalseValue* value = new AMFFalseValue();
AMFArrayValue args; AMFArrayValue args;
args.InsertValue("visible", value); args.InsertValue("visible", new AMFFalseValue());
GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, "ToggleMail", &args); GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, "ToggleMail", &args);
delete value;
} }
// This should probably get it's own "ServerEvents" system or something at some point // This should probably get it's own "ServerEvents" system or something at some point

View File

@ -276,27 +276,21 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
args.InsertValue("state", state); args.InsertValue("state", state);
GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "pushGameState", &args); GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "pushGameState", &args);
delete state;
} }
entity->AddCallbackTimer(0.5f, [customText, entity] () entity->AddCallbackTimer(0.5f, [customText, entity] ()
{ {
AMFArrayValue args; AMFArrayValue args;
auto* visiable = new AMFTrueValue();
auto* text = new AMFStringValue(); auto* text = new AMFStringValue();
text->SetStringValue(customText); text->SetStringValue(customText);
args.InsertValue("visible", visiable); args.InsertValue("visible", new AMFTrueValue());
args.InsertValue("text", text); args.InsertValue("text", text);
Game::logger->Log("SlashCommandHandler", "Sending \n%s\n", customText.c_str()); Game::logger->Log("SlashCommandHandler", "Sending \n%s\n", customText.c_str());
GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "ToggleStoryBox", &args); GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "ToggleStoryBox", &args);
delete visiable;
delete text;
}); });
return; return;
@ -556,8 +550,6 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
ChatPackets::SendSystemMessage(sysAddr, u"Switched UI state."); ChatPackets::SendSystemMessage(sysAddr, u"Switched UI state.");
delete value;
return; return;
} }
@ -570,8 +562,6 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
ChatPackets::SendSystemMessage(sysAddr, u"Toggled UI state."); ChatPackets::SendSystemMessage(sysAddr, u"Toggled UI state.");
delete value;
return; return;
} }
@ -1578,11 +1568,8 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
if ((chatCommand == "debugui") && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { if ((chatCommand == "debugui") && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) {
ChatPackets::SendSystemMessage(sysAddr, u"Opening UIDebugger..."); ChatPackets::SendSystemMessage(sysAddr, u"Opening UIDebugger...");
AMFStringValue* value = new AMFStringValue();
value->SetStringValue("ToggleUIDebugger;");
AMFArrayValue args; AMFArrayValue args;
GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, value->GetStringValue(), &args); GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, "ToggleUIDebugger;", nullptr);
delete value;
} }
if ((chatCommand == "boost") && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { if ((chatCommand == "boost") && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) {
@ -2008,11 +1995,6 @@ void SlashCommandHandler::SendAnnouncement(const std::string& title, const std::
GameMessages::SendUIMessageServerToAllClients("ToggleAnnounce", &args); GameMessages::SendUIMessageServerToAllClients("ToggleAnnounce", &args);
delete titleValue;
delete messageValue;
titleValue = nullptr;
messageValue = nullptr;
//Notify chat about it //Notify chat about it
CBITSTREAM; CBITSTREAM;
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ANNOUNCEMENT); PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ANNOUNCEMENT);

View File

@ -9,8 +9,6 @@ void BankInteractServer::OnUse(Entity* self, Entity* user)
args.InsertValue("state", bank); args.InsertValue("state", bank);
GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "pushGameState", &args); GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "pushGameState", &args);
delete bank;
} }
void BankInteractServer::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, void BankInteractServer::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1,
@ -19,13 +17,10 @@ void BankInteractServer::OnFireEventServerSide(Entity *self, Entity *sender, std
if (args == "ToggleBank") if (args == "ToggleBank")
{ {
AMFArrayValue args; AMFArrayValue args;
AMFFalseValue* amfFalse = new AMFFalseValue(); args.InsertValue("visible", new AMFFalseValue());
args.InsertValue("visible", amfFalse);
GameMessages::SendUIMessageServerToSingleClient(sender, sender->GetSystemAddress(), "ToggleBank", &args); GameMessages::SendUIMessageServerToSingleClient(sender, sender->GetSystemAddress(), "ToggleBank", &args);
delete amfFalse;
GameMessages::SendNotifyClientObject(self->GetObjectID(), u"CloseBank", 0, 0, LWOOBJID_EMPTY, "", sender->GetSystemAddress()); GameMessages::SendNotifyClientObject(self->GetObjectID(), u"CloseBank", 0, 0, LWOOBJID_EMPTY, "", sender->GetSystemAddress());
} }
} }

View File

@ -8,5 +8,4 @@ void MailBoxServer::OnUse(Entity* self, Entity* user) {
AMFArrayValue args; AMFArrayValue args;
args.InsertValue("state", value); args.InsertValue("state", value);
GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "pushGameState", &args); GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "pushGameState", &args);
delete value;
} }

View File

@ -13,21 +13,6 @@ void NsLegoClubDoor::OnStartup(Entity* self)
args = {}; args = {};
/**
{ {0,{
{"image", "textures/ui/zone_thumnails/Nimbus_Station.dds"},
{"caption", "%[UI_CHOICE_NS]"}, -- "%[LOC_STRING]" is the format for sending localization tokens to the choice box
{"identifier", "zoneID_1200"},
{"tooltipText", "%[UI_CHOICE_NS_HOVER]"}
}},
{1,{
{"image", "textures/ui/zone_thumnails/Nexus_Tower.dds"},
{"caption", "%[UI_CHOICE_NT]"},
{"identifier", "zoneID_1900"},
{"tooltipText", "%[UI_CHOICE_NT_HOVER]"}
} } }
*/
AMFStringValue* callbackClient = new AMFStringValue(); AMFStringValue* callbackClient = new AMFStringValue();
callbackClient->SetStringValue(std::to_string(self->GetObjectID())); callbackClient->SetStringValue(std::to_string(self->GetObjectID()));
args.InsertValue("callbackClient", callbackClient); args.InsertValue("callbackClient", callbackClient);
@ -97,12 +82,6 @@ void NsLegoClubDoor::OnUse(Entity* self, Entity* user)
if (CheckChoice(self, player)) if (CheckChoice(self, player))
{ {
/**
{ {"callbackClient", self},
{"strIdentifier", "choiceDoor"},
{"title", "%[UI_CHOICE_DESTINATION]"},
{"options", choiceOptions} }
*/
AMFArrayValue* multiArgs = new AMFArrayValue(); AMFArrayValue* multiArgs = new AMFArrayValue();
AMFStringValue* callbackClient = new AMFStringValue(); AMFStringValue* callbackClient = new AMFStringValue();
@ -120,19 +99,9 @@ void NsLegoClubDoor::OnUse(Entity* self, Entity* user)
multiArgs->InsertValue("options", options); multiArgs->InsertValue("options", options);
GameMessages::SendUIMessageServerToSingleClient(player, player->GetSystemAddress(), "QueueChoiceBox", multiArgs); GameMessages::SendUIMessageServerToSingleClient(player, player->GetSystemAddress(), "QueueChoiceBox", multiArgs);
delete multiArgs;
delete callbackClient;
delete strIdentifier;
delete title;
} }
else if (self->GetVar<int32_t>(u"currentZone") != m_ChoiceZoneID) else if (self->GetVar<int32_t>(u"currentZone") != m_ChoiceZoneID)
{ {
/**
{ {"state", "Lobby"},
{"context", {{"user", msg.user}, {"callbackObj", self},
{"HelpVisible", "show" }, {"type", "Lego_Club_Valid"}} }}
*/
AMFArrayValue* multiArgs = new AMFArrayValue(); AMFArrayValue* multiArgs = new AMFArrayValue();
AMFStringValue* state = new AMFStringValue(); AMFStringValue* state = new AMFStringValue();
@ -160,14 +129,6 @@ void NsLegoClubDoor::OnUse(Entity* self, Entity* user)
multiArgs->InsertValue("context", context); multiArgs->InsertValue("context", context);
GameMessages::SendUIMessageServerToSingleClient(player, player->GetSystemAddress(), "pushGameState", multiArgs); GameMessages::SendUIMessageServerToSingleClient(player, player->GetSystemAddress(), "pushGameState", multiArgs);
delete multiArgs;
delete state;
delete context;
delete user;
delete callbackObj;
delete helpVisible;
delete type;
} }
else else
{ {

View File

@ -24,7 +24,6 @@ void PropertyBankInteract::OnUse(Entity *self, Entity *user) {
args.InsertValue("state", value); args.InsertValue("state", value);
GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "pushGameState", &args); GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "pushGameState", &args);
delete value;
GameMessages::SendNotifyClientObject(self->GetObjectID(), u"OpenBank", 0, 0, LWOOBJID_EMPTY, GameMessages::SendNotifyClientObject(self->GetObjectID(), u"OpenBank", 0, 0, LWOOBJID_EMPTY,
"", user->GetSystemAddress()); "", user->GetSystemAddress());
@ -34,13 +33,10 @@ void PropertyBankInteract::OnFireEventServerSide(Entity *self, Entity *sender, s
int32_t param2, int32_t param3) { int32_t param2, int32_t param3) {
if (args == "ToggleBank") { if (args == "ToggleBank") {
AMFArrayValue amfArgs; AMFArrayValue amfArgs;
auto* amfFalse = new AMFFalseValue(); amfArgs.InsertValue("visible", new AMFFalseValue());
amfArgs.InsertValue("visible", amfFalse);
GameMessages::SendUIMessageServerToSingleClient(sender, sender->GetSystemAddress(), "ToggleBank", &amfArgs); GameMessages::SendUIMessageServerToSingleClient(sender, sender->GetSystemAddress(), "ToggleBank", &amfArgs);
delete amfFalse;
GameMessages::SendNotifyClientObject(self->GetObjectID(), u"CloseBank", 0, 0, LWOOBJID_EMPTY, GameMessages::SendNotifyClientObject(self->GetObjectID(), u"CloseBank", 0, 0, LWOOBJID_EMPTY,
"", sender->GetSystemAddress()); "", sender->GetSystemAddress());
} }

View File

@ -18,24 +18,18 @@ void StoryBoxInteractServer::OnUse(Entity* self, Entity* user) {
args.InsertValue("state", state); args.InsertValue("state", state);
GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "pushGameState", &args); GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "pushGameState", &args);
delete state;
} }
user->AddCallbackTimer(0.1f, [user, customText] () { user->AddCallbackTimer(0.1f, [user, customText] () {
AMFArrayValue args; AMFArrayValue args;
auto* visiable = new AMFTrueValue();
auto* text = new AMFStringValue(); auto* text = new AMFStringValue();
text->SetStringValue(customText); text->SetStringValue(customText);
args.InsertValue("visible", visiable); args.InsertValue("visible", new AMFTrueValue());
args.InsertValue("text", text); args.InsertValue("text", text);
GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "ToggleStoryBox", &args); GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "ToggleStoryBox", &args);
delete visiable;
delete text;
}); });
return; return;

View File

@ -577,11 +577,6 @@ void HandlePacketChat(Packet* packet) {
GameMessages::SendUIMessageServerToAllClients("ToggleAnnounce", &args); GameMessages::SendUIMessageServerToAllClients("ToggleAnnounce", &args);
delete titleValue;
delete messageValue;
titleValue = nullptr;
messageValue = nullptr;
break; break;
} }

View File

@ -129,20 +129,25 @@ int ReadAMFArrayFromBitStream() {
ASSERT_EQ(static_cast<AMFArrayValue*>(res.get())->GetDenseArray().size(), 0); ASSERT_EQ(static_cast<AMFArrayValue*>(res.get())->GetDenseArray().size(), 0);
} }
bitStream.Reset(); bitStream.Reset();
// Test a key'd value // Test a key'd value and dense value
bitStream.Write<uint8_t>(0x09); bitStream.Write<uint8_t>(0x09);
bitStream.Write<uint8_t>(0x01); bitStream.Write<uint8_t>(0x03);
bitStream.Write<uint8_t>(0x15); bitStream.Write<uint8_t>(0x15);
for (auto e : "BehaviorID") if (e != '\0') bitStream.Write<char>(e); for (auto e : "BehaviorID") if (e != '\0') bitStream.Write<char>(e);
bitStream.Write<uint8_t>(0x06); bitStream.Write<uint8_t>(0x06);
bitStream.Write<uint8_t>(0x0B); bitStream.Write<uint8_t>(0x0B);
for (auto e : "10447") if (e != '\0') bitStream.Write<char>(e); for (auto e : "10447") if (e != '\0') bitStream.Write<char>(e);
bitStream.Write<uint8_t>(0x01); bitStream.Write<uint8_t>(0x01);
bitStream.Write<uint8_t>(0x06);
bitStream.Write<uint8_t>(0x0B);
for (auto e : "10447") if (e != '\0') bitStream.Write<char>(e);
{ {
std::unique_ptr<AMFValue> res(ReadFromBitStream(&bitStream)); std::unique_ptr<AMFValue> res(ReadFromBitStream(&bitStream));
ASSERT_EQ(res->GetValueType(), AMFValueType::AMFArray); ASSERT_EQ(res->GetValueType(), AMFValueType::AMFArray);
ASSERT_EQ(static_cast<AMFArrayValue*>(res.get())->GetAssociativeMap().size(), 1); ASSERT_EQ(static_cast<AMFArrayValue*>(res.get())->GetAssociativeMap().size(), 1);
ASSERT_EQ(static_cast<AMFArrayValue*>(res.get())->GetDenseArray().size(), 1);
ASSERT_EQ(static_cast<AMFStringValue*>(static_cast<AMFArrayValue*>(res.get())->FindValue("BehaviorID"))->GetStringValue(), "10447"); ASSERT_EQ(static_cast<AMFStringValue*>(static_cast<AMFArrayValue*>(res.get())->FindValue("BehaviorID"))->GetStringValue(), "10447");
ASSERT_EQ(static_cast<AMFStringValue*>(static_cast<AMFArrayValue*>(res.get())->GetDenseArray()[0])->GetStringValue(), "10447");
} }
// Test a dense array // Test a dense array
return 0; return 0;