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;
|
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;
|
ModEntry m;
|
||||||
m.path = name;
|
m.path = name;
|
||||||
m.id = self->modEntries.size();
|
m.id = modEntries.size();
|
||||||
|
|
||||||
XMLDocument d;
|
XMLDocument d;
|
||||||
if(!Mod::loadModXML(&d, name))
|
if(!Mod::loadModXML(&d, name))
|
||||||
|
@ -1713,21 +1705,58 @@ void DSQ::LoadModsCallback(const std::string &filename, void *param)
|
||||||
if(!err)
|
if(!err)
|
||||||
err = "<unknown error>";
|
err = "<unknown error>";
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
os << "Failed to load mod xml: " << filename << " -- Error: " << err;
|
os << "Failed to load mod xml: " << name << " -- Error: " << err;
|
||||||
debugLog(os.str());
|
debugLog(os.str());
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m.type = Mod::getTypeFromXML(d.FirstChildElement("AquariaMod"));
|
m.type = Mod::getTypeFromXML(d.FirstChildElement("AquariaMod"));
|
||||||
|
|
||||||
self->modEntries.push_back(m);
|
modEntries.push_back(m);
|
||||||
|
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << "Loaded ModEntry [" << m.path << "] -> " << m.id << " | type " << m.type;
|
ss << "Loaded ModEntry [" << m.path << "] -> " << m.id << " | type " << m.type;
|
||||||
|
|
||||||
debugLog(ss.str());
|
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)
|
void DSQ::LoadModPackagesCallback(const std::string &filename, void *param)
|
||||||
{
|
{
|
||||||
DSQ *self = (DSQ*)param;
|
DSQ *self = (DSQ*)param;
|
||||||
|
@ -1772,7 +1801,17 @@ void DSQ::loadMods()
|
||||||
forEachFile(modpath, ".aqmod", LoadModPackagesCallback, this);
|
forEachFile(modpath, ".aqmod", LoadModPackagesCallback, this);
|
||||||
#endif
|
#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;
|
selectedMod = 0;
|
||||||
|
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
|
|
|
@ -305,7 +305,7 @@ public:
|
||||||
bool mountModPackage(const std::string&);
|
bool mountModPackage(const std::string&);
|
||||||
bool modIsKnown(const std::string& name);
|
bool modIsKnown(const std::string& name);
|
||||||
void unloadMods();
|
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);
|
static void LoadModPackagesCallback(const std::string &filename, void *param);
|
||||||
|
|
||||||
AquariaSaveSlot *selectedSaveSlot;
|
AquariaSaveSlot *selectedSaveSlot;
|
||||||
|
|
|
@ -87,7 +87,10 @@ bool Mod::isEditorBlocked() const
|
||||||
|
|
||||||
bool Mod::loadModXML(XMLDocument *d, std::string modName)
|
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))
|
if(!dsq->modIsKnown(localname))
|
||||||
{
|
{
|
||||||
// yay, got something new!
|
// 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)
|
if(dsq->modSelectorScr)
|
||||||
dsq->modSelectorScr->initModAndPatchPanel(); // HACK
|
dsq->modSelectorScr->initModAndPatchPanel(); // HACK
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,9 +202,15 @@ void forEachFile_vfscallback(VFILE *vf, void *user)
|
||||||
d->callback(*(d->path) + vf->name(), d->param);
|
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
|
#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;
|
if (inpath.empty()) return;
|
||||||
|
|
||||||
|
@ -331,6 +337,152 @@ void forEachFile(const std::string& inpath, std::string type, void callback(cons
|
||||||
#endif
|
#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
|
#if BBGE_BUILD_UNIX
|
||||||
|
|
|
@ -6,7 +6,11 @@
|
||||||
void initIcon(void *screen);
|
void initIcon(void *screen);
|
||||||
void destroyIcon();
|
void destroyIcon();
|
||||||
void messageBox(const std::string &title, const std::string& msg);
|
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 char *_buf);
|
||||||
std::string adjustFilenameCase(const std::string&);
|
std::string adjustFilenameCase(const std::string&);
|
||||||
bool createDir(const std::string& d);
|
bool createDir(const std::string& d);
|
||||||
|
|
Loading…
Reference in a new issue