2021-04-26 22:54:43 +02:00
/ *
* This file is part of ViaVersion - https : //github.com/ViaVersion/ViaVersion
2024-01-01 12:39:45 +01:00
* Copyright ( C ) 2016 - 2024 ViaVersion and contributors
2021-04-26 22:54:43 +02:00
*
2021-04-30 19:05:07 +02:00
* 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 3 of the License , or
* ( at your option ) any later version .
2021-04-26 22:54:43 +02:00
*
2021-04-30 19:05:07 +02:00
* 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 .
2021-04-26 22:54:43 +02:00
*
2021-04-30 19:05:07 +02:00
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2021-04-26 22:54:43 +02:00
* /
package com.viaversion.viaversion.protocol.packet ;
import com.google.common.base.Preconditions ;
import com.viaversion.viaversion.api.Via ;
2023-09-25 08:40:13 +02:00
import com.viaversion.viaversion.api.connection.ProtocolInfo ;
2021-04-26 22:54:43 +02:00
import com.viaversion.viaversion.api.connection.UserConnection ;
2021-04-27 18:21:51 +02:00
import com.viaversion.viaversion.api.protocol.Protocol ;
2021-04-26 22:54:43 +02:00
import com.viaversion.viaversion.api.protocol.packet.Direction ;
2021-07-31 12:43:07 +02:00
import com.viaversion.viaversion.api.protocol.packet.PacketType ;
2021-04-26 22:54:43 +02:00
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper ;
import com.viaversion.viaversion.api.protocol.packet.State ;
2021-06-02 22:00:20 +02:00
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler ;
2021-04-26 22:54:43 +02:00
import com.viaversion.viaversion.api.type.Type ;
import com.viaversion.viaversion.api.type.TypeConverter ;
import com.viaversion.viaversion.exception.CancelException ;
import com.viaversion.viaversion.exception.InformativeException ;
import com.viaversion.viaversion.util.PipelineUtil ;
import io.netty.buffer.ByteBuf ;
import io.netty.channel.ChannelFuture ;
import java.io.IOException ;
import java.util.ArrayDeque ;
import java.util.ArrayList ;
import java.util.Deque ;
import java.util.List ;
import java.util.NoSuchElementException ;
2023-03-17 13:26:13 +01:00
import java.util.Objects ;
2023-02-12 11:44:25 +01:00
import org.checkerframework.checker.nullness.qual.Nullable ;
2021-04-26 22:54:43 +02:00
public class PacketWrapperImpl implements PacketWrapper {
private static final Protocol [ ] PROTOCOL_ARRAY = new Protocol [ 0 ] ;
2023-10-20 04:31:16 +02:00
private final Deque < PacketValue < ? > > readableObjects = new ArrayDeque < > ( ) ;
private final List < PacketValue < ? > > packetValues = new ArrayList < > ( ) ;
2021-04-26 22:54:43 +02:00
private final ByteBuf inputBuffer ;
private final UserConnection userConnection ;
private boolean send = true ;
2023-01-06 20:33:17 +01:00
/ * *
* Only non - null if specifically set and gotten before packet transformation
* /
2021-07-31 12:43:07 +02:00
private PacketType packetType ;
private int id ;
2021-04-26 22:54:43 +02:00
2021-05-14 16:59:12 +02:00
public PacketWrapperImpl ( int packetId , @Nullable ByteBuf inputBuffer , UserConnection userConnection ) {
this . id = packetId ;
2021-04-26 22:54:43 +02:00
this . inputBuffer = inputBuffer ;
this . userConnection = userConnection ;
}
2021-07-31 12:43:07 +02:00
public PacketWrapperImpl ( @Nullable PacketType packetType , @Nullable ByteBuf inputBuffer , UserConnection userConnection ) {
this . packetType = packetType ;
this . id = packetType ! = null ? packetType . getId ( ) : - 1 ;
this . inputBuffer = inputBuffer ;
this . userConnection = userConnection ;
}
2021-04-26 22:54:43 +02:00
@Override
public < T > T get ( Type < T > type , int index ) throws Exception {
int currentIndex = 0 ;
2023-10-20 04:31:16 +02:00
for ( PacketValue < ? > packetValue : packetValues ) {
2023-02-28 21:49:08 +01:00
if ( packetValue . type ( ) ! = type ) {
continue ;
}
2021-05-29 20:53:47 +02:00
if ( currentIndex = = index ) {
2023-02-12 10:54:47 +01:00
//noinspection unchecked
2021-09-14 11:13:39 +02:00
return ( T ) packetValue . value ( ) ;
2021-04-26 22:54:43 +02:00
}
2021-05-29 20:53:47 +02:00
currentIndex + + ;
2021-04-26 22:54:43 +02:00
}
2023-01-06 20:33:17 +01:00
throw createInformativeException ( new ArrayIndexOutOfBoundsException ( " Could not find type " + type . getTypeName ( ) + " at " + index ) , type , index ) ;
2021-04-26 22:54:43 +02:00
}
@Override
public boolean is ( Type type , int index ) {
int currentIndex = 0 ;
2023-10-20 04:31:16 +02:00
for ( PacketValue < ? > packetValue : packetValues ) {
2023-02-28 21:49:08 +01:00
if ( packetValue . type ( ) ! = type ) {
continue ;
}
2021-05-29 20:53:47 +02:00
if ( currentIndex = = index ) {
return true ;
2021-04-26 22:54:43 +02:00
}
2021-05-29 20:53:47 +02:00
currentIndex + + ;
2021-04-26 22:54:43 +02:00
}
return false ;
}
@Override
public boolean isReadable ( Type type , int index ) {
int currentIndex = 0 ;
2023-10-20 04:31:16 +02:00
for ( PacketValue < ? > packetValue : readableObjects ) {
2023-02-28 21:49:08 +01:00
if ( packetValue . type ( ) . getBaseClass ( ) ! = type . getBaseClass ( ) ) {
continue ;
}
2021-05-29 20:53:47 +02:00
if ( currentIndex = = index ) {
return true ;
2021-04-26 22:54:43 +02:00
}
2021-05-29 20:53:47 +02:00
currentIndex + + ;
2021-04-26 22:54:43 +02:00
}
return false ;
}
@Override
public < T > void set ( Type < T > type , int index , T value ) throws Exception {
int currentIndex = 0 ;
2023-02-28 21:49:08 +01:00
for ( PacketValue packetValue : packetValues ) {
if ( packetValue . type ( ) ! = type ) {
continue ;
}
2021-05-29 20:53:47 +02:00
if ( currentIndex = = index ) {
packetValue . setValue ( attemptTransform ( type , value ) ) ;
return ;
2021-04-26 22:54:43 +02:00
}
2021-05-29 20:53:47 +02:00
currentIndex + + ;
2021-04-26 22:54:43 +02:00
}
2023-01-06 20:33:17 +01:00
throw createInformativeException ( new ArrayIndexOutOfBoundsException ( " Could not find type " + type . getTypeName ( ) + " at " + index ) , type , index ) ;
2021-04-26 22:54:43 +02:00
}
@Override
public < T > T read ( Type < T > type ) throws Exception {
if ( readableObjects . isEmpty ( ) ) {
Preconditions . checkNotNull ( inputBuffer , " This packet does not have an input buffer. " ) ;
// We could in the future log input read values, but honestly for things like bulk maps, mem waste D:
try {
return type . read ( inputBuffer ) ;
} catch ( Exception e ) {
2023-01-06 20:33:17 +01:00
throw createInformativeException ( e , type , packetValues . size ( ) + 1 ) ;
2021-04-26 22:54:43 +02:00
}
2021-05-29 20:53:47 +02:00
}
2023-02-28 21:49:08 +01:00
PacketValue readValue = readableObjects . poll ( ) ;
2023-10-20 04:31:16 +02:00
Type < ? > readType = readValue . type ( ) ;
2023-02-28 21:49:08 +01:00
if ( readType = = type
| | ( type . getBaseClass ( ) = = readType . getBaseClass ( )
& & type . getOutputClass ( ) = = readType . getOutputClass ( ) ) ) {
2023-02-12 10:54:47 +01:00
//noinspection unchecked
2023-02-28 21:49:08 +01:00
return ( T ) readValue . value ( ) ;
2021-04-26 22:54:43 +02:00
} else {
2023-02-28 21:49:08 +01:00
throw createInformativeException ( new IOException ( " Unable to read type " + type . getTypeName ( ) + " , found " + readValue . type ( ) . getTypeName ( ) ) , type , readableObjects . size ( ) ) ;
2021-04-26 22:54:43 +02:00
}
}
@Override
public < T > void write ( Type < T > type , T value ) {
2023-10-20 04:31:16 +02:00
packetValues . add ( new PacketValue < > ( type , attemptTransform ( type , value ) ) ) ;
2021-05-29 20:53:47 +02:00
}
/ * *
* Returns the value if already matching , else the converted value or possibly unmatched value .
*
* @param expectedType expected type
* @param value value
* @return value if already matching , else the converted value or possibly unmatched value
* /
2023-10-20 04:31:16 +02:00
private < T > @Nullable T attemptTransform ( Type < T > expectedType , @Nullable T value ) {
2021-05-29 20:53:47 +02:00
if ( value ! = null & & ! expectedType . getOutputClass ( ) . isAssignableFrom ( value . getClass ( ) ) ) {
// Attempt conversion
2023-10-20 04:31:16 +02:00
if ( expectedType instanceof TypeConverter < ? > ) {
//noinspection unchecked
return ( ( TypeConverter < T > ) expectedType ) . from ( value ) ;
2021-04-26 22:54:43 +02:00
}
2021-05-29 20:53:47 +02:00
Via . getPlatform ( ) . getLogger ( ) . warning ( " Possible type mismatch: " + value . getClass ( ) . getName ( ) + " -> " + expectedType . getOutputClass ( ) ) ;
2021-04-26 22:54:43 +02:00
}
2021-05-29 20:53:47 +02:00
return value ;
2021-04-26 22:54:43 +02:00
}
@Override
public < T > T passthrough ( Type < T > type ) throws Exception {
T value = read ( type ) ;
write ( type , value ) ;
return value ;
}
@Override
public void passthroughAll ( ) throws Exception {
// Copy previous objects
packetValues . addAll ( readableObjects ) ;
readableObjects . clear ( ) ;
// If the buffer has readable bytes, copy them.
if ( inputBuffer . isReadable ( ) ) {
passthrough ( Type . REMAINING_BYTES ) ;
}
}
@Override
public void writeToBuffer ( ByteBuf buffer ) throws Exception {
if ( id ! = - 1 ) {
Type . VAR_INT . writePrimitive ( buffer , id ) ;
}
if ( ! readableObjects . isEmpty ( ) ) {
packetValues . addAll ( readableObjects ) ;
readableObjects . clear ( ) ;
}
int index = 0 ;
2023-10-20 04:31:16 +02:00
for ( final PacketValue < ? > packetValue : packetValues ) {
2021-04-26 22:54:43 +02:00
try {
2023-10-20 04:31:16 +02:00
packetValue . write ( buffer ) ;
} catch ( final Exception e ) {
2023-02-28 21:49:08 +01:00
throw createInformativeException ( e , packetValue . type ( ) , index ) ;
2021-04-26 22:54:43 +02:00
}
index + + ;
}
writeRemaining ( buffer ) ;
}
2023-01-06 20:33:17 +01:00
private InformativeException createInformativeException ( final Exception cause , final Type < ? > type , final int index ) {
return new InformativeException ( cause )
. set ( " Index " , index )
. set ( " Type " , type . getTypeName ( ) )
. set ( " Packet ID " , this . id )
. set ( " Packet Type " , this . packetType )
. set ( " Data " , this . packetValues ) ;
}
2021-04-26 22:54:43 +02:00
@Override
public void clearInputBuffer ( ) {
if ( inputBuffer ! = null ) {
inputBuffer . clear ( ) ;
}
readableObjects . clear ( ) ; // :(
}
@Override
public void clearPacket ( ) {
clearInputBuffer ( ) ;
packetValues . clear ( ) ;
}
private void writeRemaining ( ByteBuf output ) {
if ( inputBuffer ! = null ) {
output . writeBytes ( inputBuffer ) ;
}
}
@Override
2021-05-31 22:58:47 +02:00
public void send ( Class < ? extends Protocol > protocol , boolean skipCurrentPipeline ) throws Exception {
send0 ( protocol , skipCurrentPipeline , true ) ;
2021-04-26 22:54:43 +02:00
}
@Override
2021-05-31 22:58:47 +02:00
public void scheduleSend ( Class < ? extends Protocol > protocol , boolean skipCurrentPipeline ) throws Exception {
send0 ( protocol , skipCurrentPipeline , false ) ;
}
private void send0 ( Class < ? extends Protocol > protocol , boolean skipCurrentPipeline , boolean currentThread ) throws Exception {
2023-04-26 12:18:08 +02:00
if ( isCancelled ( ) ) {
return ;
}
2021-05-31 22:58:47 +02:00
2023-04-26 12:18:08 +02:00
final UserConnection connection = user ( ) ;
if ( currentThread ) {
try {
final ByteBuf output = constructPacket ( protocol , skipCurrentPipeline , Direction . CLIENTBOUND ) ;
connection . sendRawPacket ( output ) ;
} catch ( final Exception e ) {
if ( ! PipelineUtil . containsCause ( e , CancelException . class ) ) {
throw e ;
}
2021-04-26 22:54:43 +02:00
}
2023-04-26 12:18:08 +02:00
return ;
2021-04-26 22:54:43 +02:00
}
2023-04-26 12:18:08 +02:00
connection . getChannel ( ) . eventLoop ( ) . submit ( ( ) - > {
try {
final ByteBuf output = constructPacket ( protocol , skipCurrentPipeline , Direction . CLIENTBOUND ) ;
connection . sendRawPacket ( output ) ;
} catch ( final RuntimeException e ) {
if ( ! PipelineUtil . containsCause ( e , CancelException . class ) ) {
throw e ;
}
} catch ( final Exception e ) {
if ( ! PipelineUtil . containsCause ( e , CancelException . class ) ) {
throw new RuntimeException ( e ) ;
}
}
} ) ;
2021-04-26 22:54:43 +02:00
}
/ * *
* Let the packet go through the protocol pipes and write it to ByteBuf
*
* @param packetProtocol The protocol version of the packet .
* @param skipCurrentPipeline Skip the current pipeline
* @return Packet buffer
* @throws Exception if it fails to write
* /
private ByteBuf constructPacket ( Class < ? extends Protocol > packetProtocol , boolean skipCurrentPipeline , Direction direction ) throws Exception {
2023-09-25 08:40:13 +02:00
final ProtocolInfo protocolInfo = user ( ) . getProtocolInfo ( ) ;
2023-09-25 10:59:15 +02:00
final List < Protocol > pipes = direction = = Direction . SERVERBOUND ? protocolInfo . getPipeline ( ) . pipes ( ) : protocolInfo . getPipeline ( ) . reversedPipes ( ) ;
final List < Protocol > protocols = new ArrayList < > ( ) ;
2021-04-26 22:54:43 +02:00
int index = - 1 ;
2023-09-25 10:59:15 +02:00
for ( int i = 0 ; i < pipes . size ( ) ; i + + ) {
// Always add base protocols to the head
final Protocol protocol = pipes . get ( i ) ;
if ( protocol . isBaseProtocol ( ) ) {
protocols . add ( protocol ) ;
}
if ( protocol . getClass ( ) = = packetProtocol ) {
2021-04-26 22:54:43 +02:00
index = i ;
break ;
}
}
if ( index = = - 1 ) {
// The given protocol is not in the pipeline
throw new NoSuchElementException ( packetProtocol . getCanonicalName ( ) ) ;
}
if ( skipCurrentPipeline ) {
2023-09-25 10:59:15 +02:00
index = Math . min ( index + 1 , pipes . size ( ) ) ;
2021-04-26 22:54:43 +02:00
}
2023-09-25 10:59:15 +02:00
// Add remaining protocols on top
protocols . addAll ( pipes . subList ( index , pipes . size ( ) ) ) ;
2021-04-26 22:54:43 +02:00
// Reset reader before we start
resetReader ( ) ;
// Apply other protocols
2023-09-25 10:59:15 +02:00
apply ( direction , protocolInfo . getState ( direction ) , 0 , protocols ) ;
2023-09-25 08:40:13 +02:00
final ByteBuf output = inputBuffer = = null ? user ( ) . getChannel ( ) . alloc ( ) . buffer ( ) : inputBuffer . alloc ( ) . buffer ( ) ;
2021-04-26 22:54:43 +02:00
try {
writeToBuffer ( output ) ;
return output . retain ( ) ;
} finally {
output . release ( ) ;
}
}
@Override
public ChannelFuture sendFuture ( Class < ? extends Protocol > packetProtocol ) throws Exception {
if ( ! isCancelled ( ) ) {
2021-04-28 12:59:37 +02:00
ByteBuf output = constructPacket ( packetProtocol , true , Direction . CLIENTBOUND ) ;
2021-04-26 22:54:43 +02:00
return user ( ) . sendRawPacketFuture ( output ) ;
}
return user ( ) . getChannel ( ) . newFailedFuture ( new Exception ( " Cancelled packet " ) ) ;
}
@Override
2021-07-27 17:23:55 +02:00
public void sendRaw ( ) throws Exception {
sendRaw ( true ) ;
}
@Override
public void scheduleSendRaw ( ) throws Exception {
sendRaw ( false ) ;
}
private void sendRaw ( boolean currentThread ) throws Exception {
2023-10-08 12:19:48 +02:00
if ( isCancelled ( ) ) {
return ;
}
2021-05-31 22:58:47 +02:00
ByteBuf output = inputBuffer = = null ? user ( ) . getChannel ( ) . alloc ( ) . buffer ( ) : inputBuffer . alloc ( ) . buffer ( ) ;
try {
writeToBuffer ( output ) ;
2021-07-27 17:23:55 +02:00
if ( currentThread ) {
user ( ) . sendRawPacket ( output . retain ( ) ) ;
} else {
user ( ) . scheduleSendRawPacket ( output . retain ( ) ) ;
}
2021-05-31 22:58:47 +02:00
} finally {
output . release ( ) ;
2021-04-26 22:54:43 +02:00
}
}
@Override
2021-06-01 22:52:05 +02:00
public PacketWrapperImpl create ( int packetId ) {
return new PacketWrapperImpl ( packetId , null , user ( ) ) ;
2021-04-26 22:54:43 +02:00
}
@Override
2021-06-02 22:00:20 +02:00
public PacketWrapperImpl create ( int packetId , PacketHandler handler ) throws Exception {
2021-06-01 22:52:05 +02:00
PacketWrapperImpl wrapper = create ( packetId ) ;
2021-06-02 22:00:20 +02:00
handler . handle ( wrapper ) ;
2021-04-26 22:54:43 +02:00
return wrapper ;
}
@Override
public PacketWrapperImpl apply ( Direction direction , State state , int index , List < Protocol > pipeline , boolean reverse ) throws Exception {
Protocol [ ] array = pipeline . toArray ( PROTOCOL_ARRAY ) ;
return apply ( direction , state , reverse ? array . length - 1 : index , array , reverse ) ; // Copy to prevent from removal
}
@Override
public PacketWrapperImpl apply ( Direction direction , State state , int index , List < Protocol > pipeline ) throws Exception {
return apply ( direction , state , index , pipeline . toArray ( PROTOCOL_ARRAY ) , false ) ;
}
private PacketWrapperImpl apply ( Direction direction , State state , int index , Protocol [ ] pipeline , boolean reverse ) throws Exception {
// Reset the reader after every transformation for the packetWrapper, so it can be recycled across packets
2023-09-25 08:40:13 +02:00
State updatedState = state ; // The state might change while transforming, so we need to check for that
2021-04-26 22:54:43 +02:00
if ( reverse ) {
for ( int i = index ; i > = 0 ; i - - ) {
2023-09-25 08:40:13 +02:00
pipeline [ i ] . transform ( direction , updatedState , this ) ;
2021-04-26 22:54:43 +02:00
resetReader ( ) ;
2023-09-25 08:40:13 +02:00
if ( this . packetType ! = null ) {
updatedState = this . packetType . state ( ) ;
}
2021-04-26 22:54:43 +02:00
}
} else {
for ( int i = index ; i < pipeline . length ; i + + ) {
2023-09-25 08:40:13 +02:00
pipeline [ i ] . transform ( direction , updatedState , this ) ;
2021-04-26 22:54:43 +02:00
resetReader ( ) ;
2023-09-25 08:40:13 +02:00
if ( this . packetType ! = null ) {
updatedState = this . packetType . state ( ) ;
}
2021-04-26 22:54:43 +02:00
}
}
return this ;
}
@Override
2023-02-28 21:49:08 +01:00
public boolean isCancelled ( ) {
return ! this . send ;
2021-04-26 22:54:43 +02:00
}
@Override
2023-02-28 21:49:08 +01:00
public void setCancelled ( boolean cancel ) {
this . send = ! cancel ;
2021-04-26 22:54:43 +02:00
}
@Override
public UserConnection user ( ) {
return this . userConnection ;
}
@Override
public void resetReader ( ) {
// Move all packet values to the readable for next packet.
for ( int i = packetValues . size ( ) - 1 ; i > = 0 ; i - - ) {
this . readableObjects . addFirst ( this . packetValues . get ( i ) ) ;
}
this . packetValues . clear ( ) ;
}
@Override
2021-07-27 17:23:55 +02:00
public void sendToServerRaw ( ) throws Exception {
sendToServerRaw ( true ) ;
}
@Override
public void scheduleSendToServerRaw ( ) throws Exception {
sendToServerRaw ( false ) ;
}
private void sendToServerRaw ( boolean currentThread ) throws Exception {
2023-04-26 12:18:08 +02:00
if ( isCancelled ( ) ) {
return ;
}
2021-04-26 22:54:43 +02:00
2021-05-31 22:58:47 +02:00
ByteBuf output = inputBuffer = = null ? user ( ) . getChannel ( ) . alloc ( ) . buffer ( ) : inputBuffer . alloc ( ) . buffer ( ) ;
try {
writeToBuffer ( output ) ;
2021-07-27 17:23:55 +02:00
if ( currentThread ) {
user ( ) . sendRawPacketToServer ( output . retain ( ) ) ;
} else {
user ( ) . scheduleSendRawPacketToServer ( output . retain ( ) ) ;
}
2021-05-31 22:58:47 +02:00
} finally {
output . release ( ) ;
2021-04-26 22:54:43 +02:00
}
}
@Override
2021-05-31 22:58:47 +02:00
public void sendToServer ( Class < ? extends Protocol > protocol , boolean skipCurrentPipeline ) throws Exception {
sendToServer0 ( protocol , skipCurrentPipeline , true ) ;
}
@Override
public void scheduleSendToServer ( Class < ? extends Protocol > protocol , boolean skipCurrentPipeline ) throws Exception {
sendToServer0 ( protocol , skipCurrentPipeline , false ) ;
}
private void sendToServer0 ( Class < ? extends Protocol > protocol , boolean skipCurrentPipeline , boolean currentThread ) throws Exception {
2023-02-28 21:49:08 +01:00
if ( isCancelled ( ) ) {
return ;
}
2021-05-31 22:58:47 +02:00
2023-04-26 12:18:08 +02:00
final UserConnection connection = user ( ) ;
if ( currentThread ) {
try {
final ByteBuf output = constructPacket ( protocol , skipCurrentPipeline , Direction . SERVERBOUND ) ;
connection . sendRawPacketToServer ( output ) ;
} catch ( final Exception e ) {
if ( ! PipelineUtil . containsCause ( e , CancelException . class ) ) {
throw e ;
}
2021-04-26 22:54:43 +02:00
}
2023-04-26 12:18:08 +02:00
return ;
2021-04-26 22:54:43 +02:00
}
2023-04-26 12:18:08 +02:00
connection . getChannel ( ) . eventLoop ( ) . submit ( ( ) - > {
try {
final ByteBuf output = constructPacket ( protocol , skipCurrentPipeline , Direction . SERVERBOUND ) ;
connection . sendRawPacketToServer ( output ) ;
} catch ( final RuntimeException e ) {
if ( ! PipelineUtil . containsCause ( e , CancelException . class ) ) {
throw e ;
}
} catch ( final Exception e ) {
if ( ! PipelineUtil . containsCause ( e , CancelException . class ) ) {
throw new RuntimeException ( e ) ;
}
}
} ) ;
2021-04-26 22:54:43 +02:00
}
2021-07-31 12:43:07 +02:00
@Override
public @Nullable PacketType getPacketType ( ) {
return packetType ;
}
@Override
public void setPacketType ( PacketType packetType ) {
this . packetType = packetType ;
this . id = packetType ! = null ? packetType . getId ( ) : - 1 ;
}
2021-04-26 22:54:43 +02:00
@Override
public int getId ( ) {
return id ;
}
@Override
2021-07-31 12:43:07 +02:00
@Deprecated
2021-04-26 22:54:43 +02:00
public void setId ( int id ) {
2021-07-31 12:43:07 +02:00
// Loses packet type info
this . packetType = null ;
2021-04-26 22:54:43 +02:00
this . id = id ;
}
2021-05-14 16:59:12 +02:00
2021-05-29 20:53:47 +02:00
public @Nullable ByteBuf getInputBuffer ( ) {
2021-05-14 11:19:02 +02:00
return inputBuffer ;
}
2021-04-26 22:54:43 +02:00
@Override
public String toString ( ) {
return " PacketWrapper{ " +
2023-03-17 18:36:48 +01:00
" type= " + packetType +
2021-04-26 22:54:43 +02:00
" , id= " + id +
2023-03-17 18:36:48 +01:00
" , values= " + packetValues +
" , readable= " + readableObjects +
2021-04-26 22:54:43 +02:00
'}' ;
}
2023-02-28 21:49:08 +01:00
2023-10-20 04:31:16 +02:00
public static final class PacketValue < T > {
private final Type < T > type ;
private T value ;
2023-02-28 21:49:08 +01:00
2023-10-20 04:31:16 +02:00
private PacketValue ( final Type < T > type , @Nullable final T value ) {
2023-02-28 21:49:08 +01:00
this . type = type ;
this . value = value ;
}
2023-10-20 04:31:16 +02:00
public Type < T > type ( ) {
2023-02-28 21:49:08 +01:00
return type ;
}
public @Nullable Object value ( ) {
return value ;
}
2023-10-20 04:31:16 +02:00
public void write ( final ByteBuf buffer ) throws Exception {
type . write ( buffer , value ) ;
}
public void setValue ( @Nullable final T value ) {
2023-02-28 21:49:08 +01:00
this . value = value ;
}
2023-03-17 13:26:13 +01:00
@Override
public boolean equals ( final Object o ) {
if ( this = = o ) return true ;
if ( o = = null | | getClass ( ) ! = o . getClass ( ) ) return false ;
2023-10-20 04:31:16 +02:00
final PacketValue < ? > that = ( PacketValue < ? > ) o ;
2023-03-17 13:26:13 +01:00
if ( ! type . equals ( that . type ) ) return false ;
return Objects . equals ( value , that . value ) ;
}
@Override
public int hashCode ( ) {
int result = type . hashCode ( ) ;
result = 31 * result + ( value ! = null ? value . hashCode ( ) : 0 ) ;
return result ;
}
@Override
public String toString ( ) {
2023-03-17 18:36:48 +01:00
return " { " + type + " : " + value + " } " ;
2023-03-17 13:26:13 +01:00
}
2023-02-28 21:49:08 +01:00
}
2021-04-26 22:54:43 +02:00
}