307 lines
9.7 KiB
C++
307 lines
9.7 KiB
C++
/*
|
|
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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#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<const Buffer> 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<const char*>(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<WorldSummary>* summary) const
|
|
{
|
|
for (WorldMap::const_iterator iter = m_manifest.begin(); iter != m_manifest.end(); ++iter)
|
|
{
|
|
summary->push_back(WorldSummary(iter->first));
|
|
}
|
|
}
|
|
|
|
boost::shared_ptr<World> 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<World>();
|
|
}
|
|
|
|
const boost::shared_ptr<const Buffer> 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<World>();
|
|
}
|
|
|
|
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<World>();
|
|
}
|
|
|
|
boost::shared_ptr<World> 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> 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<World>();
|
|
}
|
|
|
|
if (!actor)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
const boost::shared_ptr<ActorPropertyScript> propertyScript = actor->AddProperty<ActorPropertyScript>().lock();
|
|
for (std::map<std::string, std::string>::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<World>();
|
|
}
|
|
}
|
|
}
|
|
|
|
return world;
|
|
}
|
|
|
|
bool WorldManifest::SaveWorld(const char* worldAlias, const boost::shared_ptr<World>& 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<boost::weak_ptr<Actor> > actors;
|
|
world->GetActorManager()->EnumerateActors(&actors);
|
|
|
|
for (std::vector<boost::weak_ptr<Actor> >::iterator iter = actors.begin(); iter != actors.end(); ++iter)
|
|
{
|
|
const boost::shared_ptr<Actor> 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<ActorPropertyScript> propertyScript = actor->GetProperty<ActorPropertyScript>().lock();
|
|
if (propertyScript)
|
|
{
|
|
WorldActorPropertyHeader(ACTOR_PROPERTY_TYPE_SCRIPT).Serialize(&data);
|
|
|
|
std::vector<std::string> names;
|
|
propertyScript->EnumerateParameters(&names);
|
|
|
|
WorldActorPropertyScript worldPropertyScript;
|
|
for (std::vector<std::string>::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<int>(parameters.size()));
|
|
|
|
for (ScriptMap::const_iterator iter = parameters.begin(); iter != parameters.end(); ++iter)
|
|
{
|
|
data->WriteString(iter->first);
|
|
data->WriteString(iter->second);
|
|
}
|
|
}
|