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);
}
}