Skip to content

Commit

Permalink
Extend info file module interface and introduce MapPropertyInfoFileMo…
Browse files Browse the repository at this point in the history
…dule exporting and importing the properties to the info file.
  • Loading branch information
codereader committed Jan 19, 2020
1 parent 3126a33 commit 3eae41f
Show file tree
Hide file tree
Showing 19 changed files with 274 additions and 1 deletion.
13 changes: 12 additions & 1 deletion include/imapinfofile.h
Expand Up @@ -42,11 +42,17 @@ class IMapInfoFileModule
virtual std::string getName() = 0;

/**
* Called before any node is written to the .map file. Use tihs
* Called before any node is written to the .map file. Use this
* to prepare the internal structures for exporting.
*/
virtual void onInfoFileSaveStart() = 0;

/**
* Called before starting the actual node traversal,
* the info file exporter gets a chance to look at the map root.
*/
virtual void onBeginSaveMap(const scene::IMapRootNodePtr& root) = 0;

/**
* Called during map export traversal when a single
* primitive is about to be written to the .map file.
Expand All @@ -64,6 +70,11 @@ class IMapInfoFileModule
*/
virtual void onSaveEntity(const scene::INodePtr& node, std::size_t entityNum) = 0;

/**
* Called after node traversal.
*/
virtual void onFinishSaveMap(const scene::IMapRootNodePtr& root) = 0;

/**
* Final export function, write the assembled data to the
* info file stream. This method should include the block file name
Expand Down
10 changes: 10 additions & 0 deletions libs/KeyValueStore.h
Expand Up @@ -16,6 +16,16 @@ class KeyValueStore :
KeyValues _keyValues;

public:
std::size_t getPropertyCount() const
{
return _keyValues.size();
}

void clearProperties()
{
_keyValues.clear();
}

virtual std::string getProperty(const std::string& key, const std::string& value) const
{
auto existing = _keyValues.find(key);
Expand Down
1 change: 1 addition & 0 deletions radiant/Makefile.am
Expand Up @@ -410,6 +410,7 @@ darkradiant_SOURCES = main.cpp \
map/MapPosition.cpp \
map/EditingStopwatch.cpp \
map/EditingStopwatchInfoFileModule.cpp \
map/MapPropertyInfoFileModule.cpp \
map/FindMapElements.cpp \
map/infofile/InfoFileManager.cpp \
map/infofile/InfoFile.cpp \
Expand Down
6 changes: 6 additions & 0 deletions radiant/layers/LayerInfoFileModule.cpp
Expand Up @@ -38,6 +38,12 @@ void LayerInfoFileModule::onInfoFileSaveStart()
_output.clear();
}

void LayerInfoFileModule::onBeginSaveMap(const scene::IMapRootNodePtr& root)
{}

void LayerInfoFileModule::onFinishSaveMap(const scene::IMapRootNodePtr& root)
{}

void LayerInfoFileModule::onSavePrimitive(const INodePtr& node, std::size_t entityNum, std::size_t primitiveNum)
{
saveNode(node);
Expand Down
2 changes: 2 additions & 0 deletions radiant/layers/LayerInfoFileModule.h
Expand Up @@ -32,6 +32,8 @@ class LayerInfoFileModule :
std::string getName() override;

void onInfoFileSaveStart() override;
void onBeginSaveMap(const scene::IMapRootNodePtr& root) override;
void onFinishSaveMap(const scene::IMapRootNodePtr& root) override;
void onSavePrimitive(const INodePtr& node, std::size_t entityNum, std::size_t primitiveNum) override;
void onSaveEntity(const INodePtr& node, std::size_t entityNum) override;
void writeBlocks(std::ostream& stream) override;
Expand Down
6 changes: 6 additions & 0 deletions radiant/map/EditingStopwatchInfoFileModule.cpp
Expand Up @@ -22,6 +22,12 @@ std::string EditingStopwatchInfoFileModule::getName()
void EditingStopwatchInfoFileModule::onInfoFileSaveStart()
{}

void EditingStopwatchInfoFileModule::onBeginSaveMap(const scene::IMapRootNodePtr& root)
{}

void EditingStopwatchInfoFileModule::onFinishSaveMap(const scene::IMapRootNodePtr& root)
{}

void EditingStopwatchInfoFileModule::onSavePrimitive(const scene::INodePtr& node, std::size_t entityNum, std::size_t primitiveNum)
{}

Expand Down
2 changes: 2 additions & 0 deletions radiant/map/EditingStopwatchInfoFileModule.h
Expand Up @@ -16,6 +16,8 @@ class EditingStopwatchInfoFileModule :
std::string getName() override;

void onInfoFileSaveStart() override;
void onBeginSaveMap(const scene::IMapRootNodePtr& root) override;
void onFinishSaveMap(const scene::IMapRootNodePtr& root) override;
void onSavePrimitive(const scene::INodePtr & node, std::size_t entityNum, std::size_t primitiveNum) override;
void onSaveEntity(const scene::INodePtr & node, std::size_t entityNum) override;
void writeBlocks(std::ostream & stream) override;
Expand Down
8 changes: 8 additions & 0 deletions radiant/map/Map.cpp
Expand Up @@ -16,6 +16,7 @@
#include "iradiant.h"
#include "imainframe.h"
#include "imapresource.h"
#include "imapinfofile.h"
#include "iaasfile.h"
#include "igame.h"

Expand Down Expand Up @@ -52,6 +53,7 @@
#include "modulesystem/ModuleRegistry.h"
#include "modulesystem/StaticModule.h"
#include "RenderableAasFile.h"
#include "MapPropertyInfoFileModule.h"

#include <fmt/format.h>
#include "algorithm/ChildPrimitives.h"
Expand Down Expand Up @@ -986,6 +988,7 @@ const StringSet& Map::getDependencies() const
_dependencies.insert(MODULE_RADIANT);
_dependencies.insert(MODULE_GAMEMANAGER);
_dependencies.insert(MODULE_SCENEGRAPH);
_dependencies.insert(MODULE_MAPINFOFILEMANAGER);
_dependencies.insert(MODULE_FILETYPES);
}

Expand All @@ -1008,6 +1011,11 @@ void Map::initialiseModule(const ApplicationContext& ctx)
_scaledModelExporter.initialise();

MapFileManager::registerFileTypes();

// Register an info file module to save the map property bag
GlobalMapInfoFileManager().registerInfoFileModule(
std::make_shared<MapPropertyInfoFileModule>()
);
}

void Map::shutdownModule()
Expand Down
126 changes: 126 additions & 0 deletions radiant/map/MapPropertyInfoFileModule.cpp
@@ -0,0 +1,126 @@
#include "MapPropertyInfoFileModule.h"

#include "itextstream.h"
#include "parser/DefTokeniser.h"
#include "string/replace.h"

namespace map
{

namespace
{
const char* const MAP_PROPERTIES = "MapProperties";
const char* const KEY_VALUE = "KeyValue";
}

std::string MapPropertyInfoFileModule::getName()
{
return "Map Properties";
}

void MapPropertyInfoFileModule::onInfoFileSaveStart()
{}

void MapPropertyInfoFileModule::onBeginSaveMap(const scene::IMapRootNodePtr& root)
{
// Load all the properties from the map root into a local store
root->foreachProperty([this](const std::string& key, const std::string& value)
{
_store.setProperty(key, value);
});
}

void MapPropertyInfoFileModule::onFinishSaveMap(const scene::IMapRootNodePtr& root)
{}

void MapPropertyInfoFileModule::onSavePrimitive(const scene::INodePtr& node, std::size_t entityNum, std::size_t primitiveNum)
{}

void MapPropertyInfoFileModule::onSaveEntity(const scene::INodePtr& node, std::size_t entityNum)
{}

void MapPropertyInfoFileModule::writeBlocks(std::ostream& stream)
{
// Block output
stream << "\t" << MAP_PROPERTIES << std::endl;

stream << "\t{" << std::endl;

_store.foreachProperty([&](const std::string& key, const std::string& value)
{
stream << "\t\t" << KEY_VALUE << " { " <<
"\"" << string::replace_all_copy(key, "\"", "&quot;") << "\"" <<
" " <<
"\"" << string::replace_all_copy(value, "\"", "&quot;") << "\"" <<
" } " << std::endl;
});

stream << "\t}" << std::endl;

rMessage() << "Map Properties written." << std::endl;
}

void MapPropertyInfoFileModule::onInfoFileSaveFinished()
{
_store.clearProperties();
}

void MapPropertyInfoFileModule::onInfoFileLoadStart()
{
_store.clearProperties();
}

bool MapPropertyInfoFileModule::canParseBlock(const std::string& blockName)
{
return blockName == MAP_PROPERTIES;
}

void MapPropertyInfoFileModule::parseBlock(const std::string& blockName, parser::DefTokeniser& tok)
{
// The opening brace
tok.assertNextToken("{");

int blockLevel = 1;

while (tok.hasMoreTokens() && blockLevel > 0)
{
std::string token = tok.nextToken();

if (token == KEY_VALUE)
{
// KeyValue { "Key" "Value" }
tok.assertNextToken("{");

std::string key = tok.nextToken();
std::string value = tok.nextToken();

string::replace_all(key, "&quot;", "\"");
string::replace_all(value, "&quot;", "\"");

tok.assertNextToken("}");
}
else if (token == "{")
{
blockLevel++;
}
else if (token == "}")
{
blockLevel--;
}
}
}

void MapPropertyInfoFileModule::applyInfoToScene(const scene::IMapRootNodePtr& root, const NodeIndexMap& nodeMap)
{
_store.foreachProperty([&](const std::string& key, const std::string& value)
{
root->setProperty(key, value);
});
}

void MapPropertyInfoFileModule::onInfoFileLoadFinished()
{
rMessage() << "[InfoFile]: Parsed " << _store.getPropertyCount() << " map properties." << std::endl;
}

}
37 changes: 37 additions & 0 deletions radiant/map/MapPropertyInfoFileModule.h
@@ -0,0 +1,37 @@
#pragma once

#include "imapinfofile.h"
#include "KeyValueStore.h"

namespace map
{

/**
* Info File Module to persist the map property bag to the
* .darkradiant map info file.
*/
class MapPropertyInfoFileModule :
public IMapInfoFileModule
{
private:
KeyValueStore _store;

public:
std::string getName() override;

void onInfoFileSaveStart() override;
void onBeginSaveMap(const scene::IMapRootNodePtr& root) override;
void onFinishSaveMap(const scene::IMapRootNodePtr& root) override;
void onSavePrimitive(const scene::INodePtr& node, std::size_t entityNum, std::size_t primitiveNum) override;
void onSaveEntity(const scene::INodePtr& node, std::size_t entityNum) override;
void writeBlocks(std::ostream& stream) override;
void onInfoFileSaveFinished() override;

void onInfoFileLoadStart() override;
bool canParseBlock(const std::string& blockName) override;
void parseBlock(const std::string& blockName, parser::DefTokeniser& tok) override;
void applyInfoToScene(const scene::IMapRootNodePtr& root, const NodeIndexMap& nodeMap) override;
void onInfoFileLoadFinished() override;
};

}
21 changes: 21 additions & 0 deletions radiant/map/algorithm/MapExporter.cpp
Expand Up @@ -6,6 +6,7 @@
#include "ibrush.h"
#include "ipatch.h"
#include "ientity.h"
#include "imap.h"
#include "igroupnode.h"
#include "imainframe.h"
#include "../../brush/Brush.h"
Expand Down Expand Up @@ -88,6 +89,16 @@ void MapExporter::exportMap(const scene::INodePtr& root, const GraphTraversalFun
try
{
_writer.beginWriteMap(_mapStream);

if (_infoFileExporter)
{
auto mapRoot = std::dynamic_pointer_cast<scene::IMapRootNode>(root);

if (mapRoot)
{
_infoFileExporter->beginSaveMap(mapRoot);
}
}
}
catch (IMapWriter::FailureException& ex)
{
Expand All @@ -100,6 +111,16 @@ void MapExporter::exportMap(const scene::INodePtr& root, const GraphTraversalFun
try
{
_writer.endWriteMap(_mapStream);

if (_infoFileExporter)
{
auto mapRoot = std::dynamic_pointer_cast<scene::IMapRootNode>(root);

if (mapRoot)
{
_infoFileExporter->finishSaveMap(mapRoot);
}
}
}
catch (IMapWriter::FailureException& ex)
{
Expand Down
16 changes: 16 additions & 0 deletions radiant/map/infofile/InfoFileExporter.cpp
Expand Up @@ -41,6 +41,22 @@ InfoFileExporter::~InfoFileExporter()
});
}

void InfoFileExporter::beginSaveMap(const scene::IMapRootNodePtr& root)
{
GlobalMapInfoFileManager().foreachModule([&](IMapInfoFileModule& module)
{
module.onBeginSaveMap(root);
});
}

void InfoFileExporter::finishSaveMap(const scene::IMapRootNodePtr& root)
{
GlobalMapInfoFileManager().foreachModule([&](IMapInfoFileModule& module)
{
module.onFinishSaveMap(root);
});
}

void InfoFileExporter::visitEntity(const scene::INodePtr& node, std::size_t entityNum)
{
GlobalMapInfoFileManager().foreachModule([&](IMapInfoFileModule& module)
Expand Down
3 changes: 3 additions & 0 deletions radiant/map/infofile/InfoFileExporter.h
Expand Up @@ -3,6 +3,7 @@
#include <ostream>
#include <sstream>
#include "inode.h"
#include "imap.h"
#include <map>

namespace map
Expand All @@ -23,6 +24,8 @@ class InfoFileExporter

// Is called by the owning MapExporter
// Requirements: node must not be NULL and not a model/particle node.
void beginSaveMap(const scene::IMapRootNodePtr& root);
void finishSaveMap(const scene::IMapRootNodePtr& root);
void visitEntity(const scene::INodePtr& node, std::size_t entityNum);
void visitPrimitive(const scene::INodePtr& node, std::size_t entityNum, std::size_t primitiveNum);
};
Expand Down
6 changes: 6 additions & 0 deletions radiant/selection/group/SelectionGroupInfoFileModule.cpp
Expand Up @@ -35,6 +35,12 @@ void SelectionGroupInfoFileModule::onInfoFileSaveStart()
_nodeInfoCount = 0;
}

void SelectionGroupInfoFileModule::onBeginSaveMap(const scene::IMapRootNodePtr& root)
{}

void SelectionGroupInfoFileModule::onFinishSaveMap(const scene::IMapRootNodePtr& root)
{}

void SelectionGroupInfoFileModule::onSavePrimitive(const scene::INodePtr& node, std::size_t entityNum, std::size_t primitiveNum)
{
saveNode(node, entityNum, primitiveNum);
Expand Down

0 comments on commit 3eae41f

Please sign in to comment.