Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Counting prims by owner, use of strided lists

Jeff Kelley
Registered User
Join date: 8 Nov 2006
Posts: 223
06-05-2007 16:55
There is a nice, nice llFunc out there, just waiting for us to do something cool with it: llGetParcelPrimOwners. How cool if I could display the TOP-50 prim eaters in my sandbox? Or check quickly wich builder owns prims on a shared parcel?

llGetParcelPrimOwners returns a strided list of (ownersKey,primCount). Let's call it OwnerAndPrims.

We want to sort it by prims number to get our TOP-50. llListSort sorts a strided list. Unfortunately it uses only the first item as a sort key. We need to swap (owner,prims) to (prims,owner). That's what does swapStridedListByTwo.

swapStridedListByTwo([a,1,b,2,c,3] = [1,a,2,b,3,c]

(swapStridedListByTwo, part 1) A call to llList2ListStrided gives the list of each first item in the strided input list (items1 = [a,b,c]). We get the list of second items (items2 = [1,2,3]) with a little trick : shift the first list item out, and a second call to llList2ListStrided is what we want.

(swapStridedListByTwo, part 2) Now, we have to interleave the two flat lists (item2,item1) to get our result [1,a,2,b,3,c]. Unfortunately, I see no llLists2Strided, so we have to go algorithmically. Beware, this is the time-consuming part of this script.

We can go now through the main code. Call llGetParcelPrimOwners to get OwnerAndPrims strided list. Pass thru our swapping function to get PrimsAndOwner. Sort. Et voila.

But wait. We want to display owner names, not owner keys. Here comes the painful process of going through the ugly-ugly, sequential breaking, context loosing dataserver. Remember that dataserver will silently fail if it can't answer. It will fail when passing a group key instead of an agent key. So, the number and order of dataserver events won't match the number and order of llRequestAgentData.

We need some kind of assoc between llRequestAgentData and dataserver. queryId is our friend. Here is the solution used: When looping on llRequestAgentData, I build a strided list of (owner,query). Let's call it OwnerAndQuery.

We are all set now. In the dataserver event, we can retrieve the ownerKey from queryId using OwnerAndQuery, then numPrims from ownerKey using OwnerAndPrims. It's time for the cherry on the cake. Call Key2Name. If it fails, the owner is not in sim. We tag the output so we can know the name of the pig who quit the sanbox with 1100 prims left.

CODE

list PrimsAndOwner; // Strided list of (prims,owner)
list OwnerAndPrims; // Strided list of (owner,prims)
list OwnerAndQuery; // Strided list of (owner,query)

string gOutput; // Will hold the results

list swapStridedListByTwo(list input) {
list items1 = llList2ListStrided(input, 0, -1, 2); // All 1st items
input = llDeleteSubList(input,0,0);
list items2 = llList2ListStrided(input, 0, -1, 2); // All 2nd items

list result = [];
integer length = llGetListLength(items1);
integer i; for (i=0; i<length; i++) {
result += llList2List(items2,i,i);
result += llList2List(items1,i,i);
}

return result;
}




default {

state_entry(){
OwnerAndPrims = llGetParcelPrimOwners(llGetPos());
PrimsAndOwner = swapStridedListByTwo(OwnerAndPrims);
PrimsAndOwner = llListSort(PrimsAndOwner,2,FALSE);

key queryId;
OwnerAndQuery = [];
integer length = llGetListLength(PrimsAndOwner)/2;
integer i; for (i=0; i<length; i++) {
key ownerKey = llList2Key(PrimsAndOwner,2*i+1);
queryId = llRequestAgentData(ownerKey, DATA_NAME);
OwnerAndQuery += [ownerKey,queryId];
}
gOutput = "";
}

dataserver(key queryid, string data) {
// Retrieve ownerKey from queryId using (owner,query) list
integer index = llListFindList(OwnerAndQuery,[queryid]);
key ownerKey = llList2Key(OwnerAndQuery, index - 1);

// Retrieve numPrims from ownerKey using (owner,prims) list
index = llListFindList(OwnerAndPrims,[ownerKey]);
integer numPrims = llList2Integer(OwnerAndPrims, index+1);

string ownerName = data;
integer notInSim = (llKey2Name(ownerKey) == "");
if (notInSim) ownerName = "("+ownerName+")";

gOutput += ownerName+" "+(string)numPrims+"\n";
llSetText(gOutput,<0.0,1.0,0.0>,1.0);
}

}
Osgeld Barmy
Registered User
Join date: 22 Mar 2005
Posts: 3,336
06-06-2007 00:57
id thought id make this more confusing

CODE

list input;
integer total;
integer count;

req_input(){llRequestAgentData(llList2Key(input, count), 2);}

default
{
state_entry()
{
input = llGetParcelPrimOwners(llGetPos());
total = llGetListLength(input);
req_input();
}

dataserver(key na, string res)
{
if (llKey2Name(llList2Key(input, count)) == "")
{
input =
llListReplaceList(input, ["(" + res + ")"], count, count);
}

else
{
input = llListReplaceList(input, [res], count, count);
}

if (count + 2 < total)
{
count += 2;
req_input();
}

else
{
list output;
integer i;

count = 1;

do{output += llList2Integer(input, count);}

while ((count += 2) < total);

output = llListSort(output, 0, 0);

count = 0;

do
{
i =
llListFindList(input,[llList2Integer(output, count)]);

// BIG FUNCTION
output = llListReplaceList(
output,
[llList2String(input, i - 1) + " " +
(string)llList2Integer(output, count)],
count,
count);
// END BIG FUNCTION

input = llDeleteSubList(input, i - 1, i);
}

while((++count) < total / 2);

llSetText(llDumpList2String(output,"\n"), <1.0,1.0,1.0>, 1);
}
}
}
Squirrel Wood
Nuteater. Beware!
Join date: 14 Jun 2006
Posts: 471
06-06-2007 01:00
The function returns the top 100 prim users.
In fact, it should already be sorted by prim count.
Qie Niangao
Coin-operated
Join date: 24 May 2006
Posts: 7,138
06-06-2007 03:50
I hacked something with this a while back and hit a little snag with Group-deeded objects. As I recall, a call to llGetParcelDetails() with PARCEL_DETAILS_GROUP made sure it was the "right" group for the parcel. That was a while back, though, so your mileage may vary.
Jeff Kelley
Registered User
Join date: 8 Nov 2006
Posts: 223
06-06-2007 09:17
From: Osgeld Barmy
id thought id make this more confusing
Fails if there is any deeded object.
Global var count will be out of sync.
else case of if (count + 2 < total) will never trigger.
From: Squirrel Wood
In fact, it should already be sorted by prim count.
It is not.
From: Qie Niangao
I recall, a call to llGetParcelDetails() with PARCEL_DETAILS_GROUP made sure it was the "right" group for the parcel.
Yes, getting the PARCEL_DETAILS_GROUP and filtering it out should work.
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
06-06-2007 11:58
This used to stop working once the object owner logged off, and totally not work if the object was deeded to the group, and placed on group owned land. Have those bugs been fixed?
Qie Niangao
Coin-operated
Join date: 24 May 2006
Posts: 7,138
06-06-2007 12:21
From: Ziggy Puff
This used to stop working once the object owner logged off, and totally not work if the object was deeded to the group, and placed on group owned land. Have those bugs been fixed?


Oh right, forgot about that twist: yeah, last I checked, when the owner isn't in-world, it fails, but it seems to continue working now on Group-owned land, if it is itself deeded to the Group.
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
06-06-2007 12:47
Thanks.