diff --git a/src/main/java/ru/nanit/limbo/configuration/LimboConfig.java b/src/main/java/ru/nanit/limbo/configuration/LimboConfig.java index ae3ba17..21d5032 100644 --- a/src/main/java/ru/nanit/limbo/configuration/LimboConfig.java +++ b/src/main/java/ru/nanit/limbo/configuration/LimboConfig.java @@ -27,8 +27,10 @@ public final class LimboConfig { private boolean useJoinMessage; private boolean useBossBar; + private boolean useTitle; private String joinMessage; private BossBar bossBar; + private Title title; private InfoForwarding infoForwarding; private long readTimeout; @@ -59,6 +61,7 @@ public final class LimboConfig { gameMode = conf.node("gameMode").getInt(); useJoinMessage = conf.node("joinMessage", "enable").getBoolean(); useBossBar = conf.node("bossBar", "enable").getBoolean(); + useTitle = conf.node("title", "enable").getBoolean(); if (useJoinMessage) joinMessage = Colors.of(conf.node("joinMessage", "text").getString("")); @@ -66,6 +69,9 @@ public final class LimboConfig { if (useBossBar) bossBar = conf.node("bossBar").get(BossBar.class); + if (useTitle) + title = conf.node("title").get(Title.class); + infoForwarding = conf.node("infoForwarding").get(InfoForwarding.class); readTimeout = conf.node("readTimeout").getLong(); debugLevel = conf.node("debugLevel").getInt(); @@ -97,6 +103,7 @@ public final class LimboConfig { .register(InfoForwarding.class, new InfoForwarding.Serializer()) .register(PingData.class, new PingData.Serializer()) .register(BossBar.class, new BossBar.Serializer()) + .register(Title.class, new Title.Serializer()) .register(Position.class, new Position.Serializer()) .build(); } @@ -145,6 +152,10 @@ public final class LimboConfig { return useBossBar; } + public boolean isUseTitle() { + return useTitle; + } + public String getJoinMessage() { return joinMessage; } @@ -153,6 +164,10 @@ public final class LimboConfig { return bossBar; } + public Title getTitle() { + return title; + } + public boolean isUseEpoll() { return useEpoll; } diff --git a/src/main/java/ru/nanit/limbo/connection/ClientConnection.java b/src/main/java/ru/nanit/limbo/connection/ClientConnection.java index 93c448a..3814fda 100644 --- a/src/main/java/ru/nanit/limbo/connection/ClientConnection.java +++ b/src/main/java/ru/nanit/limbo/connection/ClientConnection.java @@ -19,6 +19,7 @@ import ru.nanit.limbo.protocol.packets.status.PacketStatusResponse; import ru.nanit.limbo.protocol.registry.State; import ru.nanit.limbo.protocol.registry.Version; import ru.nanit.limbo.server.LimboServer; +import ru.nanit.limbo.server.data.Title; import ru.nanit.limbo.util.Logger; import ru.nanit.limbo.util.UuidUtil; @@ -43,6 +44,14 @@ public class ClientConnection extends ChannelInboundHandlerAdapter { private static PreEncodedPacket PACKET_JOIN_MESSAGE; private static PreEncodedPacket PACKET_BOSS_BAR; + private static PreEncodedPacket PACKET_TITLE_TITLE; + private static PreEncodedPacket PACKET_TITLE_SUBTITLE; + private static PreEncodedPacket PACKET_TITLE_TIMES; + + private static PreEncodedPacket PACKET_TITLE_LEGACY_TITLE; + private static PreEncodedPacket PACKET_TITLE_LEGACY_SUBTITLE; + private static PreEncodedPacket PACKET_TITLE_LEGACY_TIMES; + private final LimboServer server; private final Channel channel; private final GameProfile gameProfile; @@ -211,6 +220,9 @@ public class ClientConnection extends ChannelInboundHandlerAdapter { if (PACKET_JOIN_MESSAGE != null) writePacket(PACKET_JOIN_MESSAGE); + if (PACKET_TITLE_TITLE != null) + sendTitle(); + sendKeepAlive(); } @@ -222,6 +234,18 @@ public class ClientConnection extends ChannelInboundHandlerAdapter { } } + public void sendTitle() { + if (clientVersion.moreOrEqual(Version.V1_17)) { + writePacket(PACKET_TITLE_TITLE); + writePacket(PACKET_TITLE_SUBTITLE); + sendPacket(PACKET_TITLE_TIMES); + } else { + writePacket(PACKET_TITLE_LEGACY_TITLE); + writePacket(PACKET_TITLE_LEGACY_SUBTITLE); + sendPacket(PACKET_TITLE_LEGACY_TIMES); + } + } + public void sendKeepAlive() { if (state.equals(State.PLAY)) { PacketKeepAlive keepAlive = new PacketKeepAlive(); @@ -352,5 +376,35 @@ public class ClientConnection extends ChannelInboundHandlerAdapter { bossBar.setUuid(UUID.randomUUID()); PACKET_BOSS_BAR = PreEncodedPacket.of(bossBar); } + + if (server.getConfig().isUseTitle()) { + Title title = server.getConfig().getTitle(); + + PacketTitleSetTitle packetTitle = new PacketTitleSetTitle(); + PacketTitleSetSubTitle packetSubtitle = new PacketTitleSetSubTitle(); + PacketTitleTimes packetTimes = new PacketTitleTimes(); + + PacketTitleLegacy legacyTitle = new PacketTitleLegacy(); + PacketTitleLegacy legacySubtitle = new PacketTitleLegacy(); + PacketTitleLegacy legacyTimes = new PacketTitleLegacy(); + + packetTitle.setTitle(title.getTitle()); + packetSubtitle.setSubtitle(title.getSubtitle()); + packetTimes.setFadeIn(title.getFadeIn()); + packetTimes.setStay(title.getStay()); + packetTimes.setFadeOut(title.getFadeOut()); + + legacyTitle.setTitle(title); + legacySubtitle.setTitle(title); + legacyTimes.setTitle(title); + + PACKET_TITLE_TITLE = PreEncodedPacket.of(packetTitle); + PACKET_TITLE_SUBTITLE = PreEncodedPacket.of(packetSubtitle); + PACKET_TITLE_TIMES = PreEncodedPacket.of(packetTimes); + + PACKET_TITLE_LEGACY_TITLE = PreEncodedPacket.of(legacyTitle); + PACKET_TITLE_LEGACY_SUBTITLE = PreEncodedPacket.of(legacySubtitle); + PACKET_TITLE_LEGACY_TIMES = PreEncodedPacket.of(legacyTimes); + } } } diff --git a/src/main/java/ru/nanit/limbo/protocol/packets/play/PacketTitleLegacy.java b/src/main/java/ru/nanit/limbo/protocol/packets/play/PacketTitleLegacy.java new file mode 100644 index 0000000..ea1ffd6 --- /dev/null +++ b/src/main/java/ru/nanit/limbo/protocol/packets/play/PacketTitleLegacy.java @@ -0,0 +1,65 @@ +package ru.nanit.limbo.protocol.packets.play; + +import ru.nanit.limbo.protocol.ByteMessage; +import ru.nanit.limbo.protocol.PacketOut; +import ru.nanit.limbo.protocol.registry.Version; +import ru.nanit.limbo.server.data.Title; + +public class PacketTitleLegacy implements PacketOut { + + private Action action; + private final PacketTitleSetTitle title; + private final PacketTitleSetSubTitle subtitle; + private final PacketTitleTimes times; + + public PacketTitleLegacy() { + this.title = new PacketTitleSetTitle(); + this.subtitle = new PacketTitleSetSubTitle(); + this.times = new PacketTitleTimes(); + } + + public void setAction(Action action) { + this.action = action; + } + + public void setTitle(Title title) { + this.title.setTitle(title.getTitle()); + this.subtitle.setSubtitle(title.getSubtitle()); + this.times.setFadeIn(title.getFadeIn()); + this.times.setStay(title.getStay()); + this.times.setFadeOut(title.getFadeOut()); + } + + @Override + public void encode(ByteMessage msg, Version version) { + msg.writeVarInt(action.getId(version)); + + switch (action) { + case SET_TITLE: + title.encode(msg, version); + break; + case SET_SUBTITLE: + subtitle.encode(msg, version); + break; + case SET_TIMES_AND_DISPLAY: + times.encode(msg, version); + break; + } + } + + public enum Action { + SET_TITLE(0), + SET_SUBTITLE(1), + SET_TIMES_AND_DISPLAY(3); + + private final int id; + + Action(int id) { + this.id = id; + } + + public int getId(Version version) { + return version.moreOrEqual(Version.V1_11) && id > 2 ? id - 1 : id; + } + } +} diff --git a/src/main/java/ru/nanit/limbo/protocol/packets/play/PacketTitleSetSubTitle.java b/src/main/java/ru/nanit/limbo/protocol/packets/play/PacketTitleSetSubTitle.java new file mode 100644 index 0000000..6c7a708 --- /dev/null +++ b/src/main/java/ru/nanit/limbo/protocol/packets/play/PacketTitleSetSubTitle.java @@ -0,0 +1,20 @@ +package ru.nanit.limbo.protocol.packets.play; + +import ru.nanit.limbo.protocol.ByteMessage; +import ru.nanit.limbo.protocol.PacketOut; +import ru.nanit.limbo.protocol.registry.Version; + +public class PacketTitleSetSubTitle implements PacketOut { + + private String subtitle; + + public void setSubtitle(String subtitle) { + this.subtitle = subtitle; + } + + @Override + public void encode(ByteMessage msg, Version version) { + msg.writeString(subtitle); + } + +} diff --git a/src/main/java/ru/nanit/limbo/protocol/packets/play/PacketTitleSetTitle.java b/src/main/java/ru/nanit/limbo/protocol/packets/play/PacketTitleSetTitle.java new file mode 100644 index 0000000..764fa5a --- /dev/null +++ b/src/main/java/ru/nanit/limbo/protocol/packets/play/PacketTitleSetTitle.java @@ -0,0 +1,20 @@ +package ru.nanit.limbo.protocol.packets.play; + +import ru.nanit.limbo.protocol.ByteMessage; +import ru.nanit.limbo.protocol.PacketOut; +import ru.nanit.limbo.protocol.registry.Version; + +public class PacketTitleSetTitle implements PacketOut { + + private String title; + + public void setTitle(String title) { + this.title = title; + } + + @Override + public void encode(ByteMessage msg, Version version) { + msg.writeString(title); + } + +} diff --git a/src/main/java/ru/nanit/limbo/protocol/packets/play/PacketTitleTimes.java b/src/main/java/ru/nanit/limbo/protocol/packets/play/PacketTitleTimes.java new file mode 100644 index 0000000..e9f0c63 --- /dev/null +++ b/src/main/java/ru/nanit/limbo/protocol/packets/play/PacketTitleTimes.java @@ -0,0 +1,32 @@ +package ru.nanit.limbo.protocol.packets.play; + +import ru.nanit.limbo.protocol.ByteMessage; +import ru.nanit.limbo.protocol.PacketOut; +import ru.nanit.limbo.protocol.registry.Version; + +public class PacketTitleTimes implements PacketOut { + + private int fadeIn; + private int stay; + private int fadeOut; + + public void setFadeIn(int fadeIn) { + this.fadeIn = fadeIn; + } + + public void setStay(int stay) { + this.stay = stay; + } + + public void setFadeOut(int fadeOut) { + this.fadeOut = fadeOut; + } + + @Override + public void encode(ByteMessage msg, Version version) { + msg.writeInt(fadeIn); + msg.writeInt(stay); + msg.writeInt(fadeOut); + } + +} diff --git a/src/main/java/ru/nanit/limbo/server/data/Title.java b/src/main/java/ru/nanit/limbo/server/data/Title.java new file mode 100644 index 0000000..9697f84 --- /dev/null +++ b/src/main/java/ru/nanit/limbo/server/data/Title.java @@ -0,0 +1,77 @@ +package ru.nanit.limbo.server.data; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.configurate.ConfigurationNode; +import org.spongepowered.configurate.serialize.SerializationException; +import org.spongepowered.configurate.serialize.TypeSerializer; +import ru.nanit.limbo.util.Colors; + +import java.lang.reflect.Type; + +public class Title { + + private String title; + private String subtitle; + private int fadeIn; + private int stay; + private int fadeOut; + + public String getTitle() { + return title; + } + + public String getSubtitle() { + return subtitle; + } + + public int getFadeIn() { + return fadeIn; + } + + public int getStay() { + return stay; + } + + public int getFadeOut() { + return fadeOut; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setSubtitle(String subtitle) { + this.subtitle = subtitle; + } + + public void setFadeIn(int fadeIn) { + this.fadeIn = fadeIn; + } + + public void setStay(int stay) { + this.stay = stay; + } + + public void setFadeOut(int fadeOut) { + this.fadeOut = fadeOut; + } + + public static class Serializer implements TypeSerializer