Files
CustomNPC-Plus/src/main/java/kamkeel/npcs/network/LargeAbstractPacket.java
T

161 lines
5.7 KiB
Java
Raw Normal View History

2025-01-29 13:20:04 -05:00
package kamkeel.npcs.network;
2025-01-29 15:04:19 -05:00
2025-01-29 18:25:34 -05:00
import cpw.mods.fml.common.network.internal.FMLProxyPacket;
2025-01-28 18:14:18 -05:00
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minecraft.entity.player.EntityPlayer;
2025-01-30 22:50:10 -05:00
import noppes.npcs.LogWriter;
2025-01-28 18:14:18 -05:00
import java.io.IOException;
2025-01-29 18:25:34 -05:00
import java.util.ArrayList;
import java.util.List;
2025-01-28 18:14:18 -05:00
import java.util.Map;
2025-01-28 18:25:30 -05:00
import java.util.UUID;
2025-01-29 15:04:19 -05:00
import java.util.concurrent.ConcurrentHashMap;
2025-01-28 18:14:18 -05:00
public abstract class LargeAbstractPacket extends AbstractPacket {
2025-01-29 15:04:19 -05:00
private static final Map<UUID, PacketStorage> packetChunks = new ConcurrentHashMap<>();
2025-01-29 18:25:34 -05:00
private static final int CHUNK_SIZE = 10000;
2025-01-28 18:14:18 -05:00
2025-01-29 18:25:34 -05:00
/**
* Create multiple FMLProxyPacket objects, each containing up to CHUNK_SIZE bytes.
*/
2025-01-28 18:14:18 -05:00
@Override
2025-01-29 18:25:34 -05:00
public List<FMLProxyPacket> generatePackets() {
List<FMLProxyPacket> packets = new ArrayList<>();
PacketChannel packetChannel = getChannel();
byte[] fullData;
try {
fullData = getData();
} catch (IOException e) {
e.printStackTrace();
return packets;
}
int totalSize = fullData.length;
2025-01-29 15:04:19 -05:00
UUID packetId = UUID.randomUUID();
2025-01-29 18:25:34 -05:00
// Break data into CHUNK_SIZE chunks
2025-01-29 15:04:19 -05:00
for (int offset = 0; offset < totalSize; offset += CHUNK_SIZE) {
int chunkSize = Math.min(CHUNK_SIZE, totalSize - offset);
2025-01-29 18:25:34 -05:00
ByteBuf chunkBuf = Unpooled.buffer();
chunkBuf.writeInt(packetChannel.getChannelType().ordinal());
chunkBuf.writeInt(getType().ordinal());
2025-01-29 15:04:19 -05:00
2025-01-29 18:25:34 -05:00
chunkBuf.writeLong(packetId.getMostSignificantBits());
chunkBuf.writeLong(packetId.getLeastSignificantBits());
chunkBuf.writeInt(totalSize);
chunkBuf.writeInt(offset);
chunkBuf.writeInt((totalSize + CHUNK_SIZE - 1) / CHUNK_SIZE);
2025-01-29 15:04:19 -05:00
2025-01-29 18:25:34 -05:00
chunkBuf.writeBytes(fullData, offset, chunkSize);
FMLProxyPacket proxyPacket = new FMLProxyPacket(chunkBuf, packetChannel.getChannelName());
packets.add(proxyPacket);
2025-01-28 18:14:18 -05:00
}
2025-01-29 18:25:34 -05:00
return packets;
2025-01-28 18:14:18 -05:00
}
@Override
public void receiveData(ByteBuf in, EntityPlayer player) throws IOException {
2025-01-30 22:50:10 -05:00
UUID packetId = null;
PacketStorage storage = null;
ByteBuf chunk = null;
ByteBuf completeData = null;
2025-01-29 15:04:19 -05:00
2025-01-30 22:50:10 -05:00
try {
// Read UUID from the buffer
long mostSigBits = in.readLong();
long leastSigBits = in.readLong();
packetId = new UUID(mostSigBits, leastSigBits);
// Read packet metadata
int totalSize = in.readInt();
int offset = in.readInt();
int totalChunks = in.readInt(); // Debugging info
int chunkSize = Math.min(CHUNK_SIZE, totalSize - offset);
2025-01-28 18:14:18 -05:00
2025-01-30 22:50:10 -05:00
// Basic validation to ensure the chunk won't overwrite out of bounds
if (chunkSize <= 0 || offset < 0 || (offset + chunkSize) > totalSize) {
throw new IndexOutOfBoundsException("Invalid chunk size/offset: chunkSize="
+ chunkSize + ", offset=" + offset + ", totalSize=" + totalSize);
}
// Read the exact chunk data
chunk = in.readBytes(chunkSize);
// Store the received chunk in a PacketStorage
storage = packetChunks.computeIfAbsent(packetId, k -> new PacketStorage(Unpooled.buffer(totalSize), 0, totalSize));
// Write this chunk into the buffer at the correct offset
storage.data.setBytes(offset, chunk);
storage.receivedSoFar += chunkSize;
// If we've received all bytes, finalize
if (storage.receivedSoFar >= totalSize) {
packetChunks.remove(packetId);
completeData = storage.data.copy(0, totalSize);
try {
handleCompleteData(completeData, player);
} finally {
completeData.release();
}
storage.data.release();
}
} catch (Exception e) {
// Log the exception with contextual information
LogWriter.error("Error in receiveData for packetId " + (packetId != null ? packetId.toString() : "null") + ": " + e.getMessage());
e.printStackTrace();
2025-01-29 15:04:19 -05:00
2025-01-30 22:50:10 -05:00
// If storage was created but the packet is incomplete, release storage.data
if (storage != null && storage.receivedSoFar < storage.totalSize) {
storage.data.release();
if (packetId != null) {
packetChunks.remove(packetId);
}
}
throw e; // Rethrow the exception after logging
} finally {
// Ensure that 'chunk' is released if it was allocated
if (chunk != null && chunk.refCnt() > 0) {
chunk.release();
}
// Ensure that 'completeData' is released if it was created and not yet released
if (completeData != null && completeData.refCnt() > 0) {
completeData.release();
}
2025-01-29 13:28:14 -05:00
}
}
2025-01-29 15:04:19 -05:00
protected abstract byte[] getData() throws IOException;
protected abstract void handleCompleteData(ByteBuf data, EntityPlayer player) throws IOException;
2025-01-29 18:25:34 -05:00
@Override
public final FMLProxyPacket generatePacket() {return null;}
@Override
public void sendData(ByteBuf out) throws IOException {}
2025-01-29 15:04:19 -05:00
/**
* Simple storage class to keep track of partial data and how many bytes we've received so far.
*/
private static class PacketStorage {
final ByteBuf data;
int receivedSoFar;
final int totalSize;
2025-01-28 18:25:30 -05:00
2025-01-29 15:04:19 -05:00
PacketStorage(ByteBuf data, int receivedSoFar, int totalSize) {
this.data = data;
this.receivedSoFar = receivedSoFar;
this.totalSize = totalSize;
}
}
2025-01-28 18:14:18 -05:00
}