Java tutorial
/* * Minecraft Forge * Copyright (c) 2016-2018. * * 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.common.network.internal; import io.netty.channel.ChannelPipeline; import io.netty.channel.embedded.EmbeddedChannel; import java.util.ArrayList; import java.util.Comparator; import java.util.EnumMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.inventory.Container; import net.minecraft.network.NetworkManager; import net.minecraft.network.Packet; import net.minecraft.server.management.PlayerList; import net.minecraft.world.World; import net.minecraftforge.common.util.FakePlayer; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.common.FMLContainer; import net.minecraftforge.fml.common.FMLLog; import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.ModContainer; import net.minecraftforge.fml.common.network.FMLEmbeddedChannel; import net.minecraftforge.fml.common.network.FMLOutboundHandler; import net.minecraftforge.fml.common.network.NetworkRegistry; import net.minecraftforge.fml.common.network.FMLOutboundHandler.OutboundTarget; import net.minecraftforge.fml.common.network.handshake.FMLHandshakeMessage; import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher; import net.minecraftforge.fml.common.network.internal.FMLMessage.CompleteHandshake; import net.minecraftforge.fml.common.registry.EntityRegistry; import net.minecraftforge.fml.common.registry.EntityRegistry.EntityRegistration; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nullable; public class FMLNetworkHandler { public static final int READ_TIMEOUT = Integer.parseInt(System.getProperty("fml.readTimeout", "30")); public static final int LOGIN_TIMEOUT = Integer.parseInt(System.getProperty("fml.loginTimeout", "600")); private static EnumMap<Side, FMLEmbeddedChannel> channelPair; public static void fmlServerHandshake(PlayerList scm, NetworkManager manager, EntityPlayerMP player) { NetworkDispatcher dispatcher = NetworkDispatcher.allocAndSet(manager, scm); dispatcher.serverToClientHandshake(player); } public static void fmlClientHandshake(NetworkManager networkManager) { NetworkDispatcher dispatcher = NetworkDispatcher.allocAndSet(networkManager); dispatcher.clientToServerHandshake(); } public static void openGui(EntityPlayer entityPlayer, Object mod, int modGuiId, World world, int x, int y, int z) { ModContainer mc = FMLCommonHandler.instance().findContainerFor(mod); if (entityPlayer instanceof EntityPlayerMP && !(entityPlayer instanceof FakePlayer)) { EntityPlayerMP entityPlayerMP = (EntityPlayerMP) entityPlayer; Container remoteGuiContainer = NetworkRegistry.INSTANCE.getRemoteGuiContainer(mc, entityPlayerMP, modGuiId, world, x, y, z); if (remoteGuiContainer != null) { entityPlayerMP.getNextWindowId(); entityPlayerMP.closeContainer(); int windowId = entityPlayerMP.currentWindowId; FMLMessage.OpenGui openGui = new FMLMessage.OpenGui(windowId, mc.getModId(), modGuiId, x, y, z); EmbeddedChannel embeddedChannel = channelPair.get(Side.SERVER); embeddedChannel.attr(FMLOutboundHandler.FML_MESSAGETARGET).set(OutboundTarget.PLAYER); embeddedChannel.attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(entityPlayerMP); embeddedChannel.writeOutbound(openGui); entityPlayerMP.openContainer = remoteGuiContainer; entityPlayerMP.openContainer.windowId = windowId; entityPlayerMP.openContainer.addListener(entityPlayerMP); net.minecraftforge.common.MinecraftForge.EVENT_BUS .post(new net.minecraftforge.event.entity.player.PlayerContainerEvent.Open(entityPlayer, entityPlayer.openContainer)); } } else if (entityPlayer instanceof FakePlayer) { // NO OP - I won't even log a message! } else if (FMLCommonHandler.instance().getSide().equals(Side.CLIENT)) { Object guiContainer = NetworkRegistry.INSTANCE.getLocalGuiContainer(mc, entityPlayer, modGuiId, world, x, y, z); FMLCommonHandler.instance().showGuiScreen(guiContainer); } else { FMLLog.log.debug( "Invalid attempt to open a local GUI on a dedicated server. This is likely a bug. GUI ID: {},{}", mc.getModId(), modGuiId); } } @Nullable public static Packet<?> getEntitySpawningPacket(Entity entity) { EntityRegistration er = EntityRegistry.instance().lookupModSpawn(entity.getClass(), false); if (er == null) { return null; } if (er.usesVanillaSpawning()) { return null; } return channelPair.get(Side.SERVER) .generatePacketFrom(new FMLMessage.EntitySpawnMessage(er, entity, er.getContainer())); } @Nullable public static String checkModList(FMLHandshakeMessage.ModList modListPacket, Side side) { Map<String, String> modList = modListPacket.modList(); return checkModList(modList, side); } /** * @param listData map of modId string to version string, represents the mods available on the given side * @param side the side that listData is coming from, either client or server * @return null if everything is fine, returns a string error message if there are mod rejections */ @Nullable public static String checkModList(Map<String, String> listData, Side side) { List<Pair<ModContainer, String>> rejects = NetworkRegistry.INSTANCE.registry().entrySet().stream() .map(entry -> Pair.of(entry.getKey(), entry.getValue().checkCompatible(listData, side))) .filter(pair -> pair.getValue() != null).sorted(Comparator.comparing(o -> o.getKey().getName())) .collect(Collectors.toList()); if (rejects.isEmpty()) { return null; } else { List<String> rejectStrings = new ArrayList<>(); for (Pair<ModContainer, String> reject : rejects) { ModContainer modContainer = reject.getKey(); rejectStrings.add(modContainer.getName() + ": " + reject.getValue()); } String rejectString = String.join("\n", rejectStrings); FMLLog.log.info("Rejecting connection {}: {}", side, rejectString); return String.format("Server Mod rejections:\n%s", rejectString); } } @SideOnly(Side.CLIENT) private static void addClientHandlers() { ChannelPipeline pipeline = channelPair.get(Side.CLIENT).pipeline(); String targetName = channelPair.get(Side.CLIENT).findChannelHandlerNameForType(FMLRuntimeCodec.class); pipeline.addAfter(targetName, "GuiHandler", new OpenGuiHandler()); pipeline.addAfter(targetName, "EntitySpawnHandler", new EntitySpawnHandler()); } public static void registerChannel(FMLContainer container, Side side) { channelPair = NetworkRegistry.INSTANCE.newChannel(container, "FML", new FMLRuntimeCodec(), new HandshakeCompletionHandler()); EmbeddedChannel embeddedChannel = channelPair.get(Side.SERVER); embeddedChannel.attr(FMLOutboundHandler.FML_MESSAGETARGET).set(OutboundTarget.NOWHERE); if (side == Side.CLIENT) { addClientHandlers(); } } public static List<FMLProxyPacket> forwardHandshake(CompleteHandshake push, NetworkDispatcher target, Side side) { channelPair.get(side).attr(NetworkDispatcher.FML_DISPATCHER).set(target); channelPair.get(side).writeOutbound(push); ArrayList<FMLProxyPacket> list = new ArrayList<FMLProxyPacket>(); for (Object o : channelPair.get(side).outboundMessages()) { list.add((FMLProxyPacket) o); } channelPair.get(side).outboundMessages().clear(); return list; } public static void enhanceStatusQuery(JsonObject jsonobject) { JsonObject fmlData = new JsonObject(); fmlData.addProperty("type", "FML"); JsonArray modList = new JsonArray(); for (ModContainer mc : Loader.instance().getActiveModList()) { JsonObject modData = new JsonObject(); modData.addProperty("modid", mc.getModId()); modData.addProperty("version", mc.getVersion()); modList.add(modData); } fmlData.add("modList", modList); jsonobject.add("modinfo", fmlData); } }