-
Notifications
You must be signed in to change notification settings - Fork 18
Total RP Peer to Peer Model
The Total RP Peer to Peer Model (or TRP2P) is a complex peer-to-peer communication model.
It is used for almost every data exchange between TRP3 players.
The TRP2P is a layered model, inspired by the Open Systems Interconnection model (OSI Model) but with only 4 layers. Each layer has its own responsabilities and communicate only with the two adjacent layers.
This is the layer used by the user. When the player want to send a value to another player, it use the Structure layer to send his data. The data is a Lua
value. Any Lua value: a string
, a number
, a table
... Most of the time it will be a hash table
though, much more easy to handle on both sides.
The layer will create a structure composed of the data and a prefix. The prefix is an identification for the structure, an ID of "what to do with this structure" once it arrive on the other side.
Any part of the code can attach a handler to a specific prefix. When data bound to this prefix are received, every handler is called with the data.
The layer gets:
- The data to be transmited
- The prefix attached to this data
- The target for this data (character ID)
- The priority of the data (based on ChatThrottleLib priorities)
function Comm.sendObject(prefix, object, target, priority)
It packages the prefix and the data into a structure and push that structure to the Message layer with the priority and the target.
The layer gets:
- The structure
- The sender of the data
function receiveObject(structure, sender)
When receiving a structure from the Message layer, it unpacks the structure to separate the prefix from the data.
The layer will then call any handler registered to this prefix, attaching the data and the sender to the call.
This layer purpose is to handle structure serialization, message deserialization and message cutting/recomposing.
The layer gets:
- The structure from the structure layer
- The target for this data (character ID)
- The priority of the data
local function handleStructureOut(structure, target, priority)
The structure is serialized (using Ace-Serializer) into a message. A two-characters long message ID is generated for this message.
This message is then cut into pieces of maximum 245
characters: the packets.
The message ID and the bag of packets are push to the Packets layer (always with the target and priority).
The layer gets:
- The packets
- The sender of the data
function handleStructureIn(packets, sender)
It reassembles the message and deserializes it to a structure.
It sends the structure to the structure layer, with the sender.
This layer purpose is to send and store packets.
The layer gets:
- The message ID from the message layer
- The bag of packets from the message layer
- The target for this data (character ID)
- The priority of the data
local function handlePacketsOut(messageID, packets, target, priority)
This layer send each packet with the precaution of attach to it the message ID. Also to each packet is attach a control character. This control character will tell the other side is the packet is the last for this message ID or if other packets will come.
The packets are sent to the communication layer, with the target and priority.
The layer gets:
- The packet
- The sender of the data
function handlePacketsIn(packet, sender)
The layer will detach the message ID and the control character from the packet. It will store the packet into a "bag" specific to the message ID and, if the control character indicates that it is the last packet to be received for this message, push the packets bag to the message layer.
This layer determines "how" to send the data to the target. For that it uses communication interfaces.
The interface used by everyone is the wow
interface which uses SendAddonMessage
over ChatThrottleLib, using the priority.
The other two interfaces are used for dev and debugging purpose: the direct relay
interface is like a "localhost" sending all packets to yourself, and the direct print
prints the packet to the chat frame.
- Can handle heavy concurrent data sending.
- Very robust.
- Easy to use.
- Easy to monitore.
- Easy to debug.
- Implementation can be enhanced.
- Quite heavy memory consumption.
- Can be "overkill" when sending small amounts of data.