Messaging
NGE’s networking layer automatically serializes and deserializes your Java message objects using a secure, built-in protocol. This means you can send and receive fully-typed Java objects between peers with virtually no boilerplate or manual serialization code.
Listening for Messages¶
Register a MessageListener
on your P2PChannel
to receive incoming Message
objects:
chan.addMessageListener(new com.jme3.network.MessageListener<HostedConnection>() {
@Override
public void messageReceived(HostedConnection source, Message m) {
// Handle the incoming message 'm' from peer 'source'.
}
});
Sending a Message¶
To broadcast a Message
to all connected peers:
chan.broadcast(message);
To send a Message
to a subset of peers, provide a filter predicate:
chan.broadcast(
peer -> myPeerList.contains(peer),
message
);
Here, myPeerList
is a Collection<HostedConnection>
specifying which peers should receive the message.
Message Types¶
NGE includes few built‐in message classes for convenience:
TextMessage¶
Sends a UTF‐8‐encoded String
. Suitable for chat or lightweight metadata (e.g., JSON payloads). Not recommended for high‐throughput data:
TextMessage msg = new TextMessage("Hello, World!");
chan.broadcast(msg);
CompressedMessage¶
Wraps and compresses another Message
instance. Ideal for large payloads (images, maps, etc.):
CompressedMessage msg = new CompressedMessage(myUncompressedMessage);
chan.broadcast(msg);
BinaryMessage¶
Sends raw binary data. Use this when you need complete control over serialization.
ByteBuffer buffer = BufferUtils.createByteBuffer(1024);
// Fill 'buffer' with your binary data...
BinaryMessage msg = new BinaryMessage(buffer);
chan.broadcast(msg);
Tip
To use a BinaryMessage you must handle (de)serialization manually, as the message only accepts a ByteBuffer. So oftentimes using a Custom Message is preferable.
Custom Messages¶
For flexibility, you can define your own Message
classes. Any custom message must:
- Implement the
com.jme3.network.Message
interface. - Have a public no‐argument constructor.
- Be annotated with
@NetworkSafe
(or@Serializable
, if you prefer SpiderMonkey’s annotations). - Use only safe, serializable fields (see below for details).
- Have a class name that ends in
Message
(e.g., MyCustomMessage).
PositionUpdate : wrong
PositionUpdateMessage : correct
These measures are in place to ensure that only safe and intended classes are sent over the network, preventing potential security issues caused by the deserialization of arbitrary classes and minimizing unintentional mistakes that could lead to such issues.
Example
@NetworkSafe
public class MyMessage implements Message {
private boolean reliable;
private int myNumber;
public MyMessage() {
// Public no-arg constructor is required.
}
public void setNumber(int number) {
this.myNumber = number;
}
public int getNumber() {
return myNumber;
}
@Override
public Message setReliable(boolean f) {
this.reliable = f;
return this;
}
@Override
public boolean isReliable() {
return reliable;
}
}
Fields in a Message
can be of another properly declared Message
type or any of the following serializable types:
Vector.class,
Vector2f.class,
Vector3f.class,
Vector4f.class,
Transform.class,
ColorRGBA.class,
Matrix3f.class,
Matrix4f.class,
Date.class,
Instant.class,
Duration.class,
NostrPublicKey.class,
NostrPrivateKey.class,
NostrKeyPair.class,
UnsignedNostrEvent.class,
SignedNostrEvent.class,
HashMap.class,
WeakHashMap.class,
IdentityHashMap.class,
Hashtable.class,
TreeMap.class,
HashSet.class,
ArrayList.class,
LinkedList.class,
LinkedHashSet.class,
TreeSet.class,
Attributes.class,
Integer.class,
Long.class,
Float.class,
Double.class,
String.class,
Short.class,
Boolean.class,
Byte.class,
Character.class,
int.class,
long.class,
float.class,
double.class,
boolean.class,
byte.class,
char.class,
short.class
Note
Collections and Maps are supported, but their elements (for Collections) or keys/values (for Maps) must themselves be one of the supported types listed above. Otherwise, the message will be rejected at serialization time.