[Protocol and Code] Link message handling for complex projects

Soen Eber

Vatican mole
VVO Supporter 🍦🎈👾❤
Joined
Sep 20, 2018
Messages
3,671
Waaaayyy overkill for a short project, but as a project grows in complexity with multiple scripts and moving parts, this can help organize things better.

Imagine you you have a control panel, and you flick a switch to do something. That "something", possibly in a separate link prim, gets the message, does the job, and answers back with a status. Just a "simple" way to communicate back-and-forth between different parts of the code. Well, simple when you have 3,000 lines of code in half a dozen scripts and 4 linked prims in the project. I'm posting this because I'm getting kind of tired, from digging through old projects just to tear out the linked list handling code.

This also includes a couple of my standard conventions: preceding globals with underscores, and having an init() block which is called from state_entry, and can also be called to reset global variables to initial values when needed. This helps to catch bugs which can occur when the coder forgets to clear or reset a value when running the code multiple times and it is not convenient to reset a script due to needing to preserve some of the globals while resetting others.

Protocol is pretty simple:
every script has a hardcoded value
string _me = "some kind of name";
the link message function and handler sends/receives a packet consisting of
src (who sent the message)
tgt (who the message is for)
cmd (what to do)
arg (if there are args)
Here are two scripts: panel, and indicator. They can be in the same or different prims

panel
Code:
string  _me = "panel";
integer _switch = FALSE;

on()
{
    llMessageLinked(LINK_SET,0,_me+"|indicator|switch|on",NULL_KEY);
}
off()
{
    llMessageLinked(LINK_SET,0,_me+"|indicator|switch|off",NULL_KEY);
}
default
{
    touch_end(integer num_detected)
    {
        _switch = !_switch;
        if (_switch) on();
        else off();
    }
    link_message(integer source, integer num, string msg, key id)
    {
        string fn = "link_message("+(string)source+","+(string)num+","+msg+","+(string)id;
        // llOwnerSay("switch heard"+fn) // uncomment to see all link_message args

        list lMsg = llParseString2List(msg, ["|"], []);
        string src = llList2String(lMsg,0);
        string tgt = llList2String(lMsg,1);
        string cmd = llList2String(lMsg,2);
        string arg = llList2String(lMsg,3);
     
        if (tgt == _me) {
            llOwnerSay("indicator heard "+msg);
            if (src == "indicator") {
                if (cmd == "switch") {
                    if (arg == "green") llOwnerSay("switch has been turned on");
                    if (arg == "red") llOwnerSay("switch has been turned off");
                }
            }
        }
    }
}
indicator
Code:
string  _me = "indicator";

set_neutral()
{
    llOwnerSay("setting to neutral");
    llSetColor(<1,1,1>,ALL_SIDES); // turn prim white (unchanged if plywood)
}
turn_on()
{
    llOwnerSay("turning on");
    llSetColor(<0,1,0>,ALL_SIDES); // turn prim green
}
turn_off()
{
    llOwnerSay("turning off");
    llSetColor(<1,0,0>,ALL_SIDES); // turn prim red
}
init()
{
    set_neutral();
}
default
{
    state_entry()
    {
        init();
    }
    link_message(integer source, integer num, string msg, key id)
    {
        string fn = "link_message("+(string)source+","+(string)num+","+msg+","+(string)id;
        // llOwnerSay("indicator heard"+fn) // uncomment to see all link_message args

        list lMsg = llParseString2List(msg, ["|"], []);
        string src = llList2String(lMsg,0);
        string tgt = llList2String(lMsg,1);
        string cmd = llList2String(lMsg,2);
        string arg = llList2String(lMsg,3);
     
        if (tgt == _me) {
            llOwnerSay("indicator heard "+msg);
            if (cmd == "switch") {
                if (arg == "on") {
                    turn_on();
                    llMessageLinked(LINK_SET, 0, _me+"|"+src+"|indicator|green", NULL_KEY);
                }
                else if (arg == "off") {
                    turn_off();
                    llMessageLinked(LINK_SET, 0, _me+"|"+src+"|indicator|red", NULL_KEY);
                }
            }
        }
    }
}
 
Last edited: