Read mod files to get versions... and stuff.
This commit is contained in:
parent
a266e5d0cc
commit
fcd05ca2f6
@ -16,7 +16,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
#include <QIODevice>
|
||||||
|
|
||||||
#include "libsettings_config.h"
|
#include "libsettings_config.h"
|
||||||
|
|
||||||
@ -26,6 +26,7 @@ class LIBSETTINGS_EXPORT INIFile : public QMap<QString, QVariant>
|
|||||||
public:
|
public:
|
||||||
explicit INIFile();
|
explicit INIFile();
|
||||||
|
|
||||||
|
bool loadFile(QByteArray file);
|
||||||
bool loadFile(QString fileName);
|
bool loadFile(QString fileName);
|
||||||
bool saveFile(QString fileName);
|
bool saveFile(QString fileName);
|
||||||
|
|
||||||
|
@ -60,10 +60,16 @@ bool INIFile::saveFile(QString fileName)
|
|||||||
|
|
||||||
bool INIFile::loadFile(QString fileName)
|
bool INIFile::loadFile(QString fileName)
|
||||||
{
|
{
|
||||||
// TODO Handle errors.
|
|
||||||
QFile file(fileName);
|
QFile file(fileName);
|
||||||
file.open(QIODevice::ReadOnly);
|
if(!file.open(QIODevice::ReadOnly))
|
||||||
QTextStream in(&file);
|
return false;
|
||||||
|
bool success = loadFile(file.readAll());
|
||||||
|
file.close();
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
bool INIFile::loadFile( QByteArray file )
|
||||||
|
{
|
||||||
|
QTextStream in(file);
|
||||||
in.setCodec("UTF-8");
|
in.setCodec("UTF-8");
|
||||||
|
|
||||||
QStringList lines = in.readAll().split('\n');
|
QStringList lines = in.readAll().split('\n');
|
||||||
|
240
logic/Mod.cpp
240
logic/Mod.cpp
@ -14,9 +14,20 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QString>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonValue>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <quazip.h>
|
||||||
|
#include <quazipfile.h>
|
||||||
|
|
||||||
#include "Mod.h"
|
#include "Mod.h"
|
||||||
#include <pathutils.h>
|
#include <pathutils.h>
|
||||||
#include <QDir>
|
#include <inifile.h>
|
||||||
|
|
||||||
|
|
||||||
Mod::Mod( const QFileInfo& file )
|
Mod::Mod( const QFileInfo& file )
|
||||||
{
|
{
|
||||||
@ -40,164 +51,117 @@ void Mod::repath ( const QFileInfo& file )
|
|||||||
else
|
else
|
||||||
m_type = MOD_SINGLEFILE;
|
m_type = MOD_SINGLEFILE;
|
||||||
}
|
}
|
||||||
|
if(m_type == MOD_ZIPFILE)
|
||||||
/*
|
|
||||||
switch (modType)
|
|
||||||
{
|
{
|
||||||
case MOD_ZIPFILE:
|
QuaZip zip(m_file.filePath());
|
||||||
|
if(!zip.open(QuaZip::mdUnzip))
|
||||||
|
return;
|
||||||
|
|
||||||
|
QuaZipFile file(&zip);
|
||||||
|
for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile())
|
||||||
{
|
{
|
||||||
wxFFileInputStream fileIn(modFile.GetFullPath());
|
QString name = zip.getCurrentFileName();
|
||||||
wxZipInputStream zipIn(fileIn);
|
if(name == "mcmod.info")
|
||||||
|
|
||||||
std::auto_ptr<wxZipEntry> entry;
|
|
||||||
|
|
||||||
bool is_forge = false;
|
|
||||||
while(true)
|
|
||||||
{
|
{
|
||||||
entry.reset(zipIn.GetNextEntry());
|
if(!file.open(QIODevice::ReadOnly))
|
||||||
if (entry.get() == nullptr)
|
|
||||||
break;
|
|
||||||
if(entry->GetInternalName().EndsWith("mcmod.info"))
|
|
||||||
break;
|
|
||||||
if(entry->GetInternalName().EndsWith("forgeversion.properties"))
|
|
||||||
{
|
{
|
||||||
is_forge = true;
|
zip.close();
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
|
ReadMCModInfo(file.readAll());
|
||||||
|
file.close();
|
||||||
|
zip.close();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
else if(name == "forgeversion.properties")
|
||||||
if (entry.get() != nullptr)
|
|
||||||
{
|
{
|
||||||
// Read the info file into text
|
if(!file.open(QIODevice::ReadOnly))
|
||||||
wxString infoFileData;
|
{
|
||||||
wxStringOutputStream stringOut(&infoFileData);
|
zip.close();
|
||||||
zipIn.Read(stringOut);
|
return;
|
||||||
if(!is_forge)
|
}
|
||||||
ReadModInfoData(infoFileData);
|
ReadForgeInfo(file.readAll());
|
||||||
else
|
file.close();
|
||||||
ReadForgeInfoData(infoFileData);
|
zip.close();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
zip.close();
|
||||||
|
}
|
||||||
case MOD_FOLDER:
|
else if(m_type == MOD_FOLDER)
|
||||||
{
|
{
|
||||||
wxString infoFile = Path::Combine(modFile, "mcmod.info");
|
QFileInfo mcmod_info(PathCombine(m_file.filePath(), "mcmod.info"));
|
||||||
if (!wxFileExists(infoFile))
|
if (mcmod_info.isFile())
|
||||||
{
|
{
|
||||||
infoFile = wxEmptyString;
|
QFile mcmod(mcmod_info.filePath());
|
||||||
|
if(!mcmod.open(QIODevice::ReadOnly))
|
||||||
wxDir modDir(modFile.GetFullPath());
|
return;
|
||||||
|
auto data = mcmod.readAll();
|
||||||
if (!modDir.IsOpened())
|
if(data.isEmpty() || data.isNull())
|
||||||
{
|
return;
|
||||||
wxLogError(_("Can't fine mod info file. Failed to open mod folder."));
|
ReadMCModInfo(data);
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
wxString currentFile;
|
|
||||||
if (modDir.GetFirst(¤tFile))
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (currentFile.EndsWith("mcmod.info"))
|
|
||||||
{
|
|
||||||
infoFile = Path::Combine(modFile.GetFullPath(), currentFile);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (modDir.GetNext(¤tFile));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (infoFile != wxEmptyString && wxFileExists(infoFile))
|
|
||||||
{
|
|
||||||
wxString infoStr;
|
|
||||||
wxFFileInputStream fileIn(infoFile);
|
|
||||||
wxStringOutputStream strOut(&infoStr);
|
|
||||||
fileIn.Read(strOut);
|
|
||||||
ReadModInfoData(infoStr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NEW format
|
||||||
|
// https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/6f62b37cea040daf350dc253eae6326dd9c822c3
|
||||||
|
|
||||||
/*
|
// OLD format:
|
||||||
void ReadModInfoData(QString info)
|
// https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/5bf6a2d05145ec79387acc0d45c958642fb049fc
|
||||||
|
void Mod::ReadMCModInfo(QByteArray contents)
|
||||||
{
|
{
|
||||||
using namespace boost::property_tree;
|
auto getInfoFromArray = [&]( QJsonArray arr ) -> void
|
||||||
|
|
||||||
// Read the data
|
|
||||||
ptree ptRoot;
|
|
||||||
|
|
||||||
std::stringstream stringIn(cStr(info));
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
read_json(stringIn, ptRoot);
|
if(!arr.at(0).isObject())
|
||||||
|
return;
|
||||||
ptree pt = ptRoot.get_child(ptRoot.count("modlist") == 1 ? "modlist" : "").begin()->second;
|
auto firstObj = arr.at(0).toObject();
|
||||||
|
m_id = firstObj.value("modid").toString();
|
||||||
modID = wxStr(pt.get<std::string>("modid"));
|
m_name = firstObj.value("name").toString();
|
||||||
modName = wxStr(pt.get<std::string>("name"));
|
m_version = firstObj.value("version").toString();
|
||||||
modVersion = wxStr(pt.get<std::string>("version"));
|
return;
|
||||||
|
};
|
||||||
|
QJsonParseError jsonError;
|
||||||
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(contents, &jsonError);
|
||||||
|
// this is the very old format that had just the array
|
||||||
|
if(jsonDoc.isArray())
|
||||||
|
{
|
||||||
|
getInfoFromArray(jsonDoc.array());
|
||||||
}
|
}
|
||||||
catch (json_parser_error e)
|
else if(jsonDoc.isObject())
|
||||||
{
|
{
|
||||||
// Silently fail...
|
auto val = jsonDoc.object().value("modinfoversion");
|
||||||
}
|
int version = val.toDouble();
|
||||||
catch (ptree_error e)
|
if(version != 2)
|
||||||
{
|
|
||||||
// Silently fail...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// FIXME: abstraction violated.
|
|
||||||
/*
|
|
||||||
void Mod::ReadForgeInfoData(QString infoFileData)
|
|
||||||
{
|
|
||||||
using namespace boost::property_tree;
|
|
||||||
|
|
||||||
// Read the data
|
|
||||||
ptree ptRoot;
|
|
||||||
modName = "Minecraft Forge";
|
|
||||||
modID = "Forge";
|
|
||||||
std::stringstream stringIn(cStr(infoFileData));
|
|
||||||
try
|
|
||||||
{
|
|
||||||
read_ini(stringIn, ptRoot);
|
|
||||||
wxString major, minor, revision, build;
|
|
||||||
// BUG: boost property tree is bad. won't let us get a key with dots in it
|
|
||||||
// Likely cause = treating the dots as path separators.
|
|
||||||
for (auto iter = ptRoot.begin(); iter != ptRoot.end(); iter++)
|
|
||||||
{
|
{
|
||||||
auto &item = *iter;
|
qDebug() << "BAD stuff happened to mod json:";
|
||||||
std::string key = item.first;
|
qDebug() << contents;
|
||||||
std::string value = item.second.get_value<std::string>();
|
return;
|
||||||
if(key == "forge.major.number")
|
}
|
||||||
major = value;
|
auto arrVal = jsonDoc.object().value("modlist");
|
||||||
if(key == "forge.minor.number")
|
if(arrVal.isArray())
|
||||||
minor = value;
|
{
|
||||||
if(key == "forge.revision.number")
|
getInfoFromArray(arrVal.toArray());
|
||||||
revision = value;
|
|
||||||
if(key == "forge.build.number")
|
|
||||||
build = value;
|
|
||||||
}
|
}
|
||||||
modVersion.Empty();
|
|
||||||
modVersion << major << "." << minor << "." << revision << "." << build;
|
|
||||||
}
|
|
||||||
catch (json_parser_error e)
|
|
||||||
{
|
|
||||||
std::cerr << e.what();
|
|
||||||
}
|
|
||||||
catch (ptree_error e)
|
|
||||||
{
|
|
||||||
std::cerr << e.what();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
void Mod::ReadForgeInfo(QByteArray contents)
|
||||||
|
{
|
||||||
|
// Read the data
|
||||||
|
m_name = "Minecraft Forge";
|
||||||
|
m_id = "Forge";
|
||||||
|
INIFile ini;
|
||||||
|
if(!ini.loadFile(contents))
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString major = ini.get("forge.major.number","0").toString();
|
||||||
|
QString minor = ini.get("forge.minor.number","0").toString();
|
||||||
|
QString revision = ini.get("forge.revision.number","0").toString();
|
||||||
|
QString build = ini.get("forge.build.number","0").toString();
|
||||||
|
|
||||||
|
m_version = major + "." + minor + "." + revision + "." + build;
|
||||||
|
}
|
||||||
|
|
||||||
bool Mod::replace ( Mod& with )
|
bool Mod::replace ( Mod& with )
|
||||||
{
|
{
|
||||||
|
@ -56,6 +56,9 @@ public:
|
|||||||
{
|
{
|
||||||
return filename() == other.filename() && id() == other.id() && version() == other.version() && type() == other.type();
|
return filename() == other.filename() && id() == other.id() && version() == other.version() && type() == other.type();
|
||||||
}
|
}
|
||||||
|
private:
|
||||||
|
void ReadMCModInfo(QByteArray contents);
|
||||||
|
void ReadForgeInfo(QByteArray contents);
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
//FIXME: what do do with those? HMM...
|
//FIXME: what do do with those? HMM...
|
||||||
|
Loading…
Reference in New Issue
Block a user