mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2024-11-25 09:44:02 +00:00
Support _mods/modname/mod-info.xml in addition to the old _mods/modname.xml
Needs directory enumeration; I'm not sure that it builds on linux. Will fix if it doesn't.
This commit is contained in:
parent
b59fb507ca
commit
91b7c0bf3f
6 changed files with 217 additions and 19 deletions
|
@ -1692,19 +1692,11 @@ int DSQ::getEntityTypeIndexByName(std::string s)
|
|||
return -1;
|
||||
}
|
||||
|
||||
void DSQ::LoadModsCallback(const std::string &filename, void *param)
|
||||
bool DSQ::loadModByName(const std::string &name)
|
||||
{
|
||||
DSQ *self = (DSQ*)param;
|
||||
|
||||
size_t pos = filename.find_last_of('/')+1;
|
||||
size_t pos2 = filename.find_last_of('.');
|
||||
if(pos2 < pos)
|
||||
return;
|
||||
|
||||
std::string name = filename.substr(pos, pos2-pos);
|
||||
ModEntry m;
|
||||
m.path = name;
|
||||
m.id = self->modEntries.size();
|
||||
m.id = modEntries.size();
|
||||
|
||||
XMLDocument d;
|
||||
if(!Mod::loadModXML(&d, name))
|
||||
|
@ -1713,21 +1705,58 @@ void DSQ::LoadModsCallback(const std::string &filename, void *param)
|
|||
if(!err)
|
||||
err = "<unknown error>";
|
||||
std::ostringstream os;
|
||||
os << "Failed to load mod xml: " << filename << " -- Error: " << err;
|
||||
os << "Failed to load mod xml: " << name << " -- Error: " << err;
|
||||
debugLog(os.str());
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
m.type = Mod::getTypeFromXML(d.FirstChildElement("AquariaMod"));
|
||||
|
||||
self->modEntries.push_back(m);
|
||||
modEntries.push_back(m);
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << "Loaded ModEntry [" << m.path << "] -> " << m.id << " | type " << m.type;
|
||||
|
||||
debugLog(ss.str());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// _mods/themod.xml
|
||||
static void EnumerateOuterModXMLCallback(const std::string &filename, void *param)
|
||||
{
|
||||
std::vector<std::string> *pNames = (std::vector<std::string>*)param;
|
||||
|
||||
size_t pos = filename.find_last_of('/')+1;
|
||||
size_t pos2 = filename.find_last_of('.');
|
||||
if(pos2 < pos)
|
||||
return;
|
||||
|
||||
std::string name = filename.substr(pos, pos2-pos);
|
||||
pNames->push_back(name);
|
||||
}
|
||||
|
||||
// _mods/themod/mod-info.xml
|
||||
static void EnumerateInnerModXMLCallback(const std::string &filename, void *param)
|
||||
{
|
||||
std::vector<std::string> *pNames = (std::vector<std::string>*)param;
|
||||
|
||||
std::string fn = filename;
|
||||
if(fn.empty())
|
||||
return;
|
||||
|
||||
assert(!(fn.back() == '/' || fn.back() == '\''));
|
||||
|
||||
fn += "/mod-info.xml";
|
||||
if(!exists(fn))
|
||||
return;
|
||||
|
||||
size_t pos = filename.find_last_of('/')+1;
|
||||
std::string name = filename.substr(pos);
|
||||
pNames->push_back(name);
|
||||
}
|
||||
|
||||
|
||||
void DSQ::LoadModPackagesCallback(const std::string &filename, void *param)
|
||||
{
|
||||
DSQ *self = (DSQ*)param;
|
||||
|
@ -1772,7 +1801,17 @@ void DSQ::loadMods()
|
|||
forEachFile(modpath, ".aqmod", LoadModPackagesCallback, this);
|
||||
#endif
|
||||
|
||||
forEachFile(modpath, ".xml", LoadModsCallback, this);
|
||||
std::vector<std::string> modnames;
|
||||
|
||||
forEachFile(modpath, ".xml", EnumerateOuterModXMLCallback, &modnames);
|
||||
forEachDir(modpath,EnumerateInnerModXMLCallback, &modnames);
|
||||
|
||||
std::sort(modnames.begin(), modnames.end());
|
||||
modnames.erase(std::unique(modnames.begin(), modnames.end()), modnames.end());
|
||||
|
||||
for(size_t i = 0; i < modnames.size(); ++i)
|
||||
loadModByName(modnames[i]);
|
||||
|
||||
selectedMod = 0;
|
||||
|
||||
std::ostringstream os;
|
||||
|
|
|
@ -305,7 +305,7 @@ public:
|
|||
bool mountModPackage(const std::string&);
|
||||
bool modIsKnown(const std::string& name);
|
||||
void unloadMods();
|
||||
static void LoadModsCallback(const std::string &filename, void *param);
|
||||
bool loadModByName(const std::string &filename);
|
||||
static void LoadModPackagesCallback(const std::string &filename, void *param);
|
||||
|
||||
AquariaSaveSlot *selectedSaveSlot;
|
||||
|
|
|
@ -87,7 +87,10 @@ bool Mod::isEditorBlocked() const
|
|||
|
||||
bool Mod::loadModXML(XMLDocument *d, std::string modName)
|
||||
{
|
||||
return readXML((baseModPath + modName + ".xml").c_str(), *d) == XML_SUCCESS;
|
||||
bool ok = readXML((baseModPath + modName + "/mod-info.xml").c_str(), *d) == XML_SUCCESS;
|
||||
if(!ok)
|
||||
ok = readXML((baseModPath + modName + ".xml").c_str(), *d) == XML_SUCCESS;
|
||||
return ok;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -527,7 +527,7 @@ void ModDL::NotifyMod(ModRequest *rq, NetEvent ev, size_t recvd, size_t total)
|
|||
if(!dsq->modIsKnown(localname))
|
||||
{
|
||||
// yay, got something new!
|
||||
DSQ::LoadModsCallback(archiveFile, dsq); // does not end in ".xml" but thats no problem here
|
||||
dsq->loadModByName(localname); // FIXME: This assumes that the aqmod file, the contained directory, and it's accompanying xml file all have the same base name
|
||||
if(dsq->modSelectorScr)
|
||||
dsq->modSelectorScr->initModAndPatchPanel(); // HACK
|
||||
}
|
||||
|
|
|
@ -202,9 +202,15 @@ void forEachFile_vfscallback(VFILE *vf, void *user)
|
|||
d->callback(*(d->path) + vf->name(), d->param);
|
||||
}
|
||||
|
||||
void forEachDir_vfscallback(ttvfs::DirBase *dir, void *user)
|
||||
{
|
||||
vfscallback_s *d = (vfscallback_s*)user;
|
||||
d->callback(*(d->path) + dir->name(), d->param);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void forEachFile(const std::string& inpath, std::string type, void callback(const std::string &filename, void *param), void *param)
|
||||
void forEachFile(const std::string& inpath, std::string type, FileIterationCallback callback, void *param)
|
||||
{
|
||||
if (inpath.empty()) return;
|
||||
|
||||
|
@ -331,6 +337,152 @@ void forEachFile(const std::string& inpath, std::string type, void callback(cons
|
|||
#endif
|
||||
}
|
||||
|
||||
#if defined(BBGE_BUILD_UNIX)
|
||||
|
||||
template<typename T> struct Has_d_type
|
||||
{
|
||||
struct Fallback { int d_type; };
|
||||
struct Derived : T, Fallback { };
|
||||
template<typename C, C> struct ChT;
|
||||
template<typename C> static char (&f(ChT<int Fallback::*, &C::d_type>*))[1];
|
||||
template<typename C> static char (&f(...))[2];
|
||||
static bool const value = sizeof(f<Derived>(0)) == 2;
|
||||
};
|
||||
|
||||
static bool _unixIsDirectory(const std::string& base, const char *name)
|
||||
{
|
||||
std::string full = base;
|
||||
if(full.back() != '/')
|
||||
full += '/';
|
||||
full += name;
|
||||
struct stat st;
|
||||
int err = ::stat(full.c_str(), &st, 0);
|
||||
if(err == -1)
|
||||
return false;
|
||||
return S_ISDIR(st.st_mode);
|
||||
}
|
||||
|
||||
template<bool has_d_type>
|
||||
struct Unix_IsDir
|
||||
{
|
||||
inline static bool Get(const std::string& base struct dirent *dp)
|
||||
{
|
||||
return _unixIsDirectory(base, dp->d_name);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Unix_IsDir<true>
|
||||
{
|
||||
inline static bool Get(const std::string& base, struct dirent *dp)
|
||||
{
|
||||
switch(dp->d_type)
|
||||
{
|
||||
case DT_DIR:
|
||||
return true;
|
||||
case DT_LNK: // dirent doesn't resolve links, gotta do this manually
|
||||
case DT_UNKNOWN: // file system isn't sure or doesn't support d_type, try this the hard way
|
||||
return _unixIsDirectory(base, dp->d_name);
|
||||
default: ; // avoid warnings
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
static inline tio_FileType unixIsDirectory(const std::string& base, struct dirent *dp)
|
||||
{
|
||||
return Unix_IsDir<Has_d_type<dirent>::value>::Get(pathfd, dp);
|
||||
}
|
||||
|
||||
// skip if "." or ".."
|
||||
static inline bool dirlistSkip(const char* fn)
|
||||
{
|
||||
return fn[0] == '.' && (!fn[1] || (fn[1] == '.' && !fn[2]));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void forEachDir(const std::string& inpath, FileIterationCallback callback, void *param)
|
||||
{
|
||||
if (inpath.empty()) return;
|
||||
|
||||
#ifdef BBGE_BUILD_VFS
|
||||
ttvfs::DirView view;
|
||||
if(!vfs.FillDirView(inpath.c_str(), view))
|
||||
{
|
||||
debugLog("Path '" + inpath + "' does not exist");
|
||||
return;
|
||||
}
|
||||
vfscallback_s dat;
|
||||
dat.path = &inpath;
|
||||
dat.ext = NULL;
|
||||
dat.param = param;
|
||||
dat.callback = callback;
|
||||
view.forEachDir(forEachDir_vfscallback, &dat, true);
|
||||
|
||||
return;
|
||||
// -------------------------------------
|
||||
#endif
|
||||
|
||||
std::string path = adjustFilenameCase(inpath.c_str());
|
||||
debugLog("forEachDir - path: " + path);
|
||||
|
||||
#if defined(BBGE_BUILD_UNIX)
|
||||
struct dirent * dp;
|
||||
DIR *dir=0;
|
||||
dir = opendir(path.c_str());
|
||||
if (dir)
|
||||
{
|
||||
struct dirent * dp;
|
||||
while ( (dp=readdir(dir)) != NULL )
|
||||
{
|
||||
if(!dirlistSkip(dp->d_name))
|
||||
if(unixIsDirectory(inpath, dp))
|
||||
callback(path + std::string(file->d_name), param);
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
debugLog("FAILED TO OPEN DIR");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BBGE_BUILD_WINDOWS
|
||||
BOOL fFinished;
|
||||
HANDLE hList;
|
||||
TCHAR szDir[MAX_PATH+1];
|
||||
WIN32_FIND_DATA FileData;
|
||||
|
||||
size_t end = path.size()-1;
|
||||
if (path[end] != '/')
|
||||
path[end] += '/';
|
||||
|
||||
// Get the proper directory path
|
||||
// \\ %s\\*
|
||||
|
||||
sprintf(szDir, "%s\\*", path.c_str());
|
||||
|
||||
// Get the first file
|
||||
hList = FindFirstFile(szDir, &FileData);
|
||||
if (hList != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
// Traverse through the directory structure
|
||||
for(;;)
|
||||
{
|
||||
if(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
callback(path + FileData.cFileName, param);
|
||||
|
||||
if (!FindNextFile(hList, &FileData))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FindClose(hList);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if BBGE_BUILD_UNIX
|
||||
|
|
|
@ -6,7 +6,11 @@
|
|||
void initIcon(void *screen);
|
||||
void destroyIcon();
|
||||
void messageBox(const std::string &title, const std::string& msg);
|
||||
void forEachFile(const std::string& inpath, std::string type, void callback(const std::string &filename, void *param), void *param = 0);
|
||||
|
||||
typedef void (*FileIterationCallback)(const std::string &filename, void *param);
|
||||
|
||||
void forEachFile(const std::string& inpath, std::string type, FileIterationCallback callback, void *param = 0);
|
||||
void forEachDir(const std::string& inpath, FileIterationCallback callback, void *param = 0);
|
||||
std::string adjustFilenameCase(const char *_buf);
|
||||
std::string adjustFilenameCase(const std::string&);
|
||||
bool createDir(const std::string& d);
|
||||
|
|
Loading…
Reference in a new issue