2016-06-23 03:49:47 +00:00
|
|
|
/*
|
|
|
|
* Minecraft Forge
|
|
|
|
* Copyright (c) 2016.
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2012-08-05 05:45:31 +00:00
|
|
|
/**
|
|
|
|
* This software is provided under the terms of the Minecraft Forge Public
|
|
|
|
* License v1.0.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package net.minecraftforge.common;
|
2013-12-25 08:35:59 +00:00
|
|
|
import static net.minecraftforge.common.ForgeVersion.Status.*;
|
|
|
|
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.net.URL;
|
2015-11-04 22:37:15 +00:00
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.LinkedHashMap;
|
|
|
|
import java.util.List;
|
2013-12-25 08:35:59 +00:00
|
|
|
import java.util.Map;
|
2015-11-04 22:37:15 +00:00
|
|
|
import java.util.Map.Entry;
|
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
|
|
|
|
import org.apache.logging.log4j.Level;
|
2017-06-23 05:33:11 +00:00
|
|
|
import org.apache.logging.log4j.LogManager;
|
|
|
|
import org.apache.logging.log4j.Logger;
|
2013-12-25 08:35:59 +00:00
|
|
|
|
|
|
|
import com.google.common.io.ByteStreams;
|
|
|
|
import com.google.gson.Gson;
|
|
|
|
|
2015-11-04 22:37:15 +00:00
|
|
|
import net.minecraftforge.fml.common.FMLLog;
|
|
|
|
import net.minecraftforge.fml.common.InjectedModContainer;
|
|
|
|
import net.minecraftforge.fml.common.Loader;
|
|
|
|
import net.minecraftforge.fml.common.ModContainer;
|
|
|
|
import net.minecraftforge.fml.common.versioning.ComparableVersion;
|
2012-08-05 05:45:31 +00:00
|
|
|
|
2017-01-11 23:17:56 +00:00
|
|
|
import javax.annotation.Nullable;
|
|
|
|
|
2012-08-05 05:45:31 +00:00
|
|
|
public class ForgeVersion
|
|
|
|
{
|
2016-12-17 21:23:39 +00:00
|
|
|
// This is Forge's Mod Id, used for the ForgeModContainer and resource locations
|
|
|
|
public static final String MOD_ID = "forge";
|
2012-11-03 05:16:32 +00:00
|
|
|
//This number is incremented every time we remove deprecated code/major API changes, never reset
|
2017-06-05 21:04:10 +00:00
|
|
|
public static final int majorVersion = 14;
|
2012-11-03 05:16:32 +00:00
|
|
|
//This number is incremented every minecraft release, never reset
|
2017-06-05 21:04:10 +00:00
|
|
|
public static final int minorVersion = 21;
|
2012-09-21 02:53:43 +00:00
|
|
|
//This number is incremented every time a interface changes or new major feature is added, and reset every Minecraft version
|
2016-12-27 05:34:18 +00:00
|
|
|
public static final int revisionVersion = 0;
|
2012-08-05 05:45:31 +00:00
|
|
|
//This number is incremented every time Jenkins builds Forge, and never reset. Should always be 0 in the repo code.
|
2016-06-23 06:46:02 +00:00
|
|
|
public static final int buildVersion = 0;
|
2015-08-02 04:20:19 +00:00
|
|
|
// This is the minecraft version we're building for - used in various places in Forge/FML code
|
2017-06-05 21:04:10 +00:00
|
|
|
public static final String mcVersion = "1.12";
|
2015-08-02 04:20:19 +00:00
|
|
|
// This is the MCP data version we're using
|
2017-06-05 21:04:10 +00:00
|
|
|
public static final String mcpVersion = "9.40";
|
2015-11-13 15:13:47 +00:00
|
|
|
@SuppressWarnings("unused")
|
2013-12-25 08:35:59 +00:00
|
|
|
private static Status status = PENDING;
|
2015-11-13 15:13:47 +00:00
|
|
|
@SuppressWarnings("unused")
|
2013-12-25 08:35:59 +00:00
|
|
|
private static String target = null;
|
|
|
|
|
2017-06-23 05:33:11 +00:00
|
|
|
private static final Logger log = LogManager.getLogger("ForgeVersionCheck");
|
|
|
|
|
2012-08-05 05:45:31 +00:00
|
|
|
public static int getMajorVersion()
|
|
|
|
{
|
|
|
|
return majorVersion;
|
|
|
|
}
|
2012-10-03 06:00:19 +00:00
|
|
|
|
2012-08-05 05:45:31 +00:00
|
|
|
public static int getMinorVersion()
|
|
|
|
{
|
|
|
|
return minorVersion;
|
|
|
|
}
|
2012-10-03 06:00:19 +00:00
|
|
|
|
2012-08-05 05:45:31 +00:00
|
|
|
public static int getRevisionVersion()
|
|
|
|
{
|
|
|
|
return revisionVersion;
|
|
|
|
}
|
2012-10-03 06:00:19 +00:00
|
|
|
|
2012-08-05 05:45:31 +00:00
|
|
|
public static int getBuildVersion()
|
|
|
|
{
|
|
|
|
return buildVersion;
|
|
|
|
}
|
2012-10-03 06:00:19 +00:00
|
|
|
|
2013-12-25 08:35:59 +00:00
|
|
|
public static Status getStatus()
|
|
|
|
{
|
2015-11-04 22:37:15 +00:00
|
|
|
return getResult(ForgeModContainer.getInstance()).status;
|
2013-12-25 08:35:59 +00:00
|
|
|
}
|
|
|
|
|
2017-01-11 23:17:56 +00:00
|
|
|
@Nullable
|
2013-12-25 08:35:59 +00:00
|
|
|
public static String getTarget()
|
|
|
|
{
|
2015-11-04 22:37:15 +00:00
|
|
|
CheckResult res = getResult(ForgeModContainer.getInstance());
|
|
|
|
return res.target != null ? res.target.toString() : null;
|
2013-12-25 08:35:59 +00:00
|
|
|
}
|
|
|
|
|
2012-08-05 05:45:31 +00:00
|
|
|
public static String getVersion()
|
|
|
|
{
|
|
|
|
return String.format("%d.%d.%d.%d", majorVersion, minorVersion, revisionVersion, buildVersion);
|
|
|
|
}
|
2013-12-25 08:35:59 +00:00
|
|
|
|
|
|
|
public static enum Status
|
|
|
|
{
|
2016-03-23 13:48:29 +00:00
|
|
|
PENDING(),
|
|
|
|
FAILED(),
|
|
|
|
UP_TO_DATE(),
|
|
|
|
OUTDATED(3, true),
|
|
|
|
AHEAD(),
|
|
|
|
BETA(),
|
|
|
|
BETA_OUTDATED(6, true);
|
2016-05-04 06:19:51 +00:00
|
|
|
|
2016-03-23 13:48:29 +00:00
|
|
|
final int sheetOffset;
|
|
|
|
final boolean draw, animated;
|
|
|
|
|
|
|
|
Status()
|
|
|
|
{
|
|
|
|
this(0, false, false);
|
|
|
|
}
|
2016-05-04 06:19:51 +00:00
|
|
|
|
2016-03-23 13:48:29 +00:00
|
|
|
Status(int sheetOffset)
|
|
|
|
{
|
|
|
|
this(sheetOffset, true, false);
|
|
|
|
}
|
2016-05-04 06:19:51 +00:00
|
|
|
|
2016-03-23 13:48:29 +00:00
|
|
|
Status(int sheetOffset, boolean animated)
|
|
|
|
{
|
|
|
|
this(sheetOffset, true, animated);
|
|
|
|
}
|
2016-05-04 06:19:51 +00:00
|
|
|
|
2016-03-23 13:48:29 +00:00
|
|
|
Status(int sheetOffset, boolean draw, boolean animated)
|
|
|
|
{
|
|
|
|
this.sheetOffset = sheetOffset;
|
|
|
|
this.draw = draw;
|
|
|
|
this.animated = animated;
|
|
|
|
}
|
2016-05-04 06:19:51 +00:00
|
|
|
|
2016-03-23 13:48:29 +00:00
|
|
|
public int getSheetOffset()
|
|
|
|
{
|
|
|
|
return sheetOffset;
|
|
|
|
}
|
2016-05-04 06:19:51 +00:00
|
|
|
|
2016-03-23 13:48:29 +00:00
|
|
|
public boolean shouldDraw()
|
|
|
|
{
|
|
|
|
return draw;
|
|
|
|
}
|
2016-05-04 06:19:51 +00:00
|
|
|
|
2016-03-23 13:48:29 +00:00
|
|
|
public boolean isAnimated()
|
|
|
|
{
|
|
|
|
return animated;
|
|
|
|
}
|
2016-05-04 06:19:51 +00:00
|
|
|
|
2013-12-25 08:35:59 +00:00
|
|
|
}
|
|
|
|
|
2015-11-04 22:37:15 +00:00
|
|
|
public static class CheckResult
|
|
|
|
{
|
|
|
|
public final Status status;
|
2017-01-11 23:17:56 +00:00
|
|
|
@Nullable
|
2015-11-04 22:37:15 +00:00
|
|
|
public final ComparableVersion target;
|
|
|
|
public final Map<ComparableVersion, String> changes;
|
2017-01-11 23:17:56 +00:00
|
|
|
@Nullable
|
2015-11-04 22:37:15 +00:00
|
|
|
public final String url;
|
|
|
|
|
2017-01-11 23:17:56 +00:00
|
|
|
private CheckResult(Status status, @Nullable ComparableVersion target, @Nullable Map<ComparableVersion, String> changes, @Nullable String url)
|
2015-11-04 22:37:15 +00:00
|
|
|
{
|
|
|
|
this.status = status;
|
|
|
|
this.target = target;
|
2017-01-11 23:17:56 +00:00
|
|
|
this.changes = changes == null ? Collections.<ComparableVersion, String>emptyMap() : Collections.unmodifiableMap(changes);
|
2015-11-04 22:37:15 +00:00
|
|
|
this.url = url;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-25 08:35:59 +00:00
|
|
|
public static void startVersionCheck()
|
|
|
|
{
|
|
|
|
new Thread("Forge Version Check")
|
|
|
|
{
|
|
|
|
@Override
|
|
|
|
public void run()
|
2015-11-04 22:37:15 +00:00
|
|
|
{
|
|
|
|
if (!ForgeModContainer.getConfig().get(ForgeModContainer.VERSION_CHECK_CAT, "Global", true).getBoolean())
|
|
|
|
{
|
2017-06-23 05:33:11 +00:00
|
|
|
log.info("Global Forge version check system disabled, no further processing.");
|
2015-11-04 22:37:15 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (Entry<ModContainer, URL> entry : gatherMods().entrySet())
|
|
|
|
{
|
|
|
|
ModContainer mod = entry.getKey();
|
|
|
|
if (ForgeModContainer.getConfig().get(ForgeModContainer.VERSION_CHECK_CAT, mod.getModId(), true).getBoolean())
|
|
|
|
{
|
|
|
|
process(mod, entry.getValue());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-06-23 05:33:11 +00:00
|
|
|
log.info("[{}] Skipped version check", mod.getModId());
|
2015-11-04 22:37:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void process(ModContainer mod, URL url)
|
2013-12-25 08:35:59 +00:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2017-06-23 05:33:11 +00:00
|
|
|
log.info("[{}] Starting version check at {}", mod.getModId(), url.toString());
|
2015-11-04 22:37:15 +00:00
|
|
|
Status status = PENDING;
|
|
|
|
ComparableVersion target = null;
|
|
|
|
|
2013-12-25 08:35:59 +00:00
|
|
|
InputStream con = url.openStream();
|
2016-06-11 20:06:38 +00:00
|
|
|
String data = new String(ByteStreams.toByteArray(con), "UTF-8");
|
2013-12-25 08:35:59 +00:00
|
|
|
con.close();
|
|
|
|
|
2017-06-23 05:33:11 +00:00
|
|
|
log.debug("[{}] Received version check data:\n{}", mod.getModId(), data);
|
2015-11-04 22:37:15 +00:00
|
|
|
|
|
|
|
|
2015-11-13 15:13:47 +00:00
|
|
|
@SuppressWarnings("unchecked")
|
2013-12-25 08:35:59 +00:00
|
|
|
Map<String, Object> json = new Gson().fromJson(data, Map.class);
|
2015-11-13 15:13:47 +00:00
|
|
|
@SuppressWarnings("unchecked")
|
2013-12-25 08:35:59 +00:00
|
|
|
Map<String, String> promos = (Map<String, String>)json.get("promos");
|
2015-11-04 22:37:15 +00:00
|
|
|
String display_url = (String)json.get("homepage");
|
2013-12-25 08:35:59 +00:00
|
|
|
|
|
|
|
String rec = promos.get(MinecraftForge.MC_VERSION + "-recommended");
|
|
|
|
String lat = promos.get(MinecraftForge.MC_VERSION + "-latest");
|
2015-11-04 22:37:15 +00:00
|
|
|
ComparableVersion current = new ComparableVersion(mod.getVersion());
|
2013-12-25 08:35:59 +00:00
|
|
|
|
|
|
|
if (rec != null)
|
|
|
|
{
|
2015-11-04 22:37:15 +00:00
|
|
|
ComparableVersion recommended = new ComparableVersion(rec);
|
2013-12-25 08:35:59 +00:00
|
|
|
int diff = recommended.compareTo(current);
|
|
|
|
|
|
|
|
if (diff == 0)
|
|
|
|
status = UP_TO_DATE;
|
|
|
|
else if (diff < 0)
|
|
|
|
{
|
|
|
|
status = AHEAD;
|
|
|
|
if (lat != null)
|
|
|
|
{
|
2015-11-04 22:37:15 +00:00
|
|
|
ComparableVersion latest = new ComparableVersion(lat);
|
|
|
|
if (current.compareTo(latest) < 0)
|
2013-12-25 08:35:59 +00:00
|
|
|
{
|
|
|
|
status = OUTDATED;
|
2015-11-04 22:37:15 +00:00
|
|
|
target = latest;
|
2013-12-25 08:35:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
status = OUTDATED;
|
2015-11-04 22:37:15 +00:00
|
|
|
target = recommended;
|
2013-12-25 08:35:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (lat != null)
|
|
|
|
{
|
2015-11-04 22:37:15 +00:00
|
|
|
ComparableVersion latest = new ComparableVersion(lat);
|
|
|
|
if (current.compareTo(latest) < 0)
|
2013-12-25 08:35:59 +00:00
|
|
|
{
|
|
|
|
status = BETA_OUTDATED;
|
2015-11-04 22:37:15 +00:00
|
|
|
target = latest;
|
2013-12-25 08:35:59 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
status = BETA;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
status = BETA;
|
2015-11-04 22:37:15 +00:00
|
|
|
|
2017-06-23 05:33:11 +00:00
|
|
|
log.info("[{}] Found status: {} Target: {}", mod.getModId(), status, target);
|
2015-11-04 22:37:15 +00:00
|
|
|
|
|
|
|
Map<ComparableVersion, String> changes = new LinkedHashMap<ComparableVersion, String>();
|
2015-11-13 15:13:47 +00:00
|
|
|
@SuppressWarnings("unchecked")
|
2015-11-04 22:37:15 +00:00
|
|
|
Map<String, String> tmp = (Map<String, String>)json.get(MinecraftForge.MC_VERSION);
|
|
|
|
if (tmp != null)
|
|
|
|
{
|
|
|
|
List<ComparableVersion> ordered = new ArrayList<ComparableVersion>();
|
|
|
|
for (String key : tmp.keySet())
|
|
|
|
{
|
|
|
|
ComparableVersion ver = new ComparableVersion(key);
|
|
|
|
if (ver.compareTo(current) > 0 && (target == null || ver.compareTo(target) < 1))
|
|
|
|
{
|
|
|
|
ordered.add(ver);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Collections.sort(ordered);
|
|
|
|
|
|
|
|
for (ComparableVersion ver : ordered)
|
|
|
|
{
|
|
|
|
changes.put(ver, tmp.get(ver.toString()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (mod instanceof InjectedModContainer)
|
|
|
|
mod = ((InjectedModContainer)mod).wrappedContainer;
|
|
|
|
results.put(mod, new CheckResult(status, target, changes, display_url));
|
2013-12-25 08:35:59 +00:00
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
2017-06-23 05:33:11 +00:00
|
|
|
log.debug("Failed to process update information", e);
|
2013-12-25 08:35:59 +00:00
|
|
|
status = FAILED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}.start();
|
|
|
|
}
|
2015-11-04 22:37:15 +00:00
|
|
|
|
|
|
|
// Gather a list of mods that have opted in to this update system by providing a URL.
|
|
|
|
public static Map<ModContainer, URL> gatherMods()
|
|
|
|
{
|
|
|
|
Map<ModContainer, URL> ret = new HashMap<ModContainer, URL>();
|
|
|
|
for (ModContainer mod : Loader.instance().getActiveModList())
|
|
|
|
{
|
2016-03-09 22:52:32 +00:00
|
|
|
URL url = mod.getUpdateUrl();
|
2015-11-04 22:37:15 +00:00
|
|
|
if (url != null)
|
|
|
|
ret.put(mod, url);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static Map<ModContainer, CheckResult> results = new ConcurrentHashMap<ModContainer, CheckResult>();
|
|
|
|
private static final CheckResult PENDING_CHECK = new CheckResult(PENDING, null, null, null);
|
|
|
|
|
|
|
|
public static CheckResult getResult(ModContainer mod)
|
|
|
|
{
|
2015-11-09 04:09:33 +00:00
|
|
|
if (mod == null) return PENDING_CHECK;
|
2015-11-04 22:37:15 +00:00
|
|
|
if (mod instanceof InjectedModContainer)
|
|
|
|
mod = ((InjectedModContainer)mod).wrappedContainer;
|
|
|
|
CheckResult ret = results.get(mod);
|
|
|
|
return ret == null ? PENDING_CHECK : ret;
|
|
|
|
}
|
2012-08-05 05:45:31 +00:00
|
|
|
}
|
|
|
|
|