7474import java .util .Map ;
7575import java .util .Objects ;
7676import java .util .Set ;
77+ import java .util .StringTokenizer ;
7778import java .util .concurrent .CompletableFuture ;
7879import java .util .concurrent .ConcurrentHashMap ;
7980import java .util .concurrent .ExecutorService ;
@@ -119,6 +120,7 @@ public class DependencyLoaderImpl {
119120 private static final AtomicBoolean needReboot = new AtomicBoolean (false );
120121 private static final Set <String > downloadedMods = new ConcurrentSet <>();
121122 private static final Set <String > downloadFailed = new ConcurrentSet <>();
123+ private static final AtomicBoolean anyDownloadFailCausedByGradle = new AtomicBoolean (false );
122124
123125 private static void ensureExists (Path directory ) {
124126 if (!Files .exists (directory )) {
@@ -498,6 +500,72 @@ public ModDependencyDownloaded(String message) {
498500 .flatMap (i -> i ));
499501 }
500502
503+ private static final String [] MAVEN_PREFIXES = new String []{
504+ "modules-2/files-2.1/" ,
505+ ".m2/repository/"
506+ };
507+ private static void detectLocalDep (String str ) {
508+ str = str .replace ('\\' , '/' );
509+ if (detectLocalDepSingle (str , "modules-2/files-2.1/" , true ))
510+ return ;
511+ detectLocalDepSingle (str , ".m2/repository/" , false );
512+ }
513+
514+ private static boolean detectLocalDepSingle (String str , String prefix , boolean extraPathSegment ) {
515+ val idx = str .indexOf (prefix );
516+ if (idx == -1 ) {
517+ return false ;
518+ }
519+ val dep = str .substring (idx + prefix .length ());
520+ val tok = new StringTokenizer (dep , "/" );
521+ if (!tok .hasMoreTokens ())
522+ return true ;
523+ val group = tok .nextToken ();
524+ if (!tok .hasMoreTokens ())
525+ return true ;
526+ val artifact = tok .nextToken ();
527+ if (!tok .hasMoreTokens ())
528+ return true ;
529+ val version = tok .nextToken ();
530+ if (extraPathSegment ) {
531+ if (!tok .hasMoreTokens ())
532+ return true ;
533+ tok .nextToken ();
534+ }
535+ if (!tok .hasMoreTokens ())
536+ return true ;
537+ val file = tok .nextToken ();
538+
539+ val filePrefix = artifact + "-" + version ;
540+
541+ if (!file .contains (filePrefix ))
542+ return true ;
543+
544+ val fileSuffix = file .substring (filePrefix .length ());
545+
546+ if (!fileSuffix .endsWith (".jar" ))
547+ return true ;
548+
549+ String classifier = null ;
550+ if (fileSuffix .startsWith ("-" )) {
551+ classifier = fileSuffix .substring (1 , fileSuffix .length () - 4 );
552+ }
553+
554+ val id = group + ":" + artifact + ":" + classifier ;
555+ val versionParsed = Version .parse (version );
556+
557+ LOG .warn ("Found dev dependency pulled in via Gradle {}:{}:{}{}" , group , artifact , version , classifier == null ? "" : ":" + classifier );
558+ if (!loadedLibraries .containsKey (id )) {
559+ loadedLibraries .put (id , versionParsed );
560+ } else {
561+ LOG .warn ("Duplicate gradle dependency {}:{}:{}{}" , group , artifact , version , classifier == null ? "" : ":" + classifier );
562+ }
563+ if (!loadedLibraryMods .containsKey (id )) {
564+ loadedLibraryMods .put (id , "Gradle" );
565+ }
566+ return true ;
567+ }
568+
501569 private static @ Nullable Set <ScopedSidedTask > scanDeps (Stream <URL > candidatesUnfiltered ) {
502570 long start = System .currentTimeMillis ();
503571 val urlsWithoutDeps = new HashSet <String >();
@@ -509,10 +577,16 @@ public ModDependencyDownloaded(String message) {
509577 LOG .error ("Could not read dependency scanner cache" , e );
510578 }
511579 }
512- val candidates = candidatesUnfiltered
513- .filter (Objects ::nonNull )
514- .filter ((url ) -> !urlsWithoutDeps .contains (url .toString ()))
515- .collect (Collectors .toList ());
580+ val candidates = new ArrayList <URL >();
581+ candidatesUnfiltered .forEach (candidate -> {
582+ if (candidate == null )
583+ return ;
584+ val str = candidate .toString ();
585+ detectLocalDep (str );
586+ if (urlsWithoutDeps .contains (str ))
587+ return ;
588+ candidates .add (candidate );
589+ });
516590 val urls = new ArrayList <URL >();
517591 val jijURLs = new ArrayList <URL >();
518592 for (val candidate : candidates ) {
@@ -832,14 +906,27 @@ static ScopeSide current() {
832906 if (downloadFailed .isEmpty ()) {
833907 JOptionPane .showMessageDialog (null , "FP DepLoader has encountered an error while trying to download libraries.\n See the log for more details." , "Dependency download error" , JOptionPane .ERROR_MESSAGE );
834908 } else {
835- var msgBuilder = new StringBuilder ("FP DepLoader has encountered an error while trying to download the following libraries:" );
909+ var msgBuilder = new StringBuilder ("FP DepLoader has encountered an error while trying to download the following libraries:\n " );
836910 for (val f : downloadFailed ) {
837911 msgBuilder .append ('\n' ).append (f );
838912 }
839913 msgBuilder .append ("\n \n See the log for more details." );
840914 JOptionPane .showMessageDialog (null , msgBuilder .toString (), "Dependency download error" , JOptionPane .ERROR_MESSAGE );
841915 }
842916 throw err ;
917+ } else if (!downloadFailed .isEmpty ()) {
918+ var msgBuilder = new StringBuilder ("FP DepLoader has encountered an error while trying to download the following libraries:\n " );
919+ for (val f : downloadFailed ) {
920+ msgBuilder .append ('\n' ).append (f );
921+ }
922+ msgBuilder .append ("\n \n See the log for more details. Click OK to continue anyway (may cause issues!).\n \n " );
923+ if (anyDownloadFailCausedByGradle .get () && scopeSide .scope == DependencyScope .DEV ) {
924+ msgBuilder .append ("One or more of these dependency version mismatches were caused by a gradle dependency being too old compared to a deploaded dependency!\n "
925+ + "Try manually depending on the newer versions of the required libraries via runtimeOnly(...)!" );
926+ }
927+ if (JOptionPane .showConfirmDialog (null , msgBuilder .toString (), "Dependency download error" , JOptionPane .OK_CANCEL_OPTION , JOptionPane .ERROR_MESSAGE ) != JOptionPane .OK_OPTION ) {
928+ throw new IllegalStateException ("User terminated game after dependency load error" );
929+ }
843930 }
844931 if (res .isEmpty ()) {
845932 return null ;
@@ -1040,16 +1127,22 @@ private void alreadyLoaded(boolean fromModId) {
10401127 for (int i = 0 ; i < 4 ; i ++) {
10411128 LOG .fatal ("ALERT VVVVVVVVVVVV ALERT" );
10421129 }
1130+ val loader = fromModId ? loadedModIdMods .get (modId ) : loadedLibraryMods .get (artifact );
1131+ val sfx = suffix != null ? ":" + suffix : "" ;
10431132 LOG .fatal ("Library {}:{}{} already loaded with version {}, "
10441133 + "but a version in the range {} was requested! Thing may go horribly wrong! "
10451134 + "Requested by mod: {}, previously loaded by mod: {}" ,
10461135 groupId ,
10471136 artifactId ,
1048- suffix != null ? ":" + suffix : "" ,
1137+ sfx ,
10491138 currentVer ,
10501139 rangeString ,
10511140 loadingModId ,
1052- fromModId ? loadedModIdMods .get (modId ) : loadedLibraryMods .get (artifact ));
1141+ loader );
1142+ downloadFailed .add (String .format ("%s:%s:%s%s already loaded by: %s, but mod %s requested version %s!" , groupId , artifactId , currentVer , sfx , loader , loadingModId , rangeString ));
1143+ if ("Gradle" .equals (loader )) {
1144+ anyDownloadFailCausedByGradle .set (true );
1145+ }
10531146 for (int i = 0 ; i < 4 ; i ++) {
10541147 LOG .fatal ("ALERT ^^^^^^^^^^^^ ALERT" );
10551148 }
0 commit comments