Geek To The EEP

In an outdoor photo, you can see the weather. In a film, you can FEEL the weather. That's because the dynamic medium represents how the weather CHANGES environmental cues: Clouds move in and the sky darkens, lighting changes, the sea gets heavy.

What if we could give our visitors that feeling in an intentional, _directed_ series of environmental settings? Immerse them in a little program of weather dynamics?

Below is a sample Experience script that demonstrates features of the new Environment Enhancement Project (EEP), to provide just that kind of weather-changing experience, individually for each visitor. As configured, it applies a sequence of four Library environmental "sky" assets to make the weather seem progressively more threatening over about a minute and a half after arrival. (In real use, you might choose longer transition intervals to stretch this out more realistically. And of course you can use other EEP environments in any sequence - perhaps a cheery brightening of the sky as clouds lift.)


/*
Released into Public Domain, 2020, Qie Niangao for Bay City Post
Give visitors an enhanced experience with a SERIES of Environments
So clouds can build, sky can darken, seas roil more over time - or vice versa
(sample Environments in ENV_STAGES below are super primitive, just to demo the concept)
This basic script uses simple passage of time to trigger next stage
Make sure parcel (at least) has the script's Experience enabled
*/

//== USER SPECIFIED CONSTANTS =======================

integer AGENT_SCOPE = AGENT_LIST_PARCEL; // or AGENT_LIST_PARCEL_OWNER or AGENT_LIST_REGION
// but if they're on land without the Experience, there will be errors
list ENV_STAGES = // sequence of (SAMPLE) Environment UUIDs and durations (in seconds)
[ "d15d3fb0-7e14-4af8-203e-33b85346f3f1", 20 // "Neutral" Library sky
, "cd880f86-53c7-1a91-532c-2797f517a35f", 20 // "Daytime shadows" Library sky
, "07899451-b3d8-9f5c-563b-14b89eda481d", 30 // "Dusty" Library sky
, "2a000d12-e692-da2a-9e08-0cbda70bc0bf", 30 // "PaperSnow" Library sky
]; // These use unnaturally short durations for demo & testing)
float AVATAR_SCAN_INTERVAL = 10.0; // in seconds.
// Not a real sensor, but still some list manipulation, so keep it as long as tolerable
// A new arrival may wait UP TO this interval, so just half this time on average
integer MAX_IGNORED_AGENTS = 20; // after which, forget the oldest (prevent memory leak)
integer MAX_STARTING_AGENTS = 3; // most we'll wait to reply to permissions request (prevent leak)

//== SCRIPT-MANAGED VARIABLES =======================

list tAvStages; // avatar UUIDs in scope, index of their Env.stage, preceded by time to move through stage
list ignoredAgents; // don't spam these with more exp perm requests
key parcelID;
list agentsStarting;

debugOut(string outStr) {
// llOwnerSay(outStr);
}

default
{
state_entry()
{
if ([] == llGetExperienceDetails(NULL_KEY))
{
llWhisper(DEBUG_CHANNEL, "Script \""+llGetScriptName()+"\" is not associated with an experience. Exiting.");
return;
}
// trivial, impossible to match sensor, just set a repeating no_sensor interval:
llSensorRepeat("NO SUCH NAME", llGetKey(), AGENT, 0.01, 0.01, AVATAR_SCAN_INTERVAL);
parcelID = llList2Key(llGetParcelDetails(llGetPos(), [PARCEL_DETAILS_ID]), 0);
}
on_rez(integer start_param)
{
llResetScript();
}
no_sensor()
{
list newAgents = llGetAgentList(AGENT_SCOPE, []);
// any already-staged agents need removing?
integer oldAgentIdx = llGetListLength(tAvStages) - 2;
while (0 <= oldAgentIdx)
{
key oldAgent = llList2Key(tAvStages, oldAgentIdx);
if (-1 == llListFindList(newAgents, [oldAgent]))
tAvStages = llDeleteSubList(tAvStages, oldAgentIdx-1, oldAgentIdx+1);
oldAgentIdx -= 3;
}
// any newly-arrived agents need request to add?
integer newAgentIdx = llGetListLength(newAgents);
while (0 <= --newAgentIdx)
{
key newAgent = llList2Key(newAgents, newAgentIdx);
integer scopeIdx = llListFindList(tAvStages, [newAgent]);
if (-1 == scopeIdx) // agent not yet in list of agents with managed environments
if ((-1 == llListFindList(ignoredAgents, [newAgent])) // agent didn't deny us in past
&& (-1 == llListFindList(agentsStarting, [newAgent]))) // and not already being invited
{
if (!llAgentInExperience(newAgent)) // agent new to this Experience: greet & invite
llRegionSayTo(newAgent, 0, "Greetings "+llGetDisplayName(newAgent)
+" and welcome! You're being invited to an Experience, \""
+ llList2String(llGetExperienceDetails(NULL_KEY), 0) // script's Experience name
+"\" that demonstrates dynamic personal Environment settings."
+" We hope you'll agree to participate."
+" (If you don't grant permissions, this script will try not to ask again for a while.)");
agentsStarting += newAgent;
if (MAX_STARTING_AGENTS < llGetListLength(agentsStarting))
agentsStarting = llList2List(agentsStarting, 1, -1);
llRequestExperiencePermissions(newAgent, "");
}
}
}
experience_permissions_denied(key agentId, integer reason)
{
integer agentStartingIdx = llListFindList(agentsStarting, [agentId]);
if (-1 != agentStartingIdx)
{
if (XP_ERROR_NOT_PERMITTED == reason)
{
if (-1 == llListFindList(ignoredAgents, [agentId]))
{
ignoredAgents += agentId; // don't spam after first request
if (llGetListLength(ignoredAgents) >= MAX_IGNORED_AGENTS)
ignoredAgents = llList2List(ignoredAgents, 1, MAX_IGNORED_AGENTS);
}
}
agentsStarting = llDeleteSubList(agentsStarting, agentStartingIdx, agentStartingIdx);
}
else
if (XP_ERROR_NOT_PERMITTED_LAND != reason)
// ignore _LAND perm error because it's raised every time agent moves to non-XP parcel
llWhisper(DEBUG_CHANNEL, "Experience permissions denied, reason #"+(string)reason
+": "+llGetExperienceErrorMessage(reason));
}
experience_permissions(key agentId)
{
integer agentStartingIdx = llListFindList(agentsStarting, [agentId]);
if (-1 != agentStartingIdx)
{
tAvStages = [llGetUnixTime(), agentId, 0] + tAvStages;
llSetTimerEvent(0.1);
agentsStarting = llDeleteSubList(agentsStarting, agentStartingIdx, agentStartingIdx);
return;
}
// else handle timer-triggered requests (process the tAvStages queue)
integer now = llGetUnixTime();
if (now >= llList2Integer(tAvStages, 0))
{
key agent = llList2Key(tAvStages, 1);
integer envIdx = llList2Integer(tAvStages, 2);
key env = llList2Key(ENV_STAGES, envIdx);
integer transition = llList2Integer(ENV_STAGES, envIdx + 1);
debugOut("process env "+(string)env+" for agent "+llKey2Name(agent)
+"\n\t with tAvStages = "+llDumpList2String(tAvStages, " | "));
integer envErr = llReplaceAgentEnvironment(agent, (float)transition, env);
if (0 > envErr)
llWhisper(DEBUG_CHANNEL, "Error in llReplaceAgentEnvironment : "+(string)envErr);
envIdx += 2; // advance agent to wait for next stage
integer nextTime = now + transition;
if (envIdx >= llGetListLength(ENV_STAGES))
nextTime = 2147483647; // Final env stage should last for rest of stay (MAXINT)
tAvStages = llListReplaceList(tAvStages, [nextTime, agent, envIdx], 0, 2);
}
tAvStages = llListSort(tAvStages, 3, TRUE); // lazy
float timeTo = (float)(llList2Integer(tAvStages, 0) - now);
if (0.0 >= timeTo) timeTo = 0.1;
llSetTimerEvent(timeTo);
}
timer()
{
llSetTimerEvent(0); // set again in exp_perms event
if (llGetListLength(tAvStages)) // any Avs left?
llRequestExperiencePermissions(llList2Key(tAvStages, 1), "");
}
}

Note that Experience permissions are required by llReplaceAgentEnvironment, the EEP function that makes this possible, so the script will need to be compiled to an Experience that's enabled on the land where it runs. And visitors have to grant the permissions requested when the script invites them to participate.

At the moment, EEP is only visible in the Linden viewer, but soon it'll be supported in popular third party viewers too. Although the script sequences the effect individually for each viewer, it manipulates what's called the "Shared Environment" -- so it can be overridden by users who specify their own environment or time-of-day.

Passage of time needn't be the only thing to trigger a change of EEP environment. Should one particular room or area have different lighting? Such a script would track where visitors roam and update their environments accordingly. Or maybe trigger environments by level in an in-world game, or in response to some scripted role-play interaction.

Another possible extension: _Sound_ is powerfully evocative of weather: wind, thunder, bird song, waves, etc: llPlaySound() in a HUD is heard only by the wearer; llAttachToAvatarTemp() could transparently attach a sound-emitting HUD to experience participants.
Reporter Qie Niangao
200504

No comments:

Post a Comment

Calendar



Park Plaza Hotel

Park Plaza Hotel
Please visit our Sponsor!

Luxury Living in Bay City


Park Plaza residents enjoy beautiful views, fine dining, and a roof top patio with hot tub; all this near route 66, and within walking distance to Hairy Hippo Fun Land and aquarium. Rates start at 55L a week for studios, and 185L a week for full size apartments. Free furnishings available. Contact Roc Plutonium for more information!

Archive