Wiki

Clone wiki

Aeros Addons API / Home

Aeros :: Aeros Addons API


WARNING Text below may contain adult terms and expressions



Aeros Cocks Addons Public Messaging Protocol

Aeros Cocks since version [6.0] (currently Axiom, Darius, Magnus, Nemo, Xerxes) issue commands to a predefined channel AEROS_PUBLIC_ADDON_CH = -727002 via:

  • llRegionSayTo(llGetOwner(), AEROS_PUBLIC_ADDON_CH, <command>) - when the cock is attached
  • llWhisper(AEROS_PUBLIC_ADDON_CH,<command>) - when the cock is not attached

Note: This will prevent surrounding non-attached items to listen to these messages while the cock is worn. But also allows for testing when the cock/addons are rezzed

Purpose: To allow developers to create arbitrary addons that would move together with the cocks, hide when necessary and twitch. This protocol doesn't include commands that can be issued via Partner API Script. Instead, since addons require instant action, we are removing any encryption or additional linked message layer, so the addons could react quickly, without visual inconsistency between cocks and addons. Thus, Addons Public Messaging Protocol is only a one-way communication from cocks to addons.

Listener Example

#!c
// <predefinedChannel> definition and listen example for Aeros Cocks >=6.0
integer AEROS_PUBLIC_ADDON_CH = -727002;

default {
  state_entry() {
    llListen(AEROS_PUBLIC_ADDON_CH, "", NULL_KEY, "");
  }
  listen(integer channel, string name, key id, string message) {
    if (channel!=AEROS_PUBLIC_ADDON_CH) return;
    if (llGetOwnerKey(id)!=llGetOwner()) return;
    // ...
  }
}

Commands List

"Anchor"

Purpose: Report the cock's latest attachment point and local position/rotation, as well as cock's state at the moment of message. This will be used by an addon to move its root, to stay synchronized with the cock as well as notify the user if <attachmentPoint> is not the same as the addon's one.

Frequency: Each "on" command (each change of the cock's angle, change of settings while it's shown, as well as turning the cock "on" to bring it back after hidden state).

Format:

>a0|a!|<attachmentPoint>|<localPos>|<localRot>|<hideDistance>|<currentMode>|<currentStage>|<currentVerticalAngle>|<currentHorizontalAngle>

  • ">a0" - protocol version number [string]
  • "a!" - message type [string]
  • <attachmentPoint> - corresponds to llGetAttached() [integer]
  • <localPos> - is taken from llGetLocalPos() [vector]
  • <localRot> - is taken from llGetLocalRot() [rotation]
  • <hideDistance> - a float number, representing the distance along X axis where hidden prims are located [float]
  • <currentMode> - a float between 0..1 (inclusive). Represents foreskin state. Currently only "0" and "1" are used [float]. Always "0" for models without foreskin
  • <currentStage> - cock's stage of hardness - "0", "1", or "2" [integer]
  • <currentVerticalAngle> - float number representing cock's vertical angle in radians [float]. Horizontal line is "0"
  • <currentHorizontalAngle> - float number representing cock's horizontal angle in radians [float]. Straight line is "0"

"Data"

Purpose: Report each prim's position/rotation/size, to allow addons to know where they are and be able to calculate addon's prims new locations.

Frequency: After "a!" message. Will be in a batch of <primsCount> messages, 1 per each cock prim piece, starting with the most distant one: ["knob", "shaft", "balls", and possibly, "fascia"]. (Addons should rely on the <primsCount> to determine if "fascia" is included). <batchIndex> will be the same number for each of the message in a batch (row).

Format:

>a0|d!|<batchIndex>|<primIndex>|<primsCount>|<meshName>|<alpha>|<pos>|<rot>|<size>|<widthAxisName>|<widthMultiplyer>|<overallSizeMultiplier>

  • ">a0" - protocol version number [string]
  • "d!" - message type [string]
  • <batchIndex> - incrementing index of a batch of "d!" messages [integer]
  • <primIndex> - index of the prim in the list: ["knob", "shaft", "balls", and possibly, "fascia"] [integer]
  • <primCount> - amount of prims in the list - either 3 or 4 if fascia is included [integer]
  • <meshName> - prim's mesh name [string] - it's unique for the whole cock linkset
  • <alpha> - a number between 0..1 representing actual prim's visibility. If "0", actual cock's mesh prim is hidden behind the cock into the body, but data is sent as if present. [float]
  • <pos> - prim's local position [vector]
  • <rot> - prim's local rotation [rotation]
  • <size> - prim's size [vector]
  • <widthAxisName> - "x", "y" or "z" - axis of the shaft horizontal width [string]
  • <widthMultiplyer> - width multiplyer along width axis [float]
  • <overallSizeMultiplier> - overall cock size multiplier (includes mega size) [float]

Attention: Since messages may arrive reordered (due to SL limitations), addons creators shouldn't rely on the sequence, but use <primIndex> instead and count the amount of messages per <batchIndex> before applying changes in a sequence of PRIM_LINK_TARGETs.

"Off"

Purpose: Report when the cock is hidden, providing a distance how far to move prims from the root (along X axis), deep into the body.

Frequency: Once per hiding.

Format:

>a0|o!|<hideDistance>

  • ">a0" - protocol version number [string]
  • "o!" - message type [string]
  • <hideDistance> - a float number, representing the distance along X axis where hidden prims are located [float]

"Twitch"

Purpose: Notify about throbbing moment and give data needed to make addons follow the throbbing.

Frequency: Each throbbing event.

Format:

>a0|t!|<factorsCommaSeparatedList>
* ">a0" - protocol version number [string] * "t!" - message type [string] * <factorsCommaSeparatedList> - comma separated [float] numbers, factors, one per each prim in this sequence: ["knob", "shaft", "balls", "fascia"] (Here "fascia" number will always present). These are used internally in the cock to calculate prim's size and location for current throbbing moment by simply multiplying both vectors with the corresponding factors, lasting exactly 0.1 second and then returning prims back to their previously saved positions and sizes. Addons may or may not follow resize, but they will probably relocate themselves to stay visually attached and they should move themselves back after 0.1 timeout (use llSleep)

Example

Feel free to start with this example and let me know in-world (Ray Silent) if you encounter issues.

#!c
// <predefinedChannel> definition and listen example for Aeros Cocks >=6.0
integer AEROS_PUBLIC_ADDON_CH = -727002;

// This assumes your prim consists of 2 prims, one of them will be snapped
// to the attachment point, and the other will try to follow one of the cock prims
integer check() {
  return (llGetAttached()>0 && llGetNumberOfPrims()>1);
}

default {
  state_entry() {
    if (!check()) state invalid;
    llListen(AEROS_PUBLIC_ADDON_CH, "", NULL_KEY, "");
    llOwnerSay("Attached and running");
  }

  on_rez(integer start_param) {
    if (!check()) state invalid;
  }

  changed(integer change) {
    if (change & CHANGED_LINK) {
      if (!check()) state invalid;
    }
  }

  listen(integer channel, string name, key id, string message) {
    if (channel!=AEROS_PUBLIC_ADDON_CH) return;
    if (llGetOwnerKey(id)!=llGetOwner()) return;
    // High possibility it is Aeros Addon API message :D
    list parts = llParseStringKeepNulls(message, ["|"], []);
    if (llList2String(parts,0)!=">a0") return; // Filter just in case
    if (llList2String(parts,1)=="a!") {  // "Anchor" message (https://bitbucket.org/aeros-in-sl/aeros-addons-api/wiki/Home#markdown-header-anchor)
      // >a0|a!|<attachmentPoint>|<localPos>|<localRot>|<hideDistance>|<currentMode>|<currentStage>|<currentVerticalAngle>|<currentHorizontalAngle>
      //               #2            #3         #4     
      integer attachmentPoint = llList2Integer(parts,2); // "<attachmentPoint>"

      // So your addon can now "snap" its root to this - if attached to the same attachment point
      if (llGetAttached() == attachmentPoint) { // This also checks if we are rezzed on the ground or not... Yeah! If rezzed we snap it anyway! Hope it works or it flies away!
        // Okay we are good to go.
        vector pos = (vector)llList2String(parts,3);
        rotation rot = (rotation)llList2String(parts,4);
        // Let's snap our guy.
        llSetLinkPrimitiveParamsFast(LINK_ROOT, [PRIM_POSITION, pos, PRIM_ROTATION, rot]); // It's better to test this
        // ######### TEST THIS OUT ######### May be something else should be used like PRIM_POS_LOCAL and PRIM_ROT_LOCAL
        // Once your root is snapped, you can be sure that the data message will affect your prims in relation to the same exact point in body space.
      } else {
        // Inform a user to reattach the addon somehow?
        llOwnerSay("The prim seems not to be attached to the same point as the cock");
      }

    } else if (llList2String(parts,1)=="d!") {  // "Data" message (https://bitbucket.org/aeros-in-sl/aeros-addons-api/wiki/Home#markdown-header-data)
      // >a0|d!|<batchIndex>|<primIndex>|<primsCount>|<meshName>|<alpha>|<pos>|<rot>|<size>|<widthAxisName>|<widthMultiplyer>|<overallSizeMultiplier>
      //                          #3                      #5               #7    #8    #9
      // Here we receive exact prim positions. As we want only "knob" its primIndex is....0 !!!!
      if (llList2Integer(parts,3)==0 /*knob*/) {
        // Okay good
        vector pos = (vector)llList2String(parts,7);
        rotation rot = (rotation)llList2String(parts,8);        
        vector size = (vector)llList2String(parts,9);
        // This should be enough to start playing with this data.
        // Start moving your linked prim according to this. Let's say it's link #2 (so it's a 2 prims set at least)
        float factor = 0.5; // It could be anything depending on how big your prim is in releation to the knob mesh size (which also has a bounding box so its size is bigger than it is)
        llSetLinkPrimitiveParamsFast(2 /*Link number*/, [PRIM_POS_LOCAL, pos, PRIM_ROT_LOCAL, rot, PRIM_SIZE, size * factor]);
        // I'm pretty sure we use "LOCAL" here. It's a pain above with the root prim as attachment
        // The real math will become more complex in time as you realize you need adjustments to the position and rotation and size.
        // But this is a fun part!
      }

    }
  }
}

state invalid {
  state_entry() {
    llOwnerSay("Not attached or invalid amount of prims in the linkset. Should be at least 2");
    llSetTimerEvent(5);
  }

  on_rez(integer start_param) {
    if (check()) llResetScript();
  }

  timer() {
    if (check()) llResetScript();
  }

}

Updated