Skip to content

Commit

Permalink
v1.0.13
Browse files Browse the repository at this point in the history
  • Loading branch information
pwaillette committed Dec 29, 2023
1 parent 515eb15 commit b18b98b
Show file tree
Hide file tree
Showing 13 changed files with 194 additions and 176 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ plugins {
}

group = "com.stmarygate"
version = "1.0.12"
version = "1.0.13"

repositories {
mavenCentral()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

import com.stmarygate.coral.network.codec.PacketDecoder;
import com.stmarygate.coral.network.codec.PacketEncoder;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
Expand Down
14 changes: 11 additions & 3 deletions src/main/java/com/stmarygate/coral/network/ClientSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

import com.stmarygate.coral.network.packets.Packet;
import io.netty.channel.Channel;

import java.util.Arrays;

/**
* Represents a session associated with a client's communication channel. It provides methods to
* send packets to the client and close the communication {@link Channel} associated with the client.
* send packets to the client and close the communication {@link Channel} associated with the
* client.
*/
public class ClientSession {
/** The communication channel associated with the client session. */
Expand All @@ -32,7 +32,15 @@ public void write(Packet packet) throws Exception {
try {
this.channel.writeAndFlush(packet);
} catch (Exception e) {
throw new Exception("Error writing packet " + packet.getClass().getSimpleName() + " to client " + this.channel.remoteAddress().toString() + "\nError:\n" + e.getMessage() + "\n" + Arrays.toString(e.getStackTrace()));
throw new Exception(
"Error writing packet "
+ packet.getClass().getSimpleName()
+ " to client "
+ this.channel.remoteAddress().toString()
+ "\nError:\n"
+ e.getMessage()
+ "\n"
+ Arrays.toString(e.getStackTrace()));
}
}

Expand Down
9 changes: 7 additions & 2 deletions src/main/java/com/stmarygate/coral/network/PacketHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

Expand All @@ -24,7 +23,13 @@ public void handlePacket(Packet packet) throws Exception {
Method method = findHandlerMethod(packet);
method.invoke(this, packet);
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
throw new Exception("Error handling incoming packet " + packet.getClass().getSimpleName() + "\nError:\n" + e.getMessage() + "\n" + Arrays.toString(e.getStackTrace()));
throw new Exception(
"Error handling incoming packet "
+ packet.getClass().getSimpleName()
+ "\nError:\n"
+ e.getMessage()
+ "\n"
+ Arrays.toString(e.getStackTrace()));
}
}

Expand Down
94 changes: 46 additions & 48 deletions src/main/java/com/stmarygate/coral/network/codec/PacketDecoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,41 +10,36 @@
import java.util.List;

/**
* <p>The {@code PacketDecoder} class is responsible for decoding raw bytes received over the network
* into instances of the {@link Packet} class. It extends {@link MessageToMessageDecoder} to integrate
* with Netty's decoding pipeline.
* The {@code PacketDecoder} class is responsible for decoding raw bytes received over the network
* into instances of the {@link Packet} class. It extends {@link MessageToMessageDecoder} to
* integrate with Netty's decoding pipeline.
*
* <p>This decoder works by maintaining an internal {@link ByteBuf} buffer to accumulate incoming bytes
* until there is enough data to construct a complete packet. The decoding process involves reading
* the packet ID and size from the buffer, then verifying if there is sufficient data to construct
* the entire packet. If enough data is available, the packet is created using the {@link Protocol}
* and {@link PacketBuffer}, and the decoded packet is added to the output list for further processing.
* <p>This decoder works by maintaining an internal {@link ByteBuf} buffer to accumulate incoming
* bytes until there is enough data to construct a complete packet. The decoding process involves
* reading the packet ID and size from the buffer, then verifying if there is sufficient data to
* construct the entire packet. If enough data is available, the packet is created using the {@link
* Protocol} and {@link PacketBuffer}, and the decoded packet is added to the output list for
* further processing.
*
* <p>The decoding process is performed in a loop to handle multiple packets in the input buffer, and the
* remaining bytes are retained in the buffer for subsequent decoding attempts.
* <p>The decoding process is performed in a loop to handle multiple packets in the input buffer,
* and the remaining bytes are retained in the buffer for subsequent decoding attempts.
*
* <p><strong>Example usage:</strong>
* ```java
* // Create an instance of PacketDecoder
* PacketDecoder packetDecoder = new PacketDecoder();
* <p><strong>Example usage:</strong> ```java // Create an instance of PacketDecoder PacketDecoder
* packetDecoder = new PacketDecoder();
*
* <p>// Assume 'inputBytes' is a ByteBuf containing received network data
* List<Object> outputPackets = new ArrayList<>();
* packetDecoder.decode(ctx, inputBytes, outputPackets);
* <p>// Assume 'inputBytes' is a ByteBuf containing received network data List<Object>
* outputPackets = new ArrayList<>(); packetDecoder.decode(ctx, inputBytes, outputPackets);
*
* <p>// Process the decoded packets in 'outputPackets'
* ```
* <p>// Process the decoded packets in 'outputPackets' ```
*
* <p>Note: It's crucial to properly release resources in Netty, especially ByteBuf instances, to prevent memory leaks.
* Ensure that the {@code decode} method is called with sufficient frequency to handle incoming data and release
* the retained ByteBuf instances appropriately.
* <p>Note: It's crucial to properly release resources in Netty, especially ByteBuf instances, to
* prevent memory leaks. Ensure that the {@code decode} method is called with sufficient frequency
* to handle incoming data and release the retained ByteBuf instances appropriately.
*/
public class PacketDecoder extends MessageToMessageDecoder<ByteBuf> {
private ByteBuf buffer;

/**
* Constructs a new {@code PacketDecoder}.
*/
/** Constructs a new {@code PacketDecoder}. */
public PacketDecoder() {}

/**
Expand All @@ -57,37 +52,40 @@ public PacketDecoder() {}
*/
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
// Duplicate and retain the incoming buffer for manipulation
if (this.buffer == null || this.buffer.readableBytes() == 0) {
this.buffer = msg.duplicate().retain();
} else {
this.buffer = Unpooled.copiedBuffer(this.buffer, msg).retain();
}
// Duplicate and retain the incoming buffer for manipulation
if (this.buffer == null || this.buffer.readableBytes() == 0) {
this.buffer = msg.duplicate().retain();
} else {
this.buffer = Unpooled.copiedBuffer(this.buffer, msg).retain();
}

// Continue decoding while there is enough data in the buffer
while (this.buffer.readableBytes() > Packet.HEADER_SIZE) {
int id = this.buffer.readShort();
int size = this.buffer.readShort();
// Continue decoding while there is enough data in the buffer
while (this.buffer.readableBytes() > Packet.HEADER_SIZE) {
int id = this.buffer.readShort();
int size = this.buffer.readShort();

// Check if there is enough data to read the entire packet
if (size > this.buffer.readableBytes()) {
// Not enough data to read the packet, wait for more data
return;
}
// Check if there is enough data to read the entire packet
if (size > this.buffer.readableBytes()) {
// Not enough data to read the packet, wait for more data
return;
}

// Reset the reader index to the beginning of the packet
this.buffer.resetReaderIndex();
// Reset the reader index to the beginning of the packet
this.buffer.resetReaderIndex();

// Read a slice of the buffer containing the entire packet. The size add the header size because size dosn't include the header size
ByteBuf slice = this.buffer.readSlice(size + Packet.HEADER_SIZE);
// Read a slice of the buffer containing the entire packet. The size add the header size
// because size dosn't include the header size
ByteBuf slice = this.buffer.readSlice(size + Packet.HEADER_SIZE);

// Create a new packet instance using the Protocol and PacketBuffer
Packet packet = Protocol.getInstance().getPacket(id);
// Create a new packet instance using the Protocol and PacketBuffer
Packet packet = Protocol.getInstance().getPacket(id);
if (packet != null) {
packet.decode(new PacketBuffer(slice, id, Packet.PacketAction.READ));

// Add the decoded packet to the output list
out.add(packet);
} else {
break;
}
}
}
}

34 changes: 17 additions & 17 deletions src/main/java/com/stmarygate/coral/network/codec/PacketEncoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,27 @@
* integration with Netty's encoding pipeline.
*
* <p>This encoder works by calling the {@link Packet#encode(PacketBuffer)} method on the provided
* {@link Packet} instance, creating a {@link PacketBuffer} to write the encoded data into the specified
* {@link ByteBuf} (output buffer). The encoded packet is then flushed to the network channel for transmission.
* {@link Packet} instance, creating a {@link PacketBuffer} to write the encoded data into the
* specified {@link ByteBuf} (output buffer). The encoded packet is then flushed to the network
* channel for transmission.
*
* <p>The encoding process involves creating a {@link PacketBuffer} initialized with the output buffer,
* the packet's ID, and the action type (in this case, {@link Packet.PacketAction#WRITE}). The packet's
* encode method writes the packet's data into the buffer. The resulting byte stream is then flushed
* to the network channel.
* <p>The encoding process involves creating a {@link PacketBuffer} initialized with the output
* buffer, the packet's ID, and the action type (in this case, {@link Packet.PacketAction#WRITE}).
* The packet's encode method writes the packet's data into the buffer. The resulting byte stream is
* then flushed to the network channel.
*
* <p><strong>Usage:</strong>
* To use this encoder, add an instance of {@code PacketEncoder} to the Netty pipeline in your Netty
* server or client bootstrap configuration.
* <p><strong>Usage:</strong> To use this encoder, add an instance of {@code PacketEncoder} to the
* Netty pipeline in your Netty server or client bootstrap configuration.
*
* <pre>{@code
* ChannelPipeline pipeline = ch.pipeline();
* pipeline.addLast("encoder", new PacketEncoder());
* // ... add other handlers to the pipeline
* }</pre>
*
* <p><strong>Example:</strong>
* Suppose you have a custom packet class named {@code MyPacket} that extends {@link Packet}. When you send
* an instance of {@code MyPacket} over the network, the {@code PacketEncoder} will handle the encoding
* process automatically.
* <p><strong>Example:</strong> Suppose you have a custom packet class named {@code MyPacket} that
* extends {@link Packet}. When you send an instance of {@code MyPacket} over the network, the
* {@code PacketEncoder} will handle the encoding process automatically.
*
* <pre>{@code
* MyPacket myPacket = new MyPacket(); // create an instance of your custom packet
Expand All @@ -49,8 +48,8 @@
public class PacketEncoder extends MessageToByteEncoder<Packet> {

/**
* Constructs a new {@code PacketEncoder} instance. This constructor sets the target class
* for encoding to {@link Packet}.
* Constructs a new {@code PacketEncoder} instance. This constructor sets the target class for
* encoding to {@link Packet}.
*/
public PacketEncoder() {
super(Packet.class);
Expand All @@ -68,11 +67,12 @@ public PacketEncoder() {
@Override
protected void encode(ChannelHandlerContext ctx, Packet msg, ByteBuf out) throws Exception {
try {
msg.encode(new PacketBuffer(out, Protocol.getInstance().getPacketId(msg), Packet.PacketAction.WRITE));
msg.encode(
new PacketBuffer(
out, Protocol.getInstance().getPacketId(msg), Packet.PacketAction.WRITE));
ctx.channel().flush();
} catch (Exception e) {
throw new Exception(e.getMessage(), e.getCause());
}
}
}

21 changes: 5 additions & 16 deletions src/main/java/com/stmarygate/coral/network/packets/Packet.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,9 @@

import com.stmarygate.coral.network.PacketHandler;

/**
* Represents a generic packet in the network communication.
*/
/** Represents a generic packet in the network communication. */
public class Packet {
/**
* The size of the packet header in bytes.
*/
/** The size of the packet header in bytes. */
public static final int HEADER_SIZE = 4;

/**
Expand Down Expand Up @@ -39,19 +35,12 @@ public void handle(PacketHandler handler) throws Exception {
// Implementation specific to each packet type.
}

/**
* Enum representing the action type of packet (READ or WRITE).
*/
/** Enum representing the action type of packet (READ or WRITE). */
public enum PacketAction {
/**
* Indicates a packet is being read.
*/
/** Indicates a packet is being read. */
READ,

/**
* Indicates a packet is being written.
*/
/** Indicates a packet is being written. */
WRITE
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.stmarygate.coral.network.packets.client.PacketLoginUsingCredentials;
import com.stmarygate.coral.network.packets.client.PacketVersion;
import com.stmarygate.coral.network.packets.server.PacketVersionResult;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
Expand Down Expand Up @@ -90,8 +89,8 @@ public Packet getPacket(int id)
IllegalAccessException,
NoSuchMethodException,
InvocationTargetException {
if (!PACKETS_MAP.containsKey(id))
throw new RuntimeException("Packet with id " + id + " is not registered.");
if (!PACKETS_MAP.containsKey(id)) return null;
// throw new RuntimeException("Packet with id " + id + " is not registered.");
return PACKETS_MAP.get(id).getDeclaredConstructor().newInstance();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ public PacketLoginUsingCredentials(String username, String password) {
if (username.isEmpty() && password.isEmpty()) return;
this.username = username;

Argon2PasswordEncoder argon2PasswordEncoder = new Argon2PasswordEncoder(
16, // saltLength
64, // hashLength
8, // parallelism (e.g., number of CPU cores)
65536, // memory in kilobytes
4 // iterations
);
Argon2PasswordEncoder argon2PasswordEncoder =
new Argon2PasswordEncoder(
16, // saltLength
64, // hashLength
8, // parallelism (e.g., number of CPU cores)
65536, // memory in kilobytes
4 // iterations
);

this.password = password;
this.encodedPassword = argon2PasswordEncoder.encode(password);
Expand Down
Loading

0 comments on commit b18b98b

Please sign in to comment.