Merge pull request #1046 from thatsIch/b-976-version-checker
Fixes #976 Now uses GitHub to retrieve most current version
This commit is contained in:
commit
34597a4e21
33 changed files with 2023 additions and 169 deletions
|
@ -79,6 +79,7 @@ jar {
|
||||||
minecraft {
|
minecraft {
|
||||||
version = config.minecraft_version + "-" + config.forge_version
|
version = config.minecraft_version + "-" + config.forge_version
|
||||||
|
|
||||||
|
replaceIn "AEConfig.java"
|
||||||
replace "@version@", project.version
|
replace "@version@", project.version
|
||||||
replace "@aechannel@", config.aechannel
|
replace "@aechannel@", config.aechannel
|
||||||
|
|
||||||
|
|
|
@ -55,9 +55,6 @@ public class AEConfig extends Configuration implements IConfigurableObject, ICon
|
||||||
|
|
||||||
public static final double TUNNEL_POWER_LOSS = 0.05;
|
public static final double TUNNEL_POWER_LOSS = 0.05;
|
||||||
|
|
||||||
public String latestVersion = VERSION;
|
|
||||||
public long latestTimeStamp = 0;
|
|
||||||
|
|
||||||
public static final String VERSION = "@version@";
|
public static final String VERSION = "@version@";
|
||||||
public static final String CHANNEL = "@aechannel@";
|
public static final String CHANNEL = "@aechannel@";
|
||||||
|
|
||||||
|
@ -149,7 +146,7 @@ public class AEConfig extends Configuration implements IConfigurableObject, ICon
|
||||||
public boolean disableColoredCableRecipesInNEI = true;
|
public boolean disableColoredCableRecipesInNEI = true;
|
||||||
|
|
||||||
public boolean updatable = false;
|
public boolean updatable = false;
|
||||||
final private File myPath;
|
final private File configFile;
|
||||||
|
|
||||||
public double meteoriteClusterChance = 0.1;
|
public double meteoriteClusterChance = 0.1;
|
||||||
public double meteoriteSpawnChance = 0.3;
|
public double meteoriteSpawnChance = 0.3;
|
||||||
|
@ -224,22 +221,20 @@ public class AEConfig extends Configuration implements IConfigurableObject, ICon
|
||||||
|
|
||||||
public String getFilePath()
|
public String getFilePath()
|
||||||
{
|
{
|
||||||
return this.myPath.toString();
|
return this.configFile.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public AEConfig(String path) {
|
public AEConfig( File configFile ) {
|
||||||
super( new File( path + "AppliedEnergistics2.cfg" ) );
|
super( configFile );
|
||||||
this.myPath = new File( path + "AppliedEnergistics2.cfg" );
|
this.configFile = configFile;
|
||||||
|
|
||||||
FMLCommonHandler.instance().bus().register( this );
|
FMLCommonHandler.instance().bus().register( this );
|
||||||
|
|
||||||
final double DEFAULT_BC_EXCHANGE = 5.0;
|
|
||||||
final double DEFAULT_IC2_EXCHANGE = 2.0;
|
final double DEFAULT_IC2_EXCHANGE = 2.0;
|
||||||
final double DEFAULT_RTC_EXCHANGE = 1.0 / 11256.0;
|
final double DEFAULT_RTC_EXCHANGE = 1.0 / 11256.0;
|
||||||
final double DEFAULT_RF_EXCHANGE = 0.5;
|
final double DEFAULT_RF_EXCHANGE = 0.5;
|
||||||
final double DEFAULT_MEKANISM_EXCHANGE = 0.2;
|
final double DEFAULT_MEKANISM_EXCHANGE = 0.2;
|
||||||
|
|
||||||
PowerUnits.MJ.conversionRatio = this.get( "PowerRatios", "BuildCraft", DEFAULT_BC_EXCHANGE ).getDouble( DEFAULT_BC_EXCHANGE );
|
|
||||||
PowerUnits.MK.conversionRatio = this.get( "PowerRatios", "Mekanism", DEFAULT_MEKANISM_EXCHANGE ).getDouble( DEFAULT_MEKANISM_EXCHANGE );
|
PowerUnits.MK.conversionRatio = this.get( "PowerRatios", "Mekanism", DEFAULT_MEKANISM_EXCHANGE ).getDouble( DEFAULT_MEKANISM_EXCHANGE );
|
||||||
PowerUnits.EU.conversionRatio = this.get( "PowerRatios", "IC2", DEFAULT_IC2_EXCHANGE ).getDouble( DEFAULT_IC2_EXCHANGE );
|
PowerUnits.EU.conversionRatio = this.get( "PowerRatios", "IC2", DEFAULT_IC2_EXCHANGE ).getDouble( DEFAULT_IC2_EXCHANGE );
|
||||||
PowerUnits.WA.conversionRatio = this.get( "PowerRatios", "RotaryCraft", DEFAULT_RTC_EXCHANGE ).getDouble( DEFAULT_RTC_EXCHANGE );
|
PowerUnits.WA.conversionRatio = this.get( "PowerRatios", "RotaryCraft", DEFAULT_RTC_EXCHANGE ).getDouble( DEFAULT_RTC_EXCHANGE );
|
||||||
|
@ -340,19 +335,6 @@ public class AEConfig extends Configuration implements IConfigurableObject, ICon
|
||||||
this.craftingCalculationTimePerTick );
|
this.craftingCalculationTimePerTick );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( this.isFeatureEnabled( AEFeature.VersionChecker ) )
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
this.latestVersion = this.get( "VersionChecker", "LatestVersion", "" ).getString();
|
|
||||||
this.latestTimeStamp = Long.parseLong( this.get( "VersionChecker", "LatestTimeStamp", "" ).getString() );
|
|
||||||
}
|
|
||||||
catch (NumberFormatException err)
|
|
||||||
{
|
|
||||||
this.latestTimeStamp = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.updatable = true;
|
this.updatable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,12 +393,6 @@ public class AEConfig extends Configuration implements IConfigurableObject, ICon
|
||||||
@Override
|
@Override
|
||||||
public void save()
|
public void save()
|
||||||
{
|
{
|
||||||
if ( this.isFeatureEnabled( AEFeature.VersionChecker ) )
|
|
||||||
{
|
|
||||||
this.get( "VersionChecker", "LatestVersion", this.latestVersion ).set( this.latestVersion );
|
|
||||||
this.get( "VersionChecker", "LatestTimeStamp", "" ).set( Long.toString( this.latestTimeStamp ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( this.isFeatureEnabled( AEFeature.SpatialIO ) )
|
if ( this.isFeatureEnabled( AEFeature.SpatialIO ) )
|
||||||
{
|
{
|
||||||
this.get( "spatialio", "storageBiomeID", this.storageBiomeID ).set( this.storageBiomeID );
|
this.get( "spatialio", "storageBiomeID", this.storageBiomeID ).set( this.storageBiomeID );
|
||||||
|
|
|
@ -22,8 +22,6 @@ package appeng.core;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import com.google.common.base.Stopwatch;
|
|
||||||
|
|
||||||
import cpw.mods.fml.common.FMLCommonHandler;
|
import cpw.mods.fml.common.FMLCommonHandler;
|
||||||
import cpw.mods.fml.common.Loader;
|
import cpw.mods.fml.common.Loader;
|
||||||
import cpw.mods.fml.common.Mod;
|
import cpw.mods.fml.common.Mod;
|
||||||
|
@ -37,6 +35,8 @@ import cpw.mods.fml.common.event.FMLServerStartingEvent;
|
||||||
import cpw.mods.fml.common.event.FMLServerStoppingEvent;
|
import cpw.mods.fml.common.event.FMLServerStoppingEvent;
|
||||||
import cpw.mods.fml.common.network.NetworkRegistry;
|
import cpw.mods.fml.common.network.NetworkRegistry;
|
||||||
|
|
||||||
|
import com.google.common.base.Stopwatch;
|
||||||
|
|
||||||
import appeng.core.crash.CrashEnhancement;
|
import appeng.core.crash.CrashEnhancement;
|
||||||
import appeng.core.crash.CrashInfo;
|
import appeng.core.crash.CrashInfo;
|
||||||
import appeng.core.features.AEFeature;
|
import appeng.core.features.AEFeature;
|
||||||
|
@ -47,6 +47,7 @@ import appeng.integration.IntegrationRegistry;
|
||||||
import appeng.integration.IntegrationType;
|
import appeng.integration.IntegrationType;
|
||||||
import appeng.server.AECommand;
|
import appeng.server.AECommand;
|
||||||
import appeng.services.VersionChecker;
|
import appeng.services.VersionChecker;
|
||||||
|
import appeng.services.version.VersionCheckerConfig;
|
||||||
import appeng.util.Platform;
|
import appeng.util.Platform;
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,7 +71,7 @@ public class AppEng
|
||||||
|
|
||||||
private final IMCHandler imcHandler;
|
private final IMCHandler imcHandler;
|
||||||
|
|
||||||
private String configPath;
|
private File configDirectory;
|
||||||
|
|
||||||
public AppEng()
|
public AppEng()
|
||||||
{
|
{
|
||||||
|
@ -81,9 +82,9 @@ public class AppEng
|
||||||
FMLCommonHandler.instance().registerCrashCallable( new CrashEnhancement( CrashInfo.MOD_VERSION ) );
|
FMLCommonHandler.instance().registerCrashCallable( new CrashEnhancement( CrashInfo.MOD_VERSION ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getConfigPath()
|
public final File getConfigDirectory()
|
||||||
{
|
{
|
||||||
return this.configPath;
|
return this.configDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isIntegrationEnabled( IntegrationType integrationName )
|
public boolean isIntegrationEnabled( IntegrationType integrationName )
|
||||||
|
@ -104,11 +105,16 @@ public class AppEng
|
||||||
CommonHelper.proxy.missingCoreMod();
|
CommonHelper.proxy.missingCoreMod();
|
||||||
}
|
}
|
||||||
|
|
||||||
Stopwatch star = Stopwatch.createStarted();
|
Stopwatch watch = Stopwatch.createStarted();
|
||||||
this.configPath = event.getModConfigurationDirectory().getPath() + File.separator + "AppliedEnergistics2" + File.separator;
|
this.configDirectory = new File(event.getModConfigurationDirectory().getPath(), "AppliedEnergistics2");
|
||||||
|
|
||||||
AEConfig.instance = new AEConfig( this.configPath );
|
final File configFile = new File( this.configDirectory, "AppliedEnergistics2.cfg");
|
||||||
FacadeConfig.instance = new FacadeConfig( this.configPath );
|
final File facadeFile = new File( this.configDirectory, "Facades.cfg" );
|
||||||
|
final File versionFile = new File( this.configDirectory, "VersionChecker.cfg" );
|
||||||
|
|
||||||
|
AEConfig.instance = new AEConfig( configFile );
|
||||||
|
FacadeConfig.instance = new FacadeConfig( facadeFile );
|
||||||
|
final VersionCheckerConfig versionCheckerConfig = new VersionCheckerConfig( versionFile );
|
||||||
|
|
||||||
AELog.info( "Pre Initialization ( started )" );
|
AELog.info( "Pre Initialization ( started )" );
|
||||||
|
|
||||||
|
@ -121,19 +127,23 @@ public class AppEng
|
||||||
|
|
||||||
Registration.INSTANCE.preInitialize( event );
|
Registration.INSTANCE.preInitialize( event );
|
||||||
|
|
||||||
if ( AEConfig.instance.isFeatureEnabled( AEFeature.VersionChecker ) )
|
if ( versionCheckerConfig.isEnabled() )
|
||||||
{
|
{
|
||||||
AELog.info( "Starting VersionChecker" );
|
final VersionChecker versionChecker = new VersionChecker( versionCheckerConfig );
|
||||||
this.startService( "AE2 VersionChecker", new Thread( new VersionChecker() ) );
|
final Thread versionCheckerThread = new Thread( versionChecker );
|
||||||
|
|
||||||
|
this.startService( "AE2 VersionChecker", versionCheckerThread );
|
||||||
}
|
}
|
||||||
|
|
||||||
AELog.info( "Pre Initialization ( ended after " + star.elapsed( TimeUnit.MILLISECONDS ) + "ms )" );
|
AELog.info( "Pre Initialization ( ended after " + watch.elapsed( TimeUnit.MILLISECONDS ) + "ms )" );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startService( String serviceName, Thread thread )
|
private void startService( String serviceName, Thread thread )
|
||||||
{
|
{
|
||||||
thread.setName( serviceName );
|
thread.setName( serviceName );
|
||||||
thread.setPriority( Thread.MIN_PRIORITY );
|
thread.setPriority( Thread.MIN_PRIORITY );
|
||||||
|
|
||||||
|
AELog.info( "Starting " + serviceName );
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,8 @@ public class FacadeConfig extends Configuration
|
||||||
public static FacadeConfig instance;
|
public static FacadeConfig instance;
|
||||||
final Pattern replacementPattern;
|
final Pattern replacementPattern;
|
||||||
|
|
||||||
public FacadeConfig(String path) {
|
public FacadeConfig( File facadeFile ) {
|
||||||
super( new File( path + "Facades.cfg" ) );
|
super( facadeFile );
|
||||||
this.replacementPattern = Pattern.compile( "[^a-zA-Z0-9]" );
|
this.replacementPattern = Pattern.compile( "[^a-zA-Z0-9]" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,6 @@ package appeng.core;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
import com.google.common.base.Optional;
|
|
||||||
import com.google.common.collect.ArrayListMultimap;
|
|
||||||
import com.google.common.collect.Multimap;
|
|
||||||
|
|
||||||
import net.minecraft.item.crafting.CraftingManager;
|
import net.minecraft.item.crafting.CraftingManager;
|
||||||
import net.minecraft.util.WeightedRandomChestContent;
|
import net.minecraft.util.WeightedRandomChestContent;
|
||||||
import net.minecraft.world.biome.BiomeGenBase;
|
import net.minecraft.world.biome.BiomeGenBase;
|
||||||
|
@ -41,6 +37,10 @@ import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||||
import cpw.mods.fml.common.registry.GameRegistry;
|
import cpw.mods.fml.common.registry.GameRegistry;
|
||||||
import cpw.mods.fml.common.registry.VillagerRegistry;
|
import cpw.mods.fml.common.registry.VillagerRegistry;
|
||||||
|
|
||||||
|
import com.google.common.base.Optional;
|
||||||
|
import com.google.common.collect.ArrayListMultimap;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
|
|
||||||
import appeng.api.AEApi;
|
import appeng.api.AEApi;
|
||||||
import appeng.api.IAppEngApi;
|
import appeng.api.IAppEngApi;
|
||||||
import appeng.api.config.Upgrades;
|
import appeng.api.config.Upgrades;
|
||||||
|
@ -546,7 +546,7 @@ public final class Registration
|
||||||
ItemMultiMaterial.instance.makeUnique();
|
ItemMultiMaterial.instance.makeUnique();
|
||||||
|
|
||||||
if ( AEConfig.instance.isFeatureEnabled( AEFeature.CustomRecipes ) )
|
if ( AEConfig.instance.isFeatureEnabled( AEFeature.CustomRecipes ) )
|
||||||
this.recipeHandler.parseRecipes( new ConfigLoader( AppEng.instance.getConfigPath() ), "index.recipe" );
|
this.recipeHandler.parseRecipes( new ConfigLoader( AppEng.instance.getConfigDirectory() ), "index.recipe" );
|
||||||
else
|
else
|
||||||
this.recipeHandler.parseRecipes( new JarLoader( "/assets/appliedenergistics2/recipes/" ), "index.recipe" );
|
this.recipeHandler.parseRecipes( new JarLoader( "/assets/appliedenergistics2/recipes/" ), "index.recipe" );
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ public enum AEFeature
|
||||||
|
|
||||||
MassCannonBlockDamage("BlockFeatures"), TinyTNTBlockDamage("BlockFeatures"), Facades("Facades"),
|
MassCannonBlockDamage("BlockFeatures"), TinyTNTBlockDamage("BlockFeatures"), Facades("Facades"),
|
||||||
|
|
||||||
VersionChecker("Services"), UnsupportedDeveloperTools("Misc", false), Creative("Misc"),
|
UnsupportedDeveloperTools("Misc", false), Creative("Misc"),
|
||||||
|
|
||||||
GrinderLogging("Misc", false), Logging("Misc"), IntegrationLogging("Misc", false), CustomRecipes("Crafting", false), WebsiteRecipes("Misc", false),
|
GrinderLogging("Misc", false), Logging("Misc"), IntegrationLogging("Misc", false), CustomRecipes("Crafting", false), WebsiteRecipes("Misc", false),
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ import appeng.core.WorldSettings;
|
||||||
import appeng.core.sync.AppEngPacket;
|
import appeng.core.sync.AppEngPacket;
|
||||||
import appeng.core.sync.network.INetworkInfo;
|
import appeng.core.sync.network.INetworkInfo;
|
||||||
import appeng.core.sync.network.NetworkHandler;
|
import appeng.core.sync.network.NetworkHandler;
|
||||||
import appeng.services.helpers.ICompassCallback;
|
import appeng.services.compass.ICompassCallback;
|
||||||
|
|
||||||
public class PacketCompassRequest extends AppEngPacket implements ICompassCallback
|
public class PacketCompassRequest extends AppEngPacket implements ICompassCallback
|
||||||
{
|
{
|
||||||
|
|
|
@ -33,7 +33,7 @@ import appeng.core.AEConfig;
|
||||||
import appeng.core.WorldSettings;
|
import appeng.core.WorldSettings;
|
||||||
import appeng.core.features.registries.WorldGenRegistry;
|
import appeng.core.features.registries.WorldGenRegistry;
|
||||||
import appeng.helpers.MeteoritePlacer;
|
import appeng.helpers.MeteoritePlacer;
|
||||||
import appeng.services.helpers.ICompassCallback;
|
import appeng.services.compass.ICompassCallback;
|
||||||
import appeng.util.Platform;
|
import appeng.util.Platform;
|
||||||
|
|
||||||
final public class MeteoriteWorldGen implements IWorldGenerator
|
final public class MeteoriteWorldGen implements IWorldGenerator
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
package appeng.recipes.loader;
|
package appeng.recipes.loader;
|
||||||
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
@ -25,19 +26,21 @@ import java.io.InputStreamReader;
|
||||||
|
|
||||||
import appeng.api.recipes.IRecipeLoader;
|
import appeng.api.recipes.IRecipeLoader;
|
||||||
|
|
||||||
public class ConfigLoader implements IRecipeLoader
|
|
||||||
|
public final class ConfigLoader implements IRecipeLoader
|
||||||
{
|
{
|
||||||
|
private final File rootDirectory;
|
||||||
|
|
||||||
private final String rootPath;
|
public ConfigLoader( File rootDirectory )
|
||||||
|
{
|
||||||
public ConfigLoader(String s) {
|
this.rootDirectory = rootDirectory;
|
||||||
this.rootPath = s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BufferedReader getFile( String s ) throws Exception
|
public BufferedReader getFile( String s ) throws Exception
|
||||||
{
|
{
|
||||||
File f = new File( this.rootPath + s );
|
final File f = new File( this.rootDirectory, s );
|
||||||
|
|
||||||
return new BufferedReader( new InputStreamReader( new FileInputStream( f ), "UTF-8" ) );
|
return new BufferedReader( new InputStreamReader( new FileInputStream( f ), "UTF-8" ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,8 +32,8 @@ import net.minecraft.world.chunk.Chunk;
|
||||||
|
|
||||||
import appeng.api.AEApi;
|
import appeng.api.AEApi;
|
||||||
import appeng.api.util.DimensionalCoord;
|
import appeng.api.util.DimensionalCoord;
|
||||||
import appeng.services.helpers.CompassReader;
|
import appeng.services.compass.CompassReader;
|
||||||
import appeng.services.helpers.ICompassCallback;
|
import appeng.services.compass.ICompassCallback;
|
||||||
|
|
||||||
public class CompassService implements ThreadFactory
|
public class CompassService implements ThreadFactory
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,133 +19,167 @@
|
||||||
package appeng.services;
|
package appeng.services;
|
||||||
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLConnection;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import com.google.gson.JsonArray;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.JsonParser;
|
|
||||||
|
|
||||||
import net.minecraft.nbt.NBTTagCompound;
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
|
|
||||||
|
import cpw.mods.fml.common.Loader;
|
||||||
import cpw.mods.fml.common.event.FMLInterModComms;
|
import cpw.mods.fml.common.event.FMLInterModComms;
|
||||||
|
|
||||||
import appeng.core.AEConfig;
|
import appeng.core.AEConfig;
|
||||||
import appeng.core.AELog;
|
import appeng.core.AELog;
|
||||||
import appeng.core.AppEng;
|
import appeng.core.AppEng;
|
||||||
|
import appeng.services.version.github.FormattedRelease;
|
||||||
|
import appeng.services.version.github.ReleaseFetcher;
|
||||||
|
import appeng.services.version.ModVersionFetcher;
|
||||||
|
import appeng.services.version.Version;
|
||||||
|
import appeng.services.version.VersionCheckerConfig;
|
||||||
|
import appeng.services.version.VersionFetcher;
|
||||||
|
import appeng.services.version.VersionParser;
|
||||||
|
|
||||||
public class VersionChecker implements Runnable
|
|
||||||
|
/**
|
||||||
|
* Tries to connect to GitHub to retrieve the most current build.
|
||||||
|
* After comparison with the local version, several path can be chosen.
|
||||||
|
*
|
||||||
|
* If the local version is invalid, somebody might have build that version themselves
|
||||||
|
* or it is run in a developer environment, then nothing needs to be done.
|
||||||
|
*
|
||||||
|
* If GitHub can not be reached, then either is GitHub down
|
||||||
|
* or the connection to GitHub disturbed, then nothing needs to be done,
|
||||||
|
* since no comparison can be reached
|
||||||
|
*
|
||||||
|
* If the version was just recently checked, then no need to poll again.
|
||||||
|
* Nobody wants to bother to update several times a day.
|
||||||
|
*
|
||||||
|
* Config enables to fine-tune when a version is considered newer
|
||||||
|
*
|
||||||
|
* If the local version is newer or equal to the GitHub version,
|
||||||
|
* then no update needs to be posted
|
||||||
|
*
|
||||||
|
* Only after all that cases, if the external version is higher than the local,
|
||||||
|
* use Version Checker Mod and post several information needed for it to update the mod.
|
||||||
|
*/
|
||||||
|
public final class VersionChecker implements Runnable
|
||||||
{
|
{
|
||||||
private static final int FOUR_HOURS = 1000 * 3600 * 4;
|
private static final int SEC_TO_HOUR = 3600;
|
||||||
|
private static final int MS_TO_SEC = 1000;
|
||||||
|
private final VersionCheckerConfig config;
|
||||||
|
|
||||||
private final long delay;
|
public VersionChecker( VersionCheckerConfig config )
|
||||||
|
|
||||||
public VersionChecker()
|
|
||||||
{
|
{
|
||||||
final long now = new Date().getTime();
|
this.config = config;
|
||||||
final long timeDiff = now - AEConfig.instance.latestTimeStamp;
|
|
||||||
|
|
||||||
this.delay = Math.max( 1, FOUR_HOURS - timeDiff);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run()
|
public void run()
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
this.sleep( this.delay );
|
|
||||||
}
|
|
||||||
catch (InterruptedException e)
|
|
||||||
{
|
|
||||||
// :(
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
{
|
||||||
Thread.yield();
|
Thread.yield();
|
||||||
|
|
||||||
try
|
final String rawLastCheck = this.config.lastCheck();
|
||||||
|
final long lastCheck = Long.parseLong( rawLastCheck );
|
||||||
|
final Date now = new Date();
|
||||||
|
final long nowInMs = now.getTime();
|
||||||
|
final long intervalInMs = this.config.interval() * SEC_TO_HOUR * MS_TO_SEC;
|
||||||
|
final long lastAfterInterval = lastCheck + intervalInMs;
|
||||||
|
|
||||||
|
this.processInterval( nowInMs, lastAfterInterval );
|
||||||
|
|
||||||
|
AELog.info( "Stopping AE2 VersionChecker" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checks if enough time since last check has expired
|
||||||
|
*
|
||||||
|
* @param nowInMs now in milli seconds
|
||||||
|
* @param lastAfterInterval last version check including the interval defined in the config
|
||||||
|
*/
|
||||||
|
private void processInterval( long nowInMs, long lastAfterInterval )
|
||||||
{
|
{
|
||||||
String MCVersion = cpw.mods.fml.common.Loader.instance().getMCVersionString().replace( "Minecraft ", "" );
|
if ( nowInMs > lastAfterInterval )
|
||||||
URL url = new URL( "http://feeds.ae-mod.info/latest.json?VersionMC=" + MCVersion + "&Channel=" + AEConfig.CHANNEL + "&CurrentVersion="
|
|
||||||
+ AEConfig.VERSION );
|
|
||||||
|
|
||||||
URLConnection yc = url.openConnection();
|
|
||||||
yc.setRequestProperty( "User-Agent", "AE2/" + AEConfig.VERSION + " (Channel:" + AEConfig.CHANNEL + ',' + MCVersion.replace( " ", ":" ) + ')' );
|
|
||||||
BufferedReader in = new BufferedReader( new InputStreamReader( yc.getInputStream() ) );
|
|
||||||
|
|
||||||
StringBuilder Version = new StringBuilder();
|
|
||||||
String inputLine;
|
|
||||||
|
|
||||||
while ((inputLine = in.readLine()) != null)
|
|
||||||
Version.append( inputLine );
|
|
||||||
|
|
||||||
in.close();
|
|
||||||
|
|
||||||
if ( Version.length() > 2 )
|
|
||||||
{
|
{
|
||||||
JsonElement element = (new JsonParser()).parse( Version.toString() );
|
final String rawModVersion = AEConfig.VERSION;
|
||||||
|
final VersionParser parser = new VersionParser();
|
||||||
|
final VersionFetcher modFetcher = new ModVersionFetcher( rawModVersion, parser );
|
||||||
|
final ReleaseFetcher githubFetcher = new ReleaseFetcher( this.config, parser );
|
||||||
|
|
||||||
int version = element.getAsJsonObject().get( "FormatVersion" ).getAsInt();
|
final Version modVersion = modFetcher.get();
|
||||||
if ( version == 1 )
|
final FormattedRelease githubRelease = githubFetcher.get();
|
||||||
{
|
|
||||||
JsonObject Meta = element.getAsJsonObject().get( "Meta" ).getAsJsonObject();
|
|
||||||
JsonArray Versions = element.getAsJsonObject().get( "Versions" ).getAsJsonArray();
|
|
||||||
if ( Versions.size() > 0 )
|
|
||||||
{
|
|
||||||
JsonObject Latest = Versions.get( 0 ).getAsJsonObject();
|
|
||||||
|
|
||||||
AEConfig.instance.latestVersion = Latest.get( "Version" ).getAsString();
|
this.processVersions( modVersion, githubRelease );
|
||||||
AEConfig.instance.latestTimeStamp = (new Date()).getTime();
|
}
|
||||||
AEConfig.instance.save();
|
else
|
||||||
|
|
||||||
if ( !AEConfig.VERSION.equals( AEConfig.instance.latestVersion ) )
|
|
||||||
{
|
{
|
||||||
NBTTagCompound versionInf = new NBTTagCompound();
|
AELog.info( "Last check was just recently." );
|
||||||
versionInf.setString( "modDisplayName", "Applied Energistics 2" );
|
}
|
||||||
versionInf.setString( "oldVersion", AEConfig.VERSION );
|
}
|
||||||
versionInf.setString( "newVersion", AEConfig.instance.latestVersion );
|
|
||||||
versionInf.setString( "updateUrl", Latest.get( "UserBuild" ).getAsString() );
|
/**
|
||||||
|
* Checks if the retrieved version is newer as the current mod version.
|
||||||
|
* Will notify player if config is enabled.
|
||||||
|
*
|
||||||
|
* @param modVersion version of mod
|
||||||
|
* @param githubRelease release retrieved through github
|
||||||
|
*/
|
||||||
|
private void processVersions( Version modVersion, FormattedRelease githubRelease )
|
||||||
|
{
|
||||||
|
final Version githubVersion = githubRelease.version();
|
||||||
|
final String modFormatted = modVersion.formatted();
|
||||||
|
final String ghFormatted = githubVersion.formatted();
|
||||||
|
|
||||||
|
if ( githubVersion.isNewerAs( modVersion ) )
|
||||||
|
{
|
||||||
|
final String changelog = githubRelease.changelog();
|
||||||
|
|
||||||
|
if ( this.config.shouldNotifyPlayer() )
|
||||||
|
{
|
||||||
|
AELog.info( "Newer version is available: " + ghFormatted + " (found) > " + modFormatted + " (current)" );
|
||||||
|
|
||||||
|
if ( this.config.shouldPostChangelog() )
|
||||||
|
{
|
||||||
|
AELog.info( "Changelog: " + changelog );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.interactWithVersionCheckerMod( modFormatted, ghFormatted, changelog );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AELog.info( "No newer version is available: " + ghFormatted + "(found) < " + modFormatted + " (current)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the version checker mod is installed and handles it depending on that information
|
||||||
|
*
|
||||||
|
* @param modFormatted mod version formatted as rv2-beta-8
|
||||||
|
* @param ghFormatted retrieved github version formatted as rv2-beta-8
|
||||||
|
* @param changelog retrieved github changelog
|
||||||
|
*/
|
||||||
|
private void interactWithVersionCheckerMod( String modFormatted, String ghFormatted, String changelog )
|
||||||
|
{
|
||||||
|
if ( Loader.isModLoaded( "VersionChecker" ) )
|
||||||
|
{
|
||||||
|
final NBTTagCompound versionInf = new NBTTagCompound();
|
||||||
|
versionInf.setString( "modDisplayName", AppEng.MOD_NAME );
|
||||||
|
versionInf.setString( "oldVersion", modFormatted );
|
||||||
|
versionInf.setString( "newVersion", ghFormatted );
|
||||||
|
versionInf.setString( "updateUrl", "http://ae-mod.info/builds/appliedenergistics2-" + ghFormatted + ".jar" );
|
||||||
versionInf.setBoolean( "isDirectLink", true );
|
versionInf.setBoolean( "isDirectLink", true );
|
||||||
|
|
||||||
JsonElement changeLog = Latest.get( "ChangeLog" );
|
if ( !changelog.isEmpty() )
|
||||||
if ( changeLog == null )
|
{
|
||||||
versionInf.setString( "changeLog", "For full change log please see: " + Meta.get( "DownloadLink" ).getAsString() );
|
versionInf.setString( "changeLog", changelog );
|
||||||
else
|
}
|
||||||
versionInf.setString( "changeLog", changeLog.getAsString() );
|
|
||||||
|
|
||||||
versionInf.setString( "newFileName", "appliedenergistics2-" + AEConfig.instance.latestVersion + ".jar" );
|
versionInf.setString( "newFileName", "appliedenergistics2-" + ghFormatted + ".jar" );
|
||||||
FMLInterModComms.sendRuntimeMessage( AppEng.instance, "VersionChecker", "addUpdate", versionInf );
|
FMLInterModComms.sendRuntimeMessage( AppEng.instance, "VersionChecker", "addUpdate", versionInf );
|
||||||
|
|
||||||
AELog.info( "Stopping VersionChecker" );
|
AELog.info( "Reported new version to VersionChecker mod." );
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.sleep( FOUR_HOURS );
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
{
|
||||||
try
|
AELog.info( "VersionChecker mod is not installed; Proceeding." );
|
||||||
{
|
|
||||||
this.sleep( FOUR_HOURS );
|
|
||||||
}
|
|
||||||
catch (InterruptedException e1)
|
|
||||||
{
|
|
||||||
AELog.error( e );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void sleep(long i) throws InterruptedException
|
|
||||||
{
|
|
||||||
Thread.sleep( i );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package appeng.services.helpers;
|
package appeng.services.compass;
|
||||||
|
|
||||||
public class CompassException extends RuntimeException
|
public class CompassException extends RuntimeException
|
||||||
{
|
{
|
|
@ -16,7 +16,7 @@
|
||||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package appeng.services.helpers;
|
package appeng.services.compass;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
|
@ -16,7 +16,7 @@
|
||||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package appeng.services.helpers;
|
package appeng.services.compass;
|
||||||
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
|
@ -16,7 +16,7 @@
|
||||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package appeng.services.helpers;
|
package appeng.services.compass;
|
||||||
|
|
||||||
public interface ICompassCallback
|
public interface ICompassCallback
|
||||||
{
|
{
|
91
src/main/java/appeng/services/version/BaseVersion.java
Normal file
91
src/main/java/appeng/services/version/BaseVersion.java
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
package appeng.services.version;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base version of {@link Version}.
|
||||||
|
*
|
||||||
|
* Provides a unified way to test for equality and print a formatted string
|
||||||
|
*/
|
||||||
|
public abstract class BaseVersion implements Version
|
||||||
|
{
|
||||||
|
private final int revision;
|
||||||
|
private final Channel channel;
|
||||||
|
private final int build;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param revision revision in natural number
|
||||||
|
* @param channel channel
|
||||||
|
* @param build build in natural number
|
||||||
|
*
|
||||||
|
* @throws AssertionError if assertion are enabled and revision or build are not natural numbers
|
||||||
|
*/
|
||||||
|
public BaseVersion( int revision, Channel channel, int build )
|
||||||
|
{
|
||||||
|
assert revision >= 0;
|
||||||
|
assert build >= 0;
|
||||||
|
|
||||||
|
this.revision = revision;
|
||||||
|
this.channel = channel;
|
||||||
|
this.build = build;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int revision()
|
||||||
|
{
|
||||||
|
return this.revision;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final Channel channel()
|
||||||
|
{
|
||||||
|
return this.channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int build()
|
||||||
|
{
|
||||||
|
return this.build;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String formatted()
|
||||||
|
{
|
||||||
|
return "rv" + this.revision + '-' + this.channel.name().toLowerCase() + '-' + this.build;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int hashCode()
|
||||||
|
{
|
||||||
|
int result = this.revision;
|
||||||
|
result = 31 * result + ( this.channel != null ? this.channel.hashCode() : 0 );
|
||||||
|
result = 31 * result + this.build;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean equals( Object o )
|
||||||
|
{
|
||||||
|
if ( this == o )
|
||||||
|
return true;
|
||||||
|
if ( !( o instanceof Version ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Version that = (Version) o;
|
||||||
|
|
||||||
|
if ( this.revision != that.revision() )
|
||||||
|
return false;
|
||||||
|
if ( this.build != that.build() )
|
||||||
|
return false;
|
||||||
|
return this.channel == that.channel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String toString()
|
||||||
|
{
|
||||||
|
return "Version{" +
|
||||||
|
"revision=" + this.revision +
|
||||||
|
", channel=" + this.channel +
|
||||||
|
", build=" + this.build +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
13
src/main/java/appeng/services/version/Channel.java
Normal file
13
src/main/java/appeng/services/version/Channel.java
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package appeng.services.version;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the release channel of Applied Energistics. The mod is either in Alpha, Beta or Release channel.
|
||||||
|
* Any more might be confusing to the end-user
|
||||||
|
*/
|
||||||
|
public enum Channel
|
||||||
|
{
|
||||||
|
Alpha,
|
||||||
|
Beta,
|
||||||
|
Release
|
||||||
|
}
|
35
src/main/java/appeng/services/version/DefaultVersion.java
Normal file
35
src/main/java/appeng/services/version/DefaultVersion.java
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package appeng.services.version;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AE prints version like rv2-beta-8
|
||||||
|
* GitHub prints version like rv2.beta.8
|
||||||
|
*/
|
||||||
|
public final class DefaultVersion extends BaseVersion
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param revision natural number
|
||||||
|
* @param channel either alpha, beta or release
|
||||||
|
* @param build natural number
|
||||||
|
*/
|
||||||
|
public DefaultVersion( int revision, Channel channel, int build )
|
||||||
|
{
|
||||||
|
super( revision, channel, build );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isNewerAs( Version maybeOlder )
|
||||||
|
{
|
||||||
|
if ( this.revision() > maybeOlder.revision() )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( this.channel().compareTo( maybeOlder.channel() ) > 0 )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.build() > maybeOlder.build();
|
||||||
|
}
|
||||||
|
}
|
25
src/main/java/appeng/services/version/DoNotCheckVersion.java
Normal file
25
src/main/java/appeng/services/version/DoNotCheckVersion.java
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package appeng.services.version;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exceptional template for {@link Version}, when the mod does not want a check
|
||||||
|
*/
|
||||||
|
public final class DoNotCheckVersion extends BaseVersion
|
||||||
|
{
|
||||||
|
public DoNotCheckVersion()
|
||||||
|
{
|
||||||
|
super( Integer.MAX_VALUE, Channel.Release, Integer.MAX_VALUE );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isNewerAs( Version maybeOlder )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String formatted()
|
||||||
|
{
|
||||||
|
return "dev build";
|
||||||
|
}
|
||||||
|
}
|
30
src/main/java/appeng/services/version/MissingVersion.java
Normal file
30
src/main/java/appeng/services/version/MissingVersion.java
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
package appeng.services.version;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exceptional template when the {@link Version} could not be retrieved
|
||||||
|
*/
|
||||||
|
public final class MissingVersion extends BaseVersion
|
||||||
|
{
|
||||||
|
public MissingVersion()
|
||||||
|
{
|
||||||
|
super( 0, Channel.Alpha, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param maybeOlder ignored
|
||||||
|
*
|
||||||
|
* @return false
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isNewerAs( Version maybeOlder )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String formatted()
|
||||||
|
{
|
||||||
|
return "missing";
|
||||||
|
}
|
||||||
|
}
|
39
src/main/java/appeng/services/version/ModVersionFetcher.java
Normal file
39
src/main/java/appeng/services/version/ModVersionFetcher.java
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
package appeng.services.version;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for {@link VersionParser} to check if the check is happening in developer environment or in a pull request.
|
||||||
|
*
|
||||||
|
* In that case ignore the check.
|
||||||
|
*/
|
||||||
|
public final class ModVersionFetcher implements VersionFetcher
|
||||||
|
{
|
||||||
|
private final String rawModVersion;
|
||||||
|
private final VersionParser parser;
|
||||||
|
|
||||||
|
public ModVersionFetcher( String rawModVersion, VersionParser parser )
|
||||||
|
{
|
||||||
|
this.rawModVersion = rawModVersion;
|
||||||
|
this.parser = parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses only, if not checked in developer environment or in a pull request
|
||||||
|
*
|
||||||
|
* @return {@link DoNotCheckVersion} if in developer environment or pull request, else the parsed {@link Version}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Version get()
|
||||||
|
{
|
||||||
|
if ( this.rawModVersion.equals( "@version@" ) || this.rawModVersion.contains( "pr" ) )
|
||||||
|
{
|
||||||
|
return new DoNotCheckVersion();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
final Version version = this.parser.parse( this.rawModVersion );
|
||||||
|
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
42
src/main/java/appeng/services/version/Version.java
Normal file
42
src/main/java/appeng/services/version/Version.java
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
package appeng.services.version;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores version information, which are easily compared
|
||||||
|
*/
|
||||||
|
public interface Version
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return revision of this version
|
||||||
|
*/
|
||||||
|
int revision();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return channel of this version
|
||||||
|
*/
|
||||||
|
Channel channel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return build of this version
|
||||||
|
*/
|
||||||
|
int build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A version is never if these criteria are met:
|
||||||
|
* if the current revision is higher than the compared revision OR
|
||||||
|
* if revision are equal and the current channel is higher than the compared channel (Release > Beta > Alpha) OR
|
||||||
|
* if revision, channel are equal and the build is higher than the compared build
|
||||||
|
*
|
||||||
|
* @return true if criteria are met
|
||||||
|
*/
|
||||||
|
boolean isNewerAs( Version maybeOlder );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the revision, channel and build into a common displayed way
|
||||||
|
*
|
||||||
|
* rv2-beta-8
|
||||||
|
*
|
||||||
|
* @return formatted version
|
||||||
|
*/
|
||||||
|
String formatted();
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
package appeng.services.version;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import net.minecraftforge.common.config.Configuration;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seperate config file to handle the version checker
|
||||||
|
*/
|
||||||
|
public final class VersionCheckerConfig
|
||||||
|
{
|
||||||
|
private static final int DEFAULT_INTERVAL_HOURS = 24;
|
||||||
|
private static final int MIN_INTERVAL_HOURS = 0;
|
||||||
|
private static final int MAX_INTERVAL_HOURS = 7 * 24;
|
||||||
|
|
||||||
|
private final Configuration config;
|
||||||
|
|
||||||
|
private final boolean isEnabled;
|
||||||
|
|
||||||
|
private final String lastCheck;
|
||||||
|
private final int interval;
|
||||||
|
|
||||||
|
private final String level;
|
||||||
|
|
||||||
|
private final boolean shouldNotifyPlayer;
|
||||||
|
private final boolean shouldPostChangelog;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param file requires fully qualified file in which the config is saved
|
||||||
|
*/
|
||||||
|
public VersionCheckerConfig( File file )
|
||||||
|
{
|
||||||
|
this.config = new Configuration( file );
|
||||||
|
|
||||||
|
// initializes default values by caching
|
||||||
|
this.isEnabled = this.config.getBoolean( "enabled", "general", true, "If true, the version checker is enabled. Acts as a master switch." );
|
||||||
|
|
||||||
|
this.lastCheck = this.config.getString( "lastCheck", "cache", "0", "The number of milliseconds since January 1, 1970, 00:00:00 GMT of the last successful check." );
|
||||||
|
this.interval = this.config.getInt( "interval", "cache", DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_HOURS, MAX_INTERVAL_HOURS, "Waits as many hours, until it checks again." );
|
||||||
|
|
||||||
|
this.level = this.config.getString( "level", "channel", "Beta", "Determines the channel level which should be checked for updates. Can be either Release, Beta or Alpha." );
|
||||||
|
|
||||||
|
this.shouldNotifyPlayer = this.config.getBoolean( "notify", "client", true, "If true, the player is getting a notification, that a new version is available." );
|
||||||
|
this.shouldPostChangelog = this.config.getBoolean( "changelog", "client", true, "If true, the player is getting a notification including changelog. Only happens if notification are enabled." );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnabled()
|
||||||
|
{
|
||||||
|
return this.isEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String lastCheck()
|
||||||
|
{
|
||||||
|
return this.lastCheck;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the current date in milli seconds into the "lastCheck" field of the config
|
||||||
|
* and makes it persistent.
|
||||||
|
*/
|
||||||
|
public void updateLastCheck()
|
||||||
|
{
|
||||||
|
final Date now = new Date();
|
||||||
|
final long nowInMs = now.getTime();
|
||||||
|
final String nowAsString = Long.toString( nowInMs );
|
||||||
|
|
||||||
|
this.config.get( "cache", "lastCheck", "0" ).set( nowAsString );
|
||||||
|
|
||||||
|
this.config.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int interval()
|
||||||
|
{
|
||||||
|
return this.interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String level()
|
||||||
|
{
|
||||||
|
return this.level;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldNotifyPlayer()
|
||||||
|
{
|
||||||
|
return this.shouldNotifyPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldPostChangelog()
|
||||||
|
{
|
||||||
|
return this.shouldPostChangelog;
|
||||||
|
}
|
||||||
|
}
|
10
src/main/java/appeng/services/version/VersionFetcher.java
Normal file
10
src/main/java/appeng/services/version/VersionFetcher.java
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
package appeng.services.version;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes base information to retrieve a {@link Version}
|
||||||
|
*/
|
||||||
|
public interface VersionFetcher
|
||||||
|
{
|
||||||
|
Version get();
|
||||||
|
}
|
132
src/main/java/appeng/services/version/VersionParser.java
Normal file
132
src/main/java/appeng/services/version/VersionParser.java
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
package appeng.services.version;
|
||||||
|
|
||||||
|
|
||||||
|
import java.security.InvalidParameterException;
|
||||||
|
import java.util.Scanner;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* can parse a version in form of rv2-beta-8 or rv2.beta.8
|
||||||
|
*/
|
||||||
|
public final class VersionParser
|
||||||
|
{
|
||||||
|
private static final Pattern PATTERN_DOT = Pattern.compile( "\\." );
|
||||||
|
private static final Pattern PATTERN_DASH = Pattern.compile( "-" );
|
||||||
|
private static final Pattern PATTERN_REVISION = Pattern.compile( "[^0-9]+" );
|
||||||
|
private static final Pattern PATTERN_BUILD = Pattern.compile( "[^0-9]+" );
|
||||||
|
private static final Pattern PATTERN_NATURAL = Pattern.compile( "[0-9]+" );
|
||||||
|
private static final Pattern PATTERN_VALID_REVISION = Pattern.compile( "^rv\\d+$" );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the {@link Version} out of a String
|
||||||
|
*
|
||||||
|
* @param raw String in form of rv2-beta-8 or rv2.beta.8
|
||||||
|
*
|
||||||
|
* @return {@link Version} encoded in the raw String
|
||||||
|
*
|
||||||
|
* @throws AssertionError if raw String does not match pattern of a {@link Version}
|
||||||
|
*/
|
||||||
|
public Version parse( String raw )
|
||||||
|
{
|
||||||
|
final String transformed = this.transformDelimiter( raw );
|
||||||
|
final String[] split = transformed.split( "_" );
|
||||||
|
|
||||||
|
return this.parseVersion( split );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces all "." and "-" into "_" to make them uniform
|
||||||
|
*
|
||||||
|
* @param raw raw version string containing "." or "-"
|
||||||
|
*
|
||||||
|
* @return transformed raw, where "." and "-" are replaced by "_"
|
||||||
|
*/
|
||||||
|
private String transformDelimiter( String raw )
|
||||||
|
{
|
||||||
|
assert raw.contains( "." ) || raw.contains( "-" );
|
||||||
|
|
||||||
|
final String withoutDot = PATTERN_DOT.matcher( raw ).replaceAll( "_" );
|
||||||
|
final String withoutDash = PATTERN_DASH.matcher( withoutDot ).replaceAll( "_" );
|
||||||
|
|
||||||
|
return withoutDash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parses the {@link Version} out of the split.
|
||||||
|
* The split must have a length of 3,
|
||||||
|
* representing revision, channel and build.
|
||||||
|
*
|
||||||
|
* @param splitRaw raw version split with length of 3
|
||||||
|
*
|
||||||
|
* @return {@link Version} represented by the splitRaw
|
||||||
|
*/
|
||||||
|
private Version parseVersion( String[] splitRaw )
|
||||||
|
{
|
||||||
|
assert splitRaw.length == 3;
|
||||||
|
|
||||||
|
final String rawRevision = splitRaw[0];
|
||||||
|
final String rawChannel = splitRaw[1];
|
||||||
|
final String rawBuild = splitRaw[2];
|
||||||
|
|
||||||
|
final int revision = this.parseRevision( rawRevision );
|
||||||
|
final Channel channel = this.parseChannel( rawChannel );
|
||||||
|
final int build = this.parseBuild( rawBuild );
|
||||||
|
|
||||||
|
return new DefaultVersion( revision, channel, build );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A revision starts with the keyword "rv", followed by a natural number
|
||||||
|
*
|
||||||
|
* @param rawRevision String containing the revision number
|
||||||
|
*
|
||||||
|
* @return revision number
|
||||||
|
*/
|
||||||
|
private int parseRevision( String rawRevision )
|
||||||
|
{
|
||||||
|
assert PATTERN_VALID_REVISION.matcher( rawRevision ).matches();
|
||||||
|
|
||||||
|
final int revision = new Scanner( rawRevision ).useDelimiter( PATTERN_REVISION ).nextInt();
|
||||||
|
|
||||||
|
return revision;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A channel is atm either one of {@link Channel#Alpha}, {@link Channel#Beta} or {@link Channel#Release}
|
||||||
|
*
|
||||||
|
* @param rawChannel String containing the channel
|
||||||
|
*
|
||||||
|
* @return matching {@link Channel} to the String
|
||||||
|
*/
|
||||||
|
private Channel parseChannel( String rawChannel )
|
||||||
|
{
|
||||||
|
assert rawChannel.equalsIgnoreCase( Channel.Alpha.name() ) || rawChannel.equalsIgnoreCase( Channel.Beta.name() ) || rawChannel.equalsIgnoreCase( Channel.Release.name() );
|
||||||
|
|
||||||
|
for ( Channel channel : Channel.values() )
|
||||||
|
{
|
||||||
|
if ( channel.name().equalsIgnoreCase( rawChannel ) )
|
||||||
|
{
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidParameterException( "Raw channel did not contain any of the pre-programmed types." );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A build is just a natural number
|
||||||
|
*
|
||||||
|
* @param rawBuild String containing the build number
|
||||||
|
*
|
||||||
|
* @return build number
|
||||||
|
*/
|
||||||
|
private int parseBuild( String rawBuild )
|
||||||
|
{
|
||||||
|
assert PATTERN_NATURAL.matcher( rawBuild ).matches();
|
||||||
|
|
||||||
|
final int build = new Scanner( rawBuild ).useDelimiter( PATTERN_BUILD ).nextInt();
|
||||||
|
|
||||||
|
return build;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package appeng.services.version.github;
|
||||||
|
|
||||||
|
|
||||||
|
import appeng.services.version.Version;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default template when a {@link FormattedRelease} is needed.
|
||||||
|
*/
|
||||||
|
public final class DefaultFormattedRelease implements FormattedRelease
|
||||||
|
{
|
||||||
|
private final Version version;
|
||||||
|
private final String changelog;
|
||||||
|
|
||||||
|
public DefaultFormattedRelease( Version version, String changelog )
|
||||||
|
{
|
||||||
|
this.version = version;
|
||||||
|
this.changelog = changelog;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String changelog()
|
||||||
|
{
|
||||||
|
return this.changelog;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Version version()
|
||||||
|
{
|
||||||
|
return this.version;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package appeng.services.version.github;
|
||||||
|
|
||||||
|
|
||||||
|
import appeng.services.version.Version;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the acquired, processed information through github about a release of Applied Energistics 2
|
||||||
|
*/
|
||||||
|
public interface FormattedRelease
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return changelog
|
||||||
|
*/
|
||||||
|
String changelog();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return processed version
|
||||||
|
*/
|
||||||
|
Version version();
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package appeng.services.version.github;
|
||||||
|
|
||||||
|
|
||||||
|
import appeng.services.version.MissingVersion;
|
||||||
|
import appeng.services.version.Version;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exceptional template, when no meaningful {@link FormattedRelease} could be obtained
|
||||||
|
*/
|
||||||
|
public final class MissingFormattedRelease implements FormattedRelease
|
||||||
|
{
|
||||||
|
private final Version version;
|
||||||
|
|
||||||
|
public MissingFormattedRelease()
|
||||||
|
{
|
||||||
|
this.version = new MissingVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return empty string
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String changelog()
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {@link MissingVersion}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Version version()
|
||||||
|
{
|
||||||
|
return this.version;
|
||||||
|
}
|
||||||
|
}
|
19
src/main/java/appeng/services/version/github/Release.java
Normal file
19
src/main/java/appeng/services/version/github/Release.java
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
package appeng.services.version.github;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Template class for Gson to write values from the Json Object into an actual class
|
||||||
|
*/
|
||||||
|
@SuppressWarnings( "ALL" )
|
||||||
|
public class Release
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* name of the tag it is saved
|
||||||
|
*/
|
||||||
|
public String tag_name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains the changelog
|
||||||
|
*/
|
||||||
|
public String body;
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
package appeng.services.version.github;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
|
import appeng.core.AELog;
|
||||||
|
import appeng.services.version.Channel;
|
||||||
|
import appeng.services.version.Version;
|
||||||
|
import appeng.services.version.VersionCheckerConfig;
|
||||||
|
import appeng.services.version.VersionParser;
|
||||||
|
|
||||||
|
|
||||||
|
public final class ReleaseFetcher
|
||||||
|
{
|
||||||
|
private static final String GITHUB_RELEASES_URL = "https://api.github.com/repos/AppliedEnergistics/Applied-Energistics-2/releases";
|
||||||
|
private static final FormattedRelease EXCEPTIONAL_RELEASE = new MissingFormattedRelease();
|
||||||
|
|
||||||
|
private final VersionCheckerConfig config;
|
||||||
|
private final VersionParser parser;
|
||||||
|
|
||||||
|
public ReleaseFetcher( VersionCheckerConfig config, VersionParser parser )
|
||||||
|
{
|
||||||
|
this.config = config;
|
||||||
|
this.parser = parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FormattedRelease get()
|
||||||
|
{
|
||||||
|
final Gson gson = new Gson();
|
||||||
|
final Type type = new ReleasesTypeToken().getType();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
final URL releasesURL = new URL( GITHUB_RELEASES_URL );
|
||||||
|
final String rawReleases = this.getRawReleases( releasesURL );
|
||||||
|
|
||||||
|
this.config.updateLastCheck();
|
||||||
|
|
||||||
|
final List<Release> releases = gson.fromJson( rawReleases, type );
|
||||||
|
final FormattedRelease latestFitRelease = this.getLatestFitRelease( releases );
|
||||||
|
|
||||||
|
return latestFitRelease;
|
||||||
|
}
|
||||||
|
catch ( Exception e )
|
||||||
|
{
|
||||||
|
AELog.error( e );
|
||||||
|
|
||||||
|
return EXCEPTIONAL_RELEASE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getRawReleases( URL url ) throws IOException
|
||||||
|
{
|
||||||
|
return IOUtils.toString( url );
|
||||||
|
}
|
||||||
|
|
||||||
|
private FormattedRelease getLatestFitRelease( Iterable<Release> releases )
|
||||||
|
{
|
||||||
|
final String levelInConfig = this.config.level();
|
||||||
|
final Channel level = Channel.valueOf( levelInConfig );
|
||||||
|
final int levelOrdinal = level.ordinal();
|
||||||
|
|
||||||
|
for ( Release release : releases )
|
||||||
|
{
|
||||||
|
final String rawVersion = release.tag_name;
|
||||||
|
final String changelog = release.body;
|
||||||
|
|
||||||
|
final Version version = this.parser.parse( rawVersion );
|
||||||
|
|
||||||
|
if ( version.channel().ordinal() >= levelOrdinal )
|
||||||
|
{
|
||||||
|
return new DefaultFormattedRelease( version, changelog );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXCEPTIONAL_RELEASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class ReleasesTypeToken extends TypeToken<List<Release>>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
80
src/test/java/appeng/services/version/VersionParserTest.java
Normal file
80
src/test/java/appeng/services/version/VersionParserTest.java
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
package appeng.services.version;
|
||||||
|
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link VersionParser}
|
||||||
|
*/
|
||||||
|
public final class VersionParserTest
|
||||||
|
{
|
||||||
|
private static final String GITHUB_VERSION = "rv2.beta.8";
|
||||||
|
private static final String GITHUB_INVALID_REVISION = "2.beta.8";
|
||||||
|
private static final String GITHUB_INVALID_CHANNEL = "rv2.gamma.8";
|
||||||
|
private static final String GITHUB_INVALID_BUILD = "rv2.beta.b8";
|
||||||
|
private static final String MOD_VERSION = "rv2-beta-8";
|
||||||
|
private static final String MOD_INVALID_REVISION = "2-beta-8";
|
||||||
|
private static final String MOD_INVALID_CHANNEL = "rv2-gamma-8";
|
||||||
|
private static final String MOD_INVALID_BUILD = "rv2-beta-b8";
|
||||||
|
|
||||||
|
private static final DefaultVersion VERSION = new DefaultVersion( 2, Channel.Beta, 8 );
|
||||||
|
|
||||||
|
private final VersionParser parser;
|
||||||
|
|
||||||
|
public VersionParserTest()
|
||||||
|
{
|
||||||
|
this.parser = new VersionParser();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseGitHub_shouldPass()
|
||||||
|
{
|
||||||
|
assertTrue( this.parser.parse( GITHUB_VERSION ).equals( VERSION ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test( expected = AssertionError.class )
|
||||||
|
public void parseGH_InvalidRevision_NotPass()
|
||||||
|
{
|
||||||
|
assertFalse( this.parser.parse( GITHUB_INVALID_REVISION ).equals( VERSION ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test( expected = AssertionError.class )
|
||||||
|
public void parseGH_InvalidChannel_NotPass()
|
||||||
|
{
|
||||||
|
assertFalse( this.parser.parse( GITHUB_INVALID_CHANNEL ).equals( VERSION ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test( expected = AssertionError.class )
|
||||||
|
public void parseGH_InvalidBuild_NotPass()
|
||||||
|
{
|
||||||
|
assertFalse( this.parser.parse( GITHUB_INVALID_BUILD ).equals( VERSION ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseMod_shouldPass()
|
||||||
|
{
|
||||||
|
assertTrue( this.parser.parse( MOD_VERSION ).equals( VERSION ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test( expected = AssertionError.class )
|
||||||
|
public void parseMod_InvalidRevision_NotPass()
|
||||||
|
{
|
||||||
|
assertFalse( this.parser.parse( MOD_INVALID_REVISION ).equals( VERSION ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test( expected = AssertionError.class )
|
||||||
|
public void parseMod_InvalidChannel_NotPass()
|
||||||
|
{
|
||||||
|
assertFalse( this.parser.parse( MOD_INVALID_CHANNEL ).equals( VERSION ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test( expected = AssertionError.class )
|
||||||
|
public void parseMod_InvalidBuild_NotPass()
|
||||||
|
{
|
||||||
|
assertFalse( this.parser.parse( MOD_INVALID_BUILD ).equals( VERSION ) );
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,7 +28,7 @@ import static org.junit.Assert.assertTrue;
|
||||||
/**
|
/**
|
||||||
* Tests for {@link UUIDMatcher}
|
* Tests for {@link UUIDMatcher}
|
||||||
*/
|
*/
|
||||||
public class UUIDMatcherTest
|
public final class UUIDMatcherTest
|
||||||
{
|
{
|
||||||
private static final String IS_UUID = "03ba29a1-d6bd-32ba-90b2-375e4d65abc9";
|
private static final String IS_UUID = "03ba29a1-d6bd-32ba-90b2-375e4d65abc9";
|
||||||
private static final String NO_UUID = "no";
|
private static final String NO_UUID = "no";
|
||||||
|
|
1040
src/test/resources/appeng/services/version/releases.json
Normal file
1040
src/test/resources/appeng/services/version/releases.json
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue