Skip to content

Media changes including support for PRIM_MEDIA_FIRST_CLICK_INTERACT and HUD autoplay #4177

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 160 additions & 0 deletions doc/testplans/PRIM_MEDIA_FIRST_CLICK_INTERACT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# Test plan for PRIM_MEDIA_FIRST_CLICK_INTERACT

## Requirements

- At least two accounts
- At least one group
- Land under your control

## Feature Brief

Historically media-on-a-prim (MOAP) in Second Life has been bound to a focus system which blocks mouse click/hover events, this feature creates exceptions to this focus system for a configurable set of objects to meet user preference.

## Testing

The following scripts and test cases cover each individual operational mode of the feature; in practice these modes can be combined by advanced users in any configuration they desire from debug settings. Even though the intended use case combines multiple modes, individual modes can be tested for functionality when tested as described below.

If testing an arbitrary combination of operational modes beyond what the GUI offers is desired, the parameters of the bitfield for calculation are located in lltoolpie.h under the MediaFirstClickTypes enum. As of writing there exists a total of ~127 possible unique/valid combinations, which is why testing each mode individually is considered the most efficient for a full functionality test.

### Scripts

#### Script A

This script creates a media surface that is eligible for media first-click interact. Depending on test conditions, this will exhibit new behavior.

```lsl
default {
state_entry() {
llSetLinkMedia( LINK_THIS, 0, [
PRIM_MEDIA_CURRENT_URL, "http://lecs-viewer-web-components.s3.amazonaws.com/v3.0/agni/avatars.html",
PRIM_MEDIA_HOME_URL, "http://lecs-viewer-web-components.s3.amazonaws.com/v3.0/agni/avatars.html",
PRIM_MEDIA_FIRST_CLICK_INTERACT, TRUE,
PRIM_MEDIA_AUTO_PLAY, TRUE,
PRIM_MEDIA_CONTROLS, PRIM_MEDIA_CONTROLS_MINI
] );
}
}

```

#### Script B

This script creates a media surface that is NOT eligible for media first-click interact. In all but one test case, this will behave the same way.

```lsl
default {
state_entry() {
llSetLinkMedia( LINK_THIS, 0, [
PRIM_MEDIA_CURRENT_URL, "http://lecs-viewer-web-components.s3.amazonaws.com/v3.0/agni/avatars.html",
PRIM_MEDIA_HOME_URL, "http://lecs-viewer-web-components.s3.amazonaws.com/v3.0/agni/avatars.html",
PRIM_MEDIA_FIRST_CLICK_INTERACT, FALSE,
PRIM_MEDIA_AUTO_PLAY, TRUE,
PRIM_MEDIA_CONTROLS, PRIM_MEDIA_CONTROLS_MINI
] );
}
}

```

## Standard testing procedure

You will be asked to enable media faces on multiple cubes, make sure that the webpage loads on each, and interact with them in the following ways.

1. Enable media for the cube, and verify that it displays a webpage.
2. Click on the terrain to clear any focus.
3. Hover your mouse over UI elements of the webpage, and **observe** if they highlight/react to the mouse cursor.
4. If hover events are not registered, clicking on the webpage and then **observe** if they begin reacting to hover events.
5. Clicking on the terrain to clear any focus once again.
6. Clicking on a UI element of the webpage and **observe** if it reacts to the first click, or requires a second click. *(Maximum of 2 clicks per attempt)*

These steps will be repeated for one or more pairs of cubes per test case to ensure that media first click interact is functioning within expectations. Unless otherwise mentioned for a specific test case, you simply need only be in the same region as the cubes to test with them.

## Test cases

All test cases begin with at least two cubes rezzed, one containing Script A henceforth referred to as Cube A and one with Script B referred to as Cube B. The steps of some test cases may impact the condition of the cubes, so keeping a spare set rezzed or in inventory to rapidly duplicate should improve efficiency if testing cases in series.

### Case 1 (MEDIA_FIRST_CLICK_NONE)

Ensure that debug setting `MediaFirstClickInteract` is set to `0`

Starting with Cube A and Cube B, perform the testing procedure on each.

**Expected observations:** Both webpages do not react to hover events until clicked, both webpages do not react to clicks until clicked once to establish focus

### Case 2 (MEDIA_FIRST_CLICK_HUD)

Ensure that debug setting `MediaFirstClickInteract` is set to `1`

Starting with Cube A and Cube B, attach them both to your HUD and perform the testing procedure on each. You may need to rotate or scale the cubes to fit on your screen before beginning testing. You may attach both at the same time, or only one at a time.

**Expected observations:** The webpage on Cube A will react to mouse cursor hover events and clicks without needing a focus click, but the webpage on Cube B will not.

### Case 3 (MEDIA_FIRST_CLICK_OWN)

Ensure that debug setting `MediaFirstClickInteract` is set to `2`

This test case requires two pairs of cubes, and the second pair must not be owned by your testing account. What owns them is not important, it can be a group or your second testing account.

Perform the testing procedure on both sets of cubes.

**Expected observations:** The webpage on Cube A will react to mouse cursor hover events and clicks without needing a focus click, but the webpage on Cube B will not. The other pair of cubes will react the same as your Cube B.

### Case 4 (MEDIA_FIRST_CLICK_GROUP)

Ensure that debug setting `MediaFirstClickInteract` is set to `4`

This test case requires two pairs of cubes, and the second pair must be deeded or set to a group that your testing account is a member of, but does not have set as active at the beginning of the test. As long as the second set of cubes is set to a group that your primary test account is a member of, the avatar that owns them does not matter.

1. Perform the testing procedure on both sets of cubes.
2. Activate the group that the second set of cubes is set / deeded to
3. Perform the testing procedure on both sets of cubes once more.

**Expected observations:** Both cubes owned by your primary testing account will not react to mouse cursor hover events and clicks without needing a focus click. Cube A set to group will react to mouse cursor hover events and clicks without needing a focus click, but Cube B will not.

### Case 5 (MEDIA_FIRST_CLICK_FRIEND)

Ensure that debug setting `MediaFirstClickInteract` is set to `8`

This test case requires three sets of cubes, one owned by you, one owned by another avatar on your friend list, and a third set owned by an avatar that is not on your friend list, or deeded to group. You can optionally use two sets of cubes, and dissolve friendship with your second account to test non-friend cubes.

Perform the testing procedure on all cubes

**Expected observations:** Cube A owned by a friended avatar will react to mouse cursor hover events and clicks without needing a focus click. All other cubes will not.

### Case 6 (MEDIA_FIRST_CLICK_LAND)

Ensure that debug setting `MediaFirstClickInteract` is set to `16`

This is the most tricky test case due to the multiple combinations that this operational mode considers valid. You will need multiple cubes, and can omit Cube B for brevity unless running a full test pass. This is probably most efficiently tested from your second account, using your first account to adjust the test parameters to fit other sub-cases.

Note: This requires the avatar that is performing the tests to physically be in the same parcel as the test cube(s). If you are standing outside of the parcel the media cubes are in, they will never react to mouse cursor hover events and clicks without needing a focus click under this operational mode.

1. Place down a set of cubes owned by the same avatar as the land
- The second account should see Cube A react to mouse cursor hover events and clicks without needing a focus click
- Cube B if tested, will not react in all further sub-cases and will not be mentioned further.

2. Adjust the conditions of the cubes and parcel such that they are owned by another avatar, but have the same group as the land set
- The second account should see Cube A react to mouse cursor hover events and clicks without needing a focus click

3. Adjust the conditions of the cubes and parcel such that they are deeded to the same group that the parcel is deeded to
- The second account should see Cube A react to mouse cursor hover events and clicks without needing a focus click

4. Adjust the conditions of the cubes and parcel such that the parcel and cubes do not share an owner, or a group
- The second account should see Cube A NOT react to mouse cursor hover events until clicked, and clicks WILL need a focus click before registering.

### Case 7 (MEDIA_FIRST_CLICK_ANY) (optional)

Ensure that debug setting `MediaFirstClickInteract` is set to `31`

Repeat test cases 1-6.

1. Test case 1 should fail
2. Test cases 2-6 should pass

### Case 8 (MEDIA_FIRST_CLICK_ALL) (optional)

Ensure that debug setting `MediaFirstClickInteract` is set to `1073741824`

Repeat test cases 1-6, there is no pass/fail for this run.

All cubes including B types should exhibit the same first-click interact behavior.
22 changes: 22 additions & 0 deletions indra/newview/app_settings/settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16135,5 +16135,27 @@
<key>Value</key>
<integer>1</integer>
</map>
<key>MediaAutoPlayHuds</key>
<map>
<key>Comment</key>
<string>Automatically play HUD media</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>MediaFirstClickInteract</key>
<map>
<key>Comment</key>
<string>This setting controls which media (once loaded) does not require a first click to focus before interaction can begin. This allows clicks to be passed directly to media bypassing the focus click requirement. This setting is a bitfield, precomputed values are as follows: Disabled=0; Worn HUDs only=1; Owned objects=3; Friend objects=7; Group objects=15; Landowner objects=31; Any object=31; All MOAP=1073741824. For complete details see lltoolpie.h enum MediaFirstClickTypes.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>1</integer>
</map>
</map>
</llsd>
147 changes: 146 additions & 1 deletion indra/newview/lltoolpie.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
#include "llweb.h"
#include "pipeline.h" // setHighlightObject
#include "lluiusage.h"
#include "llcallingcard.h"

extern bool gDebugClicks;

Expand Down Expand Up @@ -1501,6 +1502,140 @@ static void handle_click_action_play()
}
}

bool LLToolPie::shouldAllowFirstMediaInteraction(const LLPickInfo& pick, bool moap_flag)
{
// Early failure cases
if(!pick.getObject())
{
LL_WARNS() << "pick.getObject() is NULL" << LL_ENDL;
return false;
}

static LLCachedControl<S32> FirstClickPref(gSavedSettings, "MediaFirstClickInteract", 1);

// Special / early-exit cases first, then checks get more complex and needy as we go down
// Feature disabled
if(FirstClickPref == MEDIA_FIRST_CLICK_NONE)
{
LL_DEBUGS_ONCE() << "FirstClickPref == MEDIA_FIRST_CLICK_NONE" << LL_ENDL;
return false;
}
// All objects (overriding PRIM_MEDIA_FIRST_CLICK_INTERACT)
if(FirstClickPref == MEDIA_FIRST_CLICK_ALL)
{
LL_DEBUGS_ONCE() << "FirstClickPref & MEDIA_FIRST_CLICK_ALL" << LL_ENDL;
return true;
}
// Every check beyond this point requires PRIM_MEDIA_FIRST_CLICK_INTERACT to be TRUE
if(!moap_flag)
{
LL_DEBUGS_ONCE() << "PRIM_MEDIA_FIRST_CLICK_INTERACT not set" << LL_ENDL;
return false;
}
// Any object with PRIM_MEDIA_FIRST_CLICK_INTERACT set to TRUE
if(FirstClickPref & MEDIA_FIRST_CLICK_ANY)
{
LL_DEBUGS_ONCE() << "FirstClickPref & MEDIA_FIRST_CLICK_ANY" << LL_ENDL;
return true;
}

// The following checks require some object information so we obtain that
LLPointer<LLViewerObject> object = pick.getObject();
if(object.isNull())
{
LL_WARNS() << "pick.getObject() is NULL" << LL_ENDL;
return false;
}

// Own objects
if((FirstClickPref & MEDIA_FIRST_CLICK_OWN) && object->permYouOwner())
{
LL_DEBUGS_ONCE() << "FirstClickPref & MEDIA_FIRST_CLICK_OWN" << LL_ENDL;
return true;
}
// HUD attachments
if((FirstClickPref & MEDIA_FIRST_CLICK_HUD) && object->isHUDAttachment())
{
LL_DEBUGS_ONCE() << "FirstClickPref & MEDIA_FIRST_CLICK_HUD" << LL_ENDL;
return true;
}

// Further object detail required beyond this point
LLPermissions* perms = LLSelectMgr::getInstance()->getHoverNode()->mPermissions;
if(perms == nullptr)
{
LL_WARNS() << "LLSelectMgr::getInstance()->getHoverNode()->mPermissions is NULL" << LL_ENDL;
return false;
}
LLUUID owner_id = perms->getOwner();
LLUUID group_id = perms->getGroup();
if(owner_id.isNull() && group_id.isNull())
{
LL_WARNS() << "Owner information was not reliably obtained" << LL_ENDL;
return false;
}

// Check if the object is owned by a friend of the agent
if(FirstClickPref & MEDIA_FIRST_CLICK_FRIEND)
{
LL_DEBUGS_ONCE() << "FirstClickPref & MEDIA_FIRST_CLICK_FRIEND. id: " << owner_id << LL_ENDL;
return LLAvatarTracker::instance().isBuddy(owner_id);
}

// Check for objects set to or owned by the active group
if(FirstClickPref & MEDIA_FIRST_CLICK_GROUP)
{
// Get our active group
LLUUID active_group = gAgent.getGroupID();
if(active_group.notNull() && (active_group == group_id || active_group == owner_id))
{
LL_DEBUGS_ONCE() << "FirstClickPref & MEDIA_FIRST_CLICK_GROUP.Active group: " << active_group << ", group_id:" << group_id << ", owner_id: " << owner_id << LL_ENDL;
return true;
}
}

// This check ensures that the following conditions are met:
// 1. The object is located in the same parcel as the agent.
// 2. One of the following is true:
// a. The object is owned by the same group as the parcel.
// b. The object is set to the same group as the parcel.
// c. The object is owned by the same owner as the parcel.
// Conditions 2a and 2b are mutually exclusive, our check is the same for both.
if(FirstClickPref & MEDIA_FIRST_CLICK_LAND)
{
LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
if(parcel == nullptr)
{
LL_WARNS() << "LLViewerParcelMgr::getInstance()->getAgentParcel() is NULL" << LL_ENDL;
return false;
}

// Same parcel as the agent only
if(!LLViewerParcelMgr::getInstance()->inAgentParcel(object->getPositionGlobal()))
{
LL_WARNS_ONCE() << "Object is not in the same parcel as the agent" << LL_ENDL;
return false;
}

LLUUID parcel_owner = parcel->getOwnerID();
LLUUID parcel_group = parcel->getGroupID();

// The parcel owner and group can't both be null
if(parcel_owner.isNull() && parcel_group.isNull())
{
LL_WARNS() << "Parcel owner and group are both null" << LL_ENDL;
return false;
}

if(owner_id == parcel_owner || group_id == parcel_group)
{
LL_DEBUGS_ONCE() << "FirstClickPref & MEDIA_FIRST_CLICK_LAND. Parcel owner: " << parcel_owner << ", group_id:" << group_id << ", owner_id: " << owner_id << LL_ENDL;
return true;
}
}
return false;
}

bool LLToolPie::handleMediaClick(const LLPickInfo& pick)
{
//FIXME: how do we handle object in different parcel than us?
Expand Down Expand Up @@ -1535,6 +1670,16 @@ bool LLToolPie::handleMediaClick(const LLPickInfo& pick)
{
// It's okay to give this a null impl
LLViewerMediaFocus::getInstance()->setFocusFace(pick.getObject(), pick.mObjectFace, media_impl, pick.mNormal);
if (shouldAllowFirstMediaInteraction(pick, mep->getFirstClickInteract()))
{
if (media_impl.notNull())
{
media_impl->mouseDown(pick.mUVCoords, gKeyboard->currentMask(true));
mMediaMouseCaptureID = mep->getMediaID();
setMouseCapture(true);
return true;
}
}
}
else
{
Expand Down Expand Up @@ -1647,7 +1792,7 @@ bool LLToolPie::handleMediaHover(const LLPickInfo& pick)
}

// If this is the focused media face, send mouse move events.
if (LLViewerMediaFocus::getInstance()->isFocusedOnFace(objectp, pick.mObjectFace))
if (LLViewerMediaFocus::getInstance()->isFocusedOnFace(objectp, pick.mObjectFace) || (shouldAllowFirstMediaInteraction(pick, mep->getFirstClickInteract())))
{
media_impl->mouseMove(pick.mUVCoords, gKeyboard->currentMask(true));
gViewerWindow->setCursor(media_impl->getLastSetCursor());
Expand Down
20 changes: 20 additions & 0 deletions indra/newview/lltoolpie.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,26 @@ class LLToolPie : public LLTool, public LLSingleton<LLToolPie>
void showVisualContextMenuEffect();
ECursorType cursorFromObject(LLViewerObject* object);

enum MediaFirstClickTypes
{
MEDIA_FIRST_CLICK_NONE = 0, // Special case: Feature is disabled
MEDIA_FIRST_CLICK_HUD = 1 << 0, // 0b00000001 (1)
MEDIA_FIRST_CLICK_OWN = 1 << 1, // 0b00000010 (2)
MEDIA_FIRST_CLICK_GROUP = 1 << 2, // 0b00000100 (4)
MEDIA_FIRST_CLICK_FRIEND = 1 << 3, // 0b00001000 (8)
MEDIA_FIRST_CLICK_LAND = 1 << 4, // 0b00010000 (16)

// Covers any object with PRIM_MEDIA_FIRST_CLICK_INTERACT (combines all other flags)
MEDIA_FIRST_CLICK_ANY = MEDIA_FIRST_CLICK_HUD &
MEDIA_FIRST_CLICK_OWN &
MEDIA_FIRST_CLICK_GROUP &
MEDIA_FIRST_CLICK_FRIEND &
MEDIA_FIRST_CLICK_LAND,

// Covers all media regardless of other rules or PRIM_MEDIA_FIRST_CLICK_INTERACT
MEDIA_FIRST_CLICK_ALL = 1 << 30 // 0b01000000000000000000000000000000 (1073741824)
};
bool shouldAllowFirstMediaInteraction(const LLPickInfo& info, bool moap_flag);
bool handleMediaClick(const LLPickInfo& info);
bool handleMediaDblClick(const LLPickInfo& info);
bool handleMediaHover(const LLPickInfo& info);
Expand Down
Loading