8
8
9
9
import java .io .InputStream ;
10
10
import java .net .URL ;
11
+ import java .util .ArrayList ;
12
+ import java .util .Collections ;
13
+ import java .util .HashMap ;
14
+ import java .util .LinkedHashMap ;
15
+ import java .util .List ;
11
16
import java .util .Map ;
17
+ import java .util .Map .Entry ;
18
+ import java .util .concurrent .ConcurrentHashMap ;
19
+
20
+ import org .apache .logging .log4j .Level ;
12
21
13
22
import com .google .common .io .ByteStreams ;
14
23
import com .google .gson .Gson ;
15
24
16
- import net .minecraftforge .fml .common .versioning .ArtifactVersion ;
17
- import net .minecraftforge .fml .common .versioning .DefaultArtifactVersion ;
25
+ import net .minecraftforge .fml .common .FMLLog ;
26
+ import net .minecraftforge .fml .common .InjectedModContainer ;
27
+ import net .minecraftforge .fml .common .Loader ;
28
+ import net .minecraftforge .fml .common .ModContainer ;
29
+ import net .minecraftforge .fml .common .versioning .ComparableVersion ;
18
30
19
31
public class ForgeVersion
20
32
{
@@ -55,12 +67,13 @@ public static int getBuildVersion()
55
67
56
68
public static Status getStatus ()
57
69
{
58
- return status ;
70
+ return getResult ( ForgeModContainer . getInstance ()). status ;
59
71
}
60
72
61
73
public static String getTarget ()
62
74
{
63
- return target ;
75
+ CheckResult res = getResult (ForgeModContainer .getInstance ());
76
+ return res .target != null ? res .target .toString () : null ;
64
77
}
65
78
66
79
public static String getVersion ()
@@ -79,32 +92,75 @@ public static enum Status
79
92
BETA_OUTDATED
80
93
}
81
94
95
+ public static class CheckResult
96
+ {
97
+ public final Status status ;
98
+ public final ComparableVersion target ;
99
+ public final Map <ComparableVersion , String > changes ;
100
+ public final String url ;
101
+
102
+ private CheckResult (Status status , ComparableVersion target , Map <ComparableVersion , String > changes , String url )
103
+ {
104
+ this .status = status ;
105
+ this .target = target ;
106
+ this .changes = changes == null ? null : Collections .unmodifiableMap (changes );
107
+ this .url = url ;
108
+ }
109
+ }
110
+
82
111
public static void startVersionCheck ()
83
112
{
84
113
new Thread ("Forge Version Check" )
85
114
{
86
- @ SuppressWarnings ("unchecked" )
87
115
@ Override
88
116
public void run ()
117
+ {
118
+ if (!ForgeModContainer .getConfig ().get (ForgeModContainer .VERSION_CHECK_CAT , "Global" , true ).getBoolean ())
119
+ {
120
+ FMLLog .log ("ForgeVersionCheck" , Level .INFO , "Global Forge version check system disabeld, no futher processing." );
121
+ return ;
122
+ }
123
+
124
+ for (Entry <ModContainer , URL > entry : gatherMods ().entrySet ())
125
+ {
126
+ ModContainer mod = entry .getKey ();
127
+ if (ForgeModContainer .getConfig ().get (ForgeModContainer .VERSION_CHECK_CAT , mod .getModId (), true ).getBoolean ())
128
+ {
129
+ process (mod , entry .getValue ());
130
+ }
131
+ else
132
+ {
133
+ FMLLog .log ("ForgeVersionCheck" , Level .INFO , "[%s] Skipped version check" , mod .getModId ());
134
+ }
135
+ }
136
+ }
137
+
138
+ private void process (ModContainer mod , URL url )
89
139
{
90
140
try
91
141
{
92
- URL url = new URL ("http://files.minecraftforge.net/maven/net/minecraftforge/forge/promotions_slim.json" );
142
+ FMLLog .log ("ForgeVersionCheck" , Level .INFO , "[%s] Starting version check at %s" , mod .getModId (), url .toString ());
143
+ Status status = PENDING ;
144
+ ComparableVersion target = null ;
145
+
93
146
InputStream con = url .openStream ();
94
147
String data = new String (ByteStreams .toByteArray (con ));
95
148
con .close ();
96
149
150
+ FMLLog .log ("ForgeVersionCheck" , Level .DEBUG , "[%s] Received version check data:\n %s" , mod .getModId (), data );
151
+
152
+
97
153
Map <String , Object > json = new Gson ().fromJson (data , Map .class );
98
- //String homepage = (String)json.get("homepage");
99
154
Map <String , String > promos = (Map <String , String >)json .get ("promos" );
155
+ String display_url = (String )json .get ("homepage" );
100
156
101
157
String rec = promos .get (MinecraftForge .MC_VERSION + "-recommended" );
102
158
String lat = promos .get (MinecraftForge .MC_VERSION + "-latest" );
103
- ArtifactVersion current = new DefaultArtifactVersion ( getVersion ());
159
+ ComparableVersion current = new ComparableVersion ( mod . getVersion ());
104
160
105
161
if (rec != null )
106
162
{
107
- ArtifactVersion recommended = new DefaultArtifactVersion (rec );
163
+ ComparableVersion recommended = new ComparableVersion (rec );
108
164
int diff = recommended .compareTo (current );
109
165
110
166
if (diff == 0 )
@@ -114,39 +170,95 @@ else if (diff < 0)
114
170
status = AHEAD ;
115
171
if (lat != null )
116
172
{
117
- if (current .compareTo (new DefaultArtifactVersion (lat )) < 0 )
173
+ ComparableVersion latest = new ComparableVersion (lat );
174
+ if (current .compareTo (latest ) < 0 )
118
175
{
119
176
status = OUTDATED ;
120
- target = lat ;
177
+ target = latest ;
121
178
}
122
179
}
123
180
}
124
181
else
125
182
{
126
183
status = OUTDATED ;
127
- target = rec ;
184
+ target = recommended ;
128
185
}
129
186
}
130
187
else if (lat != null )
131
188
{
132
- if (current .compareTo (new DefaultArtifactVersion (lat )) < 0 )
189
+ ComparableVersion latest = new ComparableVersion (lat );
190
+ if (current .compareTo (latest ) < 0 )
133
191
{
134
192
status = BETA_OUTDATED ;
135
- target = lat ;
193
+ target = latest ;
136
194
}
137
195
else
138
196
status = BETA ;
139
197
}
140
198
else
141
199
status = BETA ;
200
+
201
+ FMLLog .log ("ForgeVersionCheck" , Level .INFO , "[%s] Found status: %s Target: %s" , mod .getModId (), status , target );
202
+
203
+ Map <ComparableVersion , String > changes = new LinkedHashMap <ComparableVersion , String >();
204
+ Map <String , String > tmp = (Map <String , String >)json .get (MinecraftForge .MC_VERSION );
205
+ if (tmp != null )
206
+ {
207
+ List <ComparableVersion > ordered = new ArrayList <ComparableVersion >();
208
+ for (String key : tmp .keySet ())
209
+ {
210
+ ComparableVersion ver = new ComparableVersion (key );
211
+ if (ver .compareTo (current ) > 0 && (target == null || ver .compareTo (target ) < 1 ))
212
+ {
213
+ ordered .add (ver );
214
+ }
215
+ }
216
+ Collections .sort (ordered );
217
+
218
+ for (ComparableVersion ver : ordered )
219
+ {
220
+ changes .put (ver , tmp .get (ver .toString ()));
221
+ }
222
+ }
223
+ if (mod instanceof InjectedModContainer )
224
+ mod = ((InjectedModContainer )mod ).wrappedContainer ;
225
+ results .put (mod , new CheckResult (status , target , changes , display_url ));
142
226
}
143
227
catch (Exception e )
144
228
{
145
- e . printStackTrace ( );
229
+ FMLLog . log ( "ForgeVersionCheck" , Level . DEBUG , e , "Failed to process update information" );
146
230
status = FAILED ;
147
231
}
148
232
}
149
233
}.start ();
150
234
}
235
+
236
+ // Gather a list of mods that have opted in to this update system by providing a URL.
237
+ // Small hack needed to support a interface change until we force a recompile.
238
+ public static Map <ModContainer , URL > gatherMods ()
239
+ {
240
+ Map <ModContainer , URL > ret = new HashMap <ModContainer , URL >();
241
+ for (ModContainer mod : Loader .instance ().getActiveModList ())
242
+ {
243
+ URL url = null ;
244
+ try {
245
+ url = mod .getUpdateUrl ();
246
+ } catch (AbstractMethodError abs ) { } //TODO: Remove this in 1.8.8+?
247
+ if (url != null )
248
+ ret .put (mod , url );
249
+ }
250
+ return ret ;
251
+ }
252
+
253
+ private static Map <ModContainer , CheckResult > results = new ConcurrentHashMap <ModContainer , CheckResult >();
254
+ private static final CheckResult PENDING_CHECK = new CheckResult (PENDING , null , null , null );
255
+
256
+ public static CheckResult getResult (ModContainer mod )
257
+ {
258
+ if (mod instanceof InjectedModContainer )
259
+ mod = ((InjectedModContainer )mod ).wrappedContainer ;
260
+ CheckResult ret = results .get (mod );
261
+ return ret == null ? PENDING_CHECK : ret ;
262
+ }
151
263
}
152
264