Xash Link Message API

Xash (v1.7.0 or later) comes with a link message API script, XashLinkMessageAPI, that will allow you or third-party developers to query for and subscribe to public information.

If you are a creator and would like a copy of the script please get in touch with Carlyle Theas.

Requesting Information

To request information from Xash, use llMessageLinked in your script with one of the following commands:

Message Description integer num string str key id
API_REQUEST_CLUB_CODE Request the club identifier needed to send HTTP requests to the Xash web server. A API_RESPONSE_CLUB_CODE message is sent in response. 240001 -
API_REQUEST_IS_MANAGEMENT_MEMBER Request information if a given avatar (identified by its UUID) is a management member of the club. A API_RESPONSE_IS_MANAGEMENT_MEMBER message is sent in response. 240002 - The UUID of the avatar for which to determine the management status
API_REQUEST_EVENTS Send this message to get a list of the next five events, including the current one. Handle the API_NOTIFY_EVENTS event to get the event data. 240002 - -
API_REQUEST_HIGHEST_TIPPERS Request the 5 avatars that tipped the most during the past 30 days. You can provide an optional offset to get the next 5 avatars, starting from the offset. The response is sent in a API_RESPONSE_HIGHEST_TIPPERS message. 240003 Offset (optional) -
API_REQUEST_MOST_RECENT_TIPPER Request the 5 most recent tippers. You can provide an optional offset to get the next 5 avatars, starting from the offset. The response is sent in a API_RESPONSE_HIGHEST_TIPPERS message. 240004 Offset (optional)

Obtaining Information and Notifications

Implement the link_message event handler to obtain information from Xash. It will send the following messages:

Message Description integer num string str key id
API_RESPONSE_CLUB_CODE Returns the club code 240101 {clubCode}|{senderUUID} -
API_RESPONSE_IS_MANAGEMENT_MEMBER Returns the information if {agentUUID} is a management member (0 or 1) 240102 {senderUUID}|{agentUUID}|{isManagementMember} -
API_RESPONSE_HIGHEST_TIPPERS Returns a list of the 5 highest tippers 240104 1| {tipper1UUID}|{tipper1Name}|{tipper1ProfileImageUUID}|{tipper1Amount}| ...| {tipper5UUID}|{tipper5Name}|{tipper5ProfileImageUUID}|{tipper5Amount}| -
API_RESPONSE_MOST_RECENT_TIPPERS Returns a list of the 5 most recent tippers 240105 1| {tipper1UUID}|{tipper1Name}|{tipper1ProfileImageUUID}|{tipper1Amount}| ...| {tipper5UUID}|{tipper5Name}|{tipper5ProfileImageUUID}|{tipper5Amount}| -
API_NOTIFY_EVENTS Notifies about the current and upcoming events 240201 {fontId}| {line1Texture}|{line1Date}|{line1DateColor}|{line1Text}|{line1TextColor}| ...| {line6Texture}|{line6Date}|{line6DateColor}|{line6Text}|{line6TextColor}| {currentTrackColor}|{prevTrackColor}|{titleColor}|{hasCurrentEvent}| {clubTextureUuid}|{noEventText}|{noEventTextureUUID} -
API_NOTIFY_TIP_GIVEN Notifies that a tip has been given 240202 {tipJarGroupId}|{loggedInAgentUUID}|{tipperUUID}|{amount}|{clubCommission} -
API_NOTIFY_GET_STREAM_URLS Notifies about the current stream URL 240203 {streamUrl} -
API_NOTIFY_TRACK_TITLE Notifies about the track title that is currently played 240204 {trackTitle} -

Constants

Copy the following constants for use in your own script:

integer API_REQUEST_CLUB_CODE = 240001;
integer API_RESPONSE_CLUB_CODE = 240101;
integer API_REQUEST_IS_MANAGEMENT_MEMBER = 240002;
integer API_RESPONSE_IS_MANAGEMENT_MEMBER = 240102;
integer API_REQUEST_EVENTS = 240003;
integer API_REQUEST_HIGHEST_TIPPERS = 240004;
integer API_RESPONSE_HIGHEST_TIPPERS = 240104;
integer API_REQUEST_MOST_RECENT_TIPPER = 240005;
integer API_RESPONSE_MOST_RECENT_TIPPERS = 240105;

integer API_NOTIFY_EVENTS = 240201;
integer API_NOTIFY_TIP_GIVEN = 240202;
integer API_NOTIFY_GET_STREAM_URLS = 240203;
integer API_NOTIFY_TRACK_TITLE = 240204;
    

Tip Jar API

The tip jars offer a link_message API in case you want to customize or extend their functionality.

Within the link_message event of a script you can react to the following messages:

Message Description integer num string str key id
LOG_IN_REQUESTED Sent when the user clicks the "Log In" button in the menu. 31004 The UUID of the agent requesting the log in
LOG_OUT_REQUESTED Sent when the user clicks the "Log Out" button in the menu. 31005 The UUID of the agent requesting the log out
LOG_IN Sent when a log in or log out was approved and the user is actually logged in/out. 30007 The UUID of the agent logged in, or NULL_KEY on log outs
GOAL_PERCENTAGE_UPDATED Sent if the tip jar is set to be a goal tip jar, and the percentage of the goal reached was updated. 32001 The total amount tipped to this tip jar The goal amount

Using the LOG_IN event, you could, e.g., create a tip jar that follows the logged in person around and returns to a default place when the user logs out.
See below for an example script.

Using the GOAL_PERCENTAGE_UPDATED event, you could create a donation thermometer tip jar. You would calculate the percentage with
integer percentage = ((integer) str) * 100) / ((integer) ((string) id));

Constants

Copy the following constants for use in your own script:

LOG_IN_REQUESTED = 31004;
LOG_OUT_REQUESTED = 31005;
LOG_IN = 30007;
GOAL_PERCENTAGE_UPDATED = 32001;
    

Examples

Following Tip Jar

vector OFFSET_FROM_AVATAR_CENTER = <0, 0, 1.5>;

vector g_vecHomePosition;


moveTo(vector vecTarget)
{
    integer i = 0;
    for ( ; i < 10; ++i)
    {
        vector vecBefore = llGetPos();
        llSetPos(vecTarget);
        vector vecAfter = llGetPos();

        if (llVecDist(vecAfter, vecTarget) < 0.01 || vecBefore == vecAfter)
            return;
    }
}

default
{    
    state_entry()
    {
        llSetStatus(STATUS_PHYSICS, FALSE);
    }
    
    on_rez(integer nStartParam)
    {
        llResetScript();
    }

    link_message(integer nSenderNum, integer nNum, string strMsg, key keyUUID)
    {
        if (nNum == 30007)
        {
            if (keyUUID)
            {
                // an agent logged in
                g_vecHomePosition = llGetPos();
                llSensorRepeat("", keyUUID, AGENT, 20, PI, 1);
            }
            else
            {
                // the agent logged out
                llSensorRemove();
                moveTo(g_vecHomePosition);
            }
        }
    }
    
    sensor(integer nNum)
    {
        moveTo(llDetectedPos(0) + OFFSET_FROM_AVATAR_CENTER);
    }
    
    no_sensor()
    {
        // move to the home position if the logged in user has left
        llSensorRemove();
        moveTo(g_vecHomePosition);
    }
}            
        

Stripping Tip Jar

The following script is an example of how you can turn a tip jar into a stripping tip jar. It will strip you when a tip threshold has been reached, and if no more tips are added, will start re-dressing you again after a specific amount of time.

The tip jar plugin script only sends the stripping and dressing commands. For the stripping to work, you will need to attach an additional device, such as Wardrobe's StripMe (which is available to Wardrobe Premium users), or the (CTS) StripMe device.

///////////////////////////////////////////////////////////
// CONFIGURATION

// Set this to TRUE if the script is used in a Xash tip jar.
// Set to FALSE if used in a standalone tip jar. In this case
// it is assumed that the tips will always go to the owner,
// i.e., the owner of the tip jar will be stripped.
integer IS_XASH_TIPJAR = TRUE;

// The amount of tips that needs to be given before the next layer
// of clothes are stripped from the person logged into the tip jar
integer TIPS_TO_STRIP_NEXT_LAYER = 200;

// The number of seconds before a layer of clothing is put on again
integer REDRESS_TIMEMOUT_IN_SECONDS = 600;

// The message that is shown in local chat when stripping occurs.
// The display name of the logged in person will be prepended to the mesage.
string STRIP_ANNOUNCEMENT = "is getting naked! Keep the tips coming if you want to see more skin!";

// An optional UUID of a sound that will be played when stripping occurs.
string STRIP_SOUND_UUID = "";


///////////////////////////////////////////////////////////
// IMPLEMENTATION

key g_keyLoggedInAgent = NULL_KEY;
integer g_nTipsCollected = 0;
integer g_nPreviousStripAmount = 0;
integer g_nNumLayersToStrip = 0;
integer g_bCanStripMore = TRUE;
integer g_bCanDressMore = FALSE;
integer g_bIsStripping = FALSE;


strip()
{
    integer nTimeout = REDRESS_TIMEMOUT_IN_SECONDS;

    if (g_nNumLayersToStrip > 0)
    {
        if (g_bCanStripMore)
        {
            g_bIsStripping = TRUE;
            llRegionSay(-5928148, (string) g_keyLoggedInAgent + "|strip");
        }

        --g_nNumLayersToStrip;
        if (g_nNumLayersToStrip > 0)
            nTimeout = 10;
    }

    llSetTimerEvent(nTimeout);
}

dress()
{
    integer nTimeout = 0;

    if (g_bCanDressMore)
    {
        llRegionSay(-5928148, (string) g_keyLoggedInAgent + "|dress");
        nTimeout = REDRESS_TIMEMOUT_IN_SECONDS;
    }

    llSetTimerEvent(nTimeout);
}

reset()
{
    g_nTipsCollected = 0;
    g_nPreviousStripAmount = 0;
    g_nNumLayersToStrip = 0;
    g_bCanStripMore = TRUE;
    g_bCanDressMore = FALSE;
    g_bIsStripping = FALSE;
}

default
{    
    state_entry()
    {
        // if not a Xash tip jar, assume the tips always go
        // to the owner and the owner is always logged in
        if (!IS_XASH_TIPJAR)
            g_keyLoggedInAgent = llGetOwner();

        reset();
        llListen(-5928148, "", NULL_KEY, "");
    }
    
    on_rez(integer nStartParam)
    {
        llResetScript();
    }

    listen(integer nChannel, string strName, key keyUUID, string strMessage)
    {   
        if (strMessage == "fully-dressed")
            g_bCanDressMore = FALSE;
        if (strMessage == "fully-undressed" || strMessage == "naked")
            g_bCanStripMore = FALSE;

        if (strMessage == "OK" && g_bIsStripping)
        {
            g_bCanDressMore = TRUE;

            if (STRIP_ANNOUNCEMENT)
                llSay(0, "💋👙 " + llGetDisplayName(g_keyLoggedInAgent) + " " + STRIP_ANNOUNCEMENT + " 👙💋");

            if (STRIP_SOUND_UUID)
                llPlaySound(STRIP_SOUND_UUID, 1);
        }

        g_bIsStripping = FALSE;
    }    

    link_message(integer nSenderNum, integer nNum, string strMsg, key keyUUID)
    {
        if (nNum == 30007)
        {
            g_keyLoggedInAgent = keyUUID;
            if (keyUUID)
                reset();
        }
    }

    money(key keyUUID, integer nAmount)
    {
        g_nTipsCollected += nAmount;

        g_nNumLayersToStrip += (g_nTipsCollected - g_nPreviousStripAmount) / TIPS_TO_STRIP_NEXT_LAYER;
        g_nPreviousStripAmount += g_nNumLayersToStrip * TIPS_TO_STRIP_NEXT_LAYER;

        if (g_nNumLayersToStrip > 0)
            strip();
    }

    timer()
    {
        if (g_nNumLayersToStrip > 0)
            strip();
        else
            dress();
    }
}