TerrainTextureManager file loading rewrite. Fixes #3358.

Add directory callback to vfs::ForEachFile.
Each terrain directory should now have a terrains.xml file,
as using the previous terrains.xml file is unlikely to be what was
intended.

This was SVN commit r17341.
This commit is contained in:
leper 2015-11-30 20:12:12 +00:00
parent af202ae963
commit 6f09803e8c
4 changed files with 41 additions and 65 deletions

View File

@ -82,11 +82,6 @@ CTerrainTextureEntry* CTerrainTextureManager::FindTexture(const CStr& tag_) cons
return 0;
}
CTerrainPropertiesPtr CTerrainTextureManager::GetPropertiesFromFile(const CTerrainPropertiesPtr& props, const VfsPath& pathname)
{
return CTerrainProperties::FromXML(props, pathname);
}
CTerrainTextureEntry* CTerrainTextureManager::AddTexture(const CTerrainPropertiesPtr& props, const VfsPath& path)
{
CTerrainTextureEntry* entry = new CTerrainTextureEntry(props, path);
@ -103,64 +98,37 @@ void CTerrainTextureManager::DeleteTexture(CTerrainTextureEntry* entry)
delete entry;
}
// FIXME This could be effectivized by surveying the xml files in the directory
// instead of trial-and-error checking for existence of the xml file through
// the VFS.
// jw: indeed this is inefficient and RecurseDirectory should be implemented
// via VFSUtil::EnumFiles, but it works fine and "only" takes 25ms for
// typical maps. therefore, we'll leave it for now.
void CTerrainTextureManager::LoadTextures(const CTerrainPropertiesPtr& props, const VfsPath& path)
struct AddTextureCallbackData
{
VfsPaths pathnames;
if(vfs::GetPathnames(g_VFS, path, 0, pathnames) < 0)
return;
CTerrainTextureManager* self;
CTerrainPropertiesPtr props;
};
for(size_t i = 0; i < pathnames.size(); i++)
{
if (pathnames[i].Extension() != L".xml")
continue;
if (pathnames[i].Basename() == L"terrains")
continue;
AddTexture(props, pathnames[i]);
}
static Status AddTextureDirCallback(const VfsPath& pathname, const uintptr_t cbData)
{
AddTextureCallbackData& data = *(AddTextureCallbackData*)cbData;
VfsPath path = pathname / L"terrains.xml";
if (!VfsFileExists(path))
LOGMESSAGE("'%s' does not exist. Using previous properties.", path.string8());
else
data.props = CTerrainProperties::FromXML(data.props, path);
return INFO::OK;
}
void CTerrainTextureManager::RecurseDirectory(const CTerrainPropertiesPtr& parentProps, const VfsPath& path)
static Status AddTextureCallback(const VfsPath& pathname, const CFileInfo& UNUSED(fileInfo), const uintptr_t cbData)
{
//LOGMESSAGE("CTextureManager::RecurseDirectory(%s)", path.string8());
AddTextureCallbackData& data = *(AddTextureCallbackData*)cbData;
if (pathname.Basename() != L"terrains")
data.self->AddTexture(data.props, pathname);
CTerrainPropertiesPtr props;
// Load terrains.xml first, if it exists
VfsPath pathname = path / "terrains.xml";
if (VfsFileExists(pathname))
props = GetPropertiesFromFile(parentProps, pathname);
// No terrains.xml, or read failures -> use parent props (i.e.
if (!props)
{
LOGMESSAGE("CTerrainTextureManager::RecurseDirectory(%s): no terrains.xml (or errors while loading) - using parent properties", path.string8());
props = parentProps;
}
// Recurse once for each subdirectory
DirectoryNames subdirectoryNames;
(void)g_VFS->GetDirectoryEntries(path, 0, &subdirectoryNames);
for (size_t i=0;i<subdirectoryNames.size();i++)
{
VfsPath subdirectoryPath = path / subdirectoryNames[i] / "";
RecurseDirectory(props, subdirectoryPath);
}
LoadTextures(props, path);
return INFO::OK;
}
int CTerrainTextureManager::LoadTerrainTextures()
{
CTerrainPropertiesPtr rootProps(new CTerrainProperties(CTerrainPropertiesPtr()));
RecurseDirectory(rootProps, L"art/terrains/");
AddTextureCallbackData data = {this, CTerrainPropertiesPtr(new CTerrainProperties(CTerrainPropertiesPtr()))};
vfs::ForEachFile(g_VFS, L"art/terrains/", AddTextureCallback, (uintptr_t)&data, L"*.xml", vfs::DIR_RECURSIVE, AddTextureDirCallback, (uintptr_t)&data);
return 0;
}

View File

@ -103,15 +103,6 @@ private:
size_t m_LastGroupIndex;
// Find+load all textures in directory; check if
// there's an override XML with the same basename (if there is, load it)
void LoadTextures(const CTerrainPropertiesPtr& props, const VfsPath& path);
// Load all terrains below path, using props as the parent property sheet.
void RecurseDirectory(const CTerrainPropertiesPtr& props, const VfsPath& path);
CTerrainPropertiesPtr GetPropertiesFromFile(const CTerrainPropertiesPtr& props, const VfsPath& pathname);
public:
// constructor, destructor
CTerrainTextureManager();

View File

@ -56,7 +56,7 @@ Status GetPathnames(const PIVFS& fs, const VfsPath& path, const wchar_t* filter,
}
Status ForEachFile(const PIVFS& fs, const VfsPath& startPath, FileCallback cb, uintptr_t cbData, const wchar_t* pattern, size_t flags)
Status ForEachFile(const PIVFS& fs, const VfsPath& startPath, FileCallback cb, uintptr_t cbData, const wchar_t* pattern, size_t flags, DirCallback dircb, uintptr_t dircbData)
{
// (declare here to avoid reallocations)
CFileInfos files;
@ -72,6 +72,9 @@ Status ForEachFile(const PIVFS& fs, const VfsPath& startPath, FileCallback cb, u
RETURN_STATUS_IF_ERR(fs->GetDirectoryEntries(path, &files, &subdirectoryNames));
if(dircb)
RETURN_STATUS_IF_ERR(dircb(path, dircbData));
for(size_t i = 0; i < files.size(); i++)
{
const CFileInfo fileInfo = files[i];

View File

@ -48,13 +48,25 @@ extern Status GetPathnames(const PIVFS& fs, const VfsPath& path, const wchar_t*
**/
typedef Status (*FileCallback)(const VfsPath& pathname, const CFileInfo& fileInfo, const uintptr_t cbData);
/**
* called for directories in a directory.
*
* @param pathname full pathname
* @param cbData user-specified context
* @return INFO::OK on success; any other value will immediately
* be returned to the caller (no more calls will be forthcoming).
*
* CAVEAT: pathname only valid until the function returns!
**/
typedef Status (*DirCallback)(const VfsPath& pathname, const uintptr_t cbData);
enum DirFlags
{
DIR_RECURSIVE = 1
};
/**
* call back for each file in a directory tree
* call back for each file in a directory tree, and optionally each directory.
*
* @param fs
* @param path
@ -63,9 +75,11 @@ enum DirFlags
* @param pattern that file names must match. '*' and '&' wildcards
* are allowed. 0 matches everything.
* @param flags @ref DirFlags
* @param dircb @ref DirCallback
* @param dircbData
* @return Status
**/
extern Status ForEachFile(const PIVFS& fs, const VfsPath& path, FileCallback cb, uintptr_t cbData, const wchar_t* pattern = 0, size_t flags = 0);
extern Status ForEachFile(const PIVFS& fs, const VfsPath& path, FileCallback cb, uintptr_t cbData, const wchar_t* pattern = 0, size_t flags = 0, DirCallback dircb = NULL, uintptr_t dircbData = 0);
/**