Skip to content

Commit

Permalink
Lazily deserialize BaseComponent in packets
Browse files Browse the repository at this point in the history
  • Loading branch information
Janmm14 committed Mar 31, 2024
1 parent 84d0ea7 commit 4d36170
Show file tree
Hide file tree
Showing 21 changed files with 706 additions and 76 deletions.
11 changes: 11 additions & 0 deletions chat/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import net.md_5.bungee.api.chat.SelectorComponent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.chat.TranslatableComponent;
import net.md_5.bungee.api.chat.hover.content.Content;
import net.md_5.bungee.api.chat.hover.content.Entity;
import net.md_5.bungee.api.chat.hover.content.EntitySerializer;
import net.md_5.bungee.api.chat.hover.content.Item;
Expand Down Expand Up @@ -163,6 +164,16 @@ public static String toString(Object object)
return gson.toJson( object );
}

public static String toString(Content content)
{
return gson.toJson( content );
}

public static String toString(JsonElement element)
{
return gson.toJson( element );
}

public static String toString(BaseComponent component)
{
return gson.toJson( component );
Expand Down
80 changes: 73 additions & 7 deletions protocol/src/main/java/net/md_5/bungee/protocol/DefinedPacket.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream;
Expand Down Expand Up @@ -93,17 +94,37 @@ public static String readString(ByteBuf buf, int maxLen)
return s;
}

public static Either<String, BaseComponent> readEitherBaseComponent(ByteBuf buf, int protocolVersion, boolean string)
public static Either<String, Deserializable<Either<String, SpecificTag>, BaseComponent>> readEitherBaseComponent(ByteBuf buf, int protocolVersion, boolean string)
{
return ( string ) ? Either.left( readString( buf ) ) : Either.right( readBaseComponent( buf, protocolVersion ) );
}

public static BaseComponent readBaseComponent(ByteBuf buf, int protocolVersion)
public static Deserializable<Either<String, SpecificTag>, BaseComponent> readBaseComponent(ByteBuf buf, int protocolVersion)
{
return readBaseComponent( buf, Short.MAX_VALUE, protocolVersion );
}

public static BaseComponent readBaseComponent(ByteBuf buf, int maxStringLength, int protocolVersion)
public static Deserializable<Either<String, SpecificTag>, BaseComponent> readBaseComponent(ByteBuf buf, int maxStringLength, int protocolVersion)
{
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3 )
{
SpecificTag nbt = (SpecificTag) readTag( buf, protocolVersion );

return new FunctionDeserializable<>( Either.right( nbt ), (ov) -> ComponentSerializer.deserialize( TagUtil.toJson( ov.getRight() ) ) );
} else
{
String string = readString( buf, maxStringLength );

return new FunctionDeserializable<>( Either.left( string ), (ov) -> ComponentSerializer.deserialize( ov.getLeft() ) );
}
}

public static BaseComponent readRawComponent(ByteBuf buf, int protocolVersion)
{
return readRawComponent( buf, Short.MAX_VALUE, protocolVersion );
}

public static BaseComponent readRawComponent(ByteBuf buf, int maxStringLength, int protocolVersion)
{
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3 )
{
Expand All @@ -127,7 +148,7 @@ public static ComponentStyle readComponentStyle(ByteBuf buf, int protocolVersion
return ComponentSerializer.deserializeStyle( json );
}

public static void writeEitherBaseComponent(Either<String, BaseComponent> message, ByteBuf buf, int protocolVersion)
public static void writeEitherBaseComponent(Either<String, Deserializable<Either<String, SpecificTag>, BaseComponent>> message, ByteBuf buf, int protocolVersion)
{
if ( message.isLeft() )
{
Expand All @@ -138,7 +159,52 @@ public static void writeEitherBaseComponent(Either<String, BaseComponent> messag
}
}

public static void writeBaseComponent(BaseComponent message, ByteBuf buf, int protocolVersion)
public static void writeBaseComponent(Deserializable<Either<String, SpecificTag>, BaseComponent> message, ByteBuf buf, int protocolVersion)
{
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3 )
{
if ( message.hasDeserialized() )
{
BaseComponent baseComponent = message.get();
JsonElement json = ComponentSerializer.toJson( baseComponent );
SpecificTag nbt = TagUtil.fromJson( json );

writeTag( nbt, buf, protocolVersion );
} else
{
Either<String, SpecificTag> eitherStrJsonElem = message.original();
if ( eitherStrJsonElem.isLeft() )
{
writeTag( TagUtil.fromJson( JsonParser.parseString( eitherStrJsonElem.getLeft() ) ), buf, protocolVersion );
} else
{
writeTag( eitherStrJsonElem.getRight(), buf, protocolVersion );
}
}
} else
{
if ( message.hasDeserialized() )
{
String string = ComponentSerializer.toString( message.get() );

writeString( string, buf );
} else
{
Either<String, SpecificTag> eitherStrJsonElem = message.original();
if ( eitherStrJsonElem.isLeft() )
{
writeString( eitherStrJsonElem.getLeft(), buf );
} else
{
String string = ComponentSerializer.toString( TagUtil.toJson( eitherStrJsonElem.getRight() ) );

writeString( string, buf );
}
}
}
}

public static void writeRawComponent(BaseComponent message, ByteBuf buf, int protocolVersion)
{
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3 )
{
Expand Down Expand Up @@ -398,7 +464,7 @@ public static void writeNumberFormat(NumberFormat format, ByteBuf buf, int proto
writeComponentStyle( (ComponentStyle) format.getValue(), buf, protocolVersion );
break;
case FIXED:
writeBaseComponent( (BaseComponent) format.getValue(), buf, protocolVersion );
writeRawComponent( (BaseComponent) format.getValue(), buf, protocolVersion );
break;
}
}
Expand All @@ -413,7 +479,7 @@ public static NumberFormat readNumberFormat(ByteBuf buf, int protocolVersion)
case 1:
return new NumberFormat( NumberFormat.Type.STYLED, readComponentStyle( buf, protocolVersion ) );
case 2:
return new NumberFormat( NumberFormat.Type.FIXED, readBaseComponent( buf, protocolVersion ) );
return new NumberFormat( NumberFormat.Type.FIXED, readRawComponent( buf, protocolVersion ) );
default:
throw new IllegalArgumentException( "Unknown number format " + format );
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package net.md_5.bungee.protocol;

/**
* Represents a value that can be deserialized from another value if needed.
* @param <OV> the original value
* @param <D> the deserialized value
*/
public interface Deserializable<OV, D>
{
/**
* @return the deserialized value
*/
D get();

/**
* If {@link #hasDeserialized()} returns true, this method may return null. This usually hapens after code has
* edited the deserialized value and wrote it back to its original place.
* @return the original value, if available
*/
OV original();

/**
* If the value has been deserialized, it is adviced to no longer call {@link #original()}, as the deserialized
* value may have been modified.
* @return true if the value has been deserialized
*/
boolean hasDeserialized();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package net.md_5.bungee.protocol;

import java.util.function.Function;
import org.jetbrains.annotations.NotNull;

public class FunctionDeserializable<OV, D> extends SimpleDeserializable<OV, D>
{
private final Function<OV, D> function;

public FunctionDeserializable(OV ov, Function<OV, D> supplier)
{
super( ov );
this.function = supplier;
}

@NotNull
@Override
public D deserialize()
{
return function.apply( original() );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package net.md_5.bungee.protocol;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class NoOrigDeserializable<OV, D> implements Deserializable<OV, D>
{
private final D value;

@Override
public D get()
{
return value;
}

@Override
public OV original()
{
return null;
}

@Override
public boolean hasDeserialized()
{
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package net.md_5.bungee.protocol;

import lombok.NonNull;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public abstract class SimpleDeserializable<OV, D> implements Deserializable<OV, D>
{
private final OV original;
private D deserialized;

/**
* Method called to get the deserialized value. Called only once unless multiple threads are calling get() at the
* same time.
* @return the deserialized value
*/
@NonNull
protected abstract D deserialize();

@Override
public final D get()
{
if ( !hasDeserialized() )
{
return deserialized = deserialize();
}
return deserialized;
}

@Override
public final boolean hasDeserialized()
{
return deserialized != null;
}

@Override
public final OV original()
{
return original;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.Deserializable;
import net.md_5.bungee.protocol.Either;
import net.md_5.bungee.protocol.NoOrigDeserializable;
import net.md_5.bungee.protocol.ProtocolConstants;
import se.llbit.nbt.SpecificTag;

@Data
@NoArgsConstructor
Expand All @@ -18,7 +22,7 @@ public class BossBar extends DefinedPacket

private UUID uuid;
private int action;
private BaseComponent title;
private Deserializable<Either<String, SpecificTag>, BaseComponent> title;
private float health;
private int color;
private int division;
Expand Down Expand Up @@ -107,4 +111,23 @@ public void handle(AbstractPacketHandler handler) throws Exception
{
handler.handle( this );
}

public BaseComponent getTitle()
{
if ( title == null )
{
return null;
}
return title.get();
}

public void setTitle(BaseComponent title)
{
if ( title == null )
{
this.title = null;
return;
}
this.title = new NoOrigDeserializable<>( title );
}
}
40 changes: 35 additions & 5 deletions protocol/src/main/java/net/md_5/bungee/protocol/packet/Kick.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@
import net.md_5.bungee.chat.ComponentSerializer;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.Deserializable;
import net.md_5.bungee.protocol.Either;
import net.md_5.bungee.protocol.FunctionDeserializable;
import net.md_5.bungee.protocol.NoOrigDeserializable;
import net.md_5.bungee.protocol.Protocol;
import net.md_5.bungee.protocol.ProtocolConstants;
import se.llbit.nbt.SpecificTag;

@Data
@NoArgsConstructor
Expand All @@ -19,17 +24,18 @@
public class Kick extends DefinedPacket
{

private BaseComponent message;
private Deserializable<Either<String, SpecificTag>, BaseComponent> messageRaw;

@Override
public void read(ByteBuf buf, Protocol protocol, ProtocolConstants.Direction direction, int protocolVersion)
{
if ( protocol == Protocol.LOGIN )
{
message = ComponentSerializer.deserialize( readString( buf ) );
String json = readString( buf );
messageRaw = new FunctionDeserializable<>( Either.left( json ), (ov) -> ComponentSerializer.deserialize( ov.getLeft() ) );
} else
{
message = readBaseComponent( buf, protocolVersion );
messageRaw = readBaseComponent( buf, protocolVersion );
}
}

Expand All @@ -38,10 +44,10 @@ public void write(ByteBuf buf, Protocol protocol, ProtocolConstants.Direction di
{
if ( protocol == Protocol.LOGIN )
{
writeString( ComponentSerializer.toString( message ), buf );
writeString( ComponentSerializer.toString( messageRaw.get() ), buf );
} else
{
writeBaseComponent( message, buf, protocolVersion );
writeBaseComponent( messageRaw, buf, protocolVersion );
}
}

Expand All @@ -50,4 +56,28 @@ public void handle(AbstractPacketHandler handler) throws Exception
{
handler.handle( this );
}

public Kick(BaseComponent message)
{
setMessage( message );
}

public BaseComponent getMessage()
{
if ( messageRaw == null )
{
return null;
}
return messageRaw.get();
}

public void setMessage(BaseComponent message)
{
if ( message == null )
{
this.messageRaw = null;
return;
}
this.messageRaw = new NoOrigDeserializable<>( message );
}
}
Loading

0 comments on commit 4d36170

Please sign in to comment.