User:Antony Fairport/Scripts/Simple Security System

From Second Life Wiki
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

This was originally done as an experiment, just to get to know how these things work. There are, of course, some very sophisticated security systems out there; I imagine there's even some really nice free ones too. But I wanted to have a go at writing a simple one myself and what you see below is the result.

To use it, all you need to do is create a prim and drop the script inside. Create a notecard called "Security" and also drop that in the prim. The notecard is what configures the security script. There are two types of setting for the notecard: "Owner=" and "Access=". The owner setting (one per line) lets you set up the list of people who can turn the security system on and off (by touching the prim). The access setting lets you set up the list of people who simply have have access. People who aren't on the owner or access list will be sent home when they come in range of the prim.

You can also set the rage (in meters) with "range=" and the frequency of the scans (in seconds) with "frequency=". Note that only avatars over land you own will be ejected -- this means it's safe to have a range that might extend out of parts of the plot being covered.

If the land is owned by a group, the object that contains the script will also have to be deeded to the group to work.

Because I use llTeleportAgentHome I'd advise not using this on the ground, especially not in a location where passing traffic might inadvertently wander into your plot. If you must use it in such a situation perhaps consider switching to llEjectFromLand instead?

Here's an example notecard:

Owner = Antony Fairport
Owner = Zardia Avindar
Access = Zanda Slacker

And here's the script:

//////////////////////////////////////////////////////////////////////
// Simple security system.
// By Antony Fairport.
//
// Revision history.
// =================
//
// 2011-06-27
// Initial version.

//////////////////////////////////////////////////////////////////////
// Constants.
string CONFIG_FILE = "Security";

//////////////////////////////////////////////////////////////////////
// Global configuration.
float g_nRange;         // Range to scan.
float g_nFrequency;     // Frequency of checks.
list  g_lOwners;        // Owner list.
list  g_lAccess;        // Access list.

//////////////////////////////////////////////////////////////////////
// Config reading globals.
key     g_keyConfig;
integer g_iConfig;

//////////////////////////////////////////////////////////////////////
// Is the given avatar on the given list?
integer AvatarInList( string sAvatar, list l )
{
    return ~llListFindList( l, [ sAvatar ] );
}

//////////////////////////////////////////////////////////////////////
// Is the given avatar an owner?
integer IsOwner( string sName )
{
    return AvatarInList( sName, g_lOwners );
}

//////////////////////////////////////////////////////////////////////
// Does the given avatar have access?
integer HasAccess( string sName )
{
    return AvatarInList( sName, g_lAccess );
}

//////////////////////////////////////////////////////////////////////
// Eject the intruder.
Eject( key keyIntruder )
{
    // Tell the intruder what we're doing to them.
    llInstantMessage( keyIntruder, "You do not have access to this location. Sending you home." );
    
    // And send them home.
    llTeleportAgentHome( keyIntruder );
}

//////////////////////////////////////////////////////////////////////
// Default state.
default
{
    //////////////////////////////////////////////////////////////////
    // State entry.
    state_entry()
    {
        // Read the configuration.
        state Configure;
    }
}

//////////////////////////////////////////////////////////////////////
// Configuration state.
state Configure
{
    //////////////////////////////////////////////////////////////////
    // State entry.
    state_entry()
    {
        // Let the user know what's happening.
        llWhisper( 0, "Reading configuration." );
        
        // Clear out the config.
        g_nRange     = 96.0;
        g_nFrequency = 5.0;
        g_lOwners    = [];
        g_lAccess    = [];
        
        // If it looks like we've got config...
        if ( llGetInventoryType( CONFIG_FILE ) == INVENTORY_NOTECARD )
        {
            // ...start reading it.
            g_keyConfig = llGetNotecardLine( CONFIG_FILE, g_iConfig = 0 );
        }
        else
        {
            // Tell the user things aren't good.
            llWhisper( 0, "No security configuration found. Turning off." );
        }
    }
    
    //////////////////////////////////////////////////////////////////
    // Handle data server responses.
    dataserver( key queryid, string data )
    {
        // If this is our query...
        if ( queryid == g_keyConfig )
        {
            // If this isn't the end of the file...
            if ( data != EOF )
            {
                // If the line doesn't look like it's a comment, and it isn't empty...
                if ( ( llGetSubString( data, 0, 0 ) != "#" ) && ( llStringTrim( data, STRING_TRIM ) != "" ) )
                {
                    // Split the line into a list.
                    list sLineData = llParseString2List( data, [ "=" ], [] );
                    
                    // Pull out the setting name.
                    string sSetting = llToLower( llStringTrim( llList2String( sLineData, 0 ), STRING_TRIM ) );
                    
                    // Pull out the setting value.
                    string sValue = llStringTrim( llList2String( sLineData, 1 ), STRING_TRIM );
       
                    // Owner?
                    if ( sSetting == "owner" )
                    {
                        g_lOwners += [ sValue ];
                        g_lAccess += [ sValue ];
                        llWhisper( 0, "Owner: " + sValue );
                    }
                    // Access list?
                    else if ( sSetting == "access" )
                    {
                        g_lAccess += [ sValue ];
                        llWhisper( 0, "Access: " + sValue );
                    }
                    // Range?
                    else if ( sSetting == "range" )
                    {
                        g_nRange = (float) sValue;
                        llWhisper( 0, "Range: " + sValue );
                    }
                    // Frequency?
                    else if ( sSetting == "frequency" )
                    {
                        g_nFrequency = (float) sValue;
                        llWhisper( 0, "Frequency: " + sValue );
                    }
                }
                
                // Read the next line.
                g_keyConfig = llGetNotecardLine( CONFIG_FILE, ++g_iConfig );
            }
            else
            {
                // Config read. Get protecting.
                state Protect;
            }
        }
    }
}

//////////////////////////////////////////////////////////////////////
// Paused state -- does nother but waits to be activated again.
state Paused
{
    //////////////////////////////////////////////////////////////////
    // State entry.
    state_entry()
    {
        // Tell the user we're paused.
        llWhisper( 0, "Security protection is paused." );
        
        // And add some hover text too.
        llSetText( "Security system paused.", < 1.0, 0.0, 0.0 >, 1.0 );
    }
    
    //////////////////////////////////////////////////////////////////
    // Handle a touch.
    touch_end( integer num_detected )
    {
        // If it's an owner who touched us...
        if ( IsOwner( llDetectedName( 0 ) ) )
        {
            // Jump back to the protect state.
            state Protect;
        }
    }
    
    //////////////////////////////////////////////////////////////////
    // Detect change.
    changed( integer change )
    {
        // If the inventory has changed...
        if ( change & CHANGED_INVENTORY )
        {
            // ...start over.
            state Configure;
        }
    }
}

//////////////////////////////////////////////////////////////////////
// Protect state -- does the scanning and ejecting.
state Protect
{
    //////////////////////////////////////////////////////////////////
    // State entry.
    state_entry()
    {
        // Let the user know what's happening.
        llWhisper( 0, "Security protection is enabled." );
        
        // Remove any hover text.
        llSetText( "", < 1.0, 1.0, 1.0 >, 0.0 );
        
        // Start the sensor.
        llSensorRepeat( "", "", AGENT_BY_LEGACY_NAME, g_nRange, PI, g_nFrequency );
    }
    
    //////////////////////////////////////////////////////////////////
    // State exit.
    state_exit()
    {
        // Make sure the sensor is removed.
        llSensorRemove();
    }

    //////////////////////////////////////////////////////////////////
    // Handle the sensor result.
    sensor( integer num_detected )
    {
        integer i;
        
        // For each detected avatar...
        for ( i = 0; i < num_detected; i++ )
        {
            // If they are over our land...
            if ( llOverMyLand( llDetectedKey( i ) ) )
            {
                // If they're not on the access list...
                if ( !HasAccess( llDetectedName( i ) ) )
                {
                    // Eject them.
                    Eject( llDetectedKey( i ) );
                }
            }
        }
    }
    
    //////////////////////////////////////////////////////////////////
    // Handle a touch.
    touch_end( integer num_detected )
    {
        // If it's an owner who touched us...
        if ( IsOwner( llDetectedName( 0 ) ) )
        {
            // Jump to the paused state.
            state Paused;
        }
    }
    
    //////////////////////////////////////////////////////////////////
    // Detect change.
    changed( integer change )
    {
        // If the inventory has changed...
        if ( change & CHANGED_INVENTORY )
        {
            // ...start over.
            state Configure;
        }
    }
}