#include "ModelComponent.h" #include "Entity.h" #include "Game.h" #include "Logger.h" #include "BehaviorStates.h" #include "ControlBehaviorMsgs.h" #include "tinyxml2.h" #include "SimplePhysicsComponent.h" #include "Database.h" ModelComponent::ModelComponent(Entity* parent) : Component(parent) { m_OriginalPosition = m_Parent->GetDefaultPosition(); m_OriginalRotation = m_Parent->GetDefaultRotation(); m_userModelID = m_Parent->GetVarAs(u"userModelID"); } void ModelComponent::LoadBehaviors() { auto behaviors = GeneralUtils::SplitString(m_Parent->GetVar(u"userModelBehaviors"), ','); for (const auto& behavior : behaviors) { if (behavior.empty()) continue; const auto behaviorId = GeneralUtils::TryParse(behavior); if (!behaviorId.has_value() || behaviorId.value() == 0) continue; LOG_DEBUG("Loading behavior %d", behaviorId.value()); auto& inserted = m_Behaviors.emplace_back(); inserted.SetBehaviorId(*behaviorId); const auto behaviorStr = Database::Get()->GetBehavior(behaviorId.value()); tinyxml2::XMLDocument behaviorXml; auto res = behaviorXml.Parse(behaviorStr.c_str(), behaviorStr.size()); LOG_DEBUG("Behavior %i %d: %s", res, behaviorId.value(), behaviorStr.c_str()); const auto* const behaviorRoot = behaviorXml.FirstChildElement("Behavior"); if (!behaviorRoot) { LOG("Failed to load behavior %d due to missing behavior root", behaviorId.value()); continue; } inserted.Deserialize(*behaviorRoot); } } void ModelComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { // ItemComponent Serialization. Pets do not get this serialization. if (!m_Parent->HasComponent(eReplicaComponentType::PET)) { outBitStream.Write1(); outBitStream.Write(m_userModelID != LWOOBJID_EMPTY ? m_userModelID : m_Parent->GetObjectID()); outBitStream.Write(0); outBitStream.Write0(); } //actual model component: outBitStream.Write1(); // Yes we are writing model info outBitStream.Write0(); // Is pickable outBitStream.Write(2); // Physics type outBitStream.Write(m_OriginalPosition); // Original position outBitStream.Write(m_OriginalRotation); // Original rotation outBitStream.Write1(); // We are writing behavior info outBitStream.Write(0); // Number of behaviors outBitStream.Write1(); // Is this model paused if (bIsInitialUpdate) outBitStream.Write0(); // We are not writing model editing info } void ModelComponent::UpdatePendingBehaviorId(const int32_t newId) { for (auto& behavior : m_Behaviors) if (behavior.GetBehaviorId() == -1) behavior.SetBehaviorId(newId); } void ModelComponent::SendBehaviorListToClient(AMFArrayValue& args) const { args.Insert("objectID", std::to_string(m_Parent->GetObjectID())); auto* behaviorArray = args.InsertArray("behaviors"); for (auto& behavior : m_Behaviors) { auto* behaviorArgs = behaviorArray->PushArray(); behavior.SendBehaviorListToClient(*behaviorArgs); } } void ModelComponent::VerifyBehaviors() { for (auto& behavior : m_Behaviors) behavior.VerifyLastEditedState(); } void ModelComponent::SendBehaviorBlocksToClient(int32_t behaviorToSend, AMFArrayValue& args) const { args.Insert("BehaviorID", std::to_string(behaviorToSend)); args.Insert("objectID", std::to_string(m_Parent->GetObjectID())); for (auto& behavior : m_Behaviors) if (behavior.GetBehaviorId() == behaviorToSend) behavior.SendBehaviorBlocksToClient(args); } void ModelComponent::AddBehavior(AddMessage& msg) { // Can only have 1 of the loot behaviors for (auto& behavior : m_Behaviors) if (behavior.GetBehaviorId() == msg.GetBehaviorId()) return; m_Behaviors.insert(m_Behaviors.begin() + msg.GetBehaviorIndex(), PropertyBehavior()); m_Behaviors.at(msg.GetBehaviorIndex()).HandleMsg(msg); auto* const simplePhysComponent = m_Parent->GetComponent(); if (simplePhysComponent) { simplePhysComponent->SetPhysicsMotionState(1); Game::entityManager->SerializeEntity(m_Parent); } } void ModelComponent::MoveToInventory(MoveToInventoryMessage& msg) { if (msg.GetBehaviorIndex() >= m_Behaviors.size() || m_Behaviors.at(msg.GetBehaviorIndex()).GetBehaviorId() != msg.GetBehaviorId()) return; m_Behaviors.erase(m_Behaviors.begin() + msg.GetBehaviorIndex()); // TODO move to the inventory if (m_Behaviors.empty()) { auto* const simplePhysComponent = m_Parent->GetComponent(); if (simplePhysComponent) { simplePhysComponent->SetPhysicsMotionState(4); Game::entityManager->SerializeEntity(m_Parent); } } } std::array, 5> ModelComponent::GetBehaviorsForSave() const { std::array, 5> toReturn{}; for (auto i = 0; i < m_Behaviors.size(); i++) { const auto& behavior = m_Behaviors.at(i); if (behavior.GetBehaviorId() == -1) continue; auto& [id, behaviorData] = toReturn[i]; id = behavior.GetBehaviorId(); tinyxml2::XMLDocument doc; auto* root = doc.NewElement("Behavior"); behavior.Serialize(*root); doc.InsertFirstChild(root); tinyxml2::XMLPrinter printer(0, true, 0); doc.Print(&printer); behaviorData = printer.CStr(); } return toReturn; }