diff --git a/CMakeLists.txt b/CMakeLists.txt index bcf931c0..1c93e7a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,15 +78,6 @@ set(MultiMC_PASTE_EE_API_KEY "utLvciUouSURFzfjPxLBf5W4ISsUX4pwBDF7N1AfZ" CACHE S # Google analytics ID set(MultiMC_ANALYTICS_ID "UA-87731965-2" CACHE STRING "ID you can get from Google analytics") -# Bug tracker URL -set(MultiMC_BUG_TRACKER_URL "" CACHE STRING "URL for the bug tracker.") - -# Discord URL -set(MultiMC_DISCORD_URL "" CACHE STRING "URL for the Discord guild.") - -# Subreddit URL -set(MultiMC_SUBREDDIT_URL "" CACHE STRING "URL for the subreddit.") - #### Check the current Git commit and branch include(GetGitRevisionDescription) get_git_head_revision(MultiMC_GIT_REFSPEC MultiMC_GIT_COMMIT) @@ -274,7 +265,6 @@ add_subdirectory(libraries/iconfix) # fork of Qt's QIcon loader add_subdirectory(libraries/LocalPeer) # fork of a library from Qt solutions add_subdirectory(libraries/classparser) # google analytics library add_subdirectory(libraries/optional-bare) -add_subdirectory(libraries/tomlc99) # toml parser ############################### Built Artifacts ############################### diff --git a/COPYING.md b/COPYING.md index caa4bed5..c0c98606 100644 --- a/COPYING.md +++ b/COPYING.md @@ -251,28 +251,3 @@ FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -# tomlc99 - - MIT License - - Copyright (c) 2017 CK Tan - https://github.com/cktan/tomlc99 - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. diff --git a/api/logic/BaseInstance.cpp b/api/logic/BaseInstance.cpp index cff16631..d08ceb2b 100644 --- a/api/logic/BaseInstance.cpp +++ b/api/logic/BaseInstance.cpp @@ -134,12 +134,6 @@ void BaseInstance::setRunning(bool running) m_isRunning = running; - if(!m_settings->get("RecordGameTime").toBool()) - { - emit runningStatusChanged(running); - return; - } - if(running) { m_timeStarted = QDateTime::currentDateTime(); diff --git a/api/logic/BaseInstance.h b/api/logic/BaseInstance.h index 3bb31b18..59700fbf 100644 --- a/api/logic/BaseInstance.h +++ b/api/logic/BaseInstance.h @@ -34,8 +34,6 @@ #include "multimc_logic_export.h" -#include "minecraft/launch/MinecraftServerTarget.h" - class QDir; class Task; class LaunchTask; @@ -224,9 +222,9 @@ public: bool reloadSettings(); /** - * 'print' a verbose description of the instance into a QStringList + * 'print' a verbose desription of the instance into a QStringList */ - virtual QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) = 0; + virtual QStringList verboseDescription(AuthSessionPtr session) = 0; Status currentStatus() const; diff --git a/api/logic/CMakeLists.txt b/api/logic/CMakeLists.txt index 2694dddd..0d47b4df 100644 --- a/api/logic/CMakeLists.txt +++ b/api/logic/CMakeLists.txt @@ -126,8 +126,6 @@ set(NET_SOURCES # Game launch logic set(LAUNCH_SOURCES - launch/steps/LookupServerAddress.cpp - launch/steps/LookupServerAddress.h launch/steps/PostLaunchCommand.cpp launch/steps/PostLaunchCommand.h launch/steps/PreLaunchCommand.cpp @@ -246,8 +244,6 @@ set(MINECRAFT_SOURCES minecraft/launch/ExtractNatives.h minecraft/launch/LauncherPartLaunch.cpp minecraft/launch/LauncherPartLaunch.h - minecraft/launch/MinecraftServerTarget.cpp - minecraft/launch/MinecraftServerTarget.h minecraft/launch/PrintInstanceInfo.cpp minecraft/launch/PrintInstanceInfo.h minecraft/launch/ReconstructAssets.cpp @@ -314,10 +310,6 @@ set(MINECRAFT_SOURCES minecraft/mod/ModFolderLoadTask.cpp minecraft/mod/LocalModParseTask.h minecraft/mod/LocalModParseTask.cpp - minecraft/mod/ResourcePackFolderModel.h - minecraft/mod/ResourcePackFolderModel.cpp - minecraft/mod/TexturePackFolderModel.h - minecraft/mod/TexturePackFolderModel.cpp # Assets minecraft/AssetsUtils.h @@ -560,7 +552,7 @@ set_target_properties(MultiMC_logic PROPERTIES CXX_VISIBILITY_PRESET hidden VISI generate_export_header(MultiMC_logic) # Link -target_link_libraries(MultiMC_logic systeminfo MultiMC_quazip MultiMC_classparser ${NBT_NAME} ${ZLIB_LIBRARIES} optional-bare tomlc99 BuildConfig) +target_link_libraries(MultiMC_logic systeminfo MultiMC_quazip MultiMC_classparser ${NBT_NAME} ${ZLIB_LIBRARIES} optional-bare BuildConfig) target_link_libraries(MultiMC_logic Qt5::Core Qt5::Xml Qt5::Network Qt5::Concurrent) # Mark and export headers diff --git a/api/logic/InstanceImportTask.cpp b/api/logic/InstanceImportTask.cpp index 3eac4d57..fe2cdd75 100644 --- a/api/logic/InstanceImportTask.cpp +++ b/api/logic/InstanceImportTask.cpp @@ -238,7 +238,6 @@ void InstanceImportTask::processFlame() } QString forgeVersion; - QString fabricVersion; for(auto &loader: pack.minecraft.modLoaders) { auto id = loader.id; @@ -248,12 +247,6 @@ void InstanceImportTask::processFlame() forgeVersion = id; continue; } - if(id.startsWith("fabric-")) - { - id.remove("fabric-"); - fabricVersion = id; - continue; - } logWarning(tr("Unknown mod loader in manifest: %1").arg(id)); } @@ -288,10 +281,6 @@ void InstanceImportTask::processFlame() } components->setComponentVersion("net.minecraftforge", forgeVersion); } - if(!fabricVersion.isEmpty()) - { - components->setComponentVersion("net.fabricmc.fabric-loader", fabricVersion); - } if (m_instIcon != "default") { instance.setIconKey(m_instIcon); diff --git a/api/logic/NullInstance.h b/api/logic/NullInstance.h index f2dff37c..4419a2f6 100644 --- a/api/logic/NullInstance.h +++ b/api/logic/NullInstance.h @@ -67,7 +67,7 @@ public: { return false; } - QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override + QStringList verboseDescription(AuthSessionPtr session) override { QStringList out; out << "Null instance - placeholder."; diff --git a/api/logic/java/JavaUtils.cpp b/api/logic/java/JavaUtils.cpp index 4b231e6a..647711e5 100644 --- a/api/logic/java/JavaUtils.cpp +++ b/api/logic/java/JavaUtils.cpp @@ -150,7 +150,7 @@ JavaInstallPtr JavaUtils::GetDefaultJava() } #if defined(Q_OS_WIN32) -QList JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString keyName, QString keyJavaDir, QString subkeySuffix) +QList JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString keyName) { QList javas; @@ -175,6 +175,8 @@ QList JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString RegQueryValueExA(jreKey, "CurrentVersion", NULL, NULL, (BYTE *)value, &valueSz); } + QString recommended = value; + TCHAR subKeyName[255]; DWORD subKeyNameSize, numSubKeys, retCode; @@ -193,7 +195,7 @@ QList JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString if (retCode == ERROR_SUCCESS) { // Now open the registry key for the version that we just got. - QString newKeyName = keyName + "\\" + subKeyName + subkeySuffix; + QString newKeyName = keyName + "\\" + subKeyName; HKEY newKey; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, newKeyName.toStdString().c_str(), 0, @@ -202,11 +204,11 @@ QList JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString // Read the JavaHome value to find where Java is installed. value = new char[0]; valueSz = 0; - if (RegQueryValueEx(newKey, keyJavaDir.toStdString().c_str(), NULL, NULL, (BYTE *)value, + if (RegQueryValueEx(newKey, "JavaHome", NULL, NULL, (BYTE *)value, &valueSz) == ERROR_MORE_DATA) { value = new char[valueSz]; - RegQueryValueEx(newKey, keyJavaDir.toStdString().c_str(), NULL, NULL, (BYTE *)value, + RegQueryValueEx(newKey, "JavaHome", NULL, NULL, (BYTE *)value, &valueSz); // Now, we construct the version object and add it to the list. @@ -235,78 +237,25 @@ QList JavaUtils::FindJavaPaths() { QList java_candidates; - // Oracle QList JRE64s = this->FindJavaFromRegistryKey( - KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment", "JavaHome"); + KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment"); QList JDK64s = this->FindJavaFromRegistryKey( - KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Development Kit", "JavaHome"); + KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Development Kit"); QList JRE32s = this->FindJavaFromRegistryKey( - KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment", "JavaHome"); + KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment"); QList JDK32s = this->FindJavaFromRegistryKey( - KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\Java Development Kit", "JavaHome"); + KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\Java Development Kit"); - // Oracle for Java 9 and newer - QList NEWJRE64s = this->FindJavaFromRegistryKey( - KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\JRE", "JavaHome"); - QList NEWJDK64s = this->FindJavaFromRegistryKey( - KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\JDK", "JavaHome"); - QList NEWJRE32s = this->FindJavaFromRegistryKey( - KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\JRE", "JavaHome"); - QList NEWJDK32s = this->FindJavaFromRegistryKey( - KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\JDK", "JavaHome"); - - // AdoptOpenJDK - QList ADOPTOPENJRE32s = this->FindJavaFromRegistryKey( - KEY_WOW64_32KEY, "SOFTWARE\\AdoptOpenJDK\\JRE", "Path", "\\hotspot\\MSI"); - QList ADOPTOPENJRE64s = this->FindJavaFromRegistryKey( - KEY_WOW64_64KEY, "SOFTWARE\\AdoptOpenJDK\\JRE", "Path", "\\hotspot\\MSI"); - QList ADOPTOPENJDK32s = this->FindJavaFromRegistryKey( - KEY_WOW64_32KEY, "SOFTWARE\\AdoptOpenJDK\\JDK", "Path", "\\hotspot\\MSI"); - QList ADOPTOPENJDK64s = this->FindJavaFromRegistryKey( - KEY_WOW64_64KEY, "SOFTWARE\\AdoptOpenJDK\\JDK", "Path", "\\hotspot\\MSI"); - - // Microsoft - QList MICROSOFTJDK64s = this->FindJavaFromRegistryKey( - KEY_WOW64_64KEY, "SOFTWARE\\Microsoft\\JDK", "Path", "\\hotspot\\MSI"); - - // Azul Zulu - QList ZULU64s = this->FindJavaFromRegistryKey( - KEY_WOW64_64KEY, "SOFTWARE\\Azul Systems\\Zulu", "InstallationPath"); - QList ZULU32s = this->FindJavaFromRegistryKey( - KEY_WOW64_32KEY, "SOFTWARE\\Azul Systems\\Zulu", "InstallationPath"); - - // BellSoft Liberica - QList LIBERICA64s = this->FindJavaFromRegistryKey( - KEY_WOW64_64KEY, "SOFTWARE\\BellSoft\\Liberica", "InstallationPath"); - QList LIBERICA32s = this->FindJavaFromRegistryKey( - KEY_WOW64_32KEY, "SOFTWARE\\BellSoft\\Liberica", "InstallationPath"); - - // List x64 before x86 java_candidates.append(JRE64s); - java_candidates.append(NEWJRE64s); - java_candidates.append(ADOPTOPENJRE64s); java_candidates.append(MakeJavaPtr("C:/Program Files/Java/jre8/bin/javaw.exe")); java_candidates.append(MakeJavaPtr("C:/Program Files/Java/jre7/bin/javaw.exe")); java_candidates.append(MakeJavaPtr("C:/Program Files/Java/jre6/bin/javaw.exe")); java_candidates.append(JDK64s); - java_candidates.append(NEWJDK64s); - java_candidates.append(ADOPTOPENJDK64s); - java_candidates.append(MICROSOFTJDK64s); - java_candidates.append(ZULU64s); - java_candidates.append(LIBERICA64s); - java_candidates.append(JRE32s); - java_candidates.append(NEWJRE32s); - java_candidates.append(ADOPTOPENJRE32s); java_candidates.append(MakeJavaPtr("C:/Program Files (x86)/Java/jre8/bin/javaw.exe")); java_candidates.append(MakeJavaPtr("C:/Program Files (x86)/Java/jre7/bin/javaw.exe")); java_candidates.append(MakeJavaPtr("C:/Program Files (x86)/Java/jre6/bin/javaw.exe")); java_candidates.append(JDK32s); - java_candidates.append(NEWJDK32s); - java_candidates.append(ADOPTOPENJDK32s); - java_candidates.append(ZULU32s); - java_candidates.append(LIBERICA32s); - java_candidates.append(MakeJavaPtr(this->GetDefaultJava()->path)); QList candidates; @@ -381,9 +330,6 @@ QList JavaUtils::FindJavaPaths() scanJavaDir("/usr/lib32/jvm"); // javas stored in MultiMC's folder scanJavaDir("java"); - // manually installed JDKs in /opt - scanJavaDir("/opt/jdk"); - scanJavaDir("/opt/jdks"); return javas; } #else diff --git a/api/logic/java/JavaUtils.h b/api/logic/java/JavaUtils.h index 206acf89..7474c494 100644 --- a/api/logic/java/JavaUtils.h +++ b/api/logic/java/JavaUtils.h @@ -39,6 +39,6 @@ public: JavaInstallPtr GetDefaultJava(); #ifdef Q_OS_WIN - QList FindJavaFromRegistryKey(DWORD keyType, QString keyName, QString keyJavaDir, QString subkeySuffix = ""); + QList FindJavaFromRegistryKey(DWORD keyType, QString keyName); #endif }; diff --git a/api/logic/launch/steps/LookupServerAddress.cpp b/api/logic/launch/steps/LookupServerAddress.cpp deleted file mode 100644 index de56c28a..00000000 --- a/api/logic/launch/steps/LookupServerAddress.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* Copyright 2013-2021 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 "LookupServerAddress.h" - -#include - -LookupServerAddress::LookupServerAddress(LaunchTask *parent) : - LaunchStep(parent), m_dnsLookup(new QDnsLookup(this)) -{ - connect(m_dnsLookup, &QDnsLookup::finished, this, &LookupServerAddress::on_dnsLookupFinished); - - m_dnsLookup->setType(QDnsLookup::SRV); -} - -void LookupServerAddress::setLookupAddress(const QString &lookupAddress) -{ - m_lookupAddress = lookupAddress; - m_dnsLookup->setName(QString("_minecraft._tcp.%1").arg(lookupAddress)); -} - -void LookupServerAddress::setOutputAddressPtr(MinecraftServerTargetPtr output) -{ - m_output = std::move(output); -} - -bool LookupServerAddress::abort() -{ - m_dnsLookup->abort(); - emitFailed("Aborted"); - return true; -} - -void LookupServerAddress::executeTask() -{ - m_dnsLookup->lookup(); -} - -void LookupServerAddress::on_dnsLookupFinished() -{ - if (isFinished()) - { - // Aborted - return; - } - - if (m_dnsLookup->error() != QDnsLookup::NoError) - { - emit logLine(QString("Failed to resolve server address (this is NOT an error!) %1: %2\n") - .arg(m_dnsLookup->name(), m_dnsLookup->errorString()), MessageLevel::MultiMC); - resolve(m_lookupAddress, 25565); // Technically the task failed, however, we don't abort the launch - // and leave it up to minecraft to fail (or maybe not) when connecting - return; - } - - const auto records = m_dnsLookup->serviceRecords(); - if (records.empty()) - { - emit logLine( - QString("Failed to resolve server address %1: the DNS lookup succeeded, but no records were returned.\n") - .arg(m_dnsLookup->name()), MessageLevel::Warning); - resolve(m_lookupAddress, 25565); // Technically the task failed, however, we don't abort the launch - // and leave it up to minecraft to fail (or maybe not) when connecting - return; - } - - const auto &firstRecord = records.at(0); - quint16 port = firstRecord.port(); - - emit logLine(QString("Resolved server address %1 to %2 with port %3\n").arg( - m_dnsLookup->name(), firstRecord.target(), QString::number(port)),MessageLevel::MultiMC); - resolve(firstRecord.target(), port); -} - -void LookupServerAddress::resolve(const QString &address, quint16 port) -{ - m_output->address = address; - m_output->port = port; - - emitSucceeded(); - m_dnsLookup->deleteLater(); -} diff --git a/api/logic/launch/steps/LookupServerAddress.h b/api/logic/launch/steps/LookupServerAddress.h deleted file mode 100644 index 5a5c3de1..00000000 --- a/api/logic/launch/steps/LookupServerAddress.h +++ /dev/null @@ -1,49 +0,0 @@ -/* Copyright 2013-2021 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 -#include -#include - -#include "minecraft/launch/MinecraftServerTarget.h" - -class LookupServerAddress: public LaunchStep { -Q_OBJECT -public: - explicit LookupServerAddress(LaunchTask *parent); - virtual ~LookupServerAddress() {}; - - virtual void executeTask(); - virtual bool abort(); - virtual bool canAbort() const - { - return true; - } - - void setLookupAddress(const QString &lookupAddress); - void setOutputAddressPtr(MinecraftServerTargetPtr output); - -private slots: - void on_dnsLookupFinished(); - -private: - void resolve(const QString &address, quint16 port); - - QDnsLookup *m_dnsLookup; - QString m_lookupAddress; - MinecraftServerTargetPtr m_output; -}; diff --git a/api/logic/minecraft/MinecraftInstance.cpp b/api/logic/minecraft/MinecraftInstance.cpp index c09b5c05..f35a5fdc 100644 --- a/api/logic/minecraft/MinecraftInstance.cpp +++ b/api/logic/minecraft/MinecraftInstance.cpp @@ -12,7 +12,6 @@ #include #include "launch/LaunchTask.h" -#include "launch/steps/LookupServerAddress.h" #include "launch/steps/PostLaunchCommand.h" #include "launch/steps/Update.h" #include "launch/steps/PreLaunchCommand.h" @@ -31,8 +30,6 @@ #include "meta/VersionList.h" #include "mod/ModFolderModel.h" -#include "mod/ResourcePackFolderModel.h" -#include "mod/TexturePackFolderModel.h" #include "WorldList.h" #include "icons/IIconList.h" @@ -111,15 +108,6 @@ MinecraftInstance::MinecraftInstance(SettingsObjectPtr globalSettings, SettingsO m_settings->registerOverride(globalSettings->getSetting("UseNativeOpenAL"), nativeLibraryWorkaroundsOverride); m_settings->registerOverride(globalSettings->getSetting("UseNativeGLFW"), nativeLibraryWorkaroundsOverride); - // Game time - auto gameTimeOverride = m_settings->registerSetting("OverrideGameTime", false); - m_settings->registerOverride(globalSettings->getSetting("ShowGameTime"), gameTimeOverride); - m_settings->registerOverride(globalSettings->getSetting("RecordGameTime"), gameTimeOverride); - - // Join server on launch, this does not have a global override - m_settings->registerSetting("JoinServerOnLaunch", false); - m_settings->registerSetting("JoinServerOnLaunchAddress", ""); - // DEPRECATED: Read what versions the user configuration thinks should be used m_settings->registerSetting({"IntendedVersion", "MinecraftVersion"}, ""); m_settings->registerSetting("LWJGLVersion", ""); @@ -406,8 +394,7 @@ static QString replaceTokensIn(QString text, QMap with) return result; } -QStringList MinecraftInstance::processMinecraftArgs( - AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) const +QStringList MinecraftInstance::processMinecraftArgs(AuthSessionPtr session) const { auto profile = m_components->getProfile(); QString args_pattern = profile->getMinecraftArguments(); @@ -416,12 +403,6 @@ QStringList MinecraftInstance::processMinecraftArgs( args_pattern += " --tweakClass " + tweaker; } - if (serverToJoin && !serverToJoin->address.isEmpty()) - { - args_pattern += " --server " + serverToJoin->address; - args_pattern += " --port " + QString::number(serverToJoin->port); - } - QMap token_mapping; // yggdrasil! if(session) @@ -458,7 +439,7 @@ QStringList MinecraftInstance::processMinecraftArgs( return parts; } -QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) +QString MinecraftInstance::createLaunchScript(AuthSessionPtr session) { QString launchScript; @@ -479,17 +460,8 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftS launchScript += "appletClass " + appletClass + "\n"; } - if (serverToJoin && !serverToJoin->address.isEmpty()) - { - launchScript += "serverAddress " + serverToJoin->address + "\n"; - launchScript += "serverPort " + QString::number(serverToJoin->port) + "\n"; - } - // generic minecraft params - for (auto param : processMinecraftArgs( - session, - nullptr /* When using a launch script, the server parameters are handled by it*/ - )) + for (auto param : processMinecraftArgs(session)) { launchScript += "param " + param + "\n"; } @@ -539,7 +511,7 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftS return launchScript; } -QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) +QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session) { QStringList out; out << "Main Class:" << " " + getMainClass() << ""; @@ -654,7 +626,7 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr out << ""; } - auto params = processMinecraftArgs(nullptr, serverToJoin); + auto params = processMinecraftArgs(nullptr); out << "Params:"; out << " " + params.join(' '); out << ""; @@ -801,7 +773,7 @@ QString MinecraftInstance::getStatusbarDescription() QString description; description.append(tr("Minecraft %1 (%2)").arg(m_components->getComponentVersion("net.minecraft")).arg(typeName())); - if(m_settings->get("ShowGameTime").toBool() && totalTimePlayed() > 0) + if(totalTimePlayed() > 0) { description.append(tr(", played for %1").arg(prettifyTimeDuration(totalTimePlayed()))); } @@ -860,21 +832,6 @@ shared_qobject_ptr MinecraftInstance::createLaunchTask(AuthSessionPt process->appendStep(new CreateGameFolders(pptr)); } - if (!serverToJoin && m_settings->get("JoinServerOnLaunch").toBool()) - { - QString fullAddress = m_settings->get("JoinServerOnLaunchAddress").toString(); - serverToJoin.reset(new MinecraftServerTarget(MinecraftServerTarget::parse(fullAddress))); - } - - if(serverToJoin && serverToJoin->port == 25565) - { - // Resolve server address to join on launch - auto *step = new LookupServerAddress(pptr); - step->setLookupAddress(serverToJoin->address); - step->setOutputAddressPtr(serverToJoin); - process->appendStep(step); - } - // run pre-launch command if that's needed if(getPreLaunchCommand().size()) { @@ -912,7 +869,7 @@ shared_qobject_ptr MinecraftInstance::createLaunchTask(AuthSessionPt // print some instance info here... { - process->appendStep(new PrintInstanceInfo(pptr, session, serverToJoin)); + process->appendStep(new PrintInstanceInfo(pptr, session)); } // extract native jars if needed @@ -947,7 +904,6 @@ shared_qobject_ptr MinecraftInstance::createLaunchTask(AuthSessionPt auto step = new LauncherPartLaunch(pptr); step->setWorkingDirectory(gameRoot()); step->setAuthSession(session); - step->setServerToJoin(serverToJoin); process->appendStep(step); } else if (method == "DirectJava") @@ -955,7 +911,6 @@ shared_qobject_ptr MinecraftInstance::createLaunchTask(AuthSessionPt auto step = new DirectJavaLaunch(pptr); step->setWorkingDirectory(gameRoot()); step->setAuthSession(session); - step->setServerToJoin(serverToJoin); process->appendStep(step); } } @@ -1012,7 +967,7 @@ std::shared_ptr MinecraftInstance::resourcePackList() const { if (!m_resource_pack_list) { - m_resource_pack_list.reset(new ResourcePackFolderModel(resourcePacksDir())); + m_resource_pack_list.reset(new ModFolderModel(resourcePacksDir())); m_resource_pack_list->disableInteraction(isRunning()); connect(this, &BaseInstance::runningStatusChanged, m_resource_pack_list.get(), &ModFolderModel::disableInteraction); } @@ -1023,7 +978,7 @@ std::shared_ptr MinecraftInstance::texturePackList() const { if (!m_texture_pack_list) { - m_texture_pack_list.reset(new TexturePackFolderModel(texturePacksDir())); + m_texture_pack_list.reset(new ModFolderModel(texturePacksDir())); m_texture_pack_list->disableInteraction(isRunning()); connect(this, &BaseInstance::runningStatusChanged, m_texture_pack_list.get(), &ModFolderModel::disableInteraction); } diff --git a/api/logic/minecraft/MinecraftInstance.h b/api/logic/minecraft/MinecraftInstance.h index d9d285fc..62127048 100644 --- a/api/logic/minecraft/MinecraftInstance.h +++ b/api/logic/minecraft/MinecraftInstance.h @@ -78,11 +78,11 @@ public: ////// Launch stuff ////// shared_qobject_ptr createUpdateTask(Net::Mode mode) override; - shared_qobject_ptr createLaunchTask(AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin, quint16 localAuthServerPort) override; + shared_qobject_ptr createLaunchTask(AuthSessionPtr account) override; QStringList extraArguments() const override; - QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override; + QStringList verboseDescription(AuthSessionPtr session) override; QList getJarMods() const; - QString createLaunchScript(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin); + QString createLaunchScript(AuthSessionPtr session); /// get arguments passed to java QStringList javaArguments() const; @@ -109,7 +109,7 @@ public: virtual QString getMainClass() const; // FIXME: remove - virtual QStringList processMinecraftArgs(AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) const; + virtual QStringList processMinecraftArgs(AuthSessionPtr account) const; virtual JavaVersion getJavaVersion() const; diff --git a/api/logic/minecraft/VersionFilterData.cpp b/api/logic/minecraft/VersionFilterData.cpp index 38e7b60c..a47fc0a0 100644 --- a/api/logic/minecraft/VersionFilterData.cpp +++ b/api/logic/minecraft/VersionFilterData.cpp @@ -65,7 +65,4 @@ VersionFilterData::VersionFilterData() QSet{"net.java.jinput:jinput", "net.java.jinput:jinput-platform", "net.java.jutils:jutils", "org.lwjgl.lwjgl:lwjgl", "org.lwjgl.lwjgl:lwjgl_util", "org.lwjgl.lwjgl:lwjgl-platform"}; - - java8BeginsDate = timeFromS3Time("2017-03-30T09:32:19+00:00"); - java16BeginsDate = timeFromS3Time("2021-05-12T11:19:15+00:00"); } diff --git a/api/logic/minecraft/VersionFilterData.h b/api/logic/minecraft/VersionFilterData.h index d100acc3..afd4502b 100644 --- a/api/logic/minecraft/VersionFilterData.h +++ b/api/logic/minecraft/VersionFilterData.h @@ -23,9 +23,5 @@ struct VersionFilterData QDateTime legacyCutoffDate; // Libraries that belong to LWJGL QSet lwjglWhitelist; - // release date of first version to require Java 8 (17w13a) - QDateTime java8BeginsDate; - // release data of first version to require Java 16 (21w19a) - QDateTime java16BeginsDate; }; extern VersionFilterData MULTIMC_LOGIC_EXPORT g_VersionFilterData; diff --git a/api/logic/minecraft/launch/CreateGameFolders.cpp b/api/logic/minecraft/launch/CreateGameFolders.cpp index 4081e72e..415b7e23 100644 --- a/api/logic/minecraft/launch/CreateGameFolders.cpp +++ b/api/logic/minecraft/launch/CreateGameFolders.cpp @@ -15,7 +15,7 @@ void CreateGameFolders::executeTask() if(!FS::ensureFolderPathExists(minecraftInstance->gameRoot())) { emit logLine("Couldn't create the main game folder", MessageLevel::Error); - emitFailed(tr("Couldn't create the main game folder")); + emitFailed("Couldn't create the main game folder"); return; } diff --git a/api/logic/minecraft/launch/DirectJavaLaunch.cpp b/api/logic/minecraft/launch/DirectJavaLaunch.cpp index 2110384f..d9841a43 100644 --- a/api/logic/minecraft/launch/DirectJavaLaunch.cpp +++ b/api/logic/minecraft/launch/DirectJavaLaunch.cpp @@ -55,7 +55,7 @@ void DirectJavaLaunch::executeTask() // make detachable - this will keep the process running even if the object is destroyed m_process.setDetachable(true); - auto mcArgs = minecraftInstance->processMinecraftArgs(m_session, m_serverToJoin); + auto mcArgs = minecraftInstance->processMinecraftArgs(m_session); args.append(mcArgs); QString wrapperCommandStr = instance->getWrapperCommand().trimmed(); @@ -66,9 +66,9 @@ void DirectJavaLaunch::executeTask() auto realWrapperCommand = QStandardPaths::findExecutable(wrapperCommand); if (realWrapperCommand.isEmpty()) { - const char *reason = QT_TR_NOOP("The wrapper command \"%1\" couldn't be found."); - emit logLine(QString(reason).arg(wrapperCommand), MessageLevel::Fatal); - emitFailed(tr(reason).arg(wrapperCommand)); + QString reason = tr("The wrapper command \"%1\" couldn't be found.").arg(wrapperCommand); + emit logLine(reason, MessageLevel::Fatal); + emitFailed(reason); return; } emit logLine("Wrapper command is:\n" + wrapperCommandStr + "\n\n", MessageLevel::MultiMC); @@ -87,17 +87,18 @@ void DirectJavaLaunch::on_state(LoggedProcess::State state) { case LoggedProcess::FailedToStart: { - //: Error message displayed if instance can't start - const char *reason = QT_TR_NOOP("Could not launch minecraft!"); + //: Error message displayed if instace can't start + QString reason = tr("Could not launch minecraft!"); emit logLine(reason, MessageLevel::Fatal); - emitFailed(tr(reason)); + emitFailed(reason); return; } case LoggedProcess::Aborted: case LoggedProcess::Crashed: + { m_parent->setPid(-1); - emitFailed(tr("Game crashed.")); + emitFailed("Game crashed."); return; } case LoggedProcess::Finished: @@ -107,7 +108,7 @@ void DirectJavaLaunch::on_state(LoggedProcess::State state) auto exitCode = m_process.exitCode(); if(exitCode != 0) { - emitFailed(tr("Game crashed.")); + emitFailed("Game crashed."); return; } //FIXME: make this work again @@ -117,7 +118,7 @@ void DirectJavaLaunch::on_state(LoggedProcess::State state) break; } case LoggedProcess::Running: - emit logLine(QString("Minecraft process ID: %1\n\n").arg(m_process.processId()), MessageLevel::MultiMC); + emit logLine(tr("Minecraft process ID: %1\n\n").arg(m_process.processId()), MessageLevel::MultiMC); m_parent->setPid(m_process.processId()); m_parent->instance()->setLastLaunch(); break; diff --git a/api/logic/minecraft/launch/DirectJavaLaunch.h b/api/logic/minecraft/launch/DirectJavaLaunch.h index 58b119b8..d9d9bdc2 100644 --- a/api/logic/minecraft/launch/DirectJavaLaunch.h +++ b/api/logic/minecraft/launch/DirectJavaLaunch.h @@ -19,8 +19,6 @@ #include #include -#include "MinecraftServerTarget.h" - class DirectJavaLaunch: public LaunchStep { Q_OBJECT @@ -40,12 +38,6 @@ public: { m_session = session; } - - void setServerToJoin(MinecraftServerTargetPtr serverToJoin) - { - m_serverToJoin = std::move(serverToJoin); - } - private slots: void on_state(LoggedProcess::State state); @@ -53,6 +45,5 @@ private: LoggedProcess m_process; QString m_command; AuthSessionPtr m_session; - MinecraftServerTargetPtr m_serverToJoin; }; diff --git a/api/logic/minecraft/launch/ExtractNatives.cpp b/api/logic/minecraft/launch/ExtractNatives.cpp index d57499aa..d41cb8fd 100644 --- a/api/logic/minecraft/launch/ExtractNatives.cpp +++ b/api/logic/minecraft/launch/ExtractNatives.cpp @@ -94,9 +94,9 @@ void ExtractNatives::executeTask() { if(!unzipNatives(source, outputPath, jniHackEnabled, nativeOpenAL, nativeGLFW)) { - const char *reason = QT_TR_NOOP("Couldn't extract native jar '%1' to destination '%2'"); - emit logLine(QString(reason).arg(source, outputPath), MessageLevel::Fatal); - emitFailed(tr(reason).arg(source, outputPath)); + auto reason = tr("Couldn't extract native jar '%1' to destination '%2'").arg(source, outputPath); + emit logLine(reason, MessageLevel::Fatal); + emitFailed(reason); } } emitSucceeded(); diff --git a/api/logic/minecraft/launch/LauncherPartLaunch.cpp b/api/logic/minecraft/launch/LauncherPartLaunch.cpp index ee469770..1408e6ad 100644 --- a/api/logic/minecraft/launch/LauncherPartLaunch.cpp +++ b/api/logic/minecraft/launch/LauncherPartLaunch.cpp @@ -59,7 +59,7 @@ void LauncherPartLaunch::executeTask() auto instance = m_parent->instance(); std::shared_ptr minecraftInstance = std::dynamic_pointer_cast(instance); - m_launchScript = minecraftInstance->createLaunchScript(m_session, m_serverToJoin); + m_launchScript = minecraftInstance->createLaunchScript(m_session); QStringList args = minecraftInstance->javaArguments(); QString allArgs = args.join(", "); emit logLine("Java Arguments:\n[" + m_parent->censorPrivateInfo(allArgs) + "]\n\n", MessageLevel::MultiMC); @@ -118,9 +118,9 @@ void LauncherPartLaunch::executeTask() auto realWrapperCommand = QStandardPaths::findExecutable(wrapperCommand); if (realWrapperCommand.isEmpty()) { - const char *reason = QT_TR_NOOP("The wrapper command \"%1\" couldn't be found."); - emit logLine(QString(reason).arg(wrapperCommand), MessageLevel::Fatal); - emitFailed(tr(reason).arg(wrapperCommand)); + QString reason = tr("The wrapper command \"%1\" couldn't be found.").arg(wrapperCommand); + emit logLine(reason, MessageLevel::Fatal); + emitFailed(reason); return; } emit logLine("Wrapper command is:\n" + wrapperCommandStr + "\n\n", MessageLevel::MultiMC); @@ -140,16 +140,17 @@ void LauncherPartLaunch::on_state(LoggedProcess::State state) case LoggedProcess::FailedToStart: { //: Error message displayed if instace can't start - const char *reason = QT_TR_NOOP("Could not launch minecraft!"); + QString reason = tr("Could not launch minecraft!"); emit logLine(reason, MessageLevel::Fatal); - emitFailed(tr(reason)); + emitFailed(reason); return; } case LoggedProcess::Aborted: case LoggedProcess::Crashed: + { m_parent->setPid(-1); - emitFailed(tr("Game crashed.")); + emitFailed("Game crashed."); return; } case LoggedProcess::Finished: @@ -159,7 +160,7 @@ void LauncherPartLaunch::on_state(LoggedProcess::State state) auto exitCode = m_process.exitCode(); if(exitCode != 0) { - emitFailed(tr("Game crashed.")); + emitFailed("Game crashed."); return; } //FIXME: make this work again @@ -169,7 +170,7 @@ void LauncherPartLaunch::on_state(LoggedProcess::State state) break; } case LoggedProcess::Running: - emit logLine(QString("Minecraft process ID: %1\n\n").arg(m_process.processId()), MessageLevel::MultiMC); + emit logLine(tr("Minecraft process ID: %1\n\n").arg(m_process.processId()), MessageLevel::MultiMC); m_parent->setPid(m_process.processId()); m_parent->instance()->setLastLaunch(); // send the launch script to the launcher part diff --git a/api/logic/minecraft/launch/LauncherPartLaunch.h b/api/logic/minecraft/launch/LauncherPartLaunch.h index 6a7ee0e5..9e951849 100644 --- a/api/logic/minecraft/launch/LauncherPartLaunch.h +++ b/api/logic/minecraft/launch/LauncherPartLaunch.h @@ -19,8 +19,6 @@ #include #include -#include "MinecraftServerTarget.h" - class LauncherPartLaunch: public LaunchStep { Q_OBJECT @@ -41,11 +39,6 @@ public: m_session = session; } - void setServerToJoin(MinecraftServerTargetPtr serverToJoin) - { - m_serverToJoin = std::move(serverToJoin); - } - private slots: void on_state(LoggedProcess::State state); @@ -54,7 +47,5 @@ private: QString m_command; AuthSessionPtr m_session; QString m_launchScript; - MinecraftServerTargetPtr m_serverToJoin; - bool mayProceed = false; }; diff --git a/api/logic/minecraft/launch/MinecraftServerTarget.cpp b/api/logic/minecraft/launch/MinecraftServerTarget.cpp deleted file mode 100644 index 569273b6..00000000 --- a/api/logic/minecraft/launch/MinecraftServerTarget.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* Copyright 2013-2021 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 "MinecraftServerTarget.h" - -#include - -MinecraftServerTarget MinecraftServerTarget::parse(const QString &fullAddress) { - QStringList split = fullAddress.split(":"); - - // The logic below replicates the exact logic minecraft uses for parsing server addresses. - // While the conversion is not lossless and eats errors, it ensures the same behavior - // within Minecraft and MultiMC when entering server addresses. - if (fullAddress.startsWith("[")) - { - int bracket = fullAddress.indexOf("]"); - if (bracket > 0) - { - QString ipv6 = fullAddress.mid(1, bracket - 1); - QString port = fullAddress.mid(bracket + 1).trimmed(); - - if (port.startsWith(":") && !ipv6.isEmpty()) - { - port = port.mid(1); - split = QStringList({ ipv6, port }); - } - else - { - split = QStringList({ipv6}); - } - } - } - - if (split.size() > 2) - { - split = QStringList({fullAddress}); - } - - QString realAddress = split[0]; - - quint16 realPort = 25565; - if (split.size() > 1) - { - bool ok; - realPort = split[1].toUInt(&ok); - - if (!ok) - { - realPort = 25565; - } - } - - return MinecraftServerTarget { realAddress, realPort }; -} diff --git a/api/logic/minecraft/launch/MinecraftServerTarget.h b/api/logic/minecraft/launch/MinecraftServerTarget.h deleted file mode 100644 index 3c5786f4..00000000 --- a/api/logic/minecraft/launch/MinecraftServerTarget.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright 2013-2021 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 - -#include -#include - -struct MinecraftServerTarget { - QString address; - quint16 port; - - static MULTIMC_LOGIC_EXPORT MinecraftServerTarget parse(const QString &fullAddress); -}; - -typedef std::shared_ptr MinecraftServerTargetPtr; diff --git a/api/logic/minecraft/launch/PrintInstanceInfo.cpp b/api/logic/minecraft/launch/PrintInstanceInfo.cpp index 0b9611ad..af0b5bbf 100644 --- a/api/logic/minecraft/launch/PrintInstanceInfo.cpp +++ b/api/logic/minecraft/launch/PrintInstanceInfo.cpp @@ -101,6 +101,6 @@ void PrintInstanceInfo::executeTask() #endif logLines(log, MessageLevel::MultiMC); - logLines(instance->verboseDescription(m_session, m_serverToJoin), MessageLevel::MultiMC); + logLines(instance->verboseDescription(m_session), MessageLevel::MultiMC); emitSucceeded(); } diff --git a/api/logic/minecraft/launch/PrintInstanceInfo.h b/api/logic/minecraft/launch/PrintInstanceInfo.h index fdc30f31..168eff9d 100644 --- a/api/logic/minecraft/launch/PrintInstanceInfo.h +++ b/api/logic/minecraft/launch/PrintInstanceInfo.h @@ -18,15 +18,13 @@ #include #include #include "minecraft/auth/AuthSession.h" -#include "minecraft/launch/MinecraftServerTarget.h" // FIXME: temporary wrapper for existing task. class PrintInstanceInfo: public LaunchStep { Q_OBJECT public: - explicit PrintInstanceInfo(LaunchTask *parent, AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) : - LaunchStep(parent), m_session(session), m_serverToJoin(serverToJoin) {}; + explicit PrintInstanceInfo(LaunchTask *parent, AuthSessionPtr session) : LaunchStep(parent), m_session(session) {}; virtual ~PrintInstanceInfo(){}; virtual void executeTask(); @@ -36,6 +34,5 @@ public: } private: AuthSessionPtr m_session; - MinecraftServerTargetPtr m_serverToJoin; }; diff --git a/api/logic/minecraft/launch/VerifyJavaInstall.cpp b/api/logic/minecraft/launch/VerifyJavaInstall.cpp deleted file mode 100644 index 657669af..00000000 --- a/api/logic/minecraft/launch/VerifyJavaInstall.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "VerifyJavaInstall.h" - -#include -#include -#include -#include - -void VerifyJavaInstall::executeTask() { - auto m_inst = std::dynamic_pointer_cast(m_parent->instance()); - - auto javaVersion = m_inst->getJavaVersion(); - auto minecraftComponent = m_inst->getPackProfile()->getComponent("net.minecraft"); - - // Java 16 requirement - if (minecraftComponent->getReleaseDateTime() >= g_VersionFilterData.java16BeginsDate) { - if (javaVersion.major() < 16) { - emit logLine("Minecraft 21w19a and above require the use of Java 16", - MessageLevel::Fatal); - emitFailed(tr("Minecraft 21w19a and above require the use of Java 16")); - return; - } - } - // Java 8 requirement - else if (minecraftComponent->getReleaseDateTime() >= g_VersionFilterData.java8BeginsDate) { - if (javaVersion.major() < 8) { - emit logLine("Minecraft 17w13a and above require the use of Java 8", - MessageLevel::Fatal); - emitFailed(tr("Minecraft 17w13a and above require the use of Java 8")); - return; - } - } - - emitSucceeded(); -} diff --git a/api/logic/minecraft/launch/VerifyJavaInstall.h b/api/logic/minecraft/launch/VerifyJavaInstall.h deleted file mode 100644 index a553106d..00000000 --- a/api/logic/minecraft/launch/VerifyJavaInstall.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include - -class VerifyJavaInstall : public LaunchStep { - Q_OBJECT - -public: - explicit VerifyJavaInstall(LaunchTask *parent) : LaunchStep(parent) { - }; - ~VerifyJavaInstall() override = default; - - void executeTask() override; - bool canAbort() const override { - return false; - } -}; diff --git a/api/logic/minecraft/legacy/LegacyInstance.cpp b/api/logic/minecraft/legacy/LegacyInstance.cpp index 9f9bda5a..f86e5d05 100644 --- a/api/logic/minecraft/legacy/LegacyInstance.cpp +++ b/api/logic/minecraft/legacy/LegacyInstance.cpp @@ -225,7 +225,7 @@ QString LegacyInstance::getStatusbarDescription() return tr("Instance from previous versions."); } -QStringList LegacyInstance::verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) +QStringList LegacyInstance::verboseDescription(AuthSessionPtr session) { QStringList out; diff --git a/api/logic/minecraft/legacy/LegacyInstance.h b/api/logic/minecraft/legacy/LegacyInstance.h index 083531ee..d10219ad 100644 --- a/api/logic/minecraft/legacy/LegacyInstance.h +++ b/api/logic/minecraft/legacy/LegacyInstance.h @@ -126,7 +126,7 @@ public: } QString getStatusbarDescription() override; - QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override; + QStringList verboseDescription(AuthSessionPtr session) override; QProcessEnvironment createEnvironment() override { diff --git a/api/logic/minecraft/mod/LocalModParseTask.cpp b/api/logic/minecraft/mod/LocalModParseTask.cpp index 0d6972fb..22ebd7d4 100644 --- a/api/logic/minecraft/mod/LocalModParseTask.cpp +++ b/api/logic/minecraft/mod/LocalModParseTask.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include "settings/INIFile.h" #include "FileSystem.h" @@ -91,124 +90,6 @@ std::shared_ptr ReadMCModInfo(QByteArray contents) return nullptr; } -// https://github.com/MinecraftForge/Documentation/blob/5ab4ba6cf9abc0ac4c0abd96ad187461aefd72af/docs/gettingstarted/structuring.md -std::shared_ptr ReadMCModTOML(QByteArray contents) -{ - std::shared_ptr details = std::make_shared(); - - char errbuf[200]; - // top-level table - toml_table_t* tomlData = toml_parse(contents.data(), errbuf, sizeof(errbuf)); - - if(!tomlData) - { - return nullptr; - } - - // array defined by [[mods]] - toml_array_t* tomlModsArr = toml_array_in(tomlData, "mods"); - // we only really care about the first element, since multiple mods in one file is not supported by us at the moment - toml_table_t* tomlModsTable0 = toml_table_at(tomlModsArr, 0); - - // mandatory properties - always in [[mods]] - toml_datum_t modIdDatum = toml_string_in(tomlModsTable0, "modId"); - if(modIdDatum.ok) - { - details->mod_id = modIdDatum.u.s; - // library says this is required for strings - free(modIdDatum.u.s); - } - toml_datum_t versionDatum = toml_string_in(tomlModsTable0, "version"); - if(versionDatum.ok) - { - details->version = versionDatum.u.s; - free(versionDatum.u.s); - } - toml_datum_t displayNameDatum = toml_string_in(tomlModsTable0, "displayName"); - if(displayNameDatum.ok) - { - details->name = displayNameDatum.u.s; - free(displayNameDatum.u.s); - } - toml_datum_t descriptionDatum = toml_string_in(tomlModsTable0, "description"); - if(descriptionDatum.ok) - { - details->description = descriptionDatum.u.s; - free(descriptionDatum.u.s); - } - - // optional properties - can be in the root table or [[mods]] - toml_datum_t authorsDatum = toml_string_in(tomlData, "authors"); - QString authors = ""; - if(authorsDatum.ok) - { - authors = authorsDatum.u.s; - free(authorsDatum.u.s); - } - else - { - authorsDatum = toml_string_in(tomlModsTable0, "authors"); - if(authorsDatum.ok) - { - authors = authorsDatum.u.s; - free(authorsDatum.u.s); - } - } - if(!authors.isEmpty()) - { - // author information is stored as a string now, not a list - details->authors.append(authors); - } - // is credits even used anywhere? including this for completion/parity with old data version - toml_datum_t creditsDatum = toml_string_in(tomlData, "credits"); - QString credits = ""; - if(creditsDatum.ok) - { - authors = creditsDatum.u.s; - free(creditsDatum.u.s); - } - else - { - creditsDatum = toml_string_in(tomlModsTable0, "credits"); - if(creditsDatum.ok) - { - credits = creditsDatum.u.s; - free(creditsDatum.u.s); - } - } - details->credits = credits; - toml_datum_t homeurlDatum = toml_string_in(tomlData, "displayURL"); - QString homeurl = ""; - if(homeurlDatum.ok) - { - homeurl = homeurlDatum.u.s; - free(homeurlDatum.u.s); - } - else - { - homeurlDatum = toml_string_in(tomlModsTable0, "displayURL"); - if(homeurlDatum.ok) - { - homeurl = homeurlDatum.u.s; - free(homeurlDatum.u.s); - } - } - if(!homeurl.isEmpty()) - { - // fix up url. - if (!homeurl.startsWith("http://") && !homeurl.startsWith("https://") && !homeurl.startsWith("ftp://")) - { - homeurl.prepend("http://"); - } - } - details->homeurl = homeurl; - - // this seems to be recursive, so it should free everything - toml_free(tomlData); - - return details; -} - // https://fabricmc.net/wiki/documentation:fabric_mod_json std::shared_ptr ReadFabricModInfo(QByteArray contents) { @@ -317,57 +198,7 @@ void LocalModParseTask::processAsZip() QuaZipFile file(&zip); - if (zip.setCurrentFile("META-INF/mods.toml")) - { - if (!file.open(QIODevice::ReadOnly)) - { - zip.close(); - return; - } - - m_result->details = ReadMCModTOML(file.readAll()); - file.close(); - - // to replace ${file.jarVersion} with the actual version, as needed - if (m_result->details && m_result->details->version == "${file.jarVersion}") - { - if (zip.setCurrentFile("META-INF/MANIFEST.MF")) - { - if (!file.open(QIODevice::ReadOnly)) - { - zip.close(); - return; - } - - // quick and dirty line-by-line parser - auto manifestLines = file.readAll().split('\n'); - QString manifestVersion = ""; - for (auto &line : manifestLines) - { - if (QString(line).startsWith("Implementation-Version: ")) - { - manifestVersion = QString(line).remove("Implementation-Version: "); - break; - } - } - - // some mods use ${projectversion} in their build.gradle, causing this mess to show up in MANIFEST.MF - // also keep with forge's behavior of setting the version to "NONE" if none is found - if (manifestVersion.contains("task ':jar' property 'archiveVersion'") || manifestVersion == "") - { - manifestVersion = "NONE"; - } - - m_result->details->version = manifestVersion; - - file.close(); - } - } - - zip.close(); - return; - } - else if (zip.setCurrentFile("mcmod.info")) + if (zip.setCurrentFile("mcmod.info")) { if (!file.open(QIODevice::ReadOnly)) { diff --git a/api/logic/minecraft/mod/ResourcePackFolderModel.cpp b/api/logic/minecraft/mod/ResourcePackFolderModel.cpp deleted file mode 100644 index f3d7f566..00000000 --- a/api/logic/minecraft/mod/ResourcePackFolderModel.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "ResourcePackFolderModel.h" - -ResourcePackFolderModel::ResourcePackFolderModel(const QString &dir) : ModFolderModel(dir) { -} - -QVariant ResourcePackFolderModel::headerData(int section, Qt::Orientation orientation, int role) const { - if (role == Qt::ToolTipRole) { - switch (section) { - case ActiveColumn: - return tr("Is the resource pack enabled?"); - case NameColumn: - return tr("The name of the resource pack."); - case VersionColumn: - return tr("The version of the resource pack."); - case DateColumn: - return tr("The date and time this resource pack was last changed (or added)."); - default: - return QVariant(); - } - } - - return ModFolderModel::headerData(section, orientation, role); -} diff --git a/api/logic/minecraft/mod/ResourcePackFolderModel.h b/api/logic/minecraft/mod/ResourcePackFolderModel.h deleted file mode 100644 index 47eb4bb2..00000000 --- a/api/logic/minecraft/mod/ResourcePackFolderModel.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "ModFolderModel.h" - -class MULTIMC_LOGIC_EXPORT ResourcePackFolderModel : public ModFolderModel -{ - Q_OBJECT - -public: - explicit ResourcePackFolderModel(const QString &dir); - - QVariant headerData(int section, Qt::Orientation orientation, int role) const override; -}; diff --git a/api/logic/minecraft/mod/TexturePackFolderModel.cpp b/api/logic/minecraft/mod/TexturePackFolderModel.cpp deleted file mode 100644 index d5956da1..00000000 --- a/api/logic/minecraft/mod/TexturePackFolderModel.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "TexturePackFolderModel.h" - -TexturePackFolderModel::TexturePackFolderModel(const QString &dir) : ModFolderModel(dir) { -} - -QVariant TexturePackFolderModel::headerData(int section, Qt::Orientation orientation, int role) const { - if (role == Qt::ToolTipRole) { - switch (section) { - case ActiveColumn: - return tr("Is the texture pack enabled?"); - case NameColumn: - return tr("The name of the texture pack."); - case VersionColumn: - return tr("The version of the texture pack."); - case DateColumn: - return tr("The date and time this texture pack was last changed (or added)."); - default: - return QVariant(); - } - } - - return ModFolderModel::headerData(section, orientation, role); -} diff --git a/api/logic/minecraft/mod/TexturePackFolderModel.h b/api/logic/minecraft/mod/TexturePackFolderModel.h deleted file mode 100644 index d773b17b..00000000 --- a/api/logic/minecraft/mod/TexturePackFolderModel.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "ModFolderModel.h" - -class MULTIMC_LOGIC_EXPORT TexturePackFolderModel : public ModFolderModel -{ - Q_OBJECT - -public: - explicit TexturePackFolderModel(const QString &dir); - - QVariant headerData(int section, Qt::Orientation orientation, int role) const override; -}; diff --git a/api/logic/modplatform/atlauncher/ATLPackInstallTask.cpp b/api/logic/modplatform/atlauncher/ATLPackInstallTask.cpp index 55087a27..12ceaccd 100644 --- a/api/logic/modplatform/atlauncher/ATLPackInstallTask.cpp +++ b/api/logic/modplatform/atlauncher/ATLPackInstallTask.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include "ATLPackInstallTask.h" #include "BuildConfig.h" @@ -19,20 +18,15 @@ namespace ATLauncher { -PackInstallTask::PackInstallTask(UserInteractionSupport *support, QString pack, QString version) +PackInstallTask::PackInstallTask(QString pack, QString version) { - m_support = support; m_pack = pack; m_version_name = version; } bool PackInstallTask::abort() { - if(abortable) - { - return jobPtr->abort(); - } - return false; + return true; } void PackInstallTask::executeTask() @@ -160,56 +154,23 @@ QString PackInstallTask::getVersionForLoader(QString uid) auto vlist = ENV.metadataIndex()->get(uid); if(!vlist) { - emitFailed(tr("Failed to get local metadata index for %1").arg(uid)); + emitFailed(tr("Failed to get local metadata index for ") + uid); return Q_NULLPTR; } - if(!vlist->isLoaded()) { - vlist->load(Net::Mode::Online); + // todo: filter by Minecraft version + + if(m_version.loader.recommended) { + return vlist.get()->getRecommended().get()->descriptor(); } - - if(m_version.loader.recommended || m_version.loader.latest) { - for (int i = 0; i < vlist->versions().size(); i++) { - auto version = vlist->versions().at(i); - auto reqs = version->requires(); - - // filter by minecraft version, if the loader depends on a certain version. - // not all mod loaders depend on a given Minecraft version, so we won't do this - // filtering for those loaders. - if (m_version.loader.type != "fabric") { - auto iter = std::find_if(reqs.begin(), reqs.end(), [](const Meta::Require &req) { - return req.uid == "net.minecraft"; - }); - if (iter == reqs.end()) continue; - if (iter->equalsVersion != m_version.minecraft) continue; - } - - if (m_version.loader.recommended) { - // first recommended build we find, we use. - if (!version->isRecommended()) continue; - } - - return version->descriptor(); - } - - emitFailed(tr("Failed to find version for %1 loader").arg(m_version.loader.type)); - return Q_NULLPTR; + else if(m_version.loader.latest) { + return vlist.get()->at(0)->descriptor(); } else if(m_version.loader.choose) { - // Fabric Loader doesn't depend on a given Minecraft version. - if (m_version.loader.type == "fabric") { - return m_support->chooseVersion(vlist, Q_NULLPTR); - } - - return m_support->chooseVersion(vlist, m_version.minecraft); + // todo: implement } } - if (m_version.loader.version == Q_NULLPTR || m_version.loader.version.isEmpty()) { - emitFailed(tr("No loader version set for modpack!")); - return Q_NULLPTR; - } - return m_version.loader.version; } @@ -412,29 +373,21 @@ void PackInstallTask::installConfigs() auto entry = ENV.metacache()->resolveEntry("ATLauncherPacks", path); entry->setStale(true); - auto dl = Net::Download::makeCached(url, entry); - if (!m_version.configs.sha1.isEmpty()) { - auto rawSha1 = QByteArray::fromHex(m_version.configs.sha1.toLatin1()); - dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawSha1)); - } - jobPtr->addNetAction(dl); + jobPtr->addNetAction(Net::Download::makeCached(url, entry)); archivePath = entry->getFullPath(); connect(jobPtr.get(), &NetJob::succeeded, this, [&]() { - abortable = false; jobPtr.reset(); extractConfigs(); }); connect(jobPtr.get(), &NetJob::failed, [&](QString reason) { - abortable = false; jobPtr.reset(); emitFailed(reason); }); connect(jobPtr.get(), &NetJob::progress, [&](qint64 current, qint64 total) { - abortable = true; setProgress(current, total); }); @@ -470,31 +423,13 @@ void PackInstallTask::extractConfigs() void PackInstallTask::downloadMods() { qDebug() << "PackInstallTask::installMods: " << QThread::currentThreadId(); - - QVector optionalMods; - for (const auto& mod : m_version.mods) { - if (mod.optional) { - optionalMods.push_back(mod); - } - } - - // Select optional mods, if pack contains any - QVector selectedMods; - if (!optionalMods.isEmpty()) { - setStatus(tr("Selecting optional mods...")); - selectedMods = m_support->chooseOptionalMods(optionalMods); - } - setStatus(tr("Downloading mods...")); jarmods.clear(); jobPtr.reset(new NetJob(tr("Mod download"))); for(const auto& mod : m_version.mods) { - // skip non-client mods - if(!mod.client) continue; - - // skip optional mods that were not selected - if(mod.optional && !selectedMods.contains(mod.name)) continue; + // skip optional mods for now + if(mod.optional) continue; QString url; switch(mod.download) { @@ -516,15 +451,12 @@ void PackInstallTask::downloadMods() auto cacheName = fileName.completeBaseName() + "-" + mod.md5 + "." + fileName.suffix(); if (mod.type == ModType::Extract || mod.type == ModType::TexturePackExtract || mod.type == ModType::ResourcePackExtract) { + auto entry = ENV.metacache()->resolveEntry("ATLauncherPacks", cacheName); entry->setStale(true); modsToExtract.insert(entry->getFullPath(), mod); auto dl = Net::Download::makeCached(url, entry); - if (!mod.md5.isEmpty()) { - auto rawMd5 = QByteArray::fromHex(mod.md5.toLatin1()); - dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Md5, rawMd5)); - } jobPtr->addNetAction(dl); } else if(mod.type == ModType::Decomp) { @@ -533,10 +465,6 @@ void PackInstallTask::downloadMods() modsToDecomp.insert(entry->getFullPath(), mod); auto dl = Net::Download::makeCached(url, entry); - if (!mod.md5.isEmpty()) { - auto rawMd5 = QByteArray::fromHex(mod.md5.toLatin1()); - dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Md5, rawMd5)); - } jobPtr->addNetAction(dl); } else { @@ -547,10 +475,6 @@ void PackInstallTask::downloadMods() entry->setStale(true); auto dl = Net::Download::makeCached(url, entry); - if (!mod.md5.isEmpty()) { - auto rawMd5 = QByteArray::fromHex(mod.md5.toLatin1()); - dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Md5, rawMd5)); - } jobPtr->addNetAction(dl); auto path = FS::PathCombine(m_stagingPath, "minecraft", relpath, mod.file); @@ -583,13 +507,11 @@ void PackInstallTask::downloadMods() connect(jobPtr.get(), &NetJob::succeeded, this, &PackInstallTask::onModsDownloaded); connect(jobPtr.get(), &NetJob::failed, [&](QString reason) { - abortable = false; jobPtr.reset(); emitFailed(reason); }); connect(jobPtr.get(), &NetJob::progress, [&](qint64 current, qint64 total) { - abortable = true; setProgress(current, total); }); @@ -597,12 +519,10 @@ void PackInstallTask::downloadMods() } void PackInstallTask::onModsDownloaded() { - abortable = false; - qDebug() << "PackInstallTask::onModsDownloaded: " << QThread::currentThreadId(); jobPtr.reset(); - if(!modsToExtract.empty() || !modsToDecomp.empty() || !modsToCopy.empty()) { + if(modsToExtract.size() || modsToDecomp.size() || modsToCopy.size()) { m_modExtractFuture = QtConcurrent::run(QThreadPool::globalInstance(), this, &PackInstallTask::extractMods, modsToExtract, modsToDecomp, modsToCopy); connect(&m_modExtractFutureWatcher, &QFutureWatcher::finished, this, &PackInstallTask::onModsExtracted); connect(&m_modExtractFutureWatcher, &QFutureWatcher::canceled, this, [&]() @@ -709,7 +629,6 @@ void PackInstallTask::install() // Use a component to add libraries BEFORE Minecraft if(!createLibrariesComponent(instance.instanceRoot(), components)) { - emitFailed(tr("Failed to create libraries component")); return; } @@ -747,7 +666,6 @@ void PackInstallTask::install() // Use a component to fill in the rest of the data // todo: use more detection if(!createPackComponent(instance.instanceRoot(), components)) { - emitFailed(tr("Failed to create pack component")); return; } diff --git a/api/logic/modplatform/atlauncher/ATLPackInstallTask.h b/api/logic/modplatform/atlauncher/ATLPackInstallTask.h index 15fd9b32..78544bab 100644 --- a/api/logic/modplatform/atlauncher/ATLPackInstallTask.h +++ b/api/logic/modplatform/atlauncher/ATLPackInstallTask.h @@ -15,31 +15,14 @@ namespace ATLauncher { -class MULTIMC_LOGIC_EXPORT UserInteractionSupport { - -public: - /** - * Requests a user interaction to select which optional mods should be installed. - */ - virtual QVector chooseOptionalMods(QVector mods) = 0; - - /** - * Requests a user interaction to select a component version from a given version list - * and constrained to a given Minecraft version. - */ - virtual QString chooseVersion(Meta::VersionListPtr vlist, QString minecraftVersion) = 0; - -}; - class MULTIMC_LOGIC_EXPORT PackInstallTask : public InstanceTask { Q_OBJECT public: - explicit PackInstallTask(UserInteractionSupport *support, QString pack, QString version); + explicit PackInstallTask(QString pack, QString version); virtual ~PackInstallTask(){} - bool canAbort() const override { return true; } bool abort() override; protected: @@ -71,10 +54,6 @@ private: void install(); private: - UserInteractionSupport *m_support; - - bool abortable = false; - NetJobPtr jobPtr; QByteArray response; @@ -97,6 +76,9 @@ private: QFuture m_modExtractFuture; QFutureWatcher m_modExtractFutureWatcher; + QFuture m_decompFuture; + QFutureWatcher m_decompFutureWatcher; + }; } diff --git a/api/logic/modplatform/atlauncher/ATLPackManifest.cpp b/api/logic/modplatform/atlauncher/ATLPackManifest.cpp index e25d8346..84389330 100644 --- a/api/logic/modplatform/atlauncher/ATLPackManifest.cpp +++ b/api/logic/modplatform/atlauncher/ATLPackManifest.cpp @@ -81,21 +81,12 @@ static ATLauncher::ModType parseModType(QString rawType) { static void loadVersionLoader(ATLauncher::VersionLoader & p, QJsonObject & obj) { p.type = Json::requireString(obj, "type"); + p.latest = Json::ensureBoolean(obj, QString("latest"), false); p.choose = Json::ensureBoolean(obj, QString("choose"), false); + p.recommended = Json::ensureBoolean(obj, QString("recommended"), false); auto metadata = Json::requireObject(obj, "metadata"); - p.latest = Json::ensureBoolean(metadata, QString("latest"), false); - p.recommended = Json::ensureBoolean(metadata, QString("recommended"), false); - - // Minecraft Forge - if (p.type == "forge") { - p.version = Json::ensureString(metadata, "version", ""); - } - - // Fabric Loader - if (p.type == "fabric") { - p.version = Json::ensureString(metadata, "loader", ""); - } + p.version = Json::requireString(metadata, "version"); } static void loadVersionLibrary(ATLauncher::VersionLibrary & p, QJsonObject & obj) { @@ -109,11 +100,6 @@ static void loadVersionLibrary(ATLauncher::VersionLibrary & p, QJsonObject & obj p.server = Json::ensureString(obj, "server", ""); } -static void loadVersionConfigs(ATLauncher::VersionConfigs & p, QJsonObject & obj) { - p.filesize = Json::requireInteger(obj, "filesize"); - p.sha1 = Json::requireString(obj, "sha1"); -} - static void loadVersionMod(ATLauncher::VersionMod & p, QJsonObject & obj) { p.name = Json::requireString(obj, "name"); p.version = Json::requireString(obj, "version"); @@ -148,24 +134,7 @@ static void loadVersionMod(ATLauncher::VersionMod & p, QJsonObject & obj) { p.decompFile = Json::requireString(obj, "decompFile"); } - p.description = Json::ensureString(obj, QString("description"), ""); p.optional = Json::ensureBoolean(obj, QString("optional"), false); - p.recommended = Json::ensureBoolean(obj, QString("recommended"), false); - p.selected = Json::ensureBoolean(obj, QString("selected"), false); - p.hidden = Json::ensureBoolean(obj, QString("hidden"), false); - p.library = Json::ensureBoolean(obj, QString("library"), false); - p.group = Json::ensureString(obj, QString("group"), ""); - if(obj.contains("depends")) { - auto dependsArr = Json::requireArray(obj, "depends"); - for (const auto depends : dependsArr) { - p.depends.append(Json::requireString(depends)); - } - } - - p.client = Json::ensureBoolean(obj, QString("client"), false); - - // computed - p.effectively_hidden = p.hidden || p.library; } void ATLauncher::loadVersion(PackVersion & v, QJsonObject & obj) @@ -200,19 +169,12 @@ void ATLauncher::loadVersion(PackVersion & v, QJsonObject & obj) } } - if(obj.contains("mods")) { - auto mods = Json::requireArray(obj, "mods"); - for (const auto modRaw : mods) - { - auto modObj = Json::requireObject(modRaw); - ATLauncher::VersionMod mod; - loadVersionMod(mod, modObj); - v.mods.append(mod); - } - } - - if(obj.contains("configs")) { - auto configsObj = Json::requireObject(obj, "configs"); - loadVersionConfigs(v.configs, configsObj); + auto mods = Json::requireArray(obj, "mods"); + for (const auto modRaw : mods) + { + auto modObj = Json::requireObject(modRaw); + ATLauncher::VersionMod mod; + loadVersionMod(mod, modObj); + v.mods.append(mod); } } diff --git a/api/logic/modplatform/atlauncher/ATLPackManifest.h b/api/logic/modplatform/atlauncher/ATLPackManifest.h index 17821e4c..1adf889b 100644 --- a/api/logic/modplatform/atlauncher/ATLPackManifest.h +++ b/api/logic/modplatform/atlauncher/ATLPackManifest.h @@ -86,25 +86,7 @@ struct VersionMod QString decompType_raw; QString decompFile; - QString description; bool optional; - bool recommended; - bool selected; - bool hidden; - bool library; - QString group; - QVector depends; - - bool client; - - // computed - bool effectively_hidden; -}; - -struct VersionConfigs -{ - int filesize; - QString sha1; }; struct PackVersion @@ -118,7 +100,6 @@ struct PackVersion VersionLoader loader; QVector libraries; QVector mods; - VersionConfigs configs; }; MULTIMC_LOGIC_EXPORT void loadVersion(PackVersion & v, QJsonObject & obj); diff --git a/api/logic/modplatform/legacy_ftb/PackInstallTask.h b/api/logic/modplatform/legacy_ftb/PackInstallTask.h index f3515781..7868d1c4 100644 --- a/api/logic/modplatform/legacy_ftb/PackInstallTask.h +++ b/api/logic/modplatform/legacy_ftb/PackInstallTask.h @@ -20,7 +20,6 @@ public: explicit PackInstallTask(Modpack pack, QString version); virtual ~PackInstallTask(){} - bool canAbort() const override { return true; } bool abort() override; protected: diff --git a/api/logic/modplatform/modpacksch/FTBPackInstallTask.cpp b/api/logic/modplatform/modpacksch/FTBPackInstallTask.cpp index f22373bc..068e3592 100644 --- a/api/logic/modplatform/modpacksch/FTBPackInstallTask.cpp +++ b/api/logic/modplatform/modpacksch/FTBPackInstallTask.cpp @@ -1,12 +1,10 @@ #include "FTBPackInstallTask.h" #include "BuildConfig.h" -#include "Env.h" #include "FileSystem.h" #include "Json.h" #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" -#include "net/ChecksumValidator.h" #include "settings/INISettingsObject.h" namespace ModpacksCH { @@ -19,11 +17,7 @@ PackInstallTask::PackInstallTask(Modpack pack, QString version) bool PackInstallTask::abort() { - if(abortable) - { - return jobPtr->abort(); - } - return false; + return true; } void PackInstallTask::executeTask() @@ -99,41 +93,31 @@ void PackInstallTask::downloadPack() for(auto file : m_version.files) { if(file.serverOnly) continue; - QFileInfo fileName(file.name); - auto cacheName = fileName.completeBaseName() + "-" + file.sha1 + "." + fileName.suffix(); - - auto entry = ENV.metacache()->resolveEntry("ModpacksCHPacks", cacheName); - entry->setStale(true); - auto relpath = FS::PathCombine("minecraft", file.path, file.name); auto path = FS::PathCombine(m_stagingPath, relpath); qDebug() << "Will download" << file.url << "to" << path; - filesToCopy[entry->getFullPath()] = path; - - auto dl = Net::Download::makeCached(file.url, entry); - if (!file.sha1.isEmpty()) { - auto rawSha1 = QByteArray::fromHex(file.sha1.toLatin1()); - dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawSha1)); - } + auto dl = Net::Download::makeFile(file.url, path); jobPtr->addNetAction(dl); } connect(jobPtr.get(), &NetJob::succeeded, this, [&]() { - abortable = false; jobPtr.reset(); install(); }); connect(jobPtr.get(), &NetJob::failed, [&](QString reason) { - abortable = false; jobPtr.reset(); - emitFailed(reason); + + // FIXME: Temporarily ignore file download failures (matching FTB's installer), + // while FTB's data is fucked. + qWarning() << "Failed to download files for modpack: " + reason; + + install(); }); connect(jobPtr.get(), &NetJob::progress, [&](qint64 current, qint64 total) { - abortable = true; setProgress(current, total); }); @@ -142,19 +126,6 @@ void PackInstallTask::downloadPack() void PackInstallTask::install() { - setStatus(tr("Copying modpack files")); - - for (auto iter = filesToCopy.begin(); iter != filesToCopy.end(); iter++) { - auto &from = iter.key(); - auto &to = iter.value(); - FS::copy fileCopyOperation(from, to); - if(!fileCopyOperation()) { - qWarning() << "Failed to copy" << from << "to" << to; - emitFailed(tr("Failed to copy files")); - return; - } - } - setStatus(tr("Installing modpack")); auto instanceConfigPath = FS::PathCombine(m_stagingPath, "instance.cfg"); diff --git a/api/logic/modplatform/modpacksch/FTBPackInstallTask.h b/api/logic/modplatform/modpacksch/FTBPackInstallTask.h index 55db3d3c..4f7786fd 100644 --- a/api/logic/modplatform/modpacksch/FTBPackInstallTask.h +++ b/api/logic/modplatform/modpacksch/FTBPackInstallTask.h @@ -16,7 +16,6 @@ public: explicit PackInstallTask(Modpack pack, QString version); virtual ~PackInstallTask(){} - bool canAbort() const override { return true; } bool abort() override; protected: @@ -31,8 +30,6 @@ private: void install(); private: - bool abortable = false; - NetJobPtr jobPtr; QByteArray response; @@ -40,8 +37,6 @@ private: QString m_version_name; Version m_version; - QMap filesToCopy; - }; } diff --git a/api/logic/modplatform/technic/SingleZipPackInstallTask.cpp b/api/logic/modplatform/technic/SingleZipPackInstallTask.cpp index dbce8e53..96e1804d 100644 --- a/api/logic/modplatform/technic/SingleZipPackInstallTask.cpp +++ b/api/logic/modplatform/technic/SingleZipPackInstallTask.cpp @@ -28,14 +28,6 @@ Technic::SingleZipPackInstallTask::SingleZipPackInstallTask(const QUrl &sourceUr m_minecraftVersion = minecraftVersion; } -bool Technic::SingleZipPackInstallTask::abort() { - if(m_abortable) - { - return m_filesNetJob->abort(); - } - return false; -} - void Technic::SingleZipPackInstallTask::executeTask() { setStatus(tr("Downloading modpack:\n%1").arg(m_sourceUrl.toString())); @@ -55,8 +47,6 @@ void Technic::SingleZipPackInstallTask::executeTask() void Technic::SingleZipPackInstallTask::downloadSucceeded() { - m_abortable = false; - setStatus(tr("Extracting modpack")); QDir extractDir(FS::PathCombine(m_stagingPath, ".minecraft")); qDebug() << "Attempting to create instance from" << m_archivePath; @@ -77,14 +67,12 @@ void Technic::SingleZipPackInstallTask::downloadSucceeded() void Technic::SingleZipPackInstallTask::downloadFailed(QString reason) { - m_abortable = false; emitFailed(reason); m_filesNetJob.reset(); } void Technic::SingleZipPackInstallTask::downloadProgressChanged(qint64 current, qint64 total) { - m_abortable = true; setProgress(current / 2, total); } diff --git a/api/logic/modplatform/technic/SingleZipPackInstallTask.h b/api/logic/modplatform/technic/SingleZipPackInstallTask.h index ec2ff605..c56b9e46 100644 --- a/api/logic/modplatform/technic/SingleZipPackInstallTask.h +++ b/api/logic/modplatform/technic/SingleZipPackInstallTask.h @@ -36,9 +36,6 @@ class MULTIMC_LOGIC_EXPORT SingleZipPackInstallTask : public InstanceTask public: SingleZipPackInstallTask(const QUrl &sourceUrl, const QString &minecraftVersion); - bool canAbort() const override { return true; } - bool abort() override; - protected: void executeTask() override; @@ -51,8 +48,6 @@ private slots: void extractAborted(); private: - bool m_abortable = false; - QUrl m_sourceUrl; QString m_minecraftVersion; QString m_archivePath; diff --git a/api/logic/modplatform/technic/SolderPackInstallTask.cpp b/api/logic/modplatform/technic/SolderPackInstallTask.cpp index 1b4186d4..1d17073c 100644 --- a/api/logic/modplatform/technic/SolderPackInstallTask.cpp +++ b/api/logic/modplatform/technic/SolderPackInstallTask.cpp @@ -27,14 +27,6 @@ Technic::SolderPackInstallTask::SolderPackInstallTask(const QUrl &sourceUrl, con m_minecraftVersion = minecraftVersion; } -bool Technic::SolderPackInstallTask::abort() { - if(m_abortable) - { - return m_filesNetJob->abort(); - } - return false; -} - void Technic::SolderPackInstallTask::executeTask() { setStatus(tr("Finding recommended version:\n%1").arg(m_sourceUrl.toString())); @@ -114,8 +106,6 @@ void Technic::SolderPackInstallTask::fileListSucceeded() void Technic::SolderPackInstallTask::downloadSucceeded() { - m_abortable = false; - setStatus(tr("Extracting modpack")); m_filesNetJob.reset(); m_extractFuture = QtConcurrent::run([this]() @@ -142,14 +132,12 @@ void Technic::SolderPackInstallTask::downloadSucceeded() void Technic::SolderPackInstallTask::downloadFailed(QString reason) { - m_abortable = false; emitFailed(reason); m_filesNetJob.reset(); } void Technic::SolderPackInstallTask::downloadProgressChanged(qint64 current, qint64 total) { - m_abortable = true; setProgress(current / 2, total); } diff --git a/api/logic/modplatform/technic/SolderPackInstallTask.h b/api/logic/modplatform/technic/SolderPackInstallTask.h index 9f0f20a9..0fe6cb83 100644 --- a/api/logic/modplatform/technic/SolderPackInstallTask.h +++ b/api/logic/modplatform/technic/SolderPackInstallTask.h @@ -29,9 +29,6 @@ namespace Technic public: explicit SolderPackInstallTask(const QUrl &sourceUrl, const QString &minecraftVersion); - bool canAbort() const override { return true; } - bool abort() override; - protected: //! Entry point for tasks. virtual void executeTask() override; @@ -46,8 +43,6 @@ namespace Technic void extractAborted(); private: - bool m_abortable = false; - NetJobPtr m_filesNetJob; QUrl m_sourceUrl; QString m_minecraftVersion; diff --git a/application/CMakeLists.txt b/application/CMakeLists.txt index ab2b9960..c5be22d0 100644 --- a/application/CMakeLists.txt +++ b/application/CMakeLists.txt @@ -129,8 +129,6 @@ SET(MULTIMC_SOURCES pages/modplatform/atlauncher/AtlFilterModel.h pages/modplatform/atlauncher/AtlListModel.cpp pages/modplatform/atlauncher/AtlListModel.h - pages/modplatform/atlauncher/AtlOptionalModDialog.cpp - pages/modplatform/atlauncher/AtlOptionalModDialog.h pages/modplatform/atlauncher/AtlPage.cpp pages/modplatform/atlauncher/AtlPage.h @@ -280,9 +278,6 @@ SET(MULTIMC_UIS pages/modplatform/technic/TechnicPage.ui pages/modplatform/ImportPage.ui - # Platform Dialogs - pages/modplatform/atlauncher/AtlOptionalModDialog.ui - # Dialogs dialogs/CopyInstanceDialog.ui dialogs/NewComponentDialog.ui diff --git a/application/InstancePageProvider.h b/application/InstancePageProvider.h index 3cb723c4..dde36aef 100644 --- a/application/InstancePageProvider.h +++ b/application/InstancePageProvider.h @@ -46,7 +46,7 @@ public: values.append(new TexturePackPage(onesix.get())); values.append(new NotesPage(onesix.get())); values.append(new WorldListPage(onesix.get(), onesix->worldList())); - values.append(new ServersPage(onesix)); + values.append(new ServersPage(onesix.get())); // values.append(new GameOptionsPage(onesix.get())); values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots"))); values.append(new InstanceSettingsPage(onesix.get())); diff --git a/application/LaunchController.cpp b/application/LaunchController.cpp index de587d61..c5f201c3 100644 --- a/application/LaunchController.cpp +++ b/application/LaunchController.cpp @@ -15,9 +15,6 @@ #include #include #include -#include -#include -#include LaunchController::LaunchController(QObject *parent) : Task(parent) { @@ -295,46 +292,7 @@ void LaunchController::launchInstance() connect(m_launcher.get(), &LaunchTask::failed, this, &LaunchController::onFailed); connect(m_launcher.get(), &LaunchTask::requestProgress, this, &LaunchController::onProgressRequested); - // Prepend Online and Auth Status - QString online_mode; - if(m_session->wants_online) { - online_mode = "online"; - // Prepend Server Status - QStringList servers = {"authserver.mojang.com", "session.minecraft.net", "textures.minecraft.net", "api.mojang.com"}; - QString resolved_servers = ""; - QHostInfo host_info; - - for(QString server : servers) { - host_info = QHostInfo::fromName(server); - resolved_servers = resolved_servers + server + " resolves to:\n ["; - if(!host_info.addresses().isEmpty()) { - for(QHostAddress address : host_info.addresses()) { - resolved_servers = resolved_servers + address.toString(); - if(!host_info.addresses().endsWith(address)) { - resolved_servers = resolved_servers + ", "; - } - } - } else { - resolved_servers = resolved_servers + "N/A"; - } - resolved_servers = resolved_servers + "]\n\n"; - } - m_launcher->prependStep(new TextPrint(m_launcher.get(), resolved_servers, MessageLevel::MultiMC)); - } else { - online_mode = "offline"; - } - - QString auth_server_status; - if(m_session->auth_server_online) { - auth_server_status = "online"; - } else { - auth_server_status = "offline"; - } - - m_launcher->prependStep(new TextPrint(m_launcher.get(), "Launched instance in " + online_mode + " mode\nAuthentication server is " + auth_server_status + "\n", MessageLevel::MultiMC)); - - // Prepend Version m_launcher->prependStep(new TextPrint(m_launcher.get(), "MultiMC version: " + BuildConfig.printableVersionString() + "\n\n", MessageLevel::MultiMC)); m_launcher->start(); } diff --git a/application/MainWindow.cpp b/application/MainWindow.cpp index 605a2844..d97be1a6 100644 --- a/application/MainWindow.cpp +++ b/application/MainWindow.cpp @@ -306,35 +306,29 @@ public: helpMenu = new QMenu(MainWindow); helpMenu->setToolTipsVisible(true); - if (!BuildConfig.BUG_TRACKER_URL.isEmpty()) { - actionReportBug = TranslatedAction(MainWindow); - actionReportBug->setObjectName(QStringLiteral("actionReportBug")); - actionReportBug->setIcon(MMC->getThemedIcon("bug")); - actionReportBug.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Report a Bug")); - actionReportBug.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the bug tracker to report a bug with MultiMC.")); - all_actions.append(&actionReportBug); - helpMenu->addAction(actionReportBug); - } + actionReportBug = TranslatedAction(MainWindow); + actionReportBug->setObjectName(QStringLiteral("actionReportBug")); + actionReportBug->setIcon(MMC->getThemedIcon("bug")); + actionReportBug.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Report a Bug")); + actionReportBug.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the bug tracker to report a bug with MultiMC.")); + all_actions.append(&actionReportBug); + helpMenu->addAction(actionReportBug); - if (!BuildConfig.DISCORD_URL.isEmpty()) { - actionDISCORD = TranslatedAction(MainWindow); - actionDISCORD->setObjectName(QStringLiteral("actionDISCORD")); - actionDISCORD->setIcon(MMC->getThemedIcon("discord")); - actionDISCORD.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Discord")); - actionDISCORD.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open MultiMC discord voice chat.")); - all_actions.append(&actionDISCORD); - helpMenu->addAction(actionDISCORD); - } + actionDISCORD = TranslatedAction(MainWindow); + actionDISCORD->setObjectName(QStringLiteral("actionDISCORD")); + actionDISCORD->setIcon(MMC->getThemedIcon("discord")); + actionDISCORD.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Discord")); + actionDISCORD.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open MultiMC discord voice chat.")); + all_actions.append(&actionDISCORD); + helpMenu->addAction(actionDISCORD); - if (!BuildConfig.SUBREDDIT_URL.isEmpty()) { - actionREDDIT = TranslatedAction(MainWindow); - actionREDDIT->setObjectName(QStringLiteral("actionREDDIT")); - actionREDDIT->setIcon(MMC->getThemedIcon("reddit-alien")); - actionREDDIT.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Reddit")); - actionREDDIT.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open MultiMC subreddit.")); - all_actions.append(&actionREDDIT); - helpMenu->addAction(actionREDDIT); - } + actionREDDIT = TranslatedAction(MainWindow); + actionREDDIT->setObjectName(QStringLiteral("actionREDDIT")); + actionREDDIT->setIcon(MMC->getThemedIcon("reddit-alien")); + actionREDDIT.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Reddit")); + actionREDDIT.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open MultiMC subreddit.")); + all_actions.append(&actionREDDIT); + helpMenu->addAction(actionREDDIT); actionAbout = TranslatedAction(MainWindow); actionAbout->setObjectName(QStringLiteral("actionAbout")); @@ -738,6 +732,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow repopulateAccountsMenu(); accountMenuButton = new QToolButton(this); + accountMenuButton->setText(tr("Profiles")); accountMenuButton->setMenu(accountMenu); accountMenuButton->setPopupMode(QToolButton::InstantPopup); accountMenuButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); @@ -836,21 +831,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow // removing this looks stupid view->setFocus(); - - retranslateUi(); -} - -void MainWindow::retranslateUi() -{ - accountMenuButton->setText(tr("Profiles")); - - if (m_selectedInstance) { - m_statusLeft->setText(m_selectedInstance->getStatusbarDescription()); - } else { - m_statusLeft->setText(tr("No instance selected")); - } - - ui->retranslateUi(this); } MainWindow::~MainWindow() @@ -1474,12 +1454,12 @@ void MainWindow::droppedURLs(QList urls) void MainWindow::on_actionREDDIT_triggered() { - DesktopServices::openUrl(QUrl(BuildConfig.SUBREDDIT_URL)); + DesktopServices::openUrl(QUrl("https://www.reddit.com/r/MultiMC/")); } void MainWindow::on_actionDISCORD_triggered() { - DesktopServices::openUrl(QUrl(BuildConfig.DISCORD_URL)); + DesktopServices::openUrl(QUrl("https://discord.gg/multimc")); } void MainWindow::on_actionChangeInstIcon_triggered() @@ -1657,7 +1637,7 @@ void MainWindow::on_actionManageAccounts_triggered() void MainWindow::on_actionReportBug_triggered() { - DesktopServices::openUrl(QUrl(BuildConfig.BUG_TRACKER_URL)); + DesktopServices::openUrl(QUrl("https://github.com/MultiMC/MultiMC5/issues")); } void MainWindow::on_actionPatreon_triggered() @@ -1764,7 +1744,7 @@ void MainWindow::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { - retranslateUi(); + ui->retranslateUi(this); } QMainWindow::changeEvent(event); } diff --git a/application/MainWindow.h b/application/MainWindow.h index 1aa6448b..f8f8fc03 100644 --- a/application/MainWindow.h +++ b/application/MainWindow.h @@ -187,8 +187,6 @@ private slots: void globalSettingsClosed(); private: - void retranslateUi(); - void addInstance(QString url = QString()); void activateInstance(InstancePtr instance); void setCatBackground(bool enabled); diff --git a/application/MultiMC.cpp b/application/MultiMC.cpp index 7c737c43..86639188 100644 --- a/application/MultiMC.cpp +++ b/application/MultiMC.cpp @@ -193,11 +193,6 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv) parser.addOption("launch"); parser.addShortOpt("launch", 'l'); parser.addDocumentation("launch", "Launch the specified instance (by instance ID)"); - // --server - parser.addOption("server"); - parser.addShortOpt("server", 's'); - parser.addDocumentation("server", "Join the specified server on launch " - "(only valid in combination with --launch)"); // --alive parser.addSwitch("alive"); parser.addDocumentation("alive", "Write a small '" + liveCheckFile + "' file after MultiMC starts"); @@ -239,7 +234,6 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv) } } m_instanceIdToLaunch = args["launch"].toString(); - m_serverToJoin = args["server"].toString(); m_liveCheck = args["alive"].toBool(); m_zipToImport = args["import"].toUrl(); @@ -301,13 +295,6 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv) return; } - if(m_instanceIdToLaunch.isEmpty() && !m_serverToJoin.isEmpty()) - { - std::cerr << "--server can only be used in combination with --launch!" << std::endl; - m_status = MultiMC::Failed; - return; - } - /* * Establish the mechanism for communication with an already running MultiMC that uses the same data path. * If there is one, tell it what the user actually wanted to do and exit. @@ -333,15 +320,7 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv) } else { - if(!m_serverToJoin.isEmpty()) - { - m_peerInstance->sendMessage( - "launch-with-server " + m_instanceIdToLaunch + " " + m_serverToJoin, timeout); - } - else - { - m_peerInstance->sendMessage("launch " + m_instanceIdToLaunch, timeout); - } + m_peerInstance->sendMessage("launch " + m_instanceIdToLaunch, timeout); } m_status = MultiMC::Succeeded; return; @@ -422,10 +401,6 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv) { qDebug() << "ID of instance to launch : " << m_instanceIdToLaunch; } - if(!m_serverToJoin.isEmpty()) - { - qDebug() << "Address of server to join :" << m_serverToJoin; - } qDebug() << "<> Paths set."; } @@ -541,10 +516,6 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv) m_settings->registerSetting("UseNativeOpenAL", false); m_settings->registerSetting("UseNativeGLFW", false); - // Game time - m_settings->registerSetting("ShowGameTime", true); - m_settings->registerSetting("RecordGameTime", true); - // Minecraft launch method m_settings->registerSetting("MCLaunchMethod", "LauncherPart"); @@ -881,19 +852,8 @@ void MultiMC::performMainStartupAction() auto inst = instances()->getInstanceById(m_instanceIdToLaunch); if(inst) { - MinecraftServerTargetPtr serverToJoin = nullptr; - - if(!m_serverToJoin.isEmpty()) - { - serverToJoin.reset(new MinecraftServerTarget(MinecraftServerTarget::parse(m_serverToJoin))); - qDebug() << "<> Instance" << m_instanceIdToLaunch << "launching with server" << m_serverToJoin; - } - else - { - qDebug() << "<> Instance" << m_instanceIdToLaunch << "launching"; - } - - launch(inst, true, nullptr, serverToJoin); + qDebug() << "<> Instance launching:" << m_instanceIdToLaunch; + launch(inst, true, nullptr); return; } } @@ -975,31 +935,6 @@ void MultiMC::messageReceived(const QString& message) launch(inst, true, nullptr); } } - else if(command == "launch-with-server") - { - QString instanceID = message.section(' ', 1, 1); - QString serverToJoin = message.section(' ', 2, 2); - if(instanceID.isEmpty()) - { - qWarning() << "Received" << command << "message without an instance ID."; - return; - } - if(serverToJoin.isEmpty()) - { - qWarning() << "Received" << command << "message without a server to join."; - return; - } - auto inst = instances()->getInstanceById(instanceID); - if(inst) - { - launch( - inst, - true, - nullptr, - std::make_shared(MinecraftServerTarget::parse(serverToJoin)) - ); - } - } else { qWarning() << "Received invalid message" << message; @@ -1087,12 +1022,8 @@ bool MultiMC::openJsonEditor(const QString &filename) } } -bool MultiMC::launch( - InstancePtr instance, - bool online, - BaseProfilerFactory *profiler, - MinecraftServerTargetPtr serverToJoin -) { +bool MultiMC::launch(InstancePtr instance, bool online, BaseProfilerFactory *profiler) +{ if(m_updateRunning) { qDebug() << "Cannot launch instances while an update is running. Please try again when updates are completed."; diff --git a/application/MultiMC.h b/application/MultiMC.h index 01f763ab..61a5c934 100644 --- a/application/MultiMC.h +++ b/application/MultiMC.h @@ -11,8 +11,6 @@ #include -#include "minecraft/launch/MinecraftServerTarget.h" - class LaunchController; class LocalPeer; class InstanceWindow; @@ -153,12 +151,7 @@ signals: void globalSettingsClosed(); public slots: - bool launch( - InstancePtr instance, - bool online = true, - BaseProfilerFactory *profiler = nullptr, - MinecraftServerTargetPtr serverToJoin = nullptr - ); + bool launch(InstancePtr instance, bool online = true, BaseProfilerFactory *profiler = nullptr); bool kill(InstancePtr instance); private slots: @@ -230,7 +223,6 @@ private: SetupWizard * m_setupWizard = nullptr; public: QString m_instanceIdToLaunch; - QString m_serverToJoin; bool m_liveCheck = false; QUrl m_zipToImport; std::unique_ptr logFile; diff --git a/application/dialogs/LoginDialog.ui b/application/dialogs/LoginDialog.ui index eac19a7e..95287e72 100644 --- a/application/dialogs/LoginDialog.ui +++ b/application/dialogs/LoginDialog.ui @@ -20,16 +20,6 @@ Add Account - - - - NOTICE: MultiMC does not currently support Microsoft accounts. This means that accounts created from December 2020 onwards cannot be used. - - - true - - - diff --git a/application/dialogs/NewInstanceDialog.cpp b/application/dialogs/NewInstanceDialog.cpp index 86963149..112e46ff 100644 --- a/application/dialogs/NewInstanceDialog.cpp +++ b/application/dialogs/NewInstanceDialog.cpp @@ -173,14 +173,6 @@ void NewInstanceDialog::setSuggestedIconFromFile(const QString &path, const QStr ui->iconButton->setIcon(QIcon(path)); } -void NewInstanceDialog::setSuggestedIcon(const QString &key) -{ - auto icon = MMC->icons()->getIcon(key); - importIcon = false; - - ui->iconButton->setIcon(icon); -} - InstanceTask * NewInstanceDialog::extractTask() { InstanceTask * extracted = creationTask.get(); diff --git a/application/dialogs/NewInstanceDialog.h b/application/dialogs/NewInstanceDialog.h index 53abf8cf..f8d96dbf 100644 --- a/application/dialogs/NewInstanceDialog.h +++ b/application/dialogs/NewInstanceDialog.h @@ -43,7 +43,6 @@ public: void setSuggestedPack(const QString & name = QString(), InstanceTask * task = nullptr); void setSuggestedIconFromFile(const QString &path, const QString &name); - void setSuggestedIcon(const QString &key); InstanceTask * extractTask(); diff --git a/application/pages/global/JavaPage.cpp b/application/pages/global/JavaPage.cpp index cde0e035..95271c91 100644 --- a/application/pages/global/JavaPage.cpp +++ b/application/pages/global/JavaPage.cpp @@ -37,8 +37,8 @@ JavaPage::JavaPage(QWidget *parent) : QWidget(parent), ui(new Ui::JavaPage) ui->setupUi(this); ui->tabWidget->tabBar()->hide(); - auto sysMiB = Sys::getSystemRam() / Sys::mebibyte; - ui->maxMemSpinBox->setMaximum(sysMiB); + auto sysMB = Sys::getSystemRam() / Sys::megabyte; + ui->maxMemSpinBox->setMaximum(sysMB); loadSettings(); } diff --git a/application/pages/global/JavaPage.ui b/application/pages/global/JavaPage.ui index b67e9994..201b310c 100644 --- a/application/pages/global/JavaPage.ui +++ b/application/pages/global/JavaPage.ui @@ -51,7 +51,7 @@ The maximum amount of memory Minecraft is allowed to use. - MiB + MB 128 @@ -87,7 +87,7 @@ The amount of memory Minecraft is started with. - MiB + MB 128 @@ -116,7 +116,7 @@ The amount of memory available to store loaded Java classes. - MiB + MB 64 diff --git a/application/pages/global/MinecraftPage.cpp b/application/pages/global/MinecraftPage.cpp index 6c9bd307..6a780fb4 100644 --- a/application/pages/global/MinecraftPage.cpp +++ b/application/pages/global/MinecraftPage.cpp @@ -67,10 +67,6 @@ void MinecraftPage::applySettings() // Native library workarounds s->set("UseNativeOpenAL", ui->useNativeOpenALCheck->isChecked()); s->set("UseNativeGLFW", ui->useNativeGLFWCheck->isChecked()); - - // Game time - s->set("ShowGameTime", ui->showGameTime->isChecked()); - s->set("RecordGameTime", ui->recordGameTime->isChecked()); } void MinecraftPage::loadSettings() @@ -84,7 +80,4 @@ void MinecraftPage::loadSettings() ui->useNativeOpenALCheck->setChecked(s->get("UseNativeOpenAL").toBool()); ui->useNativeGLFWCheck->setChecked(s->get("UseNativeGLFW").toBool()); - - ui->showGameTime->setChecked(s->get("ShowGameTime").toBool()); - ui->recordGameTime->setChecked(s->get("RecordGameTime").toBool()); } diff --git a/application/pages/global/MinecraftPage.ui b/application/pages/global/MinecraftPage.ui index 2abd4bd4..c096c969 100644 --- a/application/pages/global/MinecraftPage.ui +++ b/application/pages/global/MinecraftPage.ui @@ -134,29 +134,6 @@ - - - - Game time - - - - - - Show time spent playing instances - - - - - - - Record time spent playing instances - - - - - - diff --git a/application/pages/instance/InstanceSettingsPage.cpp b/application/pages/instance/InstanceSettingsPage.cpp index 7bd424c0..9a39b034 100644 --- a/application/pages/instance/InstanceSettingsPage.cpp +++ b/application/pages/instance/InstanceSettingsPage.cpp @@ -19,7 +19,7 @@ InstanceSettingsPage::InstanceSettingsPage(BaseInstance *inst, QWidget *parent) { m_settings = inst->settings(); ui->setupUi(this); - auto sysMB = Sys::getSystemRam() / Sys::mebibyte; + auto sysMB = Sys::getSystemRam() / Sys::megabyte; ui->maxMemSpinBox->setMaximum(sysMB); connect(ui->openGlobalJavaSettingsButton, &QCommandLinkButton::clicked, this, &InstanceSettingsPage::globalSettingsButtonClicked); connect(MMC, &MultiMC::globalSettingsAboutToOpen, this, &InstanceSettingsPage::applySettings); @@ -177,32 +177,6 @@ void InstanceSettingsPage::applySettings() m_settings->reset("UseNativeOpenAL"); m_settings->reset("UseNativeGLFW"); } - - // Game time - bool gameTime = ui->gameTimeGroupBox->isChecked(); - m_settings->set("OverrideGameTime", gameTime); - if (gameTime) - { - m_settings->set("ShowGameTime", ui->showGameTime->isChecked()); - m_settings->set("RecordGameTime", ui->recordGameTime->isChecked()); - } - else - { - m_settings->reset("ShowGameTime"); - m_settings->reset("RecordGameTime"); - } - - // Join server on launch - bool joinServerOnLaunch = ui->serverJoinGroupBox->isChecked(); - m_settings->set("JoinServerOnLaunch", joinServerOnLaunch); - if (joinServerOnLaunch) - { - m_settings->set("JoinServerOnLaunchAddress", ui->serverJoinAddress->text()); - } - else - { - m_settings->reset("JoinServerOnLaunchAddress"); - } } void InstanceSettingsPage::loadSettings() @@ -264,14 +238,6 @@ void InstanceSettingsPage::loadSettings() ui->nativeWorkaroundsGroupBox->setChecked(m_settings->get("OverrideNativeWorkarounds").toBool()); ui->useNativeGLFWCheck->setChecked(m_settings->get("UseNativeGLFW").toBool()); ui->useNativeOpenALCheck->setChecked(m_settings->get("UseNativeOpenAL").toBool()); - - // Miscellanous - ui->gameTimeGroupBox->setChecked(m_settings->get("OverrideGameTime").toBool()); - ui->showGameTime->setChecked(m_settings->get("ShowGameTime").toBool()); - ui->recordGameTime->setChecked(m_settings->get("RecordGameTime").toBool()); - - ui->serverJoinGroupBox->setChecked(m_settings->get("JoinServerOnLaunch").toBool()); - ui->serverJoinAddress->setText(m_settings->get("JoinServerOnLaunchAddress").toString()); } void InstanceSettingsPage::on_javaDetectBtn_clicked() diff --git a/application/pages/instance/InstanceSettingsPage.ui b/application/pages/instance/InstanceSettingsPage.ui index e569ce56..c91570c6 100644 --- a/application/pages/instance/InstanceSettingsPage.ui +++ b/application/pages/instance/InstanceSettingsPage.ui @@ -116,7 +116,7 @@ The maximum amount of memory Minecraft is allowed to use. - MiB + MB 128 @@ -138,7 +138,7 @@ The amount of memory Minecraft is started with. - MiB + MB 128 @@ -160,7 +160,7 @@ The amount of memory available to store loaded Java classes. - MiB + MB 64 @@ -416,93 +416,6 @@ - - - Miscellanous - - - - - - true - - - Override global game time settings - - - true - - - false - - - - - - Show time spent playing this instance - - - - - - - Record time spent playing this instance - - - - - - - - - - Set a server to join on launch - - - true - - - false - - - - - - - - - 0 - 0 - - - - Server address: - - - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - @@ -540,8 +453,6 @@ nativeWorkaroundsGroupBox useNativeGLFWCheck useNativeOpenALCheck - showGameTime - recordGameTime diff --git a/application/pages/instance/LogPage.cpp b/application/pages/instance/LogPage.cpp index 3d2085c6..94ada424 100644 --- a/application/pages/instance/LogPage.cpp +++ b/application/pages/instance/LogPage.cpp @@ -236,15 +236,15 @@ void LogPage::on_btnPaste_clicked() return; //FIXME: turn this into a proper task and move the upload logic out of GuiUtil! - m_model->append(MessageLevel::MultiMC, QString("MultiMC: Log upload triggered at: %1").arg(QDateTime::currentDateTime().toString(Qt::RFC2822Date))); + m_model->append(MessageLevel::MultiMC, tr("MultiMC: Log upload triggered at: %1").arg(QDateTime::currentDateTime().toString(Qt::RFC2822Date))); auto url = GuiUtil::uploadPaste(m_model->toPlainText(), this); if(!url.isEmpty()) { - m_model->append(MessageLevel::MultiMC, QString("MultiMC: Log uploaded to: %1").arg(url)); + m_model->append(MessageLevel::MultiMC, tr("MultiMC: Log uploaded to: %1").arg(url)); } else { - m_model->append(MessageLevel::Error, "MultiMC: Log upload failed!"); + m_model->append(MessageLevel::Error, tr("MultiMC: Log upload failed!")); } } diff --git a/application/pages/instance/ModFolderPage.cpp b/application/pages/instance/ModFolderPage.cpp index 98f20e77..c3d6483a 100644 --- a/application/pages/instance/ModFolderPage.cpp +++ b/application/pages/instance/ModFolderPage.cpp @@ -163,7 +163,7 @@ ModFolderPage::ModFolderPage( auto smodel = ui->modTreeView->selectionModel(); connect(smodel, &QItemSelectionModel::currentChanged, this, &ModFolderPage::modCurrent); - connect(ui->filterEdit, &QLineEdit::textChanged, this, &ModFolderPage::on_filterTextChanged); + connect(ui->filterEdit, &QLineEdit::textChanged, this, &ModFolderPage::on_filterTextChanged ); connect(m_inst, &BaseInstance::runningStatusChanged, this, &ModFolderPage::on_RunningState_changed); } diff --git a/application/pages/instance/ResourcePackPage.h b/application/pages/instance/ResourcePackPage.h index 1486bf52..e11c78a3 100644 --- a/application/pages/instance/ResourcePackPage.h +++ b/application/pages/instance/ResourcePackPage.h @@ -1,5 +1,4 @@ #pragma once - #include "ModFolderPage.h" #include "ui_ModFolderPage.h" @@ -13,8 +12,8 @@ public: { ui->actionView_configs->setVisible(false); } - virtual ~ResourcePackPage() {} + virtual ~ResourcePackPage() {} virtual bool shouldDisplay() const override { return !m_inst->traits().contains("no-texturepacks") && diff --git a/application/pages/instance/ServersPage.cpp b/application/pages/instance/ServersPage.cpp index d63c6e70..8b0c655c 100644 --- a/application/pages/instance/ServersPage.cpp +++ b/application/pages/instance/ServersPage.cpp @@ -556,7 +556,7 @@ private: QTimer m_saveTimer; }; -ServersPage::ServersPage(InstancePtr inst, QWidget* parent) +ServersPage::ServersPage(MinecraftInstance * inst, QWidget* parent) : QMainWindow(parent), ui(new Ui::ServersPage) { ui->setupUi(this); @@ -579,7 +579,7 @@ ServersPage::ServersPage(InstancePtr inst, QWidget* parent) auto selectionModel = ui->serversView->selectionModel(); connect(selectionModel, &QItemSelectionModel::currentChanged, this, &ServersPage::currentChanged); - connect(m_inst.get(), &MinecraftInstance::runningStatusChanged, this, &ServersPage::on_RunningState_changed); + connect(m_inst, &MinecraftInstance::runningStatusChanged, this, &ServersPage::on_RunningState_changed); connect(ui->nameLine, &QLineEdit::textEdited, this, &ServersPage::nameEdited); connect(ui->addressLine, &QLineEdit::textEdited, this, &ServersPage::addressEdited); connect(ui->resourceComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(resourceIndexChanged(int))); @@ -695,7 +695,6 @@ void ServersPage::updateState() ui->actionMove_Down->setEnabled(serverEditEnabled); ui->actionMove_Up->setEnabled(serverEditEnabled); ui->actionRemove->setEnabled(serverEditEnabled); - ui->actionJoin->setEnabled(serverEditEnabled); if(server) { @@ -759,10 +758,4 @@ void ServersPage::on_actionMove_Down_triggered() } } -void ServersPage::on_actionJoin_triggered() -{ - const auto &address = m_model->at(currentServer)->m_address; - MMC->launch(m_inst, true, nullptr, std::make_shared(MinecraftServerTarget::parse(address))); -} - #include "ServersPage.moc" diff --git a/application/pages/instance/ServersPage.h b/application/pages/instance/ServersPage.h index 8c5b7eb8..f164da1e 100644 --- a/application/pages/instance/ServersPage.h +++ b/application/pages/instance/ServersPage.h @@ -35,7 +35,7 @@ class ServersPage : public QMainWindow, public BasePage Q_OBJECT public: - explicit ServersPage(InstancePtr inst, QWidget *parent = 0); + explicit ServersPage(MinecraftInstance *inst, QWidget *parent = 0); virtual ~ServersPage(); void openedImpl() override; @@ -74,7 +74,6 @@ private slots: void on_actionRemove_triggered(); void on_actionMove_Up_triggered(); void on_actionMove_Down_triggered(); - void on_actionJoin_triggered(); void on_RunningState_changed(bool running); @@ -89,6 +88,6 @@ private: // data bool m_locked = true; Ui::ServersPage *ui = nullptr; ServersModel * m_model = nullptr; - InstancePtr m_inst = nullptr; + MinecraftInstance * m_inst = nullptr; }; diff --git a/application/pages/instance/ServersPage.ui b/application/pages/instance/ServersPage.ui index d89b7cba..e9518e35 100644 --- a/application/pages/instance/ServersPage.ui +++ b/application/pages/instance/ServersPage.ui @@ -148,7 +148,6 @@ - @@ -170,11 +169,6 @@ Move Down - - - Join - - diff --git a/application/pages/instance/TexturePackPage.h b/application/pages/instance/TexturePackPage.h index 3f04997d..a792ba07 100644 --- a/application/pages/instance/TexturePackPage.h +++ b/application/pages/instance/TexturePackPage.h @@ -1,5 +1,4 @@ #pragma once - #include "ModFolderPage.h" #include "ui_ModFolderPage.h" @@ -14,7 +13,6 @@ public: ui->actionView_configs->setVisible(false); } virtual ~TexturePackPage() {} - virtual bool shouldDisplay() const override { return m_inst->traits().contains("texturepacks"); diff --git a/application/pages/instance/VersionPage.cpp b/application/pages/instance/VersionPage.cpp index 18c73e7d..8b0d59d9 100644 --- a/application/pages/instance/VersionPage.cpp +++ b/application/pages/instance/VersionPage.cpp @@ -120,15 +120,7 @@ VersionPage::VersionPage(MinecraftInstance *inst, QWidget *parent) auto proxy = new IconProxy(ui->packageView); proxy->setSourceModel(m_profile.get()); - - m_filterModel = new QSortFilterProxyModel(); - m_filterModel->setDynamicSortFilter(true); - m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive); - m_filterModel->setSortCaseSensitivity(Qt::CaseInsensitive); - m_filterModel->setSourceModel(proxy); - m_filterModel->setFilterKeyColumn(-1); - - ui->packageView->setModel(m_filterModel); + ui->packageView->setModel(proxy); ui->packageView->installEventFilter(this); ui->packageView->setSelectionMode(QAbstractItemView::SingleSelection); ui->packageView->setContextMenuPolicy(Qt::CustomContextMenu); @@ -142,8 +134,7 @@ VersionPage::VersionPage(MinecraftInstance *inst, QWidget *parent) updateVersionControls(); preselect(0); connect(m_inst, &BaseInstance::runningStatusChanged, this, &VersionPage::updateRunningStatus); - connect(ui->packageView, &ModListView::customContextMenuRequested, this, &VersionPage::showContextMenu); - connect(ui->filterEdit, &QLineEdit::textChanged, this, &VersionPage::onFilterTextChanged); + connect(ui->packageView, &ModListView::customContextMenuRequested, this, &VersionPage::ShowContextMenu); } VersionPage::~VersionPage() @@ -151,7 +142,7 @@ VersionPage::~VersionPage() delete ui; } -void VersionPage::showContextMenu(const QPoint& pos) +void VersionPage::ShowContextMenu(const QPoint& pos) { auto menu = ui->toolBar->createContextMenu(this, tr("Context menu")); menu->exec(ui->packageView->mapToGlobal(pos)); @@ -212,11 +203,11 @@ void VersionPage::updateVersionControls() { // FIXME: this is a dirty hack auto minecraftVersion = Version(m_profile->getComponentVersion("net.minecraft")); - bool newCraft = minecraftVersion >= Version("1.14"); - bool oldCraft = minecraftVersion <= Version("1.12.2"); - ui->actionInstall_Fabric->setEnabled(controlsEnabled && newCraft); - ui->actionInstall_Forge->setEnabled(controlsEnabled); - ui->actionInstall_LiteLoader->setEnabled(controlsEnabled && oldCraft); + bool newCraft = controlsEnabled && (minecraftVersion >= Version("1.14")); + bool oldCraft = controlsEnabled && (minecraftVersion <= Version("1.12.2")); + ui->actionInstall_Fabric->setEnabled(newCraft); + ui->actionInstall_Forge->setEnabled(true); + ui->actionInstall_LiteLoader->setEnabled(oldCraft); ui->actionReload->setEnabled(true); updateButtons(); } @@ -629,10 +620,5 @@ void VersionPage::on_actionRevert_triggered() m_container->refreshContainer(); } -void VersionPage::onFilterTextChanged(const QString &newContents) -{ - m_filterModel->setFilterFixedString(newContents); -} - #include "VersionPage.moc" diff --git a/application/pages/instance/VersionPage.h b/application/pages/instance/VersionPage.h index b5b4a6f5..dbd9c1ee 100644 --- a/application/pages/instance/VersionPage.h +++ b/application/pages/instance/VersionPage.h @@ -86,7 +86,6 @@ protected: private: Ui::VersionPage *ui; - QSortFilterProxyModel *m_filterModel; std::shared_ptr m_profile; MinecraftInstance *m_inst; int currentIdx = 0; @@ -99,6 +98,5 @@ private slots: void updateRunningStatus(bool running); void onGameUpdateError(QString error); void packageCurrent(const QModelIndex ¤t, const QModelIndex &previous); - void showContextMenu(const QPoint &pos); - void onFilterTextChanged(const QString & newContents); + void ShowContextMenu(const QPoint &pos); }; diff --git a/application/pages/instance/VersionPage.ui b/application/pages/instance/VersionPage.ui index 84d06e2e..718ad067 100644 --- a/application/pages/instance/VersionPage.ui +++ b/application/pages/instance/VersionPage.ui @@ -45,24 +45,6 @@ - - - - - - true - - - - - - - Filter: - - - - - diff --git a/application/pages/modplatform/ImportPage.cpp b/application/pages/modplatform/ImportPage.cpp index c2369bdc..3910dfda 100644 --- a/application/pages/modplatform/ImportPage.cpp +++ b/application/pages/modplatform/ImportPage.cpp @@ -71,7 +71,6 @@ void ImportPage::updateState() { QFileInfo fi(url.fileName()); dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(url)); - dialog->setSuggestedIcon("default"); } } else @@ -84,7 +83,6 @@ void ImportPage::updateState() // hook, line and sinker. QFileInfo fi(url.fileName()); dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(url)); - dialog->setSuggestedIcon("default"); } } else diff --git a/application/pages/modplatform/VanillaPage.cpp b/application/pages/modplatform/VanillaPage.cpp index 02638315..17535f1e 100644 --- a/application/pages/modplatform/VanillaPage.cpp +++ b/application/pages/modplatform/VanillaPage.cpp @@ -82,19 +82,10 @@ BaseVersionPtr VanillaPage::selectedVersion() const void VanillaPage::suggestCurrent() { - if (!isOpened) + if(m_selectedVersion && isOpened) { - return; + dialog->setSuggestedPack(m_selectedVersion->descriptor(), new InstanceCreationTask(m_selectedVersion)); } - - if(!m_selectedVersion) - { - dialog->setSuggestedPack(); - return; - } - - dialog->setSuggestedPack(m_selectedVersion->descriptor(), new InstanceCreationTask(m_selectedVersion)); - dialog->setSuggestedIcon("default"); } void VanillaPage::setSelectedVersion(BaseVersionPtr version) diff --git a/application/pages/modplatform/atlauncher/AtlOptionalModDialog.cpp b/application/pages/modplatform/atlauncher/AtlOptionalModDialog.cpp deleted file mode 100644 index 14bbd18b..00000000 --- a/application/pages/modplatform/atlauncher/AtlOptionalModDialog.cpp +++ /dev/null @@ -1,209 +0,0 @@ -#include "AtlOptionalModDialog.h" -#include "ui_AtlOptionalModDialog.h" - -AtlOptionalModListModel::AtlOptionalModListModel(QWidget *parent, QVector mods) - : QAbstractListModel(parent), m_mods(mods) { - - // fill mod index - for (int i = 0; i < m_mods.size(); i++) { - auto mod = m_mods.at(i); - m_index[mod.name] = i; - } - // set initial state - for (int i = 0; i < m_mods.size(); i++) { - auto mod = m_mods.at(i); - m_selection[mod.name] = false; - setMod(mod, i, mod.selected, false); - } -} - -QVector AtlOptionalModListModel::getResult() { - QVector result; - - for (const auto& mod : m_mods) { - if (m_selection[mod.name]) { - result.push_back(mod.name); - } - } - - return result; -} - -int AtlOptionalModListModel::rowCount(const QModelIndex &parent) const { - return m_mods.size(); -} - -int AtlOptionalModListModel::columnCount(const QModelIndex &parent) const { - // Enabled, Name, Description - return 3; -} - -QVariant AtlOptionalModListModel::data(const QModelIndex &index, int role) const { - auto row = index.row(); - auto mod = m_mods.at(row); - - if (role == Qt::DisplayRole) { - if (index.column() == NameColumn) { - return mod.name; - } - if (index.column() == DescriptionColumn) { - return mod.description; - } - } - else if (role == Qt::ToolTipRole) { - if (index.column() == DescriptionColumn) { - return mod.description; - } - } - else if (role == Qt::CheckStateRole) { - if (index.column() == EnabledColumn) { - return m_selection[mod.name] ? Qt::Checked : Qt::Unchecked; - } - } - - return QVariant(); -} - -bool AtlOptionalModListModel::setData(const QModelIndex &index, const QVariant &value, int role) { - if (role == Qt::CheckStateRole) { - auto row = index.row(); - auto mod = m_mods.at(row); - - toggleMod(mod, row); - return true; - } - - return false; -} - -QVariant AtlOptionalModListModel::headerData(int section, Qt::Orientation orientation, int role) const { - if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { - switch (section) { - case EnabledColumn: - return QString(); - case NameColumn: - return QString("Name"); - case DescriptionColumn: - return QString("Description"); - } - } - - return QVariant(); -} - -Qt::ItemFlags AtlOptionalModListModel::flags(const QModelIndex &index) const { - auto flags = QAbstractListModel::flags(index); - if (index.isValid() && index.column() == EnabledColumn) { - flags |= Qt::ItemIsUserCheckable; - } - return flags; -} - -void AtlOptionalModListModel::selectRecommended() { - for (const auto& mod : m_mods) { - m_selection[mod.name] = mod.recommended; - } - - emit dataChanged(AtlOptionalModListModel::index(0, EnabledColumn), - AtlOptionalModListModel::index(m_mods.size() - 1, EnabledColumn)); -} - -void AtlOptionalModListModel::clearAll() { - for (const auto& mod : m_mods) { - m_selection[mod.name] = false; - } - - emit dataChanged(AtlOptionalModListModel::index(0, EnabledColumn), - AtlOptionalModListModel::index(m_mods.size() - 1, EnabledColumn)); -} - -void AtlOptionalModListModel::toggleMod(ATLauncher::VersionMod mod, int index) { - setMod(mod, index, !m_selection[mod.name]); -} - -void AtlOptionalModListModel::setMod(ATLauncher::VersionMod mod, int index, bool enable, bool shouldEmit) { - if (m_selection[mod.name] == enable) return; - - m_selection[mod.name] = enable; - - // disable other mods in the group, if applicable - if (enable && !mod.group.isEmpty()) { - for (int i = 0; i < m_mods.size(); i++) { - if (index == i) continue; - auto other = m_mods.at(i); - - if (mod.group == other.group) { - setMod(other, i, false, shouldEmit); - } - } - } - - for (const auto& dependencyName : mod.depends) { - auto dependencyIndex = m_index[dependencyName]; - auto dependencyMod = m_mods.at(dependencyIndex); - - // enable/disable dependencies - if (enable) { - setMod(dependencyMod, dependencyIndex, true, shouldEmit); - } - - // if the dependency is 'effectively hidden', then track which mods - // depend on it - so we can efficiently disable it when no more dependents - // depend on it. - auto dependants = m_dependants[dependencyName]; - - if (enable) { - dependants.append(mod.name); - } - else { - dependants.removeAll(mod.name); - - // if there are no longer any dependents, let's disable the mod - if (dependencyMod.effectively_hidden && dependants.isEmpty()) { - setMod(dependencyMod, dependencyIndex, false, shouldEmit); - } - } - } - - // disable mods that depend on this one, if disabling - if (!enable) { - auto dependants = m_dependants[mod.name]; - for (const auto& dependencyName : dependants) { - auto dependencyIndex = m_index[dependencyName]; - auto dependencyMod = m_mods.at(dependencyIndex); - - setMod(dependencyMod, dependencyIndex, false, shouldEmit); - } - } - - if (shouldEmit) { - emit dataChanged(AtlOptionalModListModel::index(index, EnabledColumn), - AtlOptionalModListModel::index(index, EnabledColumn)); - } -} - - -AtlOptionalModDialog::AtlOptionalModDialog(QWidget *parent, QVector mods) - : QDialog(parent), ui(new Ui::AtlOptionalModDialog) { - ui->setupUi(this); - - listModel = new AtlOptionalModListModel(this, mods); - ui->treeView->setModel(listModel); - - ui->treeView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - ui->treeView->header()->setSectionResizeMode( - AtlOptionalModListModel::NameColumn, QHeaderView::ResizeToContents); - ui->treeView->header()->setSectionResizeMode( - AtlOptionalModListModel::DescriptionColumn, QHeaderView::Stretch); - - connect(ui->selectRecommendedButton, &QPushButton::pressed, - listModel, &AtlOptionalModListModel::selectRecommended); - connect(ui->clearAllButton, &QPushButton::pressed, - listModel, &AtlOptionalModListModel::clearAll); - connect(ui->installButton, &QPushButton::pressed, - this, &QDialog::close); -} - -AtlOptionalModDialog::~AtlOptionalModDialog() { - delete ui; -} diff --git a/application/pages/modplatform/atlauncher/AtlOptionalModDialog.h b/application/pages/modplatform/atlauncher/AtlOptionalModDialog.h deleted file mode 100644 index a1df43f6..00000000 --- a/application/pages/modplatform/atlauncher/AtlOptionalModDialog.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -#include -#include - -#include "modplatform/atlauncher/ATLPackIndex.h" - -namespace Ui { -class AtlOptionalModDialog; -} - -class AtlOptionalModListModel : public QAbstractListModel { - Q_OBJECT - -public: - enum Columns - { - EnabledColumn = 0, - NameColumn, - DescriptionColumn, - }; - - AtlOptionalModListModel(QWidget *parent, QVector mods); - - QVector getResult(); - - int rowCount(const QModelIndex &parent) const override; - int columnCount(const QModelIndex &parent) const override; - - QVariant data(const QModelIndex &index, int role) const override; - bool setData(const QModelIndex &index, const QVariant &value, int role) override; - QVariant headerData(int section, Qt::Orientation orientation, int role) const override; - - Qt::ItemFlags flags(const QModelIndex &index) const override; - -public slots: - void selectRecommended(); - void clearAll(); - -private: - void toggleMod(ATLauncher::VersionMod mod, int index); - void setMod(ATLauncher::VersionMod mod, int index, bool enable, bool shouldEmit = true); - -private: - QVector m_mods; - QMap m_selection; - QMap m_index; - QMap> m_dependants; -}; - -class AtlOptionalModDialog : public QDialog { - Q_OBJECT - -public: - AtlOptionalModDialog(QWidget *parent, QVector mods); - ~AtlOptionalModDialog() override; - - QVector getResult() { - return listModel->getResult(); - } - -private: - Ui::AtlOptionalModDialog *ui; - - AtlOptionalModListModel *listModel; -}; diff --git a/application/pages/modplatform/atlauncher/AtlOptionalModDialog.ui b/application/pages/modplatform/atlauncher/AtlOptionalModDialog.ui deleted file mode 100644 index 5d3193a4..00000000 --- a/application/pages/modplatform/atlauncher/AtlOptionalModDialog.ui +++ /dev/null @@ -1,65 +0,0 @@ - - - AtlOptionalModDialog - - - - 0 - 0 - 550 - 310 - - - - Select Mods To Install - - - - - - Install - - - true - - - - - - - Select Recommended - - - - - - - false - - - Use Share Code - - - - - - - Clear All - - - - - - - - - - - ModListView - QTreeView -
widgets/ModListView.h
-
-
- - -
diff --git a/application/pages/modplatform/atlauncher/AtlPage.cpp b/application/pages/modplatform/atlauncher/AtlPage.cpp index 9fdf111f..f90d734c 100644 --- a/application/pages/modplatform/atlauncher/AtlPage.cpp +++ b/application/pages/modplatform/atlauncher/AtlPage.cpp @@ -2,10 +2,8 @@ #include "ui_AtlPage.h" #include "dialogs/NewInstanceDialog.h" -#include "AtlOptionalModDialog.h" #include #include -#include AtlPage::AtlPage(NewInstanceDialog* dialog, QWidget *parent) : QWidget(parent), ui(new Ui::AtlPage), dialog(dialog) @@ -21,9 +19,6 @@ AtlPage::AtlPage(NewInstanceDialog* dialog, QWidget *parent) ui->packView->header()->hide(); ui->packView->setIndentation(0); - ui->versionSelectionBox->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - ui->versionSelectionBox->view()->parentWidget()->setMaximumHeight(300); - for(int i = 0; i < filterModel->getAvailableSortings().size(); i++) { ui->sortByBox->addItem(filterModel->getAvailableSortings().keys().at(i)); @@ -49,29 +44,15 @@ bool AtlPage::shouldDisplay() const void AtlPage::openedImpl() { - if(!initialized) - { - listModel->request(); - initialized = true; - } - - suggestCurrent(); + listModel->request(); } void AtlPage::suggestCurrent() { - if(!isOpened) - { - return; + if(isOpened) { + dialog->setSuggestedPack(selected.name, new ATLauncher::PackInstallTask(selected.safeName, selectedVersion)); } - if (selectedVersion.isEmpty()) - { - dialog->setSuggestedPack(); - return; - } - - dialog->setSuggestedPack(selected.name, new ATLauncher::PackInstallTask(this, selected.safeName, selectedVersion)); auto editedLogoName = selected.safeName; auto url = QString(BuildConfig.ATL_DOWNLOAD_SERVER_URL + "launcher/images/%1.png").arg(selected.safeName.toLower()); listModel->getLogo(selected.safeName, url, [this, editedLogoName](QString logo) @@ -131,45 +112,3 @@ void AtlPage::onVersionSelectionChanged(QString data) selectedVersion = data; suggestCurrent(); } - -QVector AtlPage::chooseOptionalMods(QVector mods) { - AtlOptionalModDialog optionalModDialog(this, mods); - optionalModDialog.exec(); - return optionalModDialog.getResult(); -} - -QString AtlPage::chooseVersion(Meta::VersionListPtr vlist, QString minecraftVersion) { - VersionSelectDialog vselect(vlist.get(), "Choose Version", MMC->activeWindow(), false); - if (minecraftVersion != Q_NULLPTR) { - vselect.setExactFilter(BaseVersionList::ParentVersionRole, minecraftVersion); - vselect.setEmptyString(tr("No versions are currently available for Minecraft %1").arg(minecraftVersion)); - } - else { - vselect.setEmptyString(tr("No versions are currently available")); - } - vselect.setEmptyErrorString(tr("Couldn't load or download the version lists!")); - - // select recommended build - for (int i = 0; i < vlist->versions().size(); i++) { - auto version = vlist->versions().at(i); - auto reqs = version->requires(); - - // filter by minecraft version, if the loader depends on a certain version. - if (minecraftVersion != Q_NULLPTR) { - auto iter = std::find_if(reqs.begin(), reqs.end(), [](const Meta::Require &req) { - return req.uid == "net.minecraft"; - }); - if (iter == reqs.end()) continue; - if (iter->equalsVersion != minecraftVersion) continue; - } - - // first recommended build we find, we use. - if (version->isRecommended()) { - vselect.setCurrentVersion(version->descriptor()); - break; - } - } - - vselect.exec(); - return vselect.selectedVersion()->descriptor(); -} diff --git a/application/pages/modplatform/atlauncher/AtlPage.h b/application/pages/modplatform/atlauncher/AtlPage.h index 932ec6a6..715cf5f4 100644 --- a/application/pages/modplatform/atlauncher/AtlPage.h +++ b/application/pages/modplatform/atlauncher/AtlPage.h @@ -19,7 +19,6 @@ #include "AtlListModel.h" #include -#include #include "MultiMC.h" #include "pages/BasePage.h" @@ -32,7 +31,7 @@ namespace Ui class NewInstanceDialog; -class AtlPage : public QWidget, public BasePage, public ATLauncher::UserInteractionSupport +class AtlPage : public QWidget, public BasePage { Q_OBJECT @@ -62,9 +61,6 @@ public: private: void suggestCurrent(); - QString chooseVersion(Meta::VersionListPtr vlist, QString minecraftVersion) override; - QVector chooseOptionalMods(QVector mods) override; - private slots: void triggerSearch(); void resetSearch(); @@ -82,6 +78,4 @@ private: ATLauncher::IndexedPack selected; QString selectedVersion; - - bool initialized = false; }; diff --git a/application/pages/modplatform/atlauncher/AtlPage.ui b/application/pages/modplatform/atlauncher/AtlPage.ui index f16c24b8..bb0d5310 100644 --- a/application/pages/modplatform/atlauncher/AtlPage.ui +++ b/application/pages/modplatform/atlauncher/AtlPage.ui @@ -21,9 +21,6 @@ 48
- - true -
diff --git a/application/pages/modplatform/flame/FlamePage.cpp b/application/pages/modplatform/flame/FlamePage.cpp index ade58431..1fadc501 100644 --- a/application/pages/modplatform/flame/FlamePage.cpp +++ b/application/pages/modplatform/flame/FlamePage.cpp @@ -17,9 +17,6 @@ FlamePage::FlamePage(NewInstanceDialog* dialog, QWidget *parent) listModel = new Flame::ListModel(this); ui->packView->setModel(listModel); - ui->versionSelectionBox->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - ui->versionSelectionBox->view()->parentWidget()->setMaximumHeight(300); - // index is used to set the sorting with the curseforge api ui->sortByBox->addItem(tr("Sort by featured")); ui->sortByBox->addItem(tr("Sort by popularity")); @@ -158,12 +155,6 @@ void FlamePage::suggestCurrent() return; } - if (selectedVersion.isEmpty()) - { - dialog->setSuggestedPack(); - return; - } - dialog->setSuggestedPack(current.name, new InstanceImportTask(selectedVersion)); QString editedLogoName; editedLogoName = "curseforge_" + current.logoName.section(".", 0, 0); diff --git a/application/pages/modplatform/ftb/FtbPage.cpp b/application/pages/modplatform/ftb/FtbPage.cpp index b7f35c5d..dd2ff666 100644 --- a/application/pages/modplatform/ftb/FtbPage.cpp +++ b/application/pages/modplatform/ftb/FtbPage.cpp @@ -23,9 +23,6 @@ FtbPage::FtbPage(NewInstanceDialog* dialog, QWidget *parent) ui->searchEdit->installEventFilter(this); - ui->versionSelectionBox->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - ui->versionSelectionBox->view()->parentWidget()->setMaximumHeight(300); - for(int i = 0; i < filterModel->getAvailableSortings().size(); i++) { ui->sortByBox->addItem(filterModel->getAvailableSortings().keys().at(i)); @@ -63,33 +60,26 @@ bool FtbPage::shouldDisplay() const void FtbPage::openedImpl() { + dialog->setSuggestedPack(); triggerSearch(); - suggestCurrent(); } void FtbPage::suggestCurrent() { - if(!isOpened) + if(isOpened) { - return; - } + dialog->setSuggestedPack(selected.name, new ModpacksCH::PackInstallTask(selected, selectedVersion)); - if (selectedVersion.isEmpty()) - { - dialog->setSuggestedPack(); - return; - } + for(auto art : selected.art) { + if(art.type == "square") { + QString editedLogoName; + editedLogoName = selected.name; - dialog->setSuggestedPack(selected.name, new ModpacksCH::PackInstallTask(selected, selectedVersion)); - for(auto art : selected.art) { - if(art.type == "square") { - QString editedLogoName; - editedLogoName = selected.name; - - listModel->getLogo(selected.name, art.url, [this, editedLogoName](QString logo) - { - dialog->setSuggestedIconFromFile(logo + ".small", editedLogoName); - }); + listModel->getLogo(selected.name, art.url, [this, editedLogoName](QString logo) + { + dialog->setSuggestedIconFromFile(logo + ".small", editedLogoName); + }); + } } } } diff --git a/application/pages/modplatform/ftb/FtbPage.ui b/application/pages/modplatform/ftb/FtbPage.ui index 135afc6d..475d78bb 100644 --- a/application/pages/modplatform/ftb/FtbPage.ui +++ b/application/pages/modplatform/ftb/FtbPage.ui @@ -32,11 +32,7 @@ - - - Search and filter ... - - + @@ -55,9 +51,6 @@ 48 - - true - diff --git a/application/pages/modplatform/legacy_ftb/Page.cpp b/application/pages/modplatform/legacy_ftb/Page.cpp index a438f76c..8e40ba9e 100644 --- a/application/pages/modplatform/legacy_ftb/Page.cpp +++ b/application/pages/modplatform/legacy_ftb/Page.cpp @@ -122,50 +122,49 @@ void Page::openedImpl() void Page::suggestCurrent() { - if(!isOpened) + if(isOpened) { - return; - } - - if(selected.broken || selectedVersion.isEmpty()) - { - dialog->setSuggestedPack(); - return; - } - - dialog->setSuggestedPack(selected.name, new PackInstallTask(selected, selectedVersion)); - QString editedLogoName; - if(selected.logo.toLower().startsWith("ftb")) - { - editedLogoName = selected.logo; - } - else - { - editedLogoName = "ftb_" + selected.logo; - } - - editedLogoName = editedLogoName.left(editedLogoName.lastIndexOf(".png")); - - if(selected.type == PackType::Public) - { - publicListModel->getLogo(selected.logo, [this, editedLogoName](QString logo) + if(!selected.broken) { - dialog->setSuggestedIconFromFile(logo, editedLogoName); - }); - } - else if (selected.type == PackType::ThirdParty) - { - thirdPartyModel->getLogo(selected.logo, [this, editedLogoName](QString logo) + dialog->setSuggestedPack(selected.name, new PackInstallTask(selected, selectedVersion)); + QString editedLogoName; + if(selected.logo.toLower().startsWith("ftb")) + { + editedLogoName = selected.logo; + } + else + { + editedLogoName = "ftb_" + selected.logo; + } + + editedLogoName = editedLogoName.left(editedLogoName.lastIndexOf(".png")); + + if(selected.type == PackType::Public) + { + publicListModel->getLogo(selected.logo, [this, editedLogoName](QString logo) + { + dialog->setSuggestedIconFromFile(logo, editedLogoName); + }); + } + else if (selected.type == PackType::ThirdParty) + { + thirdPartyModel->getLogo(selected.logo, [this, editedLogoName](QString logo) + { + dialog->setSuggestedIconFromFile(logo, editedLogoName); + }); + } + else if (selected.type == PackType::Private) + { + privateListModel->getLogo(selected.logo, [this, editedLogoName](QString logo) + { + dialog->setSuggestedIconFromFile(logo, editedLogoName); + }); + } + } + else { - dialog->setSuggestedIconFromFile(logo, editedLogoName); - }); - } - else if (selected.type == PackType::Private) - { - privateListModel->getLogo(selected.logo, [this, editedLogoName](QString logo) - { - dialog->setSuggestedIconFromFile(logo, editedLogoName); - }); + dialog->setSuggestedPack(); + } } } diff --git a/application/pages/modplatform/legacy_ftb/Page.ui b/application/pages/modplatform/legacy_ftb/Page.ui index 15e5d432..36fb2359 100644 --- a/application/pages/modplatform/legacy_ftb/Page.ui +++ b/application/pages/modplatform/legacy_ftb/Page.ui @@ -29,9 +29,6 @@ 16777215 - - true - @@ -55,9 +52,6 @@ 16777215 - - true - @@ -75,9 +69,6 @@ 16777215 - - true - diff --git a/application/pages/modplatform/technic/TechnicModel.cpp b/application/pages/modplatform/technic/TechnicModel.cpp index a240a94a..bf256ab6 100644 --- a/application/pages/modplatform/technic/TechnicModel.cpp +++ b/application/pages/modplatform/technic/TechnicModel.cpp @@ -72,7 +72,7 @@ int Technic::ListModel::rowCount(const QModelIndex&) const void Technic::ListModel::searchWithTerm(const QString& term) { - if(currentSearchTerm == term && currentSearchTerm.isNull() == term.isNull()) { + if(currentSearchTerm == term) { return; } currentSearchTerm = term; @@ -93,18 +93,9 @@ void Technic::ListModel::searchWithTerm(const QString& term) void Technic::ListModel::performSearch() { NetJob *netJob = new NetJob("Technic::Search"); - QString searchUrl = ""; - if (currentSearchTerm.isEmpty()) { - searchUrl = QString( - "https://api.technicpack.net/trending?build=multimc" - ).arg(currentSearchTerm); - } - else - { - searchUrl = QString( - "https://api.technicpack.net/search?build=multimc&q=%1" - ).arg(currentSearchTerm); - } + auto searchUrl = QString( + "https://api.technicpack.net/search?build=multimc&q=%1" + ).arg(currentSearchTerm); netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response)); jobPtr = netJob; jobPtr->start(); diff --git a/application/pages/modplatform/technic/TechnicPage.cpp b/application/pages/modplatform/technic/TechnicPage.cpp index e836f767..d246edf2 100644 --- a/application/pages/modplatform/technic/TechnicPage.cpp +++ b/application/pages/modplatform/technic/TechnicPage.cpp @@ -60,8 +60,7 @@ bool TechnicPage::shouldDisplay() const void TechnicPage::openedImpl() { - suggestCurrent(); - triggerSearch(); + dialog->setSuggestedPack(); } void TechnicPage::triggerSearch() { @@ -96,7 +95,8 @@ void TechnicPage::suggestCurrent() return; } - QString editedLogoName = "technic_" + current.logoName.section(".", 0, 0); + QString editedLogoName; + editedLogoName = "technic_" + current.logoName.section(".", 0, 0); model->getLogo(current.logoName, current.logoUrl, [this, editedLogoName](QString logo) { dialog->setSuggestedIconFromFile(logo, editedLogoName); @@ -105,66 +105,67 @@ void TechnicPage::suggestCurrent() if (current.metadataLoaded) { metadataLoaded(); - return; } - - NetJob *netJob = new NetJob(QString("Technic::PackMeta(%1)").arg(current.name)); - std::shared_ptr response = std::make_shared(); - QString slug = current.slug; - netJob->addNetAction(Net::Download::makeByteArray(QString("https://api.technicpack.net/modpack/%1?build=multimc").arg(slug), response.get())); - QObject::connect(netJob, &NetJob::succeeded, this, [this, response, slug] + else { - if (current.slug != slug) + NetJob *netJob = new NetJob(QString("Technic::PackMeta(%1)").arg(current.name)); + std::shared_ptr response = std::make_shared(); + QString slug = current.slug; + netJob->addNetAction(Net::Download::makeByteArray(QString("https://api.technicpack.net/modpack/%1?build=multimc").arg(slug), response.get())); + QObject::connect(netJob, &NetJob::succeeded, this, [this, response, slug] { - return; - } - QJsonParseError parse_error; - QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); - QJsonObject obj = doc.object(); - if(parse_error.error != QJsonParseError::NoError) - { - qWarning() << "Error while parsing JSON response from Technic at " << parse_error.offset << " reason: " << parse_error.errorString(); - qWarning() << *response; - return; - } - if (!obj.contains("url")) - { - qWarning() << "Json doesn't contain an url key"; - return; - } - QJsonValueRef url = obj["url"]; - if (url.isString()) - { - current.url = url.toString(); - } - else - { - if (!obj.contains("solder")) + if (current.slug != slug) { - qWarning() << "Json doesn't contain a valid url or solder key"; return; } - QJsonValueRef solderUrl = obj["solder"]; - if (solderUrl.isString()) + QJsonParseError parse_error; + QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); + QJsonObject obj = doc.object(); + if(parse_error.error != QJsonParseError::NoError) { - current.url = solderUrl.toString(); - current.isSolder = true; + qWarning() << "Error while parsing JSON response from Technic at " << parse_error.offset << " reason: " << parse_error.errorString(); + qWarning() << *response; + return; + } + if (!obj.contains("url")) + { + qWarning() << "Json doesn't contain an url key"; + return; + } + QJsonValueRef url = obj["url"]; + if (url.isString()) + { + current.url = url.toString(); } else { - qWarning() << "Json doesn't contain a valid url or solder key"; - return; + if (!obj.contains("solder")) + { + qWarning() << "Json doesn't contain a valid url or solder key"; + return; + } + QJsonValueRef solderUrl = obj["solder"]; + if (solderUrl.isString()) + { + current.url = solderUrl.toString(); + current.isSolder = true; + } + else + { + qWarning() << "Json doesn't contain a valid url or solder key"; + return; + } } - } - current.minecraftVersion = Json::ensureString(obj, "minecraft", QString(), "__placeholder__"); - current.websiteUrl = Json::ensureString(obj, "platformUrl", QString(), "__placeholder__"); - current.author = Json::ensureString(obj, "user", QString(), "__placeholder__"); - current.description = Json::ensureString(obj, "description", QString(), "__placeholder__"); - current.metadataLoaded = true; - metadataLoaded(); - }); - netJob->start(); + current.minecraftVersion = Json::ensureString(obj, "minecraft", QString(), "__placeholder__"); + current.websiteUrl = Json::ensureString(obj, "platformUrl", QString(), "__placeholder__"); + current.author = Json::ensureString(obj, "user", QString(), "__placeholder__"); + current.description = Json::ensureString(obj, "description", QString(), "__placeholder__"); + current.metadataLoaded = true; + metadataLoaded(); + }); + netJob->start(); + } } // expects current.metadataLoaded to be true diff --git a/application/pages/modplatform/technic/TechnicPage.ui b/application/pages/modplatform/technic/TechnicPage.ui index 2ca45dd2..36ce2ecf 100644 --- a/application/pages/modplatform/technic/TechnicPage.ui +++ b/application/pages/modplatform/technic/TechnicPage.ui @@ -27,11 +27,7 @@ 0 - - - Search and filter ... - - + diff --git a/application/widgets/JavaSettingsWidget.cpp b/application/widgets/JavaSettingsWidget.cpp index 7f53dc23..a11dd1aa 100644 --- a/application/widgets/JavaSettingsWidget.cpp +++ b/application/widgets/JavaSettingsWidget.cpp @@ -19,7 +19,7 @@ JavaSettingsWidget::JavaSettingsWidget(QWidget* parent) : QWidget(parent) { - m_availableMemory = Sys::getSystemRam() / Sys::mebibyte; + m_availableMemory = Sys::getSystemRam() / Sys::megabyte; goodIcon = MMC->getThemedIcon("status-good"); yellowIcon = MMC->getThemedIcon("status-yellow"); diff --git a/buildconfig/BuildConfig.cpp.in b/buildconfig/BuildConfig.cpp.in index 577bdcb2..86ea83ee 100644 --- a/buildconfig/BuildConfig.cpp.in +++ b/buildconfig/BuildConfig.cpp.in @@ -34,10 +34,6 @@ Config::Config() NEWS_RSS_URL = "@MultiMC_NEWS_RSS_URL@"; PASTE_EE_KEY = "@MultiMC_PASTE_EE_API_KEY@"; META_URL = "@MultiMC_META_URL@"; - - BUG_TRACKER_URL = "@MultiMC_BUG_TRACKER_URL@"; - DISCORD_URL = "@MultiMC_DISCORD_URL@"; - SUBREDDIT_URL = "@MultiMC_SUBREDDIT_URL@"; } QString Config::printableVersionString() const diff --git a/buildconfig/BuildConfig.h b/buildconfig/BuildConfig.h index 10c7a102..d70f1614 100644 --- a/buildconfig/BuildConfig.h +++ b/buildconfig/BuildConfig.h @@ -65,10 +65,6 @@ public: */ QString META_URL; - QString BUG_TRACKER_URL; - QString DISCORD_URL; - QString SUBREDDIT_URL; - QString RESOURCE_BASE = "https://resources.download.minecraft.net/"; QString LIBRARY_BASE = "https://libraries.minecraft.net/"; QString MOJANG_STATUS_URL = "https://status.mojang.com/check"; diff --git a/libraries/README.md b/libraries/README.md index ac861148..cdc72004 100644 --- a/libraries/README.md +++ b/libraries/README.md @@ -158,10 +158,3 @@ A Google Analytics library for Qt. BSD licensed, derived from [qt-google-analytics](https://github.com/HSAnet/qt-google-analytics). Modifications include better handling of IP anonymization (can be enabled) and general improvements of the API (application handles persistence and ID generation instead of the library). - -## tomlc99 -A TOML language parser. Used by Forge 1.14+ to store mod metadata. - -See [github repo](https://github.com/cktan/tomlc99). - -Licenced under the MIT licence. diff --git a/libraries/launcher/org/multimc/LegacyFrame.java b/libraries/launcher/org/multimc/LegacyFrame.java index 985a10e6..c72c053e 100644 --- a/libraries/launcher/org/multimc/LegacyFrame.java +++ b/libraries/launcher/org/multimc/LegacyFrame.java @@ -46,16 +46,7 @@ public class LegacyFrame extends Frame implements WindowListener this.addWindowListener ( this ); } - public void start ( - Applet mcApplet, - String user, - String session, - int winSizeW, - int winSizeH, - boolean maximize, - String serverAddress, - String serverPort - ) + public void start ( Applet mcApplet, String user, String session, int winSizeW, int winSizeH, boolean maximize ) { try { appletWrap = new Launcher( mcApplet, new URL ( "http://www.minecraft.net/game" ) ); @@ -104,13 +95,6 @@ public class LegacyFrame extends Frame implements WindowListener e.printStackTrace(System.err); System.exit(-1); } - - if (serverAddress != null) - { - appletWrap.setParameter("server", serverAddress); - appletWrap.setParameter("port", serverPort); - } - appletWrap.setParameter ( "username", user ); appletWrap.setParameter ( "sessionid", session ); appletWrap.setParameter ( "stand-alone", "true" ); // Show the quit button. diff --git a/libraries/launcher/org/multimc/onesix/OneSixLauncher.java b/libraries/launcher/org/multimc/onesix/OneSixLauncher.java index ea445995..b6b384ab 100644 --- a/libraries/launcher/org/multimc/onesix/OneSixLauncher.java +++ b/libraries/launcher/org/multimc/onesix/OneSixLauncher.java @@ -47,9 +47,6 @@ public class OneSixLauncher implements Launcher private boolean maximize; private String cwd; - private String serverAddress; - private String serverPort; - // the much abused system classloader, for convenience (for further abuse) private ClassLoader cl; @@ -67,9 +64,6 @@ public class OneSixLauncher implements Launcher windowTitle = params.firstSafe("windowTitle", "Minecraft"); windowParams = params.firstSafe("windowParams", "854x480"); - serverAddress = params.firstSafe("serverAddress", null); - serverPort = params.firstSafe("serverPort", null); - cwd = System.getProperty("user.dir"); winSizeW = 854; @@ -128,7 +122,7 @@ public class OneSixLauncher implements Launcher Class MCAppletClass = cl.loadClass(appletClass); Applet mcappl = (Applet) MCAppletClass.newInstance(); LegacyFrame mcWindow = new LegacyFrame(windowTitle); - mcWindow.start(mcappl, userName, sessionId, winSizeW, winSizeH, maximize, serverAddress, serverPort); + mcWindow.start(mcappl, userName, sessionId, winSizeW, winSizeH, maximize); return 0; } catch (Exception e) { @@ -170,14 +164,6 @@ public class OneSixLauncher implements Launcher mcparams.add(Integer.toString(winSizeH)); } - if (serverAddress != null) - { - mcparams.add("--server"); - mcparams.add(serverAddress); - mcparams.add("--port"); - mcparams.add(serverPort); - } - // Get the Minecraft Class. Class mc; try diff --git a/libraries/systeminfo/include/sys.h b/libraries/systeminfo/include/sys.h index 914d2555..7980dfdf 100644 --- a/libraries/systeminfo/include/sys.h +++ b/libraries/systeminfo/include/sys.h @@ -3,7 +3,7 @@ namespace Sys { -const uint64_t mebibyte = 1024ull * 1024ull; +const uint64_t megabyte = 1024ull * 1024ull; struct KernelInfo { QString kernelName; diff --git a/libraries/systeminfo/src/sys_unix.cpp b/libraries/systeminfo/src/sys_unix.cpp index 42c0d319..ab3f302e 100644 --- a/libraries/systeminfo/src/sys_unix.cpp +++ b/libraries/systeminfo/src/sys_unix.cpp @@ -4,7 +4,6 @@ #include #include -#include Sys::KernelInfo Sys::getKernelInfo() { diff --git a/libraries/tomlc99/CMakeLists.txt b/libraries/tomlc99/CMakeLists.txt deleted file mode 100644 index 60786923..00000000 --- a/libraries/tomlc99/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -project(tomlc99) - -set(tomlc99_SOURCES -include/toml.h -src/toml.c -) - -add_library(tomlc99 STATIC ${tomlc99_SOURCES}) - -target_include_directories(tomlc99 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) diff --git a/libraries/tomlc99/LICENSE b/libraries/tomlc99/LICENSE deleted file mode 100644 index a3292b16..00000000 --- a/libraries/tomlc99/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -MIT License - -Copyright (c) 2017 CK Tan -https://github.com/cktan/tomlc99 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/libraries/tomlc99/README.md b/libraries/tomlc99/README.md deleted file mode 100644 index 6715b5be..00000000 --- a/libraries/tomlc99/README.md +++ /dev/null @@ -1,194 +0,0 @@ -# tomlc99 - -TOML in c99; v1.0 compliant. - -If you are looking for a C++ library, you might try this wrapper: [https://github.com/cktan/tomlcpp](https://github.com/cktan/tomlcpp). - -* Compatible with [TOML v1.0.0](https://toml.io/en/v1.0.0). -* Tested with multiple test suites, including -[BurntSushi/toml-test](https://github.com/BurntSushi/toml-test) and -[iarna/toml-spec-tests](https://github.com/iarna/toml-spec-tests). -* Provides very simple and intuitive interface. - - -## Usage - -Please see the `toml.h` file for details. What follows is a simple example that -parses this config file: - -```toml -[server] - host = "www.example.com" - port = [ 8080, 8181, 8282 ] -``` - -The steps for getting values from our file is usually : - -1. Parse the TOML file. -2. Traverse and locate a table in TOML. -3. Extract values from the table. -4. Free up allocated memory. - -Below is an example of parsing the values from the example table. - -```c -#include -#include -#include -#include -#include "toml.h" - -static void error(const char* msg, const char* msg1) -{ - fprintf(stderr, "ERROR: %s%s\n", msg, msg1?msg1:""); - exit(1); -} - - -int main() -{ - FILE* fp; - char errbuf[200]; - - // 1. Read and parse toml file - fp = fopen("sample.toml", "r"); - if (!fp) { - error("cannot open sample.toml - ", strerror(errno)); - } - - toml_table_t* conf = toml_parse_file(fp, errbuf, sizeof(errbuf)); - fclose(fp); - - if (!conf) { - error("cannot parse - ", errbuf); - } - - // 2. Traverse to a table. - toml_table_t* server = toml_table_in(conf, "server"); - if (!server) { - error("missing [server]", ""); - } - - // 3. Extract values - toml_datum_t host = toml_string_in(server, "host"); - if (!host.ok) { - error("cannot read server.host", ""); - } - - toml_array_t* portarray = toml_array_in(server, "port"); - if (!portarray) { - error("cannot read server.port", ""); - } - - printf("host: %s\n", host.u.s); - printf("port: "); - for (int i = 0; ; i++) { - toml_datum_t port = toml_int_at(portarray, i); - if (!port.ok) break; - printf("%d ", (int)port.u.i); - } - printf("\n"); - - // 4. Free memory - free(host.u.s); - toml_free(conf); - return 0; -} -``` - -#### Accessing Table Content - -TOML tables are dictionaries where lookups are done using string keys. In -general, all access functions on tables are named `toml_*_in(...)`. - -In the normal case, you know the key and its content type, and retrievals can be done -using one of these functions: -```c -toml_string_in(tab, key); -toml_bool_in(tab, key); -toml_int_in(tab, key); -toml_double_in(tab, key); -toml_timestamp_in(tab, key); -toml_table_in(tab, key); -toml_array_in(tab, key); -``` - -You can also interrogate the keys in a table using an integer index: -```c -toml_table_t* tab = toml_parse_file(...); -for (int i = 0; ; i++) { - const char* key = toml_key_in(tab, i); - if (!key) break; - printf("key %d: %s\n", i, key); -} -``` - -#### Accessing Array Content - -TOML arrays can be deref-ed using integer indices. In general, all access methods on arrays are named `toml_*_at()`. - -To obtain the size of an array: -```c -int size = toml_array_nelem(arr); -``` - -To obtain the content of an array, use a valid index and call one of these functions: -```c -toml_string_at(arr, idx); -toml_bool_at(arr, idx); -toml_int_at(arr, idx); -toml_double_at(arr, idx); -toml_timestamp_at(arr, idx); -toml_table_at(arr, idx); -toml_array_at(arr, idx); -``` - -#### toml_datum_t - -Some `toml_*_at` and `toml_*_in` functions return a toml_datum_t -structure. The `ok` flag in the structure indicates if the function -call was successful. If so, you may proceed to read the value -corresponding to the type of the content. - -For example: -``` -toml_datum_t host = toml_string_in(tab, "host"); -if (host.ok) { - printf("host: %s\n", host.u.s); - free(host.u.s); /* FREE applies to string and timestamp types only */ -} -``` - -** IMPORTANT: if the accessed value is a string or a timestamp, you must call `free(datum.u.s)` or `free(datum.u.ts)` respectively after usage. ** - -## Building and installing - -A normal *make* suffices. You can also simply include the -`toml.c` and `toml.h` files in your project. - -Invoking `make install` will install the header and library files into -/usr/local/{include,lib}. - -Alternatively, specify `make install prefix=/a/file/path` to install into -/a/file/path/{include,lib}. - -## Testing - -To test against the standard test set provided by BurntSushi/toml-test: - -```sh -% make -% cd test1 -% bash build.sh # do this once -% bash run.sh # this will run the test suite -``` - - -To test against the standard test set provided by iarna/toml: - -```sh -% make -% cd test2 -% bash build.sh # do this once -% bash run.sh # this will run the test suite -``` diff --git a/libraries/tomlc99/include/toml.h b/libraries/tomlc99/include/toml.h deleted file mode 100644 index b91ef890..00000000 --- a/libraries/tomlc99/include/toml.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - MIT License - - Copyright (c) 2017 - 2019 CK Tan - https://github.com/cktan/tomlc99 - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ -#ifndef TOML_H -#define TOML_H - - -#include -#include - - -#ifdef __cplusplus -#define TOML_EXTERN extern "C" -#else -#define TOML_EXTERN extern -#endif - -typedef struct toml_timestamp_t toml_timestamp_t; -typedef struct toml_table_t toml_table_t; -typedef struct toml_array_t toml_array_t; -typedef struct toml_datum_t toml_datum_t; - -/* Parse a file. Return a table on success, or 0 otherwise. - * Caller must toml_free(the-return-value) after use. - */ -TOML_EXTERN toml_table_t* toml_parse_file(FILE* fp, - char* errbuf, - int errbufsz); - -/* Parse a string containing the full config. - * Return a table on success, or 0 otherwise. - * Caller must toml_free(the-return-value) after use. - */ -TOML_EXTERN toml_table_t* toml_parse(char* conf, /* NUL terminated, please. */ - char* errbuf, - int errbufsz); - -/* Free the table returned by toml_parse() or toml_parse_file(). Once - * this function is called, any handles accessed through this tab - * directly or indirectly are no longer valid. - */ -TOML_EXTERN void toml_free(toml_table_t* tab); - - -/* Timestamp types. The year, month, day, hour, minute, second, z - * fields may be NULL if they are not relevant. e.g. In a DATE - * type, the hour, minute, second and z fields will be NULLs. - */ -struct toml_timestamp_t { - struct { /* internal. do not use. */ - int year, month, day; - int hour, minute, second, millisec; - char z[10]; - } __buffer; - int *year, *month, *day; - int *hour, *minute, *second, *millisec; - char* z; -}; - - -/*----------------------------------------------------------------- - * Enhanced access methods - */ -struct toml_datum_t { - int ok; - union { - toml_timestamp_t* ts; /* ts must be freed after use */ - char* s; /* string value. s must be freed after use */ - int b; /* bool value */ - int64_t i; /* int value */ - double d; /* double value */ - } u; -}; - -/* on arrays: */ -/* ... retrieve size of array. */ -TOML_EXTERN int toml_array_nelem(const toml_array_t* arr); -/* ... retrieve values using index. */ -TOML_EXTERN toml_datum_t toml_string_at(const toml_array_t* arr, int idx); -TOML_EXTERN toml_datum_t toml_bool_at(const toml_array_t* arr, int idx); -TOML_EXTERN toml_datum_t toml_int_at(const toml_array_t* arr, int idx); -TOML_EXTERN toml_datum_t toml_double_at(const toml_array_t* arr, int idx); -TOML_EXTERN toml_datum_t toml_timestamp_at(const toml_array_t* arr, int idx); -/* ... retrieve array or table using index. */ -TOML_EXTERN toml_array_t* toml_array_at(const toml_array_t* arr, int idx); -TOML_EXTERN toml_table_t* toml_table_at(const toml_array_t* arr, int idx); - -/* on tables: */ -/* ... retrieve the key in table at keyidx. Return 0 if out of range. */ -TOML_EXTERN const char* toml_key_in(const toml_table_t* tab, int keyidx); -/* ... retrieve values using key. */ -TOML_EXTERN toml_datum_t toml_string_in(const toml_table_t* arr, const char* key); -TOML_EXTERN toml_datum_t toml_bool_in(const toml_table_t* arr, const char* key); -TOML_EXTERN toml_datum_t toml_int_in(const toml_table_t* arr, const char* key); -TOML_EXTERN toml_datum_t toml_double_in(const toml_table_t* arr, const char* key); -TOML_EXTERN toml_datum_t toml_timestamp_in(const toml_table_t* arr, const char* key); -/* .. retrieve array or table using key. */ -TOML_EXTERN toml_array_t* toml_array_in(const toml_table_t* tab, - const char* key); -TOML_EXTERN toml_table_t* toml_table_in(const toml_table_t* tab, - const char* key); - -/*----------------------------------------------------------------- - * lesser used - */ -/* Return the array kind: 't'able, 'a'rray, 'v'alue, 'm'ixed */ -TOML_EXTERN char toml_array_kind(const toml_array_t* arr); - -/* For array kind 'v'alue, return the type of values - i:int, d:double, b:bool, s:string, t:time, D:date, T:timestamp, 'm'ixed - 0 if unknown -*/ -TOML_EXTERN char toml_array_type(const toml_array_t* arr); - -/* Return the key of an array */ -TOML_EXTERN const char* toml_array_key(const toml_array_t* arr); - -/* Return the number of key-values in a table */ -TOML_EXTERN int toml_table_nkval(const toml_table_t* tab); - -/* Return the number of arrays in a table */ -TOML_EXTERN int toml_table_narr(const toml_table_t* tab); - -/* Return the number of sub-tables in a table */ -TOML_EXTERN int toml_table_ntab(const toml_table_t* tab); - -/* Return the key of a table*/ -TOML_EXTERN const char* toml_table_key(const toml_table_t* tab); - -/*-------------------------------------------------------------- - * misc - */ -TOML_EXTERN int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret); -TOML_EXTERN int toml_ucs_to_utf8(int64_t code, char buf[6]); -TOML_EXTERN void toml_set_memutil(void* (*xxmalloc)(size_t), - void (*xxfree)(void*)); - - -/*-------------------------------------------------------------- - * deprecated - */ -/* A raw value, must be processed by toml_rto* before using. */ -typedef const char* toml_raw_t; -TOML_EXTERN toml_raw_t toml_raw_in(const toml_table_t* tab, const char* key); -TOML_EXTERN toml_raw_t toml_raw_at(const toml_array_t* arr, int idx); -TOML_EXTERN int toml_rtos(toml_raw_t s, char** ret); -TOML_EXTERN int toml_rtob(toml_raw_t s, int* ret); -TOML_EXTERN int toml_rtoi(toml_raw_t s, int64_t* ret); -TOML_EXTERN int toml_rtod(toml_raw_t s, double* ret); -TOML_EXTERN int toml_rtod_ex(toml_raw_t s, double* ret, char* buf, int buflen); -TOML_EXTERN int toml_rtots(toml_raw_t s, toml_timestamp_t* ret); - - -#endif /* TOML_H */ diff --git a/libraries/tomlc99/src/toml.c b/libraries/tomlc99/src/toml.c deleted file mode 100644 index e46e62e6..00000000 --- a/libraries/tomlc99/src/toml.c +++ /dev/null @@ -1,2300 +0,0 @@ -/* - - MIT License - - Copyright (c) 2017 - 2021 CK Tan - https://github.com/cktan/tomlc99 - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - -*/ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include -#include -#include "toml.h" - - -static void* (*ppmalloc)(size_t) = malloc; -static void (*ppfree)(void*) = free; - -void toml_set_memutil(void* (*xxmalloc)(size_t), - void (*xxfree)(void*)) -{ - if (xxmalloc) ppmalloc = xxmalloc; - if (xxfree) ppfree = xxfree; -} - - -#define MALLOC(a) ppmalloc(a) -#define FREE(a) ppfree(a) - -static void* CALLOC(size_t nmemb, size_t sz) -{ - int nb = sz * nmemb; - void* p = MALLOC(nb); - if (p) { - memset(p, 0, nb); - } - return p; -} - - -static char* STRDUP(const char* s) -{ - int len = strlen(s); - char* p = MALLOC(len+1); - if (p) { - memcpy(p, s, len); - p[len] = 0; - } - return p; -} - -static char* STRNDUP(const char* s, size_t n) -{ - size_t len = strnlen(s, n); - char* p = MALLOC(len+1); - if (p) { - memcpy(p, s, len); - p[len] = 0; - } - return p; -} - - - -/** - * Convert a char in utf8 into UCS, and store it in *ret. - * Return #bytes consumed or -1 on failure. - */ -int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret) -{ - const unsigned char* buf = (const unsigned char*) orig; - unsigned i = *buf++; - int64_t v; - - /* 0x00000000 - 0x0000007F: - 0xxxxxxx - */ - if (0 == (i >> 7)) { - if (len < 1) return -1; - v = i; - return *ret = v, 1; - } - /* 0x00000080 - 0x000007FF: - 110xxxxx 10xxxxxx - */ - if (0x6 == (i >> 5)) { - if (len < 2) return -1; - v = i & 0x1f; - for (int j = 0; j < 1; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } - - /* 0x00000800 - 0x0000FFFF: - 1110xxxx 10xxxxxx 10xxxxxx - */ - if (0xE == (i >> 4)) { - if (len < 3) return -1; - v = i & 0x0F; - for (int j = 0; j < 2; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } - - /* 0x00010000 - 0x001FFFFF: - 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (0x1E == (i >> 3)) { - if (len < 4) return -1; - v = i & 0x07; - for (int j = 0; j < 3; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } - - /* 0x00200000 - 0x03FFFFFF: - 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (0x3E == (i >> 2)) { - if (len < 5) return -1; - v = i & 0x03; - for (int j = 0; j < 4; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } - - /* 0x04000000 - 0x7FFFFFFF: - 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (0x7e == (i >> 1)) { - if (len < 6) return -1; - v = i & 0x01; - for (int j = 0; j < 5; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } - return -1; -} - - -/** - * Convert a UCS char to utf8 code, and return it in buf. - * Return #bytes used in buf to encode the char, or - * -1 on error. - */ -int toml_ucs_to_utf8(int64_t code, char buf[6]) -{ - /* http://stackoverflow.com/questions/6240055/manually-converting-unicode-codepoints-into-utf-8-and-utf-16 */ - /* The UCS code values 0xd800–0xdfff (UTF-16 surrogates) as well - * as 0xfffe and 0xffff (UCS noncharacters) should not appear in - * conforming UTF-8 streams. - */ - if (0xd800 <= code && code <= 0xdfff) return -1; - if (0xfffe <= code && code <= 0xffff) return -1; - - /* 0x00000000 - 0x0000007F: - 0xxxxxxx - */ - if (code < 0) return -1; - if (code <= 0x7F) { - buf[0] = (unsigned char) code; - return 1; - } - - /* 0x00000080 - 0x000007FF: - 110xxxxx 10xxxxxx - */ - if (code <= 0x000007FF) { - buf[0] = 0xc0 | (code >> 6); - buf[1] = 0x80 | (code & 0x3f); - return 2; - } - - /* 0x00000800 - 0x0000FFFF: - 1110xxxx 10xxxxxx 10xxxxxx - */ - if (code <= 0x0000FFFF) { - buf[0] = 0xe0 | (code >> 12); - buf[1] = 0x80 | ((code >> 6) & 0x3f); - buf[2] = 0x80 | (code & 0x3f); - return 3; - } - - /* 0x00010000 - 0x001FFFFF: - 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (code <= 0x001FFFFF) { - buf[0] = 0xf0 | (code >> 18); - buf[1] = 0x80 | ((code >> 12) & 0x3f); - buf[2] = 0x80 | ((code >> 6) & 0x3f); - buf[3] = 0x80 | (code & 0x3f); - return 4; - } - - /* 0x00200000 - 0x03FFFFFF: - 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (code <= 0x03FFFFFF) { - buf[0] = 0xf8 | (code >> 24); - buf[1] = 0x80 | ((code >> 18) & 0x3f); - buf[2] = 0x80 | ((code >> 12) & 0x3f); - buf[3] = 0x80 | ((code >> 6) & 0x3f); - buf[4] = 0x80 | (code & 0x3f); - return 5; - } - - /* 0x04000000 - 0x7FFFFFFF: - 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (code <= 0x7FFFFFFF) { - buf[0] = 0xfc | (code >> 30); - buf[1] = 0x80 | ((code >> 24) & 0x3f); - buf[2] = 0x80 | ((code >> 18) & 0x3f); - buf[3] = 0x80 | ((code >> 12) & 0x3f); - buf[4] = 0x80 | ((code >> 6) & 0x3f); - buf[5] = 0x80 | (code & 0x3f); - return 6; - } - - return -1; -} - -/* - * TOML has 3 data structures: value, array, table. - * Each of them can have identification key. - */ -typedef struct toml_keyval_t toml_keyval_t; -struct toml_keyval_t { - const char* key; /* key to this value */ - const char* val; /* the raw value */ -}; - -typedef struct toml_arritem_t toml_arritem_t; -struct toml_arritem_t { - int valtype; /* for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, 'D'ate, 'T'imestamp */ - char* val; - toml_array_t* arr; - toml_table_t* tab; -}; - - -struct toml_array_t { - const char* key; /* key to this array */ - int kind; /* element kind: 'v'alue, 'a'rray, or 't'able, 'm'ixed */ - int type; /* for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, 'D'ate, 'T'imestamp, 'm'ixed */ - - int nitem; /* number of elements */ - toml_arritem_t* item; -}; - - -struct toml_table_t { - const char* key; /* key to this table */ - bool implicit; /* table was created implicitly */ - bool readonly; /* no more modification allowed */ - - /* key-values in the table */ - int nkval; - toml_keyval_t** kval; - - /* arrays in the table */ - int narr; - toml_array_t** arr; - - /* tables in the table */ - int ntab; - toml_table_t** tab; -}; - - -static inline void xfree(const void* x) { if (x) FREE((void*)(intptr_t)x); } - - -enum tokentype_t { - INVALID, - DOT, - COMMA, - EQUAL, - LBRACE, - RBRACE, - NEWLINE, - LBRACKET, - RBRACKET, - STRING, -}; -typedef enum tokentype_t tokentype_t; - -typedef struct token_t token_t; -struct token_t { - tokentype_t tok; - int lineno; - char* ptr; /* points into context->start */ - int len; - int eof; -}; - - -typedef struct context_t context_t; -struct context_t { - char* start; - char* stop; - char* errbuf; - int errbufsz; - - token_t tok; - toml_table_t* root; - toml_table_t* curtab; - - struct { - int top; - char* key[10]; - token_t tok[10]; - } tpath; - -}; - -#define STRINGIFY(x) #x -#define TOSTRING(x) STRINGIFY(x) -#define FLINE __FILE__ ":" TOSTRING(__LINE__) - -static int next_token(context_t* ctx, int dotisspecial); - -/* - Error reporting. Call when an error is detected. Always return -1. -*/ -static int e_outofmemory(context_t* ctx, const char* fline) -{ - snprintf(ctx->errbuf, ctx->errbufsz, "ERROR: out of memory (%s)", fline); - return -1; -} - - -static int e_internal(context_t* ctx, const char* fline) -{ - snprintf(ctx->errbuf, ctx->errbufsz, "internal error (%s)", fline); - return -1; -} - -static int e_syntax(context_t* ctx, int lineno, const char* msg) -{ - snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, msg); - return -1; -} - -static int e_badkey(context_t* ctx, int lineno) -{ - snprintf(ctx->errbuf, ctx->errbufsz, "line %d: bad key", lineno); - return -1; -} - -static int e_keyexists(context_t* ctx, int lineno) -{ - snprintf(ctx->errbuf, ctx->errbufsz, "line %d: key exists", lineno); - return -1; -} - -static int e_forbid(context_t* ctx, int lineno, const char* msg) -{ - snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, msg); - return -1; -} - -static void* expand(void* p, int sz, int newsz) -{ - void* s = MALLOC(newsz); - if (!s) return 0; - - memcpy(s, p, sz); - FREE(p); - return s; -} - -static void** expand_ptrarr(void** p, int n) -{ - void** s = MALLOC((n+1) * sizeof(void*)); - if (!s) return 0; - - s[n] = 0; - memcpy(s, p, n * sizeof(void*)); - FREE(p); - return s; -} - -static toml_arritem_t* expand_arritem(toml_arritem_t* p, int n) -{ - toml_arritem_t* pp = expand(p, n*sizeof(*p), (n+1)*sizeof(*p)); - if (!pp) return 0; - - memset(&pp[n], 0, sizeof(pp[n])); - return pp; -} - - -static char* norm_lit_str(const char* src, int srclen, - int multiline, - char* errbuf, int errbufsz) -{ - char* dst = 0; /* will write to dst[] and return it */ - int max = 0; /* max size of dst[] */ - int off = 0; /* cur offset in dst[] */ - const char* sp = src; - const char* sq = src + srclen; - int ch; - - /* scan forward on src */ - for (;;) { - if (off >= max - 10) { /* have some slack for misc stuff */ - int newmax = max + 50; - char* x = expand(dst, max, newmax); - if (!x) { - xfree(dst); - snprintf(errbuf, errbufsz, "out of memory"); - return 0; - } - dst = x; - max = newmax; - } - - /* finished? */ - if (sp >= sq) break; - - ch = *sp++; - /* control characters other than tab is not allowed */ - if ((0 <= ch && ch <= 0x08) - || (0x0a <= ch && ch <= 0x1f) - || (ch == 0x7f)) { - if (! (multiline && (ch == '\r' || ch == '\n'))) { - xfree(dst); - snprintf(errbuf, errbufsz, "invalid char U+%04x", ch); - return 0; - } - } - - // a plain copy suffice - dst[off++] = ch; - } - - dst[off++] = 0; - return dst; -} - - - - -/* - * Convert src to raw unescaped utf-8 string. - * Returns NULL if error with errmsg in errbuf. - */ -static char* norm_basic_str(const char* src, int srclen, - int multiline, - char* errbuf, int errbufsz) -{ - char* dst = 0; /* will write to dst[] and return it */ - int max = 0; /* max size of dst[] */ - int off = 0; /* cur offset in dst[] */ - const char* sp = src; - const char* sq = src + srclen; - int ch; - - /* scan forward on src */ - for (;;) { - if (off >= max - 10) { /* have some slack for misc stuff */ - int newmax = max + 50; - char* x = expand(dst, max, newmax); - if (!x) { - xfree(dst); - snprintf(errbuf, errbufsz, "out of memory"); - return 0; - } - dst = x; - max = newmax; - } - - /* finished? */ - if (sp >= sq) break; - - ch = *sp++; - if (ch != '\\') { - /* these chars must be escaped: U+0000 to U+0008, U+000A to U+001F, U+007F */ - if ((0 <= ch && ch <= 0x08) - || (0x0a <= ch && ch <= 0x1f) - || (ch == 0x7f)) { - if (! (multiline && (ch == '\r' || ch == '\n'))) { - xfree(dst); - snprintf(errbuf, errbufsz, "invalid char U+%04x", ch); - return 0; - } - } - - // a plain copy suffice - dst[off++] = ch; - continue; - } - - /* ch was backslash. we expect the escape char. */ - if (sp >= sq) { - snprintf(errbuf, errbufsz, "last backslash is invalid"); - xfree(dst); - return 0; - } - - /* for multi-line, we want to kill line-ending-backslash ... */ - if (multiline) { - - // if there is only whitespace after the backslash ... - if (sp[strspn(sp, " \t\r")] == '\n') { - /* skip all the following whitespaces */ - sp += strspn(sp, " \t\r\n"); - continue; - } - } - - /* get the escaped char */ - ch = *sp++; - switch (ch) { - case 'u': case 'U': - { - int64_t ucs = 0; - int nhex = (ch == 'u' ? 4 : 8); - for (int i = 0; i < nhex; i++) { - if (sp >= sq) { - snprintf(errbuf, errbufsz, "\\%c expects %d hex chars", ch, nhex); - xfree(dst); - return 0; - } - ch = *sp++; - int v = ('0' <= ch && ch <= '9') - ? ch - '0' - : (('A' <= ch && ch <= 'F') ? ch - 'A' + 10 : -1); - if (-1 == v) { - snprintf(errbuf, errbufsz, "invalid hex chars for \\u or \\U"); - xfree(dst); - return 0; - } - ucs = ucs * 16 + v; - } - int n = toml_ucs_to_utf8(ucs, &dst[off]); - if (-1 == n) { - snprintf(errbuf, errbufsz, "illegal ucs code in \\u or \\U"); - xfree(dst); - return 0; - } - off += n; - } - continue; - - case 'b': ch = '\b'; break; - case 't': ch = '\t'; break; - case 'n': ch = '\n'; break; - case 'f': ch = '\f'; break; - case 'r': ch = '\r'; break; - case '"': ch = '"'; break; - case '\\': ch = '\\'; break; - default: - snprintf(errbuf, errbufsz, "illegal escape char \\%c", ch); - xfree(dst); - return 0; - } - - dst[off++] = ch; - } - - // Cap with NUL and return it. - dst[off++] = 0; - return dst; -} - - -/* Normalize a key. Convert all special chars to raw unescaped utf-8 chars. */ -static char* normalize_key(context_t* ctx, token_t strtok) -{ - const char* sp = strtok.ptr; - const char* sq = strtok.ptr + strtok.len; - int lineno = strtok.lineno; - char* ret; - int ch = *sp; - char ebuf[80]; - - /* handle quoted string */ - if (ch == '\'' || ch == '\"') { - /* if ''' or """, take 3 chars off front and back. Else, take 1 char off. */ - int multiline = 0; - if (sp[1] == ch && sp[2] == ch) { - sp += 3, sq -= 3; - multiline = 1; - } - else - sp++, sq--; - - if (ch == '\'') { - /* for single quote, take it verbatim. */ - if (! (ret = STRNDUP(sp, sq - sp))) { - e_outofmemory(ctx, FLINE); - return 0; - } - } else { - /* for double quote, we need to normalize */ - ret = norm_basic_str(sp, sq - sp, multiline, ebuf, sizeof(ebuf)); - if (!ret) { - e_syntax(ctx, lineno, ebuf); - return 0; - } - } - - /* newlines are not allowed in keys */ - if (strchr(ret, '\n')) { - xfree(ret); - e_badkey(ctx, lineno); - return 0; - } - return ret; - } - - /* for bare-key allow only this regex: [A-Za-z0-9_-]+ */ - const char* xp; - for (xp = sp; xp != sq; xp++) { - int k = *xp; - if (isalnum(k)) continue; - if (k == '_' || k == '-') continue; - e_badkey(ctx, lineno); - return 0; - } - - /* dup and return it */ - if (! (ret = STRNDUP(sp, sq - sp))) { - e_outofmemory(ctx, FLINE); - return 0; - } - return ret; -} - - -/* - * Look up key in tab. Return 0 if not found, or - * 'v'alue, 'a'rray or 't'able depending on the element. - */ -static int check_key(toml_table_t* tab, const char* key, - toml_keyval_t** ret_val, - toml_array_t** ret_arr, - toml_table_t** ret_tab) -{ - int i; - void* dummy; - - if (!ret_tab) ret_tab = (toml_table_t**) &dummy; - if (!ret_arr) ret_arr = (toml_array_t**) &dummy; - if (!ret_val) ret_val = (toml_keyval_t**) &dummy; - - *ret_tab = 0; *ret_arr = 0; *ret_val = 0; - - for (i = 0; i < tab->nkval; i++) { - if (0 == strcmp(key, tab->kval[i]->key)) { - *ret_val = tab->kval[i]; - return 'v'; - } - } - for (i = 0; i < tab->narr; i++) { - if (0 == strcmp(key, tab->arr[i]->key)) { - *ret_arr = tab->arr[i]; - return 'a'; - } - } - for (i = 0; i < tab->ntab; i++) { - if (0 == strcmp(key, tab->tab[i]->key)) { - *ret_tab = tab->tab[i]; - return 't'; - } - } - return 0; -} - - -static int key_kind(toml_table_t* tab, const char* key) -{ - return check_key(tab, key, 0, 0, 0); -} - -/* Create a keyval in the table. - */ -static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, token_t keytok) -{ - /* first, normalize the key to be used for lookup. - * remember to free it if we error out. - */ - char* newkey = normalize_key(ctx, keytok); - if (!newkey) return 0; - - /* if key exists: error out. */ - toml_keyval_t* dest = 0; - if (key_kind(tab, newkey)) { - xfree(newkey); - e_keyexists(ctx, keytok.lineno); - return 0; - } - - /* make a new entry */ - int n = tab->nkval; - toml_keyval_t** base; - if (0 == (base = (toml_keyval_t**) expand_ptrarr((void**)tab->kval, n))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; - } - tab->kval = base; - - if (0 == (base[n] = (toml_keyval_t*) CALLOC(1, sizeof(*base[n])))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; - } - dest = tab->kval[tab->nkval++]; - - /* save the key in the new value struct */ - dest->key = newkey; - return dest; -} - - -/* Create a table in the table. - */ -static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab, token_t keytok) -{ - /* first, normalize the key to be used for lookup. - * remember to free it if we error out. - */ - char* newkey = normalize_key(ctx, keytok); - if (!newkey) return 0; - - /* if key exists: error out */ - toml_table_t* dest = 0; - if (check_key(tab, newkey, 0, 0, &dest)) { - xfree(newkey); /* don't need this anymore */ - - /* special case: if table exists, but was created implicitly ... */ - if (dest && dest->implicit) { - /* we make it explicit now, and simply return it. */ - dest->implicit = false; - return dest; - } - e_keyexists(ctx, keytok.lineno); - return 0; - } - - /* create a new table entry */ - int n = tab->ntab; - toml_table_t** base; - if (0 == (base = (toml_table_t**) expand_ptrarr((void**)tab->tab, n))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; - } - tab->tab = base; - - if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; - } - dest = tab->tab[tab->ntab++]; - - /* save the key in the new table struct */ - dest->key = newkey; - return dest; -} - - -/* Create an array in the table. - */ -static toml_array_t* create_keyarray_in_table(context_t* ctx, - toml_table_t* tab, - token_t keytok, - char kind) -{ - /* first, normalize the key to be used for lookup. - * remember to free it if we error out. - */ - char* newkey = normalize_key(ctx, keytok); - if (!newkey) return 0; - - /* if key exists: error out */ - if (key_kind(tab, newkey)) { - xfree(newkey); /* don't need this anymore */ - e_keyexists(ctx, keytok.lineno); - return 0; - } - - /* make a new array entry */ - int n = tab->narr; - toml_array_t** base; - if (0 == (base = (toml_array_t**) expand_ptrarr((void**)tab->arr, n))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; - } - tab->arr = base; - - if (0 == (base[n] = (toml_array_t*) CALLOC(1, sizeof(*base[n])))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; - } - toml_array_t* dest = tab->arr[tab->narr++]; - - /* save the key in the new array struct */ - dest->key = newkey; - dest->kind = kind; - return dest; -} - - -static toml_arritem_t* create_value_in_array(context_t* ctx, - toml_array_t* parent) -{ - const int n = parent->nitem; - toml_arritem_t* base = expand_arritem(parent->item, n); - if (!base) { - e_outofmemory(ctx, FLINE); - return 0; - } - parent->item = base; - parent->nitem++; - return &parent->item[n]; -} - -/* Create an array in an array - */ -static toml_array_t* create_array_in_array(context_t* ctx, - toml_array_t* parent) -{ - const int n = parent->nitem; - toml_arritem_t* base = expand_arritem(parent->item, n); - if (!base) { - e_outofmemory(ctx, FLINE); - return 0; - } - toml_array_t* ret = (toml_array_t*) CALLOC(1, sizeof(toml_array_t)); - if (!ret) { - e_outofmemory(ctx, FLINE); - return 0; - } - base[n].arr = ret; - parent->item = base; - parent->nitem++; - return ret; -} - -/* Create a table in an array - */ -static toml_table_t* create_table_in_array(context_t* ctx, - toml_array_t* parent) -{ - int n = parent->nitem; - toml_arritem_t* base = expand_arritem(parent->item, n); - if (!base) { - e_outofmemory(ctx, FLINE); - return 0; - } - toml_table_t* ret = (toml_table_t*) CALLOC(1, sizeof(toml_table_t)); - if (!ret) { - e_outofmemory(ctx, FLINE); - return 0; - } - base[n].tab = ret; - parent->item = base; - parent->nitem++; - return ret; -} - - -static int skip_newlines(context_t* ctx, int isdotspecial) -{ - while (ctx->tok.tok == NEWLINE) { - if (next_token(ctx, isdotspecial)) return -1; - if (ctx->tok.eof) break; - } - return 0; -} - - -static int parse_keyval(context_t* ctx, toml_table_t* tab); - -static inline int eat_token(context_t* ctx, tokentype_t typ, int isdotspecial, const char* fline) -{ - if (ctx->tok.tok != typ) - return e_internal(ctx, fline); - - if (next_token(ctx, isdotspecial)) - return -1; - - return 0; -} - - - -/* We are at '{ ... }'. - * Parse the table. - */ -static int parse_inline_table(context_t* ctx, toml_table_t* tab) -{ - if (eat_token(ctx, LBRACE, 1, FLINE)) - return -1; - - for (;;) { - if (ctx->tok.tok == NEWLINE) - return e_syntax(ctx, ctx->tok.lineno, "newline not allowed in inline table"); - - /* until } */ - if (ctx->tok.tok == RBRACE) - break; - - if (ctx->tok.tok != STRING) - return e_syntax(ctx, ctx->tok.lineno, "expect a string"); - - if (parse_keyval(ctx, tab)) - return -1; - - if (ctx->tok.tok == NEWLINE) - return e_syntax(ctx, ctx->tok.lineno, "newline not allowed in inline table"); - - /* on comma, continue to scan for next keyval */ - if (ctx->tok.tok == COMMA) { - if (eat_token(ctx, COMMA, 1, FLINE)) - return -1; - continue; - } - break; - } - - if (eat_token(ctx, RBRACE, 1, FLINE)) - return -1; - - tab->readonly = 1; - - return 0; -} - -static int valtype(const char* val) -{ - toml_timestamp_t ts; - if (*val == '\'' || *val == '"') return 's'; - if (0 == toml_rtob(val, 0)) return 'b'; - if (0 == toml_rtoi(val, 0)) return 'i'; - if (0 == toml_rtod(val, 0)) return 'd'; - if (0 == toml_rtots(val, &ts)) { - if (ts.year && ts.hour) return 'T'; /* timestamp */ - if (ts.year) return 'D'; /* date */ - return 't'; /* time */ - } - return 'u'; /* unknown */ -} - - -/* We are at '[...]' */ -static int parse_array(context_t* ctx, toml_array_t* arr) -{ - if (eat_token(ctx, LBRACKET, 0, FLINE)) return -1; - - for (;;) { - if (skip_newlines(ctx, 0)) return -1; - - /* until ] */ - if (ctx->tok.tok == RBRACKET) break; - - switch (ctx->tok.tok) { - case STRING: - { - /* set array kind if this will be the first entry */ - if (arr->kind == 0) - arr->kind = 'v'; - else if (arr->kind != 'v') - arr->kind = 'm'; - - char* val = ctx->tok.ptr; - int vlen = ctx->tok.len; - - /* make a new value in array */ - toml_arritem_t* newval = create_value_in_array(ctx, arr); - if (!newval) - return e_outofmemory(ctx, FLINE); - - if (! (newval->val = STRNDUP(val, vlen))) - return e_outofmemory(ctx, FLINE); - - newval->valtype = valtype(newval->val); - - /* set array type if this is the first entry */ - if (arr->nitem == 1) - arr->type = newval->valtype; - else if (arr->type != newval->valtype) - arr->type = 'm'; /* mixed */ - - if (eat_token(ctx, STRING, 0, FLINE)) return -1; - break; - } - - case LBRACKET: - { /* [ [array], [array] ... ] */ - /* set the array kind if this will be the first entry */ - if (arr->kind == 0) - arr->kind = 'a'; - else if (arr->kind != 'a') - arr->kind = 'm'; - - toml_array_t* subarr = create_array_in_array(ctx, arr); - if (!subarr) return -1; - if (parse_array(ctx, subarr)) return -1; - break; - } - - case LBRACE: - { /* [ {table}, {table} ... ] */ - /* set the array kind if this will be the first entry */ - if (arr->kind == 0) - arr->kind = 't'; - else if (arr->kind != 't') - arr->kind = 'm'; - - toml_table_t* subtab = create_table_in_array(ctx, arr); - if (!subtab) return -1; - if (parse_inline_table(ctx, subtab)) return -1; - break; - } - - default: - return e_syntax(ctx, ctx->tok.lineno, "syntax error"); - } - - if (skip_newlines(ctx, 0)) return -1; - - /* on comma, continue to scan for next element */ - if (ctx->tok.tok == COMMA) { - if (eat_token(ctx, COMMA, 0, FLINE)) return -1; - continue; - } - break; - } - - if (eat_token(ctx, RBRACKET, 1, FLINE)) return -1; - return 0; -} - - -/* handle lines like these: - key = "value" - key = [ array ] - key = { table } -*/ -static int parse_keyval(context_t* ctx, toml_table_t* tab) -{ - if (tab->readonly) { - return e_forbid(ctx, ctx->tok.lineno, "cannot insert new entry into existing table"); - } - - token_t key = ctx->tok; - if (eat_token(ctx, STRING, 1, FLINE)) return -1; - - if (ctx->tok.tok == DOT) { - /* handle inline dotted key. - e.g. - physical.color = "orange" - physical.shape = "round" - */ - toml_table_t* subtab = 0; - { - char* subtabstr = normalize_key(ctx, key); - if (!subtabstr) return -1; - - subtab = toml_table_in(tab, subtabstr); - xfree(subtabstr); - } - if (!subtab) { - subtab = create_keytable_in_table(ctx, tab, key); - if (!subtab) return -1; - } - if (next_token(ctx, 1)) return -1; - if (parse_keyval(ctx, subtab)) return -1; - return 0; - } - - if (ctx->tok.tok != EQUAL) { - return e_syntax(ctx, ctx->tok.lineno, "missing ="); - } - - if (next_token(ctx, 0)) return -1; - - switch (ctx->tok.tok) { - case STRING: - { /* key = "value" */ - toml_keyval_t* keyval = create_keyval_in_table(ctx, tab, key); - if (!keyval) return -1; - token_t val = ctx->tok; - - assert(keyval->val == 0); - if (! (keyval->val = STRNDUP(val.ptr, val.len))) - return e_outofmemory(ctx, FLINE); - - if (next_token(ctx, 1)) return -1; - - return 0; - } - - case LBRACKET: - { /* key = [ array ] */ - toml_array_t* arr = create_keyarray_in_table(ctx, tab, key, 0); - if (!arr) return -1; - if (parse_array(ctx, arr)) return -1; - return 0; - } - - case LBRACE: - { /* key = { table } */ - toml_table_t* nxttab = create_keytable_in_table(ctx, tab, key); - if (!nxttab) return -1; - if (parse_inline_table(ctx, nxttab)) return -1; - return 0; - } - - default: - return e_syntax(ctx, ctx->tok.lineno, "syntax error"); - } - return 0; -} - - -typedef struct tabpath_t tabpath_t; -struct tabpath_t { - int cnt; - token_t key[10]; -}; - -/* at [x.y.z] or [[x.y.z]] - * Scan forward and fill tabpath until it enters ] or ]] - * There will be at least one entry on return. - */ -static int fill_tabpath(context_t* ctx) -{ - int lineno = ctx->tok.lineno; - int i; - - /* clear tpath */ - for (i = 0; i < ctx->tpath.top; i++) { - char** p = &ctx->tpath.key[i]; - xfree(*p); - *p = 0; - } - ctx->tpath.top = 0; - - for (;;) { - if (ctx->tpath.top >= 10) - return e_syntax(ctx, lineno, "table path is too deep; max allowed is 10."); - - if (ctx->tok.tok != STRING) - return e_syntax(ctx, lineno, "invalid or missing key"); - - char* key = normalize_key(ctx, ctx->tok); - if (!key) return -1; - ctx->tpath.tok[ctx->tpath.top] = ctx->tok; - ctx->tpath.key[ctx->tpath.top] = key; - ctx->tpath.top++; - - if (next_token(ctx, 1)) return -1; - - if (ctx->tok.tok == RBRACKET) break; - - if (ctx->tok.tok != DOT) - return e_syntax(ctx, lineno, "invalid key"); - - if (next_token(ctx, 1)) return -1; - } - - if (ctx->tpath.top <= 0) - return e_syntax(ctx, lineno, "empty table selector"); - - return 0; -} - - -/* Walk tabpath from the root, and create new tables on the way. - * Sets ctx->curtab to the final table. - */ -static int walk_tabpath(context_t* ctx) -{ - /* start from root */ - toml_table_t* curtab = ctx->root; - - for (int i = 0; i < ctx->tpath.top; i++) { - const char* key = ctx->tpath.key[i]; - - toml_keyval_t* nextval = 0; - toml_array_t* nextarr = 0; - toml_table_t* nexttab = 0; - switch (check_key(curtab, key, &nextval, &nextarr, &nexttab)) { - case 't': - /* found a table. nexttab is where we will go next. */ - break; - - case 'a': - /* found an array. nexttab is the last table in the array. */ - if (nextarr->kind != 't') - return e_internal(ctx, FLINE); - - if (nextarr->nitem == 0) - return e_internal(ctx, FLINE); - - nexttab = nextarr->item[nextarr->nitem-1].tab; - break; - - case 'v': - return e_keyexists(ctx, ctx->tpath.tok[i].lineno); - - default: - { /* Not found. Let's create an implicit table. */ - int n = curtab->ntab; - toml_table_t** base = (toml_table_t**) expand_ptrarr((void**)curtab->tab, n); - if (0 == base) - return e_outofmemory(ctx, FLINE); - - curtab->tab = base; - - if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) - return e_outofmemory(ctx, FLINE); - - if (0 == (base[n]->key = STRDUP(key))) - return e_outofmemory(ctx, FLINE); - - nexttab = curtab->tab[curtab->ntab++]; - - /* tabs created by walk_tabpath are considered implicit */ - nexttab->implicit = true; - } - break; - } - - /* switch to next tab */ - curtab = nexttab; - } - - /* save it */ - ctx->curtab = curtab; - - return 0; -} - - -/* handle lines like [x.y.z] or [[x.y.z]] */ -static int parse_select(context_t* ctx) -{ - assert(ctx->tok.tok == LBRACKET); - - /* true if [[ */ - int llb = (ctx->tok.ptr + 1 < ctx->stop && ctx->tok.ptr[1] == '['); - /* need to detect '[[' on our own because next_token() will skip whitespace, - and '[ [' would be taken as '[[', which is wrong. */ - - /* eat [ or [[ */ - if (eat_token(ctx, LBRACKET, 1, FLINE)) return -1; - if (llb) { - assert(ctx->tok.tok == LBRACKET); - if (eat_token(ctx, LBRACKET, 1, FLINE)) return -1; - } - - if (fill_tabpath(ctx)) return -1; - - /* For [x.y.z] or [[x.y.z]], remove z from tpath. - */ - token_t z = ctx->tpath.tok[ctx->tpath.top-1]; - xfree(ctx->tpath.key[ctx->tpath.top-1]); - ctx->tpath.top--; - - /* set up ctx->curtab */ - if (walk_tabpath(ctx)) return -1; - - if (! llb) { - /* [x.y.z] -> create z = {} in x.y */ - toml_table_t* curtab = create_keytable_in_table(ctx, ctx->curtab, z); - if (!curtab) return -1; - ctx->curtab = curtab; - } else { - /* [[x.y.z]] -> create z = [] in x.y */ - toml_array_t* arr = 0; - { - char* zstr = normalize_key(ctx, z); - if (!zstr) return -1; - arr = toml_array_in(ctx->curtab, zstr); - xfree(zstr); - } - if (!arr) { - arr = create_keyarray_in_table(ctx, ctx->curtab, z, 't'); - if (!arr) return -1; - } - if (arr->kind != 't') - return e_syntax(ctx, z.lineno, "array mismatch"); - - /* add to z[] */ - toml_table_t* dest; - { - toml_table_t* t = create_table_in_array(ctx, arr); - if (!t) return -1; - - if (0 == (t->key = STRDUP("__anon__"))) - return e_outofmemory(ctx, FLINE); - - dest = t; - } - - ctx->curtab = dest; - } - - if (ctx->tok.tok != RBRACKET) { - return e_syntax(ctx, ctx->tok.lineno, "expects ]"); - } - if (llb) { - if (! (ctx->tok.ptr + 1 < ctx->stop && ctx->tok.ptr[1] == ']')) { - return e_syntax(ctx, ctx->tok.lineno, "expects ]]"); - } - if (eat_token(ctx, RBRACKET, 1, FLINE)) return -1; - } - - if (eat_token(ctx, RBRACKET, 1, FLINE)) - return -1; - - if (ctx->tok.tok != NEWLINE) - return e_syntax(ctx, ctx->tok.lineno, "extra chars after ] or ]]"); - - return 0; -} - - - - -toml_table_t* toml_parse(char* conf, - char* errbuf, - int errbufsz) -{ - context_t ctx; - - // clear errbuf - if (errbufsz <= 0) errbufsz = 0; - if (errbufsz > 0) errbuf[0] = 0; - - // init context - memset(&ctx, 0, sizeof(ctx)); - ctx.start = conf; - ctx.stop = ctx.start + strlen(conf); - ctx.errbuf = errbuf; - ctx.errbufsz = errbufsz; - - // start with an artificial newline of length 0 - ctx.tok.tok = NEWLINE; - ctx.tok.lineno = 1; - ctx.tok.ptr = conf; - ctx.tok.len = 0; - - // make a root table - if (0 == (ctx.root = CALLOC(1, sizeof(*ctx.root)))) { - e_outofmemory(&ctx, FLINE); - // Do not goto fail, root table not set up yet - return 0; - } - - // set root as default table - ctx.curtab = ctx.root; - - /* Scan forward until EOF */ - for (token_t tok = ctx.tok; ! tok.eof ; tok = ctx.tok) { - switch (tok.tok) { - - case NEWLINE: - if (next_token(&ctx, 1)) goto fail; - break; - - case STRING: - if (parse_keyval(&ctx, ctx.curtab)) goto fail; - - if (ctx.tok.tok != NEWLINE) { - e_syntax(&ctx, ctx.tok.lineno, "extra chars after value"); - goto fail; - } - - if (eat_token(&ctx, NEWLINE, 1, FLINE)) goto fail; - break; - - case LBRACKET: /* [ x.y.z ] or [[ x.y.z ]] */ - if (parse_select(&ctx)) goto fail; - break; - - default: - e_syntax(&ctx, tok.lineno, "syntax error"); - goto fail; - } - } - - /* success */ - for (int i = 0; i < ctx.tpath.top; i++) xfree(ctx.tpath.key[i]); - return ctx.root; - -fail: - // Something bad has happened. Free resources and return error. - for (int i = 0; i < ctx.tpath.top; i++) xfree(ctx.tpath.key[i]); - toml_free(ctx.root); - return 0; -} - - -toml_table_t* toml_parse_file(FILE* fp, - char* errbuf, - int errbufsz) -{ - int bufsz = 0; - char* buf = 0; - int off = 0; - - /* read from fp into buf */ - while (! feof(fp)) { - - if (off == bufsz) { - int xsz = bufsz + 1000; - char* x = expand(buf, bufsz, xsz); - if (!x) { - snprintf(errbuf, errbufsz, "out of memory"); - xfree(buf); - return 0; - } - buf = x; - bufsz = xsz; - } - - errno = 0; - int n = fread(buf + off, 1, bufsz - off, fp); - if (ferror(fp)) { - snprintf(errbuf, errbufsz, "%s", - errno ? strerror(errno) : "Error reading file"); - xfree(buf); - return 0; - } - off += n; - } - - /* tag on a NUL to cap the string */ - if (off == bufsz) { - int xsz = bufsz + 1; - char* x = expand(buf, bufsz, xsz); - if (!x) { - snprintf(errbuf, errbufsz, "out of memory"); - xfree(buf); - return 0; - } - buf = x; - bufsz = xsz; - } - buf[off] = 0; - - /* parse it, cleanup and finish */ - toml_table_t* ret = toml_parse(buf, errbuf, errbufsz); - xfree(buf); - return ret; -} - - -static void xfree_kval(toml_keyval_t* p) -{ - if (!p) return; - xfree(p->key); - xfree(p->val); - xfree(p); -} - -static void xfree_tab(toml_table_t* p); - -static void xfree_arr(toml_array_t* p) -{ - if (!p) return; - - xfree(p->key); - const int n = p->nitem; - for (int i = 0; i < n; i++) { - toml_arritem_t* a = &p->item[i]; - if (a->val) - xfree(a->val); - else if (a->arr) - xfree_arr(a->arr); - else if (a->tab) - xfree_tab(a->tab); - } - xfree(p->item); - xfree(p); -} - - -static void xfree_tab(toml_table_t* p) -{ - int i; - - if (!p) return; - - xfree(p->key); - - for (i = 0; i < p->nkval; i++) xfree_kval(p->kval[i]); - xfree(p->kval); - - for (i = 0; i < p->narr; i++) xfree_arr(p->arr[i]); - xfree(p->arr); - - for (i = 0; i < p->ntab; i++) xfree_tab(p->tab[i]); - xfree(p->tab); - - xfree(p); -} - - -void toml_free(toml_table_t* tab) -{ - xfree_tab(tab); -} - - -static void set_token(context_t* ctx, tokentype_t tok, int lineno, char* ptr, int len) -{ - token_t t; - t.tok = tok; - t.lineno = lineno; - t.ptr = ptr; - t.len = len; - t.eof = 0; - ctx->tok = t; -} - -static void set_eof(context_t* ctx, int lineno) -{ - set_token(ctx, NEWLINE, lineno, ctx->stop, 0); - ctx->tok.eof = 1; -} - - -/* Scan p for n digits compositing entirely of [0-9] */ -static int scan_digits(const char* p, int n) -{ - int ret = 0; - for ( ; n > 0 && isdigit(*p); n--, p++) { - ret = 10 * ret + (*p - '0'); - } - return n ? -1 : ret; -} - -static int scan_date(const char* p, int* YY, int* MM, int* DD) -{ - int year, month, day; - year = scan_digits(p, 4); - month = (year >= 0 && p[4] == '-') ? scan_digits(p+5, 2) : -1; - day = (month >= 0 && p[7] == '-') ? scan_digits(p+8, 2) : -1; - if (YY) *YY = year; - if (MM) *MM = month; - if (DD) *DD = day; - return (year >= 0 && month >= 0 && day >= 0) ? 0 : -1; -} - -static int scan_time(const char* p, int* hh, int* mm, int* ss) -{ - int hour, minute, second; - hour = scan_digits(p, 2); - minute = (hour >= 0 && p[2] == ':') ? scan_digits(p+3, 2) : -1; - second = (minute >= 0 && p[5] == ':') ? scan_digits(p+6, 2) : -1; - if (hh) *hh = hour; - if (mm) *mm = minute; - if (ss) *ss = second; - return (hour >= 0 && minute >= 0 && second >= 0) ? 0 : -1; -} - - -static int scan_string(context_t* ctx, char* p, int lineno, int dotisspecial) -{ - char* orig = p; - if (0 == strncmp(p, "'''", 3)) { - char* q = p + 3; - - while (1) { - q = strstr(q, "'''"); - if (0 == q) { - return e_syntax(ctx, lineno, "unterminated triple-s-quote"); - } - while (q[3] == '\'') q++; - break; - } - - set_token(ctx, STRING, lineno, orig, q + 3 - orig); - return 0; - } - - if (0 == strncmp(p, "\"\"\"", 3)) { - char* q = p + 3; - - while (1) { - q = strstr(q, "\"\"\""); - if (0 == q) { - return e_syntax(ctx, lineno, "unterminated triple-d-quote"); - } - if (q[-1] == '\\') { - q++; - continue; - } - while (q[3] == '\"') q++; - break; - } - - // the string is [p+3, q-1] - - int hexreq = 0; /* #hex required */ - int escape = 0; - for (p += 3; p < q; p++) { - if (escape) { - escape = 0; - if (strchr("btnfr\"\\", *p)) continue; - if (*p == 'u') { hexreq = 4; continue; } - if (*p == 'U') { hexreq = 8; continue; } - if (p[strspn(p, " \t\r")] == '\n') continue; /* allow for line ending backslash */ - return e_syntax(ctx, lineno, "bad escape char"); - } - if (hexreq) { - hexreq--; - if (strchr("0123456789ABCDEF", *p)) continue; - return e_syntax(ctx, lineno, "expect hex char"); - } - if (*p == '\\') { escape = 1; continue; } - } - if (escape) - return e_syntax(ctx, lineno, "expect an escape char"); - if (hexreq) - return e_syntax(ctx, lineno, "expected more hex char"); - - set_token(ctx, STRING, lineno, orig, q + 3 - orig); - return 0; - } - - if ('\'' == *p) { - for (p++; *p && *p != '\n' && *p != '\''; p++); - if (*p != '\'') { - return e_syntax(ctx, lineno, "unterminated s-quote"); - } - - set_token(ctx, STRING, lineno, orig, p + 1 - orig); - return 0; - } - - if ('\"' == *p) { - int hexreq = 0; /* #hex required */ - int escape = 0; - for (p++; *p; p++) { - if (escape) { - escape = 0; - if (strchr("btnfr\"\\", *p)) continue; - if (*p == 'u') { hexreq = 4; continue; } - if (*p == 'U') { hexreq = 8; continue; } - return e_syntax(ctx, lineno, "bad escape char"); - } - if (hexreq) { - hexreq--; - if (strchr("0123456789ABCDEF", *p)) continue; - return e_syntax(ctx, lineno, "expect hex char"); - } - if (*p == '\\') { escape = 1; continue; } - if (*p == '\'') { - if (p[1] == '\'' && p[2] == '\'') { - return e_syntax(ctx, lineno, "triple-s-quote inside string lit"); - } - continue; - } - if (*p == '\n') break; - if (*p == '"') break; - } - if (*p != '"') { - return e_syntax(ctx, lineno, "unterminated quote"); - } - - set_token(ctx, STRING, lineno, orig, p + 1 - orig); - return 0; - } - - /* check for timestamp without quotes */ - if (0 == scan_date(p, 0, 0, 0) || 0 == scan_time(p, 0, 0, 0)) { - // forward thru the timestamp - for ( ; strchr("0123456789.:+-T Z", toupper(*p)); p++); - // squeeze out any spaces at end of string - for ( ; p[-1] == ' '; p--); - // tokenize - set_token(ctx, STRING, lineno, orig, p - orig); - return 0; - } - - /* literals */ - for ( ; *p && *p != '\n'; p++) { - int ch = *p; - if (ch == '.' && dotisspecial) break; - if ('A' <= ch && ch <= 'Z') continue; - if ('a' <= ch && ch <= 'z') continue; - if (strchr("0123456789+-_.", ch)) continue; - break; - } - - set_token(ctx, STRING, lineno, orig, p - orig); - return 0; -} - - -static int next_token(context_t* ctx, int dotisspecial) -{ - int lineno = ctx->tok.lineno; - char* p = ctx->tok.ptr; - int i; - - /* eat this tok */ - for (i = 0; i < ctx->tok.len; i++) { - if (*p++ == '\n') - lineno++; - } - - /* make next tok */ - while (p < ctx->stop) { - /* skip comment. stop just before the \n. */ - if (*p == '#') { - for (p++; p < ctx->stop && *p != '\n'; p++); - continue; - } - - if (dotisspecial && *p == '.') { - set_token(ctx, DOT, lineno, p, 1); - return 0; - } - - switch (*p) { - case ',': set_token(ctx, COMMA, lineno, p, 1); return 0; - case '=': set_token(ctx, EQUAL, lineno, p, 1); return 0; - case '{': set_token(ctx, LBRACE, lineno, p, 1); return 0; - case '}': set_token(ctx, RBRACE, lineno, p, 1); return 0; - case '[': set_token(ctx, LBRACKET, lineno, p, 1); return 0; - case ']': set_token(ctx, RBRACKET, lineno, p, 1); return 0; - case '\n': set_token(ctx, NEWLINE, lineno, p, 1); return 0; - case '\r': case ' ': case '\t': - /* ignore white spaces */ - p++; - continue; - } - - return scan_string(ctx, p, lineno, dotisspecial); - } - - set_eof(ctx, lineno); - return 0; -} - - -const char* toml_key_in(const toml_table_t* tab, int keyidx) -{ - if (keyidx < tab->nkval) return tab->kval[keyidx]->key; - - keyidx -= tab->nkval; - if (keyidx < tab->narr) return tab->arr[keyidx]->key; - - keyidx -= tab->narr; - if (keyidx < tab->ntab) return tab->tab[keyidx]->key; - - return 0; -} - -toml_raw_t toml_raw_in(const toml_table_t* tab, const char* key) -{ - int i; - for (i = 0; i < tab->nkval; i++) { - if (0 == strcmp(key, tab->kval[i]->key)) - return tab->kval[i]->val; - } - return 0; -} - -toml_array_t* toml_array_in(const toml_table_t* tab, const char* key) -{ - int i; - for (i = 0; i < tab->narr; i++) { - if (0 == strcmp(key, tab->arr[i]->key)) - return tab->arr[i]; - } - return 0; -} - - -toml_table_t* toml_table_in(const toml_table_t* tab, const char* key) -{ - int i; - for (i = 0; i < tab->ntab; i++) { - if (0 == strcmp(key, tab->tab[i]->key)) - return tab->tab[i]; - } - return 0; -} - -toml_raw_t toml_raw_at(const toml_array_t* arr, int idx) -{ - return (0 <= idx && idx < arr->nitem) ? arr->item[idx].val : 0; -} - -char toml_array_kind(const toml_array_t* arr) -{ - return arr->kind; -} - -char toml_array_type(const toml_array_t* arr) -{ - if (arr->kind != 'v') - return 0; - - if (arr->nitem == 0) - return 0; - - return arr->type; -} - - -int toml_array_nelem(const toml_array_t* arr) -{ - return arr->nitem; -} - -const char* toml_array_key(const toml_array_t* arr) -{ - return arr ? arr->key : (const char*) NULL; -} - -int toml_table_nkval(const toml_table_t* tab) -{ - return tab->nkval; -} - -int toml_table_narr(const toml_table_t* tab) -{ - return tab->narr; -} - -int toml_table_ntab(const toml_table_t* tab) -{ - return tab->ntab; -} - -const char* toml_table_key(const toml_table_t* tab) -{ - return tab ? tab->key : (const char*) NULL; -} - -toml_array_t* toml_array_at(const toml_array_t* arr, int idx) -{ - return (0 <= idx && idx < arr->nitem) ? arr->item[idx].arr : 0; -} - -toml_table_t* toml_table_at(const toml_array_t* arr, int idx) -{ - return (0 <= idx && idx < arr->nitem) ? arr->item[idx].tab : 0; -} - - -int toml_rtots(toml_raw_t src_, toml_timestamp_t* ret) -{ - if (! src_) return -1; - - const char* p = src_; - int must_parse_time = 0; - - memset(ret, 0, sizeof(*ret)); - - int* year = &ret->__buffer.year; - int* month = &ret->__buffer.month; - int* day = &ret->__buffer.day; - int* hour = &ret->__buffer.hour; - int* minute = &ret->__buffer.minute; - int* second = &ret->__buffer.second; - int* millisec = &ret->__buffer.millisec; - - /* parse date YYYY-MM-DD */ - if (0 == scan_date(p, year, month, day)) { - ret->year = year; - ret->month = month; - ret->day = day; - - p += 10; - if (*p) { - // parse the T or space separator - if (*p != 'T' && *p != ' ') return -1; - must_parse_time = 1; - p++; - } - } - - /* parse time HH:MM:SS */ - if (0 == scan_time(p, hour, minute, second)) { - ret->hour = hour; - ret->minute = minute; - ret->second = second; - - /* optionally, parse millisec */ - p += 8; - if (*p == '.') { - char* qq; - p++; - errno = 0; - *millisec = strtol(p, &qq, 0); - if (errno) { - return -1; - } - while (*millisec > 999) { - *millisec /= 10; - } - - ret->millisec = millisec; - p = qq; - } - - if (*p) { - /* parse and copy Z */ - char* z = ret->__buffer.z; - ret->z = z; - if (*p == 'Z' || *p == 'z') { - *z++ = 'Z'; p++; - *z = 0; - - } else if (*p == '+' || *p == '-') { - *z++ = *p++; - - if (! (isdigit(p[0]) && isdigit(p[1]))) return -1; - *z++ = *p++; - *z++ = *p++; - - if (*p == ':') { - *z++ = *p++; - - if (! (isdigit(p[0]) && isdigit(p[1]))) return -1; - *z++ = *p++; - *z++ = *p++; - } - - *z = 0; - } - } - } - if (*p != 0) - return -1; - - if (must_parse_time && !ret->hour) - return -1; - - return 0; -} - - -/* Raw to boolean */ -int toml_rtob(toml_raw_t src, int* ret_) -{ - if (!src) return -1; - int dummy; - int* ret = ret_ ? ret_ : &dummy; - - if (0 == strcmp(src, "true")) { - *ret = 1; - return 0; - } - if (0 == strcmp(src, "false")) { - *ret = 0; - return 0; - } - return -1; -} - - -/* Raw to integer */ -int toml_rtoi(toml_raw_t src, int64_t* ret_) -{ - if (!src) return -1; - - char buf[100]; - char* p = buf; - char* q = p + sizeof(buf); - const char* s = src; - int base = 0; - int64_t dummy; - int64_t* ret = ret_ ? ret_ : &dummy; - - - /* allow +/- */ - if (s[0] == '+' || s[0] == '-') - *p++ = *s++; - - /* disallow +_100 */ - if (s[0] == '_') - return -1; - - /* if 0 ... */ - if ('0' == s[0]) { - switch (s[1]) { - case 'x': base = 16; s += 2; break; - case 'o': base = 8; s += 2; break; - case 'b': base = 2; s += 2; break; - case '\0': return *ret = 0, 0; - default: - /* ensure no other digits after it */ - if (s[1]) return -1; - } - } - - /* just strip underscores and pass to strtoll */ - while (*s && p < q) { - int ch = *s++; - switch (ch) { - case '_': - // disallow '__' - if (s[0] == '_') return -1; - continue; /* skip _ */ - default: - break; - } - *p++ = ch; - } - if (*s || p == q) return -1; - - /* last char cannot be '_' */ - if (s[-1] == '_') return -1; - - /* cap with NUL */ - *p = 0; - - /* Run strtoll on buf to get the integer */ - char* endp; - errno = 0; - *ret = strtoll(buf, &endp, base); - return (errno || *endp) ? -1 : 0; -} - - -int toml_rtod_ex(toml_raw_t src, double* ret_, char* buf, int buflen) -{ - if (!src) return -1; - - char* p = buf; - char* q = p + buflen; - const char* s = src; - double dummy; - double* ret = ret_ ? ret_ : &dummy; - - - /* allow +/- */ - if (s[0] == '+' || s[0] == '-') - *p++ = *s++; - - /* disallow +_1.00 */ - if (s[0] == '_') - return -1; - - /* decimal point, if used, must be surrounded by at least one digit on each side */ - { - char* dot = strchr(s, '.'); - if (dot) { - if (dot == s || !isdigit(dot[-1]) || !isdigit(dot[1])) - return -1; - } - } - - /* zero must be followed by . or 'e', or NUL */ - if (s[0] == '0' && s[1] && !strchr("eE.", s[1])) - return -1; - - /* just strip underscores and pass to strtod */ - while (*s && p < q) { - int ch = *s++; - if (ch == '_') { - // disallow '__' - if (s[0] == '_') return -1; - // disallow last char '_' - if (s[0] == 0) return -1; - continue; /* skip _ */ - } - *p++ = ch; - } - if (*s || p == q) return -1; /* reached end of string or buffer is full? */ - - /* cap with NUL */ - *p = 0; - - /* Run strtod on buf to get the value */ - char* endp; - errno = 0; - *ret = strtod(buf, &endp); - return (errno || *endp) ? -1 : 0; -} - -int toml_rtod(toml_raw_t src, double* ret_) -{ - char buf[100]; - return toml_rtod_ex(src, ret_, buf, sizeof(buf)); -} - - - - -int toml_rtos(toml_raw_t src, char** ret) -{ - int multiline = 0; - const char* sp; - const char* sq; - - *ret = 0; - if (!src) return -1; - - int qchar = src[0]; - int srclen = strlen(src); - if (! (qchar == '\'' || qchar == '"')) { - return -1; - } - - // triple quotes? - if (qchar == src[1] && qchar == src[2]) { - multiline = 1; - sp = src + 3; - sq = src + srclen - 3; - /* last 3 chars in src must be qchar */ - if (! (sp <= sq && sq[0] == qchar && sq[1] == qchar && sq[2] == qchar)) - return -1; - - /* skip new line immediate after qchar */ - if (sp[0] == '\n') - sp++; - else if (sp[0] == '\r' && sp[1] == '\n') - sp += 2; - - } else { - sp = src + 1; - sq = src + srclen - 1; - /* last char in src must be qchar */ - if (! (sp <= sq && *sq == qchar)) - return -1; - } - - if (qchar == '\'') { - *ret = norm_lit_str(sp, sq - sp, - multiline, - 0, 0); - } else { - *ret = norm_basic_str(sp, sq - sp, - multiline, - 0, 0); - } - - return *ret ? 0 : -1; -} - - -toml_datum_t toml_string_at(const toml_array_t* arr, int idx) -{ - toml_datum_t ret; - memset(&ret, 0, sizeof(ret)); - ret.ok = (0 == toml_rtos(toml_raw_at(arr, idx), &ret.u.s)); - return ret; -} - -toml_datum_t toml_bool_at(const toml_array_t* arr, int idx) -{ - toml_datum_t ret; - memset(&ret, 0, sizeof(ret)); - ret.ok = (0 == toml_rtob(toml_raw_at(arr, idx), &ret.u.b)); - return ret; -} - -toml_datum_t toml_int_at(const toml_array_t* arr, int idx) -{ - toml_datum_t ret; - memset(&ret, 0, sizeof(ret)); - ret.ok = (0 == toml_rtoi(toml_raw_at(arr, idx), &ret.u.i)); - return ret; -} - -toml_datum_t toml_double_at(const toml_array_t* arr, int idx) -{ - toml_datum_t ret; - memset(&ret, 0, sizeof(ret)); - ret.ok = (0 == toml_rtod(toml_raw_at(arr, idx), &ret.u.d)); - return ret; -} - -toml_datum_t toml_timestamp_at(const toml_array_t* arr, int idx) -{ - toml_timestamp_t ts; - toml_datum_t ret; - memset(&ret, 0, sizeof(ret)); - ret.ok = (0 == toml_rtots(toml_raw_at(arr, idx), &ts)); - if (ret.ok) { - ret.ok = !!(ret.u.ts = malloc(sizeof(*ret.u.ts))); - if (ret.ok) { - *ret.u.ts = ts; - if (ret.u.ts->year) ret.u.ts->year = &ret.u.ts->__buffer.year; - if (ret.u.ts->month) ret.u.ts->month = &ret.u.ts->__buffer.month; - if (ret.u.ts->day) ret.u.ts->day = &ret.u.ts->__buffer.day; - if (ret.u.ts->hour) ret.u.ts->hour = &ret.u.ts->__buffer.hour; - if (ret.u.ts->minute) ret.u.ts->minute = &ret.u.ts->__buffer.minute; - if (ret.u.ts->second) ret.u.ts->second = &ret.u.ts->__buffer.second; - if (ret.u.ts->millisec) ret.u.ts->millisec = &ret.u.ts->__buffer.millisec; - if (ret.u.ts->z) ret.u.ts->z = ret.u.ts->__buffer.z; - } - } - return ret; -} - -toml_datum_t toml_string_in(const toml_table_t* arr, const char* key) -{ - toml_datum_t ret; - memset(&ret, 0, sizeof(ret)); - toml_raw_t raw = toml_raw_in(arr, key); - if (raw) { - ret.ok = (0 == toml_rtos(raw, &ret.u.s)); - } - return ret; -} - -toml_datum_t toml_bool_in(const toml_table_t* arr, const char* key) -{ - toml_datum_t ret; - memset(&ret, 0, sizeof(ret)); - ret.ok = (0 == toml_rtob(toml_raw_in(arr, key), &ret.u.b)); - return ret; -} - -toml_datum_t toml_int_in(const toml_table_t* arr, const char* key) -{ - toml_datum_t ret; - memset(&ret, 0, sizeof(ret)); - ret.ok = (0 == toml_rtoi(toml_raw_in(arr, key), &ret.u.i)); - return ret; -} - -toml_datum_t toml_double_in(const toml_table_t* arr, const char* key) -{ - toml_datum_t ret; - memset(&ret, 0, sizeof(ret)); - ret.ok = (0 == toml_rtod(toml_raw_in(arr, key), &ret.u.d)); - return ret; -} - -toml_datum_t toml_timestamp_in(const toml_table_t* arr, const char* key) -{ - toml_timestamp_t ts; - toml_datum_t ret; - memset(&ret, 0, sizeof(ret)); - ret.ok = (0 == toml_rtots(toml_raw_in(arr, key), &ts)); - if (ret.ok) { - ret.ok = !!(ret.u.ts = malloc(sizeof(*ret.u.ts))); - if (ret.ok) { - *ret.u.ts = ts; - if (ret.u.ts->year) ret.u.ts->year = &ret.u.ts->__buffer.year; - if (ret.u.ts->month) ret.u.ts->month = &ret.u.ts->__buffer.month; - if (ret.u.ts->day) ret.u.ts->day = &ret.u.ts->__buffer.day; - if (ret.u.ts->hour) ret.u.ts->hour = &ret.u.ts->__buffer.hour; - if (ret.u.ts->minute) ret.u.ts->minute = &ret.u.ts->__buffer.minute; - if (ret.u.ts->second) ret.u.ts->second = &ret.u.ts->__buffer.second; - if (ret.u.ts->millisec) ret.u.ts->millisec = &ret.u.ts->__buffer.millisec; - if (ret.u.ts->z) ret.u.ts->z = ret.u.ts->__buffer.z; - } - } - return ret; -}