/* Moonfall Copyright (C) 2008 Alex Yatskov This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "Pch.h" #include "WorldManifest.h" #include "ActorPropertyScript.h" #include "World.h" #include "Actor.h" bool WorldManifest::LoadManifest(const char* filename) { const boost::shared_ptr buffer = System::LoadFile(filename); if (!buffer) { TRACE_ERROR(boost::format("Cannot load world manifest %s") % filename); return false; } TiXmlDocument document; if (!document.Parse(static_cast(buffer->Get()))) { TRACE_ERROR(boost::format("Cannot parse world manifest %s") % filename); return false; } const TiXmlElement* rootElement = document.RootElement(); if (rootElement == NULL || strcmp(rootElement->Value(), "Manifest") != 0) { return false; } for (const TiXmlElement* worldElement = rootElement->FirstChildElement(); worldElement != NULL; worldElement = worldElement->NextSiblingElement()) { if (strcmp(worldElement->Value(), "World") != 0) { continue; } const char* asset = worldElement->Attribute("asset"); const char* alias = worldElement->Attribute("alias"); if (asset == NULL || alias == NULL) { TRACE_WARNING("World definition is missing required fields"); continue; } if (m_manifest.find(alias) != m_manifest.end()) { TRACE_WARNING(boost::format("Duplicate world %s") % alias); continue; } m_manifest.insert(std::make_pair(alias, asset)); } return true; } void WorldManifest::ClearManifest() { m_manifest.clear(); } void WorldManifest::SummarizeWorlds(std::vector* summary) const { for (WorldMap::const_iterator iter = m_manifest.begin(); iter != m_manifest.end(); ++iter) { summary->push_back(WorldSummary(iter->first)); } } boost::shared_ptr WorldManifest::LoadWorld(const char* worldAlias, const ParameterMap& parameters) const { WorldMap::const_iterator iter = m_manifest.find(worldAlias); if (iter == m_manifest.end()) { TRACE_ERROR(boost::format("Cannot load world %s") % worldAlias); return boost::shared_ptr(); } const boost::shared_ptr buffer = System::LoadFile(iter->second.c_str()); if (!buffer) { TRACE_ERROR(boost::format("Cannot load world from file %s") % iter->second.c_str()); return boost::shared_ptr(); } Deserializer data(buffer.get()); TRACE_INFO(boost::format("Loaded world %s") % worldAlias); WorldHeader worldHeader; if (!worldHeader.Deserialize(&data)) { TRACE_ERROR(boost::format("Invalid world header data")); return boost::shared_ptr(); } boost::shared_ptr world(new World(worldAlias)); world->SetBackdropSpriteAlias(worldHeader.backdrop.c_str()); world->SetScriptAlias(worldHeader.script.c_str()); for (ParameterMap::const_iterator paramIter = parameters.begin(); paramIter != parameters.end(); ++paramIter) { world->SetScriptParameter(paramIter->first.c_str(), paramIter->second); } WorldActor worldActor; while (worldActor.Deserialize(&data)) { const char* actorName = worldActor.name.empty() ? NULL : worldActor.name.c_str(); const boost::shared_ptr actor = world->GetActorManager()->AddActor(worldActor.alias.c_str(), worldActor.position, actorName).lock(); WorldActorPropertyHeader worldPropertyHeader; while (worldPropertyHeader.Deserialize(&data)) { if (worldPropertyHeader.type == ACTOR_PROPERTY_TYPE_SCRIPT) { WorldActorPropertyScript worldPropertyScript; if (!worldPropertyScript.Deserialize(&data)) { TRACE_ERROR(boost::format("Invalid world actor script property")); return boost::shared_ptr(); } if (!actor) { continue; } const boost::shared_ptr propertyScript = actor->AddProperty().lock(); for (std::map::iterator iter = worldPropertyScript.parameters.begin(); iter != worldPropertyScript.parameters.end(); ++iter) { ScriptParameter parameter; if (!propertyScript->GetParameter(iter->first.c_str(), ¶meter)) { TRACE_WARNING(boost::format("Attempted to set unsupported script parameter %s on actor %s, ignoring") % iter->first.c_str() % worldActor.alias.c_str()); continue; } propertyScript->SetParameter(iter->first.c_str(), ScriptParameter(iter->second.c_str(), parameter.type)); } } else { TRACE_ERROR(boost::format("Invalid world actor property")); return boost::shared_ptr(); } } } return world; } bool WorldManifest::SaveWorld(const char* worldAlias, const boost::shared_ptr& world) const { WorldMap::const_iterator iter = m_manifest.find(worldAlias); if (iter == m_manifest.end()) { TRACE_ERROR(boost::format("Cannot save world %s") % worldAlias); return false; } Buffer buffer; Serializer data(&buffer); WorldHeader worldHeader; worldHeader.backdrop = world->GetBackdropSpriteAlias(); worldHeader.script = world->GetScriptAlias(); worldHeader.Serialize(&data); std::vector > actors; world->GetActorManager()->EnumerateActors(&actors); for (std::vector >::iterator iter = actors.begin(); iter != actors.end(); ++iter) { const boost::shared_ptr actor = iter->lock(); if (actor && !actor->IsDynamic()) { WorldActor worldActor; worldActor.alias = actor->GetAlias(); worldActor.name = actor->GetName(); worldActor.position = actor->GetPosition(); worldActor.Serialize(&data); const boost::shared_ptr propertyScript = actor->GetProperty().lock(); if (propertyScript) { WorldActorPropertyHeader(ACTOR_PROPERTY_TYPE_SCRIPT).Serialize(&data); std::vector names; propertyScript->EnumerateParameters(&names); WorldActorPropertyScript worldPropertyScript; for (std::vector::iterator iter = names.begin(); iter != names.end(); ++iter) { ScriptParameter parameter; if (propertyScript->GetParameter(iter->c_str(), ¶meter)) { worldPropertyScript.parameters.insert(std::make_pair(*iter, parameter.value)); } } worldPropertyScript.Serialize(&data); } WorldActorPropertyHeader(ACTOR_PROPERTY_TYPE_DELIMITER).Serialize(&data); } } return System::SaveFile(iter->second.c_str(), buffer); } bool WorldManifest::WorldHeader::Deserialize(Deserializer* data) { int token = 0; int version = 0; return data->Read(&token) && token == WORLD_TOKEN && data->Read(&version) && version == WORLD_VERSION && data->ReadString(&script) && data->ReadString(&backdrop); } void WorldManifest::WorldHeader::Serialize(Serializer* data) const { data->Write(WORLD_TOKEN); data->Write(WORLD_VERSION); data->WriteString(script); data->WriteString(backdrop); } bool WorldManifest::WorldActor::Deserialize(Deserializer* data) { return data->ReadString(&alias) && data->ReadString(&name) && data->Read(&position); } void WorldManifest::WorldActor::Serialize(Serializer* data) const { data->WriteString(alias); data->WriteString(name); data->Write(position); } bool WorldManifest::WorldActorPropertyHeader::Deserialize(Deserializer* data) { return data->Read(&type) && type != ACTOR_PROPERTY_TYPE_DELIMITER; } void WorldManifest::WorldActorPropertyHeader::Serialize(Serializer* data) const { data->Write(type); } bool WorldManifest::WorldActorPropertyScript::Deserialize(Deserializer* data) { parameters.clear(); int count = 0; if (!data->Read(&count)) { return false; } for (int i = 0; i < count; ++i) { std::string name; std::string value; if (!data->ReadString(&name) || !data->ReadString(&value)) { return false; } parameters.insert(std::make_pair(name, value)); } return true; } void WorldManifest::WorldActorPropertyScript::Serialize(Serializer* data) const { data->Write(static_cast(parameters.size())); for (ScriptMap::const_iterator iter = parameters.begin(); iter != parameters.end(); ++iter) { data->WriteString(iter->first); data->WriteString(iter->second); } }