/* * Minecraft Forge * Copyright (c) 2016-2020. * * 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 */ package net.minecraftforge.fml.network; import com.google.common.collect.ImmutableMap; import com.google.gson.JsonArray; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSyntaxException; import net.minecraft.util.JSONUtils; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.ExtensionPoint; import net.minecraftforge.fml.ModList; import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.HashMap; import java.util.Map; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.StreamSupport; import static net.minecraftforge.fml.network.FMLNetworkConstants.NETWORK; /** * { * "fmlNetworkVersion" : FMLNETVERSION, * "channels": [ * { * "res": "fml:handshake", * "version": "1.2.3.4", * "required": true * } * ], * "mods": [ * { * "modid": "modid", * "modmarker": "" * } * ] * } * */ public class FMLStatusPing { private static final Logger LOGGER = LogManager.getLogger(); private transient Map> channels; private transient Map mods; private transient int fmlNetworkVer; private transient boolean patched; public FMLStatusPing() { this.channels = NetworkRegistry.buildChannelVersionsForListPing(); this.mods = new HashMap<>(); ModList.get().forEachModContainer((modid, mc) -> mods.put(modid, mc.getCustomExtension(ExtensionPoint.DISPLAYTEST). map(Pair::getLeft).map(Supplier::get).orElse(FMLNetworkConstants.IGNORESERVERONLY))); this.fmlNetworkVer = FMLNetworkConstants.FMLNETVERSION; this.patched = true; } private FMLStatusPing(Map> deserialized, Map modMarkers, int fmlNetVer) { this.channels = ImmutableMap.copyOf(deserialized); this.mods = modMarkers; this.fmlNetworkVer = fmlNetVer; this.patched = false; } private FMLStatusPing(Map> deserialized, Map modMarkers, int fmlNetVer, boolean p) { this.channels = ImmutableMap.copyOf(deserialized); this.mods = modMarkers; this.fmlNetworkVer = fmlNetVer; this.patched = p; } public static class Serializer { public static FMLStatusPing deserialize(JsonObject forgeData, JsonDeserializationContext ctx) { try { final Map> channels = StreamSupport.stream(JSONUtils.getJsonArray(forgeData, "channels").spliterator(), false). map(JsonElement::getAsJsonObject). collect(Collectors.toMap(jo -> new ResourceLocation(JSONUtils.getString(jo, "res")), jo -> Pair.of(JSONUtils.getString(jo, "version"), JSONUtils.getBoolean(jo, "required"))) ); final Map mods = StreamSupport.stream(JSONUtils.getJsonArray(forgeData, "mods").spliterator(), false). map(JsonElement::getAsJsonObject). collect(Collectors.toMap(jo -> JSONUtils.getString(jo, "modId"), jo->JSONUtils.getString(jo, "modmarker"))); final int remoteFMLVersion = JSONUtils.getInt(forgeData, "fmlNetworkVersion"); return new FMLStatusPing(channels, mods, remoteFMLVersion, JSONUtils.hasField(forgeData, "keithPatch")); } catch (JsonSyntaxException e) { LOGGER.debug(NETWORK, "Encountered an error parsing status ping data", e); return null; } } public static JsonObject serialize(FMLStatusPing forgeData, JsonSerializationContext ctx) { JsonObject obj = new JsonObject(); JsonArray channels = new JsonArray(); forgeData.channels.forEach((namespace, version) -> { JsonObject mi = new JsonObject(); mi.addProperty("res", namespace.toString()); mi.addProperty("version", version.getLeft()); mi.addProperty("required", version.getRight()); channels.add(mi); }); obj.add("channels", channels); JsonArray modTestValues = new JsonArray(); forgeData.mods.forEach((modId, value) -> { JsonObject mi = new JsonObject(); mi.addProperty("modId", modId); mi.addProperty("modmarker", value); modTestValues.add(mi); }); obj.add("mods", modTestValues); obj.addProperty("fmlNetworkVersion", forgeData.fmlNetworkVer); if (forgeData.patched) obj.addProperty("keithPatch", true); return obj; } } public Map> getRemoteChannels() { return this.channels; } public Map getRemoteModData() { return mods; } public int getFMLNetworkVersion() { return fmlNetworkVer; } public boolean isPatchAdvertised() { return patched; } }