Table of Contents

Recompile a Scripting within a Primitive

3 August 2023

  • C12 - added error message reporting.

3 September 2020

  • C11 - added.
recompilescript (Commands)
TypeCorrade progressive command
Commandrecompilescript
DescriptionThe recompilescript command can be used to recompile a script within an in-world primitive.
Permissionsinventory, interact
Parametersgroup, password, item, target
Last ChangesRelease 9.164 - added.

The getprimitivescripttext command is used to retrieve the text of a script inside a primitive's (task) inventory.

Command Required Parameters Required Corrade Permissions Example
getprimitivescripttext group, password, item, target inventory, interact
llInstantMessage(CORRADE,
    wasKeyValueEncode(
        [
            // Recompile a script named "New Script" 
            // within a primitive named "myscriptedobject" 
            "command", "recompilescript",
            "group", wasURLEscape(GROUP),
            "password", wasURLEscape(PASSWORD),
            // The name or UUID of the script.
            "target", "New Script",
            "range", "5",
            // The in-world primitive name or UUID.
            "item", "myscriptedobject",
            "callback", wasURLEscape(URL)
        ]
    )
);
Optional Parameter Possible Value Description
range an integer value The range in meters to look for the primitive to retrieve a script's text from.
selection attached, rezzed or all (default: all) Either attached, rezzed or all for selecting only primitives or objects attached to avatars, primitives or objects rezzed in-world or all primitives or objects respectively.
mono True or False (default: True) Whether to recompile the script using mono.
run True or False (default: True) Whether the script should be marked as "running".
reset True or False (default: False) Whether to reset the script after compilation.

Retrieving Compilation Messages

The reason why this command succeeds in case the script does not compile is due to the fact that transferring a script, even a broken script, to a primitive is a perfectly valid action such that the success status of the command does not reflect the status of compiling the LSL script but rather reflects the status of the execution of the updatescript command. One would usually issue a compilescript command in order to create a script and check whether the script compiles and only then transfer the script to a primitive. However, the updatescript allows a sort of shorthand where the user can transfer the script, compile it and also check for any compilation errors.

The updatescript command returns a value passed to the data key of the callback that can be unpacked in case the compilation of the LSL script failed in order to retrieve the messages. The order of operations to retrieve the error messages would be the following:

  • ensure that the success status of the command from the callback is true (success=True),
  • retrieve the data key of the command callback using wasKeyValueGet,
  • unescape the value of the data key using wasURLUnescape,
  • convert the value of the data key to a list,
  • locate the cell compiled within the CSV list and retrieve its value as an offset of +1 in order to ensure that the script failed to compile (index of compiled + 1),
  • retrieve the value of the cell messages (index of message + 1),
  • unescape the value of the messages cell,
  • convert the value of the messages cell to a CSV list,
  • for all cells in the CSV list:
    • unescape the value of the cell (using wasURLUnescape),
    • process the value as one of the script compilation errors

Although that might seem complicated, it is easier to write in LSL code:

// check whether the command was successful
if(wasURLUnescape(wasKeyValueGet("success", body)) != "True") {
    llOwnerSay("Command was not successful.");
    return;
}
// retrieve the value of the data key from the callback
string data = wasURLUnescape(wasKeyValueGet("data", body));
// convert the value of the data key to an LSL list
list values = wasCSVToList(data);
// check whether the script compiled successfully
string success = llList2String(
    values,
    llListFindList(values, ["compiled"]) + 1
);
if(success != "True") {
    // the script did not compile successfully so unpack the messages
    string messages = wasURLUnescape(
        llList2String(
            values,
            llListFindList(values, ["message"]) + 1
        )
    );
    // convert the messages to a list of messages
    // multiple error messages are possible during the compilation of an LSL script
    list errors = wasCSVTolist(messages);
    do {
        string error = wasURLUnescape(
            llList2String(
                errors, 
                0
            )
        );
        errors = llDeleteSubList(errors, 0, 0);
 
        // act upon the error message stored in the "error" variable
 
    } while(llGetListLength(errors) != 0);
} 

The main highlight is that Corrade will double escape the script compilation errors:

  • once in order to escape the value of the message CSV key in order to not create any conflicts with any other data returned by the command as part of the data KVP key,
  • twice, for all individual error messages that have been returned from the script compilation

Here is an abbreviated callback value for the updatescript command:

command=updatescript&time=...&data=item,..,asset,..,message,(2%252C%2B23)%2B%253A%2BERROR%2B%253A%2BName%2Bnot%2Bdefined%2Bwithin%2Bscope%250A,compiled,False&success=True

The unescaping or unpacking of the error messages can be represented as an ASCII tree where each level represents an escape operation. Let's reduce the callback just to the value of the message key and perform the operations wasURLUnescape and wasCSVToList in order to reduce the escaped string to a series of error messages:

%2522ERROR%25282%252C%252010%2529%253A%2520Invalid%2520syntax%2522%2C%2522ERROR%25281%252C%25204%2529%253A%2520Jump%2520out%2520of%2520scope%2522

                                              wasURLUnescape                                                                                                       

         %22ERROR%282%2C%2010%29%3A%20Invalid%20syntax%22,%22ERROR%281%2C%204%29%3A%20Jump%20out%20of%20scope%22

                                               wasCSVToList

  %22ERROR%282%2C%2010%29%3A%20Invalid%20syntax%22   %22ERROR%281%2C%204%29%3A%20Jump%20out%20of%20scope%22

              wasURLUnescape                                            wasURLUnescape
          
      "ERROR(2, 10): Invalid syntax"                           "ERROR(1, 4): Jump out of scope"
                                                              
2021/01/03 09:13

Notes