One thing I noticed when "renting" inside of Second Life is that you do have all the cool stats like with your own island so playing around a bit with Linden Scripting Languages and PHP I threw together a little object that would track both in world as well as RL visitors.
For everyone else this is where I get geeky...
<?php
// Read POST input
$post = file('php://input');
// If there isn't anything in the POST, don't do anything
if (!$post) {
die("go away");
}
// Read in the information that was sent
$grp = urldecode(chop($post[0]));
$name = urldecode(chop($post[1]));
// Make DB connections
$dbhost = 'localhost';
$dbuser = 'user';
$dbpass = 'password';
$conn = mysql_connect($dbhost, $dbuser, $dbpass) or die ('Error connecting to mysql');
$dbname = 'database';
mysql_select_db($dbname);
$sql = "INSERT INTO visitor(avatar,grp) VALUES ('".$name."', '".$grp."')";
echo $sql;
$sql_query = mysql_query($sql);
mysql_close($conn);
ob_flush();
flush();
?>
Just a small bit of PHP code to insert two passed parameters to a table in the database. It could be any database really...
The table is a simple table.
CREATE TABLE IF NOT EXISTS `visitor` (
`id` int(11) NOT NULL auto_increment,
`avatar` varchar(155) NOT NULL default '',
`timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP,
`grp` varchar(255) NOT NULL default '',
PRIMARY KEY (`id`),
KEY `avatar` (`avatar`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
"grp" in this case I added so I could track multiple areas with multiple objects.
Now once in world you'll need to create an ibject, any object really and then add a new script to it.
// Global variables
list visitor_list;
float range = 20.0; // in meters
float rate = 1.0; // in seconds
// Edit these to your own specifications
string GRP = "Office";
// This is the URL of the intermediary script. Don't change it unless
// you are using an intermediary of your own.
string WA = "http://www.myhost.com/myapp";
// Functions
help()
{
if (GRP == "") {
llOwnerSay(
"BEWARE! You have not configured a `group` " +
"Open the object, open the script, and fill in the variables at the top.");
}
}
integer isNameOnList( string name )
{
integer len = llGetListLength( visitor_list );
integer i;
for( i = 0; i < len; i++ )
{
if( llList2String(visitor_list, i) == name )
{
return TRUE;
}
}
return FALSE;
}
key presence_send(string url, string name, string msg)
{
return llHTTPRequest(WA+url,
[HTTP_METHOD, "POST"],
GRP + "\n" + name + "\n" + msg);
}
// States
default
{
state_entry()
{
llSensorRepeat( "", "", AGENT, range, TWO_PI, rate );
llListen(0, "", "", "");
}
sensor( integer number_detected )
{
integer i;
for( i = 0; i < number_detected; i++ )
{
//if( llDetectedKey( i ) != llGetOwner() )
//{
string detected_name = llDetectedName( i );
if( isNameOnList( detected_name ) == FALSE )
{
visitor_list += detected_name;
presence_send("visitor_insert.php", detected_name, "");
}
//}
}
}
listen( integer channel, string name, key id, string message )
{
if( message == "help" )
{
llOwnerSay( "This object records the names of everyone who" );
llOwnerSay( "comes within "+ (string)range + " meters." );
llOwnerSay( "Commands the owner can say:" );
llOwnerSay( "'say list' - Says the names of all visitors on the list.");
llOwnerSay( "'say num' - Says the number of visitors on the list.");
llOwnerSay( "'reset list' - Removes all the names from the list." );
}
else
if( message == "say list" )
{
llOwnerSay( "Visitor List:" );
integer len = llGetListLength( visitor_list );
integer i;
for( i = 0; i < len; i++ )
{
llOwnerSay( llList2String(visitor_list, i) );
}
llOwnerSay( "Total = " + (string)len );
}
else
if( message == "say num" )
{
integer len = llGetListLength( visitor_list );
llOwnerSay( "Total = " + (string)len );
}
else
if( message == "reset list" )
{
visitor_list = llDeleteSubList(visitor_list, 0, llGetListLength(visitor_list));
llOwnerSay( "Done resetting.");
}
}
}
The in world interface here is not that much, the key is the RL database.
// Global variables
float range = 20.0; // in meters
float rate = 1.0; // in seconds
// Edit these to your own specifications
string GRP = "Office";
// This is the URL of the intermediary script. Don't change it unless
// you are using an intermediary of your own.
string WA = "http://www.myhost.com/myapp";
// Functions
help()
{
if (GRP == "") {
llOwnerSay(
"BEWARE! You have not configured a `group` " +
"Open the object, open the script, and fill in the variables at the top.");
}
}
key presence_send(string url, string name, string msg)
{
return llHTTPRequest(WA+url,
[HTTP_METHOD, "POST"],
GRP + "\n" + name + "\n" + msg);
}
// States
default
{
state_entry()
{
llSensorRepeat( "", "", AGENT, range, TWO_PI, rate );
}
sensor( integer number_detected )
{
integer i;
for( i = 0; i < number_detected; i++ )
{
presence_send("visitor_insert.php", detected_name, "");
}
}
}
So as you can see you can make the in world LSL script even smaller.
You see what you really want is the data in the database and manily the Avatar name and the timestamp. With that you can use your favorite DB reporting tool to find out the type of traffic and repeat traffic the area your object is in is receiving, setup to objects an "in" and "out" group and you might even be able to track how many users are passing through from one location to another although that doesn't account for those who teleport straight out or away or simply go out the same way they go in. But you get the idea...