Java tutorial
/* * __ ______ ______ __ __ __ __ ______ ______ * /\ \ /\ == \ /\ __ \ /\ \/ / /\ "-.\ \ /\ ___\ /\__ _\ * _\_\ \ \ \ __< \ \ __ \ \ \ _"-. \ \ \-. \ \ \ __\ \/_/\ \/ * /\_____\ \ \_\ \_\ \ \_\ \_\ \ \_\ \_\ \ \_\\"\_\ \ \_____\ \ \_\ * \/_____/ \/_/ /_/ \/_/\/_/ \/_/\/_/ \/_/ \/_/ \/_____/ \/_/ * * the MIT License (MIT) * * Copyright (c) 2016-2019 Trent "Whirvis" Summerlin * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * the above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package com.whirvis.jraknet; import java.lang.reflect.Field; import java.util.Arrays; import java.util.HashMap; import java.util.UUID; import java.util.Map.Entry; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.whirvis.jraknet.map.ShortMap; import com.whirvis.jraknet.protocol.ConnectionType; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.socket.DatagramPacket; /** * A generic RakNet packet that has the ability to get the ID of the packet * along with encoding and decoding. * * @author Trent "Whirvis" Summerlin * @since JRakNet v1.0.0 */ public class RakNetPacket extends Packet { /** * The name of the <code>encode()</code> method. */ private static final String ENCODE_METHOD_NAME = "encode"; /** * The name of the <code>decode()</code> method. */ private static final String DECODE_METHOD_NAME = "decode"; /** * The cached packet names, mapped by their ID. */ private static final ShortMap<String> PACKET_NAMES = new ShortMap<String>(); /** * The cached packet IDs, mapped by their name. */ private static final HashMap<String, Short> PACKET_IDS = new HashMap<String, Short>(); /** * The magic identifier. */ public final static byte[] MAGIC = new byte[] { (byte) 0x00, (byte) 0xFF, (byte) 0xFF, 0x00, (byte) 0xFE, (byte) 0xFE, (byte) 0xFE, (byte) 0xFE, (byte) 0xFD, (byte) 0xFD, (byte) 0xFD, (byte) 0xFD, (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78 }; /** * The ID of the {@link com.whirvis.jraknet.protocol.status.ConnectedPing * CONNECTED_PING} packet. */ public static final short ID_CONNECTED_PING = 0x00; /** * The ID of the {@link com.whirvis.jraknet.protocol.status.UnconnectedPing * UNCONNECTED_PING} packet. */ public static final short ID_UNCONNECTED_PING = 0x01; /** * The ID of the * {@link com.whirvis.jraknet.protocol.status.UnconnectedPingOpenConnections * UNCONNECTED_PING_OPEN_CONNECTIONS} packet. */ public static final short ID_UNCONNECTED_PING_OPEN_CONNECTIONS = 0x02; /** * The ID of the {@link com.whirvis.jraknet.protocol.status.ConnectedPong * CONNECTED_PONG} packet. */ public static final short ID_CONNECTED_PONG = 0x03; /** * The ID of the <code>DETECT_LOST_CONNECTIONS</code> packet. */ public static final short ID_DETECT_LOST_CONNECTIONS = 0x04; /** * The ID of the * {@link com.whirvis.jraknet.protocol.connection.OpenConnectionRequestOne * OPEN_CONNECTION_REQUEST_1} packet. */ public static final short ID_OPEN_CONNECTION_REQUEST_1 = 0x05; /** * The ID of the * {@link com.whirvis.jraknet.protocol.connection.OpenConnectionResponseOne * OPEN_CONNECTION_REPLY_1} packet. */ public static final short ID_OPEN_CONNECTION_REPLY_1 = 0x06; /** * The ID of the * {@link com.whirvis.jraknet.protocol.connection.OpenConnectionRequestTwo * OPEN_CONNECTION_REQUEST_2} packet. */ public static final short ID_OPEN_CONNECTION_REQUEST_2 = 0x07; /** * The ID of the * {@link com.whirvis.jraknet.protocol.connection.OpenConnectionResponseTwo * OPEN_CONNECTION_REPLY_2} packet. */ public static final short ID_OPEN_CONNECTION_REPLY_2 = 0x08; /** * The ID of the {@link com.whirvis.jraknet.protocol.login.ConnectionRequest * CONNECTION_REQUEST} packet. */ public static final short ID_CONNECTION_REQUEST = 0x09; /** * The ID of the <code>REMOVE_SYSTEM_REQUIRES_PUBLIC_KEY</code> packet. */ public static final short ID_REMOTE_SYSTEM_REQUIRES_PUBLIC_KEY = 0x0A; /** * The ID of the <code>OUR_SYSTEM_REQUIRES_SECURITY</code> packet. */ public static final short ID_OUR_SYSTEM_REQUIRES_SECURITY = 0x0B; /** * The ID of the <code>PUBLIC_KEY_MISMATCH</code> packet. */ public static final short ID_PUBLIC_KEY_MISMATCH = 0x0C; /** * The ID of the <code>OUT_OF_BAND_INTERNAL</code> packet. */ public static final short ID_OUT_OF_BAND_INTERNAL = 0x0D; /** * The ID of the <code>SND_RECEIPT_ACKED</code> packet. * <p> * In the original implementation of RakNet, when a packet is acknowledged * by a peer this packet is sent back through loopback to the original * sender of the packet with the acknoweldgeable reliability. Since this * implementation has listeners will special built in acknowledgement and * loss methods, this packet has no need for implementation. */ public static final short ID_SND_RECEIPT_ACKED = 0x0E; /** * The ID of the <code>SND_RECEIPT_LOSS</code> packet. * <p> * In the original implementation of RakNet, when a packet is acknowledged * by a peer this packet is sent back through loopback to the original * sender of the packet with the acknoweldgeable reliability. Since this * implementation has listeners will special built in acknowledgement and * loss methods, this packet has no need for implementation. */ public static final short ID_SND_RECEIPT_LOSS = 0x0F; /** * The ID of the * {@link com.whirvis.jraknet.protocol.login.ConnectionRequestAccepted * CONNECTION_REQUEST_ACCEPTED} packet. */ public static final short ID_CONNECTION_REQUEST_ACCEPTED = 0x10; /** * The ID of the <code>CONNECTION_ATTEMPT_FAILED</code> packet. */ public static final short ID_CONNECTION_ATTEMPT_FAILED = 0x11; /** * The ID of the <code>ALREADY_CONNECTED</code> packet. */ public static final short ID_ALREADY_CONNECTED = 0x12; /** * The ID of the * {@link com.whirvis.jraknet.protocol.login.NewIncomingConnection * NEW_INCOMING_CONNECTION} packet. */ public static final short ID_NEW_INCOMING_CONNECTION = 0x13; /** * The ID of the <code>NO_FREE_INCOMING_CONNECTIONS</code> packet. */ public static final short ID_NO_FREE_INCOMING_CONNECTIONS = 0x14; /** * The ID of the <code>DISCONNECTION_NOTIFICATION</code> packet. */ public static final short ID_DISCONNECTION_NOTIFICATION = 0x15; /** * The ID of the <code>CONNECTION_LOST</code> packet. */ public static final short ID_CONNECTION_LOST = 0x16; /** * The ID of the * {@link com.whirvis.jraknet.protocol.connection.ConnectionBanned * CONNECTION_BANNED} packet. */ public static final short ID_CONNECTION_BANNED = 0x17; /** * The ID of the <code>INVALID_PASSWORD</code> packet. */ public static final short ID_INVALID_PASSWORD = 0x18; /** * The ID of the * {@link com.whirvis.jraknet.protocol.connection.IncompatibleProtocolVersion * INCOMPATIBLE_PROTOCOL_VERSION} packet. */ public static final short ID_INCOMPATIBLE_PROTOCOL_VERSION = 0x19; /** * The ID of the <code>IP_RECENTLY_CONNECTED</code> packet. */ public static final short ID_IP_RECENTLY_CONNECTED = 0x1A; /** * The ID of the <code>TIMESTAMP</code> packet. */ public static final short ID_TIMESTAMP = 0x1B; /** * The ID of the {@link com.whirvis.jraknet.protocol.status.UnconnectedPong * UNCONNECTED_PONG} packet. */ public static final short ID_UNCONNECTED_PONG = 0x1C; /** * The ID of the <code>ADVERTISE_SYSTEM</code> packet. */ public static final short ID_ADVERTISE_SYSTEM = 0x1D; /** * The ID of the <code>DOWNLOAD_PROGRESS</code> packet. */ public static final short ID_DOWNLOAD_PROGRESS = 0x1E; /** * The ID of the <code>REMOTE_DISCONNECTION_NOTIFICATION</code> packet. */ public static final short ID_REMOTE_DISCONNECTION_NOTIFICATION = 0x1F; /** * The ID of the <code>REMOTE_CONNECTION_LOST</code> packet. */ public static final short ID_REMOTE_CONNECTION_LOST = 0x20; /** * The ID of the <code>REMOTE_NEW_INCOMING_CONNECTION</code> packet. */ public static final short ID_REMOTE_NEW_INCOMING_CONNECTION = 0x21; /** * The ID of the <code>FILE_LIST_TRANSFER_HEADER</code> packet. */ public static final short ID_FILE_LIST_TRANSFER_HEADER = 0x22; /** * The ID of the <code>FILE_LIST_TRANSFER_FILE</code> packet. */ public static final short ID_FILE_LIST_TRANSFER_FILE = 0x23; /** * The ID of the <code>FILE_LIST_REFERENCE_PUSH_ACK</code> packet. */ public static final short ID_FILE_LIST_REFERENCE_PUSH_ACK = 0x24; /** * The ID of the <code>DDT_DOWNLOAD_REQUEST</code> packet. */ public static final short ID_DDT_DOWNLOAD_REQUEST = 0x25; /** * The ID of the <code>TRANSPORT_STRING</code> packet. */ public static final short ID_TRANSPORT_STRING = 0x26; /** * The ID of the <code>REPLICA_MANAGER_CONSTRUCTION</code> packet. */ public static final short ID_REPLICA_MANAGER_CONSTRUCTION = 0x27; /** * The ID of the <code>REPLICA_MANAGER_SCOPE_CHANGE</code> packet. */ public static final short ID_REPLICA_MANAGER_SCOPE_CHANGE = 0x28; /** * The ID of the <code>REPLICA_MANAGER_SERIALIZE</code> packet. */ public static final short ID_REPLICA_MANAGER_SERIALIZE = 0x29; /** * The ID of the <code>REPLICA_MANAGER_DOWNLOAD_STARTED</code> packet. */ public static final short ID_REPLICA_MANAGER_DOWNLOAD_STARTED = 0x2A; /** * The ID of the <code>REPLICA_MANAGER_DOWNLOAD_COMPLETE</code> packet. */ public static final short ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE = 0x2B; /** * The ID of the <code>RAKVOICE_OPEN_CHANNEL_REQUEST</code> packet. */ public static final short ID_RAKVOICE_OPEN_CHANNEL_REQUEST = 0x2C; /** * The ID of the <code>RAKVOICE_OPEN_CHANNEL_REPLY</code> packet. */ public static final short ID_RAKVOICE_OPEN_CHANNEL_REPLY = 0x2D; /** * The ID of the <code>RAKVOICE_CLOSE_CHANNEL</code> packet. */ public static final short ID_RAKVOICE_CLOSE_CHANNEL = 0x2E; /** * The ID of the <code>RAKVOICE_DATA</code> packet. */ public static final short ID_RAKVOICE_DATA = 0x2F; /** * The ID of the <code>AUTOPATHER_GET_CHANGELIST_SINCE_DATE</code> packet. */ public static final short ID_AUTOPATCHER_GET_CHANGELIST_SINCE_DATE = 0x30; /** * The ID of the <code>AUTOPATCHER_CREATION_LIST</code> packet. */ public static final short ID_AUTOPATCHER_CREATION_LIST = 0x31; /** * The ID of the <code>AUTOPATCHER_DELETION_LIST</code> packet. */ public static final short ID_AUTOPATCHER_DELETION_LIST = 0x32; /** * The ID of the <code>AUTOPATCHER_GET_PATCH</code> packet. */ public static final short ID_AUTOPATCHER_GET_PATCH = 0x33; /** * The ID of the <code>AUTOPATCHER_PATCH_LIST</code> packet. */ public static final short ID_AUTOPATCHER_PATCH_LIST = 0x34; /** * The ID of the <code>AUTOPATHER_REPOSITORY_FATAL_ERROR</code> packet. */ public static final short ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR = 0x35; /** * The ID of the * <code>AUTOPATHER_CANNOT_DOWNLOAD_ORIGINAL_UNMODIFIED_FILES</code> packet. */ public static final short ID_AUTOPATCHER_CANNOT_DOWNLOAD_ORIGINAL_UNMODIFIED_FILES = 0x36; /** * The ID of the <code>AUTOPATHER_FINISHED_INTERNAL</code> packet. */ public static final short ID_AUTOPATCHER_FINISHED_INTERNAL = 0x37; /** * The ID of the <code>AUTOPATHER_FINISHED</code> packet. */ public static final short ID_AUTOPATCHER_FINISHED = 0x38; /** * The ID of the <code>AUTOPATCHER_RESTART_APPLICATION</code> packet. */ public static final short ID_AUTOPATCHER_RESTART_APPLICATION = 0x39; /** * The ID of the <code>NAT_PUNCHTHROUGH_REQUEST</code> packet. */ public static final short ID_NAT_PUNCHTHROUGH_REQUEST = 0x3A; /** * The ID of the <code>NAT_CONNECT_AT_TIME</code> packet. */ public static final short ID_NAT_CONNECT_AT_TIME = 0x3B; /** * The ID of the <code>NAT_GET_MOST_RECENT_PORT</code> packet. */ public static final short ID_NAT_GET_MOST_RECENT_PORT = 0x3C; /** * The ID of the <code>NAT_CLIENT_READY</code> packet. */ public static final short ID_NAT_CLIENT_READY = 0x3D; /** * The ID of the <code>NAT_TARGET_NOT_CONNECT</code> packet. */ public static final short ID_NAT_TARGET_NOT_CONNECTED = 0x3E; /** * The ID of the <code>NAT_TARGET_UNRESPONSIVE</code> packet. */ public static final short ID_NAT_TARGET_UNRESPONSIVE = 0x3F; /** * The ID of the <code>NAT_CONNECTION_TO_TARGET_LOST</code> packet. */ public static final short ID_NAT_CONNECTION_TO_TARGET_LOST = 0x40; /** * The ID of the <code>NAT_ALREADY_IN_PROGRESS</code> packet. */ public static final short ID_NAT_ALREADY_IN_PROGRESS = 0x41; /** * The ID of the <code>NAT_PUNCHTHROUGH_FAILED</code> packet. */ public static final short ID_NAT_PUNCHTHROUGH_FAILED = 0x42; /** * The ID of the <code>NAT_PUNCHTHROUGH_SUCCEEDED</code> packet. */ public static final short ID_NAT_PUNCHTHROUGH_SUCCEEDED = 0x43; /** * The ID of the <code>READY_EVENT_SET</code> packet. */ public static final short ID_READY_EVENT_SET = 0x44; /** * The ID of the <code>READY_EVENT_UNSET</code> packet. */ public static final short ID_READY_EVENT_UNSET = 0x45; /** * The ID of the <code>READY_EVENT_ALL_SET</code> packet. */ public static final short ID_READY_EVENT_ALL_SET = 0x46; /** * The ID of the <code>READY_EVENT_QUERY</code> packet. */ public static final short ID_READY_EVENT_QUERY = 0x47; /** * The ID of the <code>LOBBY_GENERAL</code> packet. */ public static final short ID_LOBBY_GENERAL = 0x48; /** * The ID of the <code>RPC_REMOTE_ERROR</code> packet. */ public static final short ID_RPC_REMOTE_ERROR = 0x49; /** * The ID of the <code>RPC_PLUGIN</code> packet. */ public static final short ID_RPC_PLUGIN = 0x4A; /** * The ID of the <code>FILE_LIST_REFERENCE_PUSH</code> packet. */ public static final short ID_FILE_LIST_REFERENCE_PUSH = 0x4B; /** * The ID of the <code>READY_EVENT_FORCE_ALL_SET</code> packet. */ public static final short ID_READY_EVENT_FORCE_ALL_SET = 0x4C; /** * The ID of the <code>ROOMS_EXECUTE_FUNC</code> packet. */ public static final short ID_ROOMS_EXECUTE_FUNC = 0x4D; /** * The ID of the <code>ROOMS_LOGON_STATUS</code> packet. */ public static final short ID_ROOMS_LOGON_STATUS = 0x4E; /** * The ID of the <code>ROOMS_HANDLE_CHANGE</code> packet. */ public static final short ID_ROOMS_HANDLE_CHANGE = 0x4F; /** * The ID of the <code>LOBBY2_SEND_MESSAGE</code> packet. */ public static final short ID_LOBBY2_SEND_MESSAGE = 0x50; /** * The ID of the <code>LOBBY2_SERVER_ERROR</code> packet. */ public static final short ID_LOBBY2_SERVER_ERROR = 0x51; /** * The ID of the <code>FMC2_NEW_HOST</code> packet. */ public static final short ID_FCM2_NEW_HOST = 0x52; /** * The ID of the <code>FCM2_REQUEST_FCMGUID</code> packet. */ public static final short ID_FCM2_REQUEST_FCMGUID = 0x53; /** * The ID of the <code>FCM2_RESPOND_CONNECTION_COUNT</code> packet. */ public static final short ID_FCM2_RESPOND_CONNECTION_COUNT = 0x54; /** * The ID of the <code>FMC2_INFORM_FCMGUID</code> packet. */ public static final short ID_FCM2_INFORM_FCMGUID = 0x55; /** * The ID of the <code>FCM2_UPDATE_MIN_TOTAL_CONNECTION_COUNT</code> packet. */ public static final short ID_FCM2_UPDATE_MIN_TOTAL_CONNECTION_COUNT = 0x56; /** * The ID of the <code>FCM2_VERIFIED_JOIN_START</code> packet. */ public static final short ID_FCM2_VERIFIED_JOIN_START = 0x57; /** * The ID of the <code>FCM2_VERIFIED_JOIN_CAPABLE</code> packet. */ public static final short ID_FCM2_VERIFIED_JOIN_CAPABLE = 0x58; /** * The ID of the <code>FCM2_VERIFIED_JOIN_FAILED</code> packet. */ public static final short ID_FCM2_VERIFIED_JOIN_FAILED = 0x59; /** * The ID of the <code>FCM2_VERIFIED_JOIN_ACCEPTED</code> packet. */ public static final short ID_FCM2_VERIFIED_JOIN_ACCEPTED = 0x5A; /** * The ID of the <code>FCM2_VERIFIED_JOIN_REJECTED</code> packet. */ public static final short ID_FCM2_VERIFIED_JOIN_REJECTED = 0x5B; /** * The ID of the <code>UDP_PROXY_GENERAL</code> packet. */ public static final short ID_UDP_PROXY_GENERAL = 0x5C; /** * The ID of the <code>SQLITE3_EXEC</code> packet. */ public static final short ID_SQLITE3_EXEC = 0x5D; /** * The ID of the <code>SQLITE3_UNKNOWN_DB</code> packet. */ public static final short ID_SQLITE3_UNKNOWN_DB = 0x5E; /** * The ID of the <code>SQLLITE_LOGGER</code> packet. */ public static final short ID_SQLLITE_LOGGER = 0x5F; /** * The ID of the <code>NAT_TYPE_DETECTION_REQUEST</code> packet. */ public static final short ID_NAT_TYPE_DETECTION_REQUEST = 0x60; /** * The ID of the <code>NAT_TYPE_DETECTION_RESULT</code> packet. */ public static final short ID_NAT_TYPE_DETECTION_RESULT = 0x61; /** * The ID of the <code>ROUTER_2_INTERNAL</code> packet. */ public static final short ID_ROUTER_2_INTERNAL = 0x62; /** * The ID of the <code>ROUTER_2_FOWARDING_NO_PATH</code> packet. */ public static final short ID_ROUTER_2_FORWARDING_NO_PATH = 0x63; /** * The ID of the <code>ROUTER_2_FORWARDING_ESTABLISHED</code> packet. */ public static final short ID_ROUTER_2_FORWARDING_ESTABLISHED = 0x64; /** * The ID of the <code>ROUTER_2_REROUTED</code> packet. */ public static final short ID_ROUTER_2_REROUTED = 0x65; /** * The ID of the <code>TEAM_BALANCER_INTERNAL</code> packet. */ public static final short ID_TEAM_BALANCER_INTERNAL = 0x66; /** * The ID of the <code>TEAM_BALANCER_REQUESTED_TEAM_FULL</code> packet. */ public static final short ID_TEAM_BALANCER_REQUESTED_TEAM_FULL = 0x67; /** * The ID of the <code>TEAM_BALANCER_REQUESTED_TEAM_LOCKED</code> packet. */ public static final short ID_TEAM_BALANCER_REQUESTED_TEAM_LOCKED = 0x68; /** * The ID of the <code>TEAM_BALANCER_TEAM_REQUESTED_CANCELLED</code> packet. */ public static final short ID_TEAM_BALANCER_TEAM_REQUESTED_CANCELLED = 0x69; /** * The ID of the <code>TEAM_BALANCER_TEAM_ASSIGNED</code> packet. */ public static final short ID_TEAM_BALANCER_TEAM_ASSIGNED = 0x6A; /** * The ID of the <code>LIGHTSPEED_INTEGRATION</code> packet. */ public static final short ID_LIGHTSPEED_INTEGRATION = 0x6B; /** * The ID of the <code>XBOX_LOBBY</code> packet. */ public static final short ID_XBOX_LOBBY = 0x6C; /** * The ID of the * <code>TWO_WAY_AUTHENTICATION_INCOMING_CHALLENEGE_SUCCESS</code> packet. */ public static final short ID_TWO_WAY_AUTHENTICATION_INCOMING_CHALLENGE_SUCCESS = 0x6D; /** * The ID of the * <code>TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_SUCCESS</code> packet. */ public static final short ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_SUCCESS = 0x6E; /** * The ID of the * <code>TWO_WAY_AUTHENTICATION_INCOMING_CHALLENGE_FAILURE</code> packet. */ public static final short ID_TWO_WAY_AUTHENTICATION_INCOMING_CHALLENGE_FAILURE = 0x6F; /** * The ID of the * <code>TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_FAILURE</code> packet. */ public static final short ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_FAILURE = 0x70; /** * The ID of the * <code>TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_TIMEOUT</code> packet. */ public static final short ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_TIMEOUT = 0x71; /** * The ID of the <code>TWO_WAY_AUTHENTICATION_NEGOTIATION</code> packet. */ public static final short ID_TWO_WAY_AUTHENTICATION_NEGOTIATION = 0x72; /** * The ID of the <code>CLOUD_POST_REQUEST</code> packet. */ public static final short ID_CLOUD_POST_REQUEST = 0x73; /** * The ID of the <code>CLOUD_RELEASE_REQUEST</code> packet. */ public static final short ID_CLOUD_RELEASE_REQUEST = 0x74; /** * The ID of the <code>CLOUD_GET_REQUEST</code> packet. */ public static final short ID_CLOUD_GET_REQUEST = 0x75; /** * The ID of the <code>CLOUD_GET_RESPONSE</code> packet. */ public static final short ID_CLOUD_GET_RESPONSE = 0x76; /** * The ID of the <code>CLOUD_UNSUBSCRIBE_REQUEST</code> packet. */ public static final short ID_CLOUD_UNSUBSCRIBE_REQUEST = 0x77; /** * The ID of the <code>CLOUD_SERVER_TO_SERVER_COMMAND</code> packet. */ public static final short ID_CLOUD_SERVER_TO_SERVER_COMMAND = 0x78; /** * The ID of the <code>CLOUD_SUBSCRIPTION_NOTIFICATION</code> packet. */ public static final short ID_CLOUD_SUBSCRIPTION_NOTIFICATION = 0x79; /** * The ID of the <code>LIB_VOICE</code> packet. */ public static final short ID_LIB_VOICE = 0x7A; /** * The ID of the <code>RELAY_PLUGIN</code> packet. */ public static final short ID_RELAY_PLUGIN = 0x7B; /** * The ID of the <code>NAT_REQUEST_BOUND_ADDRESSES</code> packet. */ public static final short ID_NAT_REQUEST_BOUND_ADDRESSES = 0x7C; /** * The ID of the <code>NAT_RESPOND_BOUND_ADDRESSES</code> packet. */ public static final short ID_NAT_RESPOND_BOUND_ADDRESSES = 0x7D; /** * The ID of the <code>FCM2_UPDATE_USER_CONTENT</code> packet. */ public static final short ID_FCM2_UPDATE_USER_CONTEXT = 0x7E; /** * The ID of the <code>RESERVED_3</code> packet. */ public static final short ID_RESERVED_3 = 0x7F; /** * The ID of the <code>RESERVED_4</code> packet. */ public static final short ID_RESERVED_4 = 0x80; /** * The ID of the <code>RESERVED_5</code> packet. */ public static final short ID_RESERVED_5 = 0x81; /** * The ID of the <code>RESERVED_6</code> packet. */ public static final short ID_RESERVED_6 = 0x82; /** * The ID of the <code>RESERVERD_7</code> packet. */ public static final short ID_RESERVED_7 = 0x83; /** * The ID of the <code>RESERVED_8</code> packet. */ public static final short ID_RESERVED_8 = 0x84; /** * The ID of the <code>RESERVED_9</code> packet. */ public static final short ID_RESERVED_9 = 0x85; /** * This is the first ID that the user can for the IDs of their packets. * Since packet IDs are written using {@link #writeUnsignedByte(int)}, the * highest packet ID that can be used is <code>0xFF</code>. * <p> * If one must have more than <code>121</code> packet IDs * (<code>0xFF - ID_USER_PACKET_ENUM</code>), then one can have a singular * ID that they use for all of their user packets with another field to be * the packet ID. */ public static final short ID_USER_PACKET_ENUM = 0x86; /** * The ID of the <code>CUSTOM_0</code> packet. */ public static final short ID_CUSTOM_0 = 0x80; /** * The ID of the <code>CUSTOM_1</code> packet. */ public static final short ID_CUSTOM_1 = 0x81; /** * The ID of the <code>CUSTOM_2</code> packet. */ public static final short ID_CUSTOM_2 = 0x82; /** * The ID of the <code>CUSTOM_3</code> packet. */ public static final short ID_CUSTOM_3 = 0x83; /** * The ID of the * {@link com.whirvis.jraknet.protocol.message.CustomFourPacket CUSTOM_4} * packet. */ public static final short ID_CUSTOM_4 = 0x84; /** * The ID of the <code>CUSTOM_5</code> packet. */ public static final short ID_CUSTOM_5 = 0x85; /** * The ID of the <code>CUSTOM_6</code> packet. */ public static final short ID_CUSTOM_6 = 0x86; /** * The ID of the <code>CUSTOM_7</code> packet. */ public static final short ID_CUSTOM_7 = 0x87; /** * The ID of the <code>CUSTOM_8</code> packet. */ public static final short ID_CUSTOM_8 = 0x88; /** * The ID of the <code>CUSTOM_9</code> packet. */ public static final short ID_CUSTOM_9 = 0x89; /** * The ID of the <code>CUSTOM_A</code> packet. */ public static final short ID_CUSTOM_A = 0x8A; /** * The ID of the <code>CUSTOM_B</code> packet. */ public static final short ID_CUSTOM_B = 0x8B; /** * The ID of the <code>CUSTOM_C</code> packet. */ public static final short ID_CUSTOM_C = 0x8C; /** * The ID of the <code>CUSTOM_D</code> packet. */ public static final short ID_CUSTOM_D = 0x8D; /** * The ID of the <code>CUSTOM_E</code> packet. */ public static final short ID_CUSTOM_E = 0x8E; /** * The ID of the <code>CUSTOM_F</code> packet. */ public static final short ID_CUSTOM_F = 0x8F; /** * The ID of the * {@link com.whirvis.jraknet.protocol.message.acknowledge.AcknowledgedPacket * ACK} packet. */ public static final short ID_ACK = 0xC0; /** * The ID of the * {@link com.whirvis.jraknet.protocol.message.acknowledge.NotAcknowledgedPacket * NACK} packet. */ public static final short ID_NACK = 0xA0; private static boolean mappedNameIds; /** * Maps all <code>public</code> packet IDs to their respective field names * and vice-versa. * <p> * Packet IDs {@link #ID_CUSTOM_0}, {@link #ID_CUSTOM_1}, * {@link #ID_CUSTOM_2}, {@link #ID_CUSTOM_3}, {@link #ID_CUSTOM_4}, * {@link #ID_CUSTOM_5}, {@link #ID_CUSTOM_6}, {@link #ID_CUSTOM_7}, * {@link #ID_CUSTOM_8}, {@link #ID_CUSTOM_9}, {@link #ID_CUSTOM_A}, * {@link #ID_CUSTOM_B}, {@link #ID_CUSTOM_C}, {@link #ID_CUSTOM_D}, * {@link #ID_CUSTOM_E}, {@link #ID_CUSTOM_F}, {@link #ID_ACK}, and * {@link #ID_NACK} will never are ignored as they are not only internal * packets but they also override other packets with the same ID. */ private static void mapNameIds() { if (mappedNameIds == false) { Logger log = LogManager.getLogger(RakNetPacket.class); for (Field field : RakNetPacket.class.getFields()) { if (field.getType().equals(short.class)) { try { short packetId = field.getShort(null); if ((packetId >= ID_CUSTOM_0 && packetId <= ID_CUSTOM_F) || packetId == ID_ACK || packetId == ID_NACK) { continue; // Ignored as they override other packet // IDs } String packetName = field.getName(); String currentName = PACKET_NAMES.put(packetId, packetName); PACKET_IDS.put(packetName, packetId); if (currentName != null) { if (!currentName.equals(packetName)) { log.warn("Found duplicate ID " + RakNet.toHexStringId(packetId) + " for \"" + packetName + "\" and \"" + currentName + "\", overriding name and ID"); } } else { log.debug("Assigned packet ID " + RakNet.toHexStringId(packetId) + " to " + packetName); } } catch (ReflectiveOperationException e) { e.printStackTrace(); } } } mappedNameIds = true; } } /** * Returns whether or not a packet with the specified ID exists as a RakNet * packet. * * @param id * the ID of the packet. * @return <code>true</code> if a packet with the ID exists as a RakNet * packet, <code>false</code>. */ public static boolean hasPacket(int id) { return PACKET_NAMES.containsKey((short) id); } /** * Returns whether or not a packet with the specified name exists as a * RakNet packet. * * @param name * the name of the packet. * @return <code>true</code> if a packet with the name exists as a RakNet * packet, <code>false</code>. */ public static boolean hasPacket(String name) { return PACKET_IDS.containsKey(name); } /** * Returns the name of the packet with the specified ID. * <p> * Packet IDs {@link #ID_CUSTOM_0}, {@link #ID_CUSTOM_1}, * {@link #ID_CUSTOM_2}, {@link #ID_CUSTOM_3}, {@link #ID_CUSTOM_4}, * {@link #ID_CUSTOM_5}, {@link #ID_CUSTOM_6}, {@link #ID_CUSTOM_7}, * {@link #ID_CUSTOM_8}, {@link #ID_CUSTOM_9}, {@link #ID_CUSTOM_A}, * {@link #ID_CUSTOM_B}, {@link #ID_CUSTOM_C}, {@link #ID_CUSTOM_D}, * {@link #ID_CUSTOM_E}, {@link #ID_CUSTOM_F}, {@link #ID_ACK}, and * {@link #ID_NACK} will never be returned as they are not only internal * packets but they also override other packets with the same ID. * * @param id * the ID of the packet. * @return the name of the packet with the specified ID, its hexadecimal ID * according to {@link RakNet#toHexStringId(int)} if it does not * exist. */ public static String getName(int id) { if (mappedNameIds == false) { mapNameIds(); } if (!PACKET_NAMES.containsKey((short) id)) { return RakNet.toHexStringId(id & 0xFF); } return PACKET_NAMES.get((short) id); } /** * Returns the name of the specified packet. * <p> * Packet IDs {@link #ID_CUSTOM_0}, {@link #ID_CUSTOM_1}, * {@link #ID_CUSTOM_2}, {@link #ID_CUSTOM_3}, {@link #ID_CUSTOM_4}, * {@link #ID_CUSTOM_5}, {@link #ID_CUSTOM_6}, {@link #ID_CUSTOM_7}, * {@link #ID_CUSTOM_8}, {@link #ID_CUSTOM_9}, {@link #ID_CUSTOM_A}, * {@link #ID_CUSTOM_B}, {@link #ID_CUSTOM_C}, {@link #ID_CUSTOM_D}, * {@link #ID_CUSTOM_E}, {@link #ID_CUSTOM_F}, {@link #ID_ACK}, and * {@link #ID_NACK} will never be returned as they are not only internal * packets but they also override other packets with the same ID. * * @param packet * the packet. * @return the name of the packet, its hexadecimal ID according to * {@link RakNet#toHexStringId(int)} if it does not exist. * @throws NullPointerException * if the <code>packet</code> is <code>null</code>. */ public static String getName(RakNetPacket packet) throws NullPointerException { if (packet == null) { throw new NullPointerException("Packet cannot be null"); } return getName(packet.getId()); } /** * Returns the ID of the packet with the specified name. * * @param name * the name of the packet. * @return the ID of the packet with the specified name, <code>-1</code> if * it does not exist. */ public static short getId(String name) { if (mappedNameIds == false) { mapNameIds(); } return PACKET_IDS.containsKey(name) ? PACKET_IDS.get(name) : -1; } /** * Returns whether or not a method with the specified name has been * overridden the method in the original specified class by the specified * class instance. * * @param instance * the class instance. * @param clazz * the original class. * @param methodName * the name of the method. * @return <code>true</code> if the method has been overridden, * <code>false</code> otherwise. */ private static boolean isMethodOverriden(Class<?> instance, Class<?> clazz, String methodName) { try { return !clazz.getMethod(ENCODE_METHOD_NAME).getDeclaringClass().equals(clazz); } catch (NoSuchMethodException | SecurityException e) { return false; } } private short id; private final boolean supportsEncoding; private final boolean supportsDecoding; /** * Creates a RakNet packet. * * @param id * the ID of the packet. * @throws IllegalArgumentException * if the <code>id</code> is not in between <code>0-255</code>. */ public RakNetPacket(int id) throws IllegalArgumentException { super(); if (id < 0x00 || id > 0xFF) { throw new IllegalArgumentException("ID must be in between 0-255"); } this.writeUnsignedByte(this.id = (short) id); this.supportsEncoding = isMethodOverriden(this.getClass(), RakNetPacket.class, ENCODE_METHOD_NAME); this.supportsDecoding = isMethodOverriden(this.getClass(), RakNetPacket.class, DECODE_METHOD_NAME); } /** * Creates a RakNet packet. * * @param buffer * the buffer to read from and write to. The buffer must have at * least one byte to be read from for the ID. * @throws IllegalArgumentException * if the <code>buffer</code> has less than <code>1</code> * readable <code>byte</code>. */ public RakNetPacket(ByteBuf buffer) throws IllegalArgumentException { super(buffer); if (this.remaining() < 1) { throw new IllegalArgumentException("Buffer must have at least one readable byte for the ID"); } this.id = this.readUnsignedByte(); this.supportsEncoding = isMethodOverriden(this.getClass(), RakNetPacket.class, ENCODE_METHOD_NAME); this.supportsDecoding = isMethodOverriden(this.getClass(), RakNetPacket.class, DECODE_METHOD_NAME); } /** * Creates a RakNet packet. * * @param datagram * the datagram packet to read from. The datagram must have at * least one byte to be read from for the ID. * @throws IllegalArgumentException * if the buffer contained within the datagram has less than * <code>1</code> readable <code>byte</code>. * @see #RakNetPacket(ByteBuf) */ public RakNetPacket(DatagramPacket datagram) throws IllegalArgumentException { this(datagram.content()); } /** * Creates a RakNet packet. * * @param data * the byte array to read to read from. The byte array must have * at least one byte to be read from for the ID. * @throws IllegalArgumentException * if the length of the <code>data</code> is less than * <code>1</code>. * @see #RakNetPacket(ByteBuf) */ public RakNetPacket(byte[] data) throws IllegalArgumentException { this(Unpooled.copiedBuffer(data)); } /** * Creates a RakNet packet. * * @param packet * the packet to read from and write to. The packet must have at * least one byte to be read from for the ID. If the packet is an * instance of {@link RakNetPacket}, it will be casted and have * its ID retrieved via {@link #getId()}. * @throws IllegalArgumentException * if the packet size has less than <code>1</code> readable * <code>byte</code> and is not an instance of * {@link RakNetPacket}. */ public RakNetPacket(Packet packet) throws IllegalArgumentException { super(packet); if (packet instanceof RakNetPacket) { this.id = ((RakNetPacket) packet).id; } else { if (this.remaining() < 1) { throw new IllegalArgumentException("The packet must have at least one byte to read the ID"); } this.id = this.readUnsignedByte(); } this.supportsEncoding = isMethodOverriden(this.getClass(), RakNetPacket.class, ENCODE_METHOD_NAME); this.supportsDecoding = isMethodOverriden(this.getClass(), RakNetPacket.class, DECODE_METHOD_NAME); } /** * Returns the ID of the packet. * * @return the ID of the packet. */ public final short getId() { return this.id; } /** * Reads a magic array and returns whether or not it is valid. * * @return <code>true</code> if the magic array was valid, * <code>false</code> otherwise. */ public final boolean readMagic() { byte[] magicCheck = this.read(MAGIC.length); return Arrays.equals(MAGIC, magicCheck); } /** * Reads a {@link ConnectionType}. * <p> * This method will check to make sure if there is at least enough data to * read the the connection type magic before reading the data. This is due * to the fact that this is meant to be used strictly at the end of packets * that can be used to signify the protocol implementation of the sender. * * @return a {@link ConnectionType}, {@link ConnectionType#VANILLA} if not * enough data to read one is present. * @throws RakNetException * if not enough data is present in the packet after the * connection type magic or there are duplicate keys in the * metadata. */ public final ConnectionType readConnectionType() throws RakNetException { if (this.remaining() >= ConnectionType.MAGIC.length) { byte[] connectionMagicCheck = this.read(ConnectionType.MAGIC.length); if (Arrays.equals(ConnectionType.MAGIC, connectionMagicCheck)) { UUID uuid = this.readUUID(); String name = this.readString(); String language = this.readString(); String version = this.readString(); HashMap<String, String> metadata = new HashMap<String, String>(); int metadataLength = this.readUnsignedByte(); for (int i = 0; i < metadataLength; i++) { String key = this.readString(); String value = this.readString(); if (metadata.containsKey(key)) { throw new RakNetException("Duplicate metadata key \"" + key + "\""); } metadata.put(key, value); } return new ConnectionType(uuid, name, language, version, metadata); } } return ConnectionType.VANILLA; } /** * Writes the magic sequence to the packet. * * @return the packet. */ public final RakNetPacket writeMagic() { this.write(MAGIC); return this; } /** * Writes a {@link ConnectionType} to the packet. * * @param connectionType * the connection type, a <code>null</code> value will have * {@link ConnectionType#JRAKNET} connection type be used * instead. * @return the packet. * @throws RakNetException * if there are too many values in the metadata. */ public final Packet writeConnectionType(ConnectionType connectionType) throws RakNetException { connectionType = (connectionType != null ? connectionType : ConnectionType.JRAKNET); this.write(ConnectionType.MAGIC); this.writeUUID(connectionType.getUUID()); this.writeString(connectionType.getName()); this.writeString(connectionType.getLanguage()); this.writeString(connectionType.getVersion()); if (connectionType.getMetaData().size() > ConnectionType.MAX_METADATA_VALUES) { throw new RakNetException("Too many metadata values"); } this.writeUnsignedByte(connectionType.getMetaData().size()); for (Entry<String, String> metadataEntry : connectionType.getMetaData().entrySet()) { this.writeString(metadataEntry.getKey()); this.writeString(metadataEntry.getValue()); } return this; } /** * Writes the {@link ConnectionType#JRAKNET} connection type to the packet. * * @return the packet. * @throws RuntimeException * if a <code>RakNetException</code> is caught despite the fact * that this method should never throw an error in the first * place. */ public final Packet writeConnectionType() throws RuntimeException { try { return this.writeConnectionType(null); } catch (RakNetException e) { throw new RuntimeException(e); } } /** * Returns whether or not encoding is supported. If encoding is not * supported, calling {@link #encode()} will yield an * <code>UnsupportedOperationException</code>. * * @return <code>true</code> if encoding is supported, <code>false</code> * otherwise. */ public final boolean supportsEncoding() { return this.supportsEncoding; } /** * Encodes the packet. * * @throws UnsupportedOperationException * if encoding the packet is not supported. */ public void encode() throws UnsupportedOperationException { throw new UnsupportedOperationException("Encoding not supported"); } /** * Returns whether or not decoding is supported. If decoding is not * supported, calling {@link #decode()} will yield an * <code>UnsupportedOperationException</code>. * * @return <code>true</code> if decoding is supported, <code>false</code> * otherwise. */ public final boolean supportsDecoding() { return this.supportsDecoding; } /** * Decodes the packet. * * @throws UnsupportedOperationException * if decoding the packet is not supported. */ public void decode() throws UnsupportedOperationException { throw new UnsupportedOperationException("Decoding not supported"); } /** * Updates the buffer. * * @param buffer * the buffer to read from and write to, a <code>null</code> * value will have a new buffer be used instead. * @param updateId * <code>true</code> if the ID should be updated, * <code>false</code> otherwise. * @return the packet. * @throws IndexOutOfBoundsException * if <code>updateId</code> is <code>true</code> and the new * buffer has less than <code>1</code> readable * <code>byte</code>. * @see #setBuffer(ByteBuf) */ public final RakNetPacket setBuffer(ByteBuf buffer, boolean updateId) throws IndexOutOfBoundsException { super.setBuffer(buffer); if (updateId == true) { this.id = this.readUnsignedByte(); } return this; } /** * Updates the buffer. * * @param datagram * the {@link DatagramPacket} whose buffer to read from and write * to. * @param updateId * <code>true</code> if the ID should be updated, * <code>false</code> otherwise. * @return the packet. * @throws NullPointerException * if the <code>datagram</code> packet is <code>null</code>. * @throws IndexOutOfBoundsException * if <code>updateId</code> is <code>true</code> and the new * buffer has less than <code>1</code> readable * <code>byte</code>. * @see #setBuffer(DatagramPacket) */ public final RakNetPacket setBuffer(DatagramPacket datagram, boolean updateId) throws NullPointerException, IndexOutOfBoundsException { if (datagram == null) { throw new NullPointerException("Datagram packet cannot be null"); } return this.setBuffer(datagram.content(), updateId); } /** * Updates the buffer. * * @param data * the <code>byte[]</code> to create the new buffer from. * @param updateId * <code>true</code> if the ID should be updated, * <code>false</code> otherwise. * @return the packet. * @throws NullPointerException * if the <code>data</code> is <code>null</code>. * @throws IndexOutOfBoundsException * if <code>updateId</code> is <code>true</code> and the new * buffer has less than <code>1</code> readable * <code>byte</code>. * @see #setBuffer(byte[]) */ public final RakNetPacket setBuffer(byte[] data, boolean updateId) throws NullPointerException, IndexOutOfBoundsException { return this.setBuffer(Unpooled.copiedBuffer(data), updateId); } /** * Updates the buffer. * * @param packet * the packet whose buffer to copy to read from and write to. * @param updateId * <code>true</code> if the ID should be updated, * <code>false</code> otherwise. * @return the packet. * @throws IndexOutOfBoundsException * if <code>updateId</code> is <code>true</code> and the new * buffer has less than <code>1</code> readable * <code>byte</code>. * @see #setBuffer(Packet) */ public final RakNetPacket setBuffer(Packet packet, boolean updateId) throws NullPointerException, IndexOutOfBoundsException { return this.setBuffer(packet.copy(), updateId); } /** * Flips the packet. * * @param updateId * <code>true</code> if ID should be updated, <code>false</code> * otherwise. * @return the packet. * @throws IndexOutOfBoundsException * if <code>updateId</code> is <code>true</code> and the buffer * has less than <code>1</code> readable <code>byte</code>. * @see #flip() */ public final RakNetPacket flip(boolean updateId) throws IndexOutOfBoundsException { super.flip(); if (updateId == true) { this.id = this.readUnsignedByte(); } return this; } /** * {@inheritDoc} After the packet has been flipped, an unsigined * <code>byte</code> will be read to get the ID. * * @throws IndexOutOfBoundsException * if the buffer has less than <code>1</code> readable * <code>byte</code>. */ @Override public Packet flip() throws IndexOutOfBoundsException { return this.flip(true); } @Override public String toString() { return "RakNetPacket [id=" + id + ", size()=" + size() + ", remaining()=" + remaining() + "]"; } }