mirror of
https://github.com/GeyserMC/MCProtocolLib.git
synced 2024-11-14 19:34:58 -05:00
Merge branch 'feature/1.19.4'
This commit is contained in:
commit
3bc9926a38
93 changed files with 4492 additions and 239 deletions
27
Jenkinsfile
vendored
27
Jenkinsfile
vendored
|
@ -23,6 +23,31 @@ pipeline {
|
|||
when {
|
||||
branch "master"
|
||||
}
|
||||
pipeline {
|
||||
agent any
|
||||
tools {
|
||||
maven 'Maven 3'
|
||||
jdk 'Java 8'
|
||||
}
|
||||
options {
|
||||
buildDiscarder(logRotator(artifactNumToKeepStr: '20'))
|
||||
}
|
||||
stages {
|
||||
stage ('Build') {
|
||||
steps {
|
||||
sh 'mvn clean package'
|
||||
}
|
||||
post {
|
||||
success {
|
||||
archiveArtifacts artifacts: 'target/*.jar', excludes: 'target/*-sources.jar', fingerprint: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage ('Deploy') {
|
||||
when {
|
||||
branch "master"
|
||||
}
|
||||
|
||||
steps {
|
||||
rtMavenDeployer(
|
||||
|
@ -50,4 +75,4 @@ pipeline {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package com.github.steveice10.packetlib.test;
|
||||
|
||||
import com.github.steveice10.packetlib.Session;
|
||||
import com.github.steveice10.packetlib.event.session.ConnectedEvent;
|
||||
import com.github.steveice10.packetlib.event.session.DisconnectedEvent;
|
||||
import com.github.steveice10.packetlib.event.session.DisconnectingEvent;
|
||||
import com.github.steveice10.packetlib.event.session.SessionAdapter;
|
||||
import com.github.steveice10.packetlib.packet.Packet;
|
||||
|
||||
public class ClientSessionListener extends SessionAdapter {
|
||||
@Override
|
||||
public void packetReceived(Session session, Packet packet) {
|
||||
if (packet instanceof PingPacket) {
|
||||
String id = ((PingPacket) packet).getPingId();
|
||||
|
||||
System.out.println("CLIENT Received: " + id);
|
||||
|
||||
if (id.equals("hello")) {
|
||||
session.send(new PingPacket("exit"));
|
||||
} else if (id.equals("exit")) {
|
||||
session.disconnect("Finished");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void packetSent(Session session, Packet packet) {
|
||||
if (packet instanceof PingPacket) {
|
||||
System.out.println("CLIENT Sent: " + ((PingPacket) packet).getPingId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connected(ConnectedEvent event) {
|
||||
System.out.println("CLIENT Connected");
|
||||
|
||||
event.getSession().enableEncryption(((TestProtocol) event.getSession().getPacketProtocol()).getEncryption());
|
||||
event.getSession().send(new PingPacket("hello"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnecting(DisconnectingEvent event) {
|
||||
System.out.println("CLIENT Disconnecting: " + event.getReason());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnected(DisconnectedEvent event) {
|
||||
System.out.println("CLIENT Disconnected: " + event.getReason());
|
||||
}
|
||||
}
|
32
example/com/github/steveice10/packetlib/test/PingPacket.java
Normal file
32
example/com/github/steveice10/packetlib/test/PingPacket.java
Normal file
|
@ -0,0 +1,32 @@
|
|||
package com.github.steveice10.packetlib.test;
|
||||
|
||||
import com.github.steveice10.packetlib.codec.PacketCodecHelper;
|
||||
import com.github.steveice10.packetlib.packet.Packet;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class PingPacket implements Packet {
|
||||
private final String id;
|
||||
|
||||
public PingPacket(ByteBuf buf, PacketCodecHelper codecHelper) throws IOException {
|
||||
this.id = codecHelper.readString(buf);
|
||||
}
|
||||
|
||||
public PingPacket(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getPingId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf, PacketCodecHelper codecHelper) throws IOException {
|
||||
codecHelper.writeString(buf, this.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPriority() {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package com.github.steveice10.packetlib.test;
|
||||
|
||||
import com.github.steveice10.packetlib.Server;
|
||||
import com.github.steveice10.packetlib.Session;
|
||||
import com.github.steveice10.packetlib.tcp.TcpClientSession;
|
||||
import com.github.steveice10.packetlib.tcp.TcpServer;
|
||||
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.SecretKey;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
public class PingServerTest {
|
||||
public static void main(String[] args) {
|
||||
SecretKey key;
|
||||
try {
|
||||
KeyGenerator gen = KeyGenerator.getInstance("AES");
|
||||
gen.init(128);
|
||||
key = gen.generateKey();
|
||||
} catch(NoSuchAlgorithmException e) {
|
||||
System.err.println("AES algorithm not supported, exiting...");
|
||||
return;
|
||||
}
|
||||
|
||||
Server server = new TcpServer("127.0.0.1", 25565, TestProtocol::new);
|
||||
server.addListener(new ServerListener(key));
|
||||
server.bind();
|
||||
|
||||
Session client = new TcpClientSession("127.0.0.1", 25565, new TestProtocol(key));
|
||||
client.connect();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.github.steveice10.packetlib.test;
|
||||
|
||||
import com.github.steveice10.packetlib.event.server.ServerAdapter;
|
||||
import com.github.steveice10.packetlib.event.server.ServerBoundEvent;
|
||||
import com.github.steveice10.packetlib.event.server.ServerClosedEvent;
|
||||
import com.github.steveice10.packetlib.event.server.ServerClosingEvent;
|
||||
import com.github.steveice10.packetlib.event.server.SessionAddedEvent;
|
||||
import com.github.steveice10.packetlib.event.server.SessionRemovedEvent;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
public class ServerListener extends ServerAdapter {
|
||||
private SecretKey key;
|
||||
|
||||
public ServerListener(SecretKey key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serverBound(ServerBoundEvent event) {
|
||||
System.out.println("SERVER Bound: " + event.getServer().getHost() + ":" + event.getServer().getPort());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serverClosing(ServerClosingEvent event) {
|
||||
System.out.println("CLOSING SERVER...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serverClosed(ServerClosedEvent event) {
|
||||
System.out.println("SERVER CLOSED");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionAdded(SessionAddedEvent event) {
|
||||
System.out.println("SERVER Session Added: " + event.getSession().getHost() + ":" + event.getSession().getPort());
|
||||
((TestProtocol) event.getSession().getPacketProtocol()).setSecretKey(this.key);
|
||||
event.getSession().enableEncryption(((TestProtocol) event.getSession().getPacketProtocol()).getEncryption());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionRemoved(SessionRemovedEvent event) {
|
||||
System.out.println("SERVER Session Removed: " + event.getSession().getHost() + ":" + event.getSession().getPort());
|
||||
event.getServer().close(false);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package com.github.steveice10.packetlib.test;
|
||||
|
||||
import com.github.steveice10.packetlib.Session;
|
||||
import com.github.steveice10.packetlib.event.session.ConnectedEvent;
|
||||
import com.github.steveice10.packetlib.event.session.DisconnectedEvent;
|
||||
import com.github.steveice10.packetlib.event.session.DisconnectingEvent;
|
||||
import com.github.steveice10.packetlib.event.session.SessionAdapter;
|
||||
import com.github.steveice10.packetlib.packet.Packet;
|
||||
|
||||
public class ServerSessionListener extends SessionAdapter {
|
||||
@Override
|
||||
public void packetReceived(Session session, Packet packet) {
|
||||
if (packet instanceof PingPacket) {
|
||||
System.out.println("SERVER Received: " + ((PingPacket) packet).getPingId());
|
||||
session.send(packet);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void packetSent(Session session, Packet packet) {
|
||||
if (packet instanceof PingPacket) {
|
||||
System.out.println("SERVER Sent: " + ((PingPacket) packet).getPingId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connected(ConnectedEvent event) {
|
||||
System.out.println("SERVER Connected");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnecting(DisconnectingEvent event) {
|
||||
System.out.println("SERVER Disconnecting: " + event.getReason());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnected(DisconnectedEvent event) {
|
||||
System.out.println("SERVER Disconnected: " + event.getReason());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package com.github.steveice10.packetlib.test;
|
||||
|
||||
import com.github.steveice10.packetlib.Server;
|
||||
import com.github.steveice10.packetlib.Session;
|
||||
import com.github.steveice10.packetlib.crypt.AESEncryption;
|
||||
import com.github.steveice10.packetlib.crypt.PacketEncryption;
|
||||
import com.github.steveice10.packetlib.packet.DefaultPacketHeader;
|
||||
import com.github.steveice10.packetlib.packet.PacketHeader;
|
||||
import com.github.steveice10.packetlib.packet.PacketProtocol;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
public class TestProtocol extends PacketProtocol {
|
||||
private final PacketHeader header = new DefaultPacketHeader();
|
||||
private AESEncryption encrypt;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public TestProtocol() {
|
||||
}
|
||||
|
||||
public TestProtocol(SecretKey key) {
|
||||
this.setSecretKey(key);
|
||||
}
|
||||
|
||||
public PacketCodecHelper createHelper() {
|
||||
return new BasePacketCodecHelper();
|
||||
}
|
||||
|
||||
public void setSecretKey(SecretKey key) {
|
||||
this.register(0, PingPacket.class, PingPacket::new);
|
||||
try {
|
||||
this.encrypt = new AESEncryption(key);
|
||||
} catch(GeneralSecurityException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSRVRecordPrefix() {
|
||||
return "_test";
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketHeader getPacketHeader() {
|
||||
return this.header;
|
||||
}
|
||||
|
||||
public PacketEncryption getEncryption() {
|
||||
return this.encrypt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void newClientSession(Session session) {
|
||||
session.addListener(new ClientSessionListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void newServerSession(Server server, Session session) {
|
||||
session.addListener(new ServerSessionListener());
|
||||
}
|
||||
}
|
39
pom.xml
39
pom.xml
|
@ -5,7 +5,7 @@
|
|||
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>mcprotocollib</artifactId>
|
||||
<version>1.19.3-SNAPSHOT</version>
|
||||
<version>1.19.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>MCProtocolLib</name>
|
||||
|
@ -87,12 +87,6 @@
|
|||
<version>1.4</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>packetlib</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.GeyserMC</groupId>
|
||||
<artifactId>mcauthlib</artifactId>
|
||||
|
@ -135,6 +129,37 @@
|
|||
<version>4.13.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.1.66.Final</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-codec-haproxy</artifactId>
|
||||
<version>4.1.66.Final</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty.incubator</groupId>
|
||||
<artifactId>netty-incubator-transport-native-io_uring</artifactId>
|
||||
<version>0.0.8.Final</version>
|
||||
<classifier>linux-x86_64</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.spotbugs</groupId>
|
||||
<artifactId>spotbugs-annotations</artifactId>
|
||||
<version>4.3.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nukkitx.fastutil</groupId>
|
||||
<artifactId>fastutil-int-object-maps</artifactId>
|
||||
<version>8.5.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -86,7 +86,7 @@ public class ClientListener extends SessionAdapter {
|
|||
} else if (packet instanceof ClientboundGameProfilePacket) {
|
||||
protocol.setState(ProtocolState.GAME);
|
||||
} else if (packet instanceof ClientboundLoginDisconnectPacket) {
|
||||
session.disconnect(((ClientboundLoginDisconnectPacket) packet).getReason().toString());
|
||||
session.disconnect(((ClientboundLoginDisconnectPacket) packet).getReason());
|
||||
} else if (packet instanceof ClientboundLoginCompressionPacket) {
|
||||
session.setCompressionThreshold(((ClientboundLoginCompressionPacket) packet).getThreshold(), false);
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ public class ClientListener extends SessionAdapter {
|
|||
if (packet instanceof ClientboundKeepAlivePacket && session.getFlag(MinecraftConstants.AUTOMATIC_KEEP_ALIVE_MANAGEMENT, true)) {
|
||||
session.send(new ServerboundKeepAlivePacket(((ClientboundKeepAlivePacket) packet).getPingId()));
|
||||
} else if (packet instanceof ClientboundDisconnectPacket) {
|
||||
session.disconnect(((ClientboundDisconnectPacket) packet).getReason().toString());
|
||||
session.disconnect(((ClientboundDisconnectPacket) packet).getReason());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,11 @@ import com.github.steveice10.packetlib.packet.Packet;
|
|||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.security.*;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
@ -125,7 +129,7 @@ public class ServerListener extends SessionAdapter {
|
|||
if (builder == null) {
|
||||
builder = $ -> new ServerStatusInfo(
|
||||
new VersionInfo(protocol.getCodec().getMinecraftVersion(), protocol.getCodec().getProtocolVersion()),
|
||||
new PlayerInfo(0, 20, new GameProfile[0]),
|
||||
new PlayerInfo(0, 20, new ArrayList<>()),
|
||||
Component.text("A Minecraft Server"),
|
||||
null,
|
||||
false
|
||||
|
|
|
@ -13,6 +13,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundCo
|
|||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundCustomChatCompletionsPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundCustomPayloadPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundDeleteChatPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundDelimiterPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundDisconnectPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundDisguisedChatPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundKeepAlivePacket;
|
||||
|
@ -36,7 +37,9 @@ import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUp
|
|||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUpdateRecipesPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUpdateTagsPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundAnimatePacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundDamageEventPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundEntityEventPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundHurtAnimationPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundMoveEntityPosPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundMoveEntityPosRotPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundMoveEntityRotPacket;
|
||||
|
@ -79,6 +82,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.Clientb
|
|||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundBlockEntityDataPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundBlockEventPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundBlockUpdatePacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundChunksBiomesPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundExplodePacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundForgetLevelChunkPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundGameEventPacket;
|
||||
|
@ -195,9 +199,9 @@ public class MinecraftCodec {
|
|||
}
|
||||
|
||||
public static final PacketCodec CODEC = PacketCodec.builder()
|
||||
.protocolVersion(761)
|
||||
.protocolVersion(762)
|
||||
.helper(() -> new MinecraftCodecHelper(LEVEL_EVENTS, SOUND_NAMES))
|
||||
.minecraftVersion("1.19.3")
|
||||
.minecraftVersion("1.19.4")
|
||||
.state(ProtocolState.HANDSHAKE, PacketStateCodec.builder()
|
||||
.registerServerboundPacket(0x00, ClientIntentionPacket.class, ClientIntentionPacket::new)
|
||||
)
|
||||
|
@ -216,146 +220,150 @@ public class MinecraftCodec {
|
|||
.registerServerboundPacket(0x00, ServerboundStatusRequestPacket.class, ServerboundStatusRequestPacket::new)
|
||||
.registerServerboundPacket(0x01, ServerboundPingRequestPacket.class, ServerboundPingRequestPacket::new)
|
||||
).state(ProtocolState.GAME, PacketStateCodec.builder()
|
||||
.registerClientboundPacket(0x00, ClientboundAddEntityPacket.class, ClientboundAddEntityPacket::new)
|
||||
.registerClientboundPacket(0x01, ClientboundAddExperienceOrbPacket.class, ClientboundAddExperienceOrbPacket::new)
|
||||
.registerClientboundPacket(0x02, ClientboundAddPlayerPacket.class, ClientboundAddPlayerPacket::new)
|
||||
.registerClientboundPacket(0x03, ClientboundAnimatePacket.class, ClientboundAnimatePacket::new)
|
||||
.registerClientboundPacket(0x04, ClientboundAwardStatsPacket.class, ClientboundAwardStatsPacket::new)
|
||||
.registerClientboundPacket(0x05, ClientboundBlockChangedAckPacket.class, ClientboundBlockChangedAckPacket::new)
|
||||
.registerClientboundPacket(0x06, ClientboundBlockDestructionPacket.class, ClientboundBlockDestructionPacket::new)
|
||||
.registerClientboundPacket(0x07, ClientboundBlockEntityDataPacket.class, ClientboundBlockEntityDataPacket::new)
|
||||
.registerClientboundPacket(0x08, ClientboundBlockEventPacket.class, ClientboundBlockEventPacket::new)
|
||||
.registerClientboundPacket(0x09, ClientboundBlockUpdatePacket.class, ClientboundBlockUpdatePacket::new)
|
||||
.registerClientboundPacket(0x0A, ClientboundBossEventPacket.class, ClientboundBossEventPacket::new)
|
||||
.registerClientboundPacket(0x0B, ClientboundChangeDifficultyPacket.class, ClientboundChangeDifficultyPacket::new)
|
||||
.registerClientboundPacket(0x0C, ClientboundClearTitlesPacket.class, ClientboundClearTitlesPacket::new)
|
||||
.registerClientboundPacket(0x0D, ClientboundCommandSuggestionsPacket.class, ClientboundCommandSuggestionsPacket::new)
|
||||
.registerClientboundPacket(0x0E, ClientboundCommandsPacket.class, ClientboundCommandsPacket::new)
|
||||
.registerClientboundPacket(0x0F, ClientboundContainerClosePacket.class, ClientboundContainerClosePacket::new)
|
||||
.registerClientboundPacket(0x10, ClientboundContainerSetContentPacket.class, ClientboundContainerSetContentPacket::new)
|
||||
.registerClientboundPacket(0x11, ClientboundContainerSetDataPacket.class, ClientboundContainerSetDataPacket::new)
|
||||
.registerClientboundPacket(0x12, ClientboundContainerSetSlotPacket.class, ClientboundContainerSetSlotPacket::new)
|
||||
.registerClientboundPacket(0x13, ClientboundCooldownPacket.class, ClientboundCooldownPacket::new)
|
||||
.registerClientboundPacket(0x14, ClientboundCustomChatCompletionsPacket.class, ClientboundCustomChatCompletionsPacket::new)
|
||||
.registerClientboundPacket(0x15, ClientboundCustomPayloadPacket.class, ClientboundCustomPayloadPacket::new)
|
||||
.registerClientboundPacket(0x16, ClientboundDeleteChatPacket.class, ClientboundDeleteChatPacket::new)
|
||||
.registerClientboundPacket(0x17, ClientboundDisconnectPacket.class, ClientboundDisconnectPacket::new)
|
||||
.registerClientboundPacket(0x18, ClientboundDisguisedChatPacket.class, ClientboundDisguisedChatPacket::new)
|
||||
.registerClientboundPacket(0x19, ClientboundEntityEventPacket.class, ClientboundEntityEventPacket::new)
|
||||
.registerClientboundPacket(0x1A, ClientboundExplodePacket.class, ClientboundExplodePacket::new)
|
||||
.registerClientboundPacket(0x1B, ClientboundForgetLevelChunkPacket.class, ClientboundForgetLevelChunkPacket::new)
|
||||
.registerClientboundPacket(0x1C, ClientboundGameEventPacket.class, ClientboundGameEventPacket::new)
|
||||
.registerClientboundPacket(0x1D, ClientboundHorseScreenOpenPacket.class, ClientboundHorseScreenOpenPacket::new)
|
||||
.registerClientboundPacket(0x1E, ClientboundInitializeBorderPacket.class, ClientboundInitializeBorderPacket::new)
|
||||
.registerClientboundPacket(0x1F, ClientboundKeepAlivePacket.class, ClientboundKeepAlivePacket::new)
|
||||
.registerClientboundPacket(0x20, ClientboundLevelChunkWithLightPacket.class, ClientboundLevelChunkWithLightPacket::new)
|
||||
.registerClientboundPacket(0x21, ClientboundLevelEventPacket.class, ClientboundLevelEventPacket::new)
|
||||
.registerClientboundPacket(0x22, ClientboundLevelParticlesPacket.class, ClientboundLevelParticlesPacket::new)
|
||||
.registerClientboundPacket(0x23, ClientboundLightUpdatePacket.class, ClientboundLightUpdatePacket::new)
|
||||
.registerClientboundPacket(0x24, ClientboundLoginPacket.class, ClientboundLoginPacket::new)
|
||||
.registerClientboundPacket(0x25, ClientboundMapItemDataPacket.class, ClientboundMapItemDataPacket::new)
|
||||
.registerClientboundPacket(0x26, ClientboundMerchantOffersPacket.class, ClientboundMerchantOffersPacket::new)
|
||||
.registerClientboundPacket(0x27, ClientboundMoveEntityPosPacket.class, ClientboundMoveEntityPosPacket::new)
|
||||
.registerClientboundPacket(0x28, ClientboundMoveEntityPosRotPacket.class, ClientboundMoveEntityPosRotPacket::new)
|
||||
.registerClientboundPacket(0x29, ClientboundMoveEntityRotPacket.class, ClientboundMoveEntityRotPacket::new)
|
||||
.registerClientboundPacket(0x2A, ClientboundMoveVehiclePacket.class, ClientboundMoveVehiclePacket::new)
|
||||
.registerClientboundPacket(0x2B, ClientboundOpenBookPacket.class, ClientboundOpenBookPacket::new)
|
||||
.registerClientboundPacket(0x2C, ClientboundOpenScreenPacket.class, ClientboundOpenScreenPacket::new)
|
||||
.registerClientboundPacket(0x2D, ClientboundOpenSignEditorPacket.class, ClientboundOpenSignEditorPacket::new)
|
||||
.registerClientboundPacket(0x2E, ClientboundPingPacket.class, ClientboundPingPacket::new)
|
||||
.registerClientboundPacket(0x2F, ClientboundPlaceGhostRecipePacket.class, ClientboundPlaceGhostRecipePacket::new)
|
||||
.registerClientboundPacket(0x30, ClientboundPlayerAbilitiesPacket.class, ClientboundPlayerAbilitiesPacket::new)
|
||||
.registerClientboundPacket(0x31, ClientboundPlayerChatPacket.class, ClientboundPlayerChatPacket::new)
|
||||
.registerClientboundPacket(0x32, ClientboundPlayerCombatEndPacket.class, ClientboundPlayerCombatEndPacket::new)
|
||||
.registerClientboundPacket(0x33, ClientboundPlayerCombatEnterPacket.class, ClientboundPlayerCombatEnterPacket::new)
|
||||
.registerClientboundPacket(0x34, ClientboundPlayerCombatKillPacket.class, ClientboundPlayerCombatKillPacket::new)
|
||||
.registerClientboundPacket(0x35, ClientboundPlayerInfoRemovePacket.class, ClientboundPlayerInfoRemovePacket::new)
|
||||
.registerClientboundPacket(0x36, ClientboundPlayerInfoUpdatePacket.class, ClientboundPlayerInfoUpdatePacket::new)
|
||||
.registerClientboundPacket(0x37, ClientboundPlayerLookAtPacket.class, ClientboundPlayerLookAtPacket::new)
|
||||
.registerClientboundPacket(0x38, ClientboundPlayerPositionPacket.class, ClientboundPlayerPositionPacket::new)
|
||||
.registerClientboundPacket(0x39, ClientboundRecipePacket.class, ClientboundRecipePacket::new)
|
||||
.registerClientboundPacket(0x3A, ClientboundRemoveEntitiesPacket.class, ClientboundRemoveEntitiesPacket::new)
|
||||
.registerClientboundPacket(0x3B, ClientboundRemoveMobEffectPacket.class, ClientboundRemoveMobEffectPacket::new)
|
||||
.registerClientboundPacket(0x3C, ClientboundResourcePackPacket.class, ClientboundResourcePackPacket::new)
|
||||
.registerClientboundPacket(0x3D, ClientboundRespawnPacket.class, ClientboundRespawnPacket::new)
|
||||
.registerClientboundPacket(0x3E, ClientboundRotateHeadPacket.class, ClientboundRotateHeadPacket::new)
|
||||
.registerClientboundPacket(0x3F, ClientboundSectionBlocksUpdatePacket.class, ClientboundSectionBlocksUpdatePacket::new)
|
||||
.registerClientboundPacket(0x40, ClientboundSelectAdvancementsTabPacket.class, ClientboundSelectAdvancementsTabPacket::new)
|
||||
.registerClientboundPacket(0x41, ClientboundServerDataPacket.class, ClientboundServerDataPacket::new)
|
||||
.registerClientboundPacket(0x42, ClientboundSetActionBarTextPacket.class, ClientboundSetActionBarTextPacket::new)
|
||||
.registerClientboundPacket(0x43, ClientboundSetBorderCenterPacket.class, ClientboundSetBorderCenterPacket::new)
|
||||
.registerClientboundPacket(0x44, ClientboundSetBorderLerpSizePacket.class, ClientboundSetBorderLerpSizePacket::new)
|
||||
.registerClientboundPacket(0x45, ClientboundSetBorderSizePacket.class, ClientboundSetBorderSizePacket::new)
|
||||
.registerClientboundPacket(0x46, ClientboundSetBorderWarningDelayPacket.class, ClientboundSetBorderWarningDelayPacket::new)
|
||||
.registerClientboundPacket(0x47, ClientboundSetBorderWarningDistancePacket.class, ClientboundSetBorderWarningDistancePacket::new)
|
||||
.registerClientboundPacket(0x48, ClientboundSetCameraPacket.class, ClientboundSetCameraPacket::new)
|
||||
.registerClientboundPacket(0x49, ClientboundSetCarriedItemPacket.class, ClientboundSetCarriedItemPacket::new)
|
||||
.registerClientboundPacket(0x4A, ClientboundSetChunkCacheCenterPacket.class, ClientboundSetChunkCacheCenterPacket::new)
|
||||
.registerClientboundPacket(0x4B, ClientboundSetChunkCacheRadiusPacket.class, ClientboundSetChunkCacheRadiusPacket::new)
|
||||
.registerClientboundPacket(0x4C, ClientboundSetDefaultSpawnPositionPacket.class, ClientboundSetDefaultSpawnPositionPacket::new)
|
||||
.registerClientboundPacket(0x4D, ClientboundSetDisplayObjectivePacket.class, ClientboundSetDisplayObjectivePacket::new)
|
||||
.registerClientboundPacket(0x4E, ClientboundSetEntityDataPacket.class, ClientboundSetEntityDataPacket::new)
|
||||
.registerClientboundPacket(0x4F, ClientboundSetEntityLinkPacket.class, ClientboundSetEntityLinkPacket::new)
|
||||
.registerClientboundPacket(0x50, ClientboundSetEntityMotionPacket.class, ClientboundSetEntityMotionPacket::new)
|
||||
.registerClientboundPacket(0x51, ClientboundSetEquipmentPacket.class, ClientboundSetEquipmentPacket::new)
|
||||
.registerClientboundPacket(0x52, ClientboundSetExperiencePacket.class, ClientboundSetExperiencePacket::new)
|
||||
.registerClientboundPacket(0x53, ClientboundSetHealthPacket.class, ClientboundSetHealthPacket::new)
|
||||
.registerClientboundPacket(0x54, ClientboundSetObjectivePacket.class, ClientboundSetObjectivePacket::new)
|
||||
.registerClientboundPacket(0x55, ClientboundSetPassengersPacket.class, ClientboundSetPassengersPacket::new)
|
||||
.registerClientboundPacket(0x56, ClientboundSetPlayerTeamPacket.class, ClientboundSetPlayerTeamPacket::new)
|
||||
.registerClientboundPacket(0x57, ClientboundSetScorePacket.class, ClientboundSetScorePacket::new)
|
||||
.registerClientboundPacket(0x58, ClientboundSetSimulationDistancePacket.class, ClientboundSetSimulationDistancePacket::new)
|
||||
.registerClientboundPacket(0x59, ClientboundSetSubtitleTextPacket.class, ClientboundSetSubtitleTextPacket::new)
|
||||
.registerClientboundPacket(0x5A, ClientboundSetTimePacket.class, ClientboundSetTimePacket::new)
|
||||
.registerClientboundPacket(0x5B, ClientboundSetTitleTextPacket.class, ClientboundSetTitleTextPacket::new)
|
||||
.registerClientboundPacket(0x5C, ClientboundSetTitlesAnimationPacket.class, ClientboundSetTitlesAnimationPacket::new)
|
||||
.registerClientboundPacket(0x5D, ClientboundSoundEntityPacket.class, ClientboundSoundEntityPacket::new)
|
||||
.registerClientboundPacket(0x5E, ClientboundSoundPacket.class, ClientboundSoundPacket::new)
|
||||
.registerClientboundPacket(0x5F, ClientboundStopSoundPacket.class, ClientboundStopSoundPacket::new)
|
||||
.registerClientboundPacket(0x60, ClientboundSystemChatPacket.class, ClientboundSystemChatPacket::new)
|
||||
.registerClientboundPacket(0x61, ClientboundTabListPacket.class, ClientboundTabListPacket::new)
|
||||
.registerClientboundPacket(0x62, ClientboundTagQueryPacket.class, ClientboundTagQueryPacket::new)
|
||||
.registerClientboundPacket(0x63, ClientboundTakeItemEntityPacket.class, ClientboundTakeItemEntityPacket::new)
|
||||
.registerClientboundPacket(0x64, ClientboundTeleportEntityPacket.class, ClientboundTeleportEntityPacket::new)
|
||||
.registerClientboundPacket(0x65, ClientboundUpdateAdvancementsPacket.class, ClientboundUpdateAdvancementsPacket::new)
|
||||
.registerClientboundPacket(0x66, ClientboundUpdateAttributesPacket.class, ClientboundUpdateAttributesPacket::new)
|
||||
.registerClientboundPacket(0x67, ClientboundUpdateEnabledFeaturesPacket.class, ClientboundUpdateEnabledFeaturesPacket::new)
|
||||
.registerClientboundPacket(0x68, ClientboundUpdateMobEffectPacket.class, ClientboundUpdateMobEffectPacket::new)
|
||||
.registerClientboundPacket(0x69, ClientboundUpdateRecipesPacket.class, ClientboundUpdateRecipesPacket::new)
|
||||
.registerClientboundPacket(0x6A, ClientboundUpdateTagsPacket.class, ClientboundUpdateTagsPacket::new)
|
||||
.registerClientboundPacket(0x00, ClientboundDelimiterPacket.class, ClientboundDelimiterPacket::new)
|
||||
.registerClientboundPacket(0x01, ClientboundAddEntityPacket.class, ClientboundAddEntityPacket::new)
|
||||
.registerClientboundPacket(0x02, ClientboundAddExperienceOrbPacket.class, ClientboundAddExperienceOrbPacket::new)
|
||||
.registerClientboundPacket(0x03, ClientboundAddPlayerPacket.class, ClientboundAddPlayerPacket::new)
|
||||
.registerClientboundPacket(0x04, ClientboundAnimatePacket.class, ClientboundAnimatePacket::new)
|
||||
.registerClientboundPacket(0x05, ClientboundAwardStatsPacket.class, ClientboundAwardStatsPacket::new)
|
||||
.registerClientboundPacket(0x06, ClientboundBlockChangedAckPacket.class, ClientboundBlockChangedAckPacket::new)
|
||||
.registerClientboundPacket(0x07, ClientboundBlockDestructionPacket.class, ClientboundBlockDestructionPacket::new)
|
||||
.registerClientboundPacket(0x08, ClientboundBlockEntityDataPacket.class, ClientboundBlockEntityDataPacket::new)
|
||||
.registerClientboundPacket(0x09, ClientboundBlockEventPacket.class, ClientboundBlockEventPacket::new)
|
||||
.registerClientboundPacket(0x0A, ClientboundBlockUpdatePacket.class, ClientboundBlockUpdatePacket::new)
|
||||
.registerClientboundPacket(0x0B, ClientboundBossEventPacket.class, ClientboundBossEventPacket::new)
|
||||
.registerClientboundPacket(0x0C, ClientboundChangeDifficultyPacket.class, ClientboundChangeDifficultyPacket::new)
|
||||
.registerClientboundPacket(0x0D, ClientboundChunksBiomesPacket.class, ClientboundChunksBiomesPacket::new)
|
||||
.registerClientboundPacket(0x0E, ClientboundClearTitlesPacket.class, ClientboundClearTitlesPacket::new)
|
||||
.registerClientboundPacket(0x0F, ClientboundCommandSuggestionsPacket.class, ClientboundCommandSuggestionsPacket::new)
|
||||
.registerClientboundPacket(0x10, ClientboundCommandsPacket.class, ClientboundCommandsPacket::new)
|
||||
.registerClientboundPacket(0x11, ClientboundContainerClosePacket.class, ClientboundContainerClosePacket::new)
|
||||
.registerClientboundPacket(0x12, ClientboundContainerSetContentPacket.class, ClientboundContainerSetContentPacket::new)
|
||||
.registerClientboundPacket(0x13, ClientboundContainerSetDataPacket.class, ClientboundContainerSetDataPacket::new)
|
||||
.registerClientboundPacket(0x14, ClientboundContainerSetSlotPacket.class, ClientboundContainerSetSlotPacket::new)
|
||||
.registerClientboundPacket(0x15, ClientboundCooldownPacket.class, ClientboundCooldownPacket::new)
|
||||
.registerClientboundPacket(0x16, ClientboundCustomChatCompletionsPacket.class, ClientboundCustomChatCompletionsPacket::new)
|
||||
.registerClientboundPacket(0x17, ClientboundCustomPayloadPacket.class, ClientboundCustomPayloadPacket::new)
|
||||
.registerClientboundPacket(0x18, ClientboundDamageEventPacket.class, ClientboundDamageEventPacket::new)
|
||||
.registerClientboundPacket(0x19, ClientboundDeleteChatPacket.class, ClientboundDeleteChatPacket::new)
|
||||
.registerClientboundPacket(0x1A, ClientboundDisconnectPacket.class, ClientboundDisconnectPacket::new)
|
||||
.registerClientboundPacket(0x1B, ClientboundDisguisedChatPacket.class, ClientboundDisguisedChatPacket::new)
|
||||
.registerClientboundPacket(0x1C, ClientboundEntityEventPacket.class, ClientboundEntityEventPacket::new)
|
||||
.registerClientboundPacket(0x1D, ClientboundExplodePacket.class, ClientboundExplodePacket::new)
|
||||
.registerClientboundPacket(0x1E, ClientboundForgetLevelChunkPacket.class, ClientboundForgetLevelChunkPacket::new)
|
||||
.registerClientboundPacket(0x1F, ClientboundGameEventPacket.class, ClientboundGameEventPacket::new)
|
||||
.registerClientboundPacket(0x20, ClientboundHorseScreenOpenPacket.class, ClientboundHorseScreenOpenPacket::new)
|
||||
.registerClientboundPacket(0x21, ClientboundHurtAnimationPacket.class, ClientboundHurtAnimationPacket::new)
|
||||
.registerClientboundPacket(0x22, ClientboundInitializeBorderPacket.class, ClientboundInitializeBorderPacket::new)
|
||||
.registerClientboundPacket(0x23, ClientboundKeepAlivePacket.class, ClientboundKeepAlivePacket::new)
|
||||
.registerClientboundPacket(0x24, ClientboundLevelChunkWithLightPacket.class, ClientboundLevelChunkWithLightPacket::new)
|
||||
.registerClientboundPacket(0x25, ClientboundLevelEventPacket.class, ClientboundLevelEventPacket::new)
|
||||
.registerClientboundPacket(0x26, ClientboundLevelParticlesPacket.class, ClientboundLevelParticlesPacket::new)
|
||||
.registerClientboundPacket(0x27, ClientboundLightUpdatePacket.class, ClientboundLightUpdatePacket::new)
|
||||
.registerClientboundPacket(0x28, ClientboundLoginPacket.class, ClientboundLoginPacket::new)
|
||||
.registerClientboundPacket(0x29, ClientboundMapItemDataPacket.class, ClientboundMapItemDataPacket::new)
|
||||
.registerClientboundPacket(0x2A, ClientboundMerchantOffersPacket.class, ClientboundMerchantOffersPacket::new)
|
||||
.registerClientboundPacket(0x2B, ClientboundMoveEntityPosPacket.class, ClientboundMoveEntityPosPacket::new)
|
||||
.registerClientboundPacket(0x2C, ClientboundMoveEntityPosRotPacket.class, ClientboundMoveEntityPosRotPacket::new)
|
||||
.registerClientboundPacket(0x2D, ClientboundMoveEntityRotPacket.class, ClientboundMoveEntityRotPacket::new)
|
||||
.registerClientboundPacket(0x2E, ClientboundMoveVehiclePacket.class, ClientboundMoveVehiclePacket::new)
|
||||
.registerClientboundPacket(0x2F, ClientboundOpenBookPacket.class, ClientboundOpenBookPacket::new)
|
||||
.registerClientboundPacket(0x30, ClientboundOpenScreenPacket.class, ClientboundOpenScreenPacket::new)
|
||||
.registerClientboundPacket(0x31, ClientboundOpenSignEditorPacket.class, ClientboundOpenSignEditorPacket::new)
|
||||
.registerClientboundPacket(0x32, ClientboundPingPacket.class, ClientboundPingPacket::new)
|
||||
.registerClientboundPacket(0x33, ClientboundPlaceGhostRecipePacket.class, ClientboundPlaceGhostRecipePacket::new)
|
||||
.registerClientboundPacket(0x34, ClientboundPlayerAbilitiesPacket.class, ClientboundPlayerAbilitiesPacket::new)
|
||||
.registerClientboundPacket(0x35, ClientboundPlayerChatPacket.class, ClientboundPlayerChatPacket::new)
|
||||
.registerClientboundPacket(0x36, ClientboundPlayerCombatEndPacket.class, ClientboundPlayerCombatEndPacket::new)
|
||||
.registerClientboundPacket(0x37, ClientboundPlayerCombatEnterPacket.class, ClientboundPlayerCombatEnterPacket::new)
|
||||
.registerClientboundPacket(0x38, ClientboundPlayerCombatKillPacket.class, ClientboundPlayerCombatKillPacket::new)
|
||||
.registerClientboundPacket(0x39, ClientboundPlayerInfoRemovePacket.class, ClientboundPlayerInfoRemovePacket::new)
|
||||
.registerClientboundPacket(0x3A, ClientboundPlayerInfoUpdatePacket.class, ClientboundPlayerInfoUpdatePacket::new)
|
||||
.registerClientboundPacket(0x3B, ClientboundPlayerLookAtPacket.class, ClientboundPlayerLookAtPacket::new)
|
||||
.registerClientboundPacket(0x3C, ClientboundPlayerPositionPacket.class, ClientboundPlayerPositionPacket::new)
|
||||
.registerClientboundPacket(0x3D, ClientboundRecipePacket.class, ClientboundRecipePacket::new)
|
||||
.registerClientboundPacket(0x3E, ClientboundRemoveEntitiesPacket.class, ClientboundRemoveEntitiesPacket::new)
|
||||
.registerClientboundPacket(0x3F, ClientboundRemoveMobEffectPacket.class, ClientboundRemoveMobEffectPacket::new)
|
||||
.registerClientboundPacket(0x40, ClientboundResourcePackPacket.class, ClientboundResourcePackPacket::new)
|
||||
.registerClientboundPacket(0x41, ClientboundRespawnPacket.class, ClientboundRespawnPacket::new)
|
||||
.registerClientboundPacket(0x42, ClientboundRotateHeadPacket.class, ClientboundRotateHeadPacket::new)
|
||||
.registerClientboundPacket(0x43, ClientboundSectionBlocksUpdatePacket.class, ClientboundSectionBlocksUpdatePacket::new)
|
||||
.registerClientboundPacket(0x44, ClientboundSelectAdvancementsTabPacket.class, ClientboundSelectAdvancementsTabPacket::new)
|
||||
.registerClientboundPacket(0x45, ClientboundServerDataPacket.class, ClientboundServerDataPacket::new)
|
||||
.registerClientboundPacket(0x46, ClientboundSetActionBarTextPacket.class, ClientboundSetActionBarTextPacket::new)
|
||||
.registerClientboundPacket(0x47, ClientboundSetBorderCenterPacket.class, ClientboundSetBorderCenterPacket::new)
|
||||
.registerClientboundPacket(0x48, ClientboundSetBorderLerpSizePacket.class, ClientboundSetBorderLerpSizePacket::new)
|
||||
.registerClientboundPacket(0x49, ClientboundSetBorderSizePacket.class, ClientboundSetBorderSizePacket::new)
|
||||
.registerClientboundPacket(0x4A, ClientboundSetBorderWarningDelayPacket.class, ClientboundSetBorderWarningDelayPacket::new)
|
||||
.registerClientboundPacket(0x4B, ClientboundSetBorderWarningDistancePacket.class, ClientboundSetBorderWarningDistancePacket::new)
|
||||
.registerClientboundPacket(0x4C, ClientboundSetCameraPacket.class, ClientboundSetCameraPacket::new)
|
||||
.registerClientboundPacket(0x4D, ClientboundSetCarriedItemPacket.class, ClientboundSetCarriedItemPacket::new)
|
||||
.registerClientboundPacket(0x4E, ClientboundSetChunkCacheCenterPacket.class, ClientboundSetChunkCacheCenterPacket::new)
|
||||
.registerClientboundPacket(0x4F, ClientboundSetChunkCacheRadiusPacket.class, ClientboundSetChunkCacheRadiusPacket::new)
|
||||
.registerClientboundPacket(0x50, ClientboundSetDefaultSpawnPositionPacket.class, ClientboundSetDefaultSpawnPositionPacket::new)
|
||||
.registerClientboundPacket(0x51, ClientboundSetDisplayObjectivePacket.class, ClientboundSetDisplayObjectivePacket::new)
|
||||
.registerClientboundPacket(0x52, ClientboundSetEntityDataPacket.class, ClientboundSetEntityDataPacket::new)
|
||||
.registerClientboundPacket(0x53, ClientboundSetEntityLinkPacket.class, ClientboundSetEntityLinkPacket::new)
|
||||
.registerClientboundPacket(0x54, ClientboundSetEntityMotionPacket.class, ClientboundSetEntityMotionPacket::new)
|
||||
.registerClientboundPacket(0x55, ClientboundSetEquipmentPacket.class, ClientboundSetEquipmentPacket::new)
|
||||
.registerClientboundPacket(0x56, ClientboundSetExperiencePacket.class, ClientboundSetExperiencePacket::new)
|
||||
.registerClientboundPacket(0x57, ClientboundSetHealthPacket.class, ClientboundSetHealthPacket::new)
|
||||
.registerClientboundPacket(0x58, ClientboundSetObjectivePacket.class, ClientboundSetObjectivePacket::new)
|
||||
.registerClientboundPacket(0x59, ClientboundSetPassengersPacket.class, ClientboundSetPassengersPacket::new)
|
||||
.registerClientboundPacket(0x5A, ClientboundSetPlayerTeamPacket.class, ClientboundSetPlayerTeamPacket::new)
|
||||
.registerClientboundPacket(0x5B, ClientboundSetScorePacket.class, ClientboundSetScorePacket::new)
|
||||
.registerClientboundPacket(0x5C, ClientboundSetSimulationDistancePacket.class, ClientboundSetSimulationDistancePacket::new)
|
||||
.registerClientboundPacket(0x5D, ClientboundSetSubtitleTextPacket.class, ClientboundSetSubtitleTextPacket::new)
|
||||
.registerClientboundPacket(0x5E, ClientboundSetTimePacket.class, ClientboundSetTimePacket::new)
|
||||
.registerClientboundPacket(0x5F, ClientboundSetTitleTextPacket.class, ClientboundSetTitleTextPacket::new)
|
||||
.registerClientboundPacket(0x60, ClientboundSetTitlesAnimationPacket.class, ClientboundSetTitlesAnimationPacket::new)
|
||||
.registerClientboundPacket(0x61, ClientboundSoundEntityPacket.class, ClientboundSoundEntityPacket::new)
|
||||
.registerClientboundPacket(0x62, ClientboundSoundPacket.class, ClientboundSoundPacket::new)
|
||||
.registerClientboundPacket(0x63, ClientboundStopSoundPacket.class, ClientboundStopSoundPacket::new)
|
||||
.registerClientboundPacket(0x64, ClientboundSystemChatPacket.class, ClientboundSystemChatPacket::new)
|
||||
.registerClientboundPacket(0x65, ClientboundTabListPacket.class, ClientboundTabListPacket::new)
|
||||
.registerClientboundPacket(0x66, ClientboundTagQueryPacket.class, ClientboundTagQueryPacket::new)
|
||||
.registerClientboundPacket(0x67, ClientboundTakeItemEntityPacket.class, ClientboundTakeItemEntityPacket::new)
|
||||
.registerClientboundPacket(0x68, ClientboundTeleportEntityPacket.class, ClientboundTeleportEntityPacket::new)
|
||||
.registerClientboundPacket(0x69, ClientboundUpdateAdvancementsPacket.class, ClientboundUpdateAdvancementsPacket::new)
|
||||
.registerClientboundPacket(0x6A, ClientboundUpdateAttributesPacket.class, ClientboundUpdateAttributesPacket::new)
|
||||
.registerClientboundPacket(0x6B, ClientboundUpdateEnabledFeaturesPacket.class, ClientboundUpdateEnabledFeaturesPacket::new)
|
||||
.registerClientboundPacket(0x6C, ClientboundUpdateMobEffectPacket.class, ClientboundUpdateMobEffectPacket::new)
|
||||
.registerClientboundPacket(0x6D, ClientboundUpdateRecipesPacket.class, ClientboundUpdateRecipesPacket::new)
|
||||
.registerClientboundPacket(0x6E, ClientboundUpdateTagsPacket.class, ClientboundUpdateTagsPacket::new)
|
||||
.registerServerboundPacket(0x00, ServerboundAcceptTeleportationPacket.class, ServerboundAcceptTeleportationPacket::new)
|
||||
.registerServerboundPacket(0x01, ServerboundBlockEntityTagQuery.class, ServerboundBlockEntityTagQuery::new)
|
||||
.registerServerboundPacket(0x02, ServerboundChangeDifficultyPacket.class, ServerboundChangeDifficultyPacket::new)
|
||||
.registerServerboundPacket(0x03, ServerboundChatAckPacket.class, ServerboundChatAckPacket::new)
|
||||
.registerServerboundPacket(0x04, ServerboundChatCommandPacket.class, ServerboundChatCommandPacket::new)
|
||||
.registerServerboundPacket(0x05, ServerboundChatPacket.class, ServerboundChatPacket::new)
|
||||
.registerServerboundPacket(0x06, ServerboundClientCommandPacket.class, ServerboundClientCommandPacket::new)
|
||||
.registerServerboundPacket(0x07, ServerboundClientInformationPacket.class, ServerboundClientInformationPacket::new)
|
||||
.registerServerboundPacket(0x08, ServerboundCommandSuggestionPacket.class, ServerboundCommandSuggestionPacket::new)
|
||||
.registerServerboundPacket(0x09, ServerboundContainerButtonClickPacket.class, ServerboundContainerButtonClickPacket::new)
|
||||
.registerServerboundPacket(0x0A, ServerboundContainerClickPacket.class, ServerboundContainerClickPacket::new)
|
||||
.registerServerboundPacket(0x0B, ServerboundContainerClosePacket.class, ServerboundContainerClosePacket::new)
|
||||
.registerServerboundPacket(0x0C, ServerboundCustomPayloadPacket.class, ServerboundCustomPayloadPacket::new)
|
||||
.registerServerboundPacket(0x0D, ServerboundEditBookPacket.class, ServerboundEditBookPacket::new)
|
||||
.registerServerboundPacket(0x0E, ServerboundEntityTagQuery.class, ServerboundEntityTagQuery::new)
|
||||
.registerServerboundPacket(0x0F, ServerboundInteractPacket.class, ServerboundInteractPacket::new)
|
||||
.registerServerboundPacket(0x10, ServerboundJigsawGeneratePacket.class, ServerboundJigsawGeneratePacket::new)
|
||||
.registerServerboundPacket(0x11, ServerboundKeepAlivePacket.class, ServerboundKeepAlivePacket::new)
|
||||
.registerServerboundPacket(0x12, ServerboundLockDifficultyPacket.class, ServerboundLockDifficultyPacket::new)
|
||||
.registerServerboundPacket(0x13, ServerboundMovePlayerPosPacket.class, ServerboundMovePlayerPosPacket::new)
|
||||
.registerServerboundPacket(0x14, ServerboundMovePlayerPosRotPacket.class, ServerboundMovePlayerPosRotPacket::new)
|
||||
.registerServerboundPacket(0x15, ServerboundMovePlayerRotPacket.class, ServerboundMovePlayerRotPacket::new)
|
||||
.registerServerboundPacket(0x16, ServerboundMovePlayerStatusOnlyPacket.class, ServerboundMovePlayerStatusOnlyPacket::new)
|
||||
.registerServerboundPacket(0x17, ServerboundMoveVehiclePacket.class, ServerboundMoveVehiclePacket::new)
|
||||
.registerServerboundPacket(0x18, ServerboundPaddleBoatPacket.class, ServerboundPaddleBoatPacket::new)
|
||||
.registerServerboundPacket(0x19, ServerboundPickItemPacket.class, ServerboundPickItemPacket::new)
|
||||
.registerServerboundPacket(0x1A, ServerboundPlaceRecipePacket.class, ServerboundPlaceRecipePacket::new)
|
||||
.registerServerboundPacket(0x1B, ServerboundPlayerAbilitiesPacket.class, ServerboundPlayerAbilitiesPacket::new)
|
||||
.registerServerboundPacket(0x1C, ServerboundPlayerActionPacket.class, ServerboundPlayerActionPacket::new)
|
||||
.registerServerboundPacket(0x1D, ServerboundPlayerCommandPacket.class, ServerboundPlayerCommandPacket::new)
|
||||
.registerServerboundPacket(0x1E, ServerboundPlayerInputPacket.class, ServerboundPlayerInputPacket::new)
|
||||
.registerServerboundPacket(0x1F, ServerboundPongPacket.class, ServerboundPongPacket::new)
|
||||
.registerServerboundPacket(0x20, ServerboundChatSessionUpdatePacket.class, ServerboundChatSessionUpdatePacket::new)
|
||||
.registerServerboundPacket(0x06, ServerboundChatSessionUpdatePacket.class, ServerboundChatSessionUpdatePacket::new)
|
||||
.registerServerboundPacket(0x07, ServerboundClientCommandPacket.class, ServerboundClientCommandPacket::new)
|
||||
.registerServerboundPacket(0x08, ServerboundClientInformationPacket.class, ServerboundClientInformationPacket::new)
|
||||
.registerServerboundPacket(0x09, ServerboundCommandSuggestionPacket.class, ServerboundCommandSuggestionPacket::new)
|
||||
.registerServerboundPacket(0x0A, ServerboundContainerButtonClickPacket.class, ServerboundContainerButtonClickPacket::new)
|
||||
.registerServerboundPacket(0x0B, ServerboundContainerClickPacket.class, ServerboundContainerClickPacket::new)
|
||||
.registerServerboundPacket(0x0C, ServerboundContainerClosePacket.class, ServerboundContainerClosePacket::new)
|
||||
.registerServerboundPacket(0x0D, ServerboundCustomPayloadPacket.class, ServerboundCustomPayloadPacket::new)
|
||||
.registerServerboundPacket(0x0E, ServerboundEditBookPacket.class, ServerboundEditBookPacket::new)
|
||||
.registerServerboundPacket(0x0F, ServerboundEntityTagQuery.class, ServerboundEntityTagQuery::new)
|
||||
.registerServerboundPacket(0x10, ServerboundInteractPacket.class, ServerboundInteractPacket::new)
|
||||
.registerServerboundPacket(0x11, ServerboundJigsawGeneratePacket.class, ServerboundJigsawGeneratePacket::new)
|
||||
.registerServerboundPacket(0x12, ServerboundKeepAlivePacket.class, ServerboundKeepAlivePacket::new)
|
||||
.registerServerboundPacket(0x13, ServerboundLockDifficultyPacket.class, ServerboundLockDifficultyPacket::new)
|
||||
.registerServerboundPacket(0x14, ServerboundMovePlayerPosPacket.class, ServerboundMovePlayerPosPacket::new)
|
||||
.registerServerboundPacket(0x15, ServerboundMovePlayerPosRotPacket.class, ServerboundMovePlayerPosRotPacket::new)
|
||||
.registerServerboundPacket(0x16, ServerboundMovePlayerRotPacket.class, ServerboundMovePlayerRotPacket::new)
|
||||
.registerServerboundPacket(0x17, ServerboundMovePlayerStatusOnlyPacket.class, ServerboundMovePlayerStatusOnlyPacket::new)
|
||||
.registerServerboundPacket(0x18, ServerboundMoveVehiclePacket.class, ServerboundMoveVehiclePacket::new)
|
||||
.registerServerboundPacket(0x19, ServerboundPaddleBoatPacket.class, ServerboundPaddleBoatPacket::new)
|
||||
.registerServerboundPacket(0x1A, ServerboundPickItemPacket.class, ServerboundPickItemPacket::new)
|
||||
.registerServerboundPacket(0x1B, ServerboundPlaceRecipePacket.class, ServerboundPlaceRecipePacket::new)
|
||||
.registerServerboundPacket(0x1C, ServerboundPlayerAbilitiesPacket.class, ServerboundPlayerAbilitiesPacket::new)
|
||||
.registerServerboundPacket(0x1D, ServerboundPlayerActionPacket.class, ServerboundPlayerActionPacket::new)
|
||||
.registerServerboundPacket(0x1E, ServerboundPlayerCommandPacket.class, ServerboundPlayerCommandPacket::new)
|
||||
.registerServerboundPacket(0x1F, ServerboundPlayerInputPacket.class, ServerboundPlayerInputPacket::new)
|
||||
.registerServerboundPacket(0x20, ServerboundPongPacket.class, ServerboundPongPacket::new)
|
||||
.registerServerboundPacket(0x21, ServerboundRecipeBookChangeSettingsPacket.class, ServerboundRecipeBookChangeSettingsPacket::new)
|
||||
.registerServerboundPacket(0x22, ServerboundRecipeBookSeenRecipePacket.class, ServerboundRecipeBookSeenRecipePacket::new)
|
||||
.registerServerboundPacket(0x23, ServerboundRenameItemPacket.class, ServerboundRenameItemPacket::new)
|
||||
|
|
|
@ -21,6 +21,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.GlobalPos;
|
|||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.SnifferState;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.object.Direction;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.BlockBreakStage;
|
||||
|
@ -56,6 +57,7 @@ import com.github.steveice10.opennbt.tag.builtin.Tag;
|
|||
import com.github.steveice10.packetlib.codec.BasePacketCodecHelper;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.math.vector.Vector4f;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
@ -292,6 +294,22 @@ public class MinecraftCodecHelper extends BasePacketCodecHelper {
|
|||
buf.writeFloat(rot.getZ());
|
||||
}
|
||||
|
||||
public Vector4f readQuaternion(ByteBuf buf) {
|
||||
float x = buf.readFloat();
|
||||
float y = buf.readFloat();
|
||||
float z = buf.readFloat();
|
||||
float w = buf.readFloat();
|
||||
|
||||
return Vector4f.from(x, y, z, w);
|
||||
}
|
||||
|
||||
public void writeQuaternion(ByteBuf buf, Vector4f vec4) {
|
||||
buf.writeFloat(vec4.getX());
|
||||
buf.writeFloat(vec4.getY());
|
||||
buf.writeFloat(vec4.getZ());
|
||||
buf.writeFloat(vec4.getW());
|
||||
}
|
||||
|
||||
public Direction readDirection(ByteBuf buf) {
|
||||
return Direction.from(this.readVarInt(buf));
|
||||
}
|
||||
|
@ -316,6 +334,14 @@ public class MinecraftCodecHelper extends BasePacketCodecHelper {
|
|||
this.writeEnum(buf, type);
|
||||
}
|
||||
|
||||
public SnifferState readSnifferState(ByteBuf buf) {
|
||||
return SnifferState.from(this.readVarInt(buf));
|
||||
}
|
||||
|
||||
public void writeSnifferState(ByteBuf buf, SnifferState state) {
|
||||
this.writeEnum(buf, state);
|
||||
}
|
||||
|
||||
private void writeEnum(ByteBuf buf, Enum<?> e) {
|
||||
this.writeVarInt(buf, e.ordinal());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package com.github.steveice10.mc.protocol.data.game.chunk;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class ChunkBiomeData {
|
||||
private final int x;
|
||||
private final int z;
|
||||
private final byte[] buffer;
|
||||
}
|
|
@ -48,6 +48,7 @@ public enum CommandParser {
|
|||
RESOURCE_KEY,
|
||||
TEMPLATE_MIRROR,
|
||||
TEMPLATE_ROTATION,
|
||||
HEIGHTMAP,
|
||||
UUID;
|
||||
|
||||
private static final CommandParser[] VALUES = values();
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package com.github.steveice10.mc.protocol.data.game.command.properties;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class TimeProperties implements CommandProperties {
|
||||
private final int min;
|
||||
}
|
|
@ -63,7 +63,8 @@ public enum EntityEvent {
|
|||
GOAT_STOP_LOWERING_HEAD,
|
||||
MAKE_POOF_PARTICLES,
|
||||
WARDEN_RECEIVE_SIGNAL,
|
||||
WARDEN_SONIC_BOOM;
|
||||
WARDEN_SONIC_BOOM,
|
||||
SNIFFER_MAKE_SOUND;
|
||||
|
||||
private static final EntityEvent[] VALUES = values();
|
||||
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
package com.github.steveice10.mc.protocol.data.game.entity.metadata;
|
||||
|
||||
import com.github.steveice10.mc.protocol.codec.MinecraftCodecHelper;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.*;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.LongEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.object.Direction;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.type.PaintingType;
|
||||
import com.github.steveice10.mc.protocol.data.game.level.particle.Particle;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.math.vector.Vector4f;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.Getter;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
@ -16,6 +22,7 @@ import java.io.IOException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter
|
||||
|
@ -36,7 +43,8 @@ public class MetadataType<T> {
|
|||
public static final MetadataType<Optional<Vector3i>> OPTIONAL_POSITION = new MetadataType<>(optionalReader(MinecraftCodecHelper::readPosition), optionalWriter(MinecraftCodecHelper::writePosition), ObjectEntityMetadata::new);
|
||||
public static final MetadataType<Direction> DIRECTION = new MetadataType<>(MinecraftCodecHelper::readDirection, MinecraftCodecHelper::writeDirection, ObjectEntityMetadata::new);
|
||||
public static final MetadataType<Optional<UUID>> OPTIONAL_UUID = new MetadataType<>(optionalReader(MinecraftCodecHelper::readUUID), optionalWriter(MinecraftCodecHelper::writeUUID), ObjectEntityMetadata::new);
|
||||
public static final OptionalIntMetadataType BLOCK_STATE = new OptionalIntMetadataType(ObjectEntityMetadata::new);
|
||||
public static final IntMetadataType BLOCK_STATE = new IntMetadataType(MinecraftCodecHelper::readVarInt, MinecraftCodecHelper::writeVarInt, IntEntityMetadata::new);
|
||||
public static final IntMetadataType OPTIONAL_BLOCK_STATE = new IntMetadataType(MinecraftCodecHelper::readVarInt, MinecraftCodecHelper::writeVarInt, IntEntityMetadata::new);
|
||||
public static final MetadataType<CompoundTag> NBT_TAG = new MetadataType<>(MinecraftCodecHelper::readTag, MinecraftCodecHelper::writeTag, ObjectEntityMetadata::new);
|
||||
public static final MetadataType<Particle> PARTICLE = new MetadataType<>(MinecraftCodecHelper::readParticle, MinecraftCodecHelper::writeParticle, ObjectEntityMetadata::new);
|
||||
public static final MetadataType<VillagerData> VILLAGER_DATA = new MetadataType<>(MinecraftCodecHelper::readVillagerData, MinecraftCodecHelper::writeVillagerData, ObjectEntityMetadata::new);
|
||||
|
@ -46,6 +54,9 @@ public class MetadataType<T> {
|
|||
public static final IntMetadataType FROG_VARIANT = new IntMetadataType(MinecraftCodecHelper::readVarInt, MinecraftCodecHelper::writeVarInt, IntEntityMetadata::new);
|
||||
public static final MetadataType<Optional<GlobalPos>> OPTIONAL_GLOBAL_POS = new MetadataType<>(optionalReader(MinecraftCodecHelper::readGlobalPos), optionalWriter(MinecraftCodecHelper::writeGlobalPos), ObjectEntityMetadata::new);
|
||||
public static final MetadataType<PaintingType> PAINTING_VARIANT = new MetadataType<>(MinecraftCodecHelper::readPaintingType, MinecraftCodecHelper::writePaintingType, ObjectEntityMetadata::new);
|
||||
public static final MetadataType<SnifferState> SNIFFER_STATE = new MetadataType<>(MinecraftCodecHelper::readSnifferState, MinecraftCodecHelper::writeSnifferState, ObjectEntityMetadata::new);
|
||||
public static final MetadataType<Vector3f> VECTOR3 = new MetadataType<>(MinecraftCodecHelper::readRotation, MinecraftCodecHelper::writeRotation, ObjectEntityMetadata::new);
|
||||
public static final MetadataType<Vector4f> QUATERNION = new MetadataType<>(MinecraftCodecHelper::readQuaternion, MinecraftCodecHelper::writeQuaternion, ObjectEntityMetadata::new);
|
||||
|
||||
protected final int id;
|
||||
protected final Reader<T> reader;
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
package com.github.steveice10.mc.protocol.data.game.entity.metadata;
|
||||
|
||||
public enum SnifferState {
|
||||
IDLING,
|
||||
FEELING_HAPPY,
|
||||
SCENTING,
|
||||
SNIFFING,
|
||||
SEARCHING,
|
||||
DIGGING,
|
||||
RISING;
|
||||
|
||||
private static final SnifferState[] VALUES = values();
|
||||
|
||||
public static SnifferState from(int id) {
|
||||
return VALUES[id];
|
||||
}
|
||||
}
|
|
@ -1,16 +1,34 @@
|
|||
package com.github.steveice10.mc.protocol.data.game.entity.player;
|
||||
|
||||
public enum Animation {
|
||||
SWING_ARM,
|
||||
DAMAGE,
|
||||
LEAVE_BED,
|
||||
SWING_OFFHAND,
|
||||
CRITICAL_HIT,
|
||||
ENCHANTMENT_CRITICAL_HIT;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
private static final Animation[] VALUES = values();
|
||||
public enum Animation {
|
||||
SWING_ARM(0),
|
||||
LEAVE_BED(2),
|
||||
SWING_OFFHAND(3),
|
||||
CRITICAL_HIT(4),
|
||||
ENCHANTMENT_CRITICAL_HIT(5);
|
||||
|
||||
private final int id;
|
||||
|
||||
Animation(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private static Int2ObjectMap<Animation> VALUES = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
public static Animation from(int id) {
|
||||
return VALUES[id];
|
||||
return VALUES.get(id);
|
||||
}
|
||||
|
||||
static {
|
||||
for (Animation animation : values()) {
|
||||
VALUES.put(animation.id, animation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,32 +9,39 @@ public enum EntityType {
|
|||
BAT,
|
||||
BEE,
|
||||
BLAZE,
|
||||
BLOCK_DISPLAY,
|
||||
BOAT,
|
||||
CHEST_BOAT,
|
||||
CAT,
|
||||
CAMEL,
|
||||
CAT,
|
||||
CAVE_SPIDER,
|
||||
CHEST_BOAT,
|
||||
CHEST_MINECART,
|
||||
CHICKEN,
|
||||
COD,
|
||||
COMMAND_BLOCK_MINECART,
|
||||
COW,
|
||||
CREEPER,
|
||||
DOLPHIN,
|
||||
DONKEY,
|
||||
DRAGON_FIREBALL,
|
||||
DROWNED,
|
||||
EGG,
|
||||
ELDER_GUARDIAN,
|
||||
END_CRYSTAL,
|
||||
ENDER_DRAGON,
|
||||
ENDER_PEARL,
|
||||
ENDERMAN,
|
||||
ENDERMITE,
|
||||
EVOKER,
|
||||
EVOKER_FANGS,
|
||||
EXPERIENCE_BOTTLE,
|
||||
EXPERIENCE_ORB,
|
||||
EYE_OF_ENDER,
|
||||
FALLING_BLOCK,
|
||||
FIREWORK_ROCKET,
|
||||
FOX,
|
||||
FROG,
|
||||
FURNACE_MINECART,
|
||||
GHAST,
|
||||
GIANT,
|
||||
GLOW_ITEM_FRAME,
|
||||
|
@ -42,11 +49,14 @@ public enum EntityType {
|
|||
GOAT,
|
||||
GUARDIAN,
|
||||
HOGLIN,
|
||||
HOPPER_MINECART,
|
||||
HORSE,
|
||||
HUSK,
|
||||
ILLUSIONER,
|
||||
INTERACTION,
|
||||
IRON_GOLEM,
|
||||
ITEM,
|
||||
ITEM_DISPLAY,
|
||||
ITEM_FRAME,
|
||||
FIREBALL,
|
||||
LEASH_KNOT,
|
||||
|
@ -56,14 +66,8 @@ public enum EntityType {
|
|||
MAGMA_CUBE,
|
||||
MARKER,
|
||||
MINECART,
|
||||
CHEST_MINECART,
|
||||
COMMAND_BLOCK_MINECART,
|
||||
FURNACE_MINECART,
|
||||
HOPPER_MINECART,
|
||||
SPAWNER_MINECART,
|
||||
TNT_MINECART,
|
||||
MULE,
|
||||
MOOSHROOM,
|
||||
MULE,
|
||||
OCELOT,
|
||||
PAINTING,
|
||||
PANDA,
|
||||
|
@ -74,7 +78,7 @@ public enum EntityType {
|
|||
PIGLIN_BRUTE,
|
||||
PILLAGER,
|
||||
POLAR_BEAR,
|
||||
TNT,
|
||||
POTION,
|
||||
PUFFERFISH,
|
||||
RABBIT,
|
||||
RAVAGER,
|
||||
|
@ -87,20 +91,21 @@ public enum EntityType {
|
|||
SKELETON_HORSE,
|
||||
SLIME,
|
||||
SMALL_FIREBALL,
|
||||
SNIFFER,
|
||||
SNOW_GOLEM,
|
||||
SNOWBALL,
|
||||
SPAWNER_MINECART,
|
||||
SPECTRAL_ARROW,
|
||||
SPIDER,
|
||||
SQUID,
|
||||
STRAY,
|
||||
STRIDER,
|
||||
TADPOLE,
|
||||
EGG,
|
||||
ENDER_PEARL,
|
||||
EXPERIENCE_BOTTLE,
|
||||
POTION,
|
||||
TRIDENT,
|
||||
TEXT_DISPLAY,
|
||||
TNT,
|
||||
TNT_MINECART,
|
||||
TRADER_LLAMA,
|
||||
TRIDENT,
|
||||
TROPICAL_FISH,
|
||||
TURTLE,
|
||||
VEX,
|
||||
|
|
|
@ -21,6 +21,7 @@ public enum ContainerType {
|
|||
LOOM,
|
||||
MERCHANT,
|
||||
SHULKER_BOX,
|
||||
LEGACY_SMITHING,
|
||||
SMITHING,
|
||||
SMOKER,
|
||||
CARTOGRAPHY,
|
||||
|
|
|
@ -38,7 +38,9 @@ public enum BlockEntityType {
|
|||
SCULK_SENSOR,
|
||||
SCULK_CATALYST,
|
||||
SCULK_SHRIEKER,
|
||||
CHISELED_BOOKSHELF;
|
||||
CHISELED_BOOKSHELF,
|
||||
SUSPICIOUS_SAND,
|
||||
DECORATED_POT;
|
||||
|
||||
private static final BlockEntityType[] VALUES = values();
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
package com.github.steveice10.mc.protocol.data.game.level.block.value;
|
||||
|
||||
public class NoteBlockValue implements BlockValue {
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.github.steveice10.mc.protocol.data.game.level.block.value;
|
||||
|
||||
public enum NoteBlockValueType implements BlockValueType {
|
||||
PLAY_NOTE;
|
||||
|
||||
private static final NoteBlockValueType[] VALUES = values();
|
||||
|
||||
public static NoteBlockValueType from(int id) {
|
||||
return VALUES[id];
|
||||
}
|
||||
}
|
|
@ -30,6 +30,9 @@ public enum ParticleType {
|
|||
FIREWORK,
|
||||
FISHING,
|
||||
FLAME,
|
||||
DRIPPING_CHERRY_LEAVES,
|
||||
FALLING_CHERRY_LEAVES,
|
||||
LANDING_CHERRY_LEAVES,
|
||||
SCULK_SOUL,
|
||||
SCULK_CHARGE,
|
||||
SCULK_CHARGE_POP,
|
||||
|
|
|
@ -173,6 +173,8 @@ public enum BuiltinSound implements Sound {
|
|||
ITEM_BOTTLE_FILL("item.bottle.fill"),
|
||||
ITEM_BOTTLE_FILL_DRAGONBREATH("item.bottle.fill_dragonbreath"),
|
||||
BLOCK_BREWING_STAND_BREW("block.brewing_stand.brew"),
|
||||
ITEM_BRUSH_BRUSHING("item.brush.brushing"),
|
||||
ITEM_BRUSH_BRUSH_SAND_COMPLETED("item.brush.brush_sand_completed"),
|
||||
BLOCK_BUBBLE_COLUMN_BUBBLE_POP("block.bubble_column.bubble_pop"),
|
||||
BLOCK_BUBBLE_COLUMN_UPWARDS_AMBIENT("block.bubble_column.upwards_ambient"),
|
||||
BLOCK_BUBBLE_COLUMN_UPWARDS_INSIDE("block.bubble_column.upwards_inside"),
|
||||
|
@ -238,6 +240,36 @@ public enum BuiltinSound implements Sound {
|
|||
BLOCK_CHAIN_HIT("block.chain.hit"),
|
||||
BLOCK_CHAIN_PLACE("block.chain.place"),
|
||||
BLOCK_CHAIN_STEP("block.chain.step"),
|
||||
BLOCK_CHERRY_WOOD_BREAK("block.cherry_wood.break"),
|
||||
BLOCK_CHERRY_WOOD_FALL("block.cherry_wood.fall"),
|
||||
BLOCK_CHERRY_WOOD_HIT("block.cherry_wood.hit"),
|
||||
BLOCK_CHERRY_WOOD_PLACE("block.cherry_wood.place"),
|
||||
BLOCK_CHERRY_WOOD_STEP("block.cherry_wood.step"),
|
||||
BLOCK_CHERRY_SAPLING_BREAK("block.cherry_sapling.break"),
|
||||
BLOCK_CHERRY_SAPLING_FALL("block.cherry_sapling.fall"),
|
||||
BLOCK_CHERRY_SAPLING_HIT("block.cherry_sapling.hit"),
|
||||
BLOCK_CHERRY_SAPLING_PLACE("block.cherry_sapling.place"),
|
||||
BLOCK_CHERRY_SAPLING_STEP("block.cherry_sapling.step"),
|
||||
BLOCK_CHERRY_LEAVES_BREAK("block.cherry_leaves.break"),
|
||||
BLOCK_CHERRY_LEAVES_FALL("block.cherry_leaves.fall"),
|
||||
BLOCK_CHERRY_LEAVES_HIT("block.cherry_leaves.hit"),
|
||||
BLOCK_CHERRY_LEAVES_PLACE("block.cherry_leaves.place"),
|
||||
BLOCK_CHERRY_LEAVES_STEP("block.cherry_leaves.step"),
|
||||
BLOCK_CHERRY_WOOD_HANGING_SIGN_STEP("block.cherry_wood_hanging_sign.step"),
|
||||
BLOCK_CHERRY_WOOD_HANGING_SIGN_BREAK("block.cherry_wood_hanging_sign.break"),
|
||||
BLOCK_CHERRY_WOOD_HANGING_SIGN_FALL("block.cherry_wood_hanging_sign.fall"),
|
||||
BLOCK_CHERRY_WOOD_HANGING_SIGN_HIT("block.cherry_wood_hanging_sign.hit"),
|
||||
BLOCK_CHERRY_WOOD_HANGING_SIGN_PLACE("block.cherry_wood_hanging_sign.place"),
|
||||
BLOCK_CHERRY_WOOD_DOOR_CLOSE("block.cherry_wood_door.close"),
|
||||
BLOCK_CHERRY_WOOD_DOOR_OPEN("block.cherry_wood_door.open"),
|
||||
BLOCK_CHERRY_WOOD_TRAPDOOR_CLOSE("block.cherry_wood_trapdoor.close"),
|
||||
BLOCK_CHERRY_WOOD_TRAPDOOR_OPEN("block.cherry_wood_trapdoor.open"),
|
||||
BLOCK_CHERRY_WOOD_BUTTON_CLICK_OFF("block.cherry_wood_button.click_off"),
|
||||
BLOCK_CHERRY_WOOD_BUTTON_CLICK_ON("block.cherry_wood_button.click_on"),
|
||||
BLOCK_CHERRY_WOOD_PRESSURE_PLATE_CLICK_OFF("block.cherry_wood_pressure_plate.click_off"),
|
||||
BLOCK_CHERRY_WOOD_PRESSURE_PLATE_CLICK_ON("block.cherry_wood_pressure_plate.click_on"),
|
||||
BLOCK_CHERRY_WOOD_FENCE_GATE_CLOSE("block.cherry_wood_fence_gate.close"),
|
||||
BLOCK_CHERRY_WOOD_FENCE_GATE_OPEN("block.cherry_wood_fence_gate.open"),
|
||||
BLOCK_CHEST_CLOSE("block.chest.close"),
|
||||
BLOCK_CHEST_LOCKED("block.chest.locked"),
|
||||
BLOCK_CHEST_OPEN("block.chest.open"),
|
||||
|
@ -300,6 +332,12 @@ public enum BuiltinSound implements Sound {
|
|||
ITEM_CROSSBOW_QUICK_CHARGE_2("item.crossbow.quick_charge_2"),
|
||||
ITEM_CROSSBOW_QUICK_CHARGE_3("item.crossbow.quick_charge_3"),
|
||||
ITEM_CROSSBOW_SHOOT("item.crossbow.shoot"),
|
||||
BLOCK_DECORATED_POT_BREAK("block.decorated_pot.break"),
|
||||
BLOCK_DECORATED_POT_FALL("block.decorated_pot.fall"),
|
||||
BLOCK_DECORATED_POT_HIT("block.decorated_pot.hit"),
|
||||
BLOCK_DECORATED_POT_STEP("block.decorated_pot.step"),
|
||||
BLOCK_DECORATED_POT_PLACE("block.decorated_pot.place"),
|
||||
BLOCK_DECORATED_POT_SHATTER("block.decorated_pot.shatter"),
|
||||
BLOCK_DEEPSLATE_BRICKS_BREAK("block.deepslate_bricks.break"),
|
||||
BLOCK_DEEPSLATE_BRICKS_FALL("block.deepslate_bricks.fall"),
|
||||
BLOCK_DEEPSLATE_BRICKS_HIT("block.deepslate_bricks.hit"),
|
||||
|
@ -442,6 +480,11 @@ public enum BuiltinSound implements Sound {
|
|||
ENTITY_FOX_SNIFF("entity.fox.sniff"),
|
||||
ENTITY_FOX_SPIT("entity.fox.spit"),
|
||||
ENTITY_FOX_TELEPORT("entity.fox.teleport"),
|
||||
BLOCK_SUSPICIOUS_SAND_BREAK("block.suspicious_sand.break"),
|
||||
BLOCK_SUSPICIOUS_SAND_STEP("block.suspicious_sand.step"),
|
||||
BLOCK_SUSPICIOUS_SAND_PLACE("block.suspicious_sand.place"),
|
||||
BLOCK_SUSPICIOUS_SAND_HIT("block.suspicious_sand.hit"),
|
||||
BLOCK_SUSPICIOUS_SAND_FALL("block.suspicious_sand.fall"),
|
||||
BLOCK_FROGLIGHT_BREAK("block.froglight.break"),
|
||||
BLOCK_FROGLIGHT_FALL("block.froglight.fall"),
|
||||
BLOCK_FROGLIGHT_HIT("block.froglight.hit"),
|
||||
|
@ -708,6 +751,11 @@ public enum BuiltinSound implements Sound {
|
|||
BLOCK_MOSS_CARPET_HIT("block.moss_carpet.hit"),
|
||||
BLOCK_MOSS_CARPET_PLACE("block.moss_carpet.place"),
|
||||
BLOCK_MOSS_CARPET_STEP("block.moss_carpet.step"),
|
||||
BLOCK_PINK_PETALS_BREAK("block.pink_petals.break"),
|
||||
BLOCK_PINK_PETALS_FALL("block.pink_petals.fall"),
|
||||
BLOCK_PINK_PETALS_HIT("block.pink_petals.hit"),
|
||||
BLOCK_PINK_PETALS_PLACE("block.pink_petals.place"),
|
||||
BLOCK_PINK_PETALS_STEP("block.pink_petals.step"),
|
||||
BLOCK_MOSS_BREAK("block.moss.break"),
|
||||
BLOCK_MOSS_FALL("block.moss.fall"),
|
||||
BLOCK_MOSS_HIT("block.moss.hit"),
|
||||
|
@ -766,6 +814,7 @@ public enum BuiltinSound implements Sound {
|
|||
MUSIC_OVERWORLD_JUNGLE_AND_FOREST("music.overworld.jungle_and_forest"),
|
||||
MUSIC_OVERWORLD_OLD_GROWTH_TAIGA("music.overworld.old_growth_taiga"),
|
||||
MUSIC_OVERWORLD_MEADOW("music.overworld.meadow"),
|
||||
MUSIC_OVERWORLD_CHERRY_GROVE("music.overworld.cherry_grove"),
|
||||
MUSIC_NETHER_NETHER_WASTES("music.nether.nether_wastes"),
|
||||
MUSIC_OVERWORLD_FROZEN_PEAKS("music.overworld.frozen_peaks"),
|
||||
MUSIC_OVERWORLD_SNOWY_SLOPES("music.overworld.snowy_slopes"),
|
||||
|
@ -795,6 +844,7 @@ public enum BuiltinSound implements Sound {
|
|||
BLOCK_NETHER_WOOD_PRESSURE_PLATE_CLICK_ON("block.nether_wood_pressure_plate.click_on"),
|
||||
BLOCK_NETHER_WOOD_FENCE_GATE_CLOSE("block.nether_wood_fence_gate.close"),
|
||||
BLOCK_NETHER_WOOD_FENCE_GATE_OPEN("block.nether_wood_fence_gate.open"),
|
||||
INTENTIONALLY_EMPTY("intentionally_empty"),
|
||||
BLOCK_PACKED_MUD_BREAK("block.packed_mud.break"),
|
||||
BLOCK_PACKED_MUD_FALL("block.packed_mud.fall"),
|
||||
BLOCK_PACKED_MUD_HIT("block.packed_mud.hit"),
|
||||
|
@ -1167,6 +1217,18 @@ public enum BuiltinSound implements Sound {
|
|||
ENTITY_SLIME_SQUISH_SMALL("entity.slime.squish_small"),
|
||||
BLOCK_SMITHING_TABLE_USE("block.smithing_table.use"),
|
||||
BLOCK_SMOKER_SMOKE("block.smoker.smoke"),
|
||||
ENTITY_SNIFFER_STEP("entity.sniffer.step"),
|
||||
ENTITY_SNIFFER_EAT("entity.sniffer.eat"),
|
||||
ENTITY_SNIFFER_IDLE("entity.sniffer.idle"),
|
||||
ENTITY_SNIFFER_HURT("entity.sniffer.hurt"),
|
||||
ENTITY_SNIFFER_DEATH("entity.sniffer.death"),
|
||||
ENTITY_SNIFFER_DROP_SEED("entity.sniffer.drop_seed"),
|
||||
ENTITY_SNIFFER_SCENTING("entity.sniffer.scenting"),
|
||||
ENTITY_SNIFFER_SNIFFING("entity.sniffer.sniffing"),
|
||||
ENTITY_SNIFFER_SEARCHING("entity.sniffer.searching"),
|
||||
ENTITY_SNIFFER_DIGGING("entity.sniffer.digging"),
|
||||
ENTITY_SNIFFER_DIGGING_STOP("entity.sniffer.digging_stop"),
|
||||
ENTITY_SNIFFER_HAPPY("entity.sniffer.happy"),
|
||||
ENTITY_SNOWBALL_THROW("entity.snowball.throw"),
|
||||
BLOCK_SNOW_BREAK("block.snow.break"),
|
||||
BLOCK_SNOW_FALL("block.snow.fall"),
|
||||
|
@ -1356,14 +1418,14 @@ public enum BuiltinSound implements Sound {
|
|||
BLOCK_WOODEN_DOOR_OPEN("block.wooden_door.open"),
|
||||
BLOCK_WOODEN_TRAPDOOR_CLOSE("block.wooden_trapdoor.close"),
|
||||
BLOCK_WOODEN_TRAPDOOR_OPEN("block.wooden_trapdoor.open"),
|
||||
BLOCK_WOOD_BREAK("block.wood.break"),
|
||||
BLOCK_WOODEN_BUTTON_CLICK_OFF("block.wooden_button.click_off"),
|
||||
BLOCK_WOODEN_BUTTON_CLICK_ON("block.wooden_button.click_on"),
|
||||
BLOCK_WOODEN_PRESSURE_PLATE_CLICK_OFF("block.wooden_pressure_plate.click_off"),
|
||||
BLOCK_WOODEN_PRESSURE_PLATE_CLICK_ON("block.wooden_pressure_plate.click_on"),
|
||||
BLOCK_WOOD_BREAK("block.wood.break"),
|
||||
BLOCK_WOOD_FALL("block.wood.fall"),
|
||||
BLOCK_WOOD_HIT("block.wood.hit"),
|
||||
BLOCK_WOOD_PLACE("block.wood.place"),
|
||||
BLOCK_WOODEN_PRESSURE_PLATE_CLICK_OFF("block.wooden_pressure_plate.click_off"),
|
||||
BLOCK_WOODEN_PRESSURE_PLATE_CLICK_ON("block.wooden_pressure_plate.click_on"),
|
||||
BLOCK_WOOD_STEP("block.wood.step"),
|
||||
BLOCK_WOOL_BREAK("block.wool.break"),
|
||||
BLOCK_WOOL_FALL("block.wool.fall"),
|
||||
|
|
|
@ -27,7 +27,10 @@ public enum RecipeType {
|
|||
SMOKING,
|
||||
CAMPFIRE_COOKING,
|
||||
STONECUTTING,
|
||||
SMITHING;
|
||||
SMITHING,
|
||||
SMITHING_TRANSFORM,
|
||||
SMITHING_TRIM,
|
||||
CRAFTING_DECORATED_POT;
|
||||
|
||||
private final String resourceLocation;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import lombok.NonNull;
|
|||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class SmithingRecipeData implements RecipeData {
|
||||
public class LegacyUpgradeRecipeData implements RecipeData {
|
||||
private final @NonNull Ingredient base;
|
||||
private final @NonNull Ingredient addition;
|
||||
private final ItemStack result;
|
|
@ -0,0 +1,16 @@
|
|||
package com.github.steveice10.mc.protocol.data.game.recipe.data;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class SmithingTransformRecipeData implements RecipeData {
|
||||
private final @NonNull Ingredient template;
|
||||
private final @NonNull Ingredient base;
|
||||
private final @NonNull Ingredient addition;
|
||||
private final ItemStack result;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.github.steveice10.mc.protocol.data.game.recipe.data;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class SmithingTrimRecipeData implements RecipeData {
|
||||
private final @NonNull Ingredient template;
|
||||
private final @NonNull Ingredient base;
|
||||
private final @NonNull Ingredient addition;
|
||||
}
|
|
@ -7,11 +7,13 @@ import lombok.Data;
|
|||
import lombok.NonNull;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Setter(AccessLevel.NONE)
|
||||
@AllArgsConstructor
|
||||
public class PlayerInfo {
|
||||
private int maxPlayers;
|
||||
private int onlinePlayers;
|
||||
private @NonNull GameProfile[] players;
|
||||
private @NonNull List<GameProfile> players;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package com.github.steveice10.mc.protocol.packet.ingame.clientbound;
|
||||
|
||||
import com.github.steveice10.mc.protocol.codec.MinecraftCodecHelper;
|
||||
import com.github.steveice10.mc.protocol.codec.MinecraftPacket;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class ClientboundBundlePacket implements MinecraftPacket {
|
||||
private final List<MinecraftPacket> packets;
|
||||
|
||||
@Override
|
||||
public void serialize(ByteBuf buf, MinecraftCodecHelper helper) throws IOException {
|
||||
}
|
||||
}
|
|
@ -130,6 +130,9 @@ public class ClientboundCommandsPacket implements MinecraftPacket {
|
|||
case SCORE_HOLDER:
|
||||
properties = new ScoreHolderProperties(in.readBoolean());
|
||||
break;
|
||||
case TIME:
|
||||
properties = new TimeProperties(in.readInt());
|
||||
break;
|
||||
case RESOURCE_OR_TAG:
|
||||
case RESOURCE_OR_TAG_KEY:
|
||||
case RESOURCE:
|
||||
|
@ -298,6 +301,9 @@ public class ClientboundCommandsPacket implements MinecraftPacket {
|
|||
case SCORE_HOLDER:
|
||||
out.writeBoolean(((ScoreHolderProperties) node.getProperties()).isAllowMultiple());
|
||||
break;
|
||||
case TIME:
|
||||
out.writeInt(((TimeProperties) node.getProperties()).getMin());
|
||||
break;
|
||||
case RESOURCE:
|
||||
case RESOURCE_OR_TAG:
|
||||
helper.writeString(out, ((ResourceProperties) node.getProperties()).getRegistryKey());
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package com.github.steveice10.mc.protocol.packet.ingame.clientbound;
|
||||
|
||||
import com.github.steveice10.mc.protocol.codec.MinecraftCodecHelper;
|
||||
import com.github.steveice10.mc.protocol.codec.MinecraftPacket;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class ClientboundDelimiterPacket implements MinecraftPacket {
|
||||
public ClientboundDelimiterPacket(ByteBuf in, MinecraftCodecHelper helper) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(ByteBuf out, MinecraftCodecHelper helper) {
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@ package com.github.steveice10.mc.protocol.packet.ingame.clientbound;
|
|||
|
||||
import com.github.steveice10.mc.protocol.codec.MinecraftCodecHelper;
|
||||
import com.github.steveice10.mc.protocol.codec.MinecraftPacket;
|
||||
import com.github.steveice10.mc.protocol.data.DefaultComponentSerializer;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
@ -16,38 +15,20 @@ import java.io.IOException;
|
|||
@With
|
||||
@AllArgsConstructor
|
||||
public class ClientboundServerDataPacket implements MinecraftPacket {
|
||||
private final @Nullable Component motd;
|
||||
private final @Nullable String iconBase64;
|
||||
private final Component motd;
|
||||
private final byte @Nullable[] iconBytes;
|
||||
private final boolean enforcesSecureChat;
|
||||
|
||||
public ClientboundServerDataPacket(ByteBuf in, MinecraftCodecHelper helper) throws IOException {
|
||||
if (in.readBoolean()) {
|
||||
this.motd = helper.readComponent(in);
|
||||
} else {
|
||||
this.motd = null;
|
||||
}
|
||||
|
||||
if (in.readBoolean()) {
|
||||
this.iconBase64 = helper.readString(in);
|
||||
} else {
|
||||
this.iconBase64 = null;
|
||||
}
|
||||
|
||||
this.motd = helper.readComponent(in);
|
||||
this.iconBytes = helper.readNullable(in, helper::readByteArray);
|
||||
this.enforcesSecureChat = in.readBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(ByteBuf out, MinecraftCodecHelper helper) throws IOException {
|
||||
out.writeBoolean(this.motd != null);
|
||||
if (this.motd != null) {
|
||||
helper.writeComponent(out, this.motd);
|
||||
}
|
||||
|
||||
out.writeBoolean(this.iconBase64 != null);
|
||||
if (this.iconBase64 != null) {
|
||||
helper.writeString(out, this.iconBase64);
|
||||
}
|
||||
|
||||
helper.writeComponent(out, this.motd);
|
||||
helper.writeNullable(out, this.iconBytes, helper::writeByteArray);
|
||||
out.writeBoolean(this.enforcesSecureChat);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,7 +85,24 @@ public class ClientboundUpdateRecipesPacket implements MinecraftPacket {
|
|||
Ingredient addition = helper.readRecipeIngredient(in);
|
||||
ItemStack result = helper.readItemStack(in);
|
||||
|
||||
data = new SmithingRecipeData(base, addition, result);
|
||||
data = new LegacyUpgradeRecipeData(base, addition, result);
|
||||
break;
|
||||
}
|
||||
case SMITHING_TRANSFORM: {
|
||||
Ingredient template = helper.readRecipeIngredient(in);
|
||||
Ingredient base = helper.readRecipeIngredient(in);
|
||||
Ingredient addition = helper.readRecipeIngredient(in);
|
||||
ItemStack result = helper.readItemStack(in);
|
||||
|
||||
data = new SmithingTransformRecipeData(template, base, addition, result);
|
||||
break;
|
||||
}
|
||||
case SMITHING_TRIM: {
|
||||
Ingredient template = helper.readRecipeIngredient(in);
|
||||
Ingredient base = helper.readRecipeIngredient(in);
|
||||
Ingredient addition = helper.readRecipeIngredient(in);
|
||||
|
||||
data = new SmithingTrimRecipeData(template, base, addition);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
@ -160,13 +177,30 @@ public class ClientboundUpdateRecipesPacket implements MinecraftPacket {
|
|||
break;
|
||||
}
|
||||
case SMITHING: {
|
||||
SmithingRecipeData data = (SmithingRecipeData) recipe.getData();
|
||||
LegacyUpgradeRecipeData data = (LegacyUpgradeRecipeData) recipe.getData();
|
||||
|
||||
helper.writeRecipeIngredient(out, data.getBase());
|
||||
helper.writeRecipeIngredient(out, data.getAddition());
|
||||
helper.writeItemStack(out, data.getResult());
|
||||
break;
|
||||
}
|
||||
case SMITHING_TRANSFORM: {
|
||||
SmithingTransformRecipeData data = (SmithingTransformRecipeData) recipe.getData();
|
||||
|
||||
helper.writeRecipeIngredient(out, data.getTemplate());
|
||||
helper.writeRecipeIngredient(out, data.getBase());
|
||||
helper.writeRecipeIngredient(out, data.getAddition());
|
||||
helper.writeItemStack(out, data.getResult());
|
||||
break;
|
||||
}
|
||||
case SMITHING_TRIM: {
|
||||
SmithingTrimRecipeData data = (SmithingTrimRecipeData) recipe.getData();
|
||||
|
||||
helper.writeRecipeIngredient(out, data.getTemplate());
|
||||
helper.writeRecipeIngredient(out, data.getBase());
|
||||
helper.writeRecipeIngredient(out, data.getAddition());
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
SimpleCraftingRecipeData data = (SimpleCraftingRecipeData) recipe.getData();
|
||||
|
||||
|
|
|
@ -26,6 +26,6 @@ public class ClientboundAnimatePacket implements MinecraftPacket {
|
|||
@Override
|
||||
public void serialize(ByteBuf out, MinecraftCodecHelper helper) throws IOException {
|
||||
helper.writeVarInt(out, this.entityId);
|
||||
out.writeByte(this.animation.ordinal());
|
||||
out.writeByte(this.animation.getId());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
package com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.codec.MinecraftCodecHelper;
|
||||
import com.github.steveice10.mc.protocol.codec.MinecraftPacket;
|
||||
import com.nukkitx.math.vector.Vector3d;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class ClientboundDamageEventPacket implements MinecraftPacket {
|
||||
private final int entityId;
|
||||
private final int sourceTypeId;
|
||||
private final int sourceCauseId;
|
||||
private final int sourceDirectId;
|
||||
private final @Nullable Vector3d sourcePosition;
|
||||
|
||||
public ClientboundDamageEventPacket(ByteBuf in, MinecraftCodecHelper helper) {
|
||||
this.entityId = helper.readVarInt(in);
|
||||
this.sourceTypeId = helper.readVarInt(in);
|
||||
this.sourceCauseId = helper.readVarInt(in) - 1;
|
||||
this.sourceDirectId = helper.readVarInt(in) - 1;
|
||||
this.sourcePosition = in.readBoolean() ? Vector3d.from(in.readDouble(), in.readDouble(), in.readDouble()) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(ByteBuf out, MinecraftCodecHelper helper) {
|
||||
helper.writeVarInt(out, this.entityId);
|
||||
helper.writeVarInt(out, this.sourceTypeId);
|
||||
helper.writeVarInt(out, this.sourceCauseId + 1);
|
||||
helper.writeVarInt(out, this.sourceDirectId + 1);
|
||||
|
||||
if (this.sourcePosition != null) {
|
||||
out.writeBoolean(true);
|
||||
out.writeDouble(this.sourcePosition.getX());
|
||||
out.writeDouble(this.sourcePosition.getY());
|
||||
out.writeDouble(this.sourcePosition.getZ());
|
||||
} else {
|
||||
out.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.codec.MinecraftCodecHelper;
|
||||
import com.github.steveice10.mc.protocol.codec.MinecraftPacket;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.With;
|
||||
|
||||
@Data
|
||||
@With
|
||||
@AllArgsConstructor
|
||||
public class ClientboundHurtAnimationPacket implements MinecraftPacket {
|
||||
private final int id;
|
||||
private final float yaw;
|
||||
|
||||
public ClientboundHurtAnimationPacket(ByteBuf in, MinecraftCodecHelper helper) {
|
||||
this.id = helper.readVarInt(in);
|
||||
this.yaw = in.readFloat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(ByteBuf out, MinecraftCodecHelper helper) {
|
||||
helper.writeVarInt(out, this.id);
|
||||
out.writeFloat(this.yaw);
|
||||
}
|
||||
}
|
|
@ -24,11 +24,10 @@ public class ClientboundPlayerPositionPacket implements MinecraftPacket {
|
|||
private final float yaw;
|
||||
private final float pitch;
|
||||
private final int teleportId;
|
||||
private final boolean dismountVehicle;
|
||||
private final @NonNull List<PositionElement> relative;
|
||||
|
||||
public ClientboundPlayerPositionPacket(double x, double y, double z, float yaw, float pitch, int teleportId, boolean dismountVehicle, PositionElement... relative) {
|
||||
this(x, y, z, yaw, pitch, teleportId, dismountVehicle, Arrays.asList(relative != null ? relative : new PositionElement[0]));
|
||||
public ClientboundPlayerPositionPacket(double x, double y, double z, float yaw, float pitch, int teleportId, PositionElement... relative) {
|
||||
this(x, y, z, yaw, pitch, teleportId, Arrays.asList(relative != null ? relative : new PositionElement[0]));
|
||||
}
|
||||
|
||||
public ClientboundPlayerPositionPacket(ByteBuf in, MinecraftCodecHelper helper) throws IOException {
|
||||
|
@ -48,7 +47,6 @@ public class ClientboundPlayerPositionPacket implements MinecraftPacket {
|
|||
}
|
||||
|
||||
this.teleportId = helper.readVarInt(in);
|
||||
this.dismountVehicle = in.readBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -67,6 +65,5 @@ public class ClientboundPlayerPositionPacket implements MinecraftPacket {
|
|||
out.writeByte(flags);
|
||||
|
||||
helper.writeVarInt(out, this.teleportId);
|
||||
out.writeBoolean(this.dismountVehicle);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,10 @@ public class ClientboundBlockEventPacket implements MinecraftPacket {
|
|||
this.blockId = helper.readVarInt(in);
|
||||
|
||||
// TODO: Handle this in MinecraftCodecHelper
|
||||
if (this.blockId == STICKY_PISTON || this.blockId == PISTON) {
|
||||
if (this.blockId == NOTE_BLOCK) {
|
||||
this.type = NoteBlockValueType.from(type);
|
||||
this.value = new NoteBlockValue();
|
||||
} else if (this.blockId == STICKY_PISTON || this.blockId == PISTON) {
|
||||
this.type = PistonValueType.from(type);
|
||||
this.value = new PistonValue(Direction.from(Math.abs((value & 7) % 6)));
|
||||
} else if (this.blockId == MOB_SPAWNER) {
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package com.github.steveice10.mc.protocol.packet.ingame.clientbound.level;
|
||||
|
||||
import com.github.steveice10.mc.protocol.codec.MinecraftCodecHelper;
|
||||
import com.github.steveice10.mc.protocol.codec.MinecraftPacket;
|
||||
import com.github.steveice10.mc.protocol.data.game.chunk.ChunkBiomeData;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class ClientboundChunksBiomesPacket implements MinecraftPacket {
|
||||
private final List<ChunkBiomeData> chunkBiomeData;
|
||||
|
||||
public ClientboundChunksBiomesPacket(ByteBuf in, MinecraftCodecHelper helper) {
|
||||
this.chunkBiomeData = new ArrayList<>();
|
||||
|
||||
int length = helper.readVarInt(in);
|
||||
for (int i = 0; i < length; i++) {
|
||||
long raw = in.readLong();
|
||||
this.chunkBiomeData.add(new ChunkBiomeData((int)raw, (int)(raw >> 32), helper.readByteArray(in)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(ByteBuf out, MinecraftCodecHelper helper) {
|
||||
helper.writeVarInt(out, this.chunkBiomeData.size());
|
||||
for (ChunkBiomeData entry : this.chunkBiomeData) {
|
||||
long raw = (long)entry.getX() & 0xFFFFFFFFL | ((long)entry.getZ() & 0xFFFFFFFFL) << 32;
|
||||
out.writeLong(raw);
|
||||
helper.writeByteArray(out, entry.getBuffer());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -62,7 +62,7 @@ public class ClientboundSectionBlocksUpdatePacket implements MinecraftPacket {
|
|||
helper.writeVarInt(out, this.entries.length);
|
||||
for (BlockChangeEntry entry : this.entries) {
|
||||
short position = (short) ((entry.getPosition().getX() - (this.chunkX << 4)) << 8 | (entry.getPosition().getZ() - (this.chunkZ << 4)) << 4 | (entry.getPosition().getY() - (this.chunkY << 4)));
|
||||
helper.writeVarLong(out, (long) entry.getBlock() << 12 | position);
|
||||
helper.writeVarLong(out, (long) entry.getBlock() << 12 | (long) position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package com.github.steveice10.mc.protocol.packet.ingame.clientbound.scoreboard;
|
|||
|
||||
import com.github.steveice10.mc.protocol.codec.MinecraftCodecHelper;
|
||||
import com.github.steveice10.mc.protocol.codec.MinecraftPacket;
|
||||
import com.github.steveice10.mc.protocol.data.DefaultComponentSerializer;
|
||||
import com.github.steveice10.mc.protocol.data.game.scoreboard.CollisionRule;
|
||||
import com.github.steveice10.mc.protocol.data.game.scoreboard.NameTagVisibility;
|
||||
import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamAction;
|
||||
|
@ -11,6 +10,7 @@ import io.netty.buffer.ByteBuf;
|
|||
import lombok.*;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
@ -26,8 +26,8 @@ public class ClientboundSetPlayerTeamPacket implements MinecraftPacket {
|
|||
private final Component suffix;
|
||||
private final boolean friendlyFire;
|
||||
private final boolean seeFriendlyInvisibles;
|
||||
private final NameTagVisibility nameTagVisibility;
|
||||
private final CollisionRule collisionRule;
|
||||
private final @Nullable NameTagVisibility nameTagVisibility;
|
||||
private final @Nullable CollisionRule collisionRule;
|
||||
private final TeamColor color;
|
||||
|
||||
private final String[] players;
|
||||
|
|
|
@ -21,6 +21,8 @@ import net.kyori.adventure.text.Component;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@With
|
||||
|
@ -30,24 +32,23 @@ public class ClientboundStatusResponsePacket implements MinecraftPacket {
|
|||
|
||||
public ClientboundStatusResponsePacket(ByteBuf in, MinecraftCodecHelper helper) throws IOException {
|
||||
JsonObject obj = new Gson().fromJson(helper.readString(in), JsonObject.class);
|
||||
JsonObject ver = obj.get("version").getAsJsonObject();
|
||||
VersionInfo version = new VersionInfo(ver.get("name").getAsString(), ver.get("protocol").getAsInt());
|
||||
JsonElement desc = obj.get("description");
|
||||
Component description = DefaultComponentSerializer.get().serializer().fromJson(desc, Component.class);
|
||||
JsonObject plrs = obj.get("players").getAsJsonObject();
|
||||
GameProfile[] profiles = new GameProfile[0];
|
||||
List<GameProfile> profiles = new ArrayList<>();
|
||||
if (plrs.has("sample")) {
|
||||
JsonArray prof = plrs.get("sample").getAsJsonArray();
|
||||
if (prof.size() > 0) {
|
||||
profiles = new GameProfile[prof.size()];
|
||||
for (int index = 0; index < prof.size(); index++) {
|
||||
JsonObject o = prof.get(index).getAsJsonObject();
|
||||
profiles[index] = new GameProfile(o.get("id").getAsString(), o.get("name").getAsString());
|
||||
profiles.add(new GameProfile(o.get("id").getAsString(), o.get("name").getAsString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PlayerInfo players = new PlayerInfo(plrs.get("max").getAsInt(), plrs.get("online").getAsInt(), profiles);
|
||||
JsonElement desc = obj.get("description");
|
||||
Component description = DefaultComponentSerializer.get().serializer().fromJson(desc, Component.class);
|
||||
JsonObject ver = obj.get("version").getAsJsonObject();
|
||||
VersionInfo version = new VersionInfo(ver.get("name").getAsString(), ver.get("protocol").getAsInt());
|
||||
byte[] icon = null;
|
||||
if (obj.has("favicon")) {
|
||||
icon = this.stringToIcon(obj.get("favicon").getAsString());
|
||||
|
@ -66,7 +67,7 @@ public class ClientboundStatusResponsePacket implements MinecraftPacket {
|
|||
JsonObject plrs = new JsonObject();
|
||||
plrs.addProperty("max", this.info.getPlayerInfo().getMaxPlayers());
|
||||
plrs.addProperty("online", this.info.getPlayerInfo().getOnlinePlayers());
|
||||
if (this.info.getPlayerInfo().getPlayers().length > 0) {
|
||||
if (this.info.getPlayerInfo().getPlayers().size() > 0) {
|
||||
JsonArray array = new JsonArray();
|
||||
for (GameProfile profile : this.info.getPlayerInfo().getPlayers()) {
|
||||
JsonObject o = new JsonObject();
|
||||
|
@ -78,9 +79,9 @@ public class ClientboundStatusResponsePacket implements MinecraftPacket {
|
|||
plrs.add("sample", array);
|
||||
}
|
||||
|
||||
obj.add("version", ver);
|
||||
obj.add("players", plrs);
|
||||
obj.add("description", new Gson().fromJson(DefaultComponentSerializer.get().serialize(this.info.getDescription()), JsonElement.class));
|
||||
obj.add("players", plrs);
|
||||
obj.add("version", ver);
|
||||
if (this.info.getIconPng() != null) {
|
||||
obj.addProperty("favicon", this.iconToString(this.info.getIconPng()));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
package com.github.steveice10.packetlib;
|
||||
|
||||
import com.github.steveice10.packetlib.event.server.*;
|
||||
import com.github.steveice10.packetlib.packet.PacketProtocol;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public abstract class AbstractServer implements Server {
|
||||
private final String host;
|
||||
private final int port;
|
||||
private final Supplier<? extends PacketProtocol> protocolSupplier;
|
||||
|
||||
private final List<Session> sessions = new ArrayList<>();
|
||||
|
||||
private final Map<String, Object> flags = new HashMap<>();
|
||||
private final List<ServerListener> listeners = new ArrayList<>();
|
||||
|
||||
public AbstractServer(String host, int port, Supplier<? extends PacketProtocol> protocolSupplier) {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.protocolSupplier = protocolSupplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHost() {
|
||||
return this.host;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<? extends PacketProtocol> getPacketProtocol() {
|
||||
return this.protocolSupplier;
|
||||
}
|
||||
|
||||
protected PacketProtocol createPacketProtocol() {
|
||||
return this.protocolSupplier.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getGlobalFlags() {
|
||||
return Collections.unmodifiableMap(this.flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGlobalFlag(String key) {
|
||||
return this.flags.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getGlobalFlag(String key) {
|
||||
return this.getGlobalFlag(key, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> T getGlobalFlag(String key, T def) {
|
||||
Object value = this.flags.get(key);
|
||||
if(value == null) {
|
||||
return def;
|
||||
}
|
||||
|
||||
try {
|
||||
return (T) value;
|
||||
} catch(ClassCastException e) {
|
||||
throw new IllegalStateException("Tried to get flag \"" + key + "\" as the wrong type. Actual type: " + value.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGlobalFlag(String key, Object value) {
|
||||
this.flags.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ServerListener> getListeners() {
|
||||
return Collections.unmodifiableList(this.listeners);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(ServerListener listener) {
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(ServerListener listener) {
|
||||
this.listeners.remove(listener);
|
||||
}
|
||||
|
||||
protected void callEvent(ServerEvent event) {
|
||||
for(ServerListener listener : this.listeners) {
|
||||
event.call(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Session> getSessions() {
|
||||
return new ArrayList<>(this.sessions);
|
||||
}
|
||||
|
||||
public void addSession(Session session) {
|
||||
this.sessions.add(session);
|
||||
this.callEvent(new SessionAddedEvent(this, session));
|
||||
}
|
||||
|
||||
public void removeSession(Session session) {
|
||||
this.sessions.remove(session);
|
||||
if(session.isConnected()) {
|
||||
session.disconnect("Connection closed.");
|
||||
}
|
||||
|
||||
this.callEvent(new SessionRemovedEvent(this, session));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractServer bind() {
|
||||
return this.bind(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractServer bind(boolean wait) {
|
||||
return this.bind(wait, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractServer bind(boolean wait, Runnable callback) {
|
||||
this.bindImpl(wait, () -> {
|
||||
callEvent(new ServerBoundEvent(AbstractServer.this));
|
||||
if(callback != null) {
|
||||
callback.run();
|
||||
}
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
protected abstract void bindImpl(boolean wait, Runnable callback);
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.close(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(boolean wait) {
|
||||
this.close(wait, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(boolean wait, Runnable callback) {
|
||||
this.callEvent(new ServerClosingEvent(this));
|
||||
for(Session session : this.getSessions()) {
|
||||
if(session.isConnected()) {
|
||||
session.disconnect("Server closed.");
|
||||
}
|
||||
}
|
||||
|
||||
this.closeImpl(wait, () -> {
|
||||
callEvent(new ServerClosedEvent(AbstractServer.this));
|
||||
if(callback != null) {
|
||||
callback.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected abstract void closeImpl(boolean wait, Runnable callback);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.github.steveice10.packetlib;
|
||||
|
||||
/**
|
||||
* Built-in PacketLib session flags.
|
||||
*/
|
||||
public class BuiltinFlags {
|
||||
/**
|
||||
* When set to true, enables printing internal debug messages.
|
||||
*/
|
||||
public static final String PRINT_DEBUG = "print-packetlib-debug";
|
||||
|
||||
public static final String ENABLE_CLIENT_PROXY_PROTOCOL = "enable-client-proxy-protocol";
|
||||
|
||||
public static final String CLIENT_PROXIED_ADDRESS = "client-proxied-address";
|
||||
|
||||
/**
|
||||
* When set to false, an SRV record resolve is not attempted.
|
||||
*/
|
||||
public static final String ATTEMPT_SRV_RESOLVE = "attempt-srv-resolve";
|
||||
|
||||
private BuiltinFlags() {
|
||||
}
|
||||
}
|
106
src/main/java/com/github/steveice10/packetlib/ProxyInfo.java
Normal file
106
src/main/java/com/github/steveice10/packetlib/ProxyInfo.java
Normal file
|
@ -0,0 +1,106 @@
|
|||
package com.github.steveice10.packetlib;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
|
||||
/**
|
||||
* Information describing a network proxy.
|
||||
*/
|
||||
public class ProxyInfo {
|
||||
private Type type;
|
||||
private SocketAddress address;
|
||||
private boolean authenticated;
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* Creates a new unauthenticated ProxyInfo instance.
|
||||
*
|
||||
* @param type Type of proxy.
|
||||
* @param address Network address of the proxy.
|
||||
*/
|
||||
public ProxyInfo(Type type, SocketAddress address) {
|
||||
this.type = type;
|
||||
this.address = address;
|
||||
this.authenticated = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new authenticated ProxyInfo instance.
|
||||
*
|
||||
* @param type Type of proxy.
|
||||
* @param address Network address of the proxy.
|
||||
* @param username Username to authenticate with.
|
||||
* @param password Password to authenticate with.
|
||||
*/
|
||||
public ProxyInfo(Type type, SocketAddress address, String username, String password) {
|
||||
this(type, address);
|
||||
this.authenticated = true;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the proxy's type.
|
||||
*
|
||||
* @return The proxy's type.
|
||||
*/
|
||||
public Type getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the proxy's network address.
|
||||
*
|
||||
* @return The proxy's network address.
|
||||
*/
|
||||
public SocketAddress getAddress() {
|
||||
return this.address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the proxy is authenticated with.
|
||||
*
|
||||
* @return Whether to authenticate with the proxy.
|
||||
*/
|
||||
public boolean isAuthenticated() {
|
||||
return this.authenticated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the proxy's authentication username.
|
||||
*
|
||||
* @return The username to authenticate with.
|
||||
*/
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the proxy's authentication password.
|
||||
*
|
||||
* @return The password to authenticate with.
|
||||
*/
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Supported proxy types.
|
||||
*/
|
||||
public enum Type {
|
||||
/**
|
||||
* HTTP proxy.
|
||||
*/
|
||||
HTTP,
|
||||
|
||||
/**
|
||||
* SOCKS4 proxy.
|
||||
*/
|
||||
SOCKS4,
|
||||
|
||||
/**
|
||||
* SOCKS5 proxy.
|
||||
*/
|
||||
SOCKS5;
|
||||
}
|
||||
}
|
156
src/main/java/com/github/steveice10/packetlib/Server.java
Normal file
156
src/main/java/com/github/steveice10/packetlib/Server.java
Normal file
|
@ -0,0 +1,156 @@
|
|||
package com.github.steveice10.packetlib;
|
||||
|
||||
import com.github.steveice10.packetlib.event.server.ServerListener;
|
||||
import com.github.steveice10.packetlib.packet.PacketProtocol;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Listens for new sessions to connect.
|
||||
*/
|
||||
public interface Server {
|
||||
/**
|
||||
* Gets the host the session is listening on.
|
||||
*
|
||||
* @return The listening host.
|
||||
*/
|
||||
String getHost();
|
||||
|
||||
/**
|
||||
* Gets the port the session is listening on.
|
||||
*
|
||||
* @return The listening port.
|
||||
*/
|
||||
int getPort();
|
||||
|
||||
/**
|
||||
* Gets the packet protocol of the server.
|
||||
*
|
||||
* @return The server's packet protocol.
|
||||
*/
|
||||
Supplier<? extends PacketProtocol> getPacketProtocol();
|
||||
|
||||
/**
|
||||
* Returns true if the listener is listening.
|
||||
*
|
||||
* @return True if the listener is listening.
|
||||
*/
|
||||
boolean isListening();
|
||||
|
||||
/**
|
||||
* Gets this server's set flags.
|
||||
*
|
||||
* @return This server's flags.
|
||||
*/
|
||||
Map<String, Object> getGlobalFlags();
|
||||
|
||||
/**
|
||||
* Checks whether this server has a flag set.
|
||||
*
|
||||
* @param key Key of the flag to check for.
|
||||
* @return Whether this server has a flag set.
|
||||
*/
|
||||
boolean hasGlobalFlag(String key);
|
||||
|
||||
/**
|
||||
* Gets the value of the given flag as an instance of the given type.
|
||||
*
|
||||
* @param <T> Type of the flag.
|
||||
* @param key Key of the flag.
|
||||
* @return Value of the flag.
|
||||
* @throws IllegalStateException If the flag's value isn't of the required type.
|
||||
*/
|
||||
<T> T getGlobalFlag(String key);
|
||||
|
||||
/**
|
||||
* Gets the value of the given flag as an instance of the given type.
|
||||
* If the flag is not set, the specified default value will be returned.
|
||||
*
|
||||
* @param <T> Type of the flag.
|
||||
* @param key Key of the flag.
|
||||
* @param def Default value of the flag.
|
||||
* @return Value of the flag.
|
||||
* @throws IllegalStateException If the flag's value isn't of the required type.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
<T> T getGlobalFlag(String key, T def);
|
||||
|
||||
/**
|
||||
* Sets the value of a flag. The flag will be used in sessions if a session does
|
||||
* not contain a value for the flag.
|
||||
*
|
||||
* @param key Key of the flag.
|
||||
* @param value Value to set the flag to.
|
||||
*/
|
||||
void setGlobalFlag(String key, Object value);
|
||||
|
||||
/**
|
||||
* Gets the listeners listening on this session.
|
||||
*
|
||||
* @return This server's listeners.
|
||||
*/
|
||||
List<ServerListener> getListeners();
|
||||
|
||||
/**
|
||||
* Adds a listener to this server.
|
||||
*
|
||||
* @param listener Listener to add.
|
||||
*/
|
||||
void addListener(ServerListener listener);
|
||||
|
||||
/**
|
||||
* Removes a listener from this server.
|
||||
*
|
||||
* @param listener Listener to remove.
|
||||
*/
|
||||
void removeListener(ServerListener listener);
|
||||
|
||||
/**
|
||||
* Gets all sessions belonging to this server.
|
||||
*
|
||||
* @return Sessions belonging to this server.
|
||||
*/
|
||||
List<Session> getSessions();
|
||||
|
||||
/**
|
||||
* Binds the listener to its host and port.
|
||||
*/
|
||||
AbstractServer bind();
|
||||
|
||||
/**
|
||||
* Binds the listener to its host and port.
|
||||
*
|
||||
* @param wait Whether to wait for the listener to finish binding.
|
||||
*/
|
||||
AbstractServer bind(boolean wait);
|
||||
|
||||
/**
|
||||
* Binds the listener to its host and port.
|
||||
*
|
||||
* @param wait Whether to wait for the listener to finish binding.
|
||||
* @param callback Callback to call when the listener has finished binding.
|
||||
*/
|
||||
AbstractServer bind(boolean wait, Runnable callback);
|
||||
|
||||
/**
|
||||
* Closes the listener.
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Closes the listener.
|
||||
*
|
||||
* @param wait Whether to wait for the listener to finish closing.
|
||||
*/
|
||||
void close(boolean wait);
|
||||
|
||||
/**
|
||||
* Closes the listener.
|
||||
*
|
||||
* @param wait Whether to wait for the listener to finish closing.
|
||||
* @param callback Callback to call when the listener has finished closing.
|
||||
*/
|
||||
void close(boolean wait, Runnable callback);
|
||||
}
|
275
src/main/java/com/github/steveice10/packetlib/Session.java
Normal file
275
src/main/java/com/github/steveice10/packetlib/Session.java
Normal file
|
@ -0,0 +1,275 @@
|
|||
package com.github.steveice10.packetlib;
|
||||
|
||||
import com.github.steveice10.packetlib.codec.PacketCodecHelper;
|
||||
import com.github.steveice10.packetlib.crypt.PacketEncryption;
|
||||
import com.github.steveice10.packetlib.event.session.SessionEvent;
|
||||
import com.github.steveice10.packetlib.event.session.SessionListener;
|
||||
import com.github.steveice10.packetlib.packet.Packet;
|
||||
import com.github.steveice10.packetlib.packet.PacketProtocol;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A network session.
|
||||
*/
|
||||
public interface Session {
|
||||
|
||||
/**
|
||||
* Connects this session to its host and port.
|
||||
*/
|
||||
public void connect();
|
||||
|
||||
/**
|
||||
* Connects this session to its host and port.
|
||||
*
|
||||
* @param wait Whether to wait for the connection to be established before returning.
|
||||
*/
|
||||
public void connect(boolean wait);
|
||||
|
||||
/**
|
||||
* Gets the host the session is connected to.
|
||||
*
|
||||
* @return The connected host.
|
||||
*/
|
||||
public String getHost();
|
||||
|
||||
/**
|
||||
* Gets the port the session is connected to.
|
||||
*
|
||||
* @return The connected port.
|
||||
*/
|
||||
public int getPort();
|
||||
|
||||
/**
|
||||
* Gets the local address of the session.
|
||||
*
|
||||
* @return The local address, or null if the session is not connected.
|
||||
*/
|
||||
public SocketAddress getLocalAddress();
|
||||
|
||||
/**
|
||||
* Gets the remote address of the session.
|
||||
*
|
||||
* @return The remote address, or null if the session is not connected.
|
||||
*/
|
||||
public SocketAddress getRemoteAddress();
|
||||
|
||||
/**
|
||||
* Gets the packet protocol of the session.
|
||||
*
|
||||
* @return The session's packet protocol.
|
||||
*/
|
||||
public PacketProtocol getPacketProtocol();
|
||||
|
||||
/**
|
||||
* Gets the session's {@link PacketCodecHelper}.
|
||||
*
|
||||
* @return The session's packet codec helper.
|
||||
*/
|
||||
PacketCodecHelper getCodecHelper();
|
||||
|
||||
/**
|
||||
* Gets this session's set flags. If this session belongs to a server, the server's
|
||||
* flags will be included in the results.
|
||||
*
|
||||
* @return This session's flags.
|
||||
*/
|
||||
public Map<String, Object> getFlags();
|
||||
|
||||
/**
|
||||
* Checks whether this session has a flag set. If this session belongs to a server,
|
||||
* the server's flags will also be checked.
|
||||
*
|
||||
* @param key Key of the flag to check for.
|
||||
* @return Whether this session has a flag set.
|
||||
*/
|
||||
public boolean hasFlag(String key);
|
||||
|
||||
/**
|
||||
* Gets the value of the given flag as an instance of the given type. If this
|
||||
* session belongs to a server, the server's flags will be checked for the flag
|
||||
* as well.
|
||||
*
|
||||
* @param <T> Type of the flag.
|
||||
* @param key Key of the flag.
|
||||
* @return Value of the flag.
|
||||
* @throws IllegalStateException If the flag's value isn't of the required type.
|
||||
*/
|
||||
public <T> T getFlag(String key);
|
||||
|
||||
/**
|
||||
* Gets the value of the given flag as an instance of the given type. If this
|
||||
* session belongs to a server, the server's flags will be checked for the flag
|
||||
* as well. If the flag is not set, the specified default value will be returned.
|
||||
*
|
||||
* @param <T> Type of the flag.
|
||||
* @param key Key of the flag.
|
||||
* @param def Default value of the flag.
|
||||
* @return Value of the flag.
|
||||
* @throws IllegalStateException If the flag's value isn't of the required type.
|
||||
*/
|
||||
public <T> T getFlag(String key, T def);
|
||||
|
||||
/**
|
||||
* Sets the value of a flag. This does not change a server's flags if this session
|
||||
* belongs to a server.
|
||||
*
|
||||
* @param key Key of the flag.
|
||||
* @param value Value to set the flag to.
|
||||
*/
|
||||
public void setFlag(String key, Object value);
|
||||
|
||||
/**
|
||||
* Gets the listeners listening on this session.
|
||||
*
|
||||
* @return This session's listeners.
|
||||
*/
|
||||
public List<SessionListener> getListeners();
|
||||
|
||||
/**
|
||||
* Adds a listener to this session.
|
||||
*
|
||||
* @param listener Listener to add.
|
||||
*/
|
||||
public void addListener(SessionListener listener);
|
||||
|
||||
/**
|
||||
* Removes a listener from this session.
|
||||
*
|
||||
* @param listener Listener to remove.
|
||||
*/
|
||||
public void removeListener(SessionListener listener);
|
||||
|
||||
/**
|
||||
* Calls an event on the listeners of this session.
|
||||
*
|
||||
* @param event Event to call.
|
||||
*/
|
||||
void callEvent(SessionEvent event);
|
||||
|
||||
/**
|
||||
* Notifies all listeners that a packet was just received.
|
||||
*
|
||||
* @param packet Packet to notify.
|
||||
*/
|
||||
void callPacketReceived(Packet packet);
|
||||
|
||||
/**
|
||||
* Notifies all listeners that a packet was just sent.
|
||||
*
|
||||
* @param packet Packet to notify.
|
||||
*/
|
||||
void callPacketSent(Packet packet);
|
||||
|
||||
/**
|
||||
* Gets the compression packet length threshold for this session (-1 = disabled).
|
||||
*
|
||||
* @return This session's compression threshold.
|
||||
*/
|
||||
int getCompressionThreshold();
|
||||
|
||||
/**
|
||||
* Sets the compression packet length threshold for this session (-1 = disabled).
|
||||
*
|
||||
* @param threshold The new compression threshold.
|
||||
* @param validateDecompression whether to validate that the decompression fits within size checks.
|
||||
*/
|
||||
void setCompressionThreshold(int threshold, boolean validateDecompression);
|
||||
|
||||
/**
|
||||
* Enables encryption for this session.
|
||||
*
|
||||
* @param encryption the encryption to encrypt with
|
||||
*/
|
||||
void enableEncryption(PacketEncryption encryption);
|
||||
|
||||
/**
|
||||
* Gets the connect timeout for this session in seconds.
|
||||
*
|
||||
* @return The session's connect timeout.
|
||||
*/
|
||||
public int getConnectTimeout();
|
||||
|
||||
/**
|
||||
* Sets the connect timeout for this session in seconds.
|
||||
*
|
||||
* @param timeout Connect timeout to set.
|
||||
*/
|
||||
public void setConnectTimeout(int timeout);
|
||||
|
||||
/**
|
||||
* Gets the read timeout for this session in seconds.
|
||||
*
|
||||
* @return The session's read timeout.
|
||||
*/
|
||||
public int getReadTimeout();
|
||||
|
||||
/**
|
||||
* Sets the read timeout for this session in seconds.
|
||||
*
|
||||
* @param timeout Read timeout to set.
|
||||
*/
|
||||
public void setReadTimeout(int timeout);
|
||||
|
||||
/**
|
||||
* Gets the write timeout for this session in seconds.
|
||||
*
|
||||
* @return The session's write timeout.
|
||||
*/
|
||||
public int getWriteTimeout();
|
||||
|
||||
/**
|
||||
* Sets the write timeout for this session in seconds.
|
||||
*
|
||||
* @param timeout Write timeout to set.
|
||||
*/
|
||||
public void setWriteTimeout(int timeout);
|
||||
|
||||
/**
|
||||
* Returns true if the session is connected.
|
||||
*
|
||||
* @return True if the session is connected.
|
||||
*/
|
||||
public boolean isConnected();
|
||||
|
||||
/**
|
||||
* Sends a packet.
|
||||
*
|
||||
* @param packet Packet to send.
|
||||
*/
|
||||
public void send(Packet packet);
|
||||
|
||||
/**
|
||||
* Disconnects the session.
|
||||
*
|
||||
* @param reason Reason for disconnecting.
|
||||
*/
|
||||
void disconnect(@Nullable String reason);
|
||||
|
||||
/**
|
||||
* Disconnects the session.
|
||||
*
|
||||
* @param reason Reason for disconnecting.
|
||||
* @param cause Throwable responsible for disconnecting.
|
||||
*/
|
||||
void disconnect(@Nullable String reason, Throwable cause);
|
||||
|
||||
/**
|
||||
* Disconnects the session.
|
||||
*
|
||||
* @param reason Reason for disconnecting.
|
||||
*/
|
||||
void disconnect(@Nullable Component reason);
|
||||
|
||||
/**
|
||||
* Disconnects the session.
|
||||
*
|
||||
* @param reason Reason for disconnecting.
|
||||
* @param cause Throwable responsible for disconnecting.
|
||||
*/
|
||||
void disconnect(@Nullable Component reason, Throwable cause);
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
package com.github.steveice10.packetlib.codec;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class BasePacketCodecHelper implements PacketCodecHelper {
|
||||
|
||||
@Override
|
||||
public void writeVarInt(ByteBuf buf, int value) {
|
||||
this.writeVarLong(buf, value & 0xFFFFFFFFL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readVarInt(ByteBuf buf) {
|
||||
int value = 0;
|
||||
int size = 0;
|
||||
int b;
|
||||
while (((b = buf.readByte()) & 0x80) == 0x80) {
|
||||
value |= (b & 0x7F) << (size++ * 7);
|
||||
if (size > 5) {
|
||||
throw new IllegalArgumentException("VarInt too long (length must be <= 5)");
|
||||
}
|
||||
}
|
||||
|
||||
return value | ((b & 0x7F) << (size * 7));
|
||||
}
|
||||
|
||||
// Based off of Andrew Steinborn's blog post:
|
||||
// https://steinborn.me/posts/performance/how-fast-can-you-write-a-varint/
|
||||
@Override
|
||||
public void writeVarLong(ByteBuf buf, long value) {
|
||||
// Peel the one and two byte count cases explicitly as they are the most common VarInt sizes
|
||||
// that the server will write, to improve inlining.
|
||||
if ((value & ~0x7FL) == 0) {
|
||||
buf.writeByte((byte) value);
|
||||
} else if ((value & ~0x3FFFL) == 0) {
|
||||
int w = (int) ((value & 0x7FL | 0x80L) << 8 |
|
||||
(value >>> 7));
|
||||
buf.writeShort(w);
|
||||
} else {
|
||||
writeVarLongFull(buf, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeVarLongFull(ByteBuf buf, long value) {
|
||||
if ((value & ~0x7FL) == 0) {
|
||||
buf.writeByte((byte) value);
|
||||
} else if ((value & ~0x3FFFL) == 0) {
|
||||
int w = (int) ((value & 0x7FL | 0x80L) << 8 |
|
||||
(value >>> 7));
|
||||
buf.writeShort(w);
|
||||
} else if ((value & ~0x1FFFFFL) == 0) {
|
||||
int w = (int) ((value & 0x7FL | 0x80L) << 16 |
|
||||
((value >>> 7) & 0x7FL | 0x80L) << 8 |
|
||||
(value >>> 14));
|
||||
buf.writeMedium(w);
|
||||
} else if ((value & ~0xFFFFFFFL) == 0) {
|
||||
int w = (int) ((value & 0x7F | 0x80) << 24 |
|
||||
(((value >>> 7) & 0x7F | 0x80) << 16) |
|
||||
((value >>> 14) & 0x7F | 0x80) << 8 |
|
||||
(value >>> 21));
|
||||
buf.writeInt(w);
|
||||
} else if ((value & ~0x7FFFFFFFFL) == 0) {
|
||||
int w = (int) ((value & 0x7F | 0x80) << 24 |
|
||||
((value >>> 7) & 0x7F | 0x80) << 16 |
|
||||
((value >>> 14) & 0x7F | 0x80) << 8 |
|
||||
((value >>> 21) & 0x7F | 0x80));
|
||||
buf.writeInt(w);
|
||||
buf.writeByte((int) (value >>> 28));
|
||||
} else if ((value & ~0x3FFFFFFFFFFL) == 0) {
|
||||
int w = (int) ((value & 0x7F | 0x80) << 24 |
|
||||
((value >>> 7) & 0x7F | 0x80) << 16 |
|
||||
((value >>> 14) & 0x7F | 0x80) << 8 |
|
||||
((value >>> 21) & 0x7F | 0x80));
|
||||
int w2 = (int) (((value >>> 28) & 0x7FL | 0x80L) << 8 |
|
||||
(value >>> 35));
|
||||
buf.writeInt(w);
|
||||
buf.writeShort(w2);
|
||||
} else if ((value & ~0x1FFFFFFFFFFFFL) == 0) {
|
||||
int w = (int) ((value & 0x7F | 0x80) << 24 |
|
||||
((value >>> 7) & 0x7F | 0x80) << 16 |
|
||||
((value >>> 14) & 0x7F | 0x80) << 8 |
|
||||
((value >>> 21) & 0x7F | 0x80));
|
||||
int w2 = (int) ((((value >>> 28) & 0x7FL | 0x80L) << 16 |
|
||||
((value >>> 35) & 0x7FL | 0x80L) << 8) |
|
||||
(value >>> 42));
|
||||
buf.writeInt(w);
|
||||
buf.writeMedium(w2);
|
||||
} else if ((value & ~0xFFFFFFFFFFFFFFL) == 0) {
|
||||
long w = (value & 0x7F | 0x80) << 56 |
|
||||
((value >>> 7) & 0x7F | 0x80) << 48 |
|
||||
((value >>> 14) & 0x7F | 0x80) << 40 |
|
||||
((value >>> 21) & 0x7F | 0x80) << 32 |
|
||||
((value >>> 28) & 0x7FL | 0x80L) << 24 |
|
||||
((value >>> 35) & 0x7FL | 0x80L) << 16 |
|
||||
((value >>> 42) & 0x7FL | 0x80L) << 8 |
|
||||
(value >>> 49);
|
||||
buf.writeLong(w);
|
||||
} else if ((value & ~0x7FFFFFFFFFFFFFFFL) == 0) {
|
||||
long w = (value & 0x7F | 0x80) << 56 |
|
||||
((value >>> 7) & 0x7F | 0x80) << 48 |
|
||||
((value >>> 14) & 0x7F | 0x80) << 40 |
|
||||
((value >>> 21) & 0x7F | 0x80) << 32 |
|
||||
((value >>> 28) & 0x7FL | 0x80L) << 24 |
|
||||
((value >>> 35) & 0x7FL | 0x80L) << 16 |
|
||||
((value >>> 42) & 0x7FL | 0x80L) << 8 |
|
||||
(value >>> 49);
|
||||
buf.writeLong(w);
|
||||
buf.writeByte((byte) (value >>> 56));
|
||||
} else {
|
||||
long w = (value & 0x7F | 0x80) << 56 |
|
||||
((value >>> 7) & 0x7F | 0x80) << 48 |
|
||||
((value >>> 14) & 0x7F | 0x80) << 40 |
|
||||
((value >>> 21) & 0x7F | 0x80) << 32 |
|
||||
((value >>> 28) & 0x7FL | 0x80L) << 24 |
|
||||
((value >>> 35) & 0x7FL | 0x80L) << 16 |
|
||||
((value >>> 42) & 0x7FL | 0x80L) << 8 |
|
||||
(value >>> 49);
|
||||
int w2 = (int) (((value >>> 56) & 0x7FL | 0x80L) << 8 |
|
||||
(value >>> 63));
|
||||
buf.writeLong(w);
|
||||
buf.writeShort(w2);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readVarLong(ByteBuf buf) {
|
||||
int value = 0;
|
||||
int size = 0;
|
||||
int b;
|
||||
while (((b = buf.readByte()) & 0x80) == 0x80) {
|
||||
value |= (b & 0x7F) << (size++ * 7);
|
||||
if (size > 10) {
|
||||
throw new IllegalArgumentException("VarLong too long (length must be <= 10)");
|
||||
}
|
||||
}
|
||||
|
||||
return value | ((b & 0x7FL) << (size * 7));
|
||||
}
|
||||
|
||||
public String readString(ByteBuf buf) {
|
||||
return this.readString(buf, Short.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readString(ByteBuf buf, int maxLength) {
|
||||
int length = this.readVarInt(buf);
|
||||
if (length > maxLength * 3) {
|
||||
throw new IllegalArgumentException("String buffer is longer than maximum allowed length");
|
||||
}
|
||||
String string = (String) buf.readCharSequence(length, StandardCharsets.UTF_8);
|
||||
if (string.length() > maxLength) {
|
||||
throw new IllegalArgumentException("String is longer than maximum allowed length");
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeString(ByteBuf buf, String value) {
|
||||
this.writeVarInt(buf, ByteBufUtil.utf8Bytes(value));
|
||||
buf.writeCharSequence(value, StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.github.steveice10.packetlib.codec;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public interface PacketCodecHelper {
|
||||
|
||||
void writeVarInt(ByteBuf buf, int value);
|
||||
|
||||
int readVarInt(ByteBuf buf);
|
||||
|
||||
void writeVarLong(ByteBuf buf, long value);
|
||||
|
||||
long readVarLong(ByteBuf buf);
|
||||
|
||||
String readString(ByteBuf buf);
|
||||
|
||||
String readString(ByteBuf buf, int maxLength);
|
||||
|
||||
void writeString(ByteBuf buf, String value);
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.github.steveice10.packetlib.codec;
|
||||
|
||||
import com.github.steveice10.packetlib.packet.Packet;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Represents a definition of a packet with various
|
||||
* information about it, such as it's id, class and
|
||||
* factory for construction.
|
||||
*
|
||||
* @param <T> the packet type
|
||||
*/
|
||||
public class PacketDefinition<T extends Packet, H extends PacketCodecHelper> {
|
||||
private final int id;
|
||||
private final Class<T> packetClass;
|
||||
private final PacketSerializer<T, H> serializer;
|
||||
|
||||
public PacketDefinition(final int id, final Class<T> packetClass, final PacketSerializer<T, H> serializer) {
|
||||
this.id = id;
|
||||
this.packetClass = packetClass;
|
||||
this.serializer = serializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the packet.
|
||||
*
|
||||
* @return the id of the packet
|
||||
*/
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class of the packet.
|
||||
*
|
||||
* @return the class of the packet
|
||||
*/
|
||||
public Class<T> getPacketClass() {
|
||||
return this.packetClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link PacketSerializer} of the packet.
|
||||
*
|
||||
* @return the packet serializer of the packet
|
||||
*/
|
||||
public PacketSerializer<T, H> getSerializer() {
|
||||
return this.serializer;
|
||||
}
|
||||
|
||||
public T newInstance(ByteBuf buf, H helper) throws IOException {
|
||||
return this.serializer.deserialize(buf, helper, this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.github.steveice10.packetlib.codec;
|
||||
|
||||
import com.github.steveice10.packetlib.packet.Packet;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface PacketSerializer<T extends Packet, H extends PacketCodecHelper> {
|
||||
|
||||
void serialize(ByteBuf buf, H helper, T packet) throws IOException;
|
||||
|
||||
T deserialize(ByteBuf buf, H helper, PacketDefinition<T, H> definition) throws IOException;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package com.github.steveice10.packetlib.crypt;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.Key;
|
||||
|
||||
/**
|
||||
* An encryption implementation using "AES/CFB8/NoPadding" encryption.
|
||||
*/
|
||||
public class AESEncryption implements PacketEncryption {
|
||||
private Cipher inCipher;
|
||||
private Cipher outCipher;
|
||||
|
||||
/**
|
||||
* Creates a new AESEncryption instance.
|
||||
*
|
||||
* @param key Key to use when encrypting/decrypting data.
|
||||
* @throws GeneralSecurityException If a security error occurs.
|
||||
*/
|
||||
public AESEncryption(Key key) throws GeneralSecurityException {
|
||||
this.inCipher = Cipher.getInstance("AES/CFB8/NoPadding");
|
||||
this.inCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(key.getEncoded()));
|
||||
this.outCipher = Cipher.getInstance("AES/CFB8/NoPadding");
|
||||
this.outCipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(key.getEncoded()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDecryptOutputSize(int length) {
|
||||
return this.inCipher.getOutputSize(length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEncryptOutputSize(int length) {
|
||||
return this.outCipher.getOutputSize(length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decrypt(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset) throws Exception {
|
||||
return this.inCipher.update(input, inputOffset, inputLength, output, outputOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encrypt(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset) throws Exception {
|
||||
return this.outCipher.update(input, inputOffset, inputLength, output, outputOffset);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.github.steveice10.packetlib.crypt;
|
||||
|
||||
/**
|
||||
* An interface for encrypting packets.
|
||||
*/
|
||||
public interface PacketEncryption {
|
||||
/**
|
||||
* Gets the output size from decrypting.
|
||||
*
|
||||
* @param length Length of the data being decrypted.
|
||||
* @return The output size from decrypting.
|
||||
*/
|
||||
public int getDecryptOutputSize(int length);
|
||||
|
||||
/**
|
||||
* Gets the output size from encrypting.
|
||||
*
|
||||
* @param length Length of the data being encrypted.
|
||||
* @return The output size from encrypting.
|
||||
*/
|
||||
public int getEncryptOutputSize(int length);
|
||||
|
||||
/**
|
||||
* Decrypts the given data.
|
||||
*
|
||||
* @param input Input data to decrypt.
|
||||
* @param inputOffset Offset of the data to start decrypting at.
|
||||
* @param inputLength Length of the data to be decrypted.
|
||||
* @param output Array to output decrypted data to.
|
||||
* @param outputOffset Offset of the output array to start at.
|
||||
* @return The number of bytes stored in the output array.
|
||||
* @throws Exception If an error occurs.
|
||||
*/
|
||||
public int decrypt(byte input[], int inputOffset, int inputLength, byte output[], int outputOffset) throws Exception;
|
||||
|
||||
/**
|
||||
* Encrypts the given data.
|
||||
*
|
||||
* @param input Input data to encrypt.
|
||||
* @param inputOffset Offset of the data to start encrypting at.
|
||||
* @param inputLength Length of the data to be encrypted.
|
||||
* @param output Array to output encrypted data to.
|
||||
* @param outputOffset Offset of the output array to start at.
|
||||
* @return The number of bytes stored in the output array.
|
||||
* @throws Exception If an error occurs.
|
||||
*/
|
||||
public int encrypt(byte input[], int inputOffset, int inputLength, byte output[], int outputOffset) throws Exception;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.github.steveice10.packetlib.event.server;
|
||||
|
||||
/**
|
||||
* An adapter for picking server events to listen for.
|
||||
*/
|
||||
public class ServerAdapter implements ServerListener {
|
||||
@Override
|
||||
public void serverBound(ServerBoundEvent event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serverClosing(ServerClosingEvent event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serverClosed(ServerClosedEvent event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionAdded(SessionAddedEvent event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionRemoved(SessionRemovedEvent event) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.github.steveice10.packetlib.event.server;
|
||||
|
||||
import com.github.steveice10.packetlib.Server;
|
||||
|
||||
/**
|
||||
* Called when the server is bound to its host and port.
|
||||
*/
|
||||
public class ServerBoundEvent implements ServerEvent {
|
||||
private Server server;
|
||||
|
||||
/**
|
||||
* Creates a new ServerBoundEvent instance.
|
||||
*
|
||||
* @param server Server being bound.
|
||||
*/
|
||||
public ServerBoundEvent(Server server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server involved in this event.
|
||||
*
|
||||
* @return The event's server.
|
||||
*/
|
||||
public Server getServer() {
|
||||
return this.server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void call(ServerListener listener) {
|
||||
listener.serverBound(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.github.steveice10.packetlib.event.server;
|
||||
|
||||
import com.github.steveice10.packetlib.Server;
|
||||
|
||||
/**
|
||||
* Called when the server is closed.
|
||||
*/
|
||||
public class ServerClosedEvent implements ServerEvent {
|
||||
private Server server;
|
||||
|
||||
/**
|
||||
* Creates a new ServerClosedEvent instance.
|
||||
*
|
||||
* @param server Server being closed.
|
||||
*/
|
||||
public ServerClosedEvent(Server server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server involved in this event.
|
||||
*
|
||||
* @return The event's server.
|
||||
*/
|
||||
public Server getServer() {
|
||||
return this.server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void call(ServerListener listener) {
|
||||
listener.serverClosed(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.github.steveice10.packetlib.event.server;
|
||||
|
||||
import com.github.steveice10.packetlib.Server;
|
||||
|
||||
/**
|
||||
* Called when the server is about to close.
|
||||
*/
|
||||
public class ServerClosingEvent implements ServerEvent {
|
||||
private Server server;
|
||||
|
||||
/**
|
||||
* Creates a new ServerClosingEvent instance.
|
||||
*
|
||||
* @param server Server being closed.
|
||||
*/
|
||||
public ServerClosingEvent(Server server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server involved in this event.
|
||||
*
|
||||
* @return The event's server.
|
||||
*/
|
||||
public Server getServer() {
|
||||
return this.server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void call(ServerListener listener) {
|
||||
listener.serverClosing(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.github.steveice10.packetlib.event.server;
|
||||
|
||||
/**
|
||||
* An event relating to servers.
|
||||
*/
|
||||
public interface ServerEvent {
|
||||
/**
|
||||
* Calls the event.
|
||||
*
|
||||
* @param listener Listener to call the event on.
|
||||
*/
|
||||
public void call(ServerListener listener);
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.github.steveice10.packetlib.event.server;
|
||||
|
||||
/**
|
||||
* A listener for listening to server events.
|
||||
*/
|
||||
public interface ServerListener {
|
||||
/**
|
||||
* Called when a server is bound to its host and port.
|
||||
*
|
||||
* @param event Data relating to the event.
|
||||
*/
|
||||
public void serverBound(ServerBoundEvent event);
|
||||
|
||||
/**
|
||||
* Called when a server is about to close.
|
||||
*
|
||||
* @param event Data relating to the event.
|
||||
*/
|
||||
public void serverClosing(ServerClosingEvent event);
|
||||
|
||||
/**
|
||||
* Called when a server is closed.
|
||||
*
|
||||
* @param event Data relating to the event.
|
||||
*/
|
||||
public void serverClosed(ServerClosedEvent event);
|
||||
|
||||
/**
|
||||
* Called when a session is added to the server.
|
||||
*
|
||||
* @param event Data relating to the event.
|
||||
*/
|
||||
public void sessionAdded(SessionAddedEvent event);
|
||||
|
||||
/**
|
||||
* Called when a session is removed and disconnected from the server.
|
||||
*
|
||||
* @param event Data relating to the event.
|
||||
*/
|
||||
public void sessionRemoved(SessionRemovedEvent event);
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.github.steveice10.packetlib.event.server;
|
||||
|
||||
import com.github.steveice10.packetlib.Server;
|
||||
import com.github.steveice10.packetlib.Session;
|
||||
|
||||
/**
|
||||
* Called when a session is added to the server.
|
||||
*/
|
||||
public class SessionAddedEvent implements ServerEvent {
|
||||
private Server server;
|
||||
private Session session;
|
||||
|
||||
/**
|
||||
* Creates a new SessionAddedEvent instance.
|
||||
*
|
||||
* @param server Server the session is being added to.
|
||||
* @param session Session being added.
|
||||
*/
|
||||
public SessionAddedEvent(Server server, Session session) {
|
||||
this.server = server;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server involved in this event.
|
||||
*
|
||||
* @return The event's server.
|
||||
*/
|
||||
public Server getServer() {
|
||||
return this.server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the session involved in this event.
|
||||
*
|
||||
* @return The event's session.
|
||||
*/
|
||||
public Session getSession() {
|
||||
return this.session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void call(ServerListener listener) {
|
||||
listener.sessionAdded(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.github.steveice10.packetlib.event.server;
|
||||
|
||||
import com.github.steveice10.packetlib.Server;
|
||||
import com.github.steveice10.packetlib.Session;
|
||||
|
||||
/**
|
||||
* Called when a session is removed and disconnected from the server.
|
||||
*/
|
||||
public class SessionRemovedEvent implements ServerEvent {
|
||||
private Server server;
|
||||
private Session session;
|
||||
|
||||
/**
|
||||
* Creates a new SessionRemovedEvent instance.
|
||||
*
|
||||
* @param server Server the session is being removed from.
|
||||
* @param session Session being removed.
|
||||
*/
|
||||
public SessionRemovedEvent(Server server, Session session) {
|
||||
this.server = server;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server involved in this event.
|
||||
*
|
||||
* @return The event's server.
|
||||
*/
|
||||
public Server getServer() {
|
||||
return this.server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the session involved in this event.
|
||||
*
|
||||
* @return The event's session.
|
||||
*/
|
||||
public Session getSession() {
|
||||
return this.session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void call(ServerListener listener) {
|
||||
listener.sessionRemoved(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.github.steveice10.packetlib.event.session;
|
||||
|
||||
import com.github.steveice10.packetlib.Session;
|
||||
|
||||
/**
|
||||
* Called when the session connects.
|
||||
*/
|
||||
public class ConnectedEvent implements SessionEvent {
|
||||
private Session session;
|
||||
|
||||
/**
|
||||
* Creates a new ConnectedEvent instance.
|
||||
*
|
||||
* @param session Session being connected.
|
||||
*/
|
||||
public ConnectedEvent(Session session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the session involved in this event.
|
||||
*
|
||||
* @return The event's session.
|
||||
*/
|
||||
public Session getSession() {
|
||||
return this.session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void call(SessionListener listener) {
|
||||
listener.connected(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package com.github.steveice10.packetlib.event.session;
|
||||
|
||||
import com.github.steveice10.packetlib.Session;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
/**
|
||||
* Called when the session is disconnected.
|
||||
*/
|
||||
public class DisconnectedEvent implements SessionEvent {
|
||||
private final Session session;
|
||||
private final Component reason;
|
||||
private final Throwable cause;
|
||||
|
||||
/**
|
||||
* Creates a new DisconnectedEvent instance.
|
||||
*
|
||||
* @param session Session being disconnected.
|
||||
* @param reason Reason for the session to disconnect.
|
||||
* @param cause Throwable that caused the disconnect.
|
||||
*/
|
||||
public DisconnectedEvent(Session session, Component reason, Throwable cause) {
|
||||
this.session = session;
|
||||
this.reason = reason;
|
||||
this.cause = cause;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the session involved in this event.
|
||||
*
|
||||
* @return The event's session.
|
||||
*/
|
||||
public Session getSession() {
|
||||
return this.session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the reason given for the session disconnecting.
|
||||
*
|
||||
* @return The event's reason.
|
||||
*/
|
||||
public Component getReason() {
|
||||
return this.reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Throwable responsible for the session disconnecting.
|
||||
*
|
||||
* @return The Throwable responsible for the disconnect, or null if the disconnect was not caused by a Throwable.
|
||||
*/
|
||||
public Throwable getCause() {
|
||||
return this.cause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void call(SessionListener listener) {
|
||||
listener.disconnected(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package com.github.steveice10.packetlib.event.session;
|
||||
|
||||
import com.github.steveice10.packetlib.Session;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
/**
|
||||
* Called when the session is about to disconnect.
|
||||
*/
|
||||
public class DisconnectingEvent implements SessionEvent {
|
||||
private final Session session;
|
||||
private final Component reason;
|
||||
private final Throwable cause;
|
||||
|
||||
/**
|
||||
* Creates a new DisconnectingEvent instance.
|
||||
*
|
||||
* @param session Session being disconnected.
|
||||
* @param reason Reason for the session to disconnect.
|
||||
* @param cause Throwable that caused the disconnect.
|
||||
*/
|
||||
public DisconnectingEvent(Session session, Component reason, Throwable cause) {
|
||||
this.session = session;
|
||||
this.reason = reason;
|
||||
this.cause = cause;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the session involved in this event.
|
||||
*
|
||||
* @return The event's session.
|
||||
*/
|
||||
public Session getSession() {
|
||||
return this.session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the reason given for the session disconnecting.
|
||||
*
|
||||
* @return The event's reason.
|
||||
*/
|
||||
public Component getReason() {
|
||||
return this.reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Throwable responsible for the session disconnecting.
|
||||
*
|
||||
* @return The Throwable responsible for the disconnect, or null if the disconnect was not caused by a Throwable.
|
||||
*/
|
||||
public Throwable getCause() {
|
||||
return this.cause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void call(SessionListener listener) {
|
||||
listener.disconnecting(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package com.github.steveice10.packetlib.event.session;
|
||||
|
||||
import com.github.steveice10.packetlib.Session;
|
||||
|
||||
/**
|
||||
* Called when a session encounters an error while reading or writing packet data.
|
||||
*/
|
||||
public class PacketErrorEvent implements SessionEvent {
|
||||
private Session session;
|
||||
private Throwable cause;
|
||||
private boolean suppress = false;
|
||||
|
||||
/**
|
||||
* Creates a new SessionErrorEvent instance.
|
||||
*
|
||||
* @param session Session that the error came from.
|
||||
* @param cause Cause of the error.
|
||||
*/
|
||||
public PacketErrorEvent(Session session, Throwable cause) {
|
||||
this.session = session;
|
||||
this.cause = cause;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the session involved in this event.
|
||||
*
|
||||
* @return The event's session.
|
||||
*/
|
||||
public Session getSession() {
|
||||
return this.session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Throwable responsible for the error.
|
||||
*
|
||||
* @return The Throwable responsible for the error.
|
||||
*/
|
||||
public Throwable getCause() {
|
||||
return this.cause;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the error should be suppressed. If the error is not suppressed,
|
||||
* it will be passed on through internal error handling and disconnect the session.
|
||||
*
|
||||
* The default value is false.
|
||||
*
|
||||
* @return Whether the error should be suppressed.
|
||||
*/
|
||||
public boolean shouldSuppress() {
|
||||
return this.suppress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the error should be suppressed. If the error is not suppressed,
|
||||
* it will be passed on through internal error handling and disconnect the session.
|
||||
*
|
||||
* @param suppress Whether the error should be suppressed.
|
||||
*/
|
||||
public void setSuppress(boolean suppress) {
|
||||
this.suppress = suppress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void call(SessionListener listener) {
|
||||
listener.packetError(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package com.github.steveice10.packetlib.event.session;
|
||||
|
||||
import com.github.steveice10.packetlib.Session;
|
||||
import com.github.steveice10.packetlib.packet.Packet;
|
||||
|
||||
/**
|
||||
* Called when the session is sending a packet.
|
||||
*/
|
||||
public class PacketSendingEvent implements SessionEvent {
|
||||
private Session session;
|
||||
private Packet packet;
|
||||
private boolean cancelled = false;
|
||||
|
||||
/**
|
||||
* Creates a new PacketSendingEvent instance.
|
||||
*
|
||||
* @param session Session sending the packet.
|
||||
* @param packet Packet being sent.
|
||||
*/
|
||||
public PacketSendingEvent(Session session, Packet packet) {
|
||||
this.session = session;
|
||||
this.packet = packet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the session involved in this event.
|
||||
*
|
||||
* @return The event's session.
|
||||
*/
|
||||
public Session getSession() {
|
||||
return this.session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the packet involved in this event as the required type.
|
||||
*
|
||||
* @param <T> Type of the packet.
|
||||
* @return The event's packet as the required type.
|
||||
* @throws IllegalStateException If the packet's value isn't of the required type.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Packet> T getPacket() {
|
||||
try {
|
||||
return (T) this.packet;
|
||||
} catch(ClassCastException e) {
|
||||
throw new IllegalStateException("Tried to get packet as the wrong type. Actual type: " + this.packet.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the packet that should be sent as a result of this event.
|
||||
*
|
||||
* @param packet The packet to send.
|
||||
*/
|
||||
public void setPacket(Packet packet) {
|
||||
this.packet = packet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the event has been cancelled.
|
||||
*
|
||||
* @return Whether the event has been cancelled.
|
||||
*/
|
||||
public boolean isCancelled() {
|
||||
return this.cancelled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the event should be cancelled.
|
||||
*
|
||||
* @param cancelled Whether the event should be cancelled.
|
||||
*/
|
||||
public void setCancelled(boolean cancelled) {
|
||||
this.cancelled = cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void call(SessionListener listener) {
|
||||
listener.packetSending(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package com.github.steveice10.packetlib.event.session;
|
||||
|
||||
import com.github.steveice10.packetlib.Session;
|
||||
import com.github.steveice10.packetlib.packet.Packet;
|
||||
|
||||
/**
|
||||
* An adapter for picking session events to listen for.
|
||||
*/
|
||||
public class SessionAdapter implements SessionListener {
|
||||
@Override
|
||||
public void packetReceived(Session session, Packet packet) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void packetSending(PacketSendingEvent event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void packetSent(Session session, Packet packet) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void packetError(PacketErrorEvent event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connected(ConnectedEvent event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnecting(DisconnectingEvent event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnected(DisconnectedEvent event) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.github.steveice10.packetlib.event.session;
|
||||
|
||||
/**
|
||||
* An event relating to sessions.
|
||||
*/
|
||||
public interface SessionEvent {
|
||||
/**
|
||||
* Calls the event.
|
||||
*
|
||||
* @param listener Listener to call the event on.
|
||||
*/
|
||||
public void call(SessionListener listener);
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package com.github.steveice10.packetlib.event.session;
|
||||
|
||||
import com.github.steveice10.packetlib.Session;
|
||||
import com.github.steveice10.packetlib.packet.Packet;
|
||||
|
||||
/**
|
||||
* A listener for listening to session events.
|
||||
*/
|
||||
public interface SessionListener {
|
||||
/**
|
||||
* Called when a session receives a packet.
|
||||
*
|
||||
* @param packet the packet that was just received.
|
||||
*/
|
||||
void packetReceived(Session session, Packet packet);
|
||||
|
||||
/**
|
||||
* Called when a session is sending a packet.
|
||||
*
|
||||
* @param event Data relating to the event.
|
||||
*/
|
||||
public void packetSending(PacketSendingEvent event);
|
||||
|
||||
/**
|
||||
* Called when a session sends a packet.
|
||||
*
|
||||
* @param packet Packet just sent.
|
||||
*/
|
||||
void packetSent(Session session, Packet packet);
|
||||
|
||||
/**
|
||||
* Called when a session encounters an error while reading or writing packet data.
|
||||
*
|
||||
* @param event Data relating to the event.
|
||||
*/
|
||||
public void packetError(PacketErrorEvent event);
|
||||
|
||||
/**
|
||||
* Called when a session connects.
|
||||
*
|
||||
* @param event Data relating to the event.
|
||||
*/
|
||||
public void connected(ConnectedEvent event);
|
||||
|
||||
/**
|
||||
* Called when a session is about to disconnect.
|
||||
*
|
||||
* @param event Data relating to the event.
|
||||
*/
|
||||
public void disconnecting(DisconnectingEvent event);
|
||||
|
||||
/**
|
||||
* Called when a session is disconnected.
|
||||
*
|
||||
* @param event Data relating to the event.
|
||||
*/
|
||||
public void disconnected(DisconnectedEvent event);
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package com.github.steveice10.packetlib.helper;
|
||||
|
||||
import io.netty.channel.epoll.Epoll;
|
||||
import io.netty.channel.kqueue.KQueue;
|
||||
import io.netty.incubator.channel.uring.IOUring;
|
||||
|
||||
public class TransportHelper {
|
||||
public enum TransportMethod {
|
||||
NIO, EPOLL, KQUEUE, IO_URING
|
||||
}
|
||||
|
||||
public static TransportMethod determineTransportMethod() {
|
||||
if (isClassAvailable("io.netty.incubator.channel.uring.IOUring") && IOUring.isAvailable()) return TransportMethod.IO_URING;
|
||||
if (isClassAvailable("io.netty.channel.epoll.Epoll") && Epoll.isAvailable()) return TransportMethod.EPOLL;
|
||||
if (isClassAvailable("io.netty.channel.kqueue.KQueue") && KQueue.isAvailable()) return TransportMethod.KQUEUE;
|
||||
return TransportMethod.NIO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used so implementations can opt to remove these dependencies if so desired
|
||||
*/
|
||||
private static boolean isClassAvailable(String className) {
|
||||
try {
|
||||
Class.forName(className);
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package com.github.steveice10.packetlib.packet;
|
||||
|
||||
import com.github.steveice10.packetlib.codec.PacketCodecHelper;
|
||||
import com.github.steveice10.packetlib.codec.PacketDefinition;
|
||||
import com.github.steveice10.packetlib.codec.PacketSerializer;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class BufferedPacket implements Packet, PacketSerializer<BufferedPacket, PacketCodecHelper> {
|
||||
private final Class<? extends Packet> packetClass;
|
||||
private final byte[] buf;
|
||||
|
||||
public BufferedPacket(Class<? extends Packet> packetClass, byte[] buf) {
|
||||
this.packetClass = packetClass;
|
||||
this.buf = buf;
|
||||
}
|
||||
|
||||
public Class<? extends Packet> getPacketClass() {
|
||||
return packetClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPriority() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(ByteBuf buf, PacketCodecHelper helper, BufferedPacket packet) {
|
||||
buf.writeBytes(this.buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedPacket deserialize(ByteBuf buf, PacketCodecHelper helper, PacketDefinition<BufferedPacket, PacketCodecHelper> definition) {
|
||||
byte[] array = new byte[buf.readableBytes()];
|
||||
buf.readBytes(array);
|
||||
|
||||
return new BufferedPacket(definition.getPacketClass(), array);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.github.steveice10.packetlib.packet;
|
||||
|
||||
import com.github.steveice10.packetlib.codec.PacketCodecHelper;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* The default packet header, using a varint packet length and id.
|
||||
*/
|
||||
public class DefaultPacketHeader implements PacketHeader {
|
||||
@Override
|
||||
public boolean isLengthVariable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLengthSize() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLengthSize(int length) {
|
||||
if((length & -128) == 0) {
|
||||
return 1;
|
||||
} else if((length & -16384) == 0) {
|
||||
return 2;
|
||||
} else if((length & -2097152) == 0) {
|
||||
return 3;
|
||||
} else if((length & -268435456) == 0) {
|
||||
return 4;
|
||||
} else {
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readLength(ByteBuf buf, PacketCodecHelper codecHelper, int available) throws IOException {
|
||||
return codecHelper.readVarInt(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeLength(ByteBuf buf, PacketCodecHelper codecHelper, int length) throws IOException {
|
||||
codecHelper.writeVarInt(buf, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readPacketId(ByteBuf buf, PacketCodecHelper codecHelper) throws IOException {
|
||||
return codecHelper.readVarInt(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writePacketId(ByteBuf buf, PacketCodecHelper codecHelper, int packetId) throws IOException {
|
||||
codecHelper.writeVarInt(buf, packetId);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.github.steveice10.packetlib.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* A network packet. Any given packet must have a constructor that takes in a {@link ByteBuf}.
|
||||
*/
|
||||
public interface Packet {
|
||||
|
||||
/**
|
||||
* Gets whether the packet has handling priority.
|
||||
* If the result is true, the packet will be handled immediately after being
|
||||
* decoded.
|
||||
*
|
||||
* @return Whether the packet has priority.
|
||||
*/
|
||||
default boolean isPriority() {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package com.github.steveice10.packetlib.packet;
|
||||
|
||||
import com.github.steveice10.packetlib.codec.PacketCodecHelper;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* The header of a protocol's packets.
|
||||
*/
|
||||
public interface PacketHeader {
|
||||
/**
|
||||
* Gets whether the header's length value can vary in size.
|
||||
*
|
||||
* @return Whether the header's length value can vary in size.
|
||||
*/
|
||||
public boolean isLengthVariable();
|
||||
|
||||
/**
|
||||
* Gets the size of the header's length value.
|
||||
*
|
||||
* @return The length value's size.
|
||||
*/
|
||||
public int getLengthSize();
|
||||
|
||||
/**
|
||||
* Gets the size of the header's length value.
|
||||
*
|
||||
* @param length Length value to get the size of.
|
||||
* @return The length value's size.
|
||||
*/
|
||||
public int getLengthSize(int length);
|
||||
|
||||
/**
|
||||
* Reads the length of a packet from the given input.
|
||||
*
|
||||
* @param buf Buffer to read from.
|
||||
* @param codecHelper The codec helper.
|
||||
* @param available Number of packet bytes available after the length.
|
||||
* @return The resulting packet length.
|
||||
* @throws java.io.IOException If an I/O error occurs.
|
||||
*/
|
||||
public int readLength(ByteBuf buf, PacketCodecHelper codecHelper, int available) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes the length of a packet to the given output.
|
||||
*
|
||||
* @param buf Buffer to write to.
|
||||
* @param codecHelper The codec helper.
|
||||
* @param length Length to write.
|
||||
* @throws java.io.IOException If an I/O error occurs.
|
||||
*/
|
||||
public void writeLength(ByteBuf buf, PacketCodecHelper codecHelper, int length) throws IOException;
|
||||
|
||||
/**
|
||||
* Reads the ID of a packet from the given input.
|
||||
*
|
||||
* @param buf Buffer to read from.
|
||||
* @param codecHelper The codec helper.
|
||||
* @return The resulting packet ID, or -1 if the packet should not be read yet.
|
||||
* @throws java.io.IOException If an I/O error occurs.
|
||||
*/
|
||||
public int readPacketId(ByteBuf buf, PacketCodecHelper codecHelper) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes the ID of a packet to the given output.
|
||||
*
|
||||
* @param buf Buffer to write to.
|
||||
* @param codecHelper The codec helper.
|
||||
* @param packetId Packet ID to write.
|
||||
* @throws java.io.IOException If an I/O error occurs.
|
||||
*/
|
||||
public void writePacketId(ByteBuf buf, PacketCodecHelper codecHelper, int packetId) throws IOException;
|
||||
}
|
|
@ -0,0 +1,303 @@
|
|||
package com.github.steveice10.packetlib.packet;
|
||||
|
||||
import com.github.steveice10.packetlib.Server;
|
||||
import com.github.steveice10.packetlib.Session;
|
||||
import com.github.steveice10.packetlib.codec.PacketCodecHelper;
|
||||
import com.github.steveice10.packetlib.codec.PacketDefinition;
|
||||
import com.github.steveice10.packetlib.codec.PacketSerializer;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A protocol for packet sending and receiving.
|
||||
* All implementations must have a constructor that takes in a {@link ByteBuf}.
|
||||
*/
|
||||
public abstract class PacketProtocol {
|
||||
private final Int2ObjectMap<PacketDefinition<? extends Packet, ?>> serverbound = new Int2ObjectOpenHashMap<>();
|
||||
private final Int2ObjectMap<PacketDefinition<? extends Packet, ?>> clientbound = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
private final Map<Class<? extends Packet>, Integer> clientboundIds = new IdentityHashMap<>();
|
||||
private final Map<Class<? extends Packet>, Integer> serverboundIds = new IdentityHashMap<>();
|
||||
|
||||
/**
|
||||
* Gets the prefix used when locating SRV records for this protocol.
|
||||
*
|
||||
* @return The protocol's SRV record prefix.
|
||||
*/
|
||||
public abstract String getSRVRecordPrefix();
|
||||
|
||||
/**
|
||||
* Gets the packet header of this protocol.
|
||||
*
|
||||
* @return The protocol's packet header.
|
||||
*/
|
||||
public abstract PacketHeader getPacketHeader();
|
||||
|
||||
/**
|
||||
* Creates a new {@link PacketCodecHelper} that can be used
|
||||
* for each session.
|
||||
*
|
||||
* @return A new {@link PacketCodecHelper}.
|
||||
*/
|
||||
public abstract PacketCodecHelper createHelper();
|
||||
|
||||
/**
|
||||
* Called when a client session is created with this protocol.
|
||||
*
|
||||
* @param session The created session.
|
||||
*/
|
||||
public abstract void newClientSession(Session session);
|
||||
|
||||
/**
|
||||
* Called when a server session is created with this protocol.
|
||||
*
|
||||
* @param server The server that the session belongs to.
|
||||
* @param session The created session.
|
||||
*/
|
||||
public abstract void newServerSession(Server server, Session session);
|
||||
|
||||
/**
|
||||
* Clears all currently registered packets.
|
||||
*/
|
||||
public final void clearPackets() {
|
||||
this.serverbound.clear();
|
||||
this.clientbound.clear();
|
||||
this.clientboundIds.clear();
|
||||
this.serverboundIds.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a packet to this protocol as both serverbound and clientbound.
|
||||
*
|
||||
* @param id Id to register the packet to.
|
||||
* @param packet Packet to register.
|
||||
* @param serializer The packet serializer.
|
||||
* @throws IllegalArgumentException If the packet fails a test creation when being registered as serverbound.
|
||||
*/
|
||||
public final <T extends Packet, H extends PacketCodecHelper> void register(int id, Class<T> packet, PacketSerializer<T, H> serializer) {
|
||||
this.registerServerbound(id, packet, serializer);
|
||||
this.registerClientbound(id, packet, serializer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a packet to this protocol as both serverbound and clientbound.
|
||||
*
|
||||
* @param definition The packet definition.
|
||||
* @throws IllegalArgumentException If the packet fails a test creation when being registered as serverbound.
|
||||
*/
|
||||
public final void register(PacketDefinition<? extends Packet, ?> definition) {
|
||||
this.registerServerbound(definition);
|
||||
this.registerClientbound(definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a serverbound packet to this protocol.
|
||||
*
|
||||
* @param id Id to register the packet to.
|
||||
* @param packet Packet to register.
|
||||
* @param serializer The packet serializer.
|
||||
* @throws IllegalArgumentException If the packet fails a test creation.
|
||||
*/
|
||||
public final <T extends Packet, H extends PacketCodecHelper> void registerServerbound(int id, Class<T> packet, PacketSerializer<T, H> serializer) {
|
||||
this.registerServerbound(new PacketDefinition<>(id, packet, serializer));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a serverbound packet to this protocol.
|
||||
*
|
||||
* @param definition The packet definition.
|
||||
*/
|
||||
public final void registerServerbound(PacketDefinition<? extends Packet, ?> definition) {
|
||||
this.serverbound.put(definition.getId(), definition);
|
||||
this.serverboundIds.put(definition.getPacketClass(), definition.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a clientbound packet to this protocol.
|
||||
*
|
||||
* @param id Id to register the packet to.
|
||||
* @param packet Packet to register.
|
||||
* @param serializer The packet serializer.
|
||||
*/
|
||||
public final <T extends Packet, H extends PacketCodecHelper> void registerClientbound(int id, Class<T> packet, PacketSerializer<T, H> serializer) {
|
||||
this.registerClientbound(new PacketDefinition<>(id, packet, serializer));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a clientbound packet to this protocol.
|
||||
*
|
||||
* @param definition The packet definition.
|
||||
*/
|
||||
public final void registerClientbound(PacketDefinition<? extends Packet, ?> definition) {
|
||||
this.clientbound.put(definition.getId(), definition);
|
||||
this.clientboundIds.put(definition.getPacketClass(), definition.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of a clientbound packet with the given id and read the clientbound input.
|
||||
*
|
||||
* @param id Id of the packet to create.
|
||||
* @param buf The buffer to read the packet from.
|
||||
* @param codecHelper The codec helper.
|
||||
* @return The created packet.
|
||||
* @throws IOException if there was an IO error whilst reading the packet.
|
||||
* @throws IllegalArgumentException If the packet ID is not registered.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <H extends PacketCodecHelper> Packet createClientboundPacket(int id, ByteBuf buf, H codecHelper) throws IOException {
|
||||
PacketDefinition<?, H> definition = (PacketDefinition<?, H>) this.clientbound.get(id);
|
||||
if (definition == null) {
|
||||
throw new IllegalArgumentException("Invalid packet id: " + id);
|
||||
}
|
||||
|
||||
return definition.newInstance(buf, codecHelper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the registered id of a clientbound packet class.
|
||||
*
|
||||
* @param packetClass Class of the packet to get the id for.
|
||||
* @return The packet's registered id.
|
||||
* @throws IllegalArgumentException If the packet is not registered.
|
||||
*/
|
||||
public int getClientboundId(Class<? extends Packet> packetClass) {
|
||||
Integer packetId = this.clientboundIds.get(packetClass);
|
||||
if(packetId == null) {
|
||||
throw new IllegalArgumentException("Unregistered clientbound packet class: " + packetClass.getName());
|
||||
}
|
||||
|
||||
return packetId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the registered id of a clientbound {@link Packet} instance.
|
||||
*
|
||||
* @param packet Instance of {@link Packet} to get the id for.
|
||||
* @return The packet's registered id.
|
||||
* @throws IllegalArgumentException If the packet is not registered.
|
||||
*/
|
||||
public int getClientboundId(Packet packet) {
|
||||
if (packet instanceof BufferedPacket) {
|
||||
return getClientboundId(((BufferedPacket) packet).getPacketClass());
|
||||
}
|
||||
|
||||
return getClientboundId(packet.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the packet class for a packet id.
|
||||
* @param id The packet id.
|
||||
* @return The registered packet's class
|
||||
* @throws IllegalArgumentException If the packet ID is not registered.
|
||||
*/
|
||||
public Class<? extends Packet> getClientboundClass(int id) {
|
||||
PacketDefinition<?, ?> definition = this.clientbound.get(id);
|
||||
if (definition == null) {
|
||||
throw new IllegalArgumentException("Invalid packet id: " + id);
|
||||
}
|
||||
|
||||
return definition.getPacketClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of a serverbound packet with the given id and read the serverbound input.
|
||||
*
|
||||
* @param id Id of the packet to create.
|
||||
* @param buf The buffer to read the packet from.
|
||||
* @param codecHelper The codec helper.
|
||||
* @return The created packet.
|
||||
* @throws IOException if there was an IO error whilst reading the packet.
|
||||
* @throws IllegalArgumentException If the packet ID is not registered.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <H extends PacketCodecHelper> Packet createServerboundPacket(int id, ByteBuf buf, H codecHelper) throws IOException {
|
||||
PacketDefinition<?, H> definition = (PacketDefinition<?, H>) this.serverbound.get(id);
|
||||
if (definition == null) {
|
||||
throw new IllegalArgumentException("Invalid packet id: " + id);
|
||||
}
|
||||
|
||||
return definition.newInstance(buf, codecHelper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the registered id of a serverbound packet class.
|
||||
*
|
||||
* @param packetClass Class of the packet to get the id for.
|
||||
* @return The packet's registered id.
|
||||
* @throws IllegalArgumentException If the packet is not registered.
|
||||
*/
|
||||
public int getServerboundId(Class<? extends Packet> packetClass) {
|
||||
Integer packetId = this.serverboundIds.get(packetClass);
|
||||
if(packetId == null) {
|
||||
throw new IllegalArgumentException("Unregistered serverbound packet class: " + packetClass.getName());
|
||||
}
|
||||
|
||||
return packetId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the registered id of a serverbound {@link Packet} instance.
|
||||
*
|
||||
* @param packet Instance of {@link Packet} to get the id for.
|
||||
* @return The packet's registered id.
|
||||
* @throws IllegalArgumentException If the packet is not registered.
|
||||
*/
|
||||
public int getServerboundId(Packet packet) {
|
||||
if (packet instanceof BufferedPacket) {
|
||||
return getServerboundId(((BufferedPacket) packet).getPacketClass());
|
||||
}
|
||||
|
||||
return getServerboundId(packet.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the packet class for a packet id.
|
||||
* @param id The packet id.
|
||||
* @return The registered packet's class
|
||||
* @throws IllegalArgumentException If the packet ID is not registered.
|
||||
*/
|
||||
public Class<? extends Packet> getServerboundClass(int id) {
|
||||
PacketDefinition<?, ?> definition = this.serverbound.get(id);
|
||||
if (definition == null) {
|
||||
throw new IllegalArgumentException("Invalid packet id: " + id);
|
||||
}
|
||||
|
||||
return definition.getPacketClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the serverbound packet definition for the given packet id.
|
||||
*
|
||||
* @param id The packet id.
|
||||
* @return The registered packet's class
|
||||
*/
|
||||
public PacketDefinition<?, ?> getServerboundDefinition(int id) {
|
||||
PacketDefinition<?, ?> definition = this.serverbound.get(id);
|
||||
if (definition == null) {
|
||||
throw new IllegalArgumentException("Invalid packet id: " + id);
|
||||
}
|
||||
|
||||
return definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clientbound packet definition for the given packet id.
|
||||
*
|
||||
* @param id The packet id.
|
||||
* @return The registered packet's class
|
||||
*/
|
||||
public PacketDefinition<?, ?> getClientboundDefinition(int id) {
|
||||
PacketDefinition<?, ?> definition = this.clientbound.get(id);
|
||||
if (definition == null) {
|
||||
throw new IllegalArgumentException("Invalid packet id: " + id);
|
||||
}
|
||||
|
||||
return definition;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package com.github.steveice10.packetlib.tcp;
|
||||
|
||||
import com.github.steveice10.mc.protocol.codec.MinecraftPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundBundlePacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundDelimiterPacket;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TcpBundlerUnpacker extends MessageToMessageDecoder<MinecraftPacket> {
|
||||
private List<MinecraftPacket> currentPackets;
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, MinecraftPacket packet, List<Object> out) throws Exception {
|
||||
if (currentPackets != null) {
|
||||
if (packet.getClass() == ClientboundDelimiterPacket.class) {
|
||||
out.add(new ClientboundBundlePacket(currentPackets));
|
||||
currentPackets = null;
|
||||
} else {
|
||||
currentPackets.add(packet);
|
||||
}
|
||||
} else {
|
||||
if (packet.getClass() == ClientboundDelimiterPacket.class) {
|
||||
currentPackets = new ArrayList<>(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,321 @@
|
|||
package com.github.steveice10.packetlib.tcp;
|
||||
|
||||
import com.github.steveice10.packetlib.BuiltinFlags;
|
||||
import com.github.steveice10.packetlib.ProxyInfo;
|
||||
import com.github.steveice10.packetlib.codec.PacketCodecHelper;
|
||||
import com.github.steveice10.packetlib.helper.TransportHelper;
|
||||
import com.github.steveice10.packetlib.packet.PacketProtocol;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.AddressedEnvelope;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.epoll.EpollDatagramChannel;
|
||||
import io.netty.channel.epoll.EpollEventLoopGroup;
|
||||
import io.netty.channel.epoll.EpollSocketChannel;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.DatagramChannel;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.kqueue.KQueueDatagramChannel;
|
||||
import io.netty.channel.kqueue.KQueueEventLoopGroup;
|
||||
import io.netty.channel.kqueue.KQueueSocketChannel;
|
||||
import io.netty.channel.socket.nio.NioDatagramChannel;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.codec.dns.DefaultDnsQuestion;
|
||||
import io.netty.handler.codec.dns.DefaultDnsRawRecord;
|
||||
import io.netty.handler.codec.dns.DefaultDnsRecordDecoder;
|
||||
import io.netty.handler.codec.dns.DnsRecordType;
|
||||
import io.netty.handler.codec.dns.DnsResponse;
|
||||
import io.netty.handler.codec.dns.DnsSection;
|
||||
import io.netty.handler.codec.haproxy.HAProxyCommand;
|
||||
import io.netty.handler.codec.haproxy.HAProxyMessage;
|
||||
import io.netty.handler.codec.haproxy.HAProxyMessageEncoder;
|
||||
import io.netty.handler.codec.haproxy.HAProxyProtocolVersion;
|
||||
import io.netty.handler.codec.haproxy.HAProxyProxiedProtocol;
|
||||
import io.netty.handler.proxy.HttpProxyHandler;
|
||||
import io.netty.handler.proxy.Socks4ProxyHandler;
|
||||
import io.netty.handler.proxy.Socks5ProxyHandler;
|
||||
import io.netty.incubator.channel.uring.IOUringDatagramChannel;
|
||||
import io.netty.incubator.channel.uring.IOUringEventLoopGroup;
|
||||
import io.netty.incubator.channel.uring.IOUringSocketChannel;
|
||||
import io.netty.resolver.dns.DnsNameResolver;
|
||||
import io.netty.resolver.dns.DnsNameResolverBuilder;
|
||||
import java.net.*;
|
||||
|
||||
public class TcpClientSession extends TcpSession {
|
||||
private static final String IP_REGEX = "\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b";
|
||||
private static Class<? extends Channel> CHANNEL_CLASS;
|
||||
private static Class<? extends DatagramChannel> DATAGRAM_CHANNEL_CLASS;
|
||||
private static EventLoopGroup EVENT_LOOP_GROUP;
|
||||
|
||||
private final String bindAddress;
|
||||
private final int bindPort;
|
||||
private final ProxyInfo proxy;
|
||||
private final PacketCodecHelper codecHelper;
|
||||
|
||||
public TcpClientSession(String host, int port, PacketProtocol protocol) {
|
||||
this(host, port, protocol, null);
|
||||
}
|
||||
|
||||
public TcpClientSession(String host, int port, PacketProtocol protocol, ProxyInfo proxy) {
|
||||
this(host, port, "0.0.0.0", 0, protocol, proxy);
|
||||
}
|
||||
|
||||
public TcpClientSession(String host, int port, String bindAddress, int bindPort, PacketProtocol protocol) {
|
||||
this(host, port, bindAddress, bindPort, protocol, null);
|
||||
}
|
||||
|
||||
public TcpClientSession(String host, int port, String bindAddress, int bindPort, PacketProtocol protocol, ProxyInfo proxy) {
|
||||
super(host, port, protocol);
|
||||
this.bindAddress = bindAddress;
|
||||
this.bindPort = bindPort;
|
||||
this.proxy = proxy;
|
||||
this.codecHelper = protocol.createHelper();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(boolean wait) {
|
||||
if(this.disconnected) {
|
||||
throw new IllegalStateException("Session has already been disconnected.");
|
||||
}
|
||||
|
||||
boolean debug = getFlag(BuiltinFlags.PRINT_DEBUG, false);
|
||||
|
||||
if (CHANNEL_CLASS == null) {
|
||||
createTcpEventLoopGroup();
|
||||
}
|
||||
|
||||
try {
|
||||
final Bootstrap bootstrap = new Bootstrap();
|
||||
bootstrap.channel(CHANNEL_CLASS);
|
||||
bootstrap.handler(new ChannelInitializer<Channel>() {
|
||||
@Override
|
||||
public void initChannel(Channel channel) {
|
||||
PacketProtocol protocol = getPacketProtocol();
|
||||
protocol.newClientSession(TcpClientSession.this);
|
||||
|
||||
channel.config().setOption(ChannelOption.IP_TOS, 0x18);
|
||||
try {
|
||||
channel.config().setOption(ChannelOption.TCP_NODELAY, true);
|
||||
} catch (ChannelException e) {
|
||||
if(debug) {
|
||||
System.out.println("Exception while trying to set TCP_NODELAY");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
ChannelPipeline pipeline = channel.pipeline();
|
||||
|
||||
refreshReadTimeoutHandler(channel);
|
||||
refreshWriteTimeoutHandler(channel);
|
||||
|
||||
addProxy(pipeline);
|
||||
|
||||
int size = protocol.getPacketHeader().getLengthSize();
|
||||
if (size > 0) {
|
||||
pipeline.addLast("sizer", new TcpPacketSizer(TcpClientSession.this, size));
|
||||
}
|
||||
|
||||
pipeline.addLast("codec", new TcpPacketCodec(TcpClientSession.this, true));
|
||||
pipeline.addLast("manager", TcpClientSession.this);
|
||||
|
||||
addHAProxySupport(pipeline);
|
||||
}
|
||||
}).group(EVENT_LOOP_GROUP).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, getConnectTimeout() * 1000);
|
||||
|
||||
InetSocketAddress remoteAddress = resolveAddress();
|
||||
bootstrap.remoteAddress(remoteAddress);
|
||||
bootstrap.localAddress(bindAddress, bindPort);
|
||||
|
||||
ChannelFuture future = bootstrap.connect();
|
||||
if (wait) {
|
||||
future.sync();
|
||||
}
|
||||
|
||||
future.addListener((futureListener) -> {
|
||||
if (!futureListener.isSuccess()) {
|
||||
exceptionCaught(null, futureListener.cause());
|
||||
}
|
||||
});
|
||||
} catch(Throwable t) {
|
||||
exceptionCaught(null, t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketCodecHelper getCodecHelper() {
|
||||
return this.codecHelper;
|
||||
}
|
||||
|
||||
private InetSocketAddress resolveAddress() {
|
||||
boolean debug = getFlag(BuiltinFlags.PRINT_DEBUG, false);
|
||||
|
||||
String name = this.getPacketProtocol().getSRVRecordPrefix() + "._tcp." + this.getHost();
|
||||
if (debug) {
|
||||
System.out.println("[PacketLib] Attempting SRV lookup for \"" + name + "\".");
|
||||
}
|
||||
|
||||
if(getFlag(BuiltinFlags.ATTEMPT_SRV_RESOLVE, true) && (!this.host.matches(IP_REGEX) && !this.host.equalsIgnoreCase("localhost"))) {
|
||||
DnsNameResolver resolver = null;
|
||||
AddressedEnvelope<DnsResponse, InetSocketAddress> envelope = null;
|
||||
try {
|
||||
resolver = new DnsNameResolverBuilder(EVENT_LOOP_GROUP.next())
|
||||
.channelType(DATAGRAM_CHANNEL_CLASS)
|
||||
.build();
|
||||
envelope = resolver.query(new DefaultDnsQuestion(name, DnsRecordType.SRV)).get();
|
||||
|
||||
DnsResponse response = envelope.content();
|
||||
if (response.count(DnsSection.ANSWER) > 0) {
|
||||
DefaultDnsRawRecord record = response.recordAt(DnsSection.ANSWER, 0);
|
||||
if (record.type() == DnsRecordType.SRV) {
|
||||
ByteBuf buf = record.content();
|
||||
buf.skipBytes(4); // Skip priority and weight.
|
||||
|
||||
int port = buf.readUnsignedShort();
|
||||
String host = DefaultDnsRecordDecoder.decodeName(buf);
|
||||
if (host.endsWith(".")) {
|
||||
host = host.substring(0, host.length() - 1);
|
||||
}
|
||||
|
||||
if(debug) {
|
||||
System.out.println("[PacketLib] Found SRV record containing \"" + host + ":" + port + "\".");
|
||||
}
|
||||
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
} else if (debug) {
|
||||
System.out.println("[PacketLib] Received non-SRV record in response.");
|
||||
}
|
||||
} else if (debug) {
|
||||
System.out.println("[PacketLib] No SRV record found.");
|
||||
}
|
||||
} catch(Exception e) {
|
||||
if (debug) {
|
||||
System.out.println("[PacketLib] Failed to resolve SRV record.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
} finally {
|
||||
if (envelope != null) {
|
||||
envelope.release();
|
||||
}
|
||||
|
||||
if (resolver != null) {
|
||||
resolver.close();
|
||||
}
|
||||
}
|
||||
} else if(debug) {
|
||||
System.out.println("[PacketLib] Not resolving SRV record for " + this.host);
|
||||
}
|
||||
|
||||
// Resolve host here
|
||||
try {
|
||||
InetAddress resolved = InetAddress.getByName(getHost());
|
||||
if (debug) {
|
||||
System.out.printf("[PacketLib] Resolved %s -> %s%n", getHost(), resolved.getHostAddress());
|
||||
}
|
||||
return new InetSocketAddress(resolved, getPort());
|
||||
} catch (UnknownHostException e) {
|
||||
if (debug) {
|
||||
System.out.println("[PacketLib] Failed to resolve host, letting Netty do it instead.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
return InetSocketAddress.createUnresolved(getHost(), getPort());
|
||||
}
|
||||
}
|
||||
|
||||
private void addProxy(ChannelPipeline pipeline) {
|
||||
if(proxy != null) {
|
||||
switch(proxy.getType()) {
|
||||
case HTTP:
|
||||
if (proxy.isAuthenticated()) {
|
||||
pipeline.addFirst("proxy", new HttpProxyHandler(proxy.getAddress(), proxy.getUsername(), proxy.getPassword()));
|
||||
} else {
|
||||
pipeline.addFirst("proxy", new HttpProxyHandler(proxy.getAddress()));
|
||||
}
|
||||
|
||||
break;
|
||||
case SOCKS4:
|
||||
if (proxy.isAuthenticated()) {
|
||||
pipeline.addFirst("proxy", new Socks4ProxyHandler(proxy.getAddress(), proxy.getUsername()));
|
||||
} else {
|
||||
pipeline.addFirst("proxy", new Socks4ProxyHandler(proxy.getAddress()));
|
||||
}
|
||||
|
||||
break;
|
||||
case SOCKS5:
|
||||
if (proxy.isAuthenticated()) {
|
||||
pipeline.addFirst("proxy", new Socks5ProxyHandler(proxy.getAddress(), proxy.getUsername(), proxy.getPassword()));
|
||||
} else {
|
||||
pipeline.addFirst("proxy", new Socks5ProxyHandler(proxy.getAddress()));
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unsupported proxy type: " + proxy.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addHAProxySupport(ChannelPipeline pipeline) {
|
||||
InetSocketAddress clientAddress = getFlag(BuiltinFlags.CLIENT_PROXIED_ADDRESS);
|
||||
if (getFlag(BuiltinFlags.ENABLE_CLIENT_PROXY_PROTOCOL, false) && clientAddress != null) {
|
||||
pipeline.addFirst("proxy-protocol-packet-sender", new ChannelInboundHandlerAdapter() {
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
HAProxyProxiedProtocol proxiedProtocol = clientAddress.getAddress() instanceof Inet4Address ? HAProxyProxiedProtocol.TCP4 : HAProxyProxiedProtocol.TCP6;
|
||||
InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress();
|
||||
ctx.channel().writeAndFlush(new HAProxyMessage(
|
||||
HAProxyProtocolVersion.V2, HAProxyCommand.PROXY, proxiedProtocol,
|
||||
clientAddress.getAddress().getHostAddress(), remoteAddress.getAddress().getHostAddress(),
|
||||
clientAddress.getPort(), remoteAddress.getPort()
|
||||
));
|
||||
ctx.pipeline().remove(this);
|
||||
ctx.pipeline().remove("proxy-protocol-encoder");
|
||||
super.channelActive(ctx);
|
||||
}
|
||||
});
|
||||
pipeline.addFirst("proxy-protocol-encoder", HAProxyMessageEncoder.INSTANCE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(String reason, Throwable cause) {
|
||||
super.disconnect(reason, cause);
|
||||
}
|
||||
|
||||
private static void createTcpEventLoopGroup() {
|
||||
if (CHANNEL_CLASS != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (TransportHelper.determineTransportMethod()) {
|
||||
case IO_URING:
|
||||
EVENT_LOOP_GROUP = new IOUringEventLoopGroup();
|
||||
CHANNEL_CLASS = IOUringSocketChannel.class;
|
||||
DATAGRAM_CHANNEL_CLASS = IOUringDatagramChannel.class;
|
||||
break;
|
||||
case EPOLL:
|
||||
EVENT_LOOP_GROUP = new EpollEventLoopGroup();
|
||||
CHANNEL_CLASS = EpollSocketChannel.class;
|
||||
DATAGRAM_CHANNEL_CLASS = EpollDatagramChannel.class;
|
||||
break;
|
||||
case KQUEUE:
|
||||
EVENT_LOOP_GROUP = new KQueueEventLoopGroup();
|
||||
CHANNEL_CLASS = KQueueSocketChannel.class;
|
||||
DATAGRAM_CHANNEL_CLASS = KQueueDatagramChannel.class;
|
||||
break;
|
||||
case NIO:
|
||||
EVENT_LOOP_GROUP = new NioEventLoopGroup();
|
||||
CHANNEL_CLASS = NioSocketChannel.class;
|
||||
DATAGRAM_CHANNEL_CLASS = NioDatagramChannel.class;
|
||||
break;
|
||||
}
|
||||
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> EVENT_LOOP_GROUP.shutdownGracefully()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package com.github.steveice10.packetlib.tcp;
|
||||
|
||||
import com.github.steveice10.packetlib.Session;
|
||||
import com.github.steveice10.packetlib.codec.PacketCodecHelper;
|
||||
import com.github.steveice10.packetlib.codec.PacketDefinition;
|
||||
import com.github.steveice10.packetlib.event.session.PacketErrorEvent;
|
||||
import com.github.steveice10.packetlib.packet.Packet;
|
||||
import com.github.steveice10.packetlib.packet.PacketProtocol;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageCodec;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TcpPacketCodec extends ByteToMessageCodec<Packet> {
|
||||
private final Session session;
|
||||
private final boolean client;
|
||||
|
||||
public TcpPacketCodec(Session session, boolean client) {
|
||||
this.session = session;
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Override
|
||||
public void encode(ChannelHandlerContext ctx, Packet packet, ByteBuf buf) throws Exception {
|
||||
int initial = buf.writerIndex();
|
||||
|
||||
PacketProtocol packetProtocol = this.session.getPacketProtocol();
|
||||
PacketCodecHelper codecHelper = this.session.getCodecHelper();
|
||||
try {
|
||||
int packetId = this.client ? packetProtocol.getServerboundId(packet) : packetProtocol.getClientboundId(packet);
|
||||
PacketDefinition definition = this.client ? packetProtocol.getServerboundDefinition(packetId) : packetProtocol.getClientboundDefinition(packetId);
|
||||
|
||||
packetProtocol.getPacketHeader().writePacketId(buf, codecHelper, packetId);
|
||||
definition.getSerializer().serialize(buf, codecHelper, packet);
|
||||
} catch (Throwable t) {
|
||||
// Reset writer index to make sure incomplete data is not written out.
|
||||
buf.writerIndex(initial);
|
||||
|
||||
PacketErrorEvent e = new PacketErrorEvent(this.session, t);
|
||||
this.session.callEvent(e);
|
||||
if (!e.shouldSuppress()) {
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> out) throws Exception {
|
||||
int initial = buf.readerIndex();
|
||||
|
||||
PacketProtocol packetProtocol = this.session.getPacketProtocol();
|
||||
PacketCodecHelper codecHelper = this.session.getCodecHelper();
|
||||
try {
|
||||
int id = packetProtocol.getPacketHeader().readPacketId(buf, codecHelper);
|
||||
if (id == -1) {
|
||||
buf.readerIndex(initial);
|
||||
return;
|
||||
}
|
||||
|
||||
Packet packet = this.client ? packetProtocol.createClientboundPacket(id, buf, codecHelper) : packetProtocol.createServerboundPacket(id, buf, codecHelper);
|
||||
|
||||
if (buf.readableBytes() > 0) {
|
||||
throw new IllegalStateException("Packet \"" + packet.getClass().getSimpleName() + "\" not fully read.");
|
||||
}
|
||||
|
||||
out.add(packet);
|
||||
} catch (Throwable t) {
|
||||
// Advance buffer to end to make sure remaining data in this packet is skipped.
|
||||
buf.readerIndex(buf.readerIndex() + buf.readableBytes());
|
||||
|
||||
PacketErrorEvent e = new PacketErrorEvent(this.session, t);
|
||||
this.session.callEvent(e);
|
||||
if (!e.shouldSuppress()) {
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package com.github.steveice10.packetlib.tcp;
|
||||
|
||||
import com.github.steveice10.packetlib.Session;
|
||||
import com.github.steveice10.packetlib.codec.PacketCodecHelper;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageCodec;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.Inflater;
|
||||
|
||||
public class TcpPacketCompression extends ByteToMessageCodec<ByteBuf> {
|
||||
private static final int MAX_COMPRESSED_SIZE = 2097152;
|
||||
|
||||
private final Session session;
|
||||
private final Deflater deflater = new Deflater();
|
||||
private final Inflater inflater = new Inflater();
|
||||
private final byte[] buf = new byte[8192];
|
||||
private final boolean validateDecompression;
|
||||
|
||||
public TcpPacketCompression(Session session, boolean validateDecompression) {
|
||||
this.session = session;
|
||||
this.validateDecompression = validateDecompression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
|
||||
super.handlerRemoved(ctx);
|
||||
|
||||
this.deflater.end();
|
||||
this.inflater.end();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception {
|
||||
int readable = in.readableBytes();
|
||||
if(readable < this.session.getCompressionThreshold()) {
|
||||
this.session.getCodecHelper().writeVarInt(out, 0);
|
||||
out.writeBytes(in);
|
||||
} else {
|
||||
byte[] bytes = new byte[readable];
|
||||
in.readBytes(bytes);
|
||||
this.session.getCodecHelper().writeVarInt(out, bytes.length);
|
||||
this.deflater.setInput(bytes, 0, readable);
|
||||
this.deflater.finish();
|
||||
while(!this.deflater.finished()) {
|
||||
int length = this.deflater.deflate(this.buf);
|
||||
out.writeBytes(this.buf, 0, length);
|
||||
}
|
||||
|
||||
this.deflater.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> out) throws Exception {
|
||||
if(buf.readableBytes() != 0) {
|
||||
int size = this.session.getCodecHelper().readVarInt(buf);
|
||||
if(size == 0) {
|
||||
out.add(buf.readBytes(buf.readableBytes()));
|
||||
} else {
|
||||
if (validateDecompression) { // This is sectioned off as of at least Java Edition 1.18
|
||||
if (size < this.session.getCompressionThreshold()) {
|
||||
throw new DecoderException("Badly compressed packet: size of " + size + " is below threshold of " + this.session.getCompressionThreshold() + ".");
|
||||
}
|
||||
|
||||
if (size > MAX_COMPRESSED_SIZE) {
|
||||
throw new DecoderException("Badly compressed packet: size of " + size + " is larger than protocol maximum of " + MAX_COMPRESSED_SIZE + ".");
|
||||
}
|
||||
}
|
||||
|
||||
byte[] bytes = new byte[buf.readableBytes()];
|
||||
buf.readBytes(bytes);
|
||||
this.inflater.setInput(bytes);
|
||||
byte[] inflated = new byte[size];
|
||||
this.inflater.inflate(inflated);
|
||||
out.add(Unpooled.wrappedBuffer(inflated));
|
||||
this.inflater.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package com.github.steveice10.packetlib.tcp;
|
||||
|
||||
import com.github.steveice10.packetlib.crypt.PacketEncryption;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageCodec;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TcpPacketEncryptor extends ByteToMessageCodec<ByteBuf> {
|
||||
private final PacketEncryption encryption;
|
||||
private byte[] decryptedArray = new byte[0];
|
||||
private byte[] encryptedArray = new byte[0];
|
||||
|
||||
public TcpPacketEncryptor(PacketEncryption encryption) {
|
||||
this.encryption = encryption;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception {
|
||||
int length = in.readableBytes();
|
||||
byte[] bytes = this.getBytes(in);
|
||||
int outLength = this.encryption.getEncryptOutputSize(length);
|
||||
if( this.encryptedArray.length < outLength) {
|
||||
this.encryptedArray = new byte[outLength];
|
||||
}
|
||||
|
||||
out.writeBytes(this.encryptedArray, 0, this.encryption.encrypt(bytes, 0, length, this.encryptedArray, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> out) throws Exception {
|
||||
int length = buf.readableBytes();
|
||||
byte[] bytes = this.getBytes(buf);
|
||||
ByteBuf result = ctx.alloc().heapBuffer(this.encryption.getDecryptOutputSize(length));
|
||||
result.writerIndex(this.encryption.decrypt(bytes, 0, length, result.array(), result.arrayOffset()));
|
||||
out.add(result);
|
||||
}
|
||||
|
||||
private byte[] getBytes(ByteBuf buf) {
|
||||
int length = buf.readableBytes();
|
||||
if (this.decryptedArray.length < length) {
|
||||
this.decryptedArray = new byte[length];
|
||||
}
|
||||
|
||||
buf.readBytes(this.decryptedArray, 0, length);
|
||||
return this.decryptedArray;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package com.github.steveice10.packetlib.tcp;
|
||||
|
||||
import com.github.steveice10.packetlib.Session;
|
||||
import com.github.steveice10.packetlib.codec.PacketCodecHelper;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageCodec;
|
||||
import io.netty.handler.codec.CorruptedFrameException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TcpPacketSizer extends ByteToMessageCodec<ByteBuf> {
|
||||
private final Session session;
|
||||
private final int size;
|
||||
|
||||
public TcpPacketSizer(Session session, int size) {
|
||||
this.session = session;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception {
|
||||
int length = in.readableBytes();
|
||||
out.ensureWritable(this.session.getPacketProtocol().getPacketHeader().getLengthSize(length) + length);
|
||||
this.session.getPacketProtocol().getPacketHeader().writeLength(out, this.session.getCodecHelper(), length);
|
||||
out.writeBytes(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> out) throws Exception {
|
||||
buf.markReaderIndex();
|
||||
byte[] lengthBytes = new byte[size];
|
||||
for (int index = 0; index < lengthBytes.length; index++) {
|
||||
if (!buf.isReadable()) {
|
||||
buf.resetReaderIndex();
|
||||
return;
|
||||
}
|
||||
|
||||
lengthBytes[index] = buf.readByte();
|
||||
if ((this.session.getPacketProtocol().getPacketHeader().isLengthVariable() && lengthBytes[index] >= 0) || index == size - 1) {
|
||||
int length = this.session.getPacketProtocol().getPacketHeader().readLength(Unpooled.wrappedBuffer(lengthBytes), this.session.getCodecHelper(), buf.readableBytes());
|
||||
if (buf.readableBytes() < length) {
|
||||
buf.resetReaderIndex();
|
||||
return;
|
||||
}
|
||||
|
||||
out.add(buf.readBytes(length));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new CorruptedFrameException("Length is too long.");
|
||||
}
|
||||
}
|
184
src/main/java/com/github/steveice10/packetlib/tcp/TcpServer.java
Normal file
184
src/main/java/com/github/steveice10/packetlib/tcp/TcpServer.java
Normal file
|
@ -0,0 +1,184 @@
|
|||
package com.github.steveice10.packetlib.tcp;
|
||||
|
||||
import com.github.steveice10.packetlib.AbstractServer;
|
||||
import com.github.steveice10.packetlib.BuiltinFlags;
|
||||
import com.github.steveice10.packetlib.helper.TransportHelper;
|
||||
import com.github.steveice10.packetlib.packet.PacketProtocol;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.epoll.EpollEventLoopGroup;
|
||||
import io.netty.channel.epoll.EpollServerSocketChannel;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.kqueue.KQueueEventLoopGroup;
|
||||
import io.netty.channel.kqueue.KQueueServerSocketChannel;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.ServerSocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.incubator.channel.uring.IOUringEventLoopGroup;
|
||||
import io.netty.incubator.channel.uring.IOUringServerSocketChannel;
|
||||
import io.netty.util.concurrent.Future;
|
||||
import io.netty.util.concurrent.GenericFutureListener;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class TcpServer extends AbstractServer {
|
||||
private EventLoopGroup group;
|
||||
private Class<? extends ServerSocketChannel> serverSocketChannel;
|
||||
private Channel channel;
|
||||
|
||||
public TcpServer(String host, int port, Supplier<? extends PacketProtocol> protocol) {
|
||||
super(host, port, protocol);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isListening() {
|
||||
return this.channel != null && this.channel.isOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindImpl(boolean wait, final Runnable callback) {
|
||||
if(this.group != null || this.channel != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (TransportHelper.determineTransportMethod()) {
|
||||
case IO_URING:
|
||||
this.group = new IOUringEventLoopGroup();
|
||||
this.serverSocketChannel = IOUringServerSocketChannel.class;
|
||||
break;
|
||||
case EPOLL:
|
||||
this.group = new EpollEventLoopGroup();
|
||||
this.serverSocketChannel = EpollServerSocketChannel.class;
|
||||
break;
|
||||
case KQUEUE:
|
||||
this.group = new KQueueEventLoopGroup();
|
||||
this.serverSocketChannel = KQueueServerSocketChannel.class;
|
||||
break;
|
||||
case NIO:
|
||||
this.group = new NioEventLoopGroup();
|
||||
this.serverSocketChannel = NioServerSocketChannel.class;
|
||||
break;
|
||||
}
|
||||
|
||||
ChannelFuture future = new ServerBootstrap().channel(this.serverSocketChannel).childHandler(new ChannelInitializer<Channel>() {
|
||||
@Override
|
||||
public void initChannel(Channel channel) {
|
||||
InetSocketAddress address = (InetSocketAddress) channel.remoteAddress();
|
||||
PacketProtocol protocol = createPacketProtocol();
|
||||
|
||||
TcpSession session = new TcpServerSession(address.getHostName(), address.getPort(), protocol, TcpServer.this);
|
||||
session.getPacketProtocol().newServerSession(TcpServer.this, session);
|
||||
|
||||
channel.config().setOption(ChannelOption.IP_TOS, 0x18);
|
||||
try {
|
||||
channel.config().setOption(ChannelOption.TCP_NODELAY, true);
|
||||
} catch (ChannelException ignored) {
|
||||
}
|
||||
|
||||
ChannelPipeline pipeline = channel.pipeline();
|
||||
|
||||
session.refreshReadTimeoutHandler(channel);
|
||||
session.refreshWriteTimeoutHandler(channel);
|
||||
|
||||
int size = protocol.getPacketHeader().getLengthSize();
|
||||
if (size > 0) {
|
||||
pipeline.addLast("sizer", new TcpPacketSizer(session, size));
|
||||
}
|
||||
|
||||
pipeline.addLast("codec", new TcpPacketCodec(session, false));
|
||||
pipeline.addLast("manager", session);
|
||||
}
|
||||
}).group(this.group).localAddress(this.getHost(), this.getPort()).bind();
|
||||
|
||||
if(wait) {
|
||||
try {
|
||||
future.sync();
|
||||
} catch(InterruptedException e) {
|
||||
}
|
||||
|
||||
channel = future.channel();
|
||||
if(callback != null) {
|
||||
callback.run();
|
||||
}
|
||||
} else {
|
||||
future.addListener((ChannelFutureListener) future1 -> {
|
||||
if(future1.isSuccess()) {
|
||||
channel = future1.channel();
|
||||
if(callback != null) {
|
||||
callback.run();
|
||||
}
|
||||
} else {
|
||||
System.err.println("[ERROR] Failed to asynchronously bind connection listener.");
|
||||
if(future1.cause() != null) {
|
||||
future1.cause().printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeImpl(boolean wait, final Runnable callback) {
|
||||
if(this.channel != null) {
|
||||
if(this.channel.isOpen()) {
|
||||
ChannelFuture future = this.channel.close();
|
||||
if(wait) {
|
||||
try {
|
||||
future.sync();
|
||||
} catch(InterruptedException e) {
|
||||
}
|
||||
|
||||
if(callback != null) {
|
||||
callback.run();
|
||||
}
|
||||
} else {
|
||||
future.addListener((ChannelFutureListener) future1 -> {
|
||||
if(future1.isSuccess()) {
|
||||
if(callback != null) {
|
||||
callback.run();
|
||||
}
|
||||
} else {
|
||||
System.err.println("[ERROR] Failed to asynchronously close connection listener.");
|
||||
if(future1.cause() != null) {
|
||||
future1.cause().printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.channel = null;
|
||||
}
|
||||
|
||||
if(this.group != null) {
|
||||
Future<?> future = this.group.shutdownGracefully();
|
||||
if(wait) {
|
||||
try {
|
||||
future.sync();
|
||||
} catch(InterruptedException e) {
|
||||
}
|
||||
} else {
|
||||
future.addListener(new GenericFutureListener() {
|
||||
@Override
|
||||
public void operationComplete(Future future) {
|
||||
if(!future.isSuccess() && getGlobalFlag(BuiltinFlags.PRINT_DEBUG, false)) {
|
||||
System.err.println("[ERROR] Failed to asynchronously close connection listener.");
|
||||
if(future.cause() != null) {
|
||||
future.cause().printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.group = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package com.github.steveice10.packetlib.tcp;
|
||||
|
||||
import com.github.steveice10.packetlib.codec.PacketCodecHelper;
|
||||
import com.github.steveice10.packetlib.packet.PacketProtocol;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class TcpServerSession extends TcpSession {
|
||||
private final TcpServer server;
|
||||
private final PacketCodecHelper codecHelper;
|
||||
|
||||
public TcpServerSession(String host, int port, PacketProtocol protocol, TcpServer server) {
|
||||
super(host, port, protocol);
|
||||
this.server = server;
|
||||
this.codecHelper = protocol.createHelper();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketCodecHelper getCodecHelper() {
|
||||
return this.codecHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getFlags() {
|
||||
Map<String, Object> ret = new HashMap<>();
|
||||
ret.putAll(this.server.getGlobalFlags());
|
||||
ret.putAll(super.getFlags());
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFlag(String key) {
|
||||
if(super.hasFlag(key)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.server.hasGlobalFlag(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getFlag(String key, T def) {
|
||||
T ret = super.getFlag(key, null);
|
||||
if(ret != null) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return this.server.getGlobalFlag(key, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
super.channelActive(ctx);
|
||||
|
||||
this.server.addSession(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
super.channelInactive(ctx);
|
||||
|
||||
this.server.removeSession(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,391 @@
|
|||
package com.github.steveice10.packetlib.tcp;
|
||||
|
||||
import com.github.steveice10.packetlib.Session;
|
||||
import com.github.steveice10.packetlib.crypt.PacketEncryption;
|
||||
import com.github.steveice10.packetlib.event.session.ConnectedEvent;
|
||||
import com.github.steveice10.packetlib.event.session.DisconnectedEvent;
|
||||
import com.github.steveice10.packetlib.event.session.DisconnectingEvent;
|
||||
import com.github.steveice10.packetlib.event.session.PacketSendingEvent;
|
||||
import com.github.steveice10.packetlib.event.session.SessionEvent;
|
||||
import com.github.steveice10.packetlib.event.session.SessionListener;
|
||||
import com.github.steveice10.packetlib.packet.Packet;
|
||||
import com.github.steveice10.packetlib.packet.PacketProtocol;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.handler.timeout.ReadTimeoutException;
|
||||
import io.netty.handler.timeout.ReadTimeoutHandler;
|
||||
import io.netty.handler.timeout.WriteTimeoutException;
|
||||
import io.netty.handler.timeout.WriteTimeoutHandler;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.net.ConnectException;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
public abstract class TcpSession extends SimpleChannelInboundHandler<Packet> implements Session {
|
||||
/**
|
||||
* Controls whether non-priority packets are handled in a separate event loop
|
||||
*/
|
||||
public static boolean USE_EVENT_LOOP_FOR_PACKETS = true;
|
||||
private static EventLoopGroup PACKET_EVENT_LOOP;
|
||||
|
||||
protected String host;
|
||||
protected int port;
|
||||
private final PacketProtocol protocol;
|
||||
private final EventLoop eventLoop = createEventLoop();
|
||||
|
||||
private int compressionThreshold = -1;
|
||||
private int connectTimeout = 30;
|
||||
private int readTimeout = 30;
|
||||
private int writeTimeout = 0;
|
||||
|
||||
private final Map<String, Object> flags = new HashMap<>();
|
||||
private final List<SessionListener> listeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
private Channel channel;
|
||||
protected boolean disconnected = false;
|
||||
|
||||
public TcpSession(String host, int port, PacketProtocol protocol) {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect() {
|
||||
this.connect(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(boolean wait) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHost() {
|
||||
return this.host;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getLocalAddress() {
|
||||
return this.channel != null ? this.channel.localAddress() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getRemoteAddress() {
|
||||
return this.channel != null ? this.channel.remoteAddress() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketProtocol getPacketProtocol() {
|
||||
return this.protocol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getFlags() {
|
||||
return Collections.unmodifiableMap(this.flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFlag(String key) {
|
||||
return this.flags.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getFlag(String key) {
|
||||
return this.getFlag(key, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> T getFlag(String key, T def) {
|
||||
Object value = this.flags.get(key);
|
||||
if (value == null) {
|
||||
return def;
|
||||
}
|
||||
|
||||
try {
|
||||
return (T) value;
|
||||
} catch (ClassCastException e) {
|
||||
throw new IllegalStateException("Tried to get flag \"" + key + "\" as the wrong type. Actual type: " + value.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlag(String key, Object value) {
|
||||
this.flags.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SessionListener> getListeners() {
|
||||
return Collections.unmodifiableList(this.listeners);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(SessionListener listener) {
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(SessionListener listener) {
|
||||
this.listeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callEvent(SessionEvent event) {
|
||||
try {
|
||||
for (SessionListener listener : this.listeners) {
|
||||
event.call(listener);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
exceptionCaught(null, t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callPacketReceived(Packet packet) {
|
||||
try {
|
||||
for (SessionListener listener : this.listeners) {
|
||||
listener.packetReceived(this, packet);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
exceptionCaught(null, t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callPacketSent(Packet packet) {
|
||||
try {
|
||||
for (SessionListener listener : this.listeners) {
|
||||
listener.packetSent(this, packet);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
exceptionCaught(null, t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCompressionThreshold() {
|
||||
return this.compressionThreshold;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCompressionThreshold(int threshold, boolean validateDecompression) {
|
||||
this.compressionThreshold = threshold;
|
||||
if (this.channel != null) {
|
||||
if (this.compressionThreshold >= 0) {
|
||||
if (this.channel.pipeline().get("compression") == null) {
|
||||
this.channel.pipeline().addBefore("codec", "compression", new TcpPacketCompression(this, validateDecompression));
|
||||
}
|
||||
} else if (this.channel.pipeline().get("compression") != null) {
|
||||
this.channel.pipeline().remove("compression");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableEncryption(PacketEncryption encryption) {
|
||||
if (channel == null) {
|
||||
throw new IllegalStateException("Connect the client before initializing encryption!");
|
||||
}
|
||||
channel.pipeline().addBefore("sizer", "encryption", new TcpPacketEncryptor(encryption));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getConnectTimeout() {
|
||||
return this.connectTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConnectTimeout(int timeout) {
|
||||
this.connectTimeout = timeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getReadTimeout() {
|
||||
return this.readTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadTimeout(int timeout) {
|
||||
this.readTimeout = timeout;
|
||||
this.refreshReadTimeoutHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWriteTimeout() {
|
||||
return this.writeTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWriteTimeout(int timeout) {
|
||||
this.writeTimeout = timeout;
|
||||
this.refreshWriteTimeoutHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return this.channel != null && this.channel.isOpen() && !this.disconnected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Packet packet) {
|
||||
if(this.channel == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
PacketSendingEvent sendingEvent = new PacketSendingEvent(this, packet);
|
||||
this.callEvent(sendingEvent);
|
||||
|
||||
if (!sendingEvent.isCancelled()) {
|
||||
final Packet toSend = sendingEvent.getPacket();
|
||||
this.channel.writeAndFlush(toSend).addListener((ChannelFutureListener) future -> {
|
||||
if(future.isSuccess()) {
|
||||
callPacketSent(toSend);
|
||||
} else {
|
||||
exceptionCaught(null, future.cause());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(String reason) {
|
||||
this.disconnect(Component.text(reason));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(String reason, Throwable cause) {
|
||||
this.disconnect(Component.text(reason), cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(Component reason) {
|
||||
this.disconnect(reason, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(final Component reason, final Throwable cause) {
|
||||
if (this.disconnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.disconnected = true;
|
||||
|
||||
if (this.channel != null && this.channel.isOpen()) {
|
||||
this.callEvent(new DisconnectingEvent(this, reason, cause));
|
||||
this.channel.flush().close().addListener((ChannelFutureListener) future ->
|
||||
callEvent(new DisconnectedEvent(TcpSession.this,
|
||||
reason != null ? reason : Component.text("Connection closed."), cause)));
|
||||
} else {
|
||||
this.callEvent(new DisconnectedEvent(this, reason != null ? reason : Component.text("Connection closed."), cause));
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable EventLoop createEventLoop() {
|
||||
if (!USE_EVENT_LOOP_FOR_PACKETS) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (PACKET_EVENT_LOOP == null) {
|
||||
PACKET_EVENT_LOOP = new DefaultEventLoopGroup();
|
||||
}
|
||||
return PACKET_EVENT_LOOP.next();
|
||||
}
|
||||
|
||||
public Channel getChannel() {
|
||||
return this.channel;
|
||||
}
|
||||
|
||||
protected void refreshReadTimeoutHandler() {
|
||||
this.refreshReadTimeoutHandler(this.channel);
|
||||
}
|
||||
|
||||
protected void refreshReadTimeoutHandler(Channel channel) {
|
||||
if (channel != null) {
|
||||
if (this.readTimeout <= 0) {
|
||||
if (channel.pipeline().get("readTimeout") != null) {
|
||||
channel.pipeline().remove("readTimeout");
|
||||
}
|
||||
} else {
|
||||
if (channel.pipeline().get("readTimeout") == null) {
|
||||
channel.pipeline().addFirst("readTimeout", new ReadTimeoutHandler(this.readTimeout));
|
||||
} else {
|
||||
channel.pipeline().replace("readTimeout", "readTimeout", new ReadTimeoutHandler(this.readTimeout));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void refreshWriteTimeoutHandler() {
|
||||
this.refreshWriteTimeoutHandler(this.channel);
|
||||
}
|
||||
|
||||
protected void refreshWriteTimeoutHandler(Channel channel) {
|
||||
if (channel != null) {
|
||||
if (this.writeTimeout <= 0) {
|
||||
if (channel.pipeline().get("writeTimeout") != null) {
|
||||
channel.pipeline().remove("writeTimeout");
|
||||
}
|
||||
} else {
|
||||
if (channel.pipeline().get("writeTimeout") == null) {
|
||||
channel.pipeline().addFirst("writeTimeout", new WriteTimeoutHandler(this.writeTimeout));
|
||||
} else {
|
||||
channel.pipeline().replace("writeTimeout", "writeTimeout", new WriteTimeoutHandler(this.writeTimeout));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
if (this.disconnected || this.channel != null) {
|
||||
ctx.channel().close();
|
||||
return;
|
||||
}
|
||||
|
||||
this.channel = ctx.channel();
|
||||
|
||||
this.callEvent(new ConnectedEvent(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
if (ctx.channel() == this.channel) {
|
||||
this.disconnect("Connection closed.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
String message;
|
||||
if (cause instanceof ConnectTimeoutException || (cause instanceof ConnectException && cause.getMessage().contains("connection timed out"))) {
|
||||
message = "Connection timed out.";
|
||||
} else if (cause instanceof ReadTimeoutException) {
|
||||
message = "Read timed out.";
|
||||
} else if (cause instanceof WriteTimeoutException) {
|
||||
message = "Write timed out.";
|
||||
} else {
|
||||
message = cause.toString();
|
||||
}
|
||||
|
||||
this.disconnect(message, cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, Packet packet) {
|
||||
if (!packet.isPriority() && eventLoop != null) {
|
||||
eventLoop.execute(() -> this.callPacketReceived(packet));
|
||||
} else {
|
||||
this.callPacketReceived(packet);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
package com.github.steveice10.mc.protocol;
|
||||
|
||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
||||
import com.github.steveice10.mc.protocol.codec.MinecraftCodec;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||
import com.github.steveice10.mc.protocol.data.status.PlayerInfo;
|
||||
|
@ -27,6 +26,7 @@ import java.io.DataInput;
|
|||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
|
@ -46,7 +46,7 @@ public class MinecraftProtocolTest {
|
|||
|
||||
private static final ServerStatusInfo SERVER_INFO = new ServerStatusInfo(
|
||||
new VersionInfo(MinecraftCodec.CODEC.getMinecraftVersion(), MinecraftCodec.CODEC.getProtocolVersion()),
|
||||
new PlayerInfo(100, 0, new GameProfile[0]),
|
||||
new PlayerInfo(100, 0, new ArrayList<>()),
|
||||
Component.text("Hello world!"),
|
||||
null,
|
||||
false
|
||||
|
|
|
@ -8,7 +8,8 @@ import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType;
|
|||
import com.github.steveice10.mc.protocol.data.game.recipe.data.CookedRecipeData;
|
||||
import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData;
|
||||
import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData;
|
||||
import com.github.steveice10.mc.protocol.data.game.recipe.data.SmithingRecipeData;
|
||||
import com.github.steveice10.mc.protocol.data.game.recipe.data.LegacyUpgradeRecipeData;
|
||||
import com.github.steveice10.mc.protocol.data.game.recipe.data.SmithingTransformRecipeData;
|
||||
import com.github.steveice10.mc.protocol.data.game.recipe.data.StoneCuttingRecipeData;
|
||||
import com.github.steveice10.mc.protocol.packet.PacketTest;
|
||||
import org.junit.Before;
|
||||
|
@ -93,7 +94,7 @@ public class ServerDeclareRecipesTest extends PacketTest {
|
|||
new Recipe(
|
||||
RecipeType.SMITHING,
|
||||
"minecraft:Recipe5",
|
||||
new SmithingRecipeData(
|
||||
new LegacyUpgradeRecipeData(
|
||||
new Ingredient(new ItemStack[]{
|
||||
new ItemStack(10)
|
||||
}),
|
||||
|
|
|
@ -2,7 +2,12 @@ package com.github.steveice10.mc.protocol.packet.ingame.clientbound.level;
|
|||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.*;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.LongEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.object.Direction;
|
||||
import com.github.steveice10.mc.protocol.packet.PacketTest;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundSetEntityDataPacket;
|
||||
|
@ -27,7 +32,7 @@ public class ClientboundSetEntityDataPacketTest extends PacketTest {
|
|||
new FloatEntityMetadata(3, MetadataType.FLOAT, 3.0f),
|
||||
new LongEntityMetadata(8, MetadataType.LONG, 123456789L),
|
||||
new ObjectEntityMetadata<>(5, MetadataType.POSITION, Vector3i.from(0, 1, 0)),
|
||||
new ObjectEntityMetadata<>(2, MetadataType.BLOCK_STATE, OptionalInt.of(60)),
|
||||
new ObjectEntityMetadata<>(2, MetadataType.BLOCK_STATE, 60),
|
||||
new ObjectEntityMetadata<>(6, MetadataType.DIRECTION, Direction.EAST),
|
||||
new ObjectEntityMetadata<>(7, MetadataType.OPTIONAL_VARINT, OptionalInt.of(1038))
|
||||
}),
|
||||
|
|
|
@ -9,6 +9,8 @@ import com.github.steveice10.mc.protocol.packet.PacketTest;
|
|||
import net.kyori.adventure.text.Component;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ClientboundStatusResponsePacketTest extends PacketTest {
|
||||
|
@ -17,9 +19,9 @@ public class ClientboundStatusResponsePacketTest extends PacketTest {
|
|||
this.setPackets(new ClientboundStatusResponsePacket(
|
||||
new ServerStatusInfo(
|
||||
new VersionInfo(MinecraftCodec.CODEC.getMinecraftVersion(), MinecraftCodec.CODEC.getProtocolVersion()),
|
||||
new PlayerInfo(100, 10, new GameProfile[]{
|
||||
new GameProfile(UUID.randomUUID(), "Username")
|
||||
}),
|
||||
new PlayerInfo(100, 10, new ArrayList<>(
|
||||
Collections.singleton(new GameProfile(UUID.randomUUID(), "Username"))
|
||||
)),
|
||||
Component.text("Description"),
|
||||
null,
|
||||
false
|
||||
|
|
Binary file not shown.
Loading…
Reference in a new issue