/* * 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.events; import java.util.List; import java.util.Set; import javax.annotation.Nonnull; import org.bukkit.plugin.Plugin; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.injector.GamePhase; import com.comphenix.protocol.injector.packet.PacketRegistry; import com.google.common.base.Preconditions; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Sets; /** * Represents a packet listener with useful constructors. *
* Remember to override onPacketReceiving() and onPacketSending(), depending on the ConnectionSide. * @author Kristian */ public abstract class PacketAdapter implements PacketListener { protected Plugin plugin; protected ConnectionSide connectionSide; protected ListeningWhitelist receivingWhitelist = ListeningWhitelist.EMPTY_WHITELIST; protected ListeningWhitelist sendingWhitelist = ListeningWhitelist.EMPTY_WHITELIST; /** * Initialize a packet adapter using a collection of parameters. Use {@link #params()} to get an instance to this builder. * @param params - the parameters. */ public PacketAdapter(@Nonnull AdapterParameteters params) { this( checkValidity(params).plugin, params.connectionSide, params.listenerPriority, params.gamePhase, params.options, params.packets ); } /** * Initialize a packet listener with the given parameters. * @param plugin - the plugin. * @param types - the packet types. */ public PacketAdapter(Plugin plugin, PacketType... types) { this(plugin, ListenerPriority.NORMAL, types); } /** * Initialize a packet listener with the given parameters. * @param plugin - the plugin. * @param types - the packet types. */ public PacketAdapter(Plugin plugin, Iterable extends PacketType> types) { this(params(plugin, Iterables.toArray(types, PacketType.class))); } /** * Initialize a packet listener with the given parameters. * @param plugin - the plugin. * @param listenerPriority - the priority. * @param types - the packet types. */ public PacketAdapter(Plugin plugin, ListenerPriority listenerPriority, Iterable extends PacketType> types) { this(params(plugin, Iterables.toArray(types, PacketType.class)).listenerPriority(listenerPriority)); } /** * Initialize a packet listener with the given parameters. * @param plugin - the plugin. * @param listenerPriority - the priority. * @param types - the packet types. * @param options - the options. */ public PacketAdapter(Plugin plugin, ListenerPriority listenerPriority, Iterable extends PacketType> types, ListenerOptions... options) { this(params(plugin, Iterables.toArray(types, PacketType.class)).listenerPriority(listenerPriority).options(options)); } /** * Initialize a packet listener with the given parameters. * @param plugin - the plugin. * @param listenerPriority - the priority. * @param types - the packet types. */ public PacketAdapter(Plugin plugin, ListenerPriority listenerPriority, PacketType... types) { this(params(plugin, types).listenerPriority(listenerPriority)); } /** * Initialize a packet listener with default priority. *
* Deprecated: Use {@link #params()} instead. * @param plugin - the plugin that spawned this listener. * @param connectionSide - the packet type the listener is looking for. * @param packets - the packet IDs the listener is looking for. */ @Deprecated public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, Integer... packets) { this(plugin, connectionSide, ListenerPriority.NORMAL, packets); } /** * Initialize a packet listener for a single connection side. *
* Deprecated: Use {@link #params()} instead.
* @param plugin - the plugin that spawned this listener.
* @param connectionSide - the packet type the listener is looking for.
* @param listenerPriority - the event priority.
* @param packets - the packet IDs the listener is looking for.
*/
@Deprecated
public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority, Set
* The game phase is used to optimize performance. A listener should only choose BOTH or LOGIN if it's absolutely necessary.
*
* Deprecated: Use {@link #params()} instead.
* @param plugin - the plugin that spawned this listener.
* @param connectionSide - the packet type the listener is looking for.
* @param gamePhase - which game phase this listener is active under.
* @param packets - the packet IDs the listener is looking for.
*/
@Deprecated
public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, GamePhase gamePhase, Set
* The game phase is used to optimize performance. A listener should only choose BOTH or LOGIN if it's absolutely necessary.
*
* Deprecated: Use {@link #params()} instead.
* @param plugin - the plugin that spawned this listener.
* @param connectionSide - the packet type the listener is looking for.
* @param listenerPriority - the event priority.
* @param gamePhase - which game phase this listener is active under.
* @param packets - the packet IDs the listener is looking for.
*/
@Deprecated
public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority, GamePhase gamePhase, Set
* Deprecated: Use {@link #params()} instead.
* @param plugin - the plugin that spawned this listener.
* @param connectionSide - the packet type the listener is looking for.
* @param listenerPriority - the event priority.
* @param packets - the packet IDs the listener is looking for.
*/
@Deprecated
public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority, Integer... packets) {
this(plugin, connectionSide, listenerPriority, GamePhase.PLAYING, packets);
}
/**
* Initialize a packet listener for a single connection side.
*
* Deprecated: Use {@link #params()} instead.
* @param plugin - the plugin that spawned this listener.
* @param connectionSide - the packet type the listener is looking for.
* @param options - which listener options to use.
* @param packets - the packet IDs the listener is looking for.
*/
@Deprecated
public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, ListenerOptions[] options, Integer... packets) {
this(plugin, connectionSide, ListenerPriority.NORMAL, GamePhase.PLAYING, options, packets);
}
/**
* Initialize a packet listener for a single connection side.
*
* Deprecated: Use {@link #params()} instead.
* @param plugin - the plugin that spawned this listener.
* @param connectionSide - the packet type the listener is looking for.
* @param gamePhase - which game phase this listener is active under.
* @param packets - the packet IDs the listener is looking for.
*/
@Deprecated
public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, GamePhase gamePhase, Integer... packets) {
this(plugin, connectionSide, ListenerPriority.NORMAL, gamePhase, packets);
}
/**
* Initialize a packet listener for a single connection side.
*
* The game phase is used to optimize performance. A listener should only choose BOTH or LOGIN if it's absolutely necessary.
*
* Deprecated: Use {@link #params()} instead.
* @param plugin - the plugin that spawned this listener.
* @param connectionSide - the packet type the listener is looking for.
* @param listenerPriority - the event priority.
* @param gamePhase - which game phase this listener is active under.
* @param packets - the packet IDs the listener is looking for.
*/
@Deprecated
public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority, GamePhase gamePhase, Integer... packets) {
this(plugin, connectionSide, listenerPriority, gamePhase, new ListenerOptions[0], packets);
}
/**
* Initialize a packet listener for a single connection side.
*
* The game phase is used to optimize performance. A listener should only choose BOTH or LOGIN if it's absolutely necessary.
*
* Listener options must be specified in order for {@link NetworkMarker#getInputBuffer()} to function correctly.
*
* Deprecated: Use {@link #params()} instead.
* @param plugin - the plugin that spawned this listener.
* @param connectionSide - the packet type the listener is looking for.
* @param listenerPriority - the event priority.
* @param gamePhase - which game phase this listener is active under.
* @param options - which listener options to use.
* @param packets - the packet IDs the listener is looking for.
*/
@Deprecated
public PacketAdapter(
Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority,
GamePhase gamePhase, ListenerOptions[] options, Integer... packets) {
this(plugin, connectionSide, listenerPriority, gamePhase, options,
PacketRegistry.toPacketTypes(Sets.newHashSet(packets), connectionSide.getSender()).toArray(new PacketType[0])
);
}
// For internal use only
private PacketAdapter(
Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority,
GamePhase gamePhase, ListenerOptions[] options, PacketType... packets) {
if (plugin == null)
throw new IllegalArgumentException("plugin cannot be null");
if (connectionSide == null)
throw new IllegalArgumentException("connectionSide cannot be null");
if (listenerPriority == null)
throw new IllegalArgumentException("listenerPriority cannot be null");
if (gamePhase == null)
throw new IllegalArgumentException("gamePhase cannot be NULL");
if (packets == null)
throw new IllegalArgumentException("packets cannot be null");
if (options == null)
throw new IllegalArgumentException("options cannot be null");
ListenerOptions[] serverOptions = options;
ListenerOptions[] clientOptions = options;
// Special case that allows us to specify optionIntercept().
if (connectionSide == ConnectionSide.BOTH) {
serverOptions = except(serverOptions, new ListenerOptions[0],
ListenerOptions.INTERCEPT_INPUT_BUFFER);
}
// Add whitelists
if (connectionSide.isForServer())
sendingWhitelist = ListeningWhitelist.newBuilder().
priority(listenerPriority).
types(packets).
gamePhase(gamePhase).
options(serverOptions).
build();
if (connectionSide.isForClient())
receivingWhitelist = ListeningWhitelist.newBuilder().
priority(listenerPriority).
types(packets).
gamePhase(gamePhase).
options(clientOptions).
build();
this.plugin = plugin;
this.connectionSide = connectionSide;
}
// Remove a given element from an array
private static
* This is often simpler and better than passing them directly to each constructor.
* @return Helper object.
*/
public static AdapterParameteters params() {
return new AdapterParameteters();
}
/**
* Construct a helper object for passing parameters to the packet adapter.
*
* This is often simpler and better than passing them directly to each constructor.
* Deprecated: Use {@link #params(Plugin, PacketType...)} instead.
* @param plugin - the plugin that spawned this listener.
* @param packets - the packet IDs the listener is looking for.
* @return Helper object.
*/
@Deprecated
public static AdapterParameteters params(Plugin plugin, Integer... packets) {
return new AdapterParameteters().plugin(plugin).packets(packets);
}
/**
* Construct a helper object for passing parameters to the packet adapter.
*
* This is often simpler and better than passing them directly to each constructor.
* @param plugin - the plugin that spawned this listener.
* @param packets - the packet types the listener is looking for.
* @return Helper object.
*/
public static AdapterParameteters params(Plugin plugin, PacketType... packets) {
return new AdapterParameteters().plugin(plugin).types(packets);
}
/**
* Represents a builder for passing parameters to the packet adapter constructor.
*
* Note: Never make spelling mistakes in a public API!
* @author Kristian
*/
public static class AdapterParameteters {
private Plugin plugin;
private ConnectionSide connectionSide;
private PacketType[] packets;
// Parameters with default values
private GamePhase gamePhase = GamePhase.PLAYING;
private ListenerOptions[] options = new ListenerOptions[0];
private ListenerPriority listenerPriority = ListenerPriority.NORMAL;
/**
* Set the plugin that spawned this listener. This parameter is required.
* @param plugin - the plugin.
* @return This builder, for chaining.
*/
public AdapterParameteters plugin(@Nonnull Plugin plugin) {
this.plugin = Preconditions.checkNotNull(plugin, "plugin cannot be NULL.");
return this;
}
/**
* Set the packet types this listener is looking for. This parameter is required.
* @param connectionSide - the new packet type.
* @return This builder, for chaining.
*/
public AdapterParameteters connectionSide(@Nonnull ConnectionSide connectionSide) {
this.connectionSide = Preconditions.checkNotNull(connectionSide, "connectionside cannot be NULL.");
return this;
}
/**
* Set this adapter to also look for client-side packets.
* @return This builder, for chaining.
*/
public AdapterParameteters clientSide() {
return connectionSide(ConnectionSide.add(connectionSide, ConnectionSide.CLIENT_SIDE));
}
/**
* Set this adapter to also look for server-side packets.
* @return This builder, for chaining.
*/
public AdapterParameteters serverSide() {
return connectionSide(ConnectionSide.add(connectionSide, ConnectionSide.SERVER_SIDE));
}
/**
* Set the the event priority, where the execution is in ascending order from lowest to highest.
*
* Default is {@link ListenerPriority#NORMAL}.
* @param listenerPriority - the new event priority.
* @return This builder, for chaining.
*/
public AdapterParameteters listenerPriority(@Nonnull ListenerPriority listenerPriority) {
this.listenerPriority = Preconditions.checkNotNull(listenerPriority, "listener priority cannot be NULL.");
return this;
}
/**
* Set which game phase this listener is active under. This is a hint for ProtocolLib to start intercepting login packets.
*
* Default is {@link GamePhase#PLAYING}, which will not intercept login packets.
* @param gamePhase - the new game phase.
* @return This builder, for chaining.
*/
public AdapterParameteters gamePhase(@Nonnull GamePhase gamePhase) {
this.gamePhase = Preconditions.checkNotNull(gamePhase, "gamePhase cannot be NULL.");
return this;
}
/**
* Set the game phase to {@link GamePhase#LOGIN}, allowing ProtocolLib to intercept login packets.
* @return This builder, for chaining.
*/
public AdapterParameteters loginPhase() {
return gamePhase(GamePhase.LOGIN);
}
/**
* Set listener options that decide whether or not to intercept the raw packet data as read from the network stream.
*
* The default is to disable this raw packet interception.
* @param options - every option to use.
* @return This builder, for chaining.
*/
public AdapterParameteters options(@Nonnull ListenerOptions... options) {
this.options = Preconditions.checkNotNull(options, "options cannot be NULL.");
return this;
}
/**
* Set listener options that decide whether or not to intercept the raw packet data as read from the network stream.
*
* The default is to disable this raw packet interception.
* @param options - every option to use.
* @return This builder, for chaining.
*/
public AdapterParameteters options(@Nonnull Set extends ListenerOptions> options) {
Preconditions.checkNotNull(options, "options cannot be NULL.");
this.options = options.toArray(new ListenerOptions[0]);
return this;
}
/**
* Add a given option to the current builder.
* @param option - the option to add.
* @return This builder, for chaining.
*/
private AdapterParameteters addOption(ListenerOptions option) {
if (options == null) {
return options(option);
} else {
Set
* This is no longer relevant in 1.7.2.
* @return This builder, for chaining.
*/
public AdapterParameteters optionManualGamePhase() {
return addOption(ListenerOptions.DISABLE_GAMEPHASE_DETECTION);
}
/**
* Set the listener option to {@link ListenerOptions#ASYNC}, indicating that our listener is thread safe.
*
* This allows ProtocolLib to perform certain optimizations.
* @return This builder, for chaining.
*/
public AdapterParameteters optionAsync() {
return addOption(ListenerOptions.ASYNC);
}
/**
* Set the packet IDs of the packets the listener is looking for.
*
* This parameter is required.
*
* Deprecated: Use {@link #types(PacketType...)} instead.
* @param packets - the packet IDs to look for.
* @return This builder, for chaining.
*/
@Deprecated
public AdapterParameteters packets(@Nonnull Integer... packets) {
Preconditions.checkNotNull(packets, "packets cannot be NULL");
PacketType[] types = new PacketType[packets.length];
for (int i = 0; i < types.length; i++) {
types[i] = PacketType.findLegacy(packets[i]);
}
this.packets = types;
return this;
}
/**
* Set the packet IDs of the packets the listener is looking for.
*
* This parameter is required.
* @param packets - a set of the packet IDs to look for.
* @return This builder, for chaining.
*/
@Deprecated
public AdapterParameteters packets(@Nonnull Set
* This parameter is required.
* @param packets - the packet types to look for.
* @return This builder, for chaining.
*/
public AdapterParameteters types(@Nonnull PacketType... packets) {
// Set the connection side as well
if (connectionSide == null) {
for (PacketType type : packets) {
this.connectionSide = ConnectionSide.add(this.connectionSide, type.getSender().toSide());
}
}
this.packets = Preconditions.checkNotNull(packets, "packets cannot be NULL");
if (packets.length == 0)
throw new IllegalArgumentException("Passed an empty packet type array.");
return this;
}
/**
* Set the packet types the listener is looking for.
*
* This parameter is required.
* @param packets - a set of packet types to look for.
* @return This builder, for chaining.
*/
public AdapterParameteters types(@Nonnull Set