Add SerializationManager

This commit is contained in:
Kieran Wallbanks 2021-03-02 14:41:45 +00:00
parent d9c7f2cd61
commit 653859e784
7 changed files with 116 additions and 13 deletions

View File

@ -4,6 +4,7 @@ import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.audience.ForwardingAudience;
import net.minestom.server.advancements.AdvancementManager;
import net.minestom.server.adventure.BossBarManager;
import net.minestom.server.adventure.SerializationManager;
import net.minestom.server.benchmark.BenchmarkManager;
import net.minestom.server.command.CommandManager;
import net.minestom.server.data.DataManager;
@ -119,6 +120,7 @@ public final class MinecraftServer implements ForwardingAudience.Single {
private static DimensionTypeManager dimensionTypeManager;
private static BiomeManager biomeManager;
private static AdvancementManager advancementManager;
private static SerializationManager serializationManager;
private static BossBarManager bossBarManager;
private static ExtensionManager extensionManager;
@ -185,6 +187,7 @@ public final class MinecraftServer implements ForwardingAudience.Single {
dimensionTypeManager = new DimensionTypeManager();
biomeManager = new BiomeManager();
advancementManager = new AdvancementManager();
serializationManager = new SerializationManager();
bossBarManager = new BossBarManager();
updateManager = new UpdateManager();
@ -433,6 +436,16 @@ public final class MinecraftServer implements ForwardingAudience.Single {
return connectionManager;
}
/**
* Gets the manager handing component serialization.
*
* @return the manager
*/
public static SerializationManager getSerializationManager() {
checkInitStatus(serializationManager);
return serializationManager;
}
/**
* Gets the boss bar manager.
*

View File

@ -168,7 +168,7 @@ public class BossBarManager implements BossBar.Listener {
BossBarPacket createAddPacket() {
return this.createGenericPacket(ADD, packet -> {
packet.title = GsonComponentSerializer.gson().serialize(bar.name());
packet.title = MinecraftServer.getSerializationManager().serialize(bar.name());
packet.color = bar.color().ordinal();
packet.division = bar.overlay().ordinal();
packet.health = bar.progress();
@ -188,7 +188,7 @@ public class BossBarManager implements BossBar.Listener {
}
BossBarPacket createTitleUpdate(@NotNull Component title) {
return this.createGenericPacket(UPDATE_TITLE, packet -> packet.title = GsonComponentSerializer.gson().serialize(title));
return this.createGenericPacket(UPDATE_TITLE, packet -> packet.title = MinecraftServer.getSerializationManager().serialize(title));
}
BossBarPacket createFlagsUpdate() {

View File

@ -0,0 +1,87 @@
package net.minestom.server.adventure;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.function.Function;
/**
* Manager class for handling Adventure serialization. By default this will simply
* serialize components to Strings using {@link GsonComponentSerializer}. However, this
* class can be used to change the way text is serialized. For example, a pre-JSON
* implementation of Minestom could change this to the plain component serializer.
* <br><br>
* This manager also provides the ability to wrap the serializer in a renderer that
* performs operations on each component before the final serialization.
*
* @see #setSerializer(Function) (Function)
* @see #addRenderer(Function)
*/
public class SerializationManager {
private final Set<Function<Component, Component>> renderers = new CopyOnWriteArraySet<>();
private Function<Component, String> serializer = component -> GsonComponentSerializer.gson().serialize(component);
/**
* Gets the root serializer that is used to convert Components into Strings.
*
* @return the serializer
*/
public @NotNull Function<Component, String> getSerializer() {
return this.serializer;
}
/**
* Sets the root serializer that is used to convert Components into Strings. This
* method does not replace any existing renderers set with {@link #addRenderer(Function)}.
*
* @param serializer the serializer
*/
public void setSerializer(@NotNull Function<Component, String> serializer) {
this.serializer = serializer;
}
/**
* Adds a renderer that will be applied to each serializer. The order in which
* each renderer will be applied is arbitrary. If you want control over the order
* of renderers, create a multi-function using {@link Function#andThen(Function)}.
*
* @param renderer the renderer
*/
public void addRenderer(@NotNull Function<Component, Component> renderer) {
this.renderers.add(renderer);
}
/**
* Removes a renderer.
*
* @param renderer the renderer
*/
public void removeRenderer(@NotNull Function<Component, Component> renderer) {
this.renderers.remove(renderer);
}
/**
* Removes all current renderers.
*/
public void clearRenderers() {
this.renderers.clear();
}
/**
* Serializes a component into a String using the current serializer.
*
* @param component the component
*
* @return the serialized string
*/
public String serialize(Component component) {
for (Function<Component, Component> renderer : this.renderers) {
component = renderer.apply(component);
}
return this.serializer.apply(component);
}
}

View File

@ -24,6 +24,7 @@ public class ConsoleSender implements CommandSender {
@Override
public void sendMessage(@NonNull Identity source, @NonNull Component message, @NonNull MessageType type) {
// we don't use the serializer here as we just need the plain text of the message
LOGGER.info(PlainComponentSerializer.plain().serialize(message));
}

View File

@ -820,7 +820,7 @@ public class Player extends LivingEntity implements CommandSender {
@Override
public void sendMessage(@NonNull Identity source, @NonNull Component message, @NonNull MessageType type) {
ChatMessagePacket chatMessagePacket = new ChatMessagePacket(GsonComponentSerializer.gson().serialize(message), type, source.uuid());
ChatMessagePacket chatMessagePacket = new ChatMessagePacket(MinecraftServer.getSerializationManager().serialize(message), type, source.uuid());
playerConnection.sendPacket(chatMessagePacket);
}
@ -964,10 +964,10 @@ public class Player extends LivingEntity implements CommandSender {
@Override
public void sendPlayerListHeaderAndFooter(@NonNull Component header, @NonNull Component footer) {
playerConnection.sendPacket(new PlayerListHeaderAndFooterPacket(
GsonComponentSerializer.gson().serialize(header),
GsonComponentSerializer.gson().serialize(footer)
));
PlayerListHeaderAndFooterPacket packet = new PlayerListHeaderAndFooterPacket();
packet.header = MinecraftServer.getSerializationManager().serialize(header);
packet.footer = MinecraftServer.getSerializationManager().serialize(footer);
playerConnection.sendPacket(packet);
}
/**
@ -1047,7 +1047,7 @@ public class Player extends LivingEntity implements CommandSender {
@Override
public void sendActionBar(@NonNull Component message) {
TitlePacket titlePacket = new TitlePacket(TitlePacket.Action.SET_ACTION_BAR, GsonComponentSerializer.gson().serialize(message));
TitlePacket titlePacket = new TitlePacket(TitlePacket.Action.SET_ACTION_BAR, MinecraftServer.getSerializationManager().serialize(message));
playerConnection.sendPacket(titlePacket);
}
@ -1830,9 +1830,9 @@ public class Player extends LivingEntity implements CommandSender {
// Packet type depends on the current player connection state
final ServerPacket disconnectPacket;
if (connectionState == ConnectionState.LOGIN) {
disconnectPacket = new LoginDisconnectPacket(GsonComponentSerializer.gson().serialize(component));
disconnectPacket = new LoginDisconnectPacket(MinecraftServer.getSerializationManager().serialize(component));
} else {
disconnectPacket = new DisconnectPacket(GsonComponentSerializer.gson().serialize(component));
disconnectPacket = new DisconnectPacket(MinecraftServer.getSerializationManager().serialize(component));
}
if (playerConnection instanceof NettyPlayerConnection) {

View File

@ -1,6 +1,7 @@
package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -10,7 +11,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.Objects;
public class PlayerListHeaderAndFooterPacket implements ServerPacket {
private static final String EMPTY_COMPONENT = PlainComponentSerializer.plain().serialize(Component.empty());
private static final String EMPTY_COMPONENT = GsonComponentSerializer.gson().serialize(Component.empty());
public String header;
public String footer;

View File

@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.title.Title;
import net.minestom.server.MinecraftServer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.utils.TickUtils;
@ -109,8 +110,8 @@ public class TitlePacket implements ServerPacket {
List<TitlePacket> packets = new ArrayList<>(4);
// base packets
packets.add(new TitlePacket(SET_TITLE, GsonComponentSerializer.gson().serialize(title.title())));
packets.add(new TitlePacket(SET_SUBTITLE, GsonComponentSerializer.gson().serialize(title.subtitle())));
packets.add(new TitlePacket(SET_TITLE, MinecraftServer.getSerializationManager().serialize(title.title())));
packets.add(new TitlePacket(SET_SUBTITLE, MinecraftServer.getSerializationManager().serialize(title.subtitle())));
// times packet
Title.Times times = title.times();