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
|
|
|
}
|