For Players
In order to follow ZOS' opt out policy (brought up in regards to Group Damage), LibGroupSocket gives you fine grained control over what data you share with your group. Per default it automatically disables the sending of all data when you leave a group, or quit the game.
You can download and install LibGroupSocket like any other addon, in order to enable saving settings for it.

For Developers
LibGroupSocket offers a standardized way to share data with group members via map pings. It allows the sending of up to 3 byte of data in one ping or 7 bytes in 2 pings at a time.
Because the channel is very limited, there is currently only a maximum of 31 different message types supported.
If you are interested in adding a new message type, please contact me via pm and I will reserve an ID.
It is also encouraged to reuse existing message types and expand on them instead of adding a new one that does the same thing, but slightly different.

This first version of the library is mostly a trial to see how it will work in combination with the many other addons out there and also to see how ZOS will react and how much interest it generates with players.
For future versions I am considering to split message handlers into separate libraries, so they can be updated independently.

Known Issues

The library is currently not compatible with FTC's DPS sharing feature and you and all group members will see wrong values in FTC while LibGroupSocket is active

User set group pings may cause incorrect data to show up in same rare cases

User set group pings are overwritten when data is transmitted

The compass may show the automatically set group pings

Users without LibGroupSocket will see random group pings pop up in Wrothgar or Coldharbour

Settings for LibGroupSocket won't be saved unless you use the stand alone version.

Sometimes you may hear a sound when a ping is set

API Reference

ReadBit
Reads a bit from the data stream and increments the index and bit index accordingly.

Code:

boolean isSet, number nextIndex, number nextBitIndex = lib:ReadBit(table data, number index, number bitIndex)

data - an array of integers between 0 and 255
index - the current position to read from
bitIndex - the current bit inside the current byte (starts from 1)
Returns the state of the bit, the next position in the data array and the next bitIndex.

WriteBit
Writes a bit to the data stream and increments the index and bit index accordingly.

Code:

number nextIndex, number nextBitIndex = lib:WriteBit(table data, number index, number bitIndex, boolean value)

data - an array of integers between 0 and 255
index - the current position to write to
bitIndex - the current bit inside the current byte (starts from 1)
value - the new state of the bit
Returns the next position in the data array and the next bitIndex.

ReadChar
Reads a single byte from the data stream, converts it into a string character and increments the index accordingly.

data - an array of integers between 0 and 255
index - the current position to write to
value - a single character or a string of characters
charIndex - optional index of the character that should be written to the data stream. Defaults to the first character
Returns the next position in the data array.

ReadUint8
Reads a single byte from the data stream and increments the index accordingly.

Code:

number value, number nextIndex = lib:ReadUint8(table data, number index)

data - an array of integers between 0 and 255
index - the current position to read from
Returns the 8-bit unsigned integer and the next position in the data array.

WriteUint8
Writes an 8-bit unsigned integer to the data stream and increments the index accordingly. The value is clamped and floored to match the data type.

number b0, number b1, number b2, number b3 = lib:DecodeData(number x, number y, number stepSize)

Step size specifies the smallest possible increment for the coordinates on a map.
Returns 4 integers between 0 and 255.

MessageType
MessageType is an enumeration of implemented message types.lib.MESSAGE_TYPE_RESERVED: Reserved in case we ever have more than 31 message types. Can also be used for local tests.lib.MESSAGE_TYPE_RESOURCES: For exchanging stamina and magicka values.

EncodeHeader
Packs a 5-bit messageType and a 3-bit length value into one byte of data.

Send
Queues up to seven byte of data of the selected messageType for broadcasting to all group members.

Code:

boolean isValid = lib:Send(MessageType messageType, table data)

messageType - the protocol that is used for encoding the sent data
data - up to 7 byte of custom data. if more than 3 bytes are passed, the data will take 2 map pins to arrive.
Returns true if the data was successfully queued. Data won't be queued when the general sending setting is off or an invalid value was passed.

RegisterHandler
Registers a handler module for a specific data type.
This module will keep everything related to data handling out of any single addon, in order to let multiple addons use the same messageType.

messageType - The messageType the handler will take care of
handlerVersion - The loaded handler version. Works like the minor version in LibStub and prevents older instances from overwriting a newer one
Returns the handler object and saveData for the messageType.

GetHandler
Gives access to an already registered handler for addons.

Code:

table handler = lib:GetHandler(MessageType messageType)

messageType - The messageType of the handler
Returns the handler object.

RegisterCallback
Register for unprocessed data of a messageType.

Code:

lib:RegisterCallback(MessageType messageType, function callback)

UnregisterCallback
Unregister for unprocessed data of a messageType.

Code:

lib:UnregisterCallback(MessageType messageType, function callback)

/lgs
Gives access to the "enabled" setting via a chat command.

Code:

/lgs <1/0>

r2:
- reserved message type for Solinur's dps handler
- fixed settings not getting saved, even when the library is installed as a standalone addon
* NOTE: this required a small change to the way how handlers initialize their settings
- added flag to resource handler to transmit which resource pool is larger
* NOTE: when only the percentage is transmitted by a player, it will set the max value of the larger pool to 2k instead of 1k

I've recently rewritten my addon to use LibGroupSocket rather than LibMapPing at a great decrease in code size and complexity. Thanks. Great library.

I have a problem that is difficult (for me) to debug, though. Every so often one player seemingly stops sending even when LGS:Send() does not return false. I haven't been able to figure out what causes the issue, though. I thought maybe it happened to player a when player b logs out or when player b zones a lot but I can't confirm that. When player seems to stops sending, both player a and player b see player b's pings but neither sees pings from a.

Any hints on the best way to debug this? I can obviously just start sprinkling debugging d()'s throughout LibGroupSocket but that has a tendency to overload chat and sometimes the issue takes five minutes or more to crop up. Is there a more elegant way to debug a situation where a player apparently isn't sending? I think I've debugged this all the way down to the point where the code is calling LGS:Send so I don't think it's something obviously wrong with my code although typing this could very well lead to an aha! moment once I hit "Submit Reply".

Unfortunately this is one of the problems I mentioned in the LibMapPing comments. I haven't gotten around to test it with LGS2 yet, but it should be fixed since it handles outgoing pings differently in order to provide a global queuing mechanism.

Aha. If I reduce the frequency of my sends would that reduce the possibility of a problem too?

Right now, I'm sending player information every second but I could (and should) only send information if something changes.

I've recently rewritten my addon to use LibGroupSocket rather than LibMapPing at a great decrease in code size and complexity. Thanks. Great library.

I have a problem that is difficult (for me) to debug, though. Every so often one player seemingly stops sending even when LGS:Send() does not return false. I haven't been able to figure out what causes the issue, though. I thought maybe it happened to player a when player b logs out or when player b zones a lot but I can't confirm that. When player seems to stops sending, both player a and player b see player b's pings but neither sees pings from a.

Any hints on the best way to debug this? I can obviously just start sprinkling debugging d()'s throughout LibGroupSocket but that has a tendency to overload chat and sometimes the issue takes five minutes or more to crop up. Is there a more elegant way to debug a situation where a player apparently isn't sending? I think I've debugged this all the way down to the point where the code is calling LGS:Send so I don't think it's something obviously wrong with my code although typing this could very well lead to an aha! moment once I hit "Submit Reply".

Unfortunately this is one of the problems I mentioned in the LibMapPing comments. I haven't gotten around to test it with LGS2 yet, but it should be fixed since it handles outgoing pings differently in order to provide a global queuing mechanism.

__________________

>siri.exe MyAddon
Does your addon work? [y/n] n
There is a typo in there.

I've recently rewritten my addon to use LibGroupSocket rather than LibMapPing at a great decrease in code size and complexity. Thanks. Great library.

I have a problem that is difficult (for me) to debug, though. Every so often one player seemingly stops sending even when LGS:Send() does not return false. I haven't been able to figure out what causes the issue, though. I thought maybe it happened to player a when player b logs out or when player b zones a lot but I can't confirm that. When player seems to stops sending, both player a and player b see player b's pings but neither sees pings from a.

Any hints on the best way to debug this? I can obviously just start sprinkling debugging d()'s throughout LibGroupSocket but that has a tendency to overload chat and sometimes the issue takes five minutes or more to crop up. Is there a more elegant way to debug a situation where a player apparently isn't sending? I think I've debugged this all the way down to the point where the code is calling LGS:Send so I don't think it's something obviously wrong with my code although typing this could very well lead to an aha! moment once I hit "Submit Reply".

When LGS is installed as a standalone addon (and starting in the next version I am working on right now in any case) it will remember the settings.

I looked through ZOS addon terms and could not find any mention of an opt-out policy.

Even if there was one, it should be the sole responsibility of the addon utilizing the library to control whether sending is permitted.

Making such a user-unfriendly requirement to utilize this library just incentives people to make their own communication protocols (like FTC and Roll Call, both which can cause interference), which is something I'm thinking of doing myself.

In order to follow ZOS' opt out policy (brought up in regards to Group Damage), LibGroupSocket gives you fine grained control over what data you share with your group. Per default it automatically disables the sending of all data when you leave a group, or quit the game.

When LGS is installed as a standalone addon (and starting in the next version I am working on right now in any case) it will remember the settings.

__________________

>siri.exe MyAddon
Does your addon work? [y/n] n
There is a typo in there.

Can the sending permissions be changed to:
- have a different enabled flag for each MessageType
- be controllable by dependent addons (expose access to the enabled flag) rather than being only controlled by the library

Currently this library is not very usable because it requires the user to jump through a lot of hoops in order to enable sending, but there is no granularity for controlling which message types are and are not allowed to be sent.

This is not true. If an author follows the design, there should be an option for each message type. But if an author rather decides to keep the settings in his own addon instead there is not much that can be done.

Are you sure about that?

It seems that if "saveData.enabled" is set to false, message sending is disabled regardless of what the message type is.

Code:

function lib:Send(messageType, data)
if(not saveData.enabled) then return false end
if(not IsValidMessageType(messageType)) then Log("tried to send invalid messageType %s", tostring(messageType)) return false end
if(not IsValidData(data)) then return false end
-- TODO like all other api functions, this one also has a message rate limit. We need to avoid sending too much or we risk getting kicked
lib.outgoing[#lib.outgoing + 1] = OutgoingPacket:New(messageType, data)
if(not lib.isSending) then
DoSend()
else
lib.hasMore = true
end
return true
end

@sirinsidiator can you please clarify?

There are two levels of "enabled". The global enable in the code you posted is for quickly switching it completely off, e.g. when you are in a group that doesn't use these addons (pugs etc).
The handlers implement their own enabled switch and settings:

Can the sending permissions be changed to:
- have a different enabled flag for each MessageType
- be controllable by dependent addons (expose access to the enabled flag) rather than being only controlled by the library

Currently this library is not very usable because it requires the user to jump through a lot of hoops in order to enable sending, but there is no granularity for controlling which message types are and are not allowed to be sent.

This is not true. If an author follows the design, there should be an option for each message type. But if an author rather decides to keep the settings in his own addon instead there is not much that can be done.

Are you sure about that?

It seems that if "saveData.enabled" is set to false, message sending is disabled regardless of what the message type is.

Code:

function lib:Send(messageType, data)
if(not saveData.enabled) then return false end
if(not IsValidMessageType(messageType)) then Log("tried to send invalid messageType %s", tostring(messageType)) return false end
if(not IsValidData(data)) then return false end
-- TODO like all other api functions, this one also has a message rate limit. We need to avoid sending too much or we risk getting kicked
lib.outgoing[#lib.outgoing + 1] = OutgoingPacket:New(messageType, data)
if(not lib.isSending) then
DoSend()
else
lib.hasMore = true
end
return true
end

Can the sending permissions be changed to:
- have a different enabled flag for each MessageType
- be controllable by dependent addons (expose access to the enabled flag) rather than being only controlled by the library

Currently this library is not very usable because it requires the user to jump through a lot of hoops in order to enable sending, but there is no granularity for controlling which message types are and are not allowed to be sent.

This is not true. If an author follows the design, there should be an option for each message type. But if an author rather decides to keep the settings in his own addon instead there is not much that can be done.

Can the sending permissions be changed to:
- have a different enabled flag for each MessageType
- be controllable by dependent addons (expose access to the enabled flag) rather than being only controlled by the library

Currently this library is not very usable because it requires the user to jump through a lot of hoops in order to enable sending, but there is no granularity for controlling which message types are and are not allowed to be sent.

Hey, I had a question and possibly a request. What I'm looking for is a way to send/transmit your unitId to other users in your group using this library.

I am looking for this so I can do some cool things in RaidNotifier. Many (if not all) effects & actions from bosses/mobs still supply the unitId in EVENT_EFFECT_CHANGED and EVENT_COMBAT_EVENT. So instead of trying to send an event/warning/ping for whatever mechanic I want to share between group mates I can just send my unitId (to everybody that also has the lib/addon) and let each person's addon handle all the actual checks.

Obtaining your unitId is somewhat easy, I just monitor for the player blocking like this:

So here comes the actual question, how do I transmit/send a number between like 20000 and 90000 using LibGroupSocket? I'm guessing I gotta split it up but how would that work exactly?

P.S. This still won't magically enable something like GroupDamage because everything that comes FROM a player will just have a unitId of 0.

You are correct. For values that don't fit into the provided data types you would need to write your own method for serializing and deserializing them.
That said, I am not sure if what you suggest will work. As far as I am aware these ids are local to each client, so different players can have different ids for the same unit.

Hmmm yes, that might actually be the case, damn. :/

Edit: Omg I'm such an idiot, the unitTag can just be used to see who the unitId belongs to, I could've sworn I tested that and that they were left blank/empty.

Support AddOn Development!

You have just downloaded by the author . If you like this AddOn why not consider supporting the author? This author has set up a donation account. Donations ensure that authors can continue to develop useful tools for everyone.