package pneumaticCraft.common; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; import java.util.ArrayList; import java.util.List; import net.minecraft.command.CommandBase; import net.minecraft.command.ICommandSender; import net.minecraft.command.WrongUsageException; import net.minecraft.util.ChatComponentTranslation; import net.minecraftforge.common.config.Configuration; import pneumaticCraft.common.config.Config; import pneumaticCraft.lib.Log; import pneumaticCraft.lib.Versions; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.eventhandler.SubscribeEvent; import cpw.mods.fml.common.gameevent.TickEvent; public class UpdateChecker extends Thread{ private static UpdateChecker INSTANCE = new UpdateChecker(); private final String url = "http://www.minemaarten.com/downloads/pneumaticcraft-changelog/pneumaticcraft-"; private boolean doneChecking; private boolean hasNewVersion; private final List<String> additions = new ArrayList<String>(); private final List<String> apiChanges = new ArrayList<String>(); private final List<String> bugfixes = new ArrayList<String>(); private String latestVersion, updateSize; private int displayDelay = 200;//build in a delay, as many mods display it on right away, I'll wait a few seconds until their spam is gone (A). public static UpdateChecker instance(){ return INSTANCE; } @Override public void run(){ checkForUpdate(); } @SubscribeEvent public void onTick(TickEvent.PlayerTickEvent event){ if(event.phase == TickEvent.Phase.END && event.player.worldObj.isRemote) { if(displayDelay > 0) displayDelay--; if(doneChecking && displayDelay == 0) { if(hasNewVersion) { sendMessage(event.player, "There's a new " + updateSize + " version of PneumaticCraft available: version " + latestVersion + " (you are running " + Versions.fullVersionString() + ")."); sendMessage(event.player, "Use '/pc changelog' to see what has changed."); } FMLCommonHandler.instance().bus().unregister(this); } } } private static void sendMessage(ICommandSender player, List<String> message){ for(String s : message) { sendMessage(player, s); } } private static void sendMessage(ICommandSender player, String message){ player.addChatMessage(new ChatComponentTranslation(message)); } private void checkForUpdate(){ int versionNumbers = 3; latestVersion = Versions.fullVersionString(); int changeSize = 10000; try { getPage(url + latestVersion.replace('.', '-') + "/"); int curDigit = versionNumbers - 1; while(curDigit >= 0) { try { String checkingVersion = incVersion(latestVersion, curDigit); String totalText = getPage(url + checkingVersion.replace('.', '-') + "/"); if(totalText.contains("It looks like nothing was found at this location. Maybe try a search?")) { curDigit--; } else { // String totalText = new System.Net.WebClient().DownloadString(Constants.URL + checkingVersion.Replace('.', '-') + "/"); String[] text = totalText.replace("<br />", "").replace("<p>", "").replace("</p>", "").replace("\t", "").replace("</a>", "").replace("’", "'").replace("‘", "'").replace("…", "...").split(System.getProperty("line.separator")); boolean parsingContent = false; for(String line : text) { if(line.contains("entry-content")) { if(parsingContent) { break; } else { parsingContent = true; } } else if(parsingContent) { if(line.startsWith("-Bugfix")) { bugfixes.add(line); } else if(line.startsWith("-API")) { apiChanges.add(line); } else { additions.add(line); } } } latestVersion = checkingVersion; changeSize = changeSize > curDigit ? curDigit : changeSize; curDigit = versionNumbers - 1; } } catch(IOException e) { curDigit--; } } if(changeSize < 10000) { updateSize = new String[]{"Massive", "Major", "Minor"}[changeSize]; Log.info("New " + updateSize + " update available: " + latestVersion); hasNewVersion = true; } else { Log.info("Up to date!"); } doneChecking = true; } catch(IOException e) { Log.error("The URL of the current version changed, the current running version is weirdly formatted (dev version?), minemaarten.com is down or there is a problem with your internet connection."); } } private String incVersion(String version, int digit){ String[] numStrings = version.split("\\."); int[] nums = new int[numStrings.length]; for(int i = 0; i < nums.length; i++) { nums[i] = Integer.parseInt(numStrings[i]); } nums[digit]++; for(int i = digit + 1; digit != 0 && i < nums.length; i++) { nums[i] = 0; } String newVersion = Integer.toString(nums[0]); for(int i = 1; i < nums.length; i++) { newVersion += "." + nums[i]; } return newVersion; } public static String getPage(final String URL) throws IOException{ String line = "", all = ""; URL myUrl = null; BufferedReader in = null; try { myUrl = new URL(URL); in = new BufferedReader(new InputStreamReader(myUrl.openStream())); while((line = in.readLine()) != null) { all += line + System.getProperty("line.separator"); } } finally { if(in != null) { in.close(); } } return all; } public static class CommandChangelog extends CommandBase{ @Override public String getCommandName(){ return "pc"; } @Override public int getRequiredPermissionLevel(){ return -100;//everyone can use it } @Override public String getCommandUsage(ICommandSender icommandsender){ return "/pc changelog [<additions/apichanges/bugfixes/true/false>]"; } @Override public void processCommand(ICommandSender icommandsender, String[] astring){ if(astring.length > 0 && astring[0].equalsIgnoreCase("changelog")) { if(astring.length > 1) { if(astring[1].equalsIgnoreCase("additions")) { if(instance().additions.size() > 0) { sendMessage(icommandsender, "-----Additions-----"); sendMessage(icommandsender, instance().additions); } else { sendMessage(icommandsender, "No additions in the newest PneumaticCraft. :("); } } else if(astring[1].equalsIgnoreCase("apichanges")) { if(instance().apiChanges.size() > 0) { sendMessage(icommandsender, "-----API Changes-----"); sendMessage(icommandsender, instance().apiChanges); } else { sendMessage(icommandsender, "No API changes in the newest PneumaticCraft."); } } else if(astring[1].equalsIgnoreCase("bugfixes")) { if(instance().bugfixes.size() > 0) { sendMessage(icommandsender, "-----Bugfixes-----"); sendMessage(icommandsender, instance().bugfixes); } else { sendMessage(icommandsender, "No bugfixes in the newest PneumaticCraft."); } } else if(astring[1].equalsIgnoreCase("true")) { sendMessage(icommandsender, "You'll now get a notification when a new version of PneumaticCraft is released. Checking now..."); Config.config.get(Configuration.CATEGORY_GENERAL, "Enable Update Checker", true).set(true); Config.config.save(); //if(Config.enableUpdateChecker) FMLCommonHandler.instance().bus().unregister(instance()); causes NPE for some reason... INSTANCE = new UpdateChecker();//reset variables, prevent thread from running twice. instance().displayDelay = 0; FMLCommonHandler.instance().bus().register(instance()); instance().start(); Config.enableUpdateChecker = true; } else if(astring[1].equalsIgnoreCase("false")) { sendMessage(icommandsender, "You'll no longer get a notification when there's a new version of PneumaticCraft available."); Config.config.get(Configuration.CATEGORY_GENERAL, "Enable Update Checker", true).set(false); Config.config.save(); // if(Config.enableUpdateChecker) FMLCommonHandler.instance().bus().unregister(instance());//save cpu time by unsubscribing to the tickevent. //causes NPE for some reason. Config.enableUpdateChecker = false; } else { throw new WrongUsageException(getCommandUsage(icommandsender)); } } else { if(instance().additions.size() > 0) { sendMessage(icommandsender, "-----Additions-----"); sendMessage(icommandsender, instance().additions); } if(instance().apiChanges.size() > 0) { sendMessage(icommandsender, "-----API Changes-----"); sendMessage(icommandsender, instance().apiChanges); } if(instance().bugfixes.size() > 0) { sendMessage(icommandsender, "-----Bugfixes-----"); sendMessage(icommandsender, instance().bugfixes); } } } else { throw new WrongUsageException(getCommandUsage(icommandsender)); } } } }