From 0b38d878a104029892590ff7a60226ae4077aeb4 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Mon, 2 May 2022 16:27:15 +0200 Subject: [PATCH 01/52] fix: remove in-tree CMake modules where possible --- cmake/BundleUtilities.cmake | 786 --------------------------- cmake/GetPrerequisites.cmake | 902 ------------------------------- cmake/UseJava.cmake | 881 ------------------------------ cmake/UseJavaClassFilelist.cmake | 52 -- cmake/UseJavaSymlinks.cmake | 32 -- 5 files changed, 2653 deletions(-) delete mode 100644 cmake/BundleUtilities.cmake delete mode 100644 cmake/GetPrerequisites.cmake delete mode 100644 cmake/UseJava.cmake delete mode 100644 cmake/UseJavaClassFilelist.cmake delete mode 100644 cmake/UseJavaSymlinks.cmake diff --git a/cmake/BundleUtilities.cmake b/cmake/BundleUtilities.cmake deleted file mode 100644 index e3f50b94c..000000000 --- a/cmake/BundleUtilities.cmake +++ /dev/null @@ -1,786 +0,0 @@ -# - Functions to help assemble a standalone bundle application. -# A collection of CMake utility functions useful for dealing with .app -# bundles on the Mac and bundle-like directories on any OS. -# -# The following functions are provided by this module: -# fixup_bundle -# copy_and_fixup_bundle -# verify_app -# get_bundle_main_executable -# get_dotapp_dir -# get_bundle_and_executable -# get_bundle_all_executables -# get_item_key -# clear_bundle_keys -# set_bundle_key_values -# get_bundle_keys -# copy_resolved_item_into_bundle -# copy_resolved_framework_into_bundle -# fixup_bundle_item -# verify_bundle_prerequisites -# verify_bundle_symlinks -# Requires CMake 2.6 or greater because it uses function, break and -# PARENT_SCOPE. Also depends on GetPrerequisites.cmake. -# -# FIXUP_BUNDLE( ) -# Fix up a bundle in-place and make it standalone, such that it can be -# drag-n-drop copied to another machine and run on that machine as long as all -# of the system libraries are compatible. -# -# If you pass plugins to fixup_bundle as the libs parameter, you should install -# them or copy them into the bundle before calling fixup_bundle. The "libs" -# parameter is a list of libraries that must be fixed up, but that cannot be -# determined by otool output analysis. (i.e., plugins) -# -# Gather all the keys for all the executables and libraries in a bundle, and -# then, for each key, copy each prerequisite into the bundle. Then fix each one -# up according to its own list of prerequisites. -# -# Then clear all the keys and call verify_app on the final bundle to ensure -# that it is truly standalone. -# -# COPY_AND_FIXUP_BUNDLE( ) -# Makes a copy of the bundle at location and then fixes up the -# new copied bundle in-place at ... -# -# VERIFY_APP() -# Verifies that an application appears valid based on running analysis -# tools on it. Calls "message(FATAL_ERROR" if the application is not verified. -# -# GET_BUNDLE_MAIN_EXECUTABLE( ) -# The result will be the full path name of the bundle's main executable file -# or an "error:" prefixed string if it could not be determined. -# -# GET_DOTAPP_DIR( ) -# Returns the nearest parent dir whose name ends with ".app" given the full -# path to an executable. If there is no such parent dir, then simply return -# the dir containing the executable. -# -# The returned directory may or may not exist. -# -# GET_BUNDLE_AND_EXECUTABLE( ) -# Takes either a ".app" directory name or the name of an executable -# nested inside a ".app" directory and returns the path to the ".app" -# directory in and the path to its main executable in -# -# -# GET_BUNDLE_ALL_EXECUTABLES( ) -# Scans the given bundle recursively for all executable files and accumulates -# them into a variable. -# -# GET_ITEM_KEY( ) -# Given a file (item) name, generate a key that should be unique considering -# the set of libraries that need copying or fixing up to make a bundle -# standalone. This is essentially the file name including extension with "." -# replaced by "_" -# -# This key is used as a prefix for CMake variables so that we can associate a -# set of variables with a given item based on its key. -# -# CLEAR_BUNDLE_KEYS() -# Loop over the list of keys, clearing all the variables associated with each -# key. After the loop, clear the list of keys itself. -# -# Caller of get_bundle_keys should call clear_bundle_keys when done with list -# of keys. -# -# SET_BUNDLE_KEY_VALUES( -# ) -# Add a key to the list (if necessary) for the given item. If added, -# also set all the variables associated with that key. -# -# GET_BUNDLE_KEYS( ) -# Loop over all the executable and library files within the bundle (and given -# as extra ) and accumulate a list of keys representing them. Set -# values associated with each key such that we can loop over all of them and -# copy prerequisite libs into the bundle and then do appropriate -# install_name_tool fixups. -# -# COPY_RESOLVED_ITEM_INTO_BUNDLE( ) -# Copy a resolved item into the bundle if necessary. Copy is not necessary if -# the resolved_item is "the same as" the resolved_embedded_item. -# -# COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE( ) -# Copy a resolved framework into the bundle if necessary. Copy is not necessary -# if the resolved_item is "the same as" the resolved_embedded_item. -# -# By default, BU_COPY_FULL_FRAMEWORK_CONTENTS is not set. If you want full -# frameworks embedded in your bundles, set BU_COPY_FULL_FRAMEWORK_CONTENTS to -# ON before calling fixup_bundle. By default, -# COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE copies the framework dylib itself plus -# the framework Resources directory. -# -# FIXUP_BUNDLE_ITEM( ) -# Get the direct/non-system prerequisites of the resolved embedded item. For -# each prerequisite, change the way it is referenced to the value of the -# _EMBEDDED_ITEM keyed variable for that prerequisite. (Most likely changing to -# an "@executable_path" style reference.) -# -# This function requires that the resolved_embedded_item be "inside" the bundle -# already. In other words, if you pass plugins to fixup_bundle as the libs -# parameter, you should install them or copy them into the bundle before -# calling fixup_bundle. The "libs" parameter is a list of libraries that must -# be fixed up, but that cannot be determined by otool output analysis. (i.e., -# plugins) -# -# Also, change the id of the item being fixed up to its own _EMBEDDED_ITEM -# value. -# -# Accumulate changes in a local variable and make *one* call to -# install_name_tool at the end of the function with all the changes at once. -# -# If the BU_CHMOD_BUNDLE_ITEMS variable is set then bundle items will be -# marked writable before install_name_tool tries to change them. -# -# VERIFY_BUNDLE_PREREQUISITES( ) -# Verifies that the sum of all prerequisites of all files inside the bundle -# are contained within the bundle or are "system" libraries, presumed to exist -# everywhere. -# -# VERIFY_BUNDLE_SYMLINKS( ) -# Verifies that any symlinks found in the bundle point to other files that are -# already also in the bundle... Anything that points to an external file causes -# this function to fail the verification. - -#============================================================================= -# Copyright 2008-2009 Kitware, Inc. -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -# The functions defined in this file depend on the get_prerequisites function -# (and possibly others) found in: -# -get_filename_component(BundleUtilities_cmake_dir "${CMAKE_CURRENT_LIST_FILE}" PATH) -include("${BundleUtilities_cmake_dir}/GetPrerequisites.cmake") - - -function(get_bundle_main_executable bundle result_var) - set(result "error: '${bundle}/Contents/Info.plist' file does not exist") - - if(EXISTS "${bundle}/Contents/Info.plist") - set(result "error: no CFBundleExecutable in '${bundle}/Contents/Info.plist' file") - set(line_is_main_executable 0) - set(bundle_executable "") - - # Read Info.plist as a list of lines: - # - set(eol_char "E") - file(READ "${bundle}/Contents/Info.plist" info_plist) - string(REGEX REPLACE ";" "\\\\;" info_plist "${info_plist}") - string(REGEX REPLACE "\n" "${eol_char};" info_plist "${info_plist}") - - # Scan the lines for "CFBundleExecutable" - the line after that - # is the name of the main executable. - # - foreach(line ${info_plist}) - if(line_is_main_executable) - string(REGEX REPLACE "^.*(.*).*$" "\\1" bundle_executable "${line}") - break() - endif() - - if(line MATCHES "^.*CFBundleExecutable.*$") - set(line_is_main_executable 1) - endif() - endforeach() - - if(NOT "${bundle_executable}" STREQUAL "") - if(EXISTS "${bundle}/Contents/MacOS/${bundle_executable}") - set(result "${bundle}/Contents/MacOS/${bundle_executable}") - else() - - # Ultimate goal: - # If not in "Contents/MacOS" then scan the bundle for matching files. If - # there is only one executable file that matches, then use it, otherwise - # it's an error... - # - #file(GLOB_RECURSE file_list "${bundle}/${bundle_executable}") - - # But for now, pragmatically, it's an error. Expect the main executable - # for the bundle to be in Contents/MacOS, it's an error if it's not: - # - set(result "error: '${bundle}/Contents/MacOS/${bundle_executable}' does not exist") - endif() - endif() - else() - # - # More inclusive technique... (This one would work on Windows and Linux - # too, if a developer followed the typical Mac bundle naming convention...) - # - # If there is no Info.plist file, try to find an executable with the same - # base name as the .app directory: - # - endif() - - set(${result_var} "${result}" PARENT_SCOPE) -endfunction() - - -function(get_dotapp_dir exe dotapp_dir_var) - set(s "${exe}") - - if(s MATCHES "^.*/.*\\.app/.*$") - # If there is a ".app" parent directory, - # ascend until we hit it: - # (typical of a Mac bundle executable) - # - set(done 0) - while(NOT ${done}) - get_filename_component(snamewe "${s}" NAME_WE) - get_filename_component(sname "${s}" NAME) - get_filename_component(sdir "${s}" PATH) - set(s "${sdir}") - if(sname MATCHES "\\.app$") - set(done 1) - set(dotapp_dir "${sdir}/${sname}") - endif() - endwhile() - else() - # Otherwise use a directory containing the exe - # (typical of a non-bundle executable on Mac, Windows or Linux) - # - is_file_executable("${s}" is_executable) - if(is_executable) - get_filename_component(sdir "${s}" PATH) - set(dotapp_dir "${sdir}") - else() - set(dotapp_dir "${s}") - endif() - endif() - - - set(${dotapp_dir_var} "${dotapp_dir}" PARENT_SCOPE) -endfunction() - - -function(get_bundle_and_executable app bundle_var executable_var valid_var) - set(valid 0) - - if(EXISTS "${app}") - # Is it a directory ending in .app? - if(IS_DIRECTORY "${app}") - if(app MATCHES "\\.app$") - get_bundle_main_executable("${app}" executable) - if(EXISTS "${app}" AND EXISTS "${executable}") - set(${bundle_var} "${app}" PARENT_SCOPE) - set(${executable_var} "${executable}" PARENT_SCOPE) - set(valid 1) - #message(STATUS "info: handled .app directory case...") - else() - message(STATUS "warning: *NOT* handled - .app directory case...") - endif() - else() - message(STATUS "warning: *NOT* handled - directory but not .app case...") - endif() - else() - # Is it an executable file? - is_file_executable("${app}" is_executable) - if(is_executable) - get_dotapp_dir("${app}" dotapp_dir) - if(EXISTS "${dotapp_dir}") - set(${bundle_var} "${dotapp_dir}" PARENT_SCOPE) - set(${executable_var} "${app}" PARENT_SCOPE) - set(valid 1) - #message(STATUS "info: handled executable file in .app dir case...") - else() - get_filename_component(app_dir "${app}" PATH) - set(${bundle_var} "${app_dir}" PARENT_SCOPE) - set(${executable_var} "${app}" PARENT_SCOPE) - set(valid 1) - #message(STATUS "info: handled executable file in any dir case...") - endif() - else() - message(STATUS "warning: *NOT* handled - not .app dir, not executable file...") - endif() - endif() - else() - message(STATUS "warning: *NOT* handled - directory/file ${app} does not exist...") - endif() - - if(NOT valid) - set(${bundle_var} "error: not a bundle" PARENT_SCOPE) - set(${executable_var} "error: not a bundle" PARENT_SCOPE) - endif() - - set(${valid_var} ${valid} PARENT_SCOPE) -endfunction() - - -function(get_bundle_all_executables bundle exes_var) - set(exes "") - - file(GLOB_RECURSE file_list "${bundle}/*") - foreach(f ${file_list}) - is_file_executable("${f}" is_executable) - if(is_executable) - set(exes ${exes} "${f}") - endif() - endforeach() - - set(${exes_var} "${exes}" PARENT_SCOPE) -endfunction() - - -function(get_item_key item key_var) - get_filename_component(item_name "${item}" NAME) - if(WIN32) - string(TOLOWER "${item_name}" item_name) - endif() - string(REGEX REPLACE "\\." "_" ${key_var} "${item_name}") - set(${key_var} ${${key_var}} PARENT_SCOPE) -endfunction() - - -function(clear_bundle_keys keys_var) - foreach(key ${${keys_var}}) - set(${key}_ITEM PARENT_SCOPE) - set(${key}_RESOLVED_ITEM PARENT_SCOPE) - set(${key}_DEFAULT_EMBEDDED_PATH PARENT_SCOPE) - set(${key}_EMBEDDED_ITEM PARENT_SCOPE) - set(${key}_RESOLVED_EMBEDDED_ITEM PARENT_SCOPE) - set(${key}_COPYFLAG PARENT_SCOPE) - endforeach() - set(${keys_var} PARENT_SCOPE) -endfunction() - - -function(set_bundle_key_values keys_var context item exepath dirs copyflag) - get_filename_component(item_name "${item}" NAME) - - get_item_key("${item}" key) - - list(LENGTH ${keys_var} length_before) - gp_append_unique(${keys_var} "${key}") - list(LENGTH ${keys_var} length_after) - - if(NOT length_before EQUAL length_after) - gp_resolve_item("${context}" "${item}" "${exepath}" "${dirs}" resolved_item) - - gp_item_default_embedded_path("${item}" default_embedded_path) - - if(item MATCHES "[^/]+\\.framework/") - # For frameworks, construct the name under the embedded path from the - # opening "${item_name}.framework/" to the closing "/${item_name}": - # - string(REGEX REPLACE "^.*(${item_name}.framework/.*/?${item_name}).*$" "${default_embedded_path}/\\1" embedded_item "${item}") - else() - # For other items, just use the same name as the original, but in the - # embedded path: - # - set(embedded_item "${default_embedded_path}/${item_name}") - endif() - - # Replace @executable_path and resolve ".." references: - # - string(REPLACE "@executable_path" "${exepath}" resolved_embedded_item "${embedded_item}") - get_filename_component(resolved_embedded_item "${resolved_embedded_item}" ABSOLUTE) - - # *But* -- if we are not copying, then force resolved_embedded_item to be - # the same as resolved_item. In the case of multiple executables in the - # original bundle, using the default_embedded_path results in looking for - # the resolved executable next to the main bundle executable. This is here - # so that exes in the other sibling directories (like "bin") get fixed up - # properly... - # - if(NOT copyflag) - set(resolved_embedded_item "${resolved_item}") - endif() - - set(${keys_var} ${${keys_var}} PARENT_SCOPE) - set(${key}_ITEM "${item}" PARENT_SCOPE) - set(${key}_RESOLVED_ITEM "${resolved_item}" PARENT_SCOPE) - set(${key}_DEFAULT_EMBEDDED_PATH "${default_embedded_path}" PARENT_SCOPE) - set(${key}_EMBEDDED_ITEM "${embedded_item}" PARENT_SCOPE) - set(${key}_RESOLVED_EMBEDDED_ITEM "${resolved_embedded_item}" PARENT_SCOPE) - set(${key}_COPYFLAG "${copyflag}" PARENT_SCOPE) - else() - #message("warning: item key '${key}' already in the list, subsequent references assumed identical to first") - endif() -endfunction() - - -function(get_bundle_keys app libs dirs keys_var) - set(${keys_var} PARENT_SCOPE) - - get_bundle_and_executable("${app}" bundle executable valid) - if(valid) - # Always use the exepath of the main bundle executable for @executable_path - # replacements: - # - get_filename_component(exepath "${executable}" PATH) - - # But do fixups on all executables in the bundle: - # - get_bundle_all_executables("${bundle}" exes) - - # For each extra lib, accumulate a key as well and then also accumulate - # any of its prerequisites. (Extra libs are typically dynamically loaded - # plugins: libraries that are prerequisites for full runtime functionality - # but that do not show up in otool -L output...) - # - foreach(lib ${libs}) - set_bundle_key_values(${keys_var} "${lib}" "${lib}" "${exepath}" "${dirs}" 0) - - set(prereqs "") - get_prerequisites("${lib}" prereqs 1 1 "${exepath}" "${dirs}") - foreach(pr ${prereqs}) - set_bundle_key_values(${keys_var} "${lib}" "${pr}" "${exepath}" "${dirs}" 1) - endforeach() - endforeach() - - # For each executable found in the bundle, accumulate keys as we go. - # The list of keys should be complete when all prerequisites of all - # binaries in the bundle have been analyzed. - # - foreach(exe ${exes}) - # Add the exe itself to the keys: - # - set_bundle_key_values(${keys_var} "${exe}" "${exe}" "${exepath}" "${dirs}" 0) - - # Add each prerequisite to the keys: - # - set(prereqs "") - get_prerequisites("${exe}" prereqs 1 1 "${exepath}" "${dirs}") - foreach(pr ${prereqs}) - set_bundle_key_values(${keys_var} "${exe}" "${pr}" "${exepath}" "${dirs}" 1) - endforeach() - endforeach() - - # Propagate values to caller's scope: - # - set(${keys_var} ${${keys_var}} PARENT_SCOPE) - foreach(key ${${keys_var}}) - set(${key}_ITEM "${${key}_ITEM}" PARENT_SCOPE) - set(${key}_RESOLVED_ITEM "${${key}_RESOLVED_ITEM}" PARENT_SCOPE) - set(${key}_DEFAULT_EMBEDDED_PATH "${${key}_DEFAULT_EMBEDDED_PATH}" PARENT_SCOPE) - set(${key}_EMBEDDED_ITEM "${${key}_EMBEDDED_ITEM}" PARENT_SCOPE) - set(${key}_RESOLVED_EMBEDDED_ITEM "${${key}_RESOLVED_EMBEDDED_ITEM}" PARENT_SCOPE) - set(${key}_COPYFLAG "${${key}_COPYFLAG}" PARENT_SCOPE) - endforeach() - endif() -endfunction() - - -function(copy_resolved_item_into_bundle resolved_item resolved_embedded_item) - if(WIN32) - # ignore case on Windows - string(TOLOWER "${resolved_item}" resolved_item_compare) - string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare) - else() - set(resolved_item_compare "${resolved_item}") - set(resolved_embedded_item_compare "${resolved_embedded_item}") - endif() - - if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}") - message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...") - else() - #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}") - if(UNIX AND NOT APPLE) - file(RPATH_REMOVE FILE "${resolved_embedded_item}") - endif() - endif() - -endfunction() - - -function(copy_resolved_framework_into_bundle resolved_item resolved_embedded_item) - if(WIN32) - # ignore case on Windows - string(TOLOWER "${resolved_item}" resolved_item_compare) - string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare) - else() - set(resolved_item_compare "${resolved_item}") - set(resolved_embedded_item_compare "${resolved_embedded_item}") - endif() - - if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}") - message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...") - else() - if(BU_COPY_FULL_FRAMEWORK_CONTENTS) - # Full Framework (everything): - get_filename_component(resolved_dir "${resolved_item}" PATH) - get_filename_component(resolved_dir "${resolved_dir}/../.." ABSOLUTE) - get_filename_component(resolved_embedded_dir "${resolved_embedded_item}" PATH) - get_filename_component(resolved_embedded_dir "${resolved_embedded_dir}/../.." ABSOLUTE) - #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_dir}' '${resolved_embedded_dir}'") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_dir}" "${resolved_embedded_dir}") - else() - # Framework lib itself: - #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}") - - # Plus Resources, if they exist: - string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1/Resources" resolved_resources "${resolved_item}") - string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1/Resources" resolved_embedded_resources "${resolved_embedded_item}") - if(EXISTS "${resolved_resources}") - #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_resources}' '${resolved_embedded_resources}'") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_resources}" "${resolved_embedded_resources}") - endif() - endif() - if(UNIX AND NOT APPLE) - file(RPATH_REMOVE FILE "${resolved_embedded_item}") - endif() - endif() - -endfunction() - - -function(fixup_bundle_item resolved_embedded_item exepath dirs) - # This item's key is "ikey": - # - get_item_key("${resolved_embedded_item}" ikey) - - # Ensure the item is "inside the .app bundle" -- it should not be fixed up if - # it is not in the .app bundle... Otherwise, we'll modify files in the build - # tree, or in other varied locations around the file system, with our call to - # install_name_tool. Make sure that doesn't happen here: - # - get_dotapp_dir("${exepath}" exe_dotapp_dir) - string(LENGTH "${exe_dotapp_dir}/" exe_dotapp_dir_length) - string(LENGTH "${resolved_embedded_item}" resolved_embedded_item_length) - set(path_too_short 0) - set(is_embedded 0) - if(${resolved_embedded_item_length} LESS ${exe_dotapp_dir_length}) - set(path_too_short 1) - endif() - if(NOT path_too_short) - string(SUBSTRING "${resolved_embedded_item}" 0 ${exe_dotapp_dir_length} item_substring) - if("${exe_dotapp_dir}/" STREQUAL "${item_substring}") - set(is_embedded 1) - endif() - endif() - if(NOT is_embedded) - message(" exe_dotapp_dir/='${exe_dotapp_dir}/'") - message(" item_substring='${item_substring}'") - message(" resolved_embedded_item='${resolved_embedded_item}'") - message("") - message("Install or copy the item into the bundle before calling fixup_bundle.") - message("Or maybe there's a typo or incorrect path in one of the args to fixup_bundle?") - message("") - message(FATAL_ERROR "cannot fixup an item that is not in the bundle...") - endif() - - set(prereqs "") - get_prerequisites("${resolved_embedded_item}" prereqs 1 0 "${exepath}" "${dirs}") - - set(changes "") - - foreach(pr ${prereqs}) - # Each referenced item's key is "rkey" in the loop: - # - get_item_key("${pr}" rkey) - - if(NOT "${${rkey}_EMBEDDED_ITEM}" STREQUAL "") - set(changes ${changes} "-change" "${pr}" "${${rkey}_EMBEDDED_ITEM}") - else() - message("warning: unexpected reference to '${pr}'") - endif() - endforeach() - - if(BU_CHMOD_BUNDLE_ITEMS) - execute_process(COMMAND chmod u+w "${resolved_embedded_item}") - endif() - - # Change this item's id and all of its references in one call - # to install_name_tool: - # - execute_process(COMMAND install_name_tool - ${changes} -id "${${ikey}_EMBEDDED_ITEM}" "${resolved_embedded_item}" - ) -endfunction() - - -function(fixup_bundle app libs dirs) - message(STATUS "fixup_bundle") - message(STATUS " app='${app}'") - message(STATUS " libs='${libs}'") - message(STATUS " dirs='${dirs}'") - - get_bundle_and_executable("${app}" bundle executable valid) - if(valid) - get_filename_component(exepath "${executable}" PATH) - - message(STATUS "fixup_bundle: preparing...") - get_bundle_keys("${app}" "${libs}" "${dirs}" keys) - - message(STATUS "fixup_bundle: copying...") - list(LENGTH keys n) - math(EXPR n ${n}*2) - - set(i 0) - foreach(key ${keys}) - math(EXPR i ${i}+1) - if(${${key}_COPYFLAG}) - message(STATUS "${i}/${n}: copying '${${key}_RESOLVED_ITEM}'") - else() - message(STATUS "${i}/${n}: *NOT* copying '${${key}_RESOLVED_ITEM}'") - endif() - - set(show_status 0) - if(show_status) - message(STATUS "key='${key}'") - message(STATUS "item='${${key}_ITEM}'") - message(STATUS "resolved_item='${${key}_RESOLVED_ITEM}'") - message(STATUS "default_embedded_path='${${key}_DEFAULT_EMBEDDED_PATH}'") - message(STATUS "embedded_item='${${key}_EMBEDDED_ITEM}'") - message(STATUS "resolved_embedded_item='${${key}_RESOLVED_EMBEDDED_ITEM}'") - message(STATUS "copyflag='${${key}_COPYFLAG}'") - message(STATUS "") - endif() - - if(${${key}_COPYFLAG}) - set(item "${${key}_ITEM}") - if(item MATCHES "[^/]+\\.framework/") - copy_resolved_framework_into_bundle("${${key}_RESOLVED_ITEM}" - "${${key}_RESOLVED_EMBEDDED_ITEM}") - else() - copy_resolved_item_into_bundle("${${key}_RESOLVED_ITEM}" - "${${key}_RESOLVED_EMBEDDED_ITEM}") - endif() - endif() - endforeach() - - message(STATUS "fixup_bundle: fixing...") - foreach(key ${keys}) - math(EXPR i ${i}+1) - if(APPLE) - message(STATUS "${i}/${n}: fixing up '${${key}_RESOLVED_EMBEDDED_ITEM}'") - fixup_bundle_item("${${key}_RESOLVED_EMBEDDED_ITEM}" "${exepath}" "${dirs}") - else() - message(STATUS "${i}/${n}: fix-up not required on this platform '${${key}_RESOLVED_EMBEDDED_ITEM}'") - endif() - endforeach() - - message(STATUS "fixup_bundle: cleaning up...") - clear_bundle_keys(keys) - - message(STATUS "fixup_bundle: verifying...") - verify_app("${app}") - else() - message(SEND_ERROR "error: fixup_bundle: not a valid bundle") - endif() - - message(STATUS "fixup_bundle: done") -endfunction() - - -function(copy_and_fixup_bundle src dst libs dirs) - execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${src}" "${dst}") - fixup_bundle("${dst}" "${libs}" "${dirs}") -endfunction() - - -function(verify_bundle_prerequisites bundle result_var info_var) - set(result 1) - set(info "") - set(count 0) - - get_bundle_main_executable("${bundle}" main_bundle_exe) - - file(GLOB_RECURSE file_list "${bundle}/*") - foreach(f ${file_list}) - is_file_executable("${f}" is_executable) - if(is_executable) - get_filename_component(exepath "${f}" PATH) - math(EXPR count "${count} + 1") - - message(STATUS "executable file ${count}: ${f}") - - set(prereqs "") - get_prerequisites("${f}" prereqs 1 1 "${exepath}" "") - - # On the Mac, - # "embedded" and "system" prerequisites are fine... anything else means - # the bundle's prerequisites are not verified (i.e., the bundle is not - # really "standalone") - # - # On Windows (and others? Linux/Unix/...?) - # "local" and "system" prereqs are fine... - # - set(external_prereqs "") - - foreach(p ${prereqs}) - set(p_type "") - gp_file_type("${f}" "${p}" p_type) - - if(APPLE) - if(NOT "${p_type}" STREQUAL "embedded" AND NOT "${p_type}" STREQUAL "system") - set(external_prereqs ${external_prereqs} "${p}") - endif() - else() - if(NOT "${p_type}" STREQUAL "local" AND NOT "${p_type}" STREQUAL "system") - set(external_prereqs ${external_prereqs} "${p}") - endif() - endif() - endforeach() - - if(external_prereqs) - # Found non-system/somehow-unacceptable prerequisites: - set(result 0) - set(info ${info} "external prerequisites found:\nf='${f}'\nexternal_prereqs='${external_prereqs}'\n") - endif() - endif() - endforeach() - - if(result) - set(info "Verified ${count} executable files in '${bundle}'") - endif() - - set(${result_var} "${result}" PARENT_SCOPE) - set(${info_var} "${info}" PARENT_SCOPE) -endfunction() - - -function(verify_bundle_symlinks bundle result_var info_var) - set(result 1) - set(info "") - set(count 0) - - # TODO: implement this function for real... - # Right now, it is just a stub that verifies unconditionally... - - set(${result_var} "${result}" PARENT_SCOPE) - set(${info_var} "${info}" PARENT_SCOPE) -endfunction() - - -function(verify_app app) - set(verified 0) - set(info "") - - get_bundle_and_executable("${app}" bundle executable valid) - - message(STATUS "===========================================================================") - message(STATUS "Analyzing app='${app}'") - message(STATUS "bundle='${bundle}'") - message(STATUS "executable='${executable}'") - message(STATUS "valid='${valid}'") - - # Verify that the bundle does not have any "external" prerequisites: - # - verify_bundle_prerequisites("${bundle}" verified info) - message(STATUS "verified='${verified}'") - message(STATUS "info='${info}'") - message(STATUS "") - - if(verified) - # Verify that the bundle does not have any symlinks to external files: - # - verify_bundle_symlinks("${bundle}" verified info) - message(STATUS "verified='${verified}'") - message(STATUS "info='${info}'") - message(STATUS "") - endif() - - if(NOT verified) - message(FATAL_ERROR "error: verify_app failed") - endif() -endfunction() diff --git a/cmake/GetPrerequisites.cmake b/cmake/GetPrerequisites.cmake deleted file mode 100644 index 39c2cc631..000000000 --- a/cmake/GetPrerequisites.cmake +++ /dev/null @@ -1,902 +0,0 @@ -# - Functions to analyze and list executable file prerequisites. -# This module provides functions to list the .dll, .dylib or .so -# files that an executable or shared library file depends on. (Its -# prerequisites.) -# -# It uses various tools to obtain the list of required shared library files: -# dumpbin (Windows) -# objdump (MinGW on Windows) -# ldd (Linux/Unix) -# otool (Mac OSX) -# The following functions are provided by this module: -# get_prerequisites -# list_prerequisites -# list_prerequisites_by_glob -# gp_append_unique -# is_file_executable -# gp_item_default_embedded_path -# (projects can override with gp_item_default_embedded_path_override) -# gp_resolve_item -# (projects can override with gp_resolve_item_override) -# gp_resolved_file_type -# (projects can override with gp_resolved_file_type_override) -# gp_file_type -# Requires CMake 2.6 or greater because it uses function, break, return and -# PARENT_SCOPE. -# -# GET_PREREQUISITES( -# ) -# Get the list of shared library files required by . The list in -# the variable named should be empty on first entry to -# this function. On exit, will contain the list of -# required shared library files. -# -# is the full path to an executable file. is the -# name of a CMake variable to contain the results. must be 0 -# or 1 indicating whether to include or exclude "system" prerequisites. If -# is set to 1 all prerequisites will be found recursively, if set to -# 0 only direct prerequisites are listed. is the path to the top -# level executable used for @executable_path replacment on the Mac. is -# a list of paths where libraries might be found: these paths are searched -# first when a target without any path info is given. Then standard system -# locations are also searched: PATH, Framework locations, /usr/lib... -# -# LIST_PREREQUISITES( [ [ []]]) -# Print a message listing the prerequisites of . -# -# is the name of a shared library or executable target or the full -# path to a shared library or executable file. If is set to 1 all -# prerequisites will be found recursively, if set to 0 only direct -# prerequisites are listed. must be 0 or 1 indicating whether -# to include or exclude "system" prerequisites. With set to 0 only -# the full path names of the prerequisites are printed, set to 1 extra -# informatin will be displayed. -# -# LIST_PREREQUISITES_BY_GLOB( ) -# Print the prerequisites of shared library and executable files matching a -# globbing pattern. is GLOB or GLOB_RECURSE and is a -# globbing expression used with "file(GLOB" or "file(GLOB_RECURSE" to retrieve -# a list of matching files. If a matching file is executable, its prerequisites -# are listed. -# -# Any additional (optional) arguments provided are passed along as the -# optional arguments to the list_prerequisites calls. -# -# GP_APPEND_UNIQUE( ) -# Append to the list variable only if the value is not -# already in the list. -# -# IS_FILE_EXECUTABLE( ) -# Return 1 in if is a binary executable, 0 otherwise. -# -# GP_ITEM_DEFAULT_EMBEDDED_PATH( ) -# Return the path that others should refer to the item by when the item -# is embedded inside a bundle. -# -# Override on a per-project basis by providing a project-specific -# gp_item_default_embedded_path_override function. -# -# GP_RESOLVE_ITEM( ) -# Resolve an item into an existing full path file. -# -# Override on a per-project basis by providing a project-specific -# gp_resolve_item_override function. -# -# GP_RESOLVED_FILE_TYPE( ) -# Return the type of with respect to . String -# describing type of prerequisite is returned in variable named . -# -# Use and if necessary to resolve non-absolute -# values -- but only for non-embedded items. -# -# Possible types are: -# system -# local -# embedded -# other -# Override on a per-project basis by providing a project-specific -# gp_resolved_file_type_override function. -# -# GP_FILE_TYPE( ) -# Return the type of with respect to . String -# describing type of prerequisite is returned in variable named . -# -# Possible types are: -# system -# local -# embedded -# other - -#============================================================================= -# Copyright 2008-2009 Kitware, Inc. -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -function(gp_append_unique list_var value) - set(contains 0) - - foreach(item ${${list_var}}) - if("${item}" STREQUAL "${value}") - set(contains 1) - break() - endif() - endforeach() - - if(NOT contains) - set(${list_var} ${${list_var}} "${value}" PARENT_SCOPE) - endif() -endfunction() - - -function(is_file_executable file result_var) - # - # A file is not executable until proven otherwise: - # - set(${result_var} 0 PARENT_SCOPE) - - get_filename_component(file_full "${file}" ABSOLUTE) - string(TOLOWER "${file_full}" file_full_lower) - - # If file name ends in .exe on Windows, *assume* executable: - # - if(WIN32 AND NOT UNIX) - if("${file_full_lower}" MATCHES "\\.exe$") - set(${result_var} 1 PARENT_SCOPE) - return() - endif() - - # A clause could be added here that uses output or return value of dumpbin - # to determine ${result_var}. In 99%+? practical cases, the exe name - # match will be sufficient... - # - endif() - - # Use the information returned from the Unix shell command "file" to - # determine if ${file_full} should be considered an executable file... - # - # If the file command's output contains "executable" and does *not* contain - # "text" then it is likely an executable suitable for prerequisite analysis - # via the get_prerequisites macro. - # - if(UNIX) - if(NOT file_cmd) - find_program(file_cmd "file") - mark_as_advanced(file_cmd) - endif() - - if(file_cmd) - execute_process(COMMAND "${file_cmd}" "${file_full}" - OUTPUT_VARIABLE file_ov - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - - # Replace the name of the file in the output with a placeholder token - # (the string " _file_full_ ") so that just in case the path name of - # the file contains the word "text" or "executable" we are not fooled - # into thinking "the wrong thing" because the file name matches the - # other 'file' command output we are looking for... - # - string(REPLACE "${file_full}" " _file_full_ " file_ov "${file_ov}") - string(TOLOWER "${file_ov}" file_ov) - - #message(STATUS "file_ov='${file_ov}'") - if("${file_ov}" MATCHES "executable") - #message(STATUS "executable!") - if("${file_ov}" MATCHES "text") - #message(STATUS "but text, so *not* a binary executable!") - else() - set(${result_var} 1 PARENT_SCOPE) - return() - endif() - endif() - - # Also detect position independent executables on Linux, - # where "file" gives "shared object ... (uses shared libraries)" - if("${file_ov}" MATCHES "shared object.*\(uses shared libs\)") - set(${result_var} 1 PARENT_SCOPE) - return() - endif() - - # "file" version 5.22 does not print "(used shared libraries)" - # but uses "interpreter" - if("${file_ov}" MATCHES "shared object.*interpreter") - set(${result_var} 1 PARENT_SCOPE) - return() - endif() - - else() - message(STATUS "warning: No 'file' command, skipping execute_process...") - endif() - endif() -endfunction() - - -function(gp_item_default_embedded_path item default_embedded_path_var) - - # On Windows and Linux, "embed" prerequisites in the same directory - # as the executable by default: - # - set(path "@executable_path") - set(overridden 0) - - # On the Mac, relative to the executable depending on the type - # of the thing we are embedding: - # - if(APPLE) - # - # The assumption here is that all executables in the bundle will be - # in same-level-directories inside the bundle. The parent directory - # of an executable inside the bundle should be MacOS or a sibling of - # MacOS and all embedded paths returned from here will begin with - # "@executable_path/../" and will work from all executables in all - # such same-level-directories inside the bundle. - # - - # By default, embed things right next to the main bundle executable: - # - set(path "@executable_path/../../Contents/MacOS") - - # Embed .dylibs right next to the main bundle executable: - # - if(item MATCHES "\\.dylib$") - set(path "@executable_path/../MacOS") - set(overridden 1) - endif() - - # Embed frameworks in the embedded "Frameworks" directory (sibling of MacOS): - # - if(NOT overridden) - if(item MATCHES "[^/]+\\.framework/") - set(path "@executable_path/../Frameworks") - set(overridden 1) - endif() - endif() - endif() - - # Provide a hook so that projects can override the default embedded location - # of any given library by whatever logic they choose: - # - if(COMMAND gp_item_default_embedded_path_override) - gp_item_default_embedded_path_override("${item}" path) - endif() - - set(${default_embedded_path_var} "${path}" PARENT_SCOPE) -endfunction() - - -function(gp_resolve_item context item exepath dirs resolved_item_var) - set(resolved 0) - set(resolved_item "${item}") - - # Is it already resolved? - # - if(IS_ABSOLUTE "${resolved_item}" AND EXISTS "${resolved_item}") - set(resolved 1) - endif() - - if(NOT resolved) - if(item MATCHES "@executable_path") - # - # @executable_path references are assumed relative to exepath - # - string(REPLACE "@executable_path" "${exepath}" ri "${item}") - get_filename_component(ri "${ri}" ABSOLUTE) - - if(EXISTS "${ri}") - #message(STATUS "info: embedded item exists (${ri})") - set(resolved 1) - set(resolved_item "${ri}") - else() - message(STATUS "warning: embedded item does not exist '${ri}'") - endif() - endif() - endif() - - if(NOT resolved) - if(item MATCHES "@loader_path") - # - # @loader_path references are assumed relative to the - # PATH of the given "context" (presumably another library) - # - get_filename_component(contextpath "${context}" PATH) - string(REPLACE "@loader_path" "${contextpath}" ri "${item}") - get_filename_component(ri "${ri}" ABSOLUTE) - - if(EXISTS "${ri}") - #message(STATUS "info: embedded item exists (${ri})") - set(resolved 1) - set(resolved_item "${ri}") - else() - message(STATUS "warning: embedded item does not exist '${ri}'") - endif() - endif() - endif() - - if(NOT resolved) - if(item MATCHES "@rpath") - # - # @rpath references are relative to the paths built into the binaries with -rpath - # We handle this case like we do for other Unixes - # - string(REPLACE "@rpath/" "" norpath_item "${item}") - - set(ri "ri-NOTFOUND") - find_file(ri "${norpath_item}" ${exepath} ${dirs} NO_DEFAULT_PATH) - if(ri) - #message(STATUS "info: 'find_file' in exepath/dirs (${ri})") - set(resolved 1) - set(resolved_item "${ri}") - set(ri "ri-NOTFOUND") - endif() - - endif() - endif() - - if(NOT resolved) - set(ri "ri-NOTFOUND") - find_file(ri "${item}" ${exepath} ${dirs} NO_DEFAULT_PATH) - find_file(ri "${item}" ${exepath} ${dirs} /usr/lib) - if(ri) - #message(STATUS "info: 'find_file' in exepath/dirs (${ri})") - set(resolved 1) - set(resolved_item "${ri}") - set(ri "ri-NOTFOUND") - endif() - endif() - - if(NOT resolved) - if(item MATCHES "[^/]+\\.framework/") - set(fw "fw-NOTFOUND") - find_file(fw "${item}" - "~/Library/Frameworks" - "/Library/Frameworks" - "/System/Library/Frameworks" - ) - if(fw) - #message(STATUS "info: 'find_file' found framework (${fw})") - set(resolved 1) - set(resolved_item "${fw}") - set(fw "fw-NOTFOUND") - endif() - endif() - endif() - - # Using find_program on Windows will find dll files that are in the PATH. - # (Converting simple file names into full path names if found.) - # - if(WIN32 AND NOT UNIX) - if(NOT resolved) - set(ri "ri-NOTFOUND") - find_program(ri "${item}" PATHS "${exepath};${dirs}" NO_DEFAULT_PATH) - find_program(ri "${item}" PATHS "${exepath};${dirs}") - if(ri) - #message(STATUS "info: 'find_program' in exepath/dirs (${ri})") - set(resolved 1) - set(resolved_item "${ri}") - set(ri "ri-NOTFOUND") - endif() - endif() - endif() - - # Provide a hook so that projects can override item resolution - # by whatever logic they choose: - # - if(COMMAND gp_resolve_item_override) - gp_resolve_item_override("${context}" "${item}" "${exepath}" "${dirs}" resolved_item resolved) - endif() - - if(NOT resolved) - message(STATUS " -warning: cannot resolve item '${item}' - - possible problems: - need more directories? - need to use InstallRequiredSystemLibraries? - run in install tree instead of build tree? -") -# message(STATUS " -#****************************************************************************** -#warning: cannot resolve item '${item}' -# -# possible problems: -# need more directories? -# need to use InstallRequiredSystemLibraries? -# run in install tree instead of build tree? -# -# context='${context}' -# item='${item}' -# exepath='${exepath}' -# dirs='${dirs}' -# resolved_item_var='${resolved_item_var}' -#****************************************************************************** -#") - endif() - - set(${resolved_item_var} "${resolved_item}" PARENT_SCOPE) -endfunction() - - -function(gp_resolved_file_type original_file file exepath dirs type_var) - #message(STATUS "**") - - if(NOT IS_ABSOLUTE "${original_file}") - message(STATUS "warning: gp_resolved_file_type expects absolute full path for first arg original_file") - endif() - - set(is_embedded 0) - set(is_local 0) - set(is_system 0) - - set(resolved_file "${file}") - - if("${file}" MATCHES "^@(executable|loader)_path") - set(is_embedded 1) - endif() - - if(NOT is_embedded) - if(NOT IS_ABSOLUTE "${file}") - gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file) - endif() - - string(TOLOWER "${original_file}" original_lower) - string(TOLOWER "${resolved_file}" lower) - - if(UNIX) - if(resolved_file MATCHES "^(/lib/|/lib32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/lib64/|/usr/X11R6/|/usr/bin/)") - set(is_system 1) - endif() - endif() - - if(APPLE) - if(resolved_file MATCHES "^(/System/Library/|/usr/lib/)") - set(is_system 1) - endif() - endif() - - if(WIN32) - string(TOLOWER "$ENV{SystemRoot}" sysroot) - string(REGEX REPLACE "\\\\" "/" sysroot "${sysroot}") - - string(TOLOWER "$ENV{windir}" windir) - string(REGEX REPLACE "\\\\" "/" windir "${windir}") - - if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)") - set(is_system 1) - endif() - - if(UNIX) - # if cygwin, we can get the properly formed windows paths from cygpath - find_program(CYGPATH_EXECUTABLE cygpath) - - if(CYGPATH_EXECUTABLE) - execute_process(COMMAND ${CYGPATH_EXECUTABLE} -W - OUTPUT_VARIABLE env_windir - OUTPUT_STRIP_TRAILING_WHITESPACE) - execute_process(COMMAND ${CYGPATH_EXECUTABLE} -S - OUTPUT_VARIABLE env_sysdir - OUTPUT_STRIP_TRAILING_WHITESPACE) - string(TOLOWER "${env_windir}" windir) - string(TOLOWER "${env_sysdir}" sysroot) - - if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)") - set(is_system 1) - endif() - endif() - endif() - endif() - - if(NOT is_system) - get_filename_component(original_path "${original_lower}" PATH) - get_filename_component(path "${lower}" PATH) - if("${original_path}" STREQUAL "${path}") - set(is_local 1) - else() - string(LENGTH "${original_path}/" original_length) - string(LENGTH "${lower}" path_length) - if(${path_length} GREATER ${original_length}) - string(SUBSTRING "${lower}" 0 ${original_length} path) - if("${original_path}/" STREQUAL "${path}") - set(is_embedded 1) - endif() - endif() - endif() - endif() - endif() - - # Return type string based on computed booleans: - # - set(type "other") - - if(is_system) - set(type "system") - elseif(is_embedded) - set(type "embedded") - elseif(is_local) - set(type "local") - endif() - - #message(STATUS "gp_resolved_file_type: '${file}' '${resolved_file}'") - #message(STATUS " type: '${type}'") - - if(NOT is_embedded) - if(NOT IS_ABSOLUTE "${resolved_file}") - if(lower MATCHES "^msvc[^/]+dll" AND is_system) - message(STATUS "info: non-absolute msvc file '${file}' returning type '${type}'") - else() - message(STATUS "warning: gp_resolved_file_type non-absolute file '${file}' returning type '${type}' -- possibly incorrect") - endif() - endif() - endif() - - # Provide a hook so that projects can override the decision on whether a - # library belongs to the system or not by whatever logic they choose: - # - if(COMMAND gp_resolved_file_type_override) - gp_resolved_file_type_override("${resolved_file}" type) - endif() - - set(${type_var} "${type}" PARENT_SCOPE) - - #message(STATUS "**") -endfunction() - - -function(gp_file_type original_file file type_var) - if(NOT IS_ABSOLUTE "${original_file}") - message(STATUS "warning: gp_file_type expects absolute full path for first arg original_file") - endif() - - get_filename_component(exepath "${original_file}" PATH) - - set(type "") - gp_resolved_file_type("${original_file}" "${file}" "${exepath}" "" type) - - set(${type_var} "${type}" PARENT_SCOPE) -endfunction() - - -function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs) - set(verbose 0) - set(eol_char "E") - - if(NOT IS_ABSOLUTE "${target}") - message("warning: target '${target}' is not absolute...") - endif() - - if(NOT EXISTS "${target}") - message("warning: target '${target}' does not exist...") - endif() - - set(gp_cmd_paths ${gp_cmd_paths} - "C:/Program Files/Microsoft Visual Studio 9.0/VC/bin" - "C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin" - "C:/Program Files/Microsoft Visual Studio 8/VC/BIN" - "C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN" - "C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN" - "C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN" - "/usr/local/bin" - "/usr/bin" - ) - - # - # - # Try to choose the right tool by default. Caller can set gp_tool prior to - # calling this function to force using a different tool. - # - if("${gp_tool}" STREQUAL "") - set(gp_tool "ldd") - - if(APPLE) - set(gp_tool "otool") - endif() - - if(WIN32 AND NOT UNIX) # This is how to check for cygwin, har! - find_program(gp_dumpbin "dumpbin" PATHS ${gp_cmd_paths}) - if(gp_dumpbin) - set(gp_tool "dumpbin") - else() # Try harder. Maybe we're on MinGW - set(gp_tool "objdump") - endif() - endif() - endif() - - find_program(gp_cmd ${gp_tool} PATHS ${gp_cmd_paths}) - - if(NOT gp_cmd) - message(FATAL_ERROR "FATAL ERROR: could not find '${gp_tool}' - cannot analyze prerequisites!") - return() - endif() - - set(gp_tool_known 0) - - if("${gp_tool}" STREQUAL "ldd") - set(gp_cmd_args "") - set(gp_regex "^[\t ]*[^\t ]+ => ([^\t\(]+) .*${eol_char}$") - set(gp_regex_error "not found${eol_char}$") - set(gp_regex_fallback "^[\t ]*([^\t ]+) => ([^\t ]+).*${eol_char}$") - set(gp_regex_cmp_count 1) - set(gp_tool_known 1) - endif() - - if("${gp_tool}" STREQUAL "otool") - set(gp_cmd_args "-L") - set(gp_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)\\)${eol_char}$") - set(gp_regex_error "") - set(gp_regex_fallback "") - set(gp_regex_cmp_count 3) - set(gp_tool_known 1) - endif() - - if("${gp_tool}" STREQUAL "dumpbin") - set(gp_cmd_args "/dependents") - set(gp_regex "^ ([^ ].*[Dd][Ll][Ll])${eol_char}$") - set(gp_regex_error "") - set(gp_regex_fallback "") - set(gp_regex_cmp_count 1) - set(gp_tool_known 1) - endif() - - if("${gp_tool}" STREQUAL "objdump") - set(gp_cmd_args "-p") - set(gp_regex "^\t*DLL Name: (.*\\.[Dd][Ll][Ll])${eol_char}$") - set(gp_regex_error "") - set(gp_regex_fallback "") - set(gp_regex_cmp_count 1) - set(gp_tool_known 1) - endif() - - if(NOT gp_tool_known) - message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...") - message(STATUS "CMake function get_prerequisites needs more code to handle '${gp_tool}'") - message(STATUS "Valid gp_tool values are dumpbin, ldd, objdump and otool.") - return() - endif() - - - if("${gp_tool}" STREQUAL "dumpbin") - # When running dumpbin, it also needs the "Common7/IDE" directory in the - # PATH. It will already be in the PATH if being run from a Visual Studio - # command prompt. Add it to the PATH here in case we are running from a - # different command prompt. - # - get_filename_component(gp_cmd_dir "${gp_cmd}" PATH) - get_filename_component(gp_cmd_dlls_dir "${gp_cmd_dir}/../../Common7/IDE" ABSOLUTE) - # Use cmake paths as a user may have a PATH element ending with a backslash. - # This will escape the list delimiter and create havoc! - if(EXISTS "${gp_cmd_dlls_dir}") - # only add to the path if it is not already in the path - set(gp_found_cmd_dlls_dir 0) - file(TO_CMAKE_PATH "$ENV{PATH}" env_path) - foreach(gp_env_path_element ${env_path}) - if("${gp_env_path_element}" STREQUAL "${gp_cmd_dlls_dir}") - set(gp_found_cmd_dlls_dir 1) - endif() - endforeach() - - if(NOT gp_found_cmd_dlls_dir) - file(TO_NATIVE_PATH "${gp_cmd_dlls_dir}" gp_cmd_dlls_dir) - set(ENV{PATH} "$ENV{PATH};${gp_cmd_dlls_dir}") - endif() - endif() - endif() - # - # - - if("${gp_tool}" STREQUAL "ldd") - set(old_ld_env "$ENV{LD_LIBRARY_PATH}") - foreach(dir ${exepath} ${dirs}) - set(ENV{LD_LIBRARY_PATH} "${dir}:$ENV{LD_LIBRARY_PATH}") - endforeach() - endif() - - - # Track new prerequisites at each new level of recursion. Start with an - # empty list at each level: - # - set(unseen_prereqs) - - # Run gp_cmd on the target: - # - execute_process( - COMMAND ${gp_cmd} ${gp_cmd_args} ${target} - OUTPUT_VARIABLE gp_cmd_ov - ) - - if("${gp_tool}" STREQUAL "ldd") - set(ENV{LD_LIBRARY_PATH} "${old_ld_env}") - endif() - - if(verbose) - message(STATUS "") - message(STATUS "gp_cmd_ov='${gp_cmd_ov}'") - message(STATUS "") - endif() - - get_filename_component(target_dir "${target}" PATH) - - # Convert to a list of lines: - # - string(REGEX REPLACE ";" "\\\\;" candidates "${gp_cmd_ov}") - string(REGEX REPLACE "\n" "${eol_char};" candidates "${candidates}") - - # check for install id and remove it from list, since otool -L can include a - # reference to itself - set(gp_install_id) - if("${gp_tool}" STREQUAL "otool") - execute_process( - COMMAND otool -D ${target} - OUTPUT_VARIABLE gp_install_id_ov - ) - # second line is install name - string(REGEX REPLACE ".*:\n" "" gp_install_id "${gp_install_id_ov}") - if(gp_install_id) - # trim - string(REGEX MATCH "[^\n ].*[^\n ]" gp_install_id "${gp_install_id}") - #message("INSTALL ID is \"${gp_install_id}\"") - endif() - endif() - - # Analyze each line for file names that match the regular expression: - # - foreach(candidate ${candidates}) - if("${candidate}" MATCHES "${gp_regex}") - - # Extract information from each candidate: - if(gp_regex_error AND "${candidate}" MATCHES "${gp_regex_error}") - string(REGEX REPLACE "${gp_regex_fallback}" "\\1" raw_item "${candidate}") - else() - string(REGEX REPLACE "${gp_regex}" "\\1" raw_item "${candidate}") - endif() - - if(gp_regex_cmp_count GREATER 1) - string(REGEX REPLACE "${gp_regex}" "\\2" raw_compat_version "${candidate}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" compat_major_version "${raw_compat_version}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" compat_minor_version "${raw_compat_version}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" compat_patch_version "${raw_compat_version}") - endif() - - if(gp_regex_cmp_count GREATER 2) - string(REGEX REPLACE "${gp_regex}" "\\3" raw_current_version "${candidate}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" current_major_version "${raw_current_version}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" current_minor_version "${raw_current_version}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" current_patch_version "${raw_current_version}") - endif() - - # Use the raw_item as the list entries returned by this function. Use the - # gp_resolve_item function to resolve it to an actual full path file if - # necessary. - # - set(item "${raw_item}") - - # Add each item unless it is excluded: - # - set(add_item 1) - - if("${item}" STREQUAL "${gp_install_id}") - set(add_item 0) - endif() - - if(add_item AND ${exclude_system}) - set(type "") - gp_resolved_file_type("${target}" "${item}" "${exepath}" "${dirs}" type) - - if("${type}" STREQUAL "system") - set(add_item 0) - endif() - endif() - - if(add_item) - list(LENGTH ${prerequisites_var} list_length_before_append) - gp_append_unique(${prerequisites_var} "${item}") - list(LENGTH ${prerequisites_var} list_length_after_append) - - if(${recurse}) - # If item was really added, this is the first time we have seen it. - # Add it to unseen_prereqs so that we can recursively add *its* - # prerequisites... - # - # But first: resolve its name to an absolute full path name such - # that the analysis tools can simply accept it as input. - # - if(NOT list_length_before_append EQUAL list_length_after_append) - gp_resolve_item("${target}" "${item}" "${exepath}" "${dirs}" resolved_item) - set(unseen_prereqs ${unseen_prereqs} "${resolved_item}") - endif() - endif() - endif() - else() - if(verbose) - message(STATUS "ignoring non-matching line: '${candidate}'") - endif() - endif() - endforeach() - - list(LENGTH ${prerequisites_var} prerequisites_var_length) - if(prerequisites_var_length GREATER 0) - list(SORT ${prerequisites_var}) - endif() - if(${recurse}) - set(more_inputs ${unseen_prereqs}) - foreach(input ${more_inputs}) - get_prerequisites("${input}" ${prerequisites_var} ${exclude_system} ${recurse} "${exepath}" "${dirs}") - endforeach() - endif() - - set(${prerequisites_var} ${${prerequisites_var}} PARENT_SCOPE) -endfunction() - - -function(list_prerequisites target) - if("${ARGV1}" STREQUAL "") - set(all 1) - else() - set(all "${ARGV1}") - endif() - - if("${ARGV2}" STREQUAL "") - set(exclude_system 0) - else() - set(exclude_system "${ARGV2}") - endif() - - if("${ARGV3}" STREQUAL "") - set(verbose 0) - else() - set(verbose "${ARGV3}") - endif() - - set(count 0) - set(count_str "") - set(print_count "${verbose}") - set(print_prerequisite_type "${verbose}") - set(print_target "${verbose}") - set(type_str "") - - get_filename_component(exepath "${target}" PATH) - - set(prereqs "") - get_prerequisites("${target}" prereqs ${exclude_system} ${all} "${exepath}" "") - - if(print_target) - message(STATUS "File '${target}' depends on:") - endif() - - foreach(d ${prereqs}) - math(EXPR count "${count} + 1") - - if(print_count) - set(count_str "${count}. ") - endif() - - if(print_prerequisite_type) - gp_file_type("${target}" "${d}" type) - set(type_str " (${type})") - endif() - - message(STATUS "${count_str}${d}${type_str}") - endforeach() -endfunction() - - -function(list_prerequisites_by_glob glob_arg glob_exp) - message(STATUS "=============================================================================") - message(STATUS "List prerequisites of executables matching ${glob_arg} '${glob_exp}'") - message(STATUS "") - file(${glob_arg} file_list ${glob_exp}) - foreach(f ${file_list}) - is_file_executable("${f}" is_f_executable) - if(is_f_executable) - message(STATUS "=============================================================================") - list_prerequisites("${f}" ${ARGN}) - message(STATUS "") - endif() - endforeach() -endfunction() diff --git a/cmake/UseJava.cmake b/cmake/UseJava.cmake deleted file mode 100644 index 1a5ef1076..000000000 --- a/cmake/UseJava.cmake +++ /dev/null @@ -1,881 +0,0 @@ -# - Use Module for Java -# This file provides functions for Java. It is assumed that FindJava.cmake -# has already been loaded. See FindJava.cmake for information on how to -# load Java into your CMake project. -# -# add_jar(TARGET_NAME SRC1 SRC2 .. SRCN RCS1 RCS2 .. RCSN) -# -# This command creates a .jar. It compiles the given source -# files (SRC) and adds the given resource files (RCS) to the jar file. -# If only resource files are given then just a jar file is created. -# -# Additional instructions: -# To add compile flags to the target you can set these flags with -# the following variable: -# -# set(CMAKE_JAVA_COMPILE_FLAGS -nowarn) -# -# To add a path or a jar file to the class path you can do this -# with the CMAKE_JAVA_INCLUDE_PATH variable. -# -# set(CMAKE_JAVA_INCLUDE_PATH /usr/share/java/shibboleet.jar) -# -# To use a different output name for the target you can set it with: -# -# set(CMAKE_JAVA_TARGET_OUTPUT_NAME shibboleet.jar) -# add_jar(foobar foobar.java) -# -# To use a different output directory than CMAKE_CURRENT_BINARY_DIR -# you can set it with: -# -# set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${PROJECT_BINARY_DIR}/bin) -# -# To define an entry point in your jar you can set it with: -# -# set(CMAKE_JAVA_JAR_ENTRY_POINT com/examples/MyProject/Main) -# -# To add a VERSION to the target output name you can set it using -# CMAKE_JAVA_TARGET_VERSION. This will create a jar file with the name -# shibboleet-1.0.0.jar and will create a symlink shibboleet.jar -# pointing to the jar with the version information. -# -# set(CMAKE_JAVA_TARGET_VERSION 1.2.0) -# add_jar(shibboleet shibbotleet.java) -# -# If the target is a JNI library, utilize the following commands to -# create a JNI symbolic link: -# -# set(CMAKE_JNI_TARGET TRUE) -# set(CMAKE_JAVA_TARGET_VERSION 1.2.0) -# add_jar(shibboleet shibbotleet.java) -# install_jar(shibboleet ${LIB_INSTALL_DIR}/shibboleet) -# install_jni_symlink(shibboleet ${JAVA_LIB_INSTALL_DIR}) -# -# If a single target needs to produce more than one jar from its -# java source code, to prevent the accumulation of duplicate class -# files in subsequent jars, set/reset CMAKE_JAR_CLASSES_PREFIX prior -# to calling the add_jar() function: -# -# set(CMAKE_JAR_CLASSES_PREFIX com/redhat/foo) -# add_jar(foo foo.java) -# -# set(CMAKE_JAR_CLASSES_PREFIX com/redhat/bar) -# add_jar(bar bar.java) -# -# Target Properties: -# The add_jar() functions sets some target properties. You can get these -# properties with the -# get_property(TARGET PROPERTY ) -# command. -# -# INSTALL_FILES The files which should be installed. This is used by -# install_jar(). -# JNI_SYMLINK The JNI symlink which should be installed. -# This is used by install_jni_symlink(). -# JAR_FILE The location of the jar file so that you can include -# it. -# CLASS_DIR The directory where the class files can be found. For -# example to use them with javah. -# -# find_jar( -# name | NAMES name1 [name2 ...] -# [PATHS path1 [path2 ... ENV var]] -# [VERSIONS version1 [version2]] -# [DOC "cache documentation string"] -# ) -# -# This command is used to find a full path to the named jar. A cache -# entry named by is created to stor the result of this command. If -# the full path to a jar is found the result is stored in the variable -# and the search will not repeated unless the variable is cleared. If -# nothing is found, the result will be -NOTFOUND, and the search -# will be attempted again next time find_jar is invoked with the same -# variable. -# The name of the full path to a file that is searched for is specified -# by the names listed after NAMES argument. Additional search locations -# can be specified after the PATHS argument. If you require special a -# version of a jar file you can specify it with the VERSIONS argument. -# The argument after DOC will be used for the documentation string in -# the cache. -# -# install_jar(TARGET_NAME DESTINATION) -# -# This command installs the TARGET_NAME files to the given DESTINATION. -# It should be called in the same scope as add_jar() or it will fail. -# -# install_jni_symlink(TARGET_NAME DESTINATION) -# -# This command installs the TARGET_NAME JNI symlinks to the given -# DESTINATION. It should be called in the same scope as add_jar() -# or it will fail. -# -# create_javadoc( -# PACKAGES pkg1 [pkg2 ...] -# [SOURCEPATH ] -# [CLASSPATH ] -# [INSTALLPATH ] -# [DOCTITLE "the documentation title"] -# [WINDOWTITLE "the title of the document"] -# [AUTHOR TRUE|FALSE] -# [USE TRUE|FALSE] -# [VERSION TRUE|FALSE] -# ) -# -# Create java documentation based on files or packages. For more -# details please read the javadoc manpage. -# -# There are two main signatures for create_javadoc. The first -# signature works with package names on a path with source files: -# -# Example: -# create_javadoc(my_example_doc -# PACKAGES com.exmaple.foo com.example.bar -# SOURCEPATH "${CMAKE_CURRENT_SOURCE_DIR}" -# CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH} -# WINDOWTITLE "My example" -# DOCTITLE "

My example

" -# AUTHOR TRUE -# USE TRUE -# VERSION TRUE -# ) -# -# The second signature for create_javadoc works on a given list of -# files. -# -# create_javadoc( -# FILES file1 [file2 ...] -# [CLASSPATH ] -# [INSTALLPATH ] -# [DOCTITLE "the documentation title"] -# [WINDOWTITLE "the title of the document"] -# [AUTHOR TRUE|FALSE] -# [USE TRUE|FALSE] -# [VERSION TRUE|FALSE] -# ) -# -# Example: -# create_javadoc(my_example_doc -# FILES ${example_SRCS} -# CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH} -# WINDOWTITLE "My example" -# DOCTITLE "

My example

" -# AUTHOR TRUE -# USE TRUE -# VERSION TRUE -# ) -# -# Both signatures share most of the options. These options are the -# same as what you can find in the javadoc manpage. Please look at -# the manpage for CLASSPATH, DOCTITLE, WINDOWTITLE, AUTHOR, USE and -# VERSION. -# -# The documentation will be by default installed to -# -# ${CMAKE_INSTALL_PREFIX}/share/javadoc/ -# -# if you don't set the INSTALLPATH. -# - -#============================================================================= -# Copyright 2010-2011 Andreas schneider -# Copyright 2010 Ben Boeckel -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -function (__java_copy_file src dest comment) - add_custom_command( - OUTPUT ${dest} - COMMAND cmake -E copy_if_different - ARGS ${src} - ${dest} - DEPENDS ${src} - COMMENT ${comment}) -endfunction (__java_copy_file src dest comment) - -# define helper scripts -set(_JAVA_CLASS_FILELIST_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaClassFilelist.cmake) -set(_JAVA_SYMLINK_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaSymlinks.cmake) - -function(add_jar _TARGET_NAME) - set(_JAVA_SOURCE_FILES ${ARGN}) - - if (NOT DEFINED CMAKE_JAVA_TARGET_OUTPUT_DIR) - set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) - endif(NOT DEFINED CMAKE_JAVA_TARGET_OUTPUT_DIR) - - if (CMAKE_JAVA_JAR_ENTRY_POINT) - set(_ENTRY_POINT_OPTION e) - set(_ENTRY_POINT_VALUE ${CMAKE_JAVA_JAR_ENTRY_POINT}) - endif (CMAKE_JAVA_JAR_ENTRY_POINT) - - if (LIBRARY_OUTPUT_PATH) - set(CMAKE_JAVA_LIBRARY_OUTPUT_PATH ${LIBRARY_OUTPUT_PATH}) - else (LIBRARY_OUTPUT_PATH) - set(CMAKE_JAVA_LIBRARY_OUTPUT_PATH ${CMAKE_JAVA_TARGET_OUTPUT_DIR}) - endif (LIBRARY_OUTPUT_PATH) - - set(CMAKE_JAVA_INCLUDE_PATH - ${CMAKE_JAVA_INCLUDE_PATH} - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_JAVA_OBJECT_OUTPUT_PATH} - ${CMAKE_JAVA_LIBRARY_OUTPUT_PATH} - ) - - if (WIN32 AND NOT CYGWIN AND NOT CMAKE_CROSSCOMPILING) - set(CMAKE_JAVA_INCLUDE_FLAG_SEP ";") - else () - set(CMAKE_JAVA_INCLUDE_FLAG_SEP ":") - endif() - - foreach (JAVA_INCLUDE_DIR ${CMAKE_JAVA_INCLUDE_PATH}) - set(CMAKE_JAVA_INCLUDE_PATH_FINAL "${CMAKE_JAVA_INCLUDE_PATH_FINAL}${CMAKE_JAVA_INCLUDE_FLAG_SEP}${JAVA_INCLUDE_DIR}") - endforeach(JAVA_INCLUDE_DIR) - - set(CMAKE_JAVA_CLASS_OUTPUT_PATH "${CMAKE_JAVA_TARGET_OUTPUT_DIR}${CMAKE_FILES_DIRECTORY}/${_TARGET_NAME}.dir") - - set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}.jar") - if (CMAKE_JAVA_TARGET_OUTPUT_NAME AND CMAKE_JAVA_TARGET_VERSION) - set(_JAVA_TARGET_OUTPUT_NAME "${CMAKE_JAVA_TARGET_OUTPUT_NAME}-${CMAKE_JAVA_TARGET_VERSION}.jar") - set(_JAVA_TARGET_OUTPUT_LINK "${CMAKE_JAVA_TARGET_OUTPUT_NAME}.jar") - elseif (CMAKE_JAVA_TARGET_VERSION) - set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}-${CMAKE_JAVA_TARGET_VERSION}.jar") - set(_JAVA_TARGET_OUTPUT_LINK "${_TARGET_NAME}.jar") - elseif (CMAKE_JAVA_TARGET_OUTPUT_NAME) - set(_JAVA_TARGET_OUTPUT_NAME "${CMAKE_JAVA_TARGET_OUTPUT_NAME}.jar") - endif (CMAKE_JAVA_TARGET_OUTPUT_NAME AND CMAKE_JAVA_TARGET_VERSION) - # reset - set(CMAKE_JAVA_TARGET_OUTPUT_NAME) - - set(_JAVA_CLASS_FILES) - set(_JAVA_COMPILE_FILES) - set(_JAVA_DEPENDS) - set(_JAVA_RESOURCE_FILES) - foreach(_JAVA_SOURCE_FILE ${_JAVA_SOURCE_FILES}) - get_filename_component(_JAVA_EXT ${_JAVA_SOURCE_FILE} EXT) - get_filename_component(_JAVA_FILE ${_JAVA_SOURCE_FILE} NAME_WE) - get_filename_component(_JAVA_PATH ${_JAVA_SOURCE_FILE} PATH) - get_filename_component(_JAVA_FULL ${_JAVA_SOURCE_FILE} ABSOLUTE) - - file(RELATIVE_PATH _JAVA_REL_BINARY_PATH ${CMAKE_JAVA_TARGET_OUTPUT_DIR} ${_JAVA_FULL}) - file(RELATIVE_PATH _JAVA_REL_SOURCE_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${_JAVA_FULL}) - string(LENGTH ${_JAVA_REL_BINARY_PATH} _BIN_LEN) - string(LENGTH ${_JAVA_REL_SOURCE_PATH} _SRC_LEN) - if (${_BIN_LEN} LESS ${_SRC_LEN}) - set(_JAVA_REL_PATH ${_JAVA_REL_BINARY_PATH}) - else (${_BIN_LEN} LESS ${_SRC_LEN}) - set(_JAVA_REL_PATH ${_JAVA_REL_SOURCE_PATH}) - endif (${_BIN_LEN} LESS ${_SRC_LEN}) - get_filename_component(_JAVA_REL_PATH ${_JAVA_REL_PATH} PATH) - - if (_JAVA_EXT MATCHES ".java") - list(APPEND _JAVA_COMPILE_FILES ${_JAVA_SOURCE_FILE}) - set(_JAVA_CLASS_FILE "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${_JAVA_REL_PATH}/${_JAVA_FILE}.class") - set(_JAVA_CLASS_FILES ${_JAVA_CLASS_FILES} ${_JAVA_CLASS_FILE}) - - elseif (_JAVA_EXT MATCHES ".jar" - OR _JAVA_EXT MATCHES ".war" - OR _JAVA_EXT MATCHES ".ear" - OR _JAVA_EXT MATCHES ".sar") - list(APPEND CMAKE_JAVA_INCLUDE_PATH ${_JAVA_SOURCE_FILE}) - - elseif (_JAVA_EXT STREQUAL "") - list(APPEND CMAKE_JAVA_INCLUDE_PATH ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}} ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}_CLASSPATH}) - list(APPEND _JAVA_DEPENDS ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}}) - - else (_JAVA_EXT MATCHES ".java") - __java_copy_file(${CMAKE_CURRENT_SOURCE_DIR}/${_JAVA_SOURCE_FILE} - ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${_JAVA_SOURCE_FILE} - "Copying ${_JAVA_SOURCE_FILE} to the build directory") - list(APPEND _JAVA_RESOURCE_FILES ${_JAVA_SOURCE_FILE}) - endif (_JAVA_EXT MATCHES ".java") - endforeach(_JAVA_SOURCE_FILE) - - # create an empty java_class_filelist - if (NOT EXISTS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist) - file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist "") - endif() - - if (_JAVA_COMPILE_FILES) - # Compile the java files and create a list of class files - add_custom_command( - # NOTE: this command generates an artificial dependency file - OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME} - COMMAND ${Java_JAVAC_EXECUTABLE} - ${CMAKE_JAVA_COMPILE_FLAGS} - -classpath "${CMAKE_JAVA_INCLUDE_PATH_FINAL}" - -d ${CMAKE_JAVA_CLASS_OUTPUT_PATH} - ${_JAVA_COMPILE_FILES} - COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME} - DEPENDS ${_JAVA_COMPILE_FILES} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMENT "Building Java objects for ${_TARGET_NAME}.jar" - ) - add_custom_command( - OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist - COMMAND ${CMAKE_COMMAND} - -DCMAKE_JAVA_CLASS_OUTPUT_PATH=${CMAKE_JAVA_CLASS_OUTPUT_PATH} - -DCMAKE_JAR_CLASSES_PREFIX="${CMAKE_JAR_CLASSES_PREFIX}" - -P ${_JAVA_CLASS_FILELIST_SCRIPT} - DEPENDS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - ) - endif (_JAVA_COMPILE_FILES) - - # create the jar file - set(_JAVA_JAR_OUTPUT_PATH - ${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_NAME}) - if (CMAKE_JNI_TARGET) - add_custom_command( - OUTPUT ${_JAVA_JAR_OUTPUT_PATH} - COMMAND ${Java_JAR_EXECUTABLE} - -cf${_ENTRY_POINT_OPTION} ${_JAVA_JAR_OUTPUT_PATH} ${_ENTRY_POINT_VALUE} - ${_JAVA_RESOURCE_FILES} @java_class_filelist - COMMAND ${CMAKE_COMMAND} - -D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR} - -D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_TARGET_OUTPUT_NAME} - -D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK} - -P ${_JAVA_SYMLINK_SCRIPT} - COMMAND ${CMAKE_COMMAND} - -D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR} - -D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_JAR_OUTPUT_PATH} - -D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK} - -P ${_JAVA_SYMLINK_SCRIPT} - DEPENDS ${_JAVA_RESOURCE_FILES} ${_JAVA_DEPENDS} ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist - WORKING_DIRECTORY ${CMAKE_JAVA_CLASS_OUTPUT_PATH} - COMMENT "Creating Java archive ${_JAVA_TARGET_OUTPUT_NAME}" - ) - else () - add_custom_command( - OUTPUT ${_JAVA_JAR_OUTPUT_PATH} - COMMAND ${Java_JAR_EXECUTABLE} - -cf${_ENTRY_POINT_OPTION} ${_JAVA_JAR_OUTPUT_PATH} ${_ENTRY_POINT_VALUE} - ${_JAVA_RESOURCE_FILES} @java_class_filelist - COMMAND ${CMAKE_COMMAND} - -D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR} - -D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_TARGET_OUTPUT_NAME} - -D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK} - -P ${_JAVA_SYMLINK_SCRIPT} - WORKING_DIRECTORY ${CMAKE_JAVA_CLASS_OUTPUT_PATH} - DEPENDS ${_JAVA_RESOURCE_FILES} ${_JAVA_DEPENDS} ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist - COMMENT "Creating Java archive ${_JAVA_TARGET_OUTPUT_NAME}" - ) - endif (CMAKE_JNI_TARGET) - - # Add the target and make sure we have the latest resource files. - add_custom_target(${_TARGET_NAME} ALL DEPENDS ${_JAVA_JAR_OUTPUT_PATH}) - - set_property( - TARGET - ${_TARGET_NAME} - PROPERTY - INSTALL_FILES - ${_JAVA_JAR_OUTPUT_PATH} - ) - - if (_JAVA_TARGET_OUTPUT_LINK) - set_property( - TARGET - ${_TARGET_NAME} - PROPERTY - INSTALL_FILES - ${_JAVA_JAR_OUTPUT_PATH} - ${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_LINK} - ) - - if (CMAKE_JNI_TARGET) - set_property( - TARGET - ${_TARGET_NAME} - PROPERTY - JNI_SYMLINK - ${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_LINK} - ) - endif (CMAKE_JNI_TARGET) - endif (_JAVA_TARGET_OUTPUT_LINK) - - set_property( - TARGET - ${_TARGET_NAME} - PROPERTY - JAR_FILE - ${_JAVA_JAR_OUTPUT_PATH} - ) - - set_property( - TARGET - ${_TARGET_NAME} - PROPERTY - CLASSDIR - ${CMAKE_JAVA_CLASS_OUTPUT_PATH} - ) - -endfunction(add_jar) - -function(INSTALL_JAR _TARGET_NAME _DESTINATION) - get_property(__FILES - TARGET - ${_TARGET_NAME} - PROPERTY - INSTALL_FILES - ) - - if (__FILES) - install( - FILES - ${__FILES} - DESTINATION - ${_DESTINATION} - ) - else (__FILES) - message(SEND_ERROR "The target ${_TARGET_NAME} is not known in this scope.") - endif (__FILES) -endfunction(INSTALL_JAR _TARGET_NAME _DESTINATION) - -function(INSTALL_JNI_SYMLINK _TARGET_NAME _DESTINATION) - get_property(__SYMLINK - TARGET - ${_TARGET_NAME} - PROPERTY - JNI_SYMLINK - ) - - if (__SYMLINK) - install( - FILES - ${__SYMLINK} - DESTINATION - ${_DESTINATION} - ) - else (__SYMLINK) - message(SEND_ERROR "The target ${_TARGET_NAME} is not known in this scope.") - endif (__SYMLINK) -endfunction(INSTALL_JNI_SYMLINK _TARGET_NAME _DESTINATION) - -function (find_jar VARIABLE) - set(_jar_names) - set(_jar_files) - set(_jar_versions) - set(_jar_paths - /usr/share/java/ - /usr/local/share/java/ - ${Java_JAR_PATHS}) - set(_jar_doc "NOTSET") - - set(_state "name") - - foreach (arg ${ARGN}) - if (${_state} STREQUAL "name") - if (${arg} STREQUAL "VERSIONS") - set(_state "versions") - elseif (${arg} STREQUAL "NAMES") - set(_state "names") - elseif (${arg} STREQUAL "PATHS") - set(_state "paths") - elseif (${arg} STREQUAL "DOC") - set(_state "doc") - else (${arg} STREQUAL "NAMES") - set(_jar_names ${arg}) - if (_jar_doc STREQUAL "NOTSET") - set(_jar_doc "Finding ${arg} jar") - endif (_jar_doc STREQUAL "NOTSET") - endif (${arg} STREQUAL "VERSIONS") - elseif (${_state} STREQUAL "versions") - if (${arg} STREQUAL "NAMES") - set(_state "names") - elseif (${arg} STREQUAL "PATHS") - set(_state "paths") - elseif (${arg} STREQUAL "DOC") - set(_state "doc") - else (${arg} STREQUAL "NAMES") - set(_jar_versions ${_jar_versions} ${arg}) - endif (${arg} STREQUAL "NAMES") - elseif (${_state} STREQUAL "names") - if (${arg} STREQUAL "VERSIONS") - set(_state "versions") - elseif (${arg} STREQUAL "PATHS") - set(_state "paths") - elseif (${arg} STREQUAL "DOC") - set(_state "doc") - else (${arg} STREQUAL "VERSIONS") - set(_jar_names ${_jar_names} ${arg}) - if (_jar_doc STREQUAL "NOTSET") - set(_jar_doc "Finding ${arg} jar") - endif (_jar_doc STREQUAL "NOTSET") - endif (${arg} STREQUAL "VERSIONS") - elseif (${_state} STREQUAL "paths") - if (${arg} STREQUAL "VERSIONS") - set(_state "versions") - elseif (${arg} STREQUAL "NAMES") - set(_state "names") - elseif (${arg} STREQUAL "DOC") - set(_state "doc") - else (${arg} STREQUAL "VERSIONS") - set(_jar_paths ${_jar_paths} ${arg}) - endif (${arg} STREQUAL "VERSIONS") - elseif (${_state} STREQUAL "doc") - if (${arg} STREQUAL "VERSIONS") - set(_state "versions") - elseif (${arg} STREQUAL "NAMES") - set(_state "names") - elseif (${arg} STREQUAL "PATHS") - set(_state "paths") - else (${arg} STREQUAL "VERSIONS") - set(_jar_doc ${arg}) - endif (${arg} STREQUAL "VERSIONS") - endif (${_state} STREQUAL "name") - endforeach (arg ${ARGN}) - - if (NOT _jar_names) - message(FATAL_ERROR "find_jar: No name to search for given") - endif (NOT _jar_names) - - foreach (jar_name ${_jar_names}) - foreach (version ${_jar_versions}) - set(_jar_files ${_jar_files} ${jar_name}-${version}.jar) - endforeach (version ${_jar_versions}) - set(_jar_files ${_jar_files} ${jar_name}.jar) - endforeach (jar_name ${_jar_names}) - - find_file(${VARIABLE} - NAMES ${_jar_files} - PATHS ${_jar_paths} - DOC ${_jar_doc} - NO_DEFAULT_PATH) -endfunction (find_jar VARIABLE) - -function(create_javadoc _target) - set(_javadoc_packages) - set(_javadoc_files) - set(_javadoc_sourcepath) - set(_javadoc_classpath) - set(_javadoc_installpath "${CMAKE_INSTALL_PREFIX}/share/javadoc") - set(_javadoc_doctitle) - set(_javadoc_windowtitle) - set(_javadoc_author FALSE) - set(_javadoc_version FALSE) - set(_javadoc_use FALSE) - - set(_state "package") - - foreach (arg ${ARGN}) - if (${_state} STREQUAL "package") - if (${arg} STREQUAL "PACKAGES") - set(_state "packages") - elseif (${arg} STREQUAL "FILES") - set(_state "files") - elseif (${arg} STREQUAL "SOURCEPATH") - set(_state "sourcepath") - elseif (${arg} STREQUAL "CLASSPATH") - set(_state "classpath") - elseif (${arg} STREQUAL "INSTALLPATH") - set(_state "installpath") - elseif (${arg} STREQUAL "DOCTITLE") - set(_state "doctitle") - elseif (${arg} STREQUAL "WINDOWTITLE") - set(_state "windowtitle") - elseif (${arg} STREQUAL "AUTHOR") - set(_state "author") - elseif (${arg} STREQUAL "USE") - set(_state "use") - elseif (${arg} STREQUAL "VERSION") - set(_state "version") - else () - set(_javadoc_packages ${arg}) - set(_state "packages") - endif () - elseif (${_state} STREQUAL "packages") - if (${arg} STREQUAL "FILES") - set(_state "files") - elseif (${arg} STREQUAL "SOURCEPATH") - set(_state "sourcepath") - elseif (${arg} STREQUAL "CLASSPATH") - set(_state "classpath") - elseif (${arg} STREQUAL "INSTALLPATH") - set(_state "installpath") - elseif (${arg} STREQUAL "DOCTITLE") - set(_state "doctitle") - elseif (${arg} STREQUAL "WINDOWTITLE") - set(_state "windowtitle") - elseif (${arg} STREQUAL "AUTHOR") - set(_state "author") - elseif (${arg} STREQUAL "USE") - set(_state "use") - elseif (${arg} STREQUAL "VERSION") - set(_state "version") - else () - list(APPEND _javadoc_packages ${arg}) - endif () - elseif (${_state} STREQUAL "files") - if (${arg} STREQUAL "PACKAGES") - set(_state "packages") - elseif (${arg} STREQUAL "SOURCEPATH") - set(_state "sourcepath") - elseif (${arg} STREQUAL "CLASSPATH") - set(_state "classpath") - elseif (${arg} STREQUAL "INSTALLPATH") - set(_state "installpath") - elseif (${arg} STREQUAL "DOCTITLE") - set(_state "doctitle") - elseif (${arg} STREQUAL "WINDOWTITLE") - set(_state "windowtitle") - elseif (${arg} STREQUAL "AUTHOR") - set(_state "author") - elseif (${arg} STREQUAL "USE") - set(_state "use") - elseif (${arg} STREQUAL "VERSION") - set(_state "version") - else () - list(APPEND _javadoc_files ${arg}) - endif () - elseif (${_state} STREQUAL "sourcepath") - if (${arg} STREQUAL "PACKAGES") - set(_state "packages") - elseif (${arg} STREQUAL "FILES") - set(_state "files") - elseif (${arg} STREQUAL "CLASSPATH") - set(_state "classpath") - elseif (${arg} STREQUAL "INSTALLPATH") - set(_state "installpath") - elseif (${arg} STREQUAL "DOCTITLE") - set(_state "doctitle") - elseif (${arg} STREQUAL "WINDOWTITLE") - set(_state "windowtitle") - elseif (${arg} STREQUAL "AUTHOR") - set(_state "author") - elseif (${arg} STREQUAL "USE") - set(_state "use") - elseif (${arg} STREQUAL "VERSION") - set(_state "version") - else () - list(APPEND _javadoc_sourcepath ${arg}) - endif () - elseif (${_state} STREQUAL "classpath") - if (${arg} STREQUAL "PACKAGES") - set(_state "packages") - elseif (${arg} STREQUAL "FILES") - set(_state "files") - elseif (${arg} STREQUAL "SOURCEPATH") - set(_state "sourcepath") - elseif (${arg} STREQUAL "INSTALLPATH") - set(_state "installpath") - elseif (${arg} STREQUAL "DOCTITLE") - set(_state "doctitle") - elseif (${arg} STREQUAL "WINDOWTITLE") - set(_state "windowtitle") - elseif (${arg} STREQUAL "AUTHOR") - set(_state "author") - elseif (${arg} STREQUAL "USE") - set(_state "use") - elseif (${arg} STREQUAL "VERSION") - set(_state "version") - else () - list(APPEND _javadoc_classpath ${arg}) - endif () - elseif (${_state} STREQUAL "installpath") - if (${arg} STREQUAL "PACKAGES") - set(_state "packages") - elseif (${arg} STREQUAL "FILES") - set(_state "files") - elseif (${arg} STREQUAL "SOURCEPATH") - set(_state "sourcepath") - elseif (${arg} STREQUAL "DOCTITLE") - set(_state "doctitle") - elseif (${arg} STREQUAL "WINDOWTITLE") - set(_state "windowtitle") - elseif (${arg} STREQUAL "AUTHOR") - set(_state "author") - elseif (${arg} STREQUAL "USE") - set(_state "use") - elseif (${arg} STREQUAL "VERSION") - set(_state "version") - else () - set(_javadoc_installpath ${arg}) - endif () - elseif (${_state} STREQUAL "doctitle") - if (${arg} STREQUAL "PACKAGES") - set(_state "packages") - elseif (${arg} STREQUAL "FILES") - set(_state "files") - elseif (${arg} STREQUAL "SOURCEPATH") - set(_state "sourcepath") - elseif (${arg} STREQUAL "INSTALLPATH") - set(_state "installpath") - elseif (${arg} STREQUAL "CLASSPATH") - set(_state "classpath") - elseif (${arg} STREQUAL "WINDOWTITLE") - set(_state "windowtitle") - elseif (${arg} STREQUAL "AUTHOR") - set(_state "author") - elseif (${arg} STREQUAL "USE") - set(_state "use") - elseif (${arg} STREQUAL "VERSION") - set(_state "version") - else () - set(_javadoc_doctitle ${arg}) - endif () - elseif (${_state} STREQUAL "windowtitle") - if (${arg} STREQUAL "PACKAGES") - set(_state "packages") - elseif (${arg} STREQUAL "FILES") - set(_state "files") - elseif (${arg} STREQUAL "SOURCEPATH") - set(_state "sourcepath") - elseif (${arg} STREQUAL "CLASSPATH") - set(_state "classpath") - elseif (${arg} STREQUAL "INSTALLPATH") - set(_state "installpath") - elseif (${arg} STREQUAL "DOCTITLE") - set(_state "doctitle") - elseif (${arg} STREQUAL "AUTHOR") - set(_state "author") - elseif (${arg} STREQUAL "USE") - set(_state "use") - elseif (${arg} STREQUAL "VERSION") - set(_state "version") - else () - set(_javadoc_windowtitle ${arg}) - endif () - elseif (${_state} STREQUAL "author") - if (${arg} STREQUAL "PACKAGES") - set(_state "packages") - elseif (${arg} STREQUAL "FILES") - set(_state "files") - elseif (${arg} STREQUAL "SOURCEPATH") - set(_state "sourcepath") - elseif (${arg} STREQUAL "CLASSPATH") - set(_state "classpath") - elseif (${arg} STREQUAL "INSTALLPATH") - set(_state "installpath") - elseif (${arg} STREQUAL "DOCTITLE") - set(_state "doctitle") - elseif (${arg} STREQUAL "WINDOWTITLE") - set(_state "windowtitle") - elseif (${arg} STREQUAL "AUTHOR") - set(_state "author") - elseif (${arg} STREQUAL "USE") - set(_state "use") - elseif (${arg} STREQUAL "VERSION") - set(_state "version") - else () - set(_javadoc_author ${arg}) - endif () - elseif (${_state} STREQUAL "use") - if (${arg} STREQUAL "PACKAGES") - set(_state "packages") - elseif (${arg} STREQUAL "FILES") - set(_state "files") - elseif (${arg} STREQUAL "SOURCEPATH") - set(_state "sourcepath") - elseif (${arg} STREQUAL "CLASSPATH") - set(_state "classpath") - elseif (${arg} STREQUAL "INSTALLPATH") - set(_state "installpath") - elseif (${arg} STREQUAL "DOCTITLE") - set(_state "doctitle") - elseif (${arg} STREQUAL "WINDOWTITLE") - set(_state "windowtitle") - elseif (${arg} STREQUAL "AUTHOR") - set(_state "author") - elseif (${arg} STREQUAL "USE") - set(_state "use") - elseif (${arg} STREQUAL "VERSION") - set(_state "version") - else () - set(_javadoc_use ${arg}) - endif () - elseif (${_state} STREQUAL "version") - if (${arg} STREQUAL "PACKAGES") - set(_state "packages") - elseif (${arg} STREQUAL "FILES") - set(_state "files") - elseif (${arg} STREQUAL "SOURCEPATH") - set(_state "sourcepath") - elseif (${arg} STREQUAL "CLASSPATH") - set(_state "classpath") - elseif (${arg} STREQUAL "INSTALLPATH") - set(_state "installpath") - elseif (${arg} STREQUAL "DOCTITLE") - set(_state "doctitle") - elseif (${arg} STREQUAL "WINDOWTITLE") - set(_state "windowtitle") - elseif (${arg} STREQUAL "AUTHOR") - set(_state "author") - elseif (${arg} STREQUAL "USE") - set(_state "use") - elseif (${arg} STREQUAL "VERSION") - set(_state "version") - else () - set(_javadoc_version ${arg}) - endif () - endif (${_state} STREQUAL "package") - endforeach (arg ${ARGN}) - - set(_javadoc_builddir ${CMAKE_CURRENT_BINARY_DIR}/javadoc/${_target}) - set(_javadoc_options -d ${_javadoc_builddir}) - - if (_javadoc_sourcepath) - set(_start TRUE) - foreach(_path ${_javadoc_sourcepath}) - if (_start) - set(_sourcepath ${_path}) - set(_start FALSE) - else (_start) - set(_sourcepath ${_sourcepath}:${_path}) - endif (_start) - endforeach(_path ${_javadoc_sourcepath}) - set(_javadoc_options ${_javadoc_options} -sourcepath ${_sourcepath}) - endif (_javadoc_sourcepath) - - if (_javadoc_classpath) - set(_start TRUE) - foreach(_path ${_javadoc_classpath}) - if (_start) - set(_classpath ${_path}) - set(_start FALSE) - else (_start) - set(_classpath ${_classpath}:${_path}) - endif (_start) - endforeach(_path ${_javadoc_classpath}) - set(_javadoc_options ${_javadoc_options} -classpath "${_classpath}") - endif (_javadoc_classpath) - - if (_javadoc_doctitle) - set(_javadoc_options ${_javadoc_options} -doctitle '${_javadoc_doctitle}') - endif (_javadoc_doctitle) - - if (_javadoc_windowtitle) - set(_javadoc_options ${_javadoc_options} -windowtitle '${_javadoc_windowtitle}') - endif (_javadoc_windowtitle) - - if (_javadoc_author) - set(_javadoc_options ${_javadoc_options} -author) - endif (_javadoc_author) - - if (_javadoc_use) - set(_javadoc_options ${_javadoc_options} -use) - endif (_javadoc_use) - - if (_javadoc_version) - set(_javadoc_options ${_javadoc_options} -version) - endif (_javadoc_version) - - add_custom_target(${_target}_javadoc ALL - COMMAND ${Java_JAVADOC_EXECUTABLE} ${_javadoc_options} - ${_javadoc_files} - ${_javadoc_packages} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - ) - - install( - DIRECTORY ${_javadoc_builddir} - DESTINATION ${_javadoc_installpath} - ) -endfunction(create_javadoc) diff --git a/cmake/UseJavaClassFilelist.cmake b/cmake/UseJavaClassFilelist.cmake deleted file mode 100644 index c842bf71a..000000000 --- a/cmake/UseJavaClassFilelist.cmake +++ /dev/null @@ -1,52 +0,0 @@ -# -# This script create a list of compiled Java class files to be added to a -# jar file. This avoids including cmake files which get created in the -# binary directory. -# - -#============================================================================= -# Copyright 2010-2011 Andreas schneider -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -if (CMAKE_JAVA_CLASS_OUTPUT_PATH) - if (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}") - - set(_JAVA_GLOBBED_FILES) - if (CMAKE_JAR_CLASSES_PREFIX) - foreach(JAR_CLASS_PREFIX ${CMAKE_JAR_CLASSES_PREFIX}) - message(STATUS "JAR_CLASS_PREFIX: ${JAR_CLASS_PREFIX}") - - file(GLOB_RECURSE _JAVA_GLOBBED_TMP_FILES "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${JAR_CLASS_PREFIX}/*.class") - if (_JAVA_GLOBBED_TMP_FILES) - list(APPEND _JAVA_GLOBBED_FILES ${_JAVA_GLOBBED_TMP_FILES}) - endif (_JAVA_GLOBBED_TMP_FILES) - endforeach(JAR_CLASS_PREFIX ${CMAKE_JAR_CLASSES_PREFIX}) - else() - file(GLOB_RECURSE _JAVA_GLOBBED_FILES "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/*.class") - endif (CMAKE_JAR_CLASSES_PREFIX) - - set(_JAVA_CLASS_FILES) - # file(GLOB_RECURSE foo RELATIVE) is broken so we need this. - foreach(_JAVA_GLOBBED_FILE ${_JAVA_GLOBBED_FILES}) - file(RELATIVE_PATH _JAVA_CLASS_FILE ${CMAKE_JAVA_CLASS_OUTPUT_PATH} ${_JAVA_GLOBBED_FILE}) - set(_JAVA_CLASS_FILES ${_JAVA_CLASS_FILES}${_JAVA_CLASS_FILE}\n) - endforeach(_JAVA_GLOBBED_FILE ${_JAVA_GLOBBED_FILES}) - - # write to file - file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist ${_JAVA_CLASS_FILES}) - - else (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}") - message(SEND_ERROR "FATAL: Java class output path doesn't exist") - endif (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}") -else (CMAKE_JAVA_CLASS_OUTPUT_PATH) - message(SEND_ERROR "FATAL: Can't find CMAKE_JAVA_CLASS_OUTPUT_PATH") -endif (CMAKE_JAVA_CLASS_OUTPUT_PATH) diff --git a/cmake/UseJavaSymlinks.cmake b/cmake/UseJavaSymlinks.cmake deleted file mode 100644 index c66ee1ea1..000000000 --- a/cmake/UseJavaSymlinks.cmake +++ /dev/null @@ -1,32 +0,0 @@ -# -# Helper script for UseJava.cmake -# - -#============================================================================= -# Copyright 2010-2011 Andreas schneider -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -if (UNIX AND _JAVA_TARGET_OUTPUT_LINK) - if (_JAVA_TARGET_OUTPUT_NAME) - find_program(LN_EXECUTABLE - NAMES - ln - ) - - execute_process( - COMMAND ${LN_EXECUTABLE} -sf "${_JAVA_TARGET_OUTPUT_NAME}" "${_JAVA_TARGET_OUTPUT_LINK}" - WORKING_DIRECTORY ${_JAVA_TARGET_DIR} - ) - else (_JAVA_TARGET_OUTPUT_NAME) - message(SEND_ERROR "FATAL: Can't find _JAVA_TARGET_OUTPUT_NAME") - endif (_JAVA_TARGET_OUTPUT_NAME) -endif (UNIX AND _JAVA_TARGET_OUTPUT_LINK) From 2fbb7be23bb31d0c5007a0500ad2a5d3a51f644e Mon Sep 17 00:00:00 2001 From: flow Date: Sat, 7 May 2022 20:16:55 -0300 Subject: [PATCH 02/52] fix: filter based on MIME type instead of plaintext suffix Suffixes are unreliable in different locales, while MIME types are more standarized. --- launcher/ui/dialogs/SkinUploadDialog.cpp | 3 ++- launcher/ui/pages/modplatform/ImportPage.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/launcher/ui/dialogs/SkinUploadDialog.cpp b/launcher/ui/dialogs/SkinUploadDialog.cpp index 6a5a324f5..8d137afce 100644 --- a/launcher/ui/dialogs/SkinUploadDialog.cpp +++ b/launcher/ui/dialogs/SkinUploadDialog.cpp @@ -100,7 +100,8 @@ void SkinUploadDialog::on_buttonBox_accepted() void SkinUploadDialog::on_skinBrowseBtn_clicked() { - QString raw_path = QFileDialog::getOpenFileName(this, tr("Select Skin Texture"), QString(), "*.png"); + auto filter = QMimeDatabase().mimeTypeForName("image/png").filterString(); + QString raw_path = QFileDialog::getOpenFileName(this, tr("Select Skin Texture"), QString(), filter); if (raw_path.isEmpty() || !QFileInfo::exists(raw_path)) { return; diff --git a/launcher/ui/pages/modplatform/ImportPage.cpp b/launcher/ui/pages/modplatform/ImportPage.cpp index 487bf77b1..1b53dd402 100644 --- a/launcher/ui/pages/modplatform/ImportPage.cpp +++ b/launcher/ui/pages/modplatform/ImportPage.cpp @@ -143,7 +143,8 @@ void ImportPage::setUrl(const QString& url) void ImportPage::on_modpackBtn_clicked() { - const QUrl url = QFileDialog::getOpenFileUrl(this, tr("Choose modpack"), modpackUrl(), tr("Zip (*.zip)")); + auto filter = QMimeDatabase().mimeTypeForName("application/zip").filterString(); + const QUrl url = QFileDialog::getOpenFileUrl(this, tr("Choose modpack"), modpackUrl(), filter); if (url.isValid()) { if (url.isLocalFile()) From 29a53d7e95508f6c7cd6c1945d2100cca98533c1 Mon Sep 17 00:00:00 2001 From: flow Date: Sat, 7 May 2022 20:42:19 -0300 Subject: [PATCH 03/52] fix: always have the instance toolbar be vertical This overrides the orientation set automatically by Qt when we start moving the toolbar around. --- launcher/ui/MainWindow.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index f34cf1ab9..44eba3694 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -746,6 +746,9 @@ public: // disabled until we have an instance selected instanceToolBar->setEnabled(false); instanceToolBar->setMovable(true); + // Qt doesn't like vertical moving toolbars, so we have to force them... + // See https://github.com/PolyMC/PolyMC/issues/493 + connect(instanceToolBar, &QToolBar::orientationChanged, [=](Qt::Orientation){ instanceToolBar->setOrientation(Qt::Vertical); }); instanceToolBar->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea); instanceToolBar->setToolButtonStyle(Qt::ToolButtonTextOnly); instanceToolBar->setFloatable(false); From bdd2d57808004ccd12b2438c7af9d163fbe96c0d Mon Sep 17 00:00:00 2001 From: Ozynt <58683893+Ozynt@users.noreply.github.com> Date: Sun, 8 May 2022 11:19:53 +0200 Subject: [PATCH 04/52] This makes more sense --- launcher/LaunchController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/LaunchController.cpp b/launcher/LaunchController.cpp index 4cb62e693..002c08b9c 100644 --- a/launcher/LaunchController.cpp +++ b/launcher/LaunchController.cpp @@ -93,7 +93,7 @@ void LaunchController::decideAccount() auto reply = CustomMessageBox::selectable( m_parentWidget, tr("No Accounts"), - tr("In order to play Minecraft, you must have at least one Mojang or Minecraft " + tr("In order to play Minecraft, you must have at least one Mojang or Microsoft " "account logged in. " "Would you like to open the account manager to add an account now?"), QMessageBox::Information, From ea9d61c21cd0b1419329371fb22e4c101e67dda0 Mon Sep 17 00:00:00 2001 From: Kenneth Chew Date: Sun, 8 May 2022 23:19:23 -0400 Subject: [PATCH 05/52] Retranslate account actions after switching language --- launcher/ui/MainWindow.cpp | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index f34cf1ab9..e5c4708c3 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -238,6 +238,9 @@ public: TranslatedAction actionREDDIT; TranslatedAction actionAbout; + TranslatedAction actionNoAccountsAdded; + TranslatedAction actionNoDefaultAccount; + QVector all_toolbuttons; QWidget *centralWidget = nullptr; @@ -1252,10 +1255,14 @@ void MainWindow::repopulateAccountsMenu() if (accounts->count() <= 0) { - QAction *action = new QAction(tr("No accounts added!"), this); - action->setEnabled(false); - accountMenu->addAction(action); - ui->profileMenu->addAction(action); + ui->all_actions.removeAll(&ui->actionNoAccountsAdded); + ui->actionNoAccountsAdded = TranslatedAction(this); + ui->actionNoAccountsAdded->setObjectName(QStringLiteral("actionNoAccountsAdded")); + ui->actionNoAccountsAdded.setTextId(QT_TRANSLATE_NOOP("MainWindow", "No accounts added!")); + ui->actionNoAccountsAdded->setEnabled(false); + accountMenu->addAction(ui->actionNoAccountsAdded); + ui->profileMenu->addAction(ui->actionNoAccountsAdded); + ui->all_actions.append(&ui->actionNoAccountsAdded); } else { @@ -1295,18 +1302,23 @@ void MainWindow::repopulateAccountsMenu() accountMenu->addSeparator(); ui->profileMenu->addSeparator(); - QAction *action = new QAction(tr("No Default Account"), this); - action->setCheckable(true); - action->setIcon(APPLICATION->getThemedIcon("noaccount")); - action->setData(-1); - action->setShortcut(QKeySequence(tr("Ctrl+0"))); + ui->all_actions.removeAll(&ui->actionNoDefaultAccount); + ui->actionNoDefaultAccount = TranslatedAction(this); + ui->actionNoDefaultAccount->setObjectName(QStringLiteral("actionNoDefaultAccount")); + ui->actionNoDefaultAccount.setTextId(QT_TRANSLATE_NOOP("MainWindow", "No Default Account")); + ui->actionNoDefaultAccount->setCheckable(true); + ui->actionNoDefaultAccount->setIcon(APPLICATION->getThemedIcon("noaccount")); + ui->actionNoDefaultAccount->setData(-1); + ui->actionNoDefaultAccount->setShortcut(QKeySequence(tr("Ctrl+0"))); if (!defaultAccount) { - action->setChecked(true); + ui->actionNoDefaultAccount->setChecked(true); } - accountMenu->addAction(action); - ui->profileMenu->addAction(action); - connect(action, SIGNAL(triggered(bool)), SLOT(changeActiveAccount())); + accountMenu->addAction(ui->actionNoDefaultAccount); + ui->profileMenu->addAction(ui->actionNoDefaultAccount); + connect(ui->actionNoDefaultAccount, SIGNAL(triggered(bool)), SLOT(changeActiveAccount())); + ui->all_actions.append(&ui->actionNoDefaultAccount); + ui->actionNoDefaultAccount.retranslate(); accountMenu->addSeparator(); ui->profileMenu->addSeparator(); From 5171d99fe5c8d08014412e320679b32c73fd2789 Mon Sep 17 00:00:00 2001 From: Kenneth Chew Date: Sun, 8 May 2022 23:42:37 -0400 Subject: [PATCH 06/52] Retranslate playtime text immediately when language is changed --- launcher/ui/MainWindow.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index e5c4708c3..85f4157b9 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -831,7 +831,7 @@ public: QMetaObject::connectSlotsByName(MainWindow); } // setupUi - void retranslateUi(QMainWindow *MainWindow) + void retranslateUi(MainWindow *MainWindow) { QString winTitle = tr("%1 - Version %2", "Launcher - Version X").arg(BuildConfig.LAUNCHER_DISPLAYNAME, BuildConfig.printableVersionString()); MainWindow->setWindowTitle(winTitle); @@ -851,6 +851,12 @@ public: // submenu buttons foldersMenuButton->setText(tr("Folders")); helpMenuButton->setText(tr("Help")); + + // playtime counter + if (MainWindow->m_statusCenter) + { + MainWindow->updateStatusCenter(); + } } // retranslateUi }; From 40e0252d7d5f994b8ff6764bcdb7d9416881ccfe Mon Sep 17 00:00:00 2001 From: Kenneth Chew Date: Mon, 9 May 2022 00:54:47 -0400 Subject: [PATCH 07/52] Show "executable" screenshots in the screenshot manager Since the readable/writable filter was removed to do this, extra code was added to enable/disable certain buttons based on whether the screenshot is readable or writable. --- .../ui/pages/instance/ScreenshotsPage.cpp | 27 ++++++++++++++++++- launcher/ui/pages/instance/ScreenshotsPage.h | 1 + 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/launcher/ui/pages/instance/ScreenshotsPage.cpp b/launcher/ui/pages/instance/ScreenshotsPage.cpp index e694ebe3e..2cf17b32f 100644 --- a/launcher/ui/pages/instance/ScreenshotsPage.cpp +++ b/launcher/ui/pages/instance/ScreenshotsPage.cpp @@ -251,7 +251,7 @@ ScreenshotsPage::ScreenshotsPage(QString path, QWidget *parent) m_model.reset(new QFileSystemModel()); m_filterModel.reset(new FilterModel()); m_filterModel->setSourceModel(m_model.get()); - m_model->setFilter(QDir::Files | QDir::Writable | QDir::Readable); + m_model->setFilter(QDir::Files); m_model->setReadOnly(false); m_model->setNameFilters({"*.png"}); m_model->setNameFilterDisables(false); @@ -343,6 +343,29 @@ void ScreenshotsPage::onItemActivated(QModelIndex index) DesktopServices::openFile(info.absoluteFilePath()); } +void ScreenshotsPage::onCurrentSelectionChanged(const QItemSelection &selected) +{ + bool allReadable = !selected.isEmpty(); + bool allWritable = !selected.isEmpty(); + + for (auto index : selected.indexes()) + { + if (!index.isValid()) + break; + auto info = m_model->fileInfo(index); + if (!info.isReadable()) + allReadable = false; + if (!info.isWritable()) + allWritable = false; + } + + ui->actionUpload->setEnabled(allReadable); + ui->actionCopy_Image->setEnabled(allReadable); + ui->actionCopy_File_s->setEnabled(allReadable); + ui->actionDelete->setEnabled(allWritable); + ui->actionRename->setEnabled(allWritable); +} + void ScreenshotsPage::on_actionView_Folder_triggered() { DesktopServices::openDirectory(m_folder, true); @@ -503,6 +526,8 @@ void ScreenshotsPage::openedImpl() if(idx.isValid()) { ui->listView->setModel(m_filterModel.get()); + connect(ui->listView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &ScreenshotsPage::onCurrentSelectionChanged); + onCurrentSelectionChanged(ui->listView->selectionModel()->selection()); // set initial button enable states ui->listView->setRootIndex(m_filterModel->mapFromSource(idx)); } else diff --git a/launcher/ui/pages/instance/ScreenshotsPage.h b/launcher/ui/pages/instance/ScreenshotsPage.h index 50cf1a177..c22706af9 100644 --- a/launcher/ui/pages/instance/ScreenshotsPage.h +++ b/launcher/ui/pages/instance/ScreenshotsPage.h @@ -100,6 +100,7 @@ private slots: void on_actionRename_triggered(); void on_actionView_Folder_triggered(); void onItemActivated(QModelIndex); + void onCurrentSelectionChanged(const QItemSelection &selected); void ShowContextMenu(const QPoint &pos); private: From 96b2758169a7a003e2daba150bb897e702316c6f Mon Sep 17 00:00:00 2001 From: DioEgizio <83089242+DioEgizio@users.noreply.github.com> Date: Mon, 9 May 2022 17:42:17 +0200 Subject: [PATCH 08/52] fix websiteurl in curseforge modpacks --- launcher/modplatform/flame/FlamePackIndex.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/modplatform/flame/FlamePackIndex.cpp b/launcher/modplatform/flame/FlamePackIndex.cpp index 549cace65..ac24c6471 100644 --- a/launcher/modplatform/flame/FlamePackIndex.cpp +++ b/launcher/modplatform/flame/FlamePackIndex.cpp @@ -6,7 +6,7 @@ void Flame::loadIndexedPack(Flame::IndexedPack& pack, QJsonObject& obj) { pack.addonId = Json::requireInteger(obj, "id"); pack.name = Json::requireString(obj, "name"); - pack.websiteUrl = Json::ensureString(obj, "websiteUrl", ""); + pack.websiteUrl = Json::ensureString(Json::ensureObject(obj, "links"), "websiteUrl", ""); pack.description = Json::ensureString(obj, "summary", ""); auto logo = Json::requireObject(obj, "logo"); From 288e7bc9c5e1358d1ad78961cd1a771e6292014e Mon Sep 17 00:00:00 2001 From: Kenneth Chew Date: Mon, 9 May 2022 03:20:53 -0400 Subject: [PATCH 09/52] Make profile menu scrollable --- launcher/ui/MainWindow.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index f34cf1ab9..9e1074f81 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -950,6 +950,8 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow ui->mainToolBar->addWidget(spacer); accountMenu = new QMenu(this); + // Use undocumented property... https://stackoverflow.com/questions/7121718/create-a-scrollbar-in-a-submenu-qt + accountMenu->setStyleSheet("QMenu { menu-scrollable: 1; }"); repopulateAccountsMenu(); From 527fa7ba9cb4e29277acdbedf4880f6fc2255a8b Mon Sep 17 00:00:00 2001 From: Kenneth Chew Date: Mon, 9 May 2022 15:58:08 -0400 Subject: [PATCH 10/52] Hide temporary directory in instances folder --- launcher/InstanceList.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/launcher/InstanceList.cpp b/launcher/InstanceList.cpp index 6e37e3d80..847d897ef 100644 --- a/launcher/InstanceList.cpp +++ b/launcher/InstanceList.cpp @@ -38,6 +38,10 @@ #include "ExponentialSeries.h" #include "WatchLock.h" +#ifdef Q_OS_WIN32 +#include +#endif + const static int GROUP_FILE_FORMAT_VERSION = 1; InstanceList::InstanceList(SettingsObjectPtr settings, const QString & instDir, QObject *parent) @@ -851,13 +855,18 @@ Task * InstanceList::wrapInstanceTask(InstanceTask * task) QString InstanceList::getStagedInstancePath() { QString key = QUuid::createUuid().toString(); - QString relPath = FS::PathCombine("_LAUNCHER_TEMP/" , key); + QString tempDir = ".LAUNCHER_TEMP/"; + QString relPath = FS::PathCombine(tempDir, key); QDir rootPath(m_instDir); auto path = FS::PathCombine(m_instDir, relPath); if(!rootPath.mkpath(relPath)) { return QString(); } +#ifdef Q_OS_WIN32 + auto tempPath = FS::PathCombine(m_instDir, tempDir); + SetFileAttributesA(tempPath.toStdString().c_str(), FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED); +#endif return path; } From 512d7b07d01d82822a728b40dddb0efbf441dc00 Mon Sep 17 00:00:00 2001 From: DioEgizio <83089242+DioEgizio@users.noreply.github.com> Date: Wed, 11 May 2022 15:18:07 +0200 Subject: [PATCH 11/52] chore: add version of polymc area in bug report template --- .github/ISSUE_TEMPLATE/bug_report.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 1ede3f743..b387f46a2 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -23,6 +23,13 @@ body: - macOS - Linux - Other +- type: textarea + attributes: + label: Version of PolyMC + description: The version of PolyMC used in the bug report. + placeholder: PolyMC 1.2.2 + validations: + required: true - type: textarea attributes: label: Description of bug From 37e8f495b420be9c59e0349235bb5940249ed666 Mon Sep 17 00:00:00 2001 From: Ezekiel Smith Date: Thu, 12 May 2022 23:39:48 +1000 Subject: [PATCH 12/52] CurseForge API Key update to PolyMC key Use the key CurseForge provided me to use for PolyMC *pr done on mobile if someone could test that would be great* --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b052fa1e6..4d3683d7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,7 +91,7 @@ set(Launcher_MSA_CLIENT_ID "549033b2-1532-4d4e-ae77-1bbaa46f9d74" CACHE STRING " # CurseForge API Key # CHANGE THIS IF YOU FORK THIS PROJECT! -set(Launcher_CURSEFORGE_API_KEY "$2a$10$iR1RdPDG95FWdILZbHuoMOlV4vL4eckBx7QPZR6SVZmliEb9ZQplu" CACHE STRING "CurseForge API Key") +set(Launcher_CURSEFORGE_API_KEY "$2a$10$1Oqr2MX3O4n/ilhFGc597u8tfI3L2Hyr9/rtWDAMRjghSQV2QUuxq" CACHE STRING "CurseForge API Key") # Bug tracker URL set(Launcher_BUG_TRACKER_URL "https://github.com/PolyMC/PolyMC/issues" CACHE STRING "URL for the bug tracker.") From 046f1e6e58b7a28f336bb2ed79995656fe66f0bf Mon Sep 17 00:00:00 2001 From: Kenneth Chew Date: Thu, 12 May 2022 17:00:17 -0400 Subject: [PATCH 13/52] Add instance overrides for miscellaneous settings --- launcher/minecraft/MinecraftInstance.cpp | 7 ++++++- launcher/minecraft/launch/LauncherPartLaunch.cpp | 6 ++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index 3ba79178c..e20dc24c7 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -162,6 +162,11 @@ MinecraftInstance::MinecraftInstance(SettingsObjectPtr globalSettings, SettingsO m_settings->registerSetting("JoinServerOnLaunch", false); m_settings->registerSetting("JoinServerOnLaunchAddress", ""); + // Miscellaneous + auto miscellaneousOverride = m_settings->registerSetting("OverrideMiscellaneous", false); + m_settings->registerOverride(globalSettings->getSetting("CloseAfterLaunch"), miscellaneousOverride); + m_settings->registerOverride(globalSettings->getSetting("QuitAfterGameStop"), miscellaneousOverride); + m_components.reset(new PackProfile(this)); } @@ -984,7 +989,7 @@ shared_qobject_ptr MinecraftInstance::createLaunchTask(AuthSessionPt { process->setCensorFilter(createCensorFilterFromSession(session)); } - if(APPLICATION->settings()->get("QuitAfterGameStop").toBool()) + if(m_settings->get("QuitAfterGameStop").toBool()) { auto step = new QuitAfterGameStop(pptr); process->appendStep(step); diff --git a/launcher/minecraft/launch/LauncherPartLaunch.cpp b/launcher/minecraft/launch/LauncherPartLaunch.cpp index 173f29b50..d7010355a 100644 --- a/launcher/minecraft/launch/LauncherPartLaunch.cpp +++ b/launcher/minecraft/launch/LauncherPartLaunch.cpp @@ -25,7 +25,8 @@ LauncherPartLaunch::LauncherPartLaunch(LaunchTask *parent) : LaunchStep(parent) { - if (APPLICATION->settings()->get("CloseAfterLaunch").toBool()) + auto instance = parent->instance(); + if (instance->settings()->get("CloseAfterLaunch").toBool()) { std::shared_ptr connection{new QMetaObject::Connection}; *connection = connect(&m_process, &LoggedProcess::log, this, [=](QStringList lines, MessageLevel::Enum level) { @@ -168,7 +169,8 @@ void LauncherPartLaunch::on_state(LoggedProcess::State state) } case LoggedProcess::Finished: { - if (APPLICATION->settings()->get("CloseAfterLaunch").toBool()) + auto instance = m_parent->instance(); + if (instance->settings()->get("CloseAfterLaunch").toBool()) APPLICATION->showMainWindow(); m_parent->setPid(-1); From 3aea639fe4359259a27e971ae357e308ae50e69d Mon Sep 17 00:00:00 2001 From: Kenneth Chew Date: Thu, 12 May 2022 17:11:06 -0400 Subject: [PATCH 14/52] Add UI for miscellaneous instance setting overrides --- .../pages/instance/InstanceSettingsPage.cpp | 19 ++++++++++++ .../ui/pages/instance/InstanceSettingsPage.ui | 29 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.cpp b/launcher/ui/pages/instance/InstanceSettingsPage.cpp index a48c4d695..b45628432 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.cpp +++ b/launcher/ui/pages/instance/InstanceSettingsPage.cpp @@ -101,6 +101,20 @@ void InstanceSettingsPage::applySettings() { SettingsObject::Lock lock(m_settings); + // Miscellaneous + bool miscellaneous = ui->miscellaneousSettingsBox->isChecked(); + m_settings->set("OverrideMiscellaneous", miscellaneous); + if (miscellaneous) + { + m_settings->set("CloseAfterLaunch", ui->closeAfterLaunchCheck->isChecked()); + m_settings->set("QuitAfterGameStop", ui->quitAfterGameStopCheck->isChecked()); + } + else + { + m_settings->reset("CloseAfterLaunch"); + m_settings->reset("QuitAfterGameStop"); + } + // Console bool console = ui->consoleSettingsBox->isChecked(); m_settings->set("OverrideConsole", console); @@ -247,6 +261,11 @@ void InstanceSettingsPage::applySettings() void InstanceSettingsPage::loadSettings() { + // Miscellaneous + ui->miscellaneousSettingsBox->setChecked(m_settings->get("OverrideMiscellaneous").toBool()); + ui->closeAfterLaunchCheck->setChecked(m_settings->get("CloseAfterLaunch").toBool()); + ui->quitAfterGameStopCheck->setChecked(m_settings->get("QuitAfterGameStop").toBool()); + // Console ui->consoleSettingsBox->setChecked(m_settings->get("OverrideConsole").toBool()); ui->showConsoleCheck->setChecked(m_settings->get("ShowConsole").toBool()); diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.ui b/launcher/ui/pages/instance/InstanceSettingsPage.ui index 5db2d1473..cb66b3ce5 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.ui +++ b/launcher/ui/pages/instance/InstanceSettingsPage.ui @@ -349,6 +349,35 @@
+ + + + Miscellaneous + + + true + + + false + + + + + + Close the launcher after game window opens + + + + + + + Quit the launcher after game window closes + + + + + + From 84b962f256a492ae9a82846be40b726c8bd90e9c Mon Sep 17 00:00:00 2001 From: flow Date: Fri, 13 May 2022 17:21:35 -0300 Subject: [PATCH 15/52] fix: Handle icons with a dot in their names E.g. some FTB modpacks. Also fixes an issue with the name viewing on the Icon Chooser dialog when the name was too big. --- launcher/icons/IconList.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/launcher/icons/IconList.cpp b/launcher/icons/IconList.cpp index 584edd69e..c269d10a2 100644 --- a/launcher/icons/IconList.cpp +++ b/launcher/icons/IconList.cpp @@ -36,7 +36,7 @@ IconList::IconList(const QStringList &builtinPaths, QString path, QObject *paren auto file_info_list = instance_icons.entryInfoList(QDir::Files, QDir::Name); for (auto file_info : file_info_list) { - builtinNames.insert(file_info.baseName()); + builtinNames.insert(file_info.completeBaseName()); } } for(auto & builtinName : builtinNames) @@ -51,6 +51,9 @@ IconList::IconList(const QStringList &builtinPaths, QString path, QObject *paren connect(m_watcher.get(), SIGNAL(fileChanged(QString)), SLOT(fileChanged(QString))); directoryChanged(path); + + // Forces the UI to update, so that lengthy icon names are shown properly from the start + emit iconUpdated({}); } void IconList::directoryChanged(const QString &path) @@ -94,7 +97,13 @@ void IconList::directoryChanged(const QString &path) { qDebug() << "Removing " << remove; QFileInfo rmfile(remove); - QString key = rmfile.baseName(); + QString key = rmfile.completeBaseName(); + + QString suffix = rmfile.suffix(); + // The icon doesnt have a suffix, but it can have other .s in the name, so we account for those as well + if (suffix != "jpeg" && suffix != "png" && suffix != "jpg" && suffix != "ico" && suffix != "svg" && suffix != "gif") + key = rmfile.fileName(); + int idx = getIconIndex(key); if (idx == -1) continue; @@ -117,8 +126,15 @@ void IconList::directoryChanged(const QString &path) for (auto add : to_add) { qDebug() << "Adding " << add; + QFileInfo addfile(add); - QString key = addfile.baseName(); + QString key = addfile.completeBaseName(); + + QString suffix = addfile.suffix(); + // The icon doesnt have a suffix, but it can have other .s in the name, so we account for those as well + if (suffix != "jpeg" && suffix != "png" && suffix != "jpg" && suffix != "ico" && suffix != "svg" && suffix != "gif") + key = addfile.fileName(); + if (addIcon(key, QString(), addfile.filePath(), IconType::FileBased)) { m_watcher->addPath(add); @@ -133,7 +149,7 @@ void IconList::fileChanged(const QString &path) QFileInfo checkfile(path); if (!checkfile.exists()) return; - QString key = checkfile.baseName(); + QString key = checkfile.completeBaseName(); int idx = getIconIndex(key); if (idx == -1) return; From c6b3eccbdf2785b59ab33ed99fabf6f3f5d81d2a Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Sat, 14 May 2022 19:46:52 +0200 Subject: [PATCH 16/52] refactor: rename Modrinth classes to ModrinthMod --- launcher/CMakeLists.txt | 8 ++++---- launcher/ui/dialogs/ModDownloadDialog.cpp | 4 ++-- launcher/ui/dialogs/ModDownloadDialog.h | 4 ++-- .../{ModrinthModel.cpp => ModrinthModModel.cpp} | 2 +- .../{ModrinthModel.h => ModrinthModModel.h} | 4 ++-- .../{ModrinthPage.cpp => ModrinthModPage.cpp} | 16 ++++++++-------- .../{ModrinthPage.h => ModrinthModPage.h} | 6 +++--- 7 files changed, 22 insertions(+), 22 deletions(-) rename launcher/ui/pages/modplatform/modrinth/{ModrinthModel.cpp => ModrinthModModel.cpp} (97%) rename launcher/ui/pages/modplatform/modrinth/{ModrinthModel.h => ModrinthModModel.h} (85%) rename launcher/ui/pages/modplatform/modrinth/{ModrinthPage.cpp => ModrinthModPage.cpp} (85%) rename launcher/ui/pages/modplatform/modrinth/{ModrinthPage.h => ModrinthModPage.h} (93%) diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index b79f03c86..16ec4c047 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -782,10 +782,10 @@ SET(LAUNCHER_SOURCES ui/pages/modplatform/ImportPage.cpp ui/pages/modplatform/ImportPage.h - ui/pages/modplatform/modrinth/ModrinthModel.cpp - ui/pages/modplatform/modrinth/ModrinthModel.h - ui/pages/modplatform/modrinth/ModrinthPage.cpp - ui/pages/modplatform/modrinth/ModrinthPage.h + ui/pages/modplatform/modrinth/ModrinthModModel.cpp + ui/pages/modplatform/modrinth/ModrinthModModel.h + ui/pages/modplatform/modrinth/ModrinthModPage.cpp + ui/pages/modplatform/modrinth/ModrinthModPage.h # GUI - dialogs ui/dialogs/AboutDialog.cpp diff --git a/launcher/ui/dialogs/ModDownloadDialog.cpp b/launcher/ui/dialogs/ModDownloadDialog.cpp index d02ea4769..305e85c06 100644 --- a/launcher/ui/dialogs/ModDownloadDialog.cpp +++ b/launcher/ui/dialogs/ModDownloadDialog.cpp @@ -13,7 +13,7 @@ #include #include "ui/widgets/PageContainer.h" -#include "ui/pages/modplatform/modrinth/ModrinthPage.h" +#include "ui/pages/modplatform/modrinth/ModrinthModPage.h" #include "ModDownloadTask.h" @@ -98,7 +98,7 @@ void ModDownloadDialog::accept() QList ModDownloadDialog::getPages() { - modrinthPage = new ModrinthPage(this, m_instance); + modrinthPage = new ModrinthModPage(this, m_instance); flameModPage = new FlameModPage(this, m_instance); return { diff --git a/launcher/ui/dialogs/ModDownloadDialog.h b/launcher/ui/dialogs/ModDownloadDialog.h index 309d89d06..782dc3619 100644 --- a/launcher/ui/dialogs/ModDownloadDialog.h +++ b/launcher/ui/dialogs/ModDownloadDialog.h @@ -16,7 +16,7 @@ class ModDownloadDialog; class PageContainer; class QDialogButtonBox; -class ModrinthPage; +class ModrinthModPage; class ModDownloadDialog : public QDialog, public BasePageProvider { @@ -50,7 +50,7 @@ private: QVBoxLayout *m_verticalLayout = nullptr; - ModrinthPage *modrinthPage = nullptr; + ModrinthModPage *modrinthPage = nullptr; FlameModPage *flameModPage = nullptr; QHash modTask; BaseInstance *m_instance; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModModel.cpp similarity index 97% rename from launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp rename to launcher/ui/pages/modplatform/modrinth/ModrinthModModel.cpp index b788860a3..1d9f4d60b 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModModel.cpp @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -#include "ModrinthModel.h" +#include "ModrinthModModel.h" #include "modplatform/modrinth/ModrinthPackIndex.h" diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModModel.h similarity index 85% rename from launcher/ui/pages/modplatform/modrinth/ModrinthModel.h rename to launcher/ui/pages/modplatform/modrinth/ModrinthModModel.h index 45a6090a7..63c23bbeb 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModModel.h @@ -1,6 +1,6 @@ #pragma once -#include "ModrinthPage.h" +#include "ModrinthModPage.h" namespace Modrinth { @@ -8,7 +8,7 @@ class ListModel : public ModPlatform::ListModel { Q_OBJECT public: - ListModel(ModrinthPage* parent) : ModPlatform::ListModel(parent){}; + ListModel(ModrinthModPage* parent) : ModPlatform::ListModel(parent){}; ~ListModel() override = default; private: diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.cpp similarity index 85% rename from launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp rename to launcher/ui/pages/modplatform/modrinth/ModrinthModPage.cpp index 98bde0ae3..d3a1f8594 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.cpp @@ -33,14 +33,14 @@ * limitations under the License. */ -#include "ModrinthPage.h" +#include "ModrinthModPage.h" #include "modplatform/modrinth/ModrinthAPI.h" #include "ui_ModPage.h" -#include "ModrinthModel.h" +#include "ModrinthModModel.h" #include "ui/dialogs/ModDownloadDialog.h" -ModrinthPage::ModrinthPage(ModDownloadDialog* dialog, BaseInstance* instance) +ModrinthModPage::ModrinthModPage(ModDownloadDialog* dialog, BaseInstance* instance) : ModPage(dialog, instance, new ModrinthAPI()) { listModel = new Modrinth::ListModel(this); @@ -56,12 +56,12 @@ ModrinthPage::ModrinthPage(ModDownloadDialog* dialog, BaseInstance* instance) // sometimes Qt just ignores virtual slots and doesn't work as intended it seems, // so it's best not to connect them in the parent's constructor... connect(ui->sortByBox, SIGNAL(currentIndexChanged(int)), this, SLOT(triggerSearch())); - connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ModrinthPage::onSelectionChanged); - connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &ModrinthPage::onVersionSelectionChanged); - connect(ui->modSelectionButton, &QPushButton::clicked, this, &ModrinthPage::onModSelected); + connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ModrinthModPage::onSelectionChanged); + connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &ModrinthModPage::onVersionSelectionChanged); + connect(ui->modSelectionButton, &QPushButton::clicked, this, &ModrinthModPage::onModSelected); } -auto ModrinthPage::validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderType loader) const -> bool +auto ModrinthModPage::validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderType loader) const -> bool { auto loaderStrings = ModrinthAPI::getModLoaderStrings(loader); @@ -79,4 +79,4 @@ auto ModrinthPage::validateVersion(ModPlatform::IndexedVersion& ver, QString min // I don't know why, but doing this on the parent class makes it so that // other mod providers start loading before being selected, at least with // my Qt, so we need to implement this in every derived class... -auto ModrinthPage::shouldDisplay() const -> bool { return true; } +auto ModrinthModPage::shouldDisplay() const -> bool { return true; } diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.h similarity index 93% rename from launcher/ui/pages/modplatform/modrinth/ModrinthPage.h rename to launcher/ui/pages/modplatform/modrinth/ModrinthModPage.h index e3a0e1f00..b1e72bfea 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.h @@ -40,12 +40,12 @@ #include "modplatform/modrinth/ModrinthAPI.h" -class ModrinthPage : public ModPage { +class ModrinthModPage : public ModPage { Q_OBJECT public: - explicit ModrinthPage(ModDownloadDialog* dialog, BaseInstance* instance); - ~ModrinthPage() override = default; + explicit ModrinthModPage(ModDownloadDialog* dialog, BaseInstance* instance); + ~ModrinthModPage() override = default; inline auto displayName() const -> QString override { return "Modrinth"; } inline auto icon() const -> QIcon override { return APPLICATION->getThemedIcon("modrinth"); } From db038463581400005f045a277a249ab07175ab2b Mon Sep 17 00:00:00 2001 From: kb1000 Date: Mon, 31 Jan 2022 15:25:36 +0100 Subject: [PATCH 17/52] Add support for importing Modrinth packs from files --- launcher/CMakeLists.txt | 10 ++ launcher/InstanceImportTask.cpp | 170 +++++++++++++++++- launcher/InstanceImportTask.h | 6 +- .../modrinth/ModrinthPackManifest.cpp | 16 ++ .../modrinth/ModrinthPackManifest.h | 32 ++++ launcher/resources/multimc/multimc.qrc | 3 + .../resources/multimc/scalable/modrinth.svg | 4 + launcher/ui/dialogs/NewInstanceDialog.cpp | 2 + launcher/ui/pages/modplatform/ImportPage.cpp | 4 +- .../modplatform/modrinth/ModrinthPage.cpp | 55 ++++++ .../pages/modplatform/modrinth/ModrinthPage.h | 62 +++++++ .../modplatform/modrinth/ModrinthPage.ui | 94 ++++++++++ 12 files changed, 452 insertions(+), 6 deletions(-) create mode 100644 launcher/modplatform/modrinth/ModrinthPackManifest.cpp create mode 100644 launcher/modplatform/modrinth/ModrinthPackManifest.h create mode 100644 launcher/resources/multimc/scalable/modrinth.svg create mode 100644 launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp create mode 100644 launcher/ui/pages/modplatform/modrinth/ModrinthPage.h create mode 100644 launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 16ec4c047..cbe135e2b 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -563,6 +563,11 @@ set(ATLAUNCHER_SOURCES modplatform/atlauncher/ATLShareCode.h ) +set(MODRINTH_SOURCES + modplatform/modrinth/ModrinthPackManifest.cpp + modplatform/modrinth/ModrinthPackManifest.h +) + add_unit_test(Index SOURCES meta/Index_test.cpp LIBS Launcher_logic @@ -596,6 +601,7 @@ set(LOGIC_SOURCES ${MODPACKSCH_SOURCES} ${TECHNIC_SOURCES} ${ATLAUNCHER_SOURCES} + ${MODRINTH_SOURCES} ) SET(LAUNCHER_SOURCES @@ -774,6 +780,9 @@ SET(LAUNCHER_SOURCES ui/pages/modplatform/flame/FlameModPage.cpp ui/pages/modplatform/flame/FlameModPage.h + ui/pages/modplatform/modrinth/ModrinthPage.cpp + ui/pages/modplatform/modrinth/ModrinthPage.h + ui/pages/modplatform/technic/TechnicModel.cpp ui/pages/modplatform/technic/TechnicModel.h ui/pages/modplatform/technic/TechnicPage.cpp @@ -908,6 +917,7 @@ qt5_wrap_ui(LAUNCHER_UI ui/pages/modplatform/legacy_ftb/Page.ui ui/pages/modplatform/ImportPage.ui ui/pages/modplatform/ftb/FtbPage.ui + ui/pages/modplatform/modrinth/ModrinthPage.ui ui/pages/modplatform/technic/TechnicPage.ui ui/widgets/InstanceCardWidget.ui ui/widgets/CustomCommands.ui diff --git a/launcher/InstanceImportTask.cpp b/launcher/InstanceImportTask.cpp index 1a13c9973..517155811 100644 --- a/launcher/InstanceImportTask.cpp +++ b/launcher/InstanceImportTask.cpp @@ -30,10 +30,15 @@ #include "modplatform/flame/PackManifest.h" #include "Json.h" #include +#include "modplatform/modrinth/ModrinthPackManifest.h" #include "modplatform/technic/TechnicPackProcessor.h" #include "icons/IconList.h" #include "Application.h" +#include "net/ChecksumValidator.h" + +#include +#include InstanceImportTask::InstanceImportTask(const QUrl sourceUrl) { @@ -109,6 +114,7 @@ void InstanceImportTask::processZipPack() QString mmcFound = MMCZip::findFolderOfFileInZip(m_packZip.get(), "instance.cfg"); bool technicFound = QuaZipDir(m_packZip.get()).exists("/bin/modpack.jar") || QuaZipDir(m_packZip.get()).exists("/bin/version.json"); QString flameFound = MMCZip::findFolderOfFileInZip(m_packZip.get(), "manifest.json"); + QString modrinthFound = MMCZip::findFolderOfFileInZip(m_packZip.get(), "modrinth.index.json"); QString root; if(!mmcFound.isNull()) { @@ -132,6 +138,13 @@ void InstanceImportTask::processZipPack() root = flameFound; m_modpackType = ModpackType::Flame; } + else if(!modrinthFound.isNull()) + { + // process as Modrinth pack + qDebug() << "Modrinth:" << modrinthFound; + root = modrinthFound; + m_modpackType = ModpackType::Modrinth; + } if(m_modpackType == ModpackType::Unknown) { emitFailed(tr("Archive does not contain a recognized modpack type.")); @@ -188,15 +201,18 @@ void InstanceImportTask::extractFinished() switch(m_modpackType) { - case ModpackType::Flame: - processFlame(); - return; case ModpackType::MultiMC: processMultiMC(); return; case ModpackType::Technic: processTechnic(); return; + case ModpackType::Flame: + processFlame(); + return; + case ModpackType::Modrinth: + processModrinth(); + return; case ModpackType::Unknown: emitFailed(tr("Archive does not contain a recognized modpack type.")); return; @@ -461,3 +477,151 @@ void InstanceImportTask::processMultiMC() } emitSucceeded(); } + +void InstanceImportTask::processModrinth() { + std::vector files; + QString minecraftVersion, fabricVersion, forgeVersion; + try + { + QString indexPath = FS::PathCombine(m_stagingPath, "modrinth.index.json"); + auto doc = Json::requireDocument(indexPath); + auto obj = Json::requireObject(doc, "modrinth.index.json"); + int formatVersion = Json::requireInteger(obj, "formatVersion", "modrinth.index.json"); + if (formatVersion == 1) + { + auto game = Json::requireString(obj, "game", "modrinth.index.json"); + if (game != "minecraft") + { + throw JSONValidationError("Unknown game: " + game); + } + + auto jsonFiles = Json::requireIsArrayOf(obj, "files", "modrinth.index.json"); + std::transform(jsonFiles.begin(), jsonFiles.end(), std::back_inserter(files), [](const QJsonObject& obj) + { + Modrinth::File file; + file.path = Json::requireString(obj, "path"); + QString supported = Json::ensureString(Json::ensureObject(obj, "env")); + QJsonObject hashes = Json::requireObject(obj, "hashes"); + QString hash; + QCryptographicHash::Algorithm hashAlgorithm; + hash = Json::ensureString(hashes, "sha256"); + hashAlgorithm = QCryptographicHash::Sha256; + if (hash.isEmpty()) + { + hash = Json::ensureString(hashes, "sha512"); + hashAlgorithm = QCryptographicHash::Sha512; + if (hash.isEmpty()) + { + hash = Json::ensureString(hashes, "sha1"); + hashAlgorithm = QCryptographicHash::Sha1; + if (hash.isEmpty()) + { + throw JSONValidationError("No hash found for: " + file.path); + } + } + } + file.hash = QByteArray::fromHex(hash.toLatin1()); + file.hashAlgorithm = hashAlgorithm; + // Do not use requireUrl, which uses StrictMode, instead use QUrl's default TolerantMode (as Modrinth seems to incorrectly handle spaces) + file.download = Json::requireString(Json::ensureArray(obj, "downloads").first(), "Download URL for " + file.path); + if (!file.download.isValid()) + { + throw JSONValidationError("Download URL for " + file.path + " is not a correctly formatted URL"); + } + return file; + }); + + auto dependencies = Json::requireObject(obj, "dependencies", "modrinth.index.json"); + for (auto it = dependencies.begin(), end = dependencies.end(); it != end; ++it) + { + QString name = it.key(); + if (name == "minecraft") + { + if (!minecraftVersion.isEmpty()) + throw JSONValidationError("Duplicate Minecraft version"); + minecraftVersion = Json::requireString(*it, "Minecraft version"); + } + else if (name == "fabric-loader") + { + if (!fabricVersion.isEmpty()) + throw JSONValidationError("Duplicate Fabric Loader version"); + fabricVersion = Json::requireString(*it, "Fabric Loader version"); + } + else if (name == "forge") + { + if (!forgeVersion.isEmpty()) + throw JSONValidationError("Duplicate Forge version"); + forgeVersion = Json::requireString(*it, "Forge version"); + } + else + { + throw JSONValidationError("Unknown dependency type: " + name); + } + } + } + else + { + throw JSONValidationError(QStringLiteral("Unknown format version: %s").arg(formatVersion)); + } + QFile::remove(indexPath); + } + catch (const JSONValidationError &e) + { + emitFailed(tr("Could not understand pack index:\n") + e.cause()); + return; + } + QString overridePath = FS::PathCombine(m_stagingPath, "overrides"); + if (QFile::exists(overridePath)) { + QString mcPath = FS::PathCombine(m_stagingPath, ".minecraft"); + if (!QFile::rename(overridePath, mcPath)) { + emitFailed(tr("Could not rename the overrides folder:\n") + "overrides"); + return; + } + } + + QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg"); + auto instanceSettings = std::make_shared(configPath); + instanceSettings->registerSetting("InstanceType", "Legacy"); + instanceSettings->set("InstanceType", "OneSix"); + MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath); + auto components = instance.getPackProfile(); + components->buildingFromScratch(); + components->setComponentVersion("net.minecraft", minecraftVersion, true); + if (!fabricVersion.isEmpty()) + components->setComponentVersion("net.fabricmc.fabric-loader", fabricVersion, true); + if (!forgeVersion.isEmpty()) + components->setComponentVersion("net.minecraftforge", forgeVersion, true); + if (m_instIcon != "default") + { + instance.setIconKey(m_instIcon); + } + instance.setName(m_instName); + instance.saveNow(); + + m_filesNetJob = new NetJob(tr("Mod download"), APPLICATION->network()); + for (auto &file : files) + { + auto path = FS::PathCombine(m_stagingPath, ".minecraft", file.path); + qDebug() << "Will download" << file.download << "to" << path; + auto dl = Net::Download::makeFile(file.download, path); + dl->addValidator(new Net::ChecksumValidator(file.hashAlgorithm, file.hash)); + m_filesNetJob->addNetAction(dl); + } + connect(m_filesNetJob.get(), &NetJob::succeeded, this, [&]() + { + m_filesNetJob.reset(); + emitSucceeded(); + } + ); + connect(m_filesNetJob.get(), &NetJob::failed, [&](const QString &reason) + { + m_filesNetJob.reset(); + emitFailed(reason); + }); + connect(m_filesNetJob.get(), &NetJob::progress, [&](qint64 current, qint64 total) + { + setProgress(current, total); + }); + setStatus(tr("Downloading mods...")); + m_filesNetJob->start(); +} diff --git a/launcher/InstanceImportTask.h b/launcher/InstanceImportTask.h index 365c3dc47..317562d91 100644 --- a/launcher/InstanceImportTask.h +++ b/launcher/InstanceImportTask.h @@ -47,8 +47,9 @@ protected: private: void processZipPack(); void processMultiMC(); - void processFlame(); void processTechnic(); + void processFlame(); + void processModrinth(); private slots: void downloadSucceeded(); @@ -69,7 +70,8 @@ private: /* data */ enum class ModpackType{ Unknown, MultiMC, + Technic, Flame, - Technic + Modrinth, } m_modpackType = ModpackType::Unknown; }; diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp new file mode 100644 index 000000000..2100aaf91 --- /dev/null +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp @@ -0,0 +1,16 @@ +/* Copyright 2022 kb1000 + * + * 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 "ModrinthPackManifest.h" diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.h b/launcher/modplatform/modrinth/ModrinthPackManifest.h new file mode 100644 index 000000000..9742aeb21 --- /dev/null +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.h @@ -0,0 +1,32 @@ +/* Copyright 2022 kb1000 + * + * 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 + +namespace Modrinth { +struct File +{ + QString path; + QCryptographicHash::Algorithm hashAlgorithm; + QByteArray hash; + // TODO: should this support multiple download URLs, like the JSON does? + QUrl download; +}; +} diff --git a/launcher/resources/multimc/multimc.qrc b/launcher/resources/multimc/multimc.qrc index 0fe673ff5..1671093d7 100644 --- a/launcher/resources/multimc/multimc.qrc +++ b/launcher/resources/multimc/multimc.qrc @@ -20,6 +20,9 @@ scalable/atlauncher.svg scalable/atlauncher-placeholder.png + + scalable/modrinth.svg + scalable/proxy.svg diff --git a/launcher/resources/multimc/scalable/modrinth.svg b/launcher/resources/multimc/scalable/modrinth.svg new file mode 100644 index 000000000..32715f5ce --- /dev/null +++ b/launcher/resources/multimc/scalable/modrinth.svg @@ -0,0 +1,4 @@ + + + + diff --git a/launcher/ui/dialogs/NewInstanceDialog.cpp b/launcher/ui/dialogs/NewInstanceDialog.cpp index b402839cf..05ea091de 100644 --- a/launcher/ui/dialogs/NewInstanceDialog.cpp +++ b/launcher/ui/dialogs/NewInstanceDialog.cpp @@ -39,6 +39,7 @@ #include "ui/pages/modplatform/legacy_ftb/Page.h" #include "ui/pages/modplatform/flame/FlamePage.h" #include "ui/pages/modplatform/ImportPage.h" +#include "ui/pages/modplatform/modrinth/ModrinthPage.h" #include "ui/pages/modplatform/technic/TechnicPage.h" @@ -134,6 +135,7 @@ QList NewInstanceDialog::getPages() flamePage, new FtbPage(this), new LegacyFTB::Page(this), + new ModrinthPage(this), technicPage }; } diff --git a/launcher/ui/pages/modplatform/ImportPage.cpp b/launcher/ui/pages/modplatform/ImportPage.cpp index 1b53dd402..8ae38f8dd 100644 --- a/launcher/ui/pages/modplatform/ImportPage.cpp +++ b/launcher/ui/pages/modplatform/ImportPage.cpp @@ -109,7 +109,8 @@ void ImportPage::updateState() { // FIXME: actually do some validation of what's inside here... this is fake AF QFileInfo fi(input); - if(fi.exists() && fi.suffix() == "zip") + // mrpack is a modrinth pack + if(fi.exists() && (fi.suffix() == "zip" || fi.suffix() == "mrpack")) { QFileInfo fi(url.fileName()); dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(url)); @@ -143,6 +144,7 @@ void ImportPage::setUrl(const QString& url) void ImportPage::on_modpackBtn_clicked() { + // TODO: Add .mrpack filter auto filter = QMimeDatabase().mimeTypeForName("application/zip").filterString(); const QUrl url = QFileDialog::getOpenFileUrl(this, tr("Choose modpack"), modpackUrl(), filter); if (url.isValid()) diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp new file mode 100644 index 000000000..93b1ca027 --- /dev/null +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -0,0 +1,55 @@ +/* + * Copyright 2013-2021 MultiMC Contributors + * Copyright 2021-2022 kb1000 + * + * 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 "ModrinthPage.h" + +#include "ui_ModrinthPage.h" + +#include + +ModrinthPage::ModrinthPage(NewInstanceDialog *dialog, QWidget *parent) : QWidget(parent), ui(new Ui::ModrinthPage), dialog(dialog) +{ + ui->setupUi(this); +} + +ModrinthPage::~ModrinthPage() +{ + delete ui; +} + +void ModrinthPage::openedImpl() +{ + BasePage::openedImpl(); + triggerSearch(); +} + +bool ModrinthPage::eventFilter(QObject *watched, QEvent *event) +{ + if (watched == ui->searchEdit && event->type() == QEvent::KeyPress) { + auto *keyEvent = reinterpret_cast(event); + if (keyEvent->key() == Qt::Key_Return) { + this->triggerSearch(); + keyEvent->accept(); + return true; + } + } + return QObject::eventFilter(watched, event); +} + +void ModrinthPage::triggerSearch() { + +} diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h new file mode 100644 index 000000000..6c75b60dd --- /dev/null +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h @@ -0,0 +1,62 @@ +/* + * Copyright 2013-2021 MultiMC Contributors + * Copyright 2021-2022 kb1000 + * + * 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 "Application.h" +#include "ui/dialogs/NewInstanceDialog.h" +#include "ui/pages/BasePage.h" + +#include + +namespace Ui +{ + class ModrinthPage; +} + +class ModrinthPage : public QWidget, public BasePage +{ + Q_OBJECT + +public: + explicit ModrinthPage(NewInstanceDialog *dialog, QWidget *parent = nullptr); + ~ModrinthPage() override; + + QString displayName() const override + { + return tr("Modrinth"); + } + QIcon icon() const override + { + return APPLICATION->getThemedIcon("modrinth"); + } + QString id() const override + { + return "modrinth"; + } + + void openedImpl() override; + + bool eventFilter(QObject *watched, QEvent *event) override; + +private slots: + void triggerSearch(); + +private: + Ui::ModrinthPage *ui; + NewInstanceDialog *dialog; +}; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui new file mode 100644 index 000000000..7ef099d34 --- /dev/null +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui @@ -0,0 +1,94 @@ + + + ModrinthPage + + + + 0 + 0 + 837 + 685 + + + + + + + + + Search and filter ... + + + + + + + Search + + + + + + + + + + + Qt::ScrollBarAlwaysOff + + + true + + + + 48 + 48 + + + + + + + + true + + + true + + + + + + + + + + + + + + Version selected: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + searchEdit + searchButton + packView + packDescription + sortByBox + versionSelectionBox + + + + From 31988f0529f6c316d6a9ba3e66cf981a807ed710 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Sat, 14 May 2022 19:56:38 +0200 Subject: [PATCH 18/52] fix: adapt upstream Modrinth code to our codebase --- launcher/CMakeLists.txt | 8 +-- launcher/InstanceImportTask.cpp | 2 - .../multimc/128x128/instances/modrinth.png | Bin 10575 -> 0 bytes .../multimc/32x32/instances/modrinth.png | Bin 1913 -> 0 bytes launcher/resources/multimc/multimc.qrc | 3 -- launcher/ui/pages/modplatform/ImportPage.cpp | 2 +- .../modplatform/modrinth/ModrinthPage.cpp | 45 ++++++++++++----- .../pages/modplatform/modrinth/ModrinthPage.h | 46 +++++++++++++----- 8 files changed, 72 insertions(+), 34 deletions(-) delete mode 100644 launcher/resources/multimc/128x128/instances/modrinth.png delete mode 100644 launcher/resources/multimc/32x32/instances/modrinth.png diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index cbe135e2b..7984d3c98 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -532,6 +532,8 @@ set(FLAME_SOURCES set(MODRINTH_SOURCES modplatform/modrinth/ModrinthPackIndex.cpp modplatform/modrinth/ModrinthPackIndex.h + modplatform/modrinth/ModrinthPackManifest.cpp + modplatform/modrinth/ModrinthPackManifest.h ) set(MODPACKSCH_SOURCES @@ -563,11 +565,6 @@ set(ATLAUNCHER_SOURCES modplatform/atlauncher/ATLShareCode.h ) -set(MODRINTH_SOURCES - modplatform/modrinth/ModrinthPackManifest.cpp - modplatform/modrinth/ModrinthPackManifest.h -) - add_unit_test(Index SOURCES meta/Index_test.cpp LIBS Launcher_logic @@ -601,7 +598,6 @@ set(LOGIC_SOURCES ${MODPACKSCH_SOURCES} ${TECHNIC_SOURCES} ${ATLAUNCHER_SOURCES} - ${MODRINTH_SOURCES} ) SET(LAUNCHER_SOURCES diff --git a/launcher/InstanceImportTask.cpp b/launcher/InstanceImportTask.cpp index 517155811..ec0f58e08 100644 --- a/launcher/InstanceImportTask.cpp +++ b/launcher/InstanceImportTask.cpp @@ -581,8 +581,6 @@ void InstanceImportTask::processModrinth() { QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg"); auto instanceSettings = std::make_shared(configPath); - instanceSettings->registerSetting("InstanceType", "Legacy"); - instanceSettings->set("InstanceType", "OneSix"); MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath); auto components = instance.getPackProfile(); components->buildingFromScratch(); diff --git a/launcher/resources/multimc/128x128/instances/modrinth.png b/launcher/resources/multimc/128x128/instances/modrinth.png deleted file mode 100644 index 740bc8f02469f108db79d92d05484aff17bf8801..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10575 zcmZ8{Q*b3r7ww7hMJMLOwmIR+B$?Q@Z99`mPHfwn*tR{v#I|kR{I~AY?W*4W*wtO# zYwxwz4pWemKt{wz1ONcYQj#F0uQlL*6CU;}_6r)0e=X3?qEagGU&9C91PlO>0Hi=7 zDju2VS)K-%;)^|-6(<+1@iKCdq@>hAI^V91{*mjE&`B5+)c9SrRpnPeZh+hPHrv9f zJt~>byw1EBe}IH}FIfh?>DdPp1P{v z@7to)FFPTR@o$_xcBEz{Jw4v9RVQ;g_GxuJr<(H>iv z3IH&q0d~Bi#kZc*SsLMNs;CrfXg@h^T8ZjUcMF6YsP#*^*bx$g5a^+Lq}|(0x|F%d zIOS8Wt#^*?r!CJyh7JM=D?kL0lR!22n3It~0ASH@17`lf4PcWzG3{{+Rc%&PyB04r zCwlfk15Q3tPWAkn5Eal z(Nmt@Z~hcPb>P{QS9?TG3ZzFsQlW`?LVo1T8BZ834{TBHnBqsuL>uGtp#KLh*rK%PfX=opo_eLYuH(xe1GwAI_@aEb}l(ZV-8ezgS z|!lvq{O7R??68|vc)kpTJc7pOi($o0>|<`VAmKnLhdi7F=^@awNWGVJ^3%v) zUB&Hht(`mrtLydl$M?XDlU%w16kfo}$z1BWP4&bOzS1RvPI-5A%5HYlJ9cLO4X0C3X#h6>5iq69ZJp{ymKpc@QK*hZp#P9c5Cc7hBW< zN|-nv9+CwsfCC^&f`Kmc3%w=Ca)cEIXj5y43IM>bEN_^sImS0zbsgdoq(zrO>Uh{! z-`xcTYsw7j4_fg{fJl`~oQ9UE{IxBe5rK&pW z6V{q|C`VV(j)*rUzKb0>gj*eo#fn^NGynks(2W@(9(kRMpPLci+xd)C?FtFmVOq|% z&u%eZt)|&w;9QFcA<6QTvw*prnf)gZRK8e766g8HQRip{;{UeLXXJ>oa*o!;%z2cb z;DIc1b2~{1cw!Pb5!gS3|2%NQ6*II|*cmgd;L}RzLcpd3aJi^_sEC_>135q%4A|yE zy?5!Og5AaRc2x&)nycpP#X}1k#+Ya!^wJVnDz+Me>2b}w5AjhzAkOqUFgPH0^q;3ka~lGzP&(dEayJ>c{jdQ3l$wvSusYZu?u0W(At*@eY=D60HGb8~^@O#!>AH zpni*T8GobY->BA@U0fkLk4!wVLR(GtZvLPzqE~>6;pk-Y!oPtKJhO5p1GZKPHhKChWfA_hvv!)ENhuF=zT~|UR+oi|DnN! zY0ASn%-ok$xiq7T7KWybKMWh0dFQbIL~*MXSqa`%!WT}FYGR7kv9NTSq@QCs6n4xo zB&i$;n{6Bv|ED@dvZ5;f2V}waxmf)zLg1l1atZgNqFx zH)Ti(f(Hs}8FIfkLkvjg&aZ5r`)jPbl{);Qn;C29jS9?Sy8)>X+pycybe1_GfGkI7+h`e? zOcmCOB71+QOFzS~9mRl^+ZCD~$I?7kLaRGsai!h=J%G$n1`Qq$WT~WnTQ{ZDVhaG86ylBuXKVas+S+5Ol zF(dU=!P~zu&1#j=bwBmqTrL(yTccak6Fx;6Z|C9+nL&{zCbx@zm|g~t4_x0fXJ~ho ztCTpnq@3&ORp8q5)#d*FevepdZ)SS@;nSgATi01|32<#CSLF|MBxHC_&01Y%c@$P_ zySJm1nv5F62{&sDJq2k z0gRND&6=#Trnxd$c7w)x-9SqV@l7b$ZW~{ZiCiA^8kzefR+y!~2Vr`)+j@96TIIcP zp?2uncnbl5WITYCCPih@h9q_?^e=OJkoL~J`DmJW(=;ZYBt(q!Q8^W^);;f3d(5!M zh#R;I9pTkuo*Hc@%lGO-!+^QUNz^XoU4ruH`4nUT&7atF+j+hYjZwzUE4s)=ce zOgssWv5A|ik4{~y@x&*(sPn202w@7%5b}K9O@pa(4K5h}Up^D4!s&*JXpkltPPc1FoSSNfdYV*_J=V^Ew^}DD*O{v;^*mJ-k?4g-(K;EE9eLX zl++Z6GY(lV`+zlKL3Htj=IP$D84T=hN+c%(=KD9=o7R)3b%*Cn@UIRn?1v*)2jDVm zAqd;ASR`wYA_V>taT|{;bwn;P%ZlastQ)Q?Dk=R-o0P%#0BuhtqExKkuHBmF;r1ZB ze8XQLjToz(Xsk|jg-*6oX%d#(^;SPr1_aF*T(k2UXIc8Nk{~55tGeiMr%{yt0+)-P zAKW|?&y4?25co-Ar`x==LLdRp^F96r7)Q(1LBp!6?fIO;J{{|OvEFVacx3UngcwP- zzMOnAuCxnYmk_4y?&|6A*3OlZuAUJlOjNL1@#Z42T)gg_E<1^RC@sIUkB35hj*E;9 zY|wmB64Me+?`D5f&6uIv3`N$+=@Ia*?)P~Q#!X6LLnuGB0Ag%r)$KatJ!e`wotf+B z`b0${C&fK_N6lWYDLwmf*g_rk#q!;3p9zK?pGbp~d+`fH2gYM{o?Sf4)?$SG)ZA*> z2Opd`vY2IV;(OTqE1owQUn5_!*VXQa4t~pKRCL=!ohX!1Ag9J<;~LNv14Iz(MtpF9 ztRjuu;EA~`{kNLB#*LpF?Y-7WJVJSytEq`O6v|uBl_~F0>!*FItbF8FFg%_%HyjJS z!&+H4X(1ZT-A(UpgWRtxrej3>^pAw<<$N)YGLePfDMqYAj`j^Q1S_{I$4XMVmfqH* zRT-6BLkcVtA=>)LDqh93aF7pxdQ81ul{P{k5gne$ZTO9nkjP zSpoH8x#g+C6OtA3>$Di3I#u7hJ-~w+VZSmO*VlJ4w(KDJ`^$D`7WKOmwKs-7ek?Gh zyki7ci{B))z82v){gbD=Qwas zuN$lLeMIA=nklv%lgg{EO@^hjmOO1Ji&%b#akt}k2Z5W6=Cy`%bGzJoqIh;z`$k8T zQKo%2YZ$cV)Hwjo9S*-eE@q+|nF4#O%XU(FghJZg(Ij;Y>l~HM^dk|BB|Q2U&N)eQ zWok44`E)S?hRyWhbkigHWGlgRm0YGAzUlPy{-RPfXKcis`aio$I$LX&YEqFXwi|G1 z8GeT2b3v;F2P5&+-@|mR(Oh+tA9z)@v%5KrNAz zNdR1`;i4Mr@90#!53q_qq4^mjOcH-vU`s9d;{uWKcFhhc_}0eo#f=Ra6^fb0xT~%B zjd!h)1uNKwr^Y^9ebUdd5?LDYLzZlwA}gfrtD>z2y?J=Wc^^c?UwQ@@UTaXQd1o%v zU}^CW5Ft8c`+dwePLt+H>INyIy~{UY9Lt*g$%c{W4bkVZukcek*&9#T>6ht0ll^n7 z%>C;IxL;*p)9SWE1$iDnW^N&L3y@7t*=DO!wY_YC{NGNF<^u(EWAo z^uDboPZ1kg_wNI(PsUN+XpB^&^XlA{W!)6P?AxgP8kquJ;`r3EESca#I((F{fu*}k zHw=Cpzz1YJmHn}}fq_HFBzB3$#XA=DE67YJJNXh973rpOFIXyyC@Rp>l=&>7=>$uL zwq_rxY0`zF+&{ed_7ho@41;VZ>0U|RS9ivI0}+(m8rTxlEh(cc=>E84t#m_J?GPoe zY;%@q!AA@TaO5c(A-CU7Qu|^PA!J6Gzj2=*QpZikb`f=GFlb0cji&m9*Rjifd<(!r z`6YqH-wo4da6%>0D;)6*u4{WKu*e?vonj-W!PXihrPDF>1OT5|-NJXaczcs&ETzjE zAPe`F7#=^0nXEi@M(XOr1@Ow&rsV45F<{T{Im7;uNiKwAWKXt>H11B$Bu!BxHe4jj&SI$@sdE}&#^zYm*7{J2KgS^# zjW#U;n?@9?OYN`H(?V3~t$gYg_q;Ftt_}l3R<=W`Go^Pqv%0Wu_7tO9FXr&pZt(-& z#MQ^bFcY4?FeOqh3VzAC{06}O*4>vI0uZiL)%104)G0PvS`dOzm|@;{KWU{Jr$8e> zceeklGp0Oiaz~c$w$7|}EO_g-PCfPECp$(s!%rtzHGi;ry9rPQ$j>LW9eGZ8H+L;7RP$9(Vn+xRhOSoG8N5xQ_bP<$B;9a zFxE8IpB^b| zy}?wsY!I(o_F5Erb?H|e_a8xL8B!VkHS%zVOEEa(4zU{8^A`%iZ>nFvN2u^WENwbEQcRTLkoc-{;b~4ZX?YJ*M2XVS-3sP$Ia6TL(8^W40^kS>C5=_U!5$q6Ay{b*&#Ev7|^AU+_gbE8R5lclGp5 zB!?Em8N3!kiIFp%p!r{}r`*(nmVh@(+CGqnZ_Q_-WtrEIJWW(&?j|c0@*Lu|s>TmY zlZt3ydvAjHvnV$u9TN79jdLR{FL=G*4LYi)Nj%DszuBowpO_`uvlYKf%fI4?dXDJ} zsq3Al6$sDR@H9a#>^QI5*BHy{j4c(#%8zx|%zL^gk-PHJE+4&4r2oE!ib3Qm!^wwg zkJiyi%%-|a(`rP;x&dk?;sWp!!joc^0zOjs&0E-Q44prKGpnoEoN@@%>^>h{ z>JcHta-n&G9dl_IVQ$N3Td)8_!4;@@D1x3kMmr&o9iN9=#uMvh*G(P4r<`!zICvBi z3ETnnsW>^u9^QS3c&C$sz7B4H1bo9CEyXJ0#yV91$ z0DpFgv`>Q!apD1h$|x_t@Kw9}sUUuf6je=AjlLwav z>qeepG-SVk$<%?+?X6PVmA}6kh{B&Xus{zb@5?67g1%0raBuqRmV2ei3S=#_EwSXC zK3}#`Nu$zS9#nMRYRPYZHPgE``pCiXx?NZc^f%G5Q(Rm}3&gYecbO(s=~R|Iqire0%2sc^eq1%MROp(L>ldFx?hn+RA*E~U4IF{g+6Z~ zdhzb~bQZ_CQdEidKHYtPMNH=;7RKFD+%v7AkNoD)GQdaRxw>ucF_RTIv_Qy)MOelH z4ZLAYyPEnxdt(Ca_)!5*T1|F%@L(Bb8&r;rZvRtvtbdH&HEyP_dd_TVnDpYO7Rz{T zmSH7cF_8{o<~0XD4V7`5^(gD@EeM{}eUORe(85j~A3mdw<&Ox>Zx@KUtQzE0+F!TFHH^T4WyT0;5Xdb=T$1p~{XHy>D?*@L| zC3eF#VuCgj`A5YKE%PE(-sg7rRq)E~pYV`u;=&zsi={%{JPNPk)c+APc(VFut`B}N zd2_P@&wykvz zguFy6W@*TK6T2}yE!^_uH&s-_4; zBv)c2&kj9AivO=lHZ-BJu70>jdCqo}N6)#YOeXG?t}i$AZRorGroufWsH=?{5t^6`lk}n6E6ZQd4FZuY*F~)pfBE69Toh&=z7PgSHqKqT6g5i%8I?%SZZDIE_agrs? z+0Cx^H$p};)BU$OYt!NHN#A>u%rg3MACkQSXh3bx!pHOJgKGKYmy;I>v1Pt9r#Q6# zPzaMUGvh0p=1pE7#5~V})C*qNsxuS#MP2FsGrd3n!}C2E-Ta%tC(YqCzf^PdU!Gg| z>%FPLGL(?CePZsPUBU9hjav*P3Voc$eM)zcxNNAyOZ_RhF#1gtBw+Eu8H~VbrZ92a z2>rROp{>5WaMz+pE8I&{ljUjpIh`6*;$C#qPa0&lZr@R~`~=fuC=5LZdkk@1WUud# z?)yGujyRe2@ z{L$ZF%iXxv*8hEww$pqbv&!$G(9@lKbAM!&H_dT^wDugl*oh!N@d2PwaW$O(D;ah9 z*oyB>XH@jgt)GGe2n&}SDE;7H8zV@CP67Q*?hjj`Upg#EfoCAZWk7?iL~TgLaI3av z%=VYQR|g13T>N>N?-p{2V(Dd@e{+a6%s<#^9w?#BxqG+meI1-W(B-_@wkZQhEz_OJ z`GxKnsB2P=eb7>rRuxqlpTW&p7aHM(>R`TPoop>WvOols&9!}B2r*?Vp8~I-KlV#( zJdmbP(#jYrHGL9`V9vbn%r1832{CjOcp2ZX5N`%QzuzR=!W<6StDgB#u(cBQg$jqb z?P=t$I7YGu>U-``hKb3i$DTE`H$>}Z_~>d;BjIPo7g+GH#hat(;?-YO;g?x&BYx61 z%D)Ipl>L#Y>mKa5E`YOUVD37JWU`$`lrZOki*&d9$~Hzb1M;L~h9O7e25{@&Z9bzp zu~&0{J;Ih%lR>$wGe^(e^CkAa_=m&zk~f7j=}gg^b^dfd-T zU2><~4Z$mh8W)B<+0Hk_*xGzS-x>lb=hgVhP$jHkeM&kJ+qyGp?H(DxMCj>$jNi1r zx_XDfEVI^k?ol+K7ab6;yU$pV{KeCJHPc)RzHAD+aRE-dMsg`yP=E_q2>~sRG(S8b z41Ym?_{(X1`Cl(U_z)rooKO<22N#K60MfKMV&>{Ld$X-x(PY zAGYwXEd`_;$M4?mKliyFJOU`~r&`Ak_U26eq{)`%I>z;H`o~I*i6BT|<3zkO=*C^T zQ>iH@ScP^$kH(bsY(=5>MX2+BOprsAKhO>W_s$99e&MDRMgk&$we$7Wx&R+w6HR_B z5PjPHZAPi%YC~%|509Jj0E>V9gxHiR91;NU5ydNgQJL~H4=0+5UN{XdGP?61g5r-a z3|fFA7Ij{~VCM*Vx03(qOF8VNyNm3Myu6$GjyS1>#x=%s@`g+xl`*9Y+a98bteL`^ zIn%1+YyNP*gcOn7b$x3;;piLQvS$wT0-oPH=kiTIFd>6S{^#`twq_WW`n7;`0X*3u zex{}Rx~#U~l@?#~D zY^2O}8A`{_RfUt3LdFG-zxArMT!v8NP3Mi%^ZE5rXq|Ib*;s`RS?yhK+ludNWX48& z1r=4=uu(o>e_t5kUH23tJ}IFkD4E(1Tly&XvvuMMlKtlnUVr)+HGLKu)sQ@XuAJVF}}dZ`rZlxrAr!&j37_TG~Fo z3;A9m(u0Pdn^MeIzm~OiwF@kX+IJ|ctSt#w z-X7s|c@526cGvY>?vljuyn9!=91=u0ITiSAj|2l^S589)uFcXwIZ2{4q}$tl^1Lw? zyoanb1)tb_YCIX3s=Qu)33JG@l1h4t=VvO*=HT42#@^JHJ9$?npitd_3IqVqRBcs; z%Rz_G8ZOTE-~&=oA>fZ0JRLpmPgqo`vPkZ_JV4{;dbztP+PJw)@!FgQtAARaR{B`s z))1hMnrjVY^z_fNoOnOKc!3eQg70T>!9Cvl81CsMS5sk>H%az z$Npk*S>36yCx4Qj#7R%(tgtcX5d}U7SRme)t;AuXzn`fw`5HQByR8Q23piXs(Xpn} zjRB(X2V%ds!8E&O_vF!k_2uZFjw$L2=Af6PApv@(Rq6|BdrNsR?ktEz`W1P2$vHnU zUv;$zyH(wCzS=fGKT3aP+iMt4(3}>#G_B*?b5A8C98IVmI1f$5Q2c%k#1Oq!EA36a zzVPK#GMpMF7yqX4VsfBA$oWA-QY2wCMMakPdR)0Ed-W<=6&R6dhuT8;|BQdJfqL@E zUHKroci9)&g?-wJ#YtV9h5Mu7@Y$Gyd*|XlmxZC~h@*;7s4U`}h~KjONAC3B5@IC4 zAqD7;{C;w7#G$(0QI21(3}4tt_3M#tftY~q`;UG1(?!jL8Q$W^tHQ^hW0CEmiqBb* zVr~O4Xn1*m&dzSpwfXfdREI=N0AMR$;&v^}&SMr>A`^M=1JzKeg2m8uhS;m>pgn!z z^x&I*ILk}enT~q66XWimU{)T|^f_rVHka<_ln~~D@9Uh0pNR$d&i=Cno)?KK4`3_f z1Yp7K3TZw{-kf@%+U;@iV|lX1;JiC`!Nv5L{85Rl+W8yzNG=Y@yGs;v=GV^l_limC z7_~zvLQ@z3&(;M;%ZPtH{_v*@ixbz$tM3GwYHYy246Bt5L|SD2aRCESq-t+obV|w| zs9)?hO)BR`cE;W6wr`LoN5My%zhZM+I~BX13l~qCW85-(SjXE~U*a-v(O=4^*`se@ z7w6OaYr;^y0r6b(gaR{1m>KZ{VRQ*@0Y(#1On9cqvxP+S$1VyjM9NL5g zV=X$lmP>9>aX>VEmoxTahIHWT>WnE*v8DP{+AKdKJM)FqV6?g@k}*7(#sYc(Ri@YW z$B52m)4#Rs*s6I491raZQKI&4D}?k+0v+)$un!nbNZ`<(TBdaa^e@y6Pe2z21-sbB zenX?SbmKz9r4m8%XGY&+cfJ1izS%5gB6*3m!}) zEBtx8lRY?CQji--Sr8f`*%B7NGlVcCeL{SIRye76ZKz*az% zPiH#sK%7y#nrq!Ak>BD+4m9xmzB$!@LF{QIf7Sggz)r7v#6gFqr~4W}a5*Koj9opY zNKuvi&TDvLl(b>Aq2gt|;KqZ(_klK?0!dg{3ZIxr??k;q_-0qUm0Lv-&yze8czU_` zvKlGGn5x!E7+nx8G~ieU2*q`Fw-UG{_$0_kh}q{7$YMpxh=2D8lvy!9GLjvk-mrX0 z{uy)7C8!i_4a0-P<>&S=TCUtFUb{;*hE)IJLVQVE1f@Sza44f ze_p2RiMaw~td+$2cUMty-VX$CuSFj^qV%i45dfg=cpNTzC~*>8Sp4%KpkYbQP@B>- zT8Frf1b62`zVBEM>aDtQOiW4q`b2^`3XVtLT7|sugJPDRQrevt?6bc^c%c#hM;j>P z6ib4P24=zRf!q|{U0gdf(-xw diff --git a/launcher/resources/multimc/32x32/instances/modrinth.png b/launcher/resources/multimc/32x32/instances/modrinth.png deleted file mode 100644 index 025ed06534234458f6de2456868d0a66b4324f3b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1913 zcmV-<2Zs2GP)3&289m><@6E99O-OKpvFD)x&4M7Lr726LBnr*iX251# zY=ak;1huGYRobdkkfK&qNs2(JcO2sdCV_^irMOE#t=fh*Qq(0R_ShaEPN9Gj2W$^B z@7>cMGh@bV32pwh_t(7p&Uepw-}l`+=K}xhLv92d+zYKg4BTbevcLedXgCD~m6EfB zIhIVQqjTQt{A)N2^N9*5teQCmezRUHStCkrzaG{Y#z@wnKk-7#`V;T}w*sW7F@FP; z-XemDnMso8VDNV+ISo+J$gQIIX%QKhg*i*tY;G>?s`-xu1b5CE;~SIQtu!7_FW7Gk zYLPHa$?;upMwY`Hh7Zs2>1hM^DZegLA_XGi13=>;k~lX|64~_b;Kvpa+&O2Ae_ZmA z2o{2*F?iV|+^1X1drl7nhM^D!0Wf=df!6xPhRS!rwm02;Jq z$P4T8?pK!edWM{aJv4aEb4^*Kvik%8P)r^GD3J#(ZU1>??aT!L&>M?>l?Hzh5m8z_ z8?4QlbWH(btEWX|JjoADTs8v0it4HbTm#y8&{xJxU}r$MxJb=PkJprAf~p=GOIipW@!?YqCy z`49kv8l8Pg%ag`1=5%-FXAY|&0V`?(pYe@Uew z7ffzjS@&v}j0*APET3rrY~`;74_jA1O5cFxLRt;~;>RUK^r+A_~e!b>cmcNzeI zcq=7cof?WE4z?6WpS^^KH8m%1@qpMz53G6TJPh7~256+exwzvg04!>9iU8yq!zou} zAQ*(6R{=X1gvK>SWOeimDX*oHf`!5Qz^4G9us*OjC(r4%M_9ieYkRA%6%VF+PA>J{ zkO1GZ!1h_6cP{uIarULsc-RHdn+}*=P@jKWsL^>@gbx9Lh)nj|(jIDbnzbzlM9EF5 z?Tf?dm1n1LJc&z3^(_FPM9yS*he`mTGu0@Z4?-Xyj2wYN0E%lYrJfOyQ9!EeA-G9I z?h%c90Dz=xl3dkV5&g%KFf1i_A~laAsS@RmATUAzh~VujG5{BU0szr+Yhmq-J5xla zEB&=oL}V1nJ~zp4SY9$0l$X-P2^#*w^RTLAb@UYgm^R%hgOb|-z)QH1R7PX*(Szgi z=$gmff#jhK?X?b~CJIMsg)adjX(Afed#a_hdmjJU)cQ(|84w8N8FZPVfZ;l!qcej`D9wqU< zh>TaZs`JO4&Y~A*ZVNT!mlxDK_W=M-1tw{Q9T{?ykT15C#$pd|5BM!xS1TnsqEKiv zKFkvg6VO`TbK1E0UMe@Dgz#5azL9KQ)BSr~^cENouK|E4nIQ^aQ?{Vy6J$;q3wcr14Uvv=jq?@vyhKxMRh2dtj)Z z*_I4|A=?viwKh`zPR}r4IGw@Enya8TFxU308VKeAfH6FrI6JuPYQFGBOliW9ZRR2x zyz}wbFJCNJl{a2%eZS>HB?QYvM3W>8U+Rkwlw8dZUROZoeP~x;y=b-dGFv_fqQiLn zmxzccOoJdGB6b$$obk-&%PrWA3IG5+x#Nz>BgVKJKJLXt$QttrT}+0J;9h8TA#k@P zvVaPAWUgk~QfKIS$6RBM&N|uiw;Q>d{eS!$l(>|MSu=Nq00000NkvXXu0mjfgB*o# diff --git a/launcher/resources/multimc/multimc.qrc b/launcher/resources/multimc/multimc.qrc index 1671093d7..86ebf753c 100644 --- a/launcher/resources/multimc/multimc.qrc +++ b/launcher/resources/multimc/multimc.qrc @@ -275,9 +275,6 @@ 32x32/instances/flame.png 128x128/instances/flame.png - 32x32/instances/modrinth.png - 128x128/instances/modrinth.png - 32x32/instances/gear.png 128x128/instances/gear.png diff --git a/launcher/ui/pages/modplatform/ImportPage.cpp b/launcher/ui/pages/modplatform/ImportPage.cpp index 8ae38f8dd..3b65de9d4 100644 --- a/launcher/ui/pages/modplatform/ImportPage.cpp +++ b/launcher/ui/pages/modplatform/ImportPage.cpp @@ -144,8 +144,8 @@ void ImportPage::setUrl(const QString& url) void ImportPage::on_modpackBtn_clicked() { - // TODO: Add .mrpack filter auto filter = QMimeDatabase().mimeTypeForName("application/zip").filterString(); + filter += ";;" + tr("Modrinth pack (*.mrpack)"); const QUrl url = QFileDialog::getOpenFileUrl(this, tr("Choose modpack"), modpackUrl(), filter); if (url.isValid()) { diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index 93b1ca027..0d65ef166 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -1,18 +1,36 @@ +// SPDX-License-Identifier: GPL-3.0-only /* - * Copyright 2013-2021 MultiMC Contributors - * Copyright 2021-2022 kb1000 + * PolyMC - Minecraft Launcher * - * 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * 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. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * Copyright 2021-2022 kb1000 + * + * 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 "ModrinthPage.h" @@ -31,6 +49,11 @@ ModrinthPage::~ModrinthPage() delete ui; } +void ModrinthPage::retranslate() +{ + ui->retranslateUi(this); +} + void ModrinthPage::openedImpl() { BasePage::openedImpl(); diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h index 6c75b60dd..562049b48 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h @@ -1,18 +1,36 @@ +// SPDX-License-Identifier: GPL-3.0-only /* - * Copyright 2013-2021 MultiMC Contributors - * Copyright 2021-2022 kb1000 + * PolyMC - Minecraft Launcher * - * 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * 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. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * Copyright 2021-2022 kb1000 + * + * 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 @@ -49,6 +67,12 @@ public: return "modrinth"; } + virtual QString helpPage() const override + { + return "Modrinth-platform"; + } + void retranslate() override; + void openedImpl() override; bool eventFilter(QObject *watched, QEvent *event) override; From 4fda35b466e4e3f242955cf8cb692a10e8820f0b Mon Sep 17 00:00:00 2001 From: flow Date: Sat, 14 May 2022 20:17:05 -0300 Subject: [PATCH 19/52] feat: add modrinth pack downloading Things that don't work / work poorly (there's more for sure but those are the evident ones): - Icons are broken in the import dialog - No way to search for private packs - Icons are not downloaded when downloading a mod - No support for multiple download URLs - Probably a lot more... --- launcher/CMakeLists.txt | 2 + .../modrinth/ModrinthPackManifest.cpp | 84 ++++++ .../modrinth/ModrinthPackManifest.h | 50 ++++ .../modplatform/modrinth/ModrinthModel.cpp | 274 ++++++++++++++++++ .../modplatform/modrinth/ModrinthModel.h | 81 ++++++ .../modplatform/modrinth/ModrinthPage.cpp | 209 ++++++++++++- .../pages/modplatform/modrinth/ModrinthPage.h | 65 +++-- 7 files changed, 729 insertions(+), 36 deletions(-) create mode 100644 launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp create mode 100644 launcher/ui/pages/modplatform/modrinth/ModrinthModel.h diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 7984d3c98..8e75be204 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -778,6 +778,8 @@ SET(LAUNCHER_SOURCES ui/pages/modplatform/modrinth/ModrinthPage.cpp ui/pages/modplatform/modrinth/ModrinthPage.h + ui/pages/modplatform/modrinth/ModrinthModel.cpp + ui/pages/modplatform/modrinth/ModrinthModel.h ui/pages/modplatform/technic/TechnicModel.cpp ui/pages/modplatform/technic/TechnicModel.h diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp index 2100aaf91..4dcd2fd49 100644 --- a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp @@ -14,3 +14,87 @@ */ #include "ModrinthPackManifest.h" +#include "Json.h" + +#include "minecraft/MinecraftInstance.h" +#include "minecraft/PackProfile.h" + +namespace Modrinth { + +void loadIndexedPack(Modpack& pack, QJsonObject& obj) +{ + pack.id = Json::ensureString(obj, "project_id"); + + pack.name = Json::ensureString(obj, "title"); + pack.description = Json::ensureString(obj, "description"); + pack.authors << Json::ensureString(obj, "author"); + pack.iconName = QString("modrinth_%1").arg(Json::ensureString(obj, "slug")); + pack.iconUrl = Json::ensureString(obj, "icon_url"); +} + +void loadIndexedInfo(Modpack& pack, QJsonObject& obj) +{ + pack.extra.body = Json::ensureString(obj, "body"); + pack.extra.sourceUrl = Json::ensureString(obj, "source_url"); + pack.extra.wikiUrl = Json::ensureString(obj, "wiki_url"); + + pack.extraInfoLoaded = true; +} + +void loadIndexedVersions(Modpack& pack, QJsonDocument& doc) +{ + QVector unsortedVersions; + + auto arr = Json::requireArray(doc); + + for (auto versionIter : arr) { + auto obj = Json::requireObject(versionIter); + auto file = loadIndexedVersion(obj); + + if(!file.id.isEmpty()) // Heuristic to check if the returned value is valid + unsortedVersions.append(file); + } + auto orderSortPredicate = [](const ModpackVersion& a, const ModpackVersion& b) -> bool { + // dates are in RFC 3339 format + return a.date > b.date; + }; + + std::sort(unsortedVersions.begin(), unsortedVersions.end(), orderSortPredicate); + + pack.versions.swap(unsortedVersions); + + pack.versionsLoaded = true; +} + +auto loadIndexedVersion(QJsonObject &obj) -> ModpackVersion +{ + ModpackVersion file; + + file.name = Json::requireString(obj, "name"); + file.version = Json::requireString(obj, "version_number"); + + file.id = Json::requireString(obj, "id"); + file.project_id = Json::requireString(obj, "project_id"); + + file.date = Json::requireString(obj, "date_published"); + + auto files = Json::requireArray(obj, "files"); + + for (auto file_iter : files) { + File indexed_file; + auto parent = Json::requireObject(file_iter); + if (!Json::ensureBoolean(parent, "primary", false)) { + continue; + } + + file.download_url = Json::requireString(parent, "url"); + break; + } + + if(file.download_url.isEmpty()) + return {}; + + return file; +} + +} // namespace Modrinth diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.h b/launcher/modplatform/modrinth/ModrinthPackManifest.h index 9742aeb21..7dab893ca 100644 --- a/launcher/modplatform/modrinth/ModrinthPackManifest.h +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.h @@ -15,18 +15,68 @@ #pragma once +#include + #include #include #include #include +class MinecraftInstance; + namespace Modrinth { + struct File { QString path; + QCryptographicHash::Algorithm hashAlgorithm; QByteArray hash; // TODO: should this support multiple download URLs, like the JSON does? QUrl download; }; + +struct ModpackExtra { + QString body; + + QString sourceUrl; + QString wikiUrl; +}; + +struct ModpackVersion { + QString name; + QString version; + + QString id; + QString project_id; + + QString date; + + QString download_url; +}; + +struct Modpack { + QString id; + + QString name; + QString description; + QStringList authors; + QString iconName; + QUrl iconUrl; + + bool versionsLoaded = false; + bool extraInfoLoaded = false; + + ModpackExtra extra; + QVector versions; +}; + +void loadIndexedPack(Modpack&, QJsonObject&); +void loadIndexedInfo(Modpack&, QJsonObject&); +void loadIndexedVersions(Modpack&, QJsonDocument&); +auto loadIndexedVersion(QJsonObject&) -> ModpackVersion; + } + +Q_DECLARE_METATYPE(Modrinth::Modpack); +Q_DECLARE_METATYPE(Modrinth::ModpackVersion); diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp new file mode 100644 index 000000000..2890e27d5 --- /dev/null +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -0,0 +1,274 @@ +#include "ModrinthModel.h" + +#include "BuildConfig.h" +#include "Json.h" +#include "minecraft/MinecraftInstance.h" +#include "minecraft/PackProfile.h" +#include "ui/dialogs/ModDownloadDialog.h" + +#include + +namespace Modrinth { + +ModpackListModel::ModpackListModel(ModrinthPage* parent) : QAbstractListModel(parent), m_parent(parent) {} + +auto ModpackListModel::debugName() const -> QString +{ + return m_parent->debugName(); +} + +/******** Make data requests ********/ + +void ModpackListModel::fetchMore(const QModelIndex& parent) +{ + if (parent.isValid()) + return; + if (nextSearchOffset == 0) { + qWarning() << "fetchMore with 0 offset is wrong..."; + return; + } + performPaginatedSearch(); +} + +auto ModpackListModel::data(const QModelIndex& index, int role) const -> QVariant +{ + int pos = index.row(); + if (pos >= modpacks.size() || pos < 0 || !index.isValid()) { + return QString("INVALID INDEX %1").arg(pos); + } + + Modrinth::Modpack pack = modpacks.at(pos); + if (role == Qt::DisplayRole) { + return pack.name; + } else if (role == Qt::ToolTipRole) { + if (pack.description.length() > 100) { + // some magic to prevent to long tooltips and replace html linebreaks + QString edit = pack.description.left(97); + edit = edit.left(edit.lastIndexOf("
")).left(edit.lastIndexOf(" ")).append("..."); + return edit; + } + return pack.description; + } else if (role == Qt::DecorationRole) { + // FIXME: help the icons dont have the same size ;-; + if (m_logoMap.contains(pack.iconName)) { + return (m_logoMap.value(pack.iconName)); + } + QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder"); + ((ModpackListModel*)this)->requestLogo(pack.iconName, pack.iconUrl.toString()); + return icon; + } else if (role == Qt::UserRole) { + QVariant v; + v.setValue(pack); + return v; + } + + return {}; +} + +/* +void ModpackListModel::requestModVersions(ModPlatform::IndexedPack const& current) +{ + auto profile = (dynamic_cast((dynamic_cast(parent()))->m_instance))->getPackProfile(); + + m_parent->apiProvider()->getVersions(this, { current.addonId.toString(), getMineVersions(), profile->getModLoader() }); +}*/ + +void ModpackListModel::performPaginatedSearch() +{ + // TODO: Move to standalone API + NetJob* netJob = new NetJob("Modrinth::SearchModpack", APPLICATION->network()); + auto searchAllUrl = QString( + "https://staging-api.modrinth.com/v2/search?" + "query=%1&" + "facets=[[\"project_type:modpack\"]]") + .arg(currentSearchTerm); + + netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchAllUrl), &m_all_response)); + + QObject::connect(netJob, &NetJob::succeeded, this, [this] { + QJsonParseError parse_error_all {}; + + QJsonDocument doc_all = QJsonDocument::fromJson(m_all_response, &parse_error_all); + if (parse_error_all.error != QJsonParseError::NoError) { + qWarning() << "Error while parsing JSON response from " << debugName() << " at " << parse_error_all.offset + << " reason: " << parse_error_all.errorString(); + qWarning() << m_all_response; + return; + } + + searchRequestFinished(doc_all); + }); + QObject::connect(netJob, &NetJob::failed, this, &ModpackListModel::searchRequestFailed); + + jobPtr = netJob; + jobPtr->start(); +} + +void ModpackListModel::refresh() +{ + if (jobPtr) { + jobPtr->abort(); + searchState = ResetRequested; + return; + } else { + beginResetModel(); + modpacks.clear(); + endResetModel(); + searchState = None; + } + nextSearchOffset = 0; + performPaginatedSearch(); +} + +void ModpackListModel::searchWithTerm(const QString& term, const int sort) +{ + if (currentSearchTerm == term && currentSearchTerm.isNull() == term.isNull() && currentSort == sort) { + return; + } + + currentSearchTerm = term; + currentSort = sort; + + refresh(); +} + +void ModpackListModel::getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback) +{ + if (m_logoMap.contains(logo)) { + callback(APPLICATION->metacache() + ->resolveEntry(m_parent->metaEntryBase(), QString("logos/%1").arg(logo.section(".", 0, 0))) + ->getFullPath()); + } else { + requestLogo(logo, logoUrl); + } +} + +void ModpackListModel::requestLogo(QString logo, QString url) +{ + if (m_loadingLogos.contains(logo) || m_failedLogos.contains(logo)) { + return; + } + + MetaEntryPtr entry = + APPLICATION->metacache()->resolveEntry(m_parent->metaEntryBase(), QString("logos/%1").arg(logo.section(".", 0, 0))); + auto job = new NetJob(QString("%1 Icon Download %2").arg(m_parent->debugName()).arg(logo), APPLICATION->network()); + job->addNetAction(Net::Download::makeCached(QUrl(url), entry)); + + auto fullPath = entry->getFullPath(); + QObject::connect(job, &NetJob::succeeded, this, [this, logo, fullPath, job] { + job->deleteLater(); + emit logoLoaded(logo, QIcon(fullPath)); + if (waitingCallbacks.contains(logo)) { + waitingCallbacks.value(logo)(fullPath); + } + }); + + QObject::connect(job, &NetJob::failed, this, [this, logo, job] { + job->deleteLater(); + emit logoFailed(logo); + }); + + job->start(); + m_loadingLogos.append(logo); +} + +/******** Request callbacks ********/ + +void ModpackListModel::logoLoaded(QString logo, QIcon out) +{ + m_loadingLogos.removeAll(logo); + m_logoMap.insert(logo, out); + for (int i = 0; i < modpacks.size(); i++) { + if (modpacks[i].iconName == logo) { + emit dataChanged(createIndex(i, 0), createIndex(i, 0), { Qt::DecorationRole }); + } + } +} + +void ModpackListModel::logoFailed(QString logo) +{ + m_failedLogos.append(logo); + m_loadingLogos.removeAll(logo); +} + +void ModpackListModel::searchRequestFinished(QJsonDocument& doc_all) +{ + jobPtr.reset(); + + QList newList; + + auto packs_all = doc_all.object().value("hits").toArray(); + for (auto packRaw : packs_all) { + auto packObj = packRaw.toObject(); + + Modrinth::Modpack pack; + try { + Modrinth::loadIndexedPack(pack, packObj); + newList.append(pack); + } catch (const JSONValidationError& e) { + qWarning() << "Error while loading mod from " << m_parent->debugName() << ": " << e.cause(); + continue; + } + } + + if (packs_all.size() < 25) { + searchState = Finished; + } else { + nextSearchOffset += 25; + searchState = CanPossiblyFetchMore; + } + + beginInsertRows(QModelIndex(), modpacks.size(), modpacks.size() + newList.size() - 1); + modpacks.append(newList); + endInsertRows(); +} + +void ModpackListModel::searchRequestFailed(QString reason) +{ + if (!jobPtr->first()->m_reply) { + // Network error + QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load mods.")); + } else if (jobPtr->first()->m_reply && jobPtr->first()->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 409) { + // 409 Gone, notify user to update + QMessageBox::critical(nullptr, tr("Error"), + //: %1 refers to the launcher itself + QString("%1 %2") + .arg(m_parent->displayName()) + .arg(tr("API version too old!\nPlease update %1!").arg(BuildConfig.LAUNCHER_NAME))); + } + jobPtr.reset(); + + if (searchState == ResetRequested) { + beginResetModel(); + modpacks.clear(); + endResetModel(); + + nextSearchOffset = 0; + performPaginatedSearch(); + } else { + searchState = Finished; + } +} + +void ModpackListModel::versionRequestSucceeded(QJsonDocument doc, QString id) +{ + auto& current = m_parent->getCurrent(); + if (id != current.id) { + return; + } + + auto arr = doc.isObject() ? Json::ensureArray(doc.object(), "data") : doc.array(); + + try { + // loadIndexedPackVersions(current, arr); + } catch (const JSONValidationError& e) { + qDebug() << doc; + qWarning() << "Error while reading " << debugName() << " mod version: " << e.cause(); + } + + // m_parent->updateModVersions(); +} + +} // namespace Modrinth + +/******** Helpers ********/ diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h new file mode 100644 index 000000000..1fdbe278b --- /dev/null +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h @@ -0,0 +1,81 @@ +#pragma once + +#include + +#include "modplatform/modrinth/ModrinthPackManifest.h" +#include "ui/pages/modplatform/modrinth/ModrinthPage.h" + +class ModPage; +class Version; + +namespace Modrinth { + +using LogoMap = QMap; +using LogoCallback = std::function; + +class ModpackListModel : public QAbstractListModel { + Q_OBJECT + + public: + ModpackListModel(ModrinthPage* parent); + ~ModpackListModel() override = default; + + inline auto rowCount(const QModelIndex& parent) const -> int override { return modpacks.size(); }; + inline auto columnCount(const QModelIndex& parent) const -> int override { return 1; }; + inline auto flags(const QModelIndex& index) const -> Qt::ItemFlags override { return QAbstractListModel::flags(index); }; + + auto debugName() const -> QString; + + /* Retrieve information from the model at a given index with the given role */ + auto data(const QModelIndex& index, int role) const -> QVariant override; + + inline void setActiveJob(NetJob::Ptr ptr) { jobPtr = ptr; } + + /* Ask the API for more information */ + void fetchMore(const QModelIndex& parent) override; + void refresh(); + void searchWithTerm(const QString& term, const int sort); + + void getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback); + + inline auto canFetchMore(const QModelIndex& parent) const -> bool override { return searchState == CanPossiblyFetchMore; }; + + public slots: + void searchRequestFinished(QJsonDocument& doc_all); + void searchRequestFailed(QString reason); + + void versionRequestSucceeded(QJsonDocument doc, QString addonId); + + protected slots: + + void logoFailed(QString logo); + void logoLoaded(QString logo, QIcon out); + + void performPaginatedSearch(); + + protected: + void requestLogo(QString file, QString url); + + inline auto getMineVersions() const -> std::list; + + protected: + ModrinthPage* m_parent; + + QList modpacks; + + LogoMap m_logoMap; + QMap waitingCallbacks; + QStringList m_failedLogos; + QStringList m_loadingLogos; + + QString currentSearchTerm; + int currentSort = 0; + int nextSearchOffset = 0; + enum SearchState { None, CanPossiblyFetchMore, ResetRequested, Finished } searchState = None; + + NetJob::Ptr jobPtr; + + QByteArray m_all_response; + QByteArray m_specific_response; +}; +} // namespace ModPlatform diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index 0d65ef166..688053166 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -34,14 +34,41 @@ */ #include "ModrinthPage.h" - #include "ui_ModrinthPage.h" -#include +#include "ModrinthModel.h" -ModrinthPage::ModrinthPage(NewInstanceDialog *dialog, QWidget *parent) : QWidget(parent), ui(new Ui::ModrinthPage), dialog(dialog) +#include "InstanceImportTask.h" +#include "Json.h" + +#include + +#include +#include +#include + +ModrinthPage::ModrinthPage(NewInstanceDialog* dialog, QWidget* parent) : QWidget(parent), ui(new Ui::ModrinthPage), dialog(dialog) { ui->setupUi(this); + + connect(ui->searchButton, &QPushButton::clicked, this, &ModrinthPage::triggerSearch); + ui->searchEdit->installEventFilter(this); + m_model = new Modrinth::ModpackListModel(this); + ui->packView->setModel(m_model); + + ui->versionSelectionBox->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + ui->versionSelectionBox->view()->parentWidget()->setMaximumHeight(300); + + ui->sortByBox->addItem(tr("Sort by Featured")); + ui->sortByBox->addItem(tr("Sort by Popularity")); + ui->sortByBox->addItem(tr("Sort by Last Updated")); + ui->sortByBox->addItem(tr("Sort by Name")); + ui->sortByBox->addItem(tr("Sort by Author")); + ui->sortByBox->addItem(tr("Sort by Total Downloads")); + + connect(ui->sortByBox, SIGNAL(currentIndexChanged(int)), this, SLOT(triggerSearch())); + connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ModrinthPage::onSelectionChanged); + connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &ModrinthPage::onVersionSelectionChanged); } ModrinthPage::~ModrinthPage() @@ -60,10 +87,10 @@ void ModrinthPage::openedImpl() triggerSearch(); } -bool ModrinthPage::eventFilter(QObject *watched, QEvent *event) +bool ModrinthPage::eventFilter(QObject* watched, QEvent* event) { if (watched == ui->searchEdit && event->type() == QEvent::KeyPress) { - auto *keyEvent = reinterpret_cast(event); + auto* keyEvent = reinterpret_cast(event); if (keyEvent->key() == Qt::Key_Return) { this->triggerSearch(); keyEvent->accept(); @@ -73,6 +100,176 @@ bool ModrinthPage::eventFilter(QObject *watched, QEvent *event) return QObject::eventFilter(watched, event); } -void ModrinthPage::triggerSearch() { +void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second) +{ + ui->versionSelectionBox->clear(); + if (!first.isValid()) { + if (isOpened) { + dialog->setSuggestedPack(); + } + return; + } + + current = m_model->data(first, Qt::UserRole).value(); + auto name = current.name; + + if (!current.extraInfoLoaded) { + qDebug() << "Loading modrinth modpack information"; + + auto netJob = new NetJob(QString("Modrinth::PackInformation(%1)").arg(current.name), APPLICATION->network()); + auto response = new QByteArray(); + + QString id = current.id; + + netJob->addNetAction(Net::Download::makeByteArray(QString("https://staging-api.modrinth.com/v2/project/%1").arg(id), response)); + + QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id] { + if (id != current.id) { + return; // wrong request? + } + + QJsonParseError parse_error; + QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); + if (parse_error.error != QJsonParseError::NoError) { + qWarning() << "Error while parsing JSON response from Modrinth at " << parse_error.offset + << " reason: " << parse_error.errorString(); + qWarning() << *response; + return; + } + + auto obj = Json::requireObject(doc); + + try { + Modrinth::loadIndexedInfo(current, obj); + } catch (const JSONValidationError& e) { + qDebug() << *response; + qWarning() << "Error while reading modrinth modpack version: " << e.cause(); + } + + updateUI(); + suggestCurrent(); + }); + QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { + netJob->deleteLater(); + delete response; + }); + netJob->start(); + } else + updateUI(); + + if (!current.versionsLoaded) { + qDebug() << "Loading modrinth modpack versions"; + + auto netJob = new NetJob(QString("Modrinth::PackVersions(%1)").arg(current.name), APPLICATION->network()); + auto response = new QByteArray(); + + QString id = current.id; + + netJob->addNetAction( + Net::Download::makeByteArray(QString("https://staging-api.modrinth.com/v2/project/%1/version").arg(id), response)); + + QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id] { + if (id != current.id) { + return; // wrong request? + } + + QJsonParseError parse_error; + QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); + if (parse_error.error != QJsonParseError::NoError) { + qWarning() << "Error while parsing JSON response from Modrinth at " << parse_error.offset + << " reason: " << parse_error.errorString(); + qWarning() << *response; + return; + } + + try { + Modrinth::loadIndexedVersions(current, doc); + } catch (const JSONValidationError& e) { + qDebug() << *response; + qWarning() << "Error while reading modrinth modpack version: " << e.cause(); + } + + for (auto version : current.versions) { + ui->versionSelectionBox->addItem(version.version, QVariant(version.id)); + } + + updateVersionsUI(); + suggestCurrent(); + }); + QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { + netJob->deleteLater(); + delete response; + }); + netJob->start(); + + } else { + for (auto version : current.versions) { + ui->versionSelectionBox->addItem(QString("%1 - %2").arg(version.name, version.version), QVariant(version.id)); + } + + suggestCurrent(); + } +} + +void ModrinthPage::updateUI() +{ + QString text = ""; + + if (current.extra.sourceUrl.isEmpty()) + text = current.name; + else + text = "" + current.name + ""; + + if (!current.authors.empty()) { + // TODO: Implement multiple authors with links + text += "
" + tr(" by ") + current.authors.at(0); + } + + text += "
"; + + HoeDown h; + text += h.process(current.extra.body.toUtf8()); + + ui->packDescription->setHtml(text + current.description); +} + +void ModrinthPage::updateVersionsUI() +{ + // idk +} + +void ModrinthPage::suggestCurrent() +{ + if (!isOpened) { + return; + } + + if (selectedVersion.isEmpty()) { + dialog->setSuggestedPack(); + return; + } + + for (auto& ver : current.versions) { + if (ver.id == selectedVersion) { + dialog->setSuggestedPack(current.name, new InstanceImportTask(ver.download_url)); + + break; + } + } +} + +void ModrinthPage::triggerSearch() +{ + m_model->searchWithTerm(ui->searchEdit->text(), ui->sortByBox->currentIndex()); +} + +void ModrinthPage::onVersionSelectionChanged(QString data) +{ + if (data.isNull() || data.isEmpty()) { + selectedVersion = ""; + return; + } + selectedVersion = ui->versionSelectionBox->currentData().toString(); + suggestCurrent(); } diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h index 562049b48..f72a5071f 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h @@ -39,48 +39,53 @@ #include "ui/dialogs/NewInstanceDialog.h" #include "ui/pages/BasePage.h" +#include "modplatform/modrinth/ModrinthPackManifest.h" + #include -namespace Ui -{ - class ModrinthPage; +namespace Ui { +class ModrinthPage; } -class ModrinthPage : public QWidget, public BasePage -{ +namespace Modrinth { +class ModpackListModel; +} + +class ModrinthPage : public QWidget, public BasePage { Q_OBJECT -public: - explicit ModrinthPage(NewInstanceDialog *dialog, QWidget *parent = nullptr); + public: + explicit ModrinthPage(NewInstanceDialog* dialog, QWidget* parent = nullptr); ~ModrinthPage() override; - QString displayName() const override - { - return tr("Modrinth"); - } - QIcon icon() const override - { - return APPLICATION->getThemedIcon("modrinth"); - } - QString id() const override - { - return "modrinth"; - } + QString displayName() const override { return tr("Modrinth"); } + QIcon icon() const override { return APPLICATION->getThemedIcon("modrinth"); } + QString id() const override { return "modrinth"; } + QString helpPage() const override { return "Modrinth-platform"; } + + inline auto debugName() const -> QString { return "Modrinth"; } + inline auto metaEntryBase() const -> QString { return "ModrinthModpacks"; }; + + auto getCurrent() -> Modrinth::Modpack& { return current; } + void suggestCurrent(); + + void updateUI(); + void updateVersionsUI(); - virtual QString helpPage() const override - { - return "Modrinth-platform"; - } void retranslate() override; - void openedImpl() override; + bool eventFilter(QObject* watched, QEvent* event) override; - bool eventFilter(QObject *watched, QEvent *event) override; - -private slots: + private slots: + void onSelectionChanged(QModelIndex first, QModelIndex second); + void onVersionSelectionChanged(QString data); void triggerSearch(); -private: - Ui::ModrinthPage *ui; - NewInstanceDialog *dialog; + private: + Ui::ModrinthPage* ui; + NewInstanceDialog* dialog; + Modrinth::ModpackListModel* m_model; + + Modrinth::Modpack current; + QString selectedVersion; }; From 9dd70ca9ae6fdab913a77467e803bf90ddd949ed Mon Sep 17 00:00:00 2001 From: flow Date: Sat, 14 May 2022 20:26:20 -0300 Subject: [PATCH 20/52] fix: download icon as well when importing modrinth modpacks --- launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp | 3 +++ launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui | 3 +++ 2 files changed, 6 insertions(+) diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index 688053166..b21fdf4a5 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -253,6 +253,9 @@ void ModrinthPage::suggestCurrent() for (auto& ver : current.versions) { if (ver.id == selectedVersion) { dialog->setSuggestedPack(current.name, new InstanceImportTask(ver.download_url)); + auto iconName = current.iconName; + m_model->getLogo(iconName, current.iconUrl.toString(), + [this, iconName](QString logo) { dialog->setSuggestedIconFromFile(logo, iconName); }); break; } diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui index 7ef099d34..8de53a693 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui @@ -45,6 +45,9 @@ 48
+ + true +
From 5ea8cec16f6dfbaeaca56ccf7f9151039a1dd145 Mon Sep 17 00:00:00 2001 From: flow Date: Sat, 14 May 2022 21:29:48 -0300 Subject: [PATCH 21/52] fix: make all modrinth modpacks have the same icon size --- .../modplatform/modrinth/ModrinthModel.cpp | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index 2890e27d5..121f5d4e4 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -49,9 +49,10 @@ auto ModpackListModel::data(const QModelIndex& index, int role) const -> QVarian } return pack.description; } else if (role == Qt::DecorationRole) { - // FIXME: help the icons dont have the same size ;-; if (m_logoMap.contains(pack.iconName)) { - return (m_logoMap.value(pack.iconName)); + return (m_logoMap.value(pack.iconName) + .pixmap(48, 48) + .scaled(48, 48, Qt::IgnoreAspectRatio, Qt::TransformationMode::SmoothTransformation)); } QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder"); ((ModpackListModel*)this)->requestLogo(pack.iconName, pack.iconUrl.toString()); @@ -65,14 +66,6 @@ auto ModpackListModel::data(const QModelIndex& index, int role) const -> QVarian return {}; } -/* -void ModpackListModel::requestModVersions(ModPlatform::IndexedPack const& current) -{ - auto profile = (dynamic_cast((dynamic_cast(parent()))->m_instance))->getPackProfile(); - - m_parent->apiProvider()->getVersions(this, { current.addonId.toString(), getMineVersions(), profile->getModLoader() }); -}*/ - void ModpackListModel::performPaginatedSearch() { // TODO: Move to standalone API @@ -86,7 +79,7 @@ void ModpackListModel::performPaginatedSearch() netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchAllUrl), &m_all_response)); QObject::connect(netJob, &NetJob::succeeded, this, [this] { - QJsonParseError parse_error_all {}; + QJsonParseError parse_error_all{}; QJsonDocument doc_all = QJsonDocument::fromJson(m_all_response, &parse_error_all); if (parse_error_all.error != QJsonParseError::NoError) { @@ -210,7 +203,7 @@ void ModpackListModel::searchRequestFinished(QJsonDocument& doc_all) continue; } } - + if (packs_all.size() < 25) { searchState = Finished; } else { From 9899a0e098e5cfb76a754fa9da2f73be46cc880a Mon Sep 17 00:00:00 2001 From: flow Date: Sat, 14 May 2022 21:47:35 -0300 Subject: [PATCH 22/52] fix: Have the URL be the project URL itself (I think, doesn't seem to work for the waffle though, probably because of the staging API :/) --- launcher/modplatform/modrinth/ModrinthPackManifest.cpp | 1 + launcher/modplatform/modrinth/ModrinthPackManifest.h | 1 + launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp index 4dcd2fd49..4b8a9a9b5 100644 --- a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp @@ -35,6 +35,7 @@ void loadIndexedPack(Modpack& pack, QJsonObject& obj) void loadIndexedInfo(Modpack& pack, QJsonObject& obj) { pack.extra.body = Json::ensureString(obj, "body"); + pack.extra.projectUrl = QString("https://modrinth.com/modpack/%1").arg(Json::ensureString(obj, "slug")); pack.extra.sourceUrl = Json::ensureString(obj, "source_url"); pack.extra.wikiUrl = Json::ensureString(obj, "wiki_url"); diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.h b/launcher/modplatform/modrinth/ModrinthPackManifest.h index 7dab893ca..aaaacf2cd 100644 --- a/launcher/modplatform/modrinth/ModrinthPackManifest.h +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.h @@ -39,6 +39,7 @@ struct File struct ModpackExtra { QString body; + QString projectUrl; QString sourceUrl; QString wikiUrl; }; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index b21fdf4a5..cf519b8c7 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -219,7 +219,7 @@ void ModrinthPage::updateUI() if (current.extra.sourceUrl.isEmpty()) text = current.name; else - text = "" + current.name + ""; + text = "" + current.name + ""; if (!current.authors.empty()) { // TODO: Implement multiple authors with links From 365cc198ba1e4e8129c95291e60e2c3c7ffbbf7a Mon Sep 17 00:00:00 2001 From: flow Date: Sat, 14 May 2022 21:50:54 -0300 Subject: [PATCH 23/52] refactor: some random improvements --- launcher/InstanceImportTask.cpp | 8 ++++---- launcher/ui/pages/modplatform/ImportPage.cpp | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/launcher/InstanceImportTask.cpp b/launcher/InstanceImportTask.cpp index ec0f58e08..29e3a26cd 100644 --- a/launcher/InstanceImportTask.cpp +++ b/launcher/InstanceImportTask.cpp @@ -504,16 +504,16 @@ void InstanceImportTask::processModrinth() { QJsonObject hashes = Json::requireObject(obj, "hashes"); QString hash; QCryptographicHash::Algorithm hashAlgorithm; - hash = Json::ensureString(hashes, "sha256"); - hashAlgorithm = QCryptographicHash::Sha256; + hash = Json::ensureString(hashes, "sha1"); + hashAlgorithm = QCryptographicHash::Sha1; if (hash.isEmpty()) { hash = Json::ensureString(hashes, "sha512"); hashAlgorithm = QCryptographicHash::Sha512; if (hash.isEmpty()) { - hash = Json::ensureString(hashes, "sha1"); - hashAlgorithm = QCryptographicHash::Sha1; + hash = Json::ensureString(hashes, "sha256"); + hashAlgorithm = QCryptographicHash::Sha256; if (hash.isEmpty()) { throw JSONValidationError("No hash found for: " + file.path); diff --git a/launcher/ui/pages/modplatform/ImportPage.cpp b/launcher/ui/pages/modplatform/ImportPage.cpp index 3b65de9d4..c86d02cae 100644 --- a/launcher/ui/pages/modplatform/ImportPage.cpp +++ b/launcher/ui/pages/modplatform/ImportPage.cpp @@ -110,7 +110,10 @@ void ImportPage::updateState() // FIXME: actually do some validation of what's inside here... this is fake AF QFileInfo fi(input); // mrpack is a modrinth pack - if(fi.exists() && (fi.suffix() == "zip" || fi.suffix() == "mrpack")) + + // Allow non-latin people to use ZIP files! + auto zip = QMimeDatabase().mimeTypeForUrl(url).suffixes().contains("zip"); + if(fi.exists() && (zip || fi.suffix() == "mrpack")) { QFileInfo fi(url.fileName()); dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(url)); From 49de5d9b07c8e05681ef9d485ccfd3d8e4bca784 Mon Sep 17 00:00:00 2001 From: flow Date: Sat, 14 May 2022 22:04:40 -0300 Subject: [PATCH 24/52] change: list what file types can be entered in the importer --- launcher/ui/pages/modplatform/ImportPage.ui | 78 +++++++++++++++++---- 1 file changed, 66 insertions(+), 12 deletions(-) diff --git a/launcher/ui/pages/modplatform/ImportPage.ui b/launcher/ui/pages/modplatform/ImportPage.ui index eb63cbe90..77bc5da5b 100644 --- a/launcher/ui/pages/modplatform/ImportPage.ui +++ b/launcher/ui/pages/modplatform/ImportPage.ui @@ -11,28 +11,75 @@ - - - - Browse - - - - + http:// - - + + - Local file or link to a direct download: + Browse - + + + + + + The following file types are implemented (both for local files and URLs): + + + Qt::AlignCenter + + + + + + + - Curseforge modpacks (ZIP) + + + Qt::AlignCenter + + + + + + + - Modrinth modpacks (ZIP and mrpack) + + + Qt::AlignCenter + + + + + + + - PolyMC / MultiMC exported instances (ZIP) + + + Qt::AlignCenter + + + + + + + - Technic modpacks (ZIP) + + + Qt::AlignCenter + + + + + + Qt::Vertical @@ -45,6 +92,13 @@ + + + + Local file or link to a direct download: + + + From 4745ed28186f46de60de155826c8f2bfb54f45cb Mon Sep 17 00:00:00 2001 From: flow Date: Sat, 14 May 2022 22:12:51 -0300 Subject: [PATCH 25/52] fix: choose valid download url even if it's not the primary one It seems to be possible to have modpack versions that have to primary file. In those cases, we pick a valid one "at random". --- .../modplatform/modrinth/ModrinthPackManifest.cpp | 14 +++++++++++--- .../modplatform/modrinth/ModrinthPackManifest.h | 4 ++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp index 4b8a9a9b5..88ca808af 100644 --- a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp @@ -81,15 +81,23 @@ auto loadIndexedVersion(QJsonObject &obj) -> ModpackVersion auto files = Json::requireArray(obj, "files"); + qWarning() << files; + for (auto file_iter : files) { File indexed_file; auto parent = Json::requireObject(file_iter); - if (!Json::ensureBoolean(parent, "primary", false)) { - continue; + auto is_primary = Json::ensureBoolean(parent, "primary", false); + if (!is_primary) { + auto filename = Json::ensureString(parent, "filename"); + // Checking suffix here is fine because it's the response from Modrinth, + // so one would assume it will always be in English. + if(!filename.endsWith("mrpack") && !filename.endsWith("zip")) + continue; } file.download_url = Json::requireString(parent, "url"); - break; + if(is_primary) + break; } if(file.download_url.isEmpty()) diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.h b/launcher/modplatform/modrinth/ModrinthPackManifest.h index aaaacf2cd..585f692aa 100644 --- a/launcher/modplatform/modrinth/ModrinthPackManifest.h +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.h @@ -79,5 +79,5 @@ auto loadIndexedVersion(QJsonObject&) -> ModpackVersion; } -Q_DECLARE_METATYPE(Modrinth::Modpack); -Q_DECLARE_METATYPE(Modrinth::ModpackVersion); +Q_DECLARE_METATYPE(Modrinth::Modpack) +Q_DECLARE_METATYPE(Modrinth::ModpackVersion) From 9731e06728ab1bdf11f6891b563d9f7123c1a0d8 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Sun, 15 May 2022 11:49:27 +0200 Subject: [PATCH 26/52] fix: fix build on Qt 5.12 --- launcher/modplatform/modrinth/ModrinthPackManifest.h | 1 + 1 file changed, 1 insertion(+) diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.h b/launcher/modplatform/modrinth/ModrinthPackManifest.h index 585f692aa..33c3fc5ea 100644 --- a/launcher/modplatform/modrinth/ModrinthPackManifest.h +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.h @@ -21,6 +21,7 @@ #include #include #include +#include class MinecraftInstance; From a43f882d482061b86a339c1338e26246f6fc5f70 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Sun, 15 May 2022 12:06:01 +0200 Subject: [PATCH 27/52] feat: add support for Quilt Loader in Modrinth packs --- launcher/InstanceImportTask.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/launcher/InstanceImportTask.cpp b/launcher/InstanceImportTask.cpp index 29e3a26cd..293105380 100644 --- a/launcher/InstanceImportTask.cpp +++ b/launcher/InstanceImportTask.cpp @@ -480,7 +480,7 @@ void InstanceImportTask::processMultiMC() void InstanceImportTask::processModrinth() { std::vector files; - QString minecraftVersion, fabricVersion, forgeVersion; + QString minecraftVersion, fabricVersion, quiltVersion, forgeVersion; try { QString indexPath = FS::PathCombine(m_stagingPath, "modrinth.index.json"); @@ -547,6 +547,12 @@ void InstanceImportTask::processModrinth() { throw JSONValidationError("Duplicate Fabric Loader version"); fabricVersion = Json::requireString(*it, "Fabric Loader version"); } + else if (name == "quilt-loader") + { + if (!quiltVersion.isEmpty()) + throw JSONValidationError("Duplicate Quilt Loader version"); + quiltVersion = Json::requireString(*it, "Quilt Loader version"); + } else if (name == "forge") { if (!forgeVersion.isEmpty()) @@ -587,6 +593,8 @@ void InstanceImportTask::processModrinth() { components->setComponentVersion("net.minecraft", minecraftVersion, true); if (!fabricVersion.isEmpty()) components->setComponentVersion("net.fabricmc.fabric-loader", fabricVersion, true); + if (!quiltVersion.isEmpty()) + components->setComponentVersion("org.quiltmc.quilt-loader", quiltVersion, true); if (!forgeVersion.isEmpty()) components->setComponentVersion("net.minecraftforge", forgeVersion, true); if (m_instIcon != "default") From 4a0e4fdb85ae6782406919c4b4df9554a81356aa Mon Sep 17 00:00:00 2001 From: flow Date: Sun, 15 May 2022 07:12:31 -0300 Subject: [PATCH 28/52] fix: add author page url --- launcher/modplatform/modrinth/ModrinthPackManifest.cpp | 7 ++++++- launcher/modplatform/modrinth/ModrinthPackManifest.h | 2 +- launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp | 8 +++----- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp index 88ca808af..f690984b8 100644 --- a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp @@ -16,9 +16,13 @@ #include "ModrinthPackManifest.h" #include "Json.h" +#include "modplatform/modrinth/ModrinthAPI.h" + #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" +static ModrinthAPI api; + namespace Modrinth { void loadIndexedPack(Modpack& pack, QJsonObject& obj) @@ -27,7 +31,8 @@ void loadIndexedPack(Modpack& pack, QJsonObject& obj) pack.name = Json::ensureString(obj, "title"); pack.description = Json::ensureString(obj, "description"); - pack.authors << Json::ensureString(obj, "author"); + auto temp_author_name = Json::ensureString(obj, "author"); + pack.author = std::make_tuple(temp_author_name, api.getAuthorURL(temp_author_name)); pack.iconName = QString("modrinth_%1").arg(Json::ensureString(obj, "slug")); pack.iconUrl = Json::ensureString(obj, "icon_url"); } diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.h b/launcher/modplatform/modrinth/ModrinthPackManifest.h index 33c3fc5ea..47817bad1 100644 --- a/launcher/modplatform/modrinth/ModrinthPackManifest.h +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.h @@ -62,7 +62,7 @@ struct Modpack { QString name; QString description; - QStringList authors; + std::tuple author; QString iconName; QUrl iconUrl; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index cf519b8c7..acfd14b5e 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -221,10 +221,8 @@ void ModrinthPage::updateUI() else text = "" + current.name + ""; - if (!current.authors.empty()) { - // TODO: Implement multiple authors with links - text += "
" + tr(" by ") + current.authors.at(0); - } + // TODO: Implement multiple authors with links + text += "
" + tr(" by ") + QString("%2").arg(std::get<1>(current.author).toString(), std::get<0>(current.author)); text += "
"; @@ -255,7 +253,7 @@ void ModrinthPage::suggestCurrent() dialog->setSuggestedPack(current.name, new InstanceImportTask(ver.download_url)); auto iconName = current.iconName; m_model->getLogo(iconName, current.iconUrl.toString(), - [this, iconName](QString logo) { dialog->setSuggestedIconFromFile(logo, iconName); }); + [this, iconName](QString logo) { dialog->setSuggestedIconFromFile(logo, iconName); }); break; } From 4bb429a0fbe698d0f4dbdbf02719e76730b5b6bd Mon Sep 17 00:00:00 2001 From: flow Date: Sun, 15 May 2022 07:43:02 -0300 Subject: [PATCH 29/52] change: use build variables for the modrinth API URLs Make it more consistent with the others --- buildconfig/BuildConfig.h | 3 +++ launcher/modplatform/modrinth/ModrinthAPI.h | 22 ++++++++++--------- .../modplatform/modrinth/ModrinthModel.cpp | 6 ++--- .../modplatform/modrinth/ModrinthPage.cpp | 5 +++-- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/buildconfig/BuildConfig.h b/buildconfig/BuildConfig.h index a920a3d41..8594e46dc 100644 --- a/buildconfig/BuildConfig.h +++ b/buildconfig/BuildConfig.h @@ -151,6 +151,9 @@ class Config { */ QString TECHNIC_API_BUILD = "multimc"; + QString MODRINTH_STAGING_URL = "https://staging-api.modrinth.com/v2"; + QString MODRINTH_PROD_URL = "https://api.modrinth.com/v2"; + /** * \brief Converts the Version to a string. * \return The version number in string format (major.minor.revision.build). diff --git a/launcher/modplatform/modrinth/ModrinthAPI.h b/launcher/modplatform/modrinth/ModrinthAPI.h index 86852c946..874383757 100644 --- a/launcher/modplatform/modrinth/ModrinthAPI.h +++ b/launcher/modplatform/modrinth/ModrinthAPI.h @@ -1,5 +1,6 @@ #pragma once +#include "BuildConfig.h" #include "modplatform/ModAPI.h" #include "modplatform/helpers/NetworkModAPI.h" @@ -47,13 +48,13 @@ class ModrinthAPI : public NetworkModAPI { return ""; } - return QString( - "https://api.modrinth.com/v2/search?" - "offset=%1&" - "limit=25&" - "query=%2&" - "index=%3&" - "facets=[[%4],%5[\"project_type:mod\"]]") + return QString(BuildConfig.MODRINTH_PROD_URL + + "/search?" + "offset=%1&" + "limit=25&" + "query=%2&" + "index=%3&" + "facets=[[%4],%5[\"project_type:mod\"]]") .arg(args.offset) .arg(args.search) .arg(args.sorting) @@ -63,9 +64,10 @@ class ModrinthAPI : public NetworkModAPI { inline auto getVersionsURL(VersionSearchArgs& args) const -> QString override { - return QString("https://api.modrinth.com/v2/project/%1/version?" - "game_versions=[%2]" - "loaders=[\"%3\"]") + return QString(BuildConfig.MODRINTH_PROD_URL + + "/project/%1/version?" + "game_versions=[%2]" + "loaders=[\"%3\"]") .arg(args.addonId) .arg(getGameVersionsString(args.mcVersions)) .arg(getModLoaderStrings(args.loader).join("\",\"")); diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index 121f5d4e4..1d1b4c8e7 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -71,10 +71,10 @@ void ModpackListModel::performPaginatedSearch() // TODO: Move to standalone API NetJob* netJob = new NetJob("Modrinth::SearchModpack", APPLICATION->network()); auto searchAllUrl = QString( - "https://staging-api.modrinth.com/v2/search?" - "query=%1&" + "%1/search?" + "query=%2&" "facets=[[\"project_type:modpack\"]]") - .arg(currentSearchTerm); + .arg(BuildConfig.MODRINTH_STAGING_URL, currentSearchTerm); netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchAllUrl), &m_all_response)); diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index acfd14b5e..5dc66e56a 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -38,6 +38,7 @@ #include "ModrinthModel.h" +#include "BuildConfig.h" #include "InstanceImportTask.h" #include "Json.h" @@ -122,7 +123,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second) QString id = current.id; - netJob->addNetAction(Net::Download::makeByteArray(QString("https://staging-api.modrinth.com/v2/project/%1").arg(id), response)); + netJob->addNetAction(Net::Download::makeByteArray(QString("%1/project/%2").arg(BuildConfig.MODRINTH_STAGING_URL, id), response)); QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id] { if (id != current.id) { @@ -167,7 +168,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second) QString id = current.id; netJob->addNetAction( - Net::Download::makeByteArray(QString("https://staging-api.modrinth.com/v2/project/%1/version").arg(id), response)); + Net::Download::makeByteArray(QString("%1/project/%2/version").arg(BuildConfig.MODRINTH_STAGING_URL, id), response)); QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id] { if (id != current.id) { From 3abf466632588f9285579a9822b5da2c9fea7bec Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Sun, 15 May 2022 13:20:05 +0200 Subject: [PATCH 30/52] chore: add/update license headers --- launcher/InstanceImportTask.cpp | 40 ++++++++++++++----- launcher/InstanceImportTask.h | 40 ++++++++++++++----- launcher/modplatform/modrinth/ModrinthAPI.h | 17 ++++++++ .../modrinth/ModrinthPackIndex.cpp | 17 ++++++++ .../modplatform/modrinth/ModrinthPackIndex.h | 17 ++++++++ .../modrinth/ModrinthPackManifest.cpp | 40 ++++++++++++++----- .../modrinth/ModrinthPackManifest.h | 40 ++++++++++++++----- launcher/ui/pages/modplatform/ImportPage.cpp | 1 + .../modplatform/modrinth/ModrinthModModel.h | 18 +++++++++ .../modplatform/modrinth/ModrinthModel.cpp | 34 ++++++++++++++++ .../modplatform/modrinth/ModrinthModel.h | 34 ++++++++++++++++ 11 files changed, 258 insertions(+), 40 deletions(-) diff --git a/launcher/InstanceImportTask.cpp b/launcher/InstanceImportTask.cpp index 293105380..8a0432c9f 100644 --- a/launcher/InstanceImportTask.cpp +++ b/launcher/InstanceImportTask.cpp @@ -1,16 +1,36 @@ -/* Copyright 2013-2021 MultiMC Contributors +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * Copyright (C) 2022 Sefa Eyeoglu * - * 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * 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. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * 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 "InstanceImportTask.h" diff --git a/launcher/InstanceImportTask.h b/launcher/InstanceImportTask.h index 317562d91..0dc6ba88b 100644 --- a/launcher/InstanceImportTask.h +++ b/launcher/InstanceImportTask.h @@ -1,16 +1,36 @@ -/* Copyright 2013-2021 MultiMC Contributors +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * Copyright (C) 2022 Sefa Eyeoglu * - * 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * 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. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * 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 diff --git a/launcher/modplatform/modrinth/ModrinthAPI.h b/launcher/modplatform/modrinth/ModrinthAPI.h index 874383757..09eefcd1a 100644 --- a/launcher/modplatform/modrinth/ModrinthAPI.h +++ b/launcher/modplatform/modrinth/ModrinthAPI.h @@ -1,3 +1,20 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #pragma once #include "BuildConfig.h" diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp index a3c2f166f..f7fa98641 100644 --- a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp @@ -1,3 +1,20 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "ModrinthPackIndex.h" #include "ModrinthAPI.h" diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.h b/launcher/modplatform/modrinth/ModrinthPackIndex.h index fd17847af..7f306f25f 100644 --- a/launcher/modplatform/modrinth/ModrinthPackIndex.h +++ b/launcher/modplatform/modrinth/ModrinthPackIndex.h @@ -1,3 +1,20 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #pragma once #include "modplatform/ModIndex.h" diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp index f690984b8..f77baa6ae 100644 --- a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp @@ -1,16 +1,36 @@ -/* Copyright 2022 kb1000 +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher * - * 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * 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. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * Copyright 2022 kb1000 + * + * 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 "ModrinthPackManifest.h" diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.h b/launcher/modplatform/modrinth/ModrinthPackManifest.h index 47817bad1..d350477b5 100644 --- a/launcher/modplatform/modrinth/ModrinthPackManifest.h +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.h @@ -1,16 +1,36 @@ -/* Copyright 2022 kb1000 +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher * - * 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * 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. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * Copyright 2022 kb1000 + * + * 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 diff --git a/launcher/ui/pages/modplatform/ImportPage.cpp b/launcher/ui/pages/modplatform/ImportPage.cpp index c86d02cae..c7bc13d88 100644 --- a/launcher/ui/pages/modplatform/ImportPage.cpp +++ b/launcher/ui/pages/modplatform/ImportPage.cpp @@ -2,6 +2,7 @@ /* * PolyMC - Minecraft Launcher * Copyright (c) 2022 Jamie Mansfield + * Copyright (c) 2022 Sefa Eyeoglu * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModModel.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModModel.h index 63c23bbeb..ae7b0bddc 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModModel.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModModel.h @@ -1,3 +1,21 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * Copyright (C) 2022 Sefa Eyeoglu + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #pragma once #include "ModrinthModPage.h" diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index 1d1b4c8e7..b0dfb1b75 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -1,3 +1,37 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * 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 "ModrinthModel.h" #include "BuildConfig.h" diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h index 1fdbe278b..6ec3bb976 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h @@ -1,3 +1,37 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * 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 From 5f2398fe59b0053d94c0600f54bddc642751bf74 Mon Sep 17 00:00:00 2001 From: flow Date: Sun, 15 May 2022 08:25:58 -0300 Subject: [PATCH 31/52] chore: license headers 2 --- launcher/InstanceImportTask.cpp | 1 + launcher/modplatform/modrinth/ModrinthAPI.h | 1 + launcher/modplatform/modrinth/ModrinthPackManifest.cpp | 1 + launcher/modplatform/modrinth/ModrinthPackManifest.h | 1 + launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp | 1 + launcher/ui/pages/modplatform/modrinth/ModrinthModel.h | 1 + launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp | 1 + launcher/ui/pages/modplatform/modrinth/ModrinthPage.h | 1 + 8 files changed, 8 insertions(+) diff --git a/launcher/InstanceImportTask.cpp b/launcher/InstanceImportTask.cpp index 8a0432c9f..26d46be03 100644 --- a/launcher/InstanceImportTask.cpp +++ b/launcher/InstanceImportTask.cpp @@ -2,6 +2,7 @@ /* * PolyMC - Minecraft Launcher * Copyright (C) 2022 Sefa Eyeoglu + * Copyright (c) 2022 flowln * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/launcher/modplatform/modrinth/ModrinthAPI.h b/launcher/modplatform/modrinth/ModrinthAPI.h index 09eefcd1a..6d642b5e8 100644 --- a/launcher/modplatform/modrinth/ModrinthAPI.h +++ b/launcher/modplatform/modrinth/ModrinthAPI.h @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only /* * PolyMC - Minecraft Launcher + * Copyright (c) 2022 flowln * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp index f77baa6ae..facf5ddbd 100644 --- a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only /* * PolyMC - Minecraft Launcher + * Copyright (c) 2022 flowln * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.h b/launcher/modplatform/modrinth/ModrinthPackManifest.h index d350477b5..55ad40d94 100644 --- a/launcher/modplatform/modrinth/ModrinthPackManifest.h +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.h @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only /* * PolyMC - Minecraft Launcher + * Copyright (c) 2022 flowln * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index b0dfb1b75..50974e13f 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only /* * PolyMC - Minecraft Launcher + * Copyright (c) 2022 flowln * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h index 6ec3bb976..e61eae7cf 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only /* * PolyMC - Minecraft Launcher + * Copyright (c) 2022 flowln * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index 5dc66e56a..f69983ee5 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only /* * PolyMC - Minecraft Launcher + * Copyright (c) 2022 flowln * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h index f72a5071f..9aa702f92 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only /* * PolyMC - Minecraft Launcher + * Copyright (c) 2022 flowln * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From 682a7fb6bad2c2d07ae5ddf67c139ac3f15672bb Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Sun, 15 May 2022 13:36:55 +0200 Subject: [PATCH 32/52] feat: add version of Modrinth modpack to instance name --- launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index f69983ee5..fd9adc247 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -252,7 +252,7 @@ void ModrinthPage::suggestCurrent() for (auto& ver : current.versions) { if (ver.id == selectedVersion) { - dialog->setSuggestedPack(current.name, new InstanceImportTask(ver.download_url)); + dialog->setSuggestedPack(current.name + " " + ver.version, new InstanceImportTask(ver.download_url)); auto iconName = current.iconName; m_model->getLogo(iconName, current.iconUrl.toString(), [this, iconName](QString logo) { dialog->setSuggestedIconFromFile(logo, iconName); }); From 93e0041d0e6c3d7859f7d8b058a0fd014329bec6 Mon Sep 17 00:00:00 2001 From: flow Date: Sun, 15 May 2022 11:09:45 -0300 Subject: [PATCH 33/52] change: use modrinth icon as default on modrinth packs --- launcher/InstanceImportTask.cpp | 4 ++++ launcher/resources/multimc/multimc.qrc | 2 +- .../resources/multimc/scalable/{ => instances}/modrinth.svg | 0 3 files changed, 5 insertions(+), 1 deletion(-) rename launcher/resources/multimc/scalable/{ => instances}/modrinth.svg (100%) diff --git a/launcher/InstanceImportTask.cpp b/launcher/InstanceImportTask.cpp index 26d46be03..f02aed910 100644 --- a/launcher/InstanceImportTask.cpp +++ b/launcher/InstanceImportTask.cpp @@ -622,6 +622,10 @@ void InstanceImportTask::processModrinth() { { instance.setIconKey(m_instIcon); } + else + { + instance.setIconKey("modrinth"); + } instance.setName(m_instName); instance.saveNow(); diff --git a/launcher/resources/multimc/multimc.qrc b/launcher/resources/multimc/multimc.qrc index 86ebf753c..e22fe7eef 100644 --- a/launcher/resources/multimc/multimc.qrc +++ b/launcher/resources/multimc/multimc.qrc @@ -21,7 +21,7 @@ scalable/atlauncher-placeholder.png - scalable/modrinth.svg + scalable/instances/modrinth.svg scalable/proxy.svg diff --git a/launcher/resources/multimc/scalable/modrinth.svg b/launcher/resources/multimc/scalable/instances/modrinth.svg similarity index 100% rename from launcher/resources/multimc/scalable/modrinth.svg rename to launcher/resources/multimc/scalable/instances/modrinth.svg From 4adc61bda91bb01e603fb975b05651df7decaf52 Mon Sep 17 00:00:00 2001 From: flow Date: Sun, 15 May 2022 11:26:15 -0300 Subject: [PATCH 34/52] change: update modrinth icon Updates to the version at https://github.com/modrinth/docs/blob/master/static/img/logo.svg --- launcher/resources/multimc/scalable/instances/modrinth.svg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launcher/resources/multimc/scalable/instances/modrinth.svg b/launcher/resources/multimc/scalable/instances/modrinth.svg index 32715f5ce..a40f0e72b 100644 --- a/launcher/resources/multimc/scalable/instances/modrinth.svg +++ b/launcher/resources/multimc/scalable/instances/modrinth.svg @@ -1,4 +1,4 @@ - - + + From 78cf0c73c89f0d1207bb079bf4670cc032607c4d Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Sun, 15 May 2022 20:38:27 +0200 Subject: [PATCH 35/52] fix: always show project url, if available --- launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index fd9adc247..a2e18d19a 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -218,7 +218,7 @@ void ModrinthPage::updateUI() { QString text = ""; - if (current.extra.sourceUrl.isEmpty()) + if (current.extra.projectUrl.isEmpty()) text = current.name; else text = "" + current.name + ""; From 7194bb1b8114a2ec96d3cb30a4fe3338f3962d4c Mon Sep 17 00:00:00 2001 From: flow Date: Sun, 15 May 2022 15:58:23 -0300 Subject: [PATCH 36/52] fix: validate whitelisted download urls --- launcher/InstanceImportTask.cpp | 2 +- .../modrinth/ModrinthPackManifest.cpp | 25 +++++++++++++++++-- .../modrinth/ModrinthPackManifest.h | 2 ++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/launcher/InstanceImportTask.cpp b/launcher/InstanceImportTask.cpp index f02aed910..3ca82923e 100644 --- a/launcher/InstanceImportTask.cpp +++ b/launcher/InstanceImportTask.cpp @@ -545,7 +545,7 @@ void InstanceImportTask::processModrinth() { file.hashAlgorithm = hashAlgorithm; // Do not use requireUrl, which uses StrictMode, instead use QUrl's default TolerantMode (as Modrinth seems to incorrectly handle spaces) file.download = Json::requireString(Json::ensureArray(obj, "downloads").first(), "Download URL for " + file.path); - if (!file.download.isValid()) + if (!file.download.isValid() || !Modrinth::validadeDownloadUrl(file.download)) { throw JSONValidationError("Download URL for " + file.path + " is not a correctly formatted URL"); } diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp index facf5ddbd..947ac1823 100644 --- a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp @@ -93,6 +93,23 @@ void loadIndexedVersions(Modpack& pack, QJsonDocument& doc) pack.versionsLoaded = true; } +auto validadeDownloadUrl(QUrl url) -> bool +{ + auto domain = url.host(); + if(domain == "cdn.modrinth.com") + return true; + if(domain == "edge.forgecdn.net") + return true; + if(domain == "media.forgecdn.net") + return true; + if(domain == "github.com") + return true; + if(domain == "raw.githubusercontent.com") + return true; + + return false; +} + auto loadIndexedVersion(QJsonObject &obj) -> ModpackVersion { ModpackVersion file; @@ -107,7 +124,6 @@ auto loadIndexedVersion(QJsonObject &obj) -> ModpackVersion auto files = Json::requireArray(obj, "files"); - qWarning() << files; for (auto file_iter : files) { File indexed_file; @@ -121,7 +137,12 @@ auto loadIndexedVersion(QJsonObject &obj) -> ModpackVersion continue; } - file.download_url = Json::requireString(parent, "url"); + auto url = Json::requireString(parent, "url"); + + if(!validadeDownloadUrl(url)) + continue; + + file.download_url = url; if(is_primary) break; } diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.h b/launcher/modplatform/modrinth/ModrinthPackManifest.h index 55ad40d94..4db4a75d8 100644 --- a/launcher/modplatform/modrinth/ModrinthPackManifest.h +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.h @@ -99,6 +99,8 @@ void loadIndexedInfo(Modpack&, QJsonObject&); void loadIndexedVersions(Modpack&, QJsonDocument&); auto loadIndexedVersion(QJsonObject&) -> ModpackVersion; +auto validadeDownloadUrl(QUrl) -> bool; + } Q_DECLARE_METATYPE(Modrinth::Modpack) From 80908efdcb1f8d4deb35c0df65651cc96fae71ac Mon Sep 17 00:00:00 2001 From: Kenneth Chew Date: Sun, 15 May 2022 16:33:52 -0400 Subject: [PATCH 37/52] Fix indentation of macOS resources --- cmake/MacOSXBundleInfo.plist.in | 8 ++++---- program_info/App.entitlements | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cmake/MacOSXBundleInfo.plist.in b/cmake/MacOSXBundleInfo.plist.in index 0e3a43c67..9e663d312 100644 --- a/cmake/MacOSXBundleInfo.plist.in +++ b/cmake/MacOSXBundleInfo.plist.in @@ -2,10 +2,10 @@ - NSCameraUsageDescription - A Minecraft mod wants to access your camera. - NSMicrophoneUsageDescription - A Minecraft mod wants to access your microphone. + NSCameraUsageDescription + A Minecraft mod wants to access your camera. + NSMicrophoneUsageDescription + A Minecraft mod wants to access your microphone. NSPrincipalClass NSApplication NSHighResolutionCapable diff --git a/program_info/App.entitlements b/program_info/App.entitlements index 1850b9900..032308a18 100644 --- a/program_info/App.entitlements +++ b/program_info/App.entitlements @@ -2,11 +2,11 @@ - com.apple.security.cs.disable-library-validation - - com.apple.security.device.audio-input - - com.apple.security.device.camera - + com.apple.security.cs.disable-library-validation + + com.apple.security.device.audio-input + + com.apple.security.device.camera + From 7f305aad1b80e28d15dda71ba62bec2e8eb9dac3 Mon Sep 17 00:00:00 2001 From: Kenneth Chew Date: Sun, 15 May 2022 16:34:53 -0400 Subject: [PATCH 38/52] Add Allow DYLD Environment Variables Entitlement to macOS build This allows the Steam overlay to be injected into Minecraft. --- program_info/App.entitlements | 2 ++ 1 file changed, 2 insertions(+) diff --git a/program_info/App.entitlements b/program_info/App.entitlements index 032308a18..b46e8ff2a 100644 --- a/program_info/App.entitlements +++ b/program_info/App.entitlements @@ -4,6 +4,8 @@ com.apple.security.cs.disable-library-validation + com.apple.security.cs.allow-dyld-environment-variables + com.apple.security.device.audio-input com.apple.security.device.camera From a110d445ac48a2493bafef8c4ce59a234d0e648e Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Sun, 15 May 2022 23:00:09 +0200 Subject: [PATCH 39/52] feat: support quilt.mod.json metadata --- launcher/minecraft/mod/LocalModParseTask.cpp | 53 +++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/launcher/minecraft/mod/LocalModParseTask.cpp b/launcher/minecraft/mod/LocalModParseTask.cpp index f01da8aee..699cf7eeb 100644 --- a/launcher/minecraft/mod/LocalModParseTask.cpp +++ b/launcher/minecraft/mod/LocalModParseTask.cpp @@ -8,6 +8,7 @@ #include #include +#include "Json.h" #include "settings/INIFile.h" #include "FileSystem.h" @@ -262,6 +263,43 @@ std::shared_ptr ReadFabricModInfo(QByteArray contents) return details; } +// https://github.com/QuiltMC/rfcs/blob/master/specification/0002-quilt.mod.json.md#the-schema_version-field +std::shared_ptr ReadQuiltModInfo(QByteArray contents) +{ + QJsonParseError jsonError; + QJsonDocument jsonDoc = QJsonDocument::fromJson(contents, &jsonError); + auto object = Json::requireObject(jsonDoc, "quilt.mod.json"); + auto schemaVersion = Json::ensureInteger(object.value("schema_version"), 0, "Quilt schema_version"); + + std::shared_ptr details = std::make_shared(); + + if (schemaVersion == 1) + { + auto modInfo = Json::requireObject(object.value("quilt_loader"), "Quilt mod info"); + + details->mod_id = Json::requireString(modInfo.value("id"), "Mod ID"); + details->version = Json::requireString(modInfo.value("version"), "Mod version"); + + auto modMetadata = Json::ensureObject(modInfo.value("metadata")); + + details->name = Json::ensureString(modMetadata.value("name"), details->mod_id); + details->description = Json::ensureString(modMetadata.value("description")); + + auto modContributors = Json::ensureObject(modMetadata.value("contributors")); + + // We don't really care about the role of a contributor here + details->authors += modContributors.keys(); + + auto modContact = Json::ensureObject(modMetadata.value("contact")); + + if (modContact.contains("homepage")) + { + details->homeurl = Json::requireString(modContact.value("homepage")); + } + } + return details; +} + std::shared_ptr ReadForgeInfo(QByteArray contents) { std::shared_ptr details = std::make_shared(); @@ -391,7 +429,7 @@ void LocalModParseTask::processAsZip() zip.close(); return; } - else if (zip.setCurrentFile("fabric.mod.json")) // TODO: Support quilt.mod.json + else if (zip.setCurrentFile("fabric.mod.json")) { if (!file.open(QIODevice::ReadOnly)) { @@ -404,6 +442,19 @@ void LocalModParseTask::processAsZip() zip.close(); return; } + else if (zip.setCurrentFile("quilt.mod.json")) + { + if (!file.open(QIODevice::ReadOnly)) + { + zip.close(); + return; + } + + m_result->details = ReadQuiltModInfo(file.readAll()); + file.close(); + zip.close(); + return; + } else if (zip.setCurrentFile("forgeversion.properties")) { if (!file.open(QIODevice::ReadOnly)) From 66ce5a4a2d38803bf667d7326f2ffb1bc06bff99 Mon Sep 17 00:00:00 2001 From: flow Date: Sun, 15 May 2022 20:45:27 -0300 Subject: [PATCH 40/52] fix: pack sorting and other search parameters --- .../modplatform/modrinth/ModrinthModel.cpp | 24 ++++++++++++++----- .../modplatform/modrinth/ModrinthModel.h | 2 +- .../modplatform/modrinth/ModrinthPage.cpp | 9 ++++--- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index 50974e13f..6786b0dad 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -105,11 +105,16 @@ void ModpackListModel::performPaginatedSearch() { // TODO: Move to standalone API NetJob* netJob = new NetJob("Modrinth::SearchModpack", APPLICATION->network()); - auto searchAllUrl = QString( - "%1/search?" + auto searchAllUrl = QString(BuildConfig.MODRINTH_STAGING_URL + + "/search?" + "offset=%1&" + "limit=20&" "query=%2&" + "index=%3&" "facets=[[\"project_type:modpack\"]]") - .arg(BuildConfig.MODRINTH_STAGING_URL, currentSearchTerm); + .arg(nextSearchOffset) + .arg(currentSearchTerm) + .arg(currentSort); netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchAllUrl), &m_all_response)); @@ -148,14 +153,21 @@ void ModpackListModel::refresh() performPaginatedSearch(); } +static std::array sorts {"relevance", "downloads", "follows", "newest", "updated"}; + void ModpackListModel::searchWithTerm(const QString& term, const int sort) { - if (currentSearchTerm == term && currentSearchTerm.isNull() == term.isNull() && currentSort == sort) { + if(sort > 5 || sort < 0) + return; + + auto sort_str = sorts.at(sort); + + if (currentSearchTerm == term && currentSearchTerm.isNull() == term.isNull() && currentSort == sort_str) { return; } currentSearchTerm = term; - currentSort = sort; + currentSort = sort_str; refresh(); } @@ -255,7 +267,7 @@ void ModpackListModel::searchRequestFailed(QString reason) { if (!jobPtr->first()->m_reply) { // Network error - QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load mods.")); + QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load modpacks.")); } else if (jobPtr->first()->m_reply && jobPtr->first()->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 409) { // 409 Gone, notify user to update QMessageBox::critical(nullptr, tr("Error"), diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h index e61eae7cf..bffea54da 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h @@ -104,7 +104,7 @@ class ModpackListModel : public QAbstractListModel { QStringList m_loadingLogos; QString currentSearchTerm; - int currentSort = 0; + QString currentSort; int nextSearchOffset = 0; enum SearchState { None, CanPossiblyFetchMore, ResetRequested, Finished } searchState = None; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index a2e18d19a..ceddcfb51 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -61,12 +61,11 @@ ModrinthPage::ModrinthPage(NewInstanceDialog* dialog, QWidget* parent) : QWidget ui->versionSelectionBox->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); ui->versionSelectionBox->view()->parentWidget()->setMaximumHeight(300); - ui->sortByBox->addItem(tr("Sort by Featured")); - ui->sortByBox->addItem(tr("Sort by Popularity")); - ui->sortByBox->addItem(tr("Sort by Last Updated")); - ui->sortByBox->addItem(tr("Sort by Name")); - ui->sortByBox->addItem(tr("Sort by Author")); + ui->sortByBox->addItem(tr("Sort by Relevance")); ui->sortByBox->addItem(tr("Sort by Total Downloads")); + ui->sortByBox->addItem(tr("Sort by Follows")); + ui->sortByBox->addItem(tr("Sort by Newest")); + ui->sortByBox->addItem(tr("Sort by Last Updated")); connect(ui->sortByBox, SIGNAL(currentIndexChanged(int)), this, SLOT(triggerSearch())); connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ModrinthPage::onSelectionChanged); From ec3c882a44624f18b088322b28efe7153e7db083 Mon Sep 17 00:00:00 2001 From: flow Date: Sun, 15 May 2022 20:52:57 -0300 Subject: [PATCH 41/52] change: add alpha note to modrinth page --- .../ui/pages/modplatform/modrinth/ModrinthPage.ui | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui index 8de53a693..90e8dba3c 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui @@ -11,6 +11,21 @@ + + + + + true + + + + Note: Modrinth modpacks is still in alpha phase. Some things may be rough on the edges, or not working at all! Use it with caution. + + + Qt::AlignCenter + + + From e7bb3b277647a21b85cb01ee90bf640e22d01552 Mon Sep 17 00:00:00 2001 From: flow Date: Sun, 15 May 2022 20:59:07 -0300 Subject: [PATCH 42/52] fix: macos compilation i forgor macos is cringe with static arrays :skull: edit: WHY DONT MAC LET ME USE STD::ARRAY ;----; --- .../modplatform/modrinth/ModrinthModel.cpp | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index 6786b0dad..2504b294b 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -153,14 +153,31 @@ void ModpackListModel::refresh() performPaginatedSearch(); } -static std::array sorts {"relevance", "downloads", "follows", "newest", "updated"}; +static auto sortFromIndex(int index) -> QString +{ + switch(index){ + default: + case 1: + return "relevance"; + case 2: + return "downloads"; + case 3: + return "follows"; + case 4: + return "newest"; + case 5: + return "updated"; + } + + return {}; +} void ModpackListModel::searchWithTerm(const QString& term, const int sort) { if(sort > 5 || sort < 0) return; - auto sort_str = sorts.at(sort); + auto sort_str = sortFromIndex(sort); if (currentSearchTerm == term && currentSearchTerm.isNull() == term.isNull() && currentSort == sort_str) { return; From e92b7bd25e9eccf293ff97652364def63a674df2 Mon Sep 17 00:00:00 2001 From: flow Date: Sun, 15 May 2022 21:50:42 -0300 Subject: [PATCH 43/52] change: switch to modrinth production servers --- launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp | 2 +- launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index 2504b294b..0cf53659b 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -105,7 +105,7 @@ void ModpackListModel::performPaginatedSearch() { // TODO: Move to standalone API NetJob* netJob = new NetJob("Modrinth::SearchModpack", APPLICATION->network()); - auto searchAllUrl = QString(BuildConfig.MODRINTH_STAGING_URL + + auto searchAllUrl = QString(BuildConfig.MODRINTH_PROD_URL + "/search?" "offset=%1&" "limit=20&" diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index ceddcfb51..fadad9df7 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -123,7 +123,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second) QString id = current.id; - netJob->addNetAction(Net::Download::makeByteArray(QString("%1/project/%2").arg(BuildConfig.MODRINTH_STAGING_URL, id), response)); + netJob->addNetAction(Net::Download::makeByteArray(QString("%1/project/%2").arg(BuildConfig.MODRINTH_PROD_URL, id), response)); QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id] { if (id != current.id) { @@ -168,7 +168,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second) QString id = current.id; netJob->addNetAction( - Net::Download::makeByteArray(QString("%1/project/%2/version").arg(BuildConfig.MODRINTH_STAGING_URL, id), response)); + Net::Download::makeByteArray(QString("%1/project/%2/version").arg(BuildConfig.MODRINTH_PROD_URL, id), response)); QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id] { if (id != current.id) { From 62e099ace5db8e04bba684e6c2517291dcce3578 Mon Sep 17 00:00:00 2001 From: flow Date: Sun, 15 May 2022 22:16:52 -0300 Subject: [PATCH 44/52] feat: better handling of optional mods This disables the optional mods by default and tell the user about it. Pretty hackish, but a better solution would involve the modrinth metadata to have the mod names... Also sorry for the diffs, my clangd went rogue x.x --- launcher/InstanceImportTask.cpp | 153 +++++++++--------- launcher/InstanceImportTask.h | 5 +- .../modplatform/modrinth/ModrinthPage.cpp | 2 +- 3 files changed, 80 insertions(+), 80 deletions(-) diff --git a/launcher/InstanceImportTask.cpp b/launcher/InstanceImportTask.cpp index 3ca82923e..64f2dd021 100644 --- a/launcher/InstanceImportTask.cpp +++ b/launcher/InstanceImportTask.cpp @@ -35,35 +35,38 @@ */ #include "InstanceImportTask.h" +#include +#include "Application.h" #include "BaseInstance.h" #include "FileSystem.h" -#include "Application.h" #include "MMCZip.h" #include "NullInstance.h" -#include "settings/INISettingsObject.h" #include "icons/IconUtils.h" -#include +#include "settings/INISettingsObject.h" // FIXME: this does not belong here, it's Minecraft/Flame specific +#include +#include "Json.h" #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" #include "modplatform/flame/FileResolvingTask.h" #include "modplatform/flame/PackManifest.h" -#include "Json.h" -#include #include "modplatform/modrinth/ModrinthPackManifest.h" #include "modplatform/technic/TechnicPackProcessor.h" -#include "icons/IconList.h" #include "Application.h" +#include "icons/IconList.h" #include "net/ChecksumValidator.h" +#include "ui/dialogs/CustomMessageBox.h" + #include #include -InstanceImportTask::InstanceImportTask(const QUrl sourceUrl) +InstanceImportTask::InstanceImportTask(const QUrl sourceUrl, QWidget* parent) { m_sourceUrl = sourceUrl; + m_parent = parent; } bool InstanceImportTask::abort() @@ -476,124 +479,118 @@ void InstanceImportTask::processMultiMC() instance.setName(m_instName); // if the icon was specified by user, use that. otherwise pull icon from the pack - if (m_instIcon != "default") - { + if (m_instIcon != "default") { instance.setIconKey(m_instIcon); - } - else - { + } else { m_instIcon = instance.iconKey(); auto importIconPath = IconUtils::findBestIconIn(instance.instanceRoot(), m_instIcon); - if (!importIconPath.isNull() && QFile::exists(importIconPath)) - { + if (!importIconPath.isNull() && QFile::exists(importIconPath)) { // import icon auto iconList = APPLICATION->icons(); - if (iconList->iconFileExists(m_instIcon)) - { + if (iconList->iconFileExists(m_instIcon)) { iconList->deleteIcon(m_instIcon); } - iconList->installIcons({importIconPath}); + iconList->installIcons({ importIconPath }); } } emitSucceeded(); } -void InstanceImportTask::processModrinth() { +void InstanceImportTask::processModrinth() +{ std::vector files; QString minecraftVersion, fabricVersion, quiltVersion, forgeVersion; - try - { + try { QString indexPath = FS::PathCombine(m_stagingPath, "modrinth.index.json"); auto doc = Json::requireDocument(indexPath); auto obj = Json::requireObject(doc, "modrinth.index.json"); int formatVersion = Json::requireInteger(obj, "formatVersion", "modrinth.index.json"); - if (formatVersion == 1) - { + if (formatVersion == 1) { auto game = Json::requireString(obj, "game", "modrinth.index.json"); - if (game != "minecraft") - { + if (game != "minecraft") { throw JSONValidationError("Unknown game: " + game); } auto jsonFiles = Json::requireIsArrayOf(obj, "files", "modrinth.index.json"); - std::transform(jsonFiles.begin(), jsonFiles.end(), std::back_inserter(files), [](const QJsonObject& obj) - { - Modrinth::File file; - file.path = Json::requireString(obj, "path"); - QString supported = Json::ensureString(Json::ensureObject(obj, "env")); - QJsonObject hashes = Json::requireObject(obj, "hashes"); - QString hash; - QCryptographicHash::Algorithm hashAlgorithm; - hash = Json::ensureString(hashes, "sha1"); - hashAlgorithm = QCryptographicHash::Sha1; - if (hash.isEmpty()) - { - hash = Json::ensureString(hashes, "sha512"); - hashAlgorithm = QCryptographicHash::Sha512; - if (hash.isEmpty()) - { - hash = Json::ensureString(hashes, "sha256"); - hashAlgorithm = QCryptographicHash::Sha256; - if (hash.isEmpty()) - { - throw JSONValidationError("No hash found for: " + file.path); - } + bool had_optional = false; + for (auto& obj : jsonFiles) { + Modrinth::File file; + file.path = Json::requireString(obj, "path"); + + auto env = Json::ensureObject(obj, "env"); + QString support = Json::ensureString(env, "client", "unsupported"); + if (support == "unsupported") { + continue; + } else if (support == "optional") { + // TODO: Make a review dialog for choosing which ones the user wants! + if (!had_optional) { + had_optional = true; + auto info = CustomMessageBox::selectable( + m_parent, tr("Optional mod detected!"), + tr("One or more mods from this modpack are optional. They will be downloaded, but disabled by default!"), QMessageBox::Information); + info->exec(); + } + + if (file.path.endsWith(".jar")) + file.path += ".disabled"; + } + + QJsonObject hashes = Json::requireObject(obj, "hashes"); + QString hash; + QCryptographicHash::Algorithm hashAlgorithm; + hash = Json::ensureString(hashes, "sha1"); + hashAlgorithm = QCryptographicHash::Sha1; + if (hash.isEmpty()) { + hash = Json::ensureString(hashes, "sha512"); + hashAlgorithm = QCryptographicHash::Sha512; + if (hash.isEmpty()) { + hash = Json::ensureString(hashes, "sha256"); + hashAlgorithm = QCryptographicHash::Sha256; + if (hash.isEmpty()) { + throw JSONValidationError("No hash found for: " + file.path); } } - file.hash = QByteArray::fromHex(hash.toLatin1()); - file.hashAlgorithm = hashAlgorithm; - // Do not use requireUrl, which uses StrictMode, instead use QUrl's default TolerantMode (as Modrinth seems to incorrectly handle spaces) - file.download = Json::requireString(Json::ensureArray(obj, "downloads").first(), "Download URL for " + file.path); - if (!file.download.isValid() || !Modrinth::validadeDownloadUrl(file.download)) - { - throw JSONValidationError("Download URL for " + file.path + " is not a correctly formatted URL"); - } - return file; - }); + } + file.hash = QByteArray::fromHex(hash.toLatin1()); + file.hashAlgorithm = hashAlgorithm; + // Do not use requireUrl, which uses StrictMode, instead use QUrl's default TolerantMode (as Modrinth seems to incorrectly + // handle spaces) + file.download = Json::requireString(Json::ensureArray(obj, "downloads").first(), "Download URL for " + file.path); + if (!file.download.isValid() || !Modrinth::validadeDownloadUrl(file.download)) { + throw JSONValidationError("Download URL for " + file.path + " is not a correctly formatted URL"); + } + files.push_back(file); + } auto dependencies = Json::requireObject(obj, "dependencies", "modrinth.index.json"); - for (auto it = dependencies.begin(), end = dependencies.end(); it != end; ++it) - { + for (auto it = dependencies.begin(), end = dependencies.end(); it != end; ++it) { QString name = it.key(); - if (name == "minecraft") - { + if (name == "minecraft") { if (!minecraftVersion.isEmpty()) throw JSONValidationError("Duplicate Minecraft version"); minecraftVersion = Json::requireString(*it, "Minecraft version"); - } - else if (name == "fabric-loader") - { + } else if (name == "fabric-loader") { if (!fabricVersion.isEmpty()) throw JSONValidationError("Duplicate Fabric Loader version"); fabricVersion = Json::requireString(*it, "Fabric Loader version"); - } - else if (name == "quilt-loader") - { + } else if (name == "quilt-loader") { if (!quiltVersion.isEmpty()) throw JSONValidationError("Duplicate Quilt Loader version"); quiltVersion = Json::requireString(*it, "Quilt Loader version"); - } - else if (name == "forge") - { + } else if (name == "forge") { if (!forgeVersion.isEmpty()) throw JSONValidationError("Duplicate Forge version"); forgeVersion = Json::requireString(*it, "Forge version"); - } - else - { + } else { throw JSONValidationError("Unknown dependency type: " + name); } } - } - else - { + } else { throw JSONValidationError(QStringLiteral("Unknown format version: %s").arg(formatVersion)); } QFile::remove(indexPath); - } - catch (const JSONValidationError &e) - { + } catch (const JSONValidationError& e) { emitFailed(tr("Could not understand pack index:\n") + e.cause()); return; } diff --git a/launcher/InstanceImportTask.h b/launcher/InstanceImportTask.h index 0dc6ba88b..5e4d32351 100644 --- a/launcher/InstanceImportTask.h +++ b/launcher/InstanceImportTask.h @@ -55,7 +55,7 @@ class InstanceImportTask : public InstanceTask { Q_OBJECT public: - explicit InstanceImportTask(const QUrl sourceUrl); + explicit InstanceImportTask(const QUrl sourceUrl, QWidget* parent = nullptr); bool canAbort() const override { return true; } bool abort() override; @@ -94,4 +94,7 @@ private: /* data */ Flame, Modrinth, } m_modpackType = ModpackType::Unknown; + + //FIXME: nuke + QWidget* m_parent; }; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index fadad9df7..f24d36518 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -251,7 +251,7 @@ void ModrinthPage::suggestCurrent() for (auto& ver : current.versions) { if (ver.id == selectedVersion) { - dialog->setSuggestedPack(current.name + " " + ver.version, new InstanceImportTask(ver.download_url)); + dialog->setSuggestedPack(current.name + " " + ver.version, new InstanceImportTask(ver.download_url, this)); auto iconName = current.iconName; m_model->getLogo(iconName, current.iconUrl.toString(), [this, iconName](QString logo) { dialog->setSuggestedIconFromFile(logo, iconName); }); From 82760f4b916ef122eabb644e8679f9ae76587e44 Mon Sep 17 00:00:00 2001 From: flow Date: Mon, 16 May 2022 10:50:46 -0300 Subject: [PATCH 45/52] fix: import modrinth packs with weird overrides structure Probably because of Packwiz limitations, or an space optimizer that did this :) --- launcher/MMCZip.cpp | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/launcher/MMCZip.cpp b/launcher/MMCZip.cpp index b92f17817..8591fcc06 100644 --- a/launcher/MMCZip.cpp +++ b/launcher/MMCZip.cpp @@ -297,20 +297,40 @@ nonstd::optional MMCZip::extractSubDir(QuaZip *zip, const QString & { continue; } + name.remove(0, subdir.size()); - QString absFilePath = directory.absoluteFilePath(name); + auto original_name = name; + + // Fix weird "folders with a single file get squashed" thing + QString path; + if(name.contains('/') && !name.endsWith('/')){ + path = name.section('/', 0, -2) + "/"; + FS::ensureFolderPathExists(path); + + name = name.split('/').last(); + } + + QString absFilePath; if(name.isEmpty()) { - absFilePath += "/"; + absFilePath = directory.absoluteFilePath(name) + "/"; } + else + { + absFilePath = directory.absoluteFilePath(path + name); + } + if (!JlCompress::extractFile(zip, "", absFilePath)) { - qWarning() << "Failed to extract file" << name << "to" << absFilePath; + qWarning() << "Failed to extract file" << original_name << "to" << absFilePath; JlCompress::removeFile(extracted); return nonstd::nullopt; } + extracted.append(absFilePath); - qDebug() << "Extracted file" << name; + QFile::setPermissions(absFilePath, QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser | QFileDevice::Permission::ExeUser); + + qDebug() << "Extracted file" << name << "to" << absFilePath; } while (zip->goToNextFile()); return extracted; } From a6d2c5e18131ab155ed482aeab548dabc2741d62 Mon Sep 17 00:00:00 2001 From: flow Date: Mon, 16 May 2022 12:59:32 -0300 Subject: [PATCH 46/52] fix: better hack for icons that cant be natively scaled to 48x48 --- launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index 0cf53659b..bb54bc20f 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -85,9 +85,10 @@ auto ModpackListModel::data(const QModelIndex& index, int role) const -> QVarian return pack.description; } else if (role == Qt::DecorationRole) { if (m_logoMap.contains(pack.iconName)) { - return (m_logoMap.value(pack.iconName) - .pixmap(48, 48) - .scaled(48, 48, Qt::IgnoreAspectRatio, Qt::TransformationMode::SmoothTransformation)); + auto icon = m_logoMap.value(pack.iconName); + auto icon_scaled = QIcon(icon.pixmap(48, 48).scaledToWidth(48)); + + return icon_scaled; } QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder"); ((ModpackListModel*)this)->requestLogo(pack.iconName, pack.iconUrl.toString()); From cd9e0e0cc0228ffa24466814a649abef43045745 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Mon, 16 May 2022 20:17:19 +0200 Subject: [PATCH 47/52] fix: use own metacache base for modrinth icons --- launcher/Application.cpp | 1 + launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 11109857f..afb33a502 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -819,6 +819,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) m_metacache->addBase("ModpacksCHPacks", QDir("cache/ModpacksCHPacks").absolutePath()); m_metacache->addBase("TechnicPacks", QDir("cache/TechnicPacks").absolutePath()); m_metacache->addBase("FlamePacks", QDir("cache/FlamePacks").absolutePath()); + m_metacache->addBase("ModrinthPacks", QDir("cache/ModrinthPacks").absolutePath()); m_metacache->addBase("root", QDir::currentPath()); m_metacache->addBase("translations", QDir("translations").absolutePath()); m_metacache->addBase("icons", QDir("cache/icons").absolutePath()); diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index bb54bc20f..bc1046ad5 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -208,7 +208,7 @@ void ModpackListModel::requestLogo(QString logo, QString url) } MetaEntryPtr entry = - APPLICATION->metacache()->resolveEntry(m_parent->metaEntryBase(), QString("logos/%1").arg(logo.section(".", 0, 0))); + APPLICATION->metacache()->resolveEntry("ModrinthPacks", QString("logos/%1").arg(logo.section(".", 0, 0))); auto job = new NetJob(QString("%1 Icon Download %2").arg(m_parent->debugName()).arg(logo), APPLICATION->network()); job->addNetAction(Net::Download::makeCached(QUrl(url), entry)); From 887246a66b5391b16d5b0d275ba77fe3a8bf540b Mon Sep 17 00:00:00 2001 From: flow Date: Mon, 16 May 2022 17:05:54 -0300 Subject: [PATCH 48/52] fix: typo and useless code --- launcher/InstanceImportTask.cpp | 27 +++++++++---------- .../modrinth/ModrinthPackManifest.cpp | 4 +-- .../modrinth/ModrinthPackManifest.h | 2 +- .../modplatform/modrinth/ModrinthPage.cpp | 6 ----- .../pages/modplatform/modrinth/ModrinthPage.h | 1 - 5 files changed, 15 insertions(+), 25 deletions(-) diff --git a/launcher/InstanceImportTask.cpp b/launcher/InstanceImportTask.cpp index 64f2dd021..8f68b95f0 100644 --- a/launcher/InstanceImportTask.cpp +++ b/launcher/InstanceImportTask.cpp @@ -554,10 +554,10 @@ void InstanceImportTask::processModrinth() } file.hash = QByteArray::fromHex(hash.toLatin1()); file.hashAlgorithm = hashAlgorithm; - // Do not use requireUrl, which uses StrictMode, instead use QUrl's default TolerantMode (as Modrinth seems to incorrectly - // handle spaces) + // Do not use requireUrl, which uses StrictMode, instead use QUrl's default TolerantMode + // (as Modrinth seems to incorrectly handle spaces) file.download = Json::requireString(Json::ensureArray(obj, "downloads").first(), "Download URL for " + file.path); - if (!file.download.isValid() || !Modrinth::validadeDownloadUrl(file.download)) { + if (!file.download.isValid() || !Modrinth::validateDownloadUrl(file.download)) { throw JSONValidationError("Download URL for " + file.path + " is not a correctly formatted URL"); } files.push_back(file); @@ -567,22 +567,18 @@ void InstanceImportTask::processModrinth() for (auto it = dependencies.begin(), end = dependencies.end(); it != end; ++it) { QString name = it.key(); if (name == "minecraft") { - if (!minecraftVersion.isEmpty()) - throw JSONValidationError("Duplicate Minecraft version"); minecraftVersion = Json::requireString(*it, "Minecraft version"); - } else if (name == "fabric-loader") { - if (!fabricVersion.isEmpty()) - throw JSONValidationError("Duplicate Fabric Loader version"); + } + else if (name == "fabric-loader") { fabricVersion = Json::requireString(*it, "Fabric Loader version"); - } else if (name == "quilt-loader") { - if (!quiltVersion.isEmpty()) - throw JSONValidationError("Duplicate Quilt Loader version"); + } + else if (name == "quilt-loader") { quiltVersion = Json::requireString(*it, "Quilt Loader version"); - } else if (name == "forge") { - if (!forgeVersion.isEmpty()) - throw JSONValidationError("Duplicate Forge version"); + } + else if (name == "forge") { forgeVersion = Json::requireString(*it, "Forge version"); - } else { + } + else { throw JSONValidationError("Unknown dependency type: " + name); } } @@ -594,6 +590,7 @@ void InstanceImportTask::processModrinth() emitFailed(tr("Could not understand pack index:\n") + e.cause()); return; } + QString overridePath = FS::PathCombine(m_stagingPath, "overrides"); if (QFile::exists(overridePath)) { QString mcPath = FS::PathCombine(m_stagingPath, ".minecraft"); diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp index 947ac1823..f1ad39cea 100644 --- a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp @@ -93,7 +93,7 @@ void loadIndexedVersions(Modpack& pack, QJsonDocument& doc) pack.versionsLoaded = true; } -auto validadeDownloadUrl(QUrl url) -> bool +auto validateDownloadUrl(QUrl url) -> bool { auto domain = url.host(); if(domain == "cdn.modrinth.com") @@ -139,7 +139,7 @@ auto loadIndexedVersion(QJsonObject &obj) -> ModpackVersion auto url = Json::requireString(parent, "url"); - if(!validadeDownloadUrl(url)) + if(!validateDownloadUrl(url)) continue; file.download_url = url; diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.h b/launcher/modplatform/modrinth/ModrinthPackManifest.h index 4db4a75d8..e5fc9a700 100644 --- a/launcher/modplatform/modrinth/ModrinthPackManifest.h +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.h @@ -99,7 +99,7 @@ void loadIndexedInfo(Modpack&, QJsonObject&); void loadIndexedVersions(Modpack&, QJsonDocument&); auto loadIndexedVersion(QJsonObject&) -> ModpackVersion; -auto validadeDownloadUrl(QUrl) -> bool; +auto validateDownloadUrl(QUrl) -> bool; } diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index f24d36518..9bd24b578 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -195,7 +195,6 @@ void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second) ui->versionSelectionBox->addItem(version.version, QVariant(version.id)); } - updateVersionsUI(); suggestCurrent(); }); QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { @@ -233,11 +232,6 @@ void ModrinthPage::updateUI() ui->packDescription->setHtml(text + current.description); } -void ModrinthPage::updateVersionsUI() -{ - // idk -} - void ModrinthPage::suggestCurrent() { if (!isOpened) { diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h index 9aa702f92..db5e1a3d6 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h @@ -71,7 +71,6 @@ class ModrinthPage : public QWidget, public BasePage { void suggestCurrent(); void updateUI(); - void updateVersionsUI(); void retranslate() override; void openedImpl() override; From 696a711e397440275a55f4dbe02947a78ab0b208 Mon Sep 17 00:00:00 2001 From: flow Date: Mon, 16 May 2022 19:10:31 -0300 Subject: [PATCH 49/52] fix: missed change to metacache entry lookup --- launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index bc1046ad5..701a20324 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -194,7 +194,7 @@ void ModpackListModel::getLogo(const QString& logo, const QString& logoUrl, Logo { if (m_logoMap.contains(logo)) { callback(APPLICATION->metacache() - ->resolveEntry(m_parent->metaEntryBase(), QString("logos/%1").arg(logo.section(".", 0, 0))) + ->resolveEntry("ModrinthPacks", QString("logos/%1").arg(logo.section(".", 0, 0))) ->getFullPath()); } else { requestLogo(logo, logoUrl); From 2e9d7f5c3d3cbc33ad95d830af4fdcab6eab6a06 Mon Sep 17 00:00:00 2001 From: flow Date: Mon, 16 May 2022 19:17:37 -0300 Subject: [PATCH 50/52] fix: mod skipping between pages and remove dead code --- .../modplatform/modrinth/ModrinthModel.cpp | 30 ++++--------------- .../modplatform/modrinth/ModrinthModel.h | 4 +-- 2 files changed, 8 insertions(+), 26 deletions(-) diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index 701a20324..7cacf37ad 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -109,11 +109,12 @@ void ModpackListModel::performPaginatedSearch() auto searchAllUrl = QString(BuildConfig.MODRINTH_PROD_URL + "/search?" "offset=%1&" - "limit=20&" - "query=%2&" - "index=%3&" + "limit=%2&" + "query=%3&" + "index=%4&" "facets=[[\"project_type:modpack\"]]") .arg(nextSearchOffset) + .arg(m_modpacks_per_page) .arg(currentSearchTerm) .arg(currentSort); @@ -269,10 +270,10 @@ void ModpackListModel::searchRequestFinished(QJsonDocument& doc_all) } } - if (packs_all.size() < 25) { + if (packs_all.size() < m_modpacks_per_page) { searchState = Finished; } else { - nextSearchOffset += 25; + nextSearchOffset += m_modpacks_per_page; searchState = CanPossiblyFetchMore; } @@ -308,25 +309,6 @@ void ModpackListModel::searchRequestFailed(QString reason) } } -void ModpackListModel::versionRequestSucceeded(QJsonDocument doc, QString id) -{ - auto& current = m_parent->getCurrent(); - if (id != current.id) { - return; - } - - auto arr = doc.isObject() ? Json::ensureArray(doc.object(), "data") : doc.array(); - - try { - // loadIndexedPackVersions(current, arr); - } catch (const JSONValidationError& e) { - qDebug() << doc; - qWarning() << "Error while reading " << debugName() << " mod version: " << e.cause(); - } - - // m_parent->updateModVersions(); -} - } // namespace Modrinth /******** Helpers ********/ diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h index bffea54da..14aa67473 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h @@ -79,8 +79,6 @@ class ModpackListModel : public QAbstractListModel { void searchRequestFinished(QJsonDocument& doc_all); void searchRequestFailed(QString reason); - void versionRequestSucceeded(QJsonDocument doc, QString addonId); - protected slots: void logoFailed(QString logo); @@ -112,5 +110,7 @@ class ModpackListModel : public QAbstractListModel { QByteArray m_all_response; QByteArray m_specific_response; + + int m_modpacks_per_page = 20; }; } // namespace ModPlatform From ddc3b5eb0bbd17edd60d96f5094d65dbdb922765 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Tue, 17 May 2022 15:14:53 +0200 Subject: [PATCH 51/52] Update launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui Co-authored-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com> --- launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui index 90e8dba3c..4fb59cdf0 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui @@ -19,7 +19,7 @@ - Note: Modrinth modpacks is still in alpha phase. Some things may be rough on the edges, or not working at all! Use it with caution. + Note: Modrinth modpacks are still in alpha phase. Some things may be rough on the edges, or not working at all! Use it with caution. Qt::AlignCenter From edbd90a4e671486bdc1ca6f8f051445ae473fdcc Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Tue, 17 May 2022 15:17:20 +0200 Subject: [PATCH 52/52] fix: update links for Quilt metadata format --- launcher/minecraft/mod/LocalModParseTask.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/launcher/minecraft/mod/LocalModParseTask.cpp b/launcher/minecraft/mod/LocalModParseTask.cpp index 699cf7eeb..631c3abbc 100644 --- a/launcher/minecraft/mod/LocalModParseTask.cpp +++ b/launcher/minecraft/mod/LocalModParseTask.cpp @@ -263,7 +263,7 @@ std::shared_ptr ReadFabricModInfo(QByteArray contents) return details; } -// https://github.com/QuiltMC/rfcs/blob/master/specification/0002-quilt.mod.json.md#the-schema_version-field +// https://github.com/QuiltMC/rfcs/blob/master/specification/0002-quilt.mod.json.md std::shared_ptr ReadQuiltModInfo(QByteArray contents) { QJsonParseError jsonError; @@ -273,6 +273,7 @@ std::shared_ptr ReadQuiltModInfo(QByteArray contents) std::shared_ptr details = std::make_shared(); + // https://github.com/QuiltMC/rfcs/blob/be6ba280d785395fefa90a43db48e5bfc1d15eb4/specification/0002-quilt.mod.json.md if (schemaVersion == 1) { auto modInfo = Json::requireObject(object.value("quilt_loader"), "Quilt mod info");