Skip to main content

Network Objects

What is a network object

Network Objects are an essential part of the GNOM System.
Their particularity is that they are bound with a reference.
This concept is really simple, but this allows the framework to perform packet stream size optimisation, by sending the reference instead of the object itself, and, on top of that, sending the reference of an object allows to solve recurrent issues when developing a network based system, and eases the manipulation of network objects between remote engines

Regular, Static and Dynamic Network Objects

The concept of Static, Dynamic, and Regular Network Objects only differs by their presence handling over the network.
Here is how you can retrieve the presence for each kind of network objects.

Regular Network Objects

The NetworkObject trait is the base class for declaring a network object.
The only thing exposed in this class is the reference of the object.

To retrieve the presence of a regular network object reference, you can use its linker, or a parent of the targeted linker (such as the GNOL).

val linker: NetworkObjectLinker[R] = network.gnol
val no: NetworkObject = ???
val presence: Option[NetworkObjectPresence] = linker.findPresence(no.reference)
note

If the network object is registered in the GNOL tree, linker.findPresence will return Some(NetworkObjectPresence) But if the network object isn't registered, or if you try to find the presence of a reference that isn't bound to any network object, the return value isn't likely to return None, it could return Some(NetworkObjectPresence) with the presence state for current engine set to NOT_PRESENT

Dynamic Network Objects

A Dynamic Network Object presence is handled like a regular Network Object, the only thing is that their presence is exposed in the DynamicNetworkObject trait.

val dno: DynamicNetworkObject = ???
val presence: NetworkObjectPresence = dno.presence

Static Network Objects

Static Network Objects are specifically handled by the persistence system.
When the serialization process meets a StaticNetworkObject, it'll suppose that the object is present on any engine, as it is statically present on the network.

Thus, retrieving a

How to create a Network Object

To create a Network Object, you'll need 3 things:

  1. Define (or use) a NetworkObjectReference. Take a look at the Network Object Reference page to learn more. we'll use MyNetworkObjectReference as an example.
  2. Define your network object class by extending the NetworkObject interface.
class MyNetworkObject(override val reference: MyNetworkObjectReference) extends NetworkObject[MyNetworkObjectReference]
  1. Put the instances of this class in a Network Object Linker . You can define your own Network Object Linker, or use the DefaultNetworkObjectLinker as a linker for your objects. You can also prefer the ContextObjectLinker of your PacketChannel.
val ref = MyNetworkReference("tommy")
val myNetworkObject = new MyNetworkObject(ref)
val defaultLinker = network.gnol.defaultNOL
defaultLinker.save(myNetworkObject)

Did not understand a thing of the last sentence ? take a look at Network Object Linker page to understand what is a network object linker, and know what linker you should use depending on the context and your needs.

That's it. Now the framework knows your object, and if another engine also have an object referenced at MyNetworkReference("tommy"), no matters the used linker, the referencing will work.

So what happens if an engine sends a network object that is not referenced on the targeted engine ?

The handling of a network object whose reference is not registered on targeted engine is different depending on the type of Network Object involved:

  • Regular / Dynamic Network Objects The object is sent on the distant engine, then the distant engine will register the object's reference.
  • Static Network Objects Because they are intended to be static over the network, if an engine receives an unregistered static object reference, it'll throw an exception.

Use cases

Serialize non-serializable objects

The current persistence system is already able to handle objects that are not designed to support serialization, and is enough configurable to let the user define how an object should be serialised/deserializedif the default 'field copy/paste' method is not convenient.
however, there is still enough reason why serialization/deserialization of an object can be undesirable:

For example, the trait ApplicationContext's implementations objects are just too big to get send threw the network. Moreover, they are intended to have only one instance in the JVM. Without the GNOM (General Network's Objects Management), if the Application object is set into a packet, and then the packet is send to any engine, the the persistence system will handle the Application object as such, and so, the receiver of the packet will end up with two applications objects, which is problematic because only one ApplicationContext is intended. Thanks to the GNOM System, this kind of conceptual problem can be avoided as only the application's reference will be sent in the socket, and then the receiver's GNOM system will replace the received reference by its Application object.

Relative Objects

Well, as NetworkObjects are bound to their reference, this means that a Network Object Reference (or NOR) can point to a network object that can be different depending on the machine.

As an example, let's assume that we are making a multiplayer game.

For this game, we define a trait Player extends NetworkObject[PlayerReference] and two implementations of Player:

  • ControlledPlayer, relative to each connected engine, which is the player object of the human behind the screen that can actually control the player
  • RemotePlayer, for remote players that are connected to our session.

We can define a reference (such as @session/players/controller) that all ControlledPlayer objects of the network will be bound to (invoking ControlledPlayer#reference will return the reference @session/players/controller). using this trick, once the ControlledPlayer object is sent to an engine, as Network Object are replaced by their reference during the serialization, the engines that will receive the reference will take the object referenced at @session/players/controller, which will result to its own ControlledPlayer instance.

This way, we can easily create packets that says 'hey, do something with your own controlled player'

Conversely, we could define a reference to each player connected on the session.
For engine 'n', we would have reference @session/players/n, and then, we bind our ControlledPlayer object to the network object reference where 'n' is equals to our actual engine's identifier.
This way, when we receive or send a player object, we are sure that it will be the correct type depending on which engine the object lands, and the conversion from the 'RemotePlayer' object of the engine that sends us our own player instance (our ControlledPlayer) will be naturally performed.

Reinjecting same objects references

Note: Do not be confused between Network Object Reference and a normal object reference. Object References, or a 'reference' is simply the normal reference of an object, the usual term to point to an instance (variables, fields etc) Network Object References are, as said multiple times, the reference of an object threw the network.

Using normal objects, if you send twice the same object to an engine, the engine will get two different clones of the object you sent.

Using a NetworkObject, you ensure that the object will have only one instance of itself on engines, without having anyundesirable clones.

Using PersistenceConfig and ContextObjectLinker]], it is possible tobind any object to a network reference.
Binding a regular object to a network reference using ContextObjectLinkers is sufficient for the objects to be handled as a network object by thepersistence system.