Packages system with .otpkg files

When otclient initializes it tries to find all .otpkg files inside the
current search paths (./ ./modules ./addons) and then add them
to the front of current search paths. This way .otpkg can contains
many modules/addons and modifications in a single file that otclient
can recognize.

otpkg files can be compressed files supported by PhysFS, which
are ZIP (.zip) and LZMA (.7z).
This commit is contained in:
Eduardo Bart 2012-07-16 16:35:14 -03:00
parent 09425eba31
commit bc81c9c8bf
6 changed files with 77 additions and 44 deletions

View File

@ -8,18 +8,21 @@ g_logger.setLogFile(g_resources.getWorkDir() .. g_app.getCompactName() .. ".log"
g_logger.info(g_app.getName() .. ' ' .. g_app.getVersion() .. ' rev ' .. g_app.getBuildRevision() .. ' (' .. g_app.getBuildCommit() .. ') built on ' .. g_app.getBuildDate() .. ' for arch ' .. g_app.getBuildArch())
--add base folder to search path
g_resources.addToSearchPath(g_resources.getWorkDir())
g_resources.addSearchPath(g_resources.getWorkDir())
-- add modules directory to the search path
if not g_resources.addToSearchPath(g_resources.getWorkDir() .. "modules", true) then
if not g_resources.addSearchPath(g_resources.getWorkDir() .. "modules", true) then
g_logger.fatal("Unable to add modules directory to the search path.")
end
-- try to add addons path too
g_resources.addToSearchPath(g_resources.getWorkDir() .. "addons", true)
g_resources.addSearchPath(g_resources.getWorkDir() .. "addons", true)
-- setup directory for saving configurations
g_resources.setupWriteDir(g_app.getCompactName())
g_resources.setupUserWriteDir(g_app.getCompactName())
-- search all packages
g_resources.searchAndAddPackages('/', '.otpkg', true)
-- load configurations
g_configs.load("/config.otml")

View File

@ -27,7 +27,7 @@ function Skins.init()
Skins.installSkins('skins')
if installedSkins[defaultSkinName] then
g_resources.addToSearchPath(getSkinPath(defaultSkinName), 0)
g_resources.addSearchPath(getSkinPath(defaultSkinName), 0)
end
local userSkinName = g_settings.get('skin', 'false')
@ -50,9 +50,9 @@ function Skins.init()
end
function Skins.terminate()
g_resources.removeFromSearchPath(getSkinPath(defaultSkinName))
g_resources.removeSearchPath(getSkinPath(defaultSkinName))
if currentSkin then
g_resources.removeFromSearchPath(getSkinPath(currentSkin.name))
g_resources.removeSearchPath(getSkinPath(currentSkin.name))
end
installedSkins = nil
@ -98,10 +98,12 @@ function Skins.setSkin(name)
Skins.loadSkin(defaultSkin)
end
if currentSkin then
g_resources.removeFromSearchPath(getSkinPath(currentSkin.name))
if currentSkin and currentSkin.name ~= defaultSkinName then
g_resources.removeSearchPath(getSkinPath(currentSkin.name))
end
if skin.name ~= defaultSkinName then
g_resources.addSearchPath(getSkinPath(skin.name), true)
end
g_resources.addToSearchPath(getSkinPath(skin.name), true)
Skins.loadSkin(skin)
currentSkin = skin

View File

@ -38,7 +38,7 @@ function UIMessageBox.display(title, message, flags)
connect(messagebox, { onEscape = function(self) self:cancel() end })
end
messagebox:lock()
--messagebox:lock()
return messagebox
end

View File

@ -65,7 +65,7 @@ void ResourceManager::discoverWorkDir(const std::string& appName, const std::str
g_logger.fatal(stdext::format("Unable to find %s, the application cannot be initialized.", existentFile));
}
bool ResourceManager::setupWriteDir(const std::string& appWriteDirName)
bool ResourceManager::setupUserWriteDir(const std::string& appWriteDirName)
{
std::string userDir = PHYSFS_getUserDir();
std::string dirName;
@ -75,49 +75,69 @@ bool ResourceManager::setupWriteDir(const std::string& appWriteDirName)
dirName = appWriteDirName;
#endif
std::string writeDir = userDir + dirName;
return setWriteDir(writeDir);
}
bool ResourceManager::setWriteDir(const std::string& writeDir, bool create)
{
if(!PHYSFS_setWriteDir(writeDir.c_str()) && !create) {
g_logger.error(stdext::format("Unable to set write directory '%s': %s", writeDir, PHYSFS_getLastError()));
return false;
}
if(!PHYSFS_mkdir(writeDir.c_str())) {
g_logger.error(stdext::format("Unable to create write directory '%s': %s", writeDir, PHYSFS_getLastError()));
return false;
}
if(!PHYSFS_setWriteDir(writeDir.c_str())) {
if(!PHYSFS_setWriteDir(userDir.c_str())) {
g_logger.error("User directory not found.");
return false;
}
if(!PHYSFS_mkdir(dirName.c_str())) {
g_logger.error("Cannot create directory for saving configurations.");
return false;
}
if(!PHYSFS_setWriteDir(writeDir.c_str())) {
g_logger.error("Unable to set write directory.");
return false;
}
g_logger.error(stdext::format("Unable to set write directory '%s': %s", writeDir, PHYSFS_getLastError()));
return false;
}
addToSearchPath(writeDir, true);
//g_logger.debug(stdext::format("Setup write dir %s", writeDir));
if(!m_writeDir.empty())
removeSearchPath(m_writeDir);
m_writeDir = writeDir;
if(!addSearchPath(writeDir))
g_logger.error(stdext::format("Unable to add write directory '%s' to search path"));
return true;
}
bool ResourceManager::addToSearchPath(const std::string& path, bool insertInFront)
bool ResourceManager::addSearchPath(const std::string& path, bool pushFront)
{
if(!PHYSFS_addToSearchPath(path.c_str(), insertInFront ? 0 : 1))
if(!PHYSFS_addToSearchPath(path.c_str(), pushFront ? 0 : 1))
return false;
//g_logger.debug(stdext::format("Add search path %s", path));
if(pushFront)
m_searchPaths.push_front(path);
else
m_searchPaths.push_back(path);
m_hasSearchPath = true;
return true;
}
bool ResourceManager::removeFromSearchPath(const std::string& path)
bool ResourceManager::removeSearchPath(const std::string& path)
{
if(!PHYSFS_removeFromSearchPath(path.c_str()))
return false;
//g_logger.debug(stdext::format("Remove search path %s", path));
auto it = std::find(m_searchPaths.begin(), m_searchPaths.end(), path);
assert(it != m_searchPaths.end());
m_searchPaths.erase(it);
return true;
}
void ResourceManager::searchAndAddPackages(const std::string& packagesDir, const std::string& packageExt, bool append)
void ResourceManager::searchAndAddPackages(const std::string& packagesDir, const std::string& packageExt)
{
auto files = listDirectoryFiles(resolvePath(packagesDir));
for(const std::string& file : files) {
if(boost::ends_with(file, packageExt))
addToSearchPath(packagesDir + "/" + file, !append);
auto files = listDirectoryFiles(packagesDir);
for(auto it = files.rbegin(); it != files.rend(); ++it) {
const std::string& file = *it;
if(!boost::ends_with(file, packageExt))
continue;
std::string package = getRealDir(packagesDir) + "/" + file;
if(!addSearchPath(package, true))
g_logger.error(stdext::format("Unable to read package '%s': %s", package, PHYSFS_getLastError()));
}
}
@ -267,7 +287,7 @@ std::string ResourceManager::resolvePath(const std::string& path)
std::string ResourceManager::getRealDir(const std::string& path)
{
std::string dir;
const char *cdir = PHYSFS_getRealDir(path.c_str());
const char *cdir = PHYSFS_getRealDir(resolvePath(path).c_str());
if(cdir)
dir = cdir;
return dir;

View File

@ -35,11 +35,12 @@ public:
void terminate();
void discoverWorkDir(const std::string& appName, const std::string& existentFile);
bool setupWriteDir(const std::string& appWriteDirName);
bool setupUserWriteDir(const std::string& appWriteDirName);
bool setWriteDir(const std::string& writeDir, bool create = false);
bool addToSearchPath(const std::string& path, bool insertInFront = true);
bool removeFromSearchPath(const std::string& path);
void searchAndAddPackages(const std::string& packagesDir, const std::string& packagesExt, bool append);
bool addSearchPath(const std::string& path, bool pushFront = false);
bool removeSearchPath(const std::string& path);
void searchAndAddPackages(const std::string& packagesDir, const std::string& packagesExt);
bool fileExists(const std::string& fileName);
bool directoryExists(const std::string& directoryName);
@ -64,11 +65,15 @@ public:
std::string resolvePath(const std::string& path);
std::string getRealDir(const std::string& path);
std::string getBaseDir();
std::string getWriteDir() { return m_writeDir; }
std::string getWorkDir() { return m_workDir; }
std::deque<std::string> getSearchPaths() { return m_searchPaths; }
private:
std::string m_workDir;
std::string m_writeDir;
Boolean<false> m_hasSearchPath;
std::deque<std::string> m_searchPaths;
};
extern ResourceManager g_resources;

View File

@ -125,12 +125,15 @@ void Application::registerLuaFunctions()
// ResourceManager
g_lua.registerSingletonClass("g_resources");
g_lua.bindSingletonFunction("g_resources", "addToSearchPath", &ResourceManager::addToSearchPath, &g_resources);
g_lua.bindSingletonFunction("g_resources", "setupWriteDir", &ResourceManager::setupWriteDir, &g_resources);
g_lua.bindSingletonFunction("g_resources", "removeFromSearchPath", &ResourceManager::removeFromSearchPath, &g_resources);
g_lua.bindSingletonFunction("g_resources", "addSearchPath", &ResourceManager::addSearchPath, &g_resources);
g_lua.bindSingletonFunction("g_resources", "setupUserWriteDir", &ResourceManager::setupUserWriteDir, &g_resources);
g_lua.bindSingletonFunction("g_resources", "setWriteDir", &ResourceManager::setWriteDir, &g_resources);
g_lua.bindSingletonFunction("g_resources", "searchAndAddPackages", &ResourceManager::searchAndAddPackages, &g_resources);
g_lua.bindSingletonFunction("g_resources", "removeSearchPath", &ResourceManager::removeSearchPath, &g_resources);
g_lua.bindSingletonFunction("g_resources", "fileExists", &ResourceManager::fileExists, &g_resources);
g_lua.bindSingletonFunction("g_resources", "getRealDir", &ResourceManager::getRealDir, &g_resources);
g_lua.bindSingletonFunction("g_resources", "getWorkDir", &ResourceManager::getWorkDir, &g_resources);
g_lua.bindSingletonFunction("g_resources", "getSearchPaths", &ResourceManager::getSearchPaths, &g_resources);
// Module
g_lua.registerClass<Module>();