2018-04-07 15:48:43 +00:00
/ *
* Minecraft Forge
2019-02-10 22:57:03 +00:00
* Copyright ( c ) 2016 - 2019 .
2018-04-07 15:48:43 +00:00
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2 . 1
* of the License .
*
* This library 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
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
* /
package net.minecraftforge.fml.loading ;
2019-01-01 21:50:04 +00:00
import cpw.mods.modlauncher.ServiceLoaderStreamUtils ;
2019-01-14 03:51:36 +00:00
import net.minecraftforge.forgespi.language.IModLanguageProvider ;
2018-10-04 15:31:08 +00:00
import net.minecraftforge.fml.loading.moddiscovery.ExplodedDirectoryLocator ;
2018-04-07 15:48:43 +00:00
import net.minecraftforge.fml.loading.moddiscovery.ModFile ;
2018-08-27 17:10:07 +00:00
import org.apache.logging.log4j.LogManager ;
import org.apache.logging.log4j.Logger ;
2018-10-04 02:47:07 +00:00
import org.apache.maven.artifact.versioning.ArtifactVersion ;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion ;
import org.apache.maven.artifact.versioning.VersionRange ;
2018-04-07 15:48:43 +00:00
2019-01-01 21:50:04 +00:00
import java.io.File ;
import java.net.URI ;
2018-12-31 21:33:54 +00:00
import java.net.URISyntaxException ;
import java.net.URL ;
2019-01-01 21:50:04 +00:00
import java.net.URLClassLoader ;
2018-12-31 21:33:54 +00:00
import java.nio.file.Files ;
2018-04-07 15:48:43 +00:00
import java.nio.file.Path ;
2018-12-31 21:33:54 +00:00
import java.nio.file.Paths ;
2018-10-04 15:31:08 +00:00
import java.util.* ;
2018-06-19 18:04:05 +00:00
import java.util.function.Consumer ;
2018-04-07 15:48:43 +00:00
import java.util.stream.Stream ;
2019-01-01 21:50:04 +00:00
import static cpw.mods.modlauncher.api.LamdbaExceptionUtils.rethrowFunction ;
2018-12-31 21:33:54 +00:00
import static net.minecraftforge.fml.loading.LogMarkers.CORE ;
2018-04-07 15:48:43 +00:00
public class LanguageLoadingProvider
{
2018-08-27 17:10:07 +00:00
private static final Logger LOGGER = LogManager . getLogger ( ) ;
2019-01-01 21:50:04 +00:00
private final LanguageClassLoader languageClassLoader ;
2018-04-07 15:48:43 +00:00
private final List < IModLanguageProvider > languageProviders = new ArrayList < > ( ) ;
private final ServiceLoader < IModLanguageProvider > serviceLoader ;
2018-06-06 15:37:56 +00:00
private final Map < String , ModLanguageWrapper > languageProviderMap = new HashMap < > ( ) ;
2018-04-07 15:48:43 +00:00
2018-06-19 18:04:05 +00:00
public void forEach ( final Consumer < IModLanguageProvider > consumer )
{
languageProviders . forEach ( consumer ) ;
}
2018-06-06 15:37:56 +00:00
private static class ModLanguageWrapper {
2019-01-01 21:50:04 +00:00
2018-06-06 15:37:56 +00:00
private final IModLanguageProvider modLanguageProvider ;
private final ArtifactVersion version ;
public ModLanguageWrapper ( IModLanguageProvider modLanguageProvider , ArtifactVersion version )
{
this . modLanguageProvider = modLanguageProvider ;
this . version = version ;
}
public ArtifactVersion getVersion ( )
{
return version ;
}
public IModLanguageProvider getModLanguageProvider ( )
{
return modLanguageProvider ;
}
2019-01-01 21:50:04 +00:00
}
private static class LanguageClassLoader extends URLClassLoader
{
public LanguageClassLoader ( ) {
super ( new URL [ 0 ] ) ;
}
@Override
public void addURL ( final URL url ) {
LOGGER . debug ( CORE , " Adding {} to languageloader classloader " , url ) ;
super . addURL ( url ) ;
}
2018-06-06 15:37:56 +00:00
}
2018-04-07 15:48:43 +00:00
LanguageLoadingProvider ( ) {
2019-01-01 21:50:04 +00:00
languageClassLoader = new LanguageClassLoader ( ) ;
serviceLoader = ServiceLoader . load ( IModLanguageProvider . class , languageClassLoader ) ;
loadLanguageProviders ( ) ;
}
private void loadLanguageProviders ( ) {
LOGGER . debug ( CORE , " Found {} language providers " , ServiceLoaderStreamUtils . toList ( serviceLoader ) . size ( ) ) ;
2018-04-07 15:48:43 +00:00
serviceLoader . forEach ( languageProviders : : add ) ;
languageProviders . forEach ( lp - > {
2018-12-31 21:33:54 +00:00
final Path lpPath ;
try {
lpPath = Paths . get ( lp . getClass ( ) . getProtectionDomain ( ) . getCodeSource ( ) . getLocation ( ) . toURI ( ) ) ;
} catch ( URISyntaxException e ) {
throw new RuntimeException ( " Huh? " , e ) ;
2018-06-06 15:37:56 +00:00
}
2018-12-31 21:33:54 +00:00
Optional < String > implementationVersion = JarVersionLookupHandler . getImplementationVersion ( lp . getClass ( ) ) ;
String impl = implementationVersion . orElse ( Files . isDirectory ( lpPath ) ? FMLLoader . forgeVersion . split ( " \\ . " ) [ 0 ] : null ) ;
if ( impl = = null ) {
2019-01-06 20:46:29 +00:00
LOGGER . fatal ( CORE , " Found unversioned language provider {} " , lp . name ( ) ) ;
2018-12-31 21:33:54 +00:00
throw new RuntimeException ( " Failed to find implementation version for language provider " + lp . name ( ) ) ;
}
2019-01-01 21:50:04 +00:00
LOGGER . debug ( CORE , " Found language provider {}, version {} " , lp . name ( ) , impl ) ;
2018-12-31 21:33:54 +00:00
languageProviderMap . put ( lp . name ( ) , new ModLanguageWrapper ( lp , new DefaultArtifactVersion ( impl ) ) ) ;
2018-04-07 15:48:43 +00:00
} ) ;
}
2019-01-01 21:50:04 +00:00
void addForgeLanguage ( final Path forgePath ) {
if ( ! languageProviderMap . containsKey ( " javafml " ) ) {
LOGGER . debug ( CORE , " Adding forge as a language from {} " , forgePath . toString ( ) ) ;
addLanguagePaths ( Stream . of ( forgePath ) ) ;
serviceLoader . reload ( ) ;
loadLanguageProviders ( ) ;
} else {
LOGGER . debug ( CORE , " Skipping adding forge jar - javafml is already present " ) ;
}
}
private void addLanguagePaths ( final Stream < Path > langPaths ) {
languageProviders . clear ( ) ;
languageProviderMap . clear ( ) ;
langPaths . map ( Path : : toFile ) . map ( File : : toURI ) . map ( rethrowFunction ( URI : : toURL ) ) . forEach ( languageClassLoader : : addURL ) ;
}
2018-04-07 15:48:43 +00:00
public void addAdditionalLanguages ( List < ModFile > modFiles )
{
if ( modFiles = = null ) return ;
Stream < Path > langPaths = modFiles . stream ( ) . map ( ModFile : : getFilePath ) ;
2019-01-01 21:50:04 +00:00
addLanguagePaths ( langPaths ) ;
2018-04-07 15:48:43 +00:00
serviceLoader . reload ( ) ;
2019-01-01 21:50:04 +00:00
loadLanguageProviders ( ) ;
2018-04-07 15:48:43 +00:00
}
2018-10-04 15:31:08 +00:00
public IModLanguageProvider findLanguage ( ModFile mf , String modLoader , VersionRange modLoaderVersion ) {
final String languageFileName = mf . getLocator ( ) instanceof ExplodedDirectoryLocator ? " in-development " : mf . getFileName ( ) ;
2018-06-06 15:37:56 +00:00
final ModLanguageWrapper mlw = languageProviderMap . get ( modLoader ) ;
if ( mlw = = null ) {
2018-10-04 15:31:08 +00:00
LOGGER . error ( " Missing language {} version {} wanted by {} " , modLoader , modLoaderVersion , languageFileName ) ;
throw new EarlyLoadingException ( " Missing language " + modLoader , null , Collections . singletonList ( new EarlyLoadingException . ExceptionData ( " fml.language.missingversion " , modLoader , modLoaderVersion , languageFileName , " null " ) ) ) ;
2018-06-06 15:37:56 +00:00
}
if ( ! modLoaderVersion . containsVersion ( mlw . getVersion ( ) ) ) {
2018-10-04 15:31:08 +00:00
LOGGER . error ( " Missing language {} version {} wanted by {}, found {} " , modLoader , modLoaderVersion , languageFileName , mlw . getVersion ( ) ) ;
throw new EarlyLoadingException ( " Missing language " + modLoader + " matching range " + modLoaderVersion + " found " + mlw . getVersion ( ) , null , Collections . singletonList ( new EarlyLoadingException . ExceptionData ( " fml.language.missingversion " , modLoader , modLoaderVersion , languageFileName , mlw . getVersion ( ) ) ) ) ;
2018-06-06 15:37:56 +00:00
}
return mlw . getModLanguageProvider ( ) ;
2018-04-07 15:48:43 +00:00
}
}