com.comphenix.protocol.injector.packet.PacketRegistry.java Source code

Java tutorial

Introduction

Here is the source code for com.comphenix.protocol.injector.packet.PacketRegistry.java

Source

/*
 *  ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
 *  Copyright (C) 2012 Kristian S. Stangeland
 *
 *  This program is free software; you can redistribute it and/or modify it under the terms of the
 *  GNU General Public License as published by the Free Software Foundation; either version 2 of
 *  the License, or (at your option) any later version.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along with this program;
 *  if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 *  02111-1307 USA
 */

package com.comphenix.protocol.injector.packet;

import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.error.ReportType;
import com.comphenix.protocol.injector.netty.NettyProtocolRegistry;
import com.comphenix.protocol.injector.netty.ProtocolRegistry;
import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.base.Function;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

/**
 * Static packet registry in Minecraft.
 * @author Kristian
 */
@SuppressWarnings("rawtypes")
public class PacketRegistry {
    public static final ReportType REPORT_CANNOT_CORRECT_TROVE_MAP = new ReportType(
            "Unable to correct no entry value.");

    public static final ReportType REPORT_INSUFFICIENT_SERVER_PACKETS = new ReportType(
            "Too few server packets detected: %s");
    public static final ReportType REPORT_INSUFFICIENT_CLIENT_PACKETS = new ReportType(
            "Too few client packets detected: %s");

    // The Netty packet registry
    private static volatile ProtocolRegistry NETTY;

    // Cached for Netty
    private static volatile Set<Integer> LEGACY_SERVER_PACKETS;
    private static volatile Set<Integer> LEGACY_CLIENT_PACKETS;
    private static volatile Map<Integer, Class> LEGACY_PREVIOUS_PACKETS;

    // Whether or not the registry has been initialized
    private static volatile boolean INITIALIZED = false;

    /**
     * Initializes the packet registry.
     */
    private static void initialize() {
        if (INITIALIZED) {
            if (NETTY == null) {
                throw new IllegalStateException("Failed to initialize packet registry.");
            }
            return;
        }

        NETTY = new NettyProtocolRegistry();
        INITIALIZED = true;
    }

    /**
     * Determine if the given packet type is supported on the current server.
     * @param type - the type to check.
     * @return TRUE if it is, FALSE otherwise.
     */
    public static boolean isSupported(PacketType type) {
        initialize();
        return NETTY.getPacketTypeLookup().containsKey(type);
    }

    /**
     * Retrieve a map of every packet class to every ID.
     * <p>
     * Deprecated: Use {@link #getPacketToType()} instead.
     * @return A map of packet classes and their corresponding ID.
     */
    @Deprecated
    public static Map<Class, Integer> getPacketToID() {
        initialize();

        @SuppressWarnings("unchecked")
        Map<Class, Integer> result = (Map) Maps.transformValues(NETTY.getPacketClassLookup(),
                new Function<PacketType, Integer>() {
                    @Override
                    public Integer apply(PacketType type) {
                        return type.getLegacyId();
                    };
                });
        return result;
    }

    /**
     * Retrieve a map of every packet class to the respective packet type.
     * @return A map of packet classes and their corresponding packet type.
     */
    public static Map<Class, PacketType> getPacketToType() {
        initialize();

        @SuppressWarnings("unchecked")
        Map<Class, PacketType> result = (Map) NETTY.getPacketClassLookup();
        return result;
    }

    /**
     * Retrieve the injected proxy classes handlig each packet ID.
     * <p>
     * This is not supported in 1.7.2 and later.
     * @return Injected classes.
     */
    @Deprecated
    public static Map<Integer, Class> getOverwrittenPackets() {
        initialize();
        throw new IllegalStateException("Not supported on Netty.");
    }

    /**
     * Retrieve the vanilla classes handling each packet ID.
     * @return Vanilla classes.
     */
    @Deprecated
    public static Map<Integer, Class> getPreviousPackets() {
        initialize();

        // Construct it first
        if (LEGACY_PREVIOUS_PACKETS == null) {
            Map<Integer, Class> map = Maps.newHashMap();

            for (Entry<PacketType, Class<?>> entry : NETTY.getPacketTypeLookup().entrySet()) {
                map.put(entry.getKey().getLegacyId(), entry.getValue());
            }
            LEGACY_PREVIOUS_PACKETS = Collections.unmodifiableMap(map);
        }
        return LEGACY_PREVIOUS_PACKETS;
    }

    /**
     * Retrieve every known and supported server packet.
     * <p>
     * Deprecated: Use {@link #getServerPacketTypes()} instead.
     * @return An immutable set of every known server packet.
     * @throws FieldAccessException If we're unable to retrieve the server packet data from Minecraft.
     */
    @Deprecated
    public static Set<Integer> getServerPackets() throws FieldAccessException {
        if (LEGACY_SERVER_PACKETS == null) {
            LEGACY_SERVER_PACKETS = toLegacy(getServerPacketTypes());
        }

        return LEGACY_SERVER_PACKETS;
    }

    /**
     * Retrieve every known and supported server packet type.
     * @return Every server packet type.
     */
    public static Set<PacketType> getServerPacketTypes() {
        initialize();
        NETTY.synchronize();

        Set<PacketType> types = new HashSet<>();

        // Filter out unsupported packets
        for (PacketType type : NETTY.getServerPackets()) {
            if (!type.isDeprecated()) {
                types.add(type);
            }
        }

        return types;
    }

    /**
     * Retrieve every known and supported client packet.
     * <p>
     * Deprecated: Use {@link #getClientPacketTypes()} instead.
     * @return An immutable set of every known client packet.
     * @throws FieldAccessException If we're unable to retrieve the client packet data from Minecraft.
     */
    @Deprecated
    public static Set<Integer> getClientPackets() throws FieldAccessException {
        if (LEGACY_CLIENT_PACKETS == null) {
            LEGACY_CLIENT_PACKETS = toLegacy(getClientPacketTypes());
        }

        return LEGACY_CLIENT_PACKETS;
    }

    /**
     * Retrieve every known and supported server packet type.
     * @return Every server packet type.
     */
    public static Set<PacketType> getClientPacketTypes() {
        initialize();
        NETTY.synchronize();

        Set<PacketType> types = new HashSet<>();

        // Filter out unsupported packets
        for (PacketType type : NETTY.getClientPackets()) {
            if (!type.isDeprecated()) {
                types.add(type);
            }
        }

        return types;
    }

    /**
     * Convert a set of packet types to a set of integers based on the legacy packet ID.
     * @param types - packet type.
     * @return Set of integers.
     */
    public static Set<Integer> toLegacy(Set<PacketType> types) {
        Set<Integer> result = Sets.newHashSet();

        for (PacketType type : types)
            result.add(type.getLegacyId());
        return Collections.unmodifiableSet(result);
    }

    /**
     * Convert a set of legacy packet IDs to packet types.
     * @param ids - legacy packet IDs.
     * @return Set of packet types.
     */
    public static Set<PacketType> toPacketTypes(Set<Integer> ids) {
        return toPacketTypes(ids, null);
    }

    /**
     * Convert a set of legacy packet IDs to packet types.
     * @param ids - legacy packet IDs.
     * @param preference - the sender preference, if any.
     * @return Set of packet types.
     */
    public static Set<PacketType> toPacketTypes(Set<Integer> ids, Sender preference) {
        Set<PacketType> result = Sets.newHashSet();

        for (int id : ids)
            result.add(PacketType.fromLegacy(id, preference));
        return Collections.unmodifiableSet(result);
    }

    /**
     * Retrieves the correct packet class from a given packet ID.
     * <p>
     * Deprecated: Use {@link #getPacketClassFromType(PacketType)} instead.
     * @param packetID - the packet ID.
     * @return The associated class.
     */
    @Deprecated
    public static Class getPacketClassFromID(int packetID) {
        initialize();
        return NETTY.getPacketTypeLookup().get(PacketType.findLegacy(packetID));
    }

    /**
     * Retrieves the correct packet class from a given type.
     * @param type - the packet type.
     * @return The associated class.
     */
    public static Class getPacketClassFromType(PacketType type) {
        return getPacketClassFromType(type, false);
    }

    /**
     * Retrieves the correct packet class from a given type.
     * <p>
     * Note that forceVanillla will be ignored on MC 1.7.2 and later.
     * @param type - the packet type.
     * @param forceVanilla - whether or not to look for vanilla classes, not injected classes.
     * @return The associated class.
     */
    public static Class getPacketClassFromType(PacketType type, boolean forceVanilla) {
        initialize();

        // Try the lookup first
        Class<?> clazz = NETTY.getPacketTypeLookup().get(type);
        if (clazz != null) {
            return clazz;
        }

        // Then try looking up the class names
        for (String name : type.getClassNames()) {
            try {
                clazz = MinecraftReflection.getMinecraftClass(name);
                break;
            } catch (Exception ex) {
            }
        }

        // TODO Cache the result?
        return clazz;
    }

    /**
     * Retrieves the correct packet class from a given packet ID.
     * <p>
     * This method has been deprecated.
     * @param packetID - the packet ID.
      * @param forceVanilla - whether or not to look for vanilla classes, not injected classes.
     * @return The associated class.
     */
    @Deprecated
    public static Class getPacketClassFromID(int packetID, boolean forceVanilla) {
        initialize();
        return getPacketClassFromID(packetID);
    }

    /**
     * Retrieve the packet ID of a given packet.
     * <p>
     * Deprecated: Use {@link #getPacketType(Class)}.
     * @param packet - the type of packet to check.
     * @return The legacy ID of the given packet.
     * @throws IllegalArgumentException If this is not a valid packet.
     */
    @Deprecated
    public static int getPacketID(Class<?> packet) {
        initialize();
        return NETTY.getPacketClassLookup().get(packet).getLegacyId();
    }

    /**
     * Retrieve the packet type of a given packet.
     * @param packet - the class of the packet.
     * @return The packet type, or NULL if not found.
     */
    public static PacketType getPacketType(Class<?> packet) {
        return getPacketType(packet, null);
    }

    /**
     * Retrieve the packet type of a given packet.
     * @param packet - the class of the packet.
     * @param sender - the sender of the packet, or NULL.
     * @return The packet type, or NULL if not found.
     */
    public static PacketType getPacketType(Class<?> packet, Sender sender) {
        initialize();
        return NETTY.getPacketClassLookup().get(packet);
    }
}