all worlds list will now join correct instance for each world

This commit is contained in:
Ice Yeti 2026-05-31 13:48:31 -04:00
parent 0ceb218180
commit 3a6ae78bc6
5 changed files with 66 additions and 56 deletions

View file

@ -46,7 +46,9 @@
#include <QUuid>
#include <Qt>
MultiWorldList::MultiWorldList(const QList<QString>& dirs, QList<BaseInstance*> instances) : QAbstractListModel(), m_instances(instances)
#include "MinecraftInstance.h"
MultiWorldList::MultiWorldList(const QList<QString>& dirs, const QList<BaseInstance*>& instances) : QAbstractListModel(), m_instances(instances)
{
for (QString dir : dirs) {
m_dirs.append(dir);
@ -105,9 +107,10 @@ bool MultiWorldList::update()
if (!isValid())
return false;
QList<World> newWorlds;
QList<InstanceWorld> newWorlds;
for (QDir dir : m_dirs) {
for (BaseInstance* inst : m_instances) {
QDir dir = dynamic_cast<MinecraftInstance*>(inst)->worldDir();
dir.refresh();
auto folderContents = dir.entryInfoList();
// if there are any untracked files...
@ -117,7 +120,7 @@ bool MultiWorldList::update()
World w(entry);
if (w.isValid()) {
newWorlds.append(w);
newWorlds.append(InstanceWorld(w, inst));
}
}
}
@ -134,16 +137,24 @@ void MultiWorldList::directoryChanged(QString)
update();
}
bool MultiWorldList::isValid() //account for all directories
bool MultiWorldList::isValid()
{
return m_dirs[0].exists() && m_dirs[0].isReadable();
bool valid = true;
for (const QDir& dir : m_dirs) {
if (!(dir.exists() && dir.isReadable())) {
valid = false;
}
}
return valid;
}
QList<QString> MultiWorldList::instDirPaths() const
{
QList<QString> dirList;
for (BaseInstance* instance : m_instances) {
for (BaseInstance* instance : m_instances) { //use m_dirs??? iy
dirList.append(QFileInfo(instance->instanceRoot()).absoluteFilePath());
}
@ -154,7 +165,7 @@ bool MultiWorldList::deleteWorld(int index)
{
if (index >= m_worlds.size() || index < 0)
return false;
World& m = m_worlds[index];
World& m = m_worlds[index].world;
if (m.destroy()) {
beginRemoveRows(QModelIndex(), index, index);
m_worlds.removeAt(index);
@ -168,7 +179,7 @@ bool MultiWorldList::deleteWorld(int index)
bool MultiWorldList::deleteWorlds(int first, int last)
{
for (int i = first; i <= last; i++) {
World& m = m_worlds[i];
World& m = m_worlds[i].world;
m.destroy();
}
beginRemoveRows(QModelIndex(), first, last);
@ -182,7 +193,7 @@ bool MultiWorldList::resetIcon(int row)
{
if (row >= m_worlds.size() || row < 0)
return false;
World& m = m_worlds[row];
World& m = m_worlds[row].world;
if (m.resetIcon()) {
QModelIndex modelIndex = index(row, NameColumn);
emit dataChanged(modelIndex, modelIndex, { MultiWorldList::IconFileRole });
@ -209,29 +220,29 @@ QVariant MultiWorldList::data(const QModelIndex& index, int role) const
QLocale locale;
auto& world = m_worlds[row];
auto& instanceWorld = m_worlds[row];
switch (role) {
case Qt::DisplayRole:
switch (column) {
case NameColumn:
return world.name();
return instanceWorld.world.name();
case GameModeColumn:
return world.gameType().toTranslatedString();
return instanceWorld.world.gameType().toTranslatedString();
case LastPlayedColumn:
return world.lastPlayed();
return instanceWorld.world.lastPlayed();
case SizeColumn:
return locale.formattedDataSize(world.bytes());
return locale.formattedDataSize(instanceWorld.world.bytes());
case InfoColumn:
for (QString path : instDirPaths()) { //use canonical paths instead of for loops? iy
if (world.isSymLinkUnder(path)) {
if (instanceWorld.world.isSymLinkUnder(path)) {
return tr("This world is symbolically linked from elsewhere.");
}
}
if (world.isMoreThanOneHardLink()) {
if (instanceWorld.world.isMoreThanOneHardLink()) {
return tr("\nThis world is hard linked elsewhere.");
}
return "";
@ -241,44 +252,44 @@ QVariant MultiWorldList::data(const QModelIndex& index, int role) const
case Qt::UserRole:
if (column == SizeColumn)
return QVariant::fromValue<qlonglong>(world.bytes());
return QVariant::fromValue<qlonglong>(instanceWorld.world.bytes());
return data(index, Qt::DisplayRole);
case Qt::ToolTipRole: {
if (column == InfoColumn) {
for (QString path : instDirPaths()) { //use canonical paths instead of for loops? iy
if (world.isSymLinkUnder(path)) {
if (instanceWorld.world.isSymLinkUnder(path)) {
return tr("Warning: This world is symbolically linked from elsewhere. Editing it will also change the original."
"\nCanonical Path: %1")
.arg(world.canonicalFilePath());
.arg(instanceWorld.world.canonicalFilePath());
}
}
if (world.isMoreThanOneHardLink()) {
if (instanceWorld.world.isMoreThanOneHardLink()) {
return tr("Warning: This world is hard linked elsewhere. Editing it will also change the original.");
}
}
return world.folderName();
return instanceWorld.world.folderName();
}
case ObjectRole: {
return QVariant::fromValue<void*>((void*)&world);
return QVariant::fromValue<void*>((void*)&instanceWorld);
}
case FolderRole: {
return QDir::toNativeSeparators(QDir(world.canonicalFilePath()).absoluteFilePath(world.folderName())); //test if canonical file path works iy
return QDir::toNativeSeparators(QDir(instanceWorld.world.canonicalFilePath()).absoluteFilePath(instanceWorld.world.folderName())); //test if canonical file path works iy
}
case SeedRole: {
return QVariant::fromValue<qlonglong>(world.seed());
return QVariant::fromValue<qlonglong>(instanceWorld.world.seed());
}
case NameRole: {
return world.name();
return instanceWorld.world.name();
}
case LastPlayedRole: {
return world.lastPlayed();
return instanceWorld.world.lastPlayed();
}
case SizeRole: {
return QVariant::fromValue<qlonglong>(world.bytes());
return QVariant::fromValue<qlonglong>(instanceWorld.world.bytes());
}
case IconFileRole: {
return world.iconFile();
return instanceWorld.world.iconFile();
}
default:
return QVariant();
@ -345,7 +356,7 @@ QMimeData* MultiWorldList::mimeData(const QModelIndexList& indexes) const
if (row < 0 || row >= this->m_worlds.size())
continue;
const World& world = m_worlds[row];
const World& world = m_worlds[row].world;
if (!world.isValid() || !world.isOnFS())
continue;
@ -446,7 +457,7 @@ int64_t MultiWorldList::calculateWorldSize(const QFileInfo& file)
void MultiWorldList::loadWorldsAsync()
{
for (int i = 0; i < m_worlds.size(); ++i) {
auto file = m_worlds.at(i).container();
auto file = m_worlds.at(i).world.container();
int row = i;
QThreadPool::globalInstance()->start([this, file, row]() mutable {
auto size = calculateWorldSize(file);
@ -454,8 +465,8 @@ void MultiWorldList::loadWorldsAsync()
QMetaObject::invokeMethod(
this,
[this, size, row, file]() {
if (row < m_worlds.size() && m_worlds[row].container() == file) {
m_worlds[row].setSize(size);
if (row < m_worlds.size() && m_worlds[row].world.container() == file) {
m_worlds[row].world.setSize(size);
// Notify views
QModelIndex modelIndex = index(row, SizeColumn);

View file

@ -25,6 +25,11 @@
class QFileSystemWatcher;
struct InstanceWorld {
World world;
BaseInstance* instance;
};
class MultiWorldList : public QAbstractListModel {
Q_OBJECT
public:
@ -32,7 +37,7 @@ class MultiWorldList : public QAbstractListModel {
enum Roles { ObjectRole = Qt::UserRole + 1, FolderRole, SeedRole, NameRole, GameModeRole, LastPlayedRole, SizeRole, IconFileRole };
MultiWorldList(const QList<QString>& dirs, QList<BaseInstance*> instances);
MultiWorldList(const QList<QString>& dirs, const QList<BaseInstance*>& instances);
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
@ -42,7 +47,7 @@ class MultiWorldList : public QAbstractListModel {
size_t size() const { return m_worlds.size(); };
bool empty() const { return size() == 0; }
World& operator[](size_t index) { return m_worlds[index]; }
World& operator[](size_t index) { return m_worlds[index].world; }
/// Reloads the mod list and returns true if the list changed.
virtual bool update();
@ -83,7 +88,7 @@ class MultiWorldList : public QAbstractListModel {
QList<QString> instDirPaths() const;
const QList<World>& allWorlds() const { return m_worlds; }
const QList<InstanceWorld>& allWorlds() const { return m_worlds; }
private slots:
void directoryChanged(QString path);
@ -97,5 +102,5 @@ class MultiWorldList : public QAbstractListModel {
QFileSystemWatcher* m_watcher;
bool m_isWatching;
QList<QDir> m_dirs;
QList<World> m_worlds;
QList<InstanceWorld> m_worlds;
};

View file

@ -339,7 +339,6 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi
// Create the all worlds widget
{
QList<BaseInstance*> allInstances = APPLICATION->instances()->getAllInstances();
qDebug() << "iy initially" << allInstances.length();
QList<QString> dirs;
for (BaseInstance* inst : allInstances) {
dirs.append(dynamic_cast<MinecraftInstance*>(inst)->worldDir());
@ -347,7 +346,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi
allWorlds = new MultiWorldList(dirs, allInstances);
allWorlds->update();
allWorldsPage = new MultiWorldListPage(dynamic_cast<MinecraftInstance*>(allInstances[0]), allWorlds); //shouldnt be only one instance iy
allWorldsPage = new MultiWorldListPage(allWorlds);
ui->horizontalLayout->addWidget(allWorldsPage);
}
@ -945,10 +944,7 @@ void MainWindow::addInstance(const QString& url, const QMap<QString, QString>& e
instanceFromInstanceTask(creationTask);
}
//clean this up iy - fix ghosting issue and only joining one world despite which one you click
QList<BaseInstance*> allInstances = APPLICATION->instances()->getAllInstances();
qDebug() << "iy finally " << allInstances.length();
QList<QString> dirs;
for (BaseInstance* inst : allInstances) {
dirs.append(dynamic_cast<MinecraftInstance*>(inst)->worldDir());
@ -956,8 +952,9 @@ void MainWindow::addInstance(const QString& url, const QMap<QString, QString>& e
allWorlds = new MultiWorldList(dirs, allInstances);
allWorlds->update();
auto newAllWorldsPage = new MultiWorldListPage(dynamic_cast<MinecraftInstance*>(allInstances[0]), allWorlds); //shouldnt be only one instance iy
auto newAllWorldsPage = new MultiWorldListPage(allWorlds);
ui->horizontalLayout->replaceWidget(allWorldsPage, newAllWorldsPage);
delete allWorldsPage;
allWorldsPage = newAllWorldsPage;
}

View file

@ -86,14 +86,14 @@ class MultiWorldListProxyModel : public QSortFilterProxyModel {
}
};
MultiWorldListPage::MultiWorldListPage(MinecraftInstance* inst, MultiWorldList* worlds, QWidget* parent) //require all instances instead of just one iy
: QMainWindow(parent), m_inst(inst), ui(new Ui::MultiWorldListPage), m_worlds(worlds)
MultiWorldListPage::MultiWorldListPage(MultiWorldList* worlds, QWidget* parent)
: QMainWindow(parent), ui(new Ui::MultiWorldListPage), m_worlds(worlds)
{
ui->setupUi(this);
ui->toolBar->insertSpacer(ui->actionRefresh);
MultiWorldListProxyModel* proxy = new MultiWorldListProxyModel(this);
auto* proxy = new MultiWorldListProxyModel(this);
proxy->setSortCaseSensitivity(Qt::CaseInsensitive);
proxy->setSourceModel(m_worlds);
proxy->setSortRole(Qt::UserRole);
@ -195,7 +195,7 @@ void MultiWorldListPage::on_actionRemove_triggered()
tr("You are about to delete \"%1\".\n"
"The world may be gone forever (A LONG TIME).\n\n"
"Are you sure?")
.arg(m_worlds->allWorlds().at(proxiedIndex.row()).name()),
.arg(m_worlds->allWorlds().at(proxiedIndex.row()).world.name()),
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
->exec();
@ -237,9 +237,9 @@ void MultiWorldListPage::on_actionData_Packs_triggered()
GenericPageProvider provider(dialog->windowTitle());
bool isIndexed = !APPLICATION->settings()->get("ModMetadataDisabled").toBool();
m_datapackModel.reset(new DataPackFolderModel(folder, m_inst, isIndexed, true));
m_datapackModel.reset(new DataPackFolderModel(folder, m_worlds->allWorlds()[0].instance, isIndexed, true)); //don't use instance 0 iy
provider.addPageCreator([this] { return new DataPackPage(m_inst, m_datapackModel.get(), this); });
provider.addPageCreator([this] { return new DataPackPage(m_worlds->allWorlds()[0].instance, m_datapackModel.get(), this); }); //no instance 0 iy
auto layout = new QVBoxLayout(dialog);
@ -402,7 +402,7 @@ void MultiWorldListPage::on_actionAdd_triggered()
bool MultiWorldListPage::isWorldSafe(QModelIndex)
{
return !m_inst->isRunning();
return !m_worlds->allWorlds()[0].instance->isRunning(); //don't use instance 0 iy
}
bool MultiWorldListPage::worldSafetyNagQuestion(const QString& actionType)
@ -471,8 +471,8 @@ void MultiWorldListPage::on_actionJoin_triggered()
return;
}
auto worldVariant = m_worlds->data(index, MultiWorldList::ObjectRole);
auto world = (World*)worldVariant.value<void*>();
APPLICATION->launch(m_inst, LaunchMode::Normal, std::make_shared<MinecraftTarget>(MinecraftTarget::parse(world->folderName(), true)));
auto world = (InstanceWorld*)worldVariant.value<void*>();
APPLICATION->launch(world->instance, LaunchMode::Normal, std::make_shared<MinecraftTarget>(MinecraftTarget::parse(world->world.folderName(), true)));
}
#include "MultiWorldListPage.moc"

View file

@ -52,7 +52,7 @@ class MultiWorldListPage : public QMainWindow, public BasePage {
Q_OBJECT
public:
explicit MultiWorldListPage(MinecraftInstance* inst, MultiWorldList* worlds, QWidget* parent = 0);
explicit MultiWorldListPage(MultiWorldList* worlds, QWidget* parent = 0);
virtual ~MultiWorldListPage();
virtual QString displayName() const override { return tr("Worlds"); }
@ -70,9 +70,6 @@ class MultiWorldListPage : public QMainWindow, public BasePage {
bool worldListFilter(QKeyEvent* ev);
QMenu* createPopupMenu() override;
protected:
MinecraftInstance* m_inst;
private:
QModelIndex getSelectedWorld();
bool isWorldSafe(QModelIndex index);