mirror of
https://github.com/MultiMC/MultiMC5.git
synced 2024-09-02 21:19:25 +00:00
Working on legacy support, incomplete.
This commit is contained in:
parent
ff33d4a1a4
commit
77e8066542
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,3 +7,4 @@ CMakeLists.txt.user
|
||||
build
|
||||
resources/CMakeFiles
|
||||
resources/MultiMCLauncher.jar
|
||||
*~
|
||||
|
@ -28,6 +28,8 @@ BaseUpdate.h
|
||||
BaseInstance.h
|
||||
BaseInstance_p.h
|
||||
MinecraftProcess.h
|
||||
Mod.h
|
||||
ModList.h
|
||||
|
||||
# network stuffs
|
||||
net/DownloadJob.h
|
||||
@ -38,6 +40,7 @@ net/NetWorker.h
|
||||
LegacyInstance.h
|
||||
LegacyInstance_p.h
|
||||
LegacyUpdate.h
|
||||
LegacyForge.h
|
||||
|
||||
# 1.6 instances
|
||||
OneSixAssets.h
|
||||
@ -68,6 +71,8 @@ InstanceFactory.cpp
|
||||
BaseUpdate.cpp
|
||||
BaseInstance.cpp
|
||||
MinecraftProcess.cpp
|
||||
Mod.cpp
|
||||
ModList.cpp
|
||||
|
||||
# network stuffs
|
||||
net/NetWorker.cpp
|
||||
@ -76,6 +81,7 @@ net/DownloadJob.cpp
|
||||
# legacy instances
|
||||
LegacyInstance.cpp
|
||||
LegacyUpdate.cpp
|
||||
LegacyForge.cpp
|
||||
|
||||
# 1.6 instances
|
||||
OneSixAssets.cpp
|
||||
|
57
backend/LegacyForge.cpp
Normal file
57
backend/LegacyForge.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
//
|
||||
// Copyright 2012 MultiMC Contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#include "LegacyForge.h"
|
||||
|
||||
MinecraftForge::MinecraftForge ( const QString& file ) : Mod ( file )
|
||||
{
|
||||
|
||||
}
|
||||
bool MinecraftForge::FixVersionIfNeeded ( QString newVersion )
|
||||
{/*
|
||||
wxString reportedVersion = GetModVersion();
|
||||
if(reportedVersion == "..." || reportedVersion.empty())
|
||||
{
|
||||
std::auto_ptr<wxFFileInputStream> in(new wxFFileInputStream("forge.zip"));
|
||||
wxTempFileOutputStream out("forge.zip");
|
||||
wxTextOutputStream textout(out);
|
||||
wxZipInputStream inzip(*in);
|
||||
wxZipOutputStream outzip(out);
|
||||
std::auto_ptr<wxZipEntry> entry;
|
||||
// preserve metadata
|
||||
outzip.CopyArchiveMetaData(inzip);
|
||||
// copy all entries
|
||||
while (entry.reset(inzip.GetNextEntry()), entry.get() != NULL)
|
||||
if (!outzip.CopyEntry(entry.release(), inzip))
|
||||
return false;
|
||||
// release last entry
|
||||
in.reset();
|
||||
outzip.PutNextEntry("forgeversion.properties");
|
||||
|
||||
wxStringTokenizer tokenizer(newVersion,".");
|
||||
wxString verFile;
|
||||
verFile << wxString("forge.major.number=") << tokenizer.GetNextToken() << "\n";
|
||||
verFile << wxString("forge.minor.number=") << tokenizer.GetNextToken() << "\n";
|
||||
verFile << wxString("forge.revision.number=") << tokenizer.GetNextToken() << "\n";
|
||||
verFile << wxString("forge.build.number=") << tokenizer.GetNextToken() << "\n";
|
||||
auto buf = verFile.ToUTF8();
|
||||
outzip.Write(buf.data(), buf.length());
|
||||
// check if we succeeded
|
||||
return inzip.Eof() && outzip.Close() && out.Commit();
|
||||
}
|
||||
*/
|
||||
return true;
|
||||
}
|
25
backend/LegacyForge.h
Normal file
25
backend/LegacyForge.h
Normal file
@ -0,0 +1,25 @@
|
||||
//
|
||||
// Copyright 2012 MultiMC Contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "Mod.h"
|
||||
|
||||
class MinecraftForge : public Mod
|
||||
{
|
||||
public:
|
||||
MinecraftForge ( const QString& file );
|
||||
bool FixVersionIfNeeded(QString newVersion);
|
||||
};
|
@ -212,6 +212,13 @@ void LegacyUpdate::jarStart()
|
||||
return;
|
||||
}
|
||||
|
||||
// nuke the backup file, we are replacing the base jar anyway
|
||||
QFile mc_backup(inst->mcBackup());
|
||||
if (mc_backup.exists())
|
||||
{
|
||||
mc_backup.remove();
|
||||
}
|
||||
|
||||
// Get a pointer to the version object that corresponds to the instance's version.
|
||||
auto targetVersion = MinecraftVersionList::getMainList().findVersion(intended_version_id);
|
||||
|
||||
@ -260,3 +267,115 @@ void LegacyUpdate::jarFailed()
|
||||
// bad, bad
|
||||
emitFailed("Failed to download the minecraft jar. Try again later.");
|
||||
}
|
||||
|
||||
void LegacyUpdate::ModTheJar()
|
||||
{
|
||||
/*
|
||||
LegacyInstance * inst = (LegacyInstance *) m_inst;
|
||||
// Get the mod list
|
||||
auto modList = inst->getJarModList();
|
||||
|
||||
QFileInfo mcBin(inst->binDir());
|
||||
QFileInfo mcJar(inst->mcJar());
|
||||
QFileInfo mcBackup(inst->mcBackup());
|
||||
|
||||
// Nothing to do if there are no jar mods to install, no backup and just the mc jar
|
||||
if(mcJar.isFile() && !mcBackup.exists() && modList->empty())
|
||||
{
|
||||
inst->setShouldRebuild(false);
|
||||
emitSucceeded();
|
||||
return;
|
||||
}
|
||||
|
||||
setStatus("Installing mods - backing up minecraft.jar...");
|
||||
if (!mcBackup.exists() && !QFile::copy(mcJar.absoluteFilePath(), mcBackup.absoluteFilePath()) )
|
||||
{
|
||||
emitFailed("Failed to back up minecraft.jar");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mcJar.isFile() && !QFile::remove(mcJar.absoluteFilePath()))
|
||||
{
|
||||
emitFailed("Failed to delete old minecraft.jar");
|
||||
return;
|
||||
}
|
||||
|
||||
setStatus("Installing mods - Opening minecraft.jar");
|
||||
|
||||
wxFFileOutputStream jarStream(mcJar.absoluteFilePath());
|
||||
wxZipOutputStream zipOut(jarStream);
|
||||
|
||||
// Files already added to the jar.
|
||||
// These files will be skipped.
|
||||
QSet<QString> addedFiles;
|
||||
|
||||
// Modify the jar
|
||||
setStatus("Installing mods - Adding mod files...");
|
||||
for (ModList::const_reverse_iterator iter = modList->rbegin(); iter != modList->rend(); iter++)
|
||||
{
|
||||
wxFileName modFileName = iter->GetFileName();
|
||||
setStatus("Installing mods - Adding " + modFileName.GetFullName());
|
||||
if (iter->GetModType() == Mod::ModType::MOD_ZIPFILE)
|
||||
{
|
||||
wxFFileInputStream modStream(modFileName.GetFullPath());
|
||||
wxZipInputStream zipStream(modStream);
|
||||
std::unique_ptr<wxZipEntry> entry;
|
||||
while (entry.reset(zipStream.GetNextEntry()), entry.get() != NULL)
|
||||
{
|
||||
if (entry->IsDir())
|
||||
continue;
|
||||
|
||||
wxString name = entry->GetName();
|
||||
if (addedFiles.count(name) == 0)
|
||||
{
|
||||
if (!zipOut.CopyEntry(entry.release(), zipStream))
|
||||
break;
|
||||
addedFiles.insert(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wxFileName destFileName = modFileName;
|
||||
destFileName.MakeRelativeTo(m_inst->GetInstModsDir().GetFullPath());
|
||||
wxString destFile = destFileName.GetFullPath();
|
||||
|
||||
if (addedFiles.count(destFile) == 0)
|
||||
{
|
||||
wxFFileInputStream input(modFileName.GetFullPath());
|
||||
zipOut.PutNextEntry(destFile);
|
||||
zipOut.Write(input);
|
||||
|
||||
addedFiles.insert(destFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
wxFFileInputStream inStream(mcBackup.GetFullPath());
|
||||
wxZipInputStream zipIn(inStream);
|
||||
|
||||
std::auto_ptr<wxZipEntry> entry;
|
||||
while (entry.reset(zipIn.GetNextEntry()), entry.get() != NULL)
|
||||
{
|
||||
wxString name = entry->GetName();
|
||||
|
||||
if (!name.Matches("META-INF*") &&
|
||||
addedFiles.count(name) == 0)
|
||||
{
|
||||
if (!zipOut.CopyEntry(entry.release(), zipIn))
|
||||
break;
|
||||
addedFiles.insert(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recompress the jar
|
||||
TaskStep(); // STEP 3
|
||||
SetStatus(_("Installing mods - Recompressing jar..."));
|
||||
|
||||
inst->SetNeedsRebuild(false);
|
||||
inst->UpdateVersion(true);
|
||||
return (ExitCode)1;
|
||||
*/
|
||||
}
|
@ -44,6 +44,8 @@ private slots:
|
||||
void jarFailed();
|
||||
|
||||
void extractLwjgl();
|
||||
|
||||
void ModTheJar();
|
||||
private:
|
||||
|
||||
QSharedPointer<QNetworkReply> m_reply;
|
||||
|
264
backend/Mod.cpp
Normal file
264
backend/Mod.cpp
Normal file
@ -0,0 +1,264 @@
|
||||
//
|
||||
// Copyright 2012 MultiMC Contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#include "Mod.h"
|
||||
#include <pathutils.h>
|
||||
#include <QDir>
|
||||
|
||||
Mod::Mod( const QFileInfo& file )
|
||||
{
|
||||
repath(file);
|
||||
}
|
||||
|
||||
void Mod::repath ( const QFileInfo& file )
|
||||
{
|
||||
m_file = file;
|
||||
m_name = file.baseName();
|
||||
m_id = file.fileName();
|
||||
|
||||
m_type = Mod::MOD_UNKNOWN;
|
||||
if (m_file.isDir())
|
||||
m_type = MOD_FOLDER;
|
||||
else if (m_file.isFile())
|
||||
{
|
||||
QString ext = m_file.suffix().toLower();
|
||||
if (ext == "zip" || ext == "jar")
|
||||
m_type = MOD_ZIPFILE;
|
||||
else
|
||||
m_type = MOD_SINGLEFILE;
|
||||
}
|
||||
|
||||
/*
|
||||
switch (modType)
|
||||
{
|
||||
case MOD_ZIPFILE:
|
||||
{
|
||||
wxFFileInputStream fileIn(modFile.GetFullPath());
|
||||
wxZipInputStream zipIn(fileIn);
|
||||
|
||||
std::auto_ptr<wxZipEntry> entry;
|
||||
|
||||
bool is_forge = false;
|
||||
while(true)
|
||||
{
|
||||
entry.reset(zipIn.GetNextEntry());
|
||||
if (entry.get() == nullptr)
|
||||
break;
|
||||
if(entry->GetInternalName().EndsWith("mcmod.info"))
|
||||
break;
|
||||
if(entry->GetInternalName().EndsWith("forgeversion.properties"))
|
||||
{
|
||||
is_forge = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry.get() != nullptr)
|
||||
{
|
||||
// Read the info file into text
|
||||
wxString infoFileData;
|
||||
wxStringOutputStream stringOut(&infoFileData);
|
||||
zipIn.Read(stringOut);
|
||||
if(!is_forge)
|
||||
ReadModInfoData(infoFileData);
|
||||
else
|
||||
ReadForgeInfoData(infoFileData);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MOD_FOLDER:
|
||||
{
|
||||
wxString infoFile = Path::Combine(modFile, "mcmod.info");
|
||||
if (!wxFileExists(infoFile))
|
||||
{
|
||||
infoFile = wxEmptyString;
|
||||
|
||||
wxDir modDir(modFile.GetFullPath());
|
||||
|
||||
if (!modDir.IsOpened())
|
||||
{
|
||||
wxLogError(_("Can't fine mod info file. Failed to open mod folder."));
|
||||
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;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
void ReadModInfoData(QString info)
|
||||
{
|
||||
using namespace boost::property_tree;
|
||||
|
||||
// Read the data
|
||||
ptree ptRoot;
|
||||
|
||||
std::stringstream stringIn(cStr(info));
|
||||
try
|
||||
{
|
||||
read_json(stringIn, ptRoot);
|
||||
|
||||
ptree pt = ptRoot.get_child(ptRoot.count("modlist") == 1 ? "modlist" : "").begin()->second;
|
||||
|
||||
modID = wxStr(pt.get<std::string>("modid"));
|
||||
modName = wxStr(pt.get<std::string>("name"));
|
||||
modVersion = wxStr(pt.get<std::string>("version"));
|
||||
}
|
||||
catch (json_parser_error e)
|
||||
{
|
||||
// Silently fail...
|
||||
}
|
||||
catch (ptree_error e)
|
||||
{
|
||||
// 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;
|
||||
std::string key = item.first;
|
||||
std::string value = item.second.get_value<std::string>();
|
||||
if(key == "forge.major.number")
|
||||
major = value;
|
||||
if(key == "forge.minor.number")
|
||||
minor = value;
|
||||
if(key == "forge.revision.number")
|
||||
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();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
bool Mod::replace ( Mod& with )
|
||||
{
|
||||
if(!destroy())
|
||||
return false;
|
||||
bool success = false;
|
||||
auto t = with.type();
|
||||
if(t == MOD_ZIPFILE || t == MOD_SINGLEFILE)
|
||||
{
|
||||
success = QFile::copy(with.m_file.filePath(), m_file.path());
|
||||
}
|
||||
if(t == MOD_FOLDER)
|
||||
{
|
||||
success = copyPath(with.m_file.filePath(), m_file.path());
|
||||
}
|
||||
if(success)
|
||||
{
|
||||
m_id = with.m_id;
|
||||
m_mcversion = with.m_mcversion;
|
||||
m_type = with.m_type;
|
||||
m_name = with.m_name;
|
||||
m_version = with.m_version;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool Mod::destroy()
|
||||
{
|
||||
if(m_type == MOD_FOLDER)
|
||||
{
|
||||
QDir d(m_file.filePath());
|
||||
if(d.removeRecursively())
|
||||
{
|
||||
m_type = MOD_UNKNOWN;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (m_type == MOD_SINGLEFILE || m_type == MOD_ZIPFILE)
|
||||
{
|
||||
QFile f(m_file.filePath());
|
||||
if(f.remove())
|
||||
{
|
||||
m_type = MOD_UNKNOWN;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QString Mod::version() const
|
||||
{
|
||||
switch(type())
|
||||
{
|
||||
case MOD_ZIPFILE:
|
||||
return m_version;
|
||||
case MOD_FOLDER:
|
||||
return "Folder";
|
||||
case MOD_SINGLEFILE:
|
||||
return "File";
|
||||
}
|
||||
}
|
69
backend/Mod.h
Normal file
69
backend/Mod.h
Normal file
@ -0,0 +1,69 @@
|
||||
//
|
||||
// Copyright 2012 MultiMC Contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <QFileInfo>
|
||||
|
||||
class Mod
|
||||
{
|
||||
public:
|
||||
enum ModType
|
||||
{
|
||||
MOD_UNKNOWN, //!< Indicates an unspecified mod type.
|
||||
MOD_ZIPFILE, //!< The mod is a zip file containing the mod's class files.
|
||||
MOD_SINGLEFILE, //!< The mod is a single file (not a zip file).
|
||||
MOD_FOLDER, //!< The mod is in a folder on the filesystem.
|
||||
};
|
||||
|
||||
Mod(const QFileInfo &file);
|
||||
|
||||
QFileInfo filename() const { return m_file; }
|
||||
QString id() const { return m_id; }
|
||||
ModType type() const { return m_type; }
|
||||
QString mcversion() const;
|
||||
bool valid() {return m_type != MOD_UNKNOWN;}
|
||||
|
||||
QString version() const;
|
||||
|
||||
// delete all the files of this mod
|
||||
bool destroy();
|
||||
// replace this mod with a copy of the other
|
||||
bool replace(Mod & with);
|
||||
// change the mod's filesystem path (used by mod lists for *MAGIC* purposes)
|
||||
void repath(const QFileInfo &file);
|
||||
|
||||
|
||||
bool operator ==(const Mod &other) const
|
||||
{
|
||||
return filename() == other.filename();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
//FIXME: what do do with those? HMM...
|
||||
/*
|
||||
void ReadModInfoData(QString info);
|
||||
void ReadForgeInfoData(QString infoFileData);
|
||||
*/
|
||||
|
||||
QFileInfo m_file;
|
||||
QString m_id;
|
||||
QString m_name;
|
||||
QString m_version;
|
||||
QString m_mcversion;
|
||||
|
||||
ModType m_type;
|
||||
};
|
418
backend/ModList.cpp
Normal file
418
backend/ModList.cpp
Normal file
@ -0,0 +1,418 @@
|
||||
//
|
||||
// Copyright 2012 MultiMC Contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#include "ModList.h"
|
||||
#include "LegacyInstance.h"
|
||||
#include <pathutils.h>
|
||||
|
||||
ModList::ModList ( const QString& dir ) : QObject(), m_dir(dir)
|
||||
{
|
||||
m_dir.setFilter(QDir::Readable | QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs | QDir::NoSymLinks);
|
||||
m_dir.setSorting(QDir::Name);
|
||||
update();
|
||||
}
|
||||
|
||||
bool ModList::update()
|
||||
{
|
||||
if (!isValid())
|
||||
return false;
|
||||
|
||||
bool initial = mods.empty();
|
||||
|
||||
bool listChanged = false;
|
||||
|
||||
auto list = m_dir.entryInfoList();
|
||||
for(auto entry: list)
|
||||
{
|
||||
Mod mod(entry);
|
||||
if (initial || !mods.contains(mod))
|
||||
{
|
||||
mods.push_back(mod);
|
||||
listChanged = true;
|
||||
}
|
||||
}
|
||||
return listChanged;
|
||||
}
|
||||
|
||||
bool ModList::isValid()
|
||||
{
|
||||
return m_dir.exists() && m_dir.isReadable();
|
||||
}
|
||||
|
||||
bool ModList::installMod ( const QFileInfo& filename, size_t index )
|
||||
{
|
||||
if(!filename.exists() || !filename.isReadable())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Mod m(filename);
|
||||
if(!m.valid())
|
||||
return false;
|
||||
|
||||
// if it's already there, replace the original mod (in place)
|
||||
int idx = mods.indexOf(m);
|
||||
if(idx != -1)
|
||||
{
|
||||
if(mods[idx].replace(m))
|
||||
{
|
||||
emit changed();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto type = m.type();
|
||||
if(type == Mod::MOD_UNKNOWN)
|
||||
return false;
|
||||
if(type == Mod::MOD_SINGLEFILE || type == Mod::MOD_ZIPFILE)
|
||||
{
|
||||
QString newpath = PathCombine(m_dir.path(), filename.fileName());
|
||||
if(!QFile::copy(filename.filePath(), newpath))
|
||||
return false;
|
||||
m.repath(newpath);
|
||||
mods.append(m);
|
||||
emit changed();
|
||||
return true;
|
||||
}
|
||||
else if(type == Mod::MOD_FOLDER)
|
||||
{
|
||||
QString newpath = PathCombine(m_dir.path(), filename.fileName());
|
||||
if(!copyPath(filename.filePath(), newpath))
|
||||
return false;
|
||||
m.repath(newpath);
|
||||
mods.append(m);
|
||||
emit changed();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ModList::deleteMod ( size_t index )
|
||||
{
|
||||
if(index >= mods.size())
|
||||
return false;
|
||||
Mod & m = mods[index];
|
||||
if(m.destroy())
|
||||
{
|
||||
mods.erase(mods.begin() + index);
|
||||
emit changed();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
ModList::ModList(const QString &dir)
|
||||
: modsFolder(dir)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool ModList::update(bool quickLoad)
|
||||
{
|
||||
bool listChanged = false;
|
||||
|
||||
// Check for mods in the list whose files do not exist and remove them from the list.
|
||||
// If doing a quickLoad, erase the whole list.
|
||||
for (size_t i = 0; i < size(); i++)
|
||||
{
|
||||
if (quickLoad || !at(i).GetFileName().FileExists())
|
||||
{
|
||||
erase(begin() + i);
|
||||
i--;
|
||||
listChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Add any mods in the mods folder that aren't already in the list.
|
||||
if (LoadModListFromDir(QString(), quickLoad))
|
||||
listChanged = true;
|
||||
|
||||
return listChanged;
|
||||
}
|
||||
|
||||
bool ModList::LoadModListFromDir(const QString& loadFrom, bool quickLoad)
|
||||
{
|
||||
QString dir(loadFrom.isEmpty() ? modsFolder : loadFrom);
|
||||
|
||||
QDir modDir(dir);
|
||||
if (!modDir.exists())
|
||||
return false;
|
||||
|
||||
bool listChanged = false;
|
||||
|
||||
auto list = modDir.entryInfoList(QDir::Readable|QDir::NoDotAndDotDot, QDir::Name);
|
||||
for(auto currentFile: list)
|
||||
{
|
||||
if (currentFile.isFile())
|
||||
{
|
||||
if (quickLoad || FindByFilename(currentFile.absoluteFilePath()) == nullptr)
|
||||
{
|
||||
Mod mod(currentFile.absoluteFilePath());
|
||||
push_back(mod);
|
||||
listChanged = true;
|
||||
}
|
||||
}
|
||||
else if (currentFile.isDir())
|
||||
{
|
||||
if (LoadModListFromDir(currentFile.absoluteFilePath()))
|
||||
listChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
return listChanged;
|
||||
}
|
||||
|
||||
Mod *ModList::FindByFilename(const QString& filename)
|
||||
{
|
||||
// Search the list for a mod with the given filename.
|
||||
for (auto iter = begin(); iter != end(); ++iter)
|
||||
{
|
||||
if (iter->GetFileName() == QFileInfo(filename))
|
||||
return &(*iter);
|
||||
}
|
||||
|
||||
// If nothing is found, return nullptr.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int ModList::FindIndexByFilename(const QString& filename)
|
||||
{
|
||||
// Search the list for a mod with the given filename.
|
||||
int i = 0;
|
||||
for (auto iter = begin(); iter != end(); ++iter, i++)
|
||||
{
|
||||
if (iter->GetFileName() == QFileInfo(filename))
|
||||
return i;
|
||||
}
|
||||
|
||||
// If nothing is found, return nullptr.
|
||||
return -1;
|
||||
}
|
||||
|
||||
Mod* ModList::FindByID(const QString& modID, const QString& modVersion)
|
||||
{
|
||||
// Search the list for a mod that matches
|
||||
for (auto iter = begin(); iter != end(); ++iter)
|
||||
{
|
||||
QString ID = iter->GetModID();
|
||||
QString version = iter->GetModVersion();
|
||||
if ( ID == modID && version == modVersion)
|
||||
return &(*iter);
|
||||
}
|
||||
|
||||
// If nothing is found, return nullptr.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ModList::LoadFromFile(const QString& file)
|
||||
{
|
||||
if (!wxFileExists(file))
|
||||
return;
|
||||
|
||||
wxFFileInputStream inputStream(file);
|
||||
wxArrayString modListFile = ReadAllLines(inputStream);
|
||||
|
||||
for (wxArrayString::iterator iter = modListFile.begin(); iter != modListFile.end(); iter++)
|
||||
{
|
||||
// Normalize the path to the instMods dir.
|
||||
wxFileName modFile(*iter);
|
||||
modFile.Normalize(wxPATH_NORM_ALL, modsFolder);
|
||||
modFile.MakeRelativeTo();
|
||||
// if the file is gone, do not load it
|
||||
if(!modFile.Exists())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FindByFilename(modFile.GetFullPath()) == nullptr)
|
||||
{
|
||||
push_back(Mod(modFile));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModList::SaveToFile(const QString& file)
|
||||
{
|
||||
QString text;
|
||||
for (iterator iter = begin(); iter != end(); ++iter)
|
||||
{
|
||||
wxFileName modFile = iter->GetFileName();
|
||||
modFile.MakeRelativeTo(modsFolder);
|
||||
text.append(modFile.GetFullPath());
|
||||
text.append("\n");
|
||||
}
|
||||
|
||||
wxTempFileOutputStream out(file);
|
||||
WriteAllText(out, text);
|
||||
out.Commit();
|
||||
}
|
||||
|
||||
bool ModList::InsertMod(size_t index, const QString &filename, const QString& saveToFile)
|
||||
{
|
||||
QFileInfo source(filename);
|
||||
QFileInfo dest(PathCombine(modsFolder, source.fileName()));
|
||||
|
||||
if (source != dest)
|
||||
{
|
||||
QFile::copy(source.absoluteFilePath(), dest.absoluteFilePath());
|
||||
}
|
||||
|
||||
int oldIndex = FindIndexByFilename(dest.absoluteFilePath());
|
||||
|
||||
if (oldIndex != -1)
|
||||
{
|
||||
erase(begin() + oldIndex);
|
||||
}
|
||||
|
||||
if (index >= size())
|
||||
push_back(Mod(dest));
|
||||
else
|
||||
insert(begin() + index, Mod(dest));
|
||||
|
||||
if (!saveToFile.isEmpty())
|
||||
SaveToFile(saveToFile);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ModList::DeleteMod(size_t index, const QString& saveToFile)
|
||||
{
|
||||
Mod *mod = &at(index);
|
||||
if(mod->GetModType() == Mod::MOD_FOLDER)
|
||||
{
|
||||
QDir dir(mod->GetFileName().absoluteFilePath());
|
||||
if(dir.removeRecursively())
|
||||
{
|
||||
erase(begin() + index);
|
||||
|
||||
if (!saveToFile.isEmpty())
|
||||
SaveToFile(saveToFile);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// wxLogError(_("Failed to delete mod."));
|
||||
}
|
||||
}
|
||||
else if (QFile(mod->GetFileName().absoluteFilePath()).remove())
|
||||
{
|
||||
erase(begin() + index);
|
||||
|
||||
if (!saveToFile.isEmpty())
|
||||
SaveToFile(saveToFile);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// wxLogError(_("Failed to delete mod."));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool JarModList::InsertMod(size_t index, const QString &filename, const QString& saveToFile)
|
||||
{
|
||||
QString saveFile = saveToFile;
|
||||
if (saveToFile.isEmpty())
|
||||
saveFile = m_inst->GetModListFile().GetFullPath();
|
||||
|
||||
if (ModList::InsertMod(index, filename, saveFile))
|
||||
{
|
||||
m_inst->setLWJGLVersion(true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool JarModList::DeleteMod(size_t index, const QString& saveToFile)
|
||||
{
|
||||
QString saveFile = saveToFile;
|
||||
if (saveToFile.IsEmpty())
|
||||
saveFile = m_inst->GetModListFile().GetFullPath();
|
||||
|
||||
if (ModList::DeleteMod(index, saveFile))
|
||||
{
|
||||
m_inst->SetNeedsRebuild();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool JarModList::UpdateModList(bool quickLoad)
|
||||
{
|
||||
if (ModList::UpdateModList(quickLoad))
|
||||
{
|
||||
m_inst->SetNeedsRebuild();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FolderModList::LoadModListFromDir(const QString& loadFrom, bool quickLoad)
|
||||
{
|
||||
QString dir(loadFrom.IsEmpty() ? modsFolder : loadFrom);
|
||||
|
||||
if (!wxDirExists(dir))
|
||||
return false;
|
||||
|
||||
bool listChanged = false;
|
||||
wxDir modDir(dir);
|
||||
|
||||
if (!modDir.IsOpened())
|
||||
{
|
||||
wxLogError(_("Failed to open directory: ") + dir);
|
||||
return false;
|
||||
}
|
||||
|
||||
QString currentFile;
|
||||
if (modDir.GetFirst(¤tFile))
|
||||
{
|
||||
do
|
||||
{
|
||||
wxFileName modFile(Path::Combine(dir, currentFile));
|
||||
|
||||
if (wxFileExists(modFile.GetFullPath()) || wxDirExists(modFile.GetFullPath()))
|
||||
{
|
||||
if (quickLoad || FindByFilename(modFile.GetFullPath()) == nullptr)
|
||||
{
|
||||
Mod mod(modFile.GetFullPath());
|
||||
push_back(mod);
|
||||
listChanged = true;
|
||||
}
|
||||
}
|
||||
} while (modDir.GetNext(¤tFile));
|
||||
}
|
||||
|
||||
return listChanged;
|
||||
}
|
||||
|
||||
bool ModNameSort (const Mod & i,const Mod & j)
|
||||
{
|
||||
if(i.GetModType() == j.GetModType())
|
||||
return (i.GetName().toLower() < j.GetName().toLower());
|
||||
return (i.GetModType() < j.GetModType());
|
||||
}
|
||||
|
||||
bool FolderModList::UpdateModList ( bool quickLoad )
|
||||
{
|
||||
bool changed = ModList::UpdateModList(quickLoad);
|
||||
std::sort(begin(),end(),ModNameSort);
|
||||
return changed;
|
||||
}
|
||||
*/
|
75
backend/ModList.h
Normal file
75
backend/ModList.h
Normal file
@ -0,0 +1,75 @@
|
||||
//
|
||||
// Copyright 2012 MultiMC Contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
#pragma once
|
||||
|
||||
class LegacyInstance;
|
||||
class BaseInstance;
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QDir>
|
||||
|
||||
#include "Mod.h"
|
||||
|
||||
/**
|
||||
* A basic mod list.
|
||||
* Backed by a folder.
|
||||
*/
|
||||
class ModList : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ModList(const QString& dir = QString());
|
||||
|
||||
size_t size() { return mods.size(); };
|
||||
Mod& operator[](size_t index) { return mods[index]; };
|
||||
|
||||
/// Reloads the mod list and returns true if the list changed.
|
||||
virtual bool update();
|
||||
|
||||
/// Adds the given mod to the list at the given index.
|
||||
virtual bool installMod(const QFileInfo& filename, size_t index = 0);
|
||||
|
||||
/// Deletes the mod at the given index.
|
||||
virtual bool deleteMod(size_t index);
|
||||
|
||||
/**
|
||||
* move the mod at index to the position N
|
||||
* 0 is the beginning of the list, length() is the end of the list.
|
||||
*/
|
||||
virtual bool moveMod(size_t from, size_t to) { return false; };
|
||||
|
||||
virtual bool isValid();
|
||||
|
||||
signals:
|
||||
virtual void changed();
|
||||
protected:
|
||||
QDir m_dir;
|
||||
QList<Mod> mods;
|
||||
};
|
||||
|
||||
/**
|
||||
* A jar mod list.
|
||||
* Backed by a folder and a file which specifies the load order.
|
||||
*/
|
||||
class JarModList : public ModList
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
JarModList(const QString& dir, const QString& list_file, LegacyInstance * inst)
|
||||
: ModList(dir), m_listfile(list_file), m_inst(inst) {}
|
||||
|
||||
virtual bool update();
|
||||
virtual bool installMod(const QString &filename, size_t index);
|
||||
virtual bool deleteMod(size_t index);
|
||||
virtual bool moveMod(size_t from, size_t to);
|
||||
protected:
|
||||
QString m_listfile;
|
||||
LegacyInstance * m_inst;
|
||||
};
|
@ -92,12 +92,15 @@ void OneSixUpdate::versionFileFinished()
|
||||
{
|
||||
QString version1 = PathCombine(inst_dir, "/version.json");
|
||||
ensurePathExists(version1);
|
||||
// FIXME: detect errors here, download to a temp file, swap
|
||||
QFile vfile1 (version1);
|
||||
vfile1.open(QIODevice::Truncate | QIODevice::WriteOnly );
|
||||
vfile1.write(DlJob->m_data);
|
||||
vfile1.close();
|
||||
}
|
||||
|
||||
// the version is downloaded safely. update is 'done' at this point
|
||||
m_inst->setShouldUpdate(false);
|
||||
// save the version file in versions/$version/$version.json
|
||||
/*
|
||||
//QString version2 = QString("versions/") + version_id + "/" + version_id + ".json";
|
||||
|
@ -31,4 +31,7 @@ LIBUTIL_EXPORT QString DirNameFromString(QString string, QString inDir = ".");
|
||||
|
||||
LIBUTIL_EXPORT bool ensurePathExists(QString filenamepath);
|
||||
|
||||
LIBUTIL_EXPORT bool copyPath(QString src, QString dst);
|
||||
|
||||
|
||||
#endif // PATHUTILS_H
|
||||
|
@ -73,3 +73,22 @@ bool ensurePathExists(QString filenamepath)
|
||||
return (dir.mkpath ( a.path() ));
|
||||
}
|
||||
|
||||
bool copyPath(QString src, QString dst)
|
||||
{
|
||||
QDir dir(src);
|
||||
if (!dir.exists())
|
||||
return false;
|
||||
|
||||
foreach (QString d, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot))
|
||||
{
|
||||
QString dst_path = dst + QDir::separator() + d;
|
||||
dir.mkpath(dst_path);
|
||||
copyPath(src+ QDir::separator() + d, dst_path);
|
||||
}
|
||||
|
||||
foreach (QString f, dir.entryList(QDir::Files))
|
||||
{
|
||||
QFile::copy(src + QDir::separator() + f, dst + QDir::separator() + f);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user