Mojira Archive
MCL-8475

Launcher incorrectly serializes version data

The bug

The Java launcher incorrectly serializes version data of the new format. This prevents playing versions which use the new version file format in offline mode.

How to reproduce

  1. Start a Minecraft version higher than or equal to 17w43b
  2. Look in the Launcher Log tab of your launcher
    → The following error was logged
    [19:16:51 INFO]: Refreshing local version list...
    [19:16:51 ERROR]: Couldn't load local version .minecraft\versions\17w43b\17w43b.json
    java.lang.NullPointerException
    	at net.minecraft.launcher.updater.Argument$Serializer.deserialize(Argument.java:56) ~[launcher.jar:1.6.84-j]
    	at net.minecraft.launcher.updater.Argument$Serializer.deserialize(Argument.java:46) ~[launcher.jar:1.6.84-j]
    	at com.google.gson.TreeTypeAdapter.read(TreeTypeAdapter.java:58) ~[launcher.jar:1.6.84-j]
    	at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40) ~[launcher.jar:1.6.84-j]
    	at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:81) ~[launcher.jar:1.6.84-j]
    	at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:60) ~[launcher.jar:1.6.84-j]
    	at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40) ~[launcher.jar:1.6.84-j]
    	at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:187) ~[launcher.jar:1.6.84-j]
    	at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:145) ~[launcher.jar:1.6.84-j]
    	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:93) ~[launcher.jar:1.6.84-j]
    	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:172) ~[launcher.jar:1.6.84-j]
    	at com.google.gson.Gson.fromJson(Gson.java:803) ~[launcher.jar:1.6.84-j]
    	at com.google.gson.Gson.fromJson(Gson.java:768) ~[launcher.jar:1.6.84-j]
    	at com.google.gson.Gson.fromJson(Gson.java:717) ~[launcher.jar:1.6.84-j]
    	at com.google.gson.Gson.fromJson(Gson.java:689) ~[launcher.jar:1.6.84-j]
    	at net.minecraft.launcher.updater.LocalVersionList.refreshVersions(LocalVersionList.java:46) [launcher.jar:1.6.84-j]
    	at net.minecraft.launcher.updater.MinecraftVersionManager.refreshVersions(MinecraftVersionManager.java:60) [launcher.jar:1.6.84-j]
    	at net.minecraft.launcher.Launcher$3.run(Launcher.java:184) [launcher.jar:1.6.84-j]
    	at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) [?:1.8.0_151]
    	at java.util.concurrent.FutureTask.run(Unknown Source) [?:1.8.0_151]
    	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [?:1.8.0_151]
    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [?:1.8.0_151]
    	at java.lang.Thread.run(Unknown Source) [?:1.8.0_151]
    

Code analysis

The problem is caused by the class net.minecraft.launcher.updater.Argument. This class is missing a proper serializer and therefore when called by net.minecraft.launcher.updater.VersionList.serializeVersion(CompleteVersion) all fields are serialized. This causes two problems:

  • Deserializing requires a key value, but the field is called values
  • For rules the key rules is expected, but the field is called compatibilityRules

The following is rough implementation added to the class net.minecraft.launcher.updater.Argument.Serializer after having it implement com.google.gson.JsonSerializer<Argument> as well. Please verify that this works as expected and does not miss any corner case before implementing it.

@Override
public JsonElement serialize(Argument argument, Type type, JsonSerializationContext serializationContext) {
    if (argument.values.length == 0) {
        throw new IllegalStateException("Don't know how to serialize Argument with no values");
    }
    else if (argument.values.length == 1 && (argument.compatibilityRules == null || argument.compatibilityRules.isEmpty())) {
        return new JsonPrimitive(argument.values[0]);
    }
    else {
        JsonObject argumentObject = new JsonObject();
        
        if (argument.values.length == 1) {
            argumentObject.addProperty("value", argument.values[0]);
        }
        else {
            argumentObject.add("value", serializationContext.serialize(argument.values));
        }
        
        if (!(argument.compatibilityRules == null || argument.compatibilityRules.isEmpty())) {
            argumentObject.add("rules", serializationContext.serialize(argument.compatibilityRules, new TypeToken<ArrayList<CompatibilityRule>>(){}.getType()));
        }
        
        return argumentObject;
    }
}

Affected versions

Currently tracked here since selectable launcher versions here in Mojira are not always up to date

  • 1.6.84-j

Won't Fix

Marcono1234

2017-11-07, 08:56 PM

2020-07-14, 03:55 PM

2020-07-14, 03:55 PM

5

5

Confirmed

json, version

1.6.76 (java)

-