User:Nexii Malthus/Script API

From Second Life Wiki
< User:Nexii Malthus
Revision as of 13:30, 25 January 2015 by ObviousAltIsObvious Resident (talk | contribs) (<lsl> tag to <source>)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Based from LSL To Client Communication I decided to go ahead and attempt to fully implement a modified version of the protocol.

Please see Dale's implementation first, so not everything has to be repeated here and you might see the slight differences in my protocol.

Protocol

Before anything can be queried, a connection has to be made with the client by agreeing on a common channel for receiving responses. The protocol uses tokens like Dale's implementation. Any message addressed to the viewer has to begin with 'Vwr'.

The connection is made with the command Connect, followed by a channel number. Query:

$Vwr$Connect$123456

The client will then verify this connection by an 'Ok.' on the channel. Repeating the query with a different channel will change the agreed upon channel to the new one.

Once a connection is made, the LSL Script can execute all the other queries

There are some general basic functions.

$Vwr$Capabilities
$Vwr$Client
$Vwr$Creator
$Vwr$OperatingSystem

Then there are 'Packages' or 'Extensions', much like in Dale's implementation, but not really requiring a full name of the creator.

The current extension available is 'Nexii', this contains some client side processing like Raycasting (custom raytraces of a line), or special features like the Picker (third-person click-triggered raycasting).

Some or most functions require special permissions (using the normal permission system but with custom bits) that may contain sensitive data or incorrect use causing potential system instability, this makes sure that rouge scripts won't be able to cause havoc or pry on private information unless explicit permission is given by the user.

(Note: Dialogs are incorrectly referenced currently, despite being the correct permissions given, not sure why its doing this exactly)

Components

Picker

Brief
Allows a script to subscribe to the 'picker', which is basically to know where a user clicks/touches (Actions) on certain surfaces/objects/geometry (SurfaceType) and what kind of data the script wants (Output) back out of the actions. The subscribe function expects 'bits' that are OR'd together ("|") (OR is a bitwise operator).
Call
$Vwr$Nexii$Picker$Subscribe$ActionBits OR'd SurfaceTypeBits OR'd OutputBits

Bits

Actions
Start, Stop, for touchable surfaces, any prim with scripts that have a touch event handler.
Start Click, Stop Click, just ordinary empty clicks that didn't lead to anything.
Surface Types
HUD, Av, Prims, Terrain, Water, Water is untested
Output
Pos, equivilant to llDetectedTouchST.
Normal, equivilant to llDetectedTouchNormal.
Binormal, equivilant to llDetectedTouchBinormal.
UUID, the key of the object hit.
Get Touch, the type of the touch for this message.
Get Type the (internal) object type of the surface hit.

Picker Example

$Vwr$Nexii$Picker$Subscribe$Start Click|Stop Click|Prims|Pos
This subscription would cause any start and stop clicks on prims, to cause a message to be returned to the connected channel, simply with the Pos, which is the intersection and precise location in world coordinates where these clicks ocurred by the connected user. For example "<125.45,23.8,123.456>", which could then be easily converted into a vector and plugged into functions directly.
$Vwr$Nexii$Picker$Subscribe$Start Click|Av|UUID
This simply returns the UUID of any Avatars that were clicked on into the connected channel.

Picker Ghosting

Brief
A function to position any single prim or linked object wherever the cursor 'hovers'. Only one Ghost may exist. A ghost may be removed via setting the target key to a null key, this may cause the target to disappear from the users screen and an update may be needed to return it to the original location.
Call
:$Vwr$Nexii$Picker$Ghost$Key1:Value1|Key2:Value2:Value3|Key3:Value4|...
Keys
uuid, the target object to ghost.
Mode, Argument takes a single integer defining the mode of the ghosting. 0: Instant, 1: Damped, 2: No Rotation, 3: Limit Rotation (Arc Max/Min/Dir)
Arc, Value 1 is the maximum of arc (1.0 ~> -1.0, Default 1.0), Value 2 is the minimum of the arc (-1.0 ~> 1.0, Default -1.0). Equivilance: 1.0 is horizontal, 0.0 is vertical, -1.0 is upside down, 0.5 is 45 degrees.
Dir, direction to test the arc against.

Arc can easily be imagined as llSensor or more specifically a dimpled sphere. Dir (Direction) is a normalised vector that points into the direction of the dimpled sphere's rotation or where the sphere is looking towards.

Selection

Brief
Allows scripts to connect to the Selection Manager of the client which handles prim selections.
Call
:$Vwr$Nexii$Selection$Selection$Mode
Mode
:Only FirstObject available at the moment, which immediately returns the UUID of the root object in a selection.

Examples

These work from Vertical Life v1.5 on up to v1.5.3. v1.5.4 has had some changes in Picker.

Picker

default {
    state_entry(){
        llListen( 9000, "", llGetOwner(), "" );
        llOwnerSay( "$Vwr$Ping$9000" );
    }
    
    listen( integer ch, string nm, key k, string msg ){
        if( msg == "pong:0" ) state Main;
    }
    
    on_rez( integer p ){ llResetScript(); }
}

state Main {
    state_entry(){
        llListen( 9001, "", llGetOwner(), "" );
        llOwnerSay( "$Vwr$Connect$9001" );
    }
    
    run_time_permissions( integer p ){
        if( p & (0x1<<31) ) llOwnerSay( "$Vwr$Nexii$Picker$World|All" );
    }
    
    listen( integer ch, string nm, key k, string msg ){
        if( msg == "Ok." ){
            llOwnerSay( "Connection Created" );
            llRequestPermissions( llGetOwner(), (0x1<<31) );
        } else {
            list t = llParseString2List( msg, ["$"], [] );
            vector Pos = (vector)llList2String(t,0);
            vector Scale = llGetScale();
            rotation Rot = llRotBetween( <0,0,1>, (vector)llList2String(t,1) );
            if( Pos != ZERO_VECTOR && Pos != llGetPos() )// Sanity Check
                llSetPrimitiveParams([PRIM_POSITION,Pos+(<0,0,Scale.z/2>*Rot),PRIM_ROTATION,Rot]);
        }
    }
    
    on_rez( integer p ){ llResetScript(); }
}

Benchmark

list Data = [];
integer Tick;

default{
    state_entry(){
        llSetColor( <1,0,0>, -1 );
        llListen( 30, "", llGetOwner(), "" );
    }
    
    touch_start( integer dn ){
        llSetColor( <1,0,0>, -1 );
        llOwnerSay( "Creating connection to owner..." );
        llOwnerSay( "$Vwr$Connect$30" );
    }
    
    listen( integer ch, string nm, key k, string msg ){
        if( msg == "Ok." ) state Two;
    }
}

state Two{
    state_entry(){
        llOwnerSay( "Connection successful." );
        llSetColor( <1,1,0>, -1 );
        llListen( 30, "", llGetOwner(), "" );
        Tick = 0; Data = [];
        llOwnerSay( "Executing functions..." );
        llOwnerSay( "$Vwr$Capabilities" );
    }
    
    listen( integer ch, string nm, key k, string msg ){
        if( Tick == 0 ){
            Data += msg; ++Tick;
            llOwnerSay( "$Vwr$Creator" );
        } else if( Tick == 1 ){
            Data += msg; ++Tick;
            llOwnerSay( "$Vwr$OperatingSystem" );
        } else if( Tick == 2 ){
            Data += msg;
            state Three;
        }
    }
}

state Three{
    state_entry(){
        llSetColor( <0,1,0>, -1 );
        llOwnerSay( "Complete. Debug:\n"+
            "Capabilities: "+llList2String(Data,0) +"\n"+
            "Creator: "+llList2String(Data,1) +"\n"+
            "OS: "+llList2String(Data,2) );
        llListen( 30, "", llGetOwner(), "" );
        llRequestPermissions( llGetOwner(), (0x1<<32)|(0x1<<31) );
    }
    
    run_time_permissions( integer p ){
        if( p && 1073741824 ){
            llOwnerSay( "Selection Permission granted." );
        }
    }
        
    touch_start( integer dn ){
        if( llDetectedKey(0) == llGetOwner() ){
            llOwnerSay( "$Vwr$Nexii$Picker$World|All" );
            //llOwnerSay( "$Vwr$Nexii$Selection$FirstObject" );
        }
    }
    
    listen( integer ch, string nm, key k, string msg ){
        list t = llParseString2List( msg, ["$"], [] );
        vector Pos = (vector)llList2String(t,0);
        rotation Rot = llRotBetween(<0,0,1>,(vector)llList2String(t,1));
        if( Pos != ZERO_VECTOR ){
            llSetPrimitiveParams([PRIM_POSITION,Pos,PRIM_ROTATION,Rot]);
        }
        //if( llStringLength(msg) == 36 ){
        //    list t = llGetObjectDetails( msg, [OBJECT_NAME, OBJECT_POS] );
        //    llSay( 0, "Selected Object: "+llList2String(t,0)+" @ "+(string)llList2Vector(t,1) );
        //} else {
        //    llOwnerSay( msg );
        //}
    }
}

Supported Clients

Currently the Vertical Life Client is the only client currently with a working version of "Script Collaboration" LSL-Client communication.

Official Vertical Life Client Forum http://nexii.ordoimperialis.com/index.php

<FYI this is a dead link. Wolt Amat>