Files
Protocol/src/main/java/org/openautonomousconnection/protocol/packets/OACPacket.java

167 lines
5.6 KiB
Java
Raw Normal View History

2025-09-24 22:02:10 +02:00
package org.openautonomousconnection.protocol.packets;
2025-09-19 21:27:35 +02:00
2025-09-24 22:02:10 +02:00
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
2025-09-25 23:41:17 +02:00
import lombok.Getter;
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
2025-12-11 01:22:58 +01:00
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSResponseStatus;
2025-09-20 19:55:28 +02:00
2026-02-06 17:59:04 +01:00
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
2026-02-11 23:11:33 +01:00
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
2025-09-19 21:27:35 +02:00
2025-09-29 17:46:30 +02:00
/**
* Abstract class representing a packet in the Open Autonomous Connection (OAC) protocol.
* This class extends the base Packet class and includes additional functionality specific to OAC.
*/
2025-09-19 21:27:35 +02:00
public abstract class OACPacket extends Packet {
2025-09-20 19:55:28 +02:00
2025-09-29 17:46:30 +02:00
/**
* The protocol version associated with this packet.
*/
2025-09-19 21:27:35 +02:00
@Getter
2025-09-20 15:17:36 +02:00
private final ProtocolVersion protocolVersion;
2026-02-06 17:59:04 +01:00
private final int id;
2025-09-29 17:46:30 +02:00
/**
* The response code for the packet, defaulting to RESPONSE_NOT_REQUIRED.
*/
2025-12-11 01:22:58 +01:00
private INSResponseStatus responseCode = INSResponseStatus.RESPONSE_NOT_REQUIRED;
2025-09-20 19:55:28 +02:00
2025-09-29 17:46:30 +02:00
/**
* Constructor for OACPacket.
2025-09-29 18:46:31 +02:00
*
2025-09-29 17:46:30 +02:00
* @param id The unique identifier for the packet.
* @param protocolVersion The protocol version associated with this packet.
*/
2025-09-20 20:42:58 +02:00
public OACPacket(int id, ProtocolVersion protocolVersion) {
this.id = id;
2025-09-20 20:42:58 +02:00
this.protocolVersion = protocolVersion;
2025-09-20 19:55:28 +02:00
}
2026-02-06 17:59:04 +01:00
@Override
public int getPacketID() {
return id;
}
2025-09-29 17:46:30 +02:00
/**
* Gets the response code for the packet.
2025-09-29 18:46:31 +02:00
*
2025-12-08 09:59:58 +01:00
* @return The INSResponseCode associated with the packet.
2025-09-29 17:46:30 +02:00
*/
2025-12-11 01:22:58 +01:00
protected final INSResponseStatus getResponseCode() {
2025-09-20 19:55:28 +02:00
return responseCode;
}
2025-09-29 17:46:30 +02:00
/**
* Sets the response code for the packet.
2025-09-29 18:46:31 +02:00
*
2025-12-08 09:59:58 +01:00
* @param responseCode The INSResponseCode to set for the packet.
2025-09-29 17:46:30 +02:00
*/
2025-12-11 01:22:58 +01:00
protected final void setResponseCode(INSResponseStatus responseCode) {
2025-09-20 20:42:58 +02:00
this.responseCode = responseCode;
2025-09-19 21:27:35 +02:00
}
2025-09-20 19:55:28 +02:00
2025-09-29 17:46:30 +02:00
/**
* Writes the packet data to the output stream.
2025-09-29 18:46:31 +02:00
*
* @param outputStream The output stream to write the packet data to.
2026-02-06 17:59:04 +01:00
* @throws IOException If an I/O error occurs.
2025-09-29 17:46:30 +02:00
*/
2025-09-20 19:55:28 +02:00
@Override
public final void write(DataOutputStream outputStream) throws IOException {
2025-09-29 17:46:30 +02:00
// Write the specific packet data
onWrite(outputStream);
2025-09-29 17:46:30 +02:00
// Write the response code if the protocol version is not classic
if (protocolVersion != ProtocolVersion.PV_1_0_0_CLASSIC) outputStream.writeUTF(responseCode.name());
2025-09-20 19:55:28 +02:00
}
@Override
public final void read(DataInputStream inputStream, UUID clientID) throws IOException {
2025-09-29 17:46:30 +02:00
// Read the specific packet data
onRead(inputStream, clientID);
2025-09-29 17:46:30 +02:00
// Read the response code if the protocol version is not classic
2025-09-29 18:46:31 +02:00
if (protocolVersion != ProtocolVersion.PV_1_0_0_CLASSIC)
responseCode = INSResponseStatus.valueOf(inputStream.readUTF());
2025-12-11 01:22:58 +01:00
else responseCode = INSResponseStatus.RESPONSE_NOT_REQUIRED;
2025-09-29 17:46:30 +02:00
// Call the response code read handler
onResponseCodeRead(inputStream, clientID);
2025-09-20 19:55:28 +02:00
}
2025-09-29 17:46:30 +02:00
/**
* Abstract method to be implemented by subclasses for writing specific packet data.
2025-09-29 18:46:31 +02:00
*
* @param outputStream The output stream to write the packet data to.
2026-02-06 17:59:04 +01:00
* @throws IOException If an I/O error occurs.
2025-09-29 17:46:30 +02:00
*/
public abstract void onWrite(DataOutputStream outputStream) throws IOException;
2025-09-20 20:42:58 +02:00
2025-09-29 17:46:30 +02:00
/**
* Abstract method to be implemented by subclasses for reading specific packet data.
2025-09-29 18:46:31 +02:00
*
* @param inputStream The input stream to read the packet data from.
2026-02-06 17:59:04 +01:00
* @throws IOException If an I/O error occurs.
2025-09-29 17:46:30 +02:00
*/
public abstract void onRead(DataInputStream inputStream, UUID clientID) throws IOException;
2025-09-20 20:42:58 +02:00
2025-09-29 17:46:30 +02:00
/**
* Method called after the response code has been read from the input stream.
* Subclasses can override this method to handle any additional logic based on the response code.
2025-09-29 18:46:31 +02:00
*
* @param inputStream The input stream from which the response code was read.
2025-09-29 17:46:30 +02:00
*/
protected void onResponseCodeRead(DataInputStream inputStream, UUID clientID) {
2025-09-29 18:46:31 +02:00
}
2026-02-11 23:11:33 +01:00
/**
* Writes a string map in a deterministic way (no Java object serialization).
*
* @param out output stream
* @param map map to write (may be null)
* @throws IOException on I/O errors
*/
protected final void writeStringMap(DataOutputStream out, Map<String, String> map) throws IOException {
if (map == null || map.isEmpty()) {
out.writeInt(0);
return;
}
out.writeInt(map.size());
for (Map.Entry<String, String> e : map.entrySet()) {
// Null keys/values are normalized to empty strings to keep the wire format stable.
out.writeUTF((e.getKey() != null) ? e.getKey() : "");
out.writeUTF((e.getValue() != null) ? e.getValue() : "");
}
}
/**
* Reads a string map in a deterministic way (no Java object serialization).
*
* @param in input stream
* @return headers map (never null)
* @throws IOException on I/O errors / invalid sizes
*/
protected final Map<String, String> readStringMap(DataInputStream in) throws IOException {
int size = in.readInt();
if (size < 0) {
throw new IOException("Negative map size");
}
if (size == 0) {
return Collections.emptyMap();
}
Map<String, String> map = new LinkedHashMap<>(Math.max(16, size * 2));
for (int i = 0; i < size; i++) {
String key = in.readUTF();
String value = in.readUTF();
map.put(key, value);
}
return map;
}
2025-09-19 21:27:35 +02:00
}