Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

llsensor() Invocation Once Per Avatar?

Meengla Yip
Registered User
Join date: 1 Feb 2007
Posts: 8
05-15-2007 11:59
Hi, the following script fragment is programmed to detect all avatars present within 2 meters and play a video file to all of them in asynchronous way (e.g. One avatar walks in and watches the video while another one walks in starts his own video watch without affecting the first avatar's experience--this part works fine).

Problem is that I have no way prevent the reload of video to the one who are already watching it. The script fragment below shows the Sensor event.
Any ideas?
Thanks in advance.

---------------------
sensor(integer total_number) // total_number is the number of avatars detected.
{


integer i;
for (i = 0; i < total_number; i++)
{
if (llDetectedKey(i) != NearbyUserIDPrev) {
llParcelMediaCommandList( [PARCEL_MEDIA_COMMAND_URL,(string) videofile, PARCEL_MEDIA_COMMAND_AGENT, llDetectedKey(i), PARCEL_MEDIA_COMMAND_TEXTURE, (key) screentexture, PARCEL_MEDIA_COMMAND_PLAY ] );

NearbyUserIDPrev = llDetectedKey(i);
llSay(0, "AFTER: " + (string) NearbyUserIDPrev);
llSetTimerEvent( 1 ); // NOTE: the timer() simply resets the script, thus starting to enable sensor() function again--and THAT IS WHAT IS CAUSING the replay of video.
}
}
Ordinal Malaprop
really very ordinary
Join date: 9 Sep 2005
Posts: 4,607
05-15-2007 12:14
You can only have one parcel media stream running at once, so if you reset it it will always reset for everyone.

If you want to have different avatars watching streams starting at different times (or even different streams) the way to do it is to subdivide the parcel into lots of small "booths", and have avs enter individually.
_____________________
http://ordinalmalaprop.com/forum/ - visit Ordinal's Scripting Colloquium for scripting discussion with actual working BBCode!

http://ordinalmalaprop.com/engine/ - An Engine Fit For My Proceeding, my Aethernet Journal

http://www.flickr.com/groups/slgriefbuild/ - Second Life Griefbuild Digest, pictures of horrible ad griefing and land spam, and the naming of names
Meengla Yip
Registered User
Join date: 1 Feb 2007
Posts: 8
05-15-2007 12:22
Yeah, I knew of the limitations but have gotten around it for the most part! What is needed in my script above is some way to check if the video is playing or some kind of LIST/array variable which will hold the names of the people (from the FOR LOOP) so that they dont' see the video again.
And that's where I need help.

Thanks!
Sys Slade
Registered User
Join date: 15 Feb 2007
Posts: 626
05-15-2007 13:22
From: Ordinal Malaprop
You can only have one parcel media stream running at once, so if you reset it it will always reset for everyone.

Take another look at his code, the one stream limit can be circumvented :p

@Meengla: everything you need for working with lists can be found here http://rpgstats.com/wiki/index.php?title=List

Simply place users who are already watching to a list, then search the list for the name in the sensor event. If they're in the list, continue, if not then play the vid and add them to the list.

CODE
if(llListFindList(watching, [llDetectedKey(0)]) == -1){
watching = (watching=[]) + watching + llDetectedKey(0);
// do your media commands here
}


You'll also want regular sensor sweeps for the names in the list so you can remove them in the no_sensor event otherwise you're likely to run into memory errors. Keeping track of the sensor sweeps might be a problem though unless you prevent the timed ones from running while cleaning the list.
_____________________
Send me the last 4 digits of a valid SSN, I'll verify you are who you say you are, even if you aren't.
Ordinal Malaprop
really very ordinary
Join date: 9 Sep 2005
Posts: 4,607
05-15-2007 15:15
Ah, sorry, it seems I was being a bit dense. That sounds like the right sort of thing though.
_____________________
http://ordinalmalaprop.com/forum/ - visit Ordinal's Scripting Colloquium for scripting discussion with actual working BBCode!

http://ordinalmalaprop.com/engine/ - An Engine Fit For My Proceeding, my Aethernet Journal

http://www.flickr.com/groups/slgriefbuild/ - Second Life Griefbuild Digest, pictures of horrible ad griefing and land spam, and the naming of names
Meengla Yip
Registered User
Join date: 1 Feb 2007
Posts: 8
05-15-2007 17:55
Thanks guys for your help. Okay, here is the fullcode!! But it still does not work (still replay/reload of same movie). You may try it in your own system....
Any more ideas? I think we are getting closer.


--------------------------------
string screentexture = "";
key http_request_id;
integer count;
string current_display = "My Video"; // CURRENT DISPLAY STRING
string videofile = "rtsp://blahblahblah.mov";//
string NearbyUser = "";
key NearbyUserID;
key NearbyUserIDPrev;
list watching;

Update_Display(string str) // UPDATE Control Panel DISPLAY's text
{
llSetText(str, <0,0,0>, 1);

}


default
{
state_entry()
{

count = 0;
screentexture = llGetTexture(-1);

// llSensorRepeat("", NULL_KEY, AGENT, 2, PI, 10); // scan for agents/avatars within 2 metres.
llSensor("",NULL_KEY,AGENT,PI,2);

Update_Display(current_display);//Show initial message in the Display area
}

sensor(integer total_number) // total_number is the number of avatars detected.
{
NearbyUserID = llDetectedKey(0);

llSay(0, "BEFORE: " + (string) NearbyUserIDPrev);
integer i;
for (i = 0; i < total_number; i++)
{
llSay(0, "AFTER: " + (string) NearbyUserIDPrev);
if(llListFindList(watching, [llDetectedKey(0)]) == -1){
watching = (watching=[]) + watching + llDetectedKey(0);
// do your media commands here
llParcelMediaCommandList( [PARCEL_MEDIA_COMMAND_URL,(string) videofile, PARCEL_MEDIA_COMMAND_AGENT, llDetectedKey(i), PARCEL_MEDIA_COMMAND_TEXTURE, (key) screentexture, PARCEL_MEDIA_COMMAND_PLAY ] );
count == 0;
llSetTimerEvent( 1 ); //
}

}

}

// if nobody is within 10 meters, say so.
no_sensor() {
llParcelMediaCommandList( [PARCEL_MEDIA_COMMAND_URL,(string) videofile, PARCEL_MEDIA_COMMAND_AGENT, NearbyUserID, PARCEL_MEDIA_COMMAND_TEXTURE, (key) screentexture, PARCEL_MEDIA_COMMAND_STOP] );
llResetScript();
}


timer () // run this code every time the timer event is raised
{
count ++; //increment count
if(count > 5) // reset after 10 secs
{
llResetScript();
// llSensor("", NULL_KEY, AGENT, 2, PI); // scan for agents/avatars within 2 metres.
Update_Display(current_display);
}
}


}
Sys Slade
Registered User
Join date: 15 Feb 2007
Posts: 626
05-16-2007 01:03
Quick look, you are resetting the script after 10 seconds which loses all records of who is watching and thus starts the movie for them again.

I'll have more time to look into it when I get back home, about 30 mins.
_____________________
Send me the last 4 digits of a valid SSN, I'll verify you are who you say you are, even if you aren't.
Domino Marama
Domino Designs
Join date: 22 Sep 2006
Posts: 1,126
05-16-2007 02:29
As well as taking the reset out (or take the timer out completely), there's a bit of confusion in the sensor event. You are looping on (i) but have a few references to llDetectedKey(0).
If you aren't changing the current_display, there's no need to run the update_display. I've included it below as an example of where it could go without a timer.

CODE
sensor(integer total_number) // total_number is the number of avatars detected.
{
for (i = 0; i < total_number; i++)
{
NearbyUserID = llDetectedKey(i);
if(llListFindList(watching, [NearbyUserID]) == -1)
{
watching = (watching=[]) + watching + NearbyUserID;
// do your media commands here
llParcelMediaCommandList( [PARCEL_MEDIA_COMMAND_URL,(string) videofile, PARCEL_MEDIA_COMMAND_AGENT, NearbyUserID, PARCEL_MEDIA_COMMAND_TEXTURE, (key) screentexture, PARCEL_MEDIA_COMMAND_PLAY ] );
}
}
Update_Display(current_display);
}
Sys Slade
Registered User
Join date: 15 Feb 2007
Posts: 626
05-16-2007 02:57
Here's something I threw together quickly, probably a few bugs in there :p
It uses 2 lists, one for user keys and one for scan times. It scans every 2 seconds, and if a user hasn't been detected in the last 3 seconds it removes them from the list.
You might hit problems with those timings on laggy sims, or with many users as the media command list will delay script execution for 2 seconds. Branching off the media command to a seperate script and calling it via a linked message would solve that problem.

CODE
list watching;
list scantimes;
string screentexture = "";
string current_display = "My Video";
string videofile = "rtsp://blahblahblah.mov";

Update_Display(string str){
llSetText(str, <0,0,0>, 1);
}

clean_lists(){
integer length=llGetListLength(scantimes);
if(length>0){
integer i=0;
do{
integer time=llList2Integer(scantimes,i);
if(time < (llGetUnixTime() - 3)){
llParcelMediaCommandList(
[PARCEL_MEDIA_COMMAND_AGENT, llList2Key(watching,i),
PARCEL_MEDIA_COMMAND_STOP]
);
watching=llDeleteSubList(watching,i,i);
scantimes=llDeleteSubList(scantimes,i,i);
llOwnerSay(llDumpList2String(watching,","));
if(length>1)
clean_lists();
return;
}else
i++;
} while(i<length);
}
}

default{
state_entry(){
screentexture = llGetTexture(-1);
llSensor("",NULL_KEY,AGENT,PI,2);
Update_Display(current_display);
}

sensor(integer t){
integer i=0;
do{
integer index=llListFindList(watching, [llDetectedKey(i)]);
if(index == -1){
watching = (watching=[]) + watching + llDetectedKey(i);
scantimes = (scantimes=[]) + scantimes + llGetUnixTime();
llParcelMediaCommandList(
[PARCEL_MEDIA_COMMAND_AGENT, llDetectedKey(i),
PARCEL_MEDIA_COMMAND_URL,(string) videofile,
PARCEL_MEDIA_COMMAND_TEXTURE, (key) screentexture,
PARCEL_MEDIA_COMMAND_PLAY]
);
}else
scantimes=llListReplaceList(scantimes,[llGetUnixTime()],index,index);
i++;
} while(i<t);
llSetTimerEvent(1);
}

no_sensor(){
integer length=llGetListLength(watching);
integer i=0;
do{
llParcelMediaCommandList(
[PARCEL_MEDIA_COMMAND_AGENT, llList2Key(watching,0),
PARCEL_MEDIA_COMMAND_STOP]
);
watching=llDeleteSubList(watching,0,0);
scantimes=llDeleteSubList(scantimes,0,0);
i++;
} while(i<length);
llSetTimerEvent(1);
}

timer(){
clean_lists();
llSensor("",NULL_KEY,AGENT,PI,2);
}
}
_____________________
Send me the last 4 digits of a valid SSN, I'll verify you are who you say you are, even if you aren't.
Meengla Yip
Registered User
Join date: 1 Feb 2007
Posts: 8
05-16-2007 07:54
Sys Slade,
Thanks a bunch for the code. I didn't get enough time to test it in SL (SL is down right now) but the replay/refresh stopped for at least one Avatar while the video did not play for another Avatar on a different prim (with the same script). I will test more later and let you know. But using the Lists to keep track of users who are in the vicinity seems like correct approach.
More later...
Meengla
Sys Slade
Registered User
Join date: 15 Feb 2007
Posts: 626
05-16-2007 09:42
There might be a bug in there somewhere involving counts or list pointers, not tested it with an alt, just playing for one user.
Another possibility is server lag causing the sensor event to be triggered after 3 seconds, which would mean the user seeing the video stop then restart.
Also, if you have more than a couple of people at once, the media commands should definately be moved to a second script and triggered through link messages to prevent the script pausing.
_____________________
Send me the last 4 digits of a valid SSN, I'll verify you are who you say you are, even if you aren't.
Meengla Yip
Registered User
Join date: 1 Feb 2007
Posts: 8
05-16-2007 10:54
Sys Slade,
Well, there are likely to be more than a couple of users at one time so it is better to start thinking of some other coding strategy.
Any other ideas? Do you have more info about this 'link message' way to go around the lag or other issues?
Thanks!
Meengla
Sys Slade
Registered User
Join date: 15 Feb 2007
Posts: 626
05-17-2007 03:28
In your main piece of code:
CODE

integer players=10;
list playTimes=[];
integer currentPlayer=0;

playVid(key id, string msg){
integer avail=llList2Integer(playTimes,currentPlayer);
if(avail >= llGetUnixTime()){
llSleep(1);
playVid(id,msg);
}else{
llMessageLinked(LINK_SET,currentPlayer + 1,msg,id);
playTimes=llListReplaceList(playTimes,[llGetUnixTime() + 2], currentPlayer, currentPlayer);
currentPlayer += 1;
if(currentPlayer >=players)
currentPlayer=0;
}
}

........
........

state_entry(){
integer i=0;
do{
playTimes += [0];
i++;
}while(i<players);
}

To start a vid, use playVid(llDetectedKey(i),"start";);
To stopa vid, use playVid(llList2Key(watching,i),"stop";);

Now create a script called vidplayer:
CODE
integer scriptnum;
string videofile="rtsp://blahblahblah.mov";
key texture;

default {
state_entry(){
scriptnum=llList2Integer(llParseString2List( llGetScriptName(), ["vidplayer "], [] ), 0);
texture=llGetTexture(-1);
}

link_message(integer sender_num, integer num, string msg, key id){
if(num==scriptnum){
if(msg=="start"){
llParcelMediaCommandList(
[PARCEL_MEDIA_COMMAND_AGENT, id,
PARCEL_MEDIA_COMMAND_URL, videofile,
PARCEL_MEDIA_COMMAND_TEXTURE, texture,
PARCEL_MEDIA_COMMAND_PLAY]
);
}else if(msg=="stop"){
llParcelMediaCommandList(
[PARCEL_MEDIA_COMMAND_AGENT, id,
PARCEL_MEDIA_COMMAND_STOP]
);
}
}
}
}

Now drop 10 copies of vidplayer (or however many you specify in players in your main script), and rename the one called "vidplayer" without a number to "vidplayer 10". Each copy should have a space and a number in the name.

Now you can send 10 media command sets every 2 seconds instead of 1.
_____________________
Send me the last 4 digits of a valid SSN, I'll verify you are who you say you are, even if you aren't.
Meengla Yip
Registered User
Join date: 1 Feb 2007
Posts: 8
05-17-2007 08:02
Hey, I will implement it later.
Thanks!