Last active
August 29, 2015 14:02
-
-
Save aadnk/e5906a3af254b88924cb to your computer and use it in GitHub Desktop.
Recieve custom data through ping packets. See https://gist.github.com/aadnk/59756145619d076ccd04 in order to test this.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.comphenix.example; | |
import java.io.ByteArrayOutputStream; | |
import java.io.DataOutputStream; | |
import java.io.IOException; | |
import java.util.Arrays; | |
import java.util.concurrent.ConcurrentMap; | |
import org.bukkit.entity.Player; | |
import org.bukkit.plugin.java.JavaPlugin; | |
import com.comphenix.protocol.PacketType; | |
import com.comphenix.protocol.ProtocolLibrary; | |
import com.comphenix.protocol.events.PacketAdapter; | |
import com.comphenix.protocol.events.PacketEvent; | |
import com.google.common.collect.MapMaker; | |
import com.google.common.primitives.Bytes; | |
public class ExampleMod extends JavaPlugin { | |
private static final long MAGIC_START = 0x1C5FEEC587C1C8C5L; | |
@Override | |
public void onEnable() { | |
ProtocolLibrary.getProtocolManager().addPacketListener( | |
new PacketAdapter(this, PacketType.Status.Client.IN_PING) { | |
private ConcurrentMap<Player, CustomDataState> buffers = new MapMaker().weakKeys().makeMap(); | |
@Override | |
public void onPacketReceiving(PacketEvent event) { | |
CustomDataState current = buffers.get(event.getPlayer()); | |
long data = event.getPacket().getLongs().read(0); | |
if (current != null) { | |
if (current.receieve(data)) { | |
byte[] remote = current.getData(); | |
// Clean up | |
buffers.remove(event.getPlayer()); | |
System.out.println("Recieved data: " + Bytes.asList(remote)); | |
} | |
} else if (data == MAGIC_START) { | |
// Start capturing. Theoretically, a normal client could trigger this, but it wouldn't normally send | |
// a second PING packet. | |
buffers.put(event.getPlayer(), new CustomDataState()); | |
} else { | |
// Let Minecraft handle the rest | |
return; | |
} | |
// This is our special "data channel" - don't let Minecraft interfer | |
event.setCancelled(true); | |
} | |
}); | |
} | |
private static class CustomDataState { | |
private ByteArrayOutputStream buffer = new ByteArrayOutputStream(); | |
private DataOutputStream writer = new DataOutputStream(buffer); | |
// Number of bytes to expect - maximum 2GB | |
private int payload; | |
private int written; | |
/** | |
* Recieve the given data. | |
* @param data - the data. | |
* @return TRUE if we are done recieving data, FALSE otherwise. | |
* @throws IOException | |
*/ | |
public boolean receieve(long data) { | |
try { | |
if (written == 0) { | |
// Get the payload size | |
payload = (int)data; | |
writer.writeInt((int) (data >> 32)); | |
written += 4; | |
} else { | |
writer.writeLong(data); | |
written += 8; | |
} | |
// See if we have enough data to produce an output | |
return hasData(); | |
} catch (IOException e) { | |
throw new RuntimeException("Cannot recieve data.", e); | |
} | |
} | |
public boolean hasData() { | |
return written >= payload; | |
} | |
public byte[] getData() { | |
if (!hasData()) | |
throw new IllegalStateException("Insufficient data."); | |
return Arrays.copyOf(buffer.toByteArray(), payload); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment