Jump to content

Long-Time Open-Source Rental Script Ceases to Refund Properly


You are about to reply to a thread that has been inactive for 401 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

So all of a sudden this open source rental script I have used for years which included the ability to refund payments has stopped refunding.

It gives messages stating that it is giving a refund minus a cancellation fee; it then returns the rental box to the unrented state but does not actually refund any money and no money is debited from the payor's account. At first I thought this was a problem with scripts turned off on the land or sim performance, but I've tested it on various sims and accounts and I think it must be the script itself.

When I try refunding a box myself, it gives me this error message: 

Script trying to debit L$ from owner but PERMISSION_DEBIT permission not set!

It occurred to me that this problem could be related to this post from LL about deprecating XML-RPC. The Lindens said they were going to do "circuit-breaker exercises" but didn't specify the exact dates.

This script has been edited by multiple people for many years. Since it would have to communicate with the web (presumably) to reflect a credit or debit, perhaps that's the issue. I can't tell from looking at it.

But of course it could be some unrelated problem.

I'd appreciate any help here as I really don't want to go and replace thousands of rental boxes now, all the while doing manual refunds.

The last time it seems to have worked right was March 23 but I can't be sure. Previously, if the rental box was paid way ahead, it would sometimes not refund correctly if the sim had been re-set in the meantime, but generally it seemed to survive even returns to inventory; you could put it out and it would be at the exact same paid state and time it was before it returned.

Of course, the record is kept on the web site and there is also a message in chat "you failed to pay..." or an obviously incorrect number. But if no refund is being shown on the web at all, or actually being debited, it would require the customer to report it.

//Rental Script v1.921
//by Hank Ramos
//08/18/2015, Rex Cronon(added 1h,6h...48h intervals)
// 08/27/2015, Rex Cronon(no more duplicate reminders?)
//08/29/2015, Rex Cronon(timestamp)
//09/17/2016, Rolig Loon(fixed integer issue for refunds)
//05/23/2018, Fnordian Link (after rent due notices sent out, changes shape to pilar and texture to GRACE PERIOD - UNAVAILABLE and cannot be rented for 48 hours).

//Options
vector  rentalOffset   = <0,0,10>;
float   updateInterval = 60.0; // Seconds. Use a low value (e.g., 10.0) to test. Use 60.0 for standard.
float   time_multiplier = 1.0; // Use a high value (e.g. 1800) to test. Use 1.0 for standard operation.
string  infoNotecard   = "Rent This Space Info";

//Variables
string  tierName;
float   rentalCost;
float discountTime;
integer primCount;
integer rentalVolume;
float   refundFee;
key     renterID;
string  renterName;
float   rentalTime;
integer listenQueryID;
vector  initPos;
vector  initScale;
integer count;
integer lineCount;
key     readKey;
string  rentalGrade;
integer primAllotment;

//Constants
float ONE_WEEK = 604800.0;
float _48_HOURS  = 172800.0;//2*24*3600
float _36_HOURS=129600.0;//36*3600
float _24_HOURS  = 86400.0;//24*3600
float _12_HOURS=43200.0;//12*3600
float _6_HOURS=21600.0;//6*3600
float _1_HOUR = 3600.0;//60*60
float DISCOUNT_PERCENT = 10.0;

//Textures
string grace_period_unavailable = "grace";


dispString(string value)
{
    llSetText(value, <1,1,1>, 1);
}
sendReminder(string message)
{ 
    llInstantMessage(renterID, "Current date and time: "+llGetTimestamp()+"\n"+"Your lease located in " + llGetRegionName() + " (" + (string)initPos.x + "," + (string)initPos.y + "," + (string)initPos.z + ") will expire " + message); 
}
saveData()
{
    list saveData;
    vector storageVector;
    
    saveData += renterID;
    saveData += renterName;
    saveData += llRound(rentalTime);
    storageVector = initPos * 1000;
    saveData += "<" + (string)llRound(storageVector.x) + "," + (string)llRound(storageVector.y) + "," + (string)llRound(storageVector.z) + ">";
    storageVector = initScale * 1000;
    saveData += "<" + (string)llRound(storageVector.x) + "," + (string)llRound(storageVector.y) + "," + (string)llRound(storageVector.z) + ">";
    saveData += llRound(discountTime);
    
    llSetObjectDesc(llDumpList2String(saveData, "|"));
}
string getTimeString(integer time)
{
    integer days;
    integer hours;
    integer minutes; 
    integer seconds;
    
    days = llRound(time / 86400);
    time = time % 86400;
    
    hours = (time / 3600);
    time  = time % 3600;

    minutes = time / 60;
    time    = time % 60;

    seconds = time;
    
    return (string)days + " days, " + (string)hours + " hours, " + (string)minutes + " minutes"; // + ":" + (string)seconds; 
}

integer setupDialogListen()
{
    integer chatChannel = (integer)llFrand(2000000);
    llListenRemove(listenQueryID);
    listenQueryID = llListen(chatChannel, "", NULL_KEY, "");
    return chatChannel;
}

updateTimeDisp()
{ 
    dispString("Leased by: " + renterName + "\nTime Remaining: " + getTimeString(llRound(rentalTime)));   
}

dispData()
{
    llSay(0, "========================");
    llSay(0, "Rental Space Information");
    llSay(0, "========================");
    llSay(0, "This space is currently leased by " + renterName);
    llSay(0, "The current rental price is L$" + (string)((integer)rentalCost) + " per week.");
    llSay(0, "This space will be open for lease in " + getTimeString(llRound(rentalTime)) + "."); 
    llSay(0, "Memory Free: " + (string)llGetFreeMemory());
}
default
{
    state_entry()
    {
        state initialize;
    }
}

state initialize
{
    state_entry()
    {
        llSetTimerEvent(300);
        llOwnerSay("Waiting to obtain Debit Permissions.");
        llRequestPermissions(llGetOwner(), PERMISSION_DEBIT);
    }
    run_time_permissions(integer permissions)
    {
        //Only wait for payment if the owner agreed to pay out money
        if (permissions & PERMISSION_DEBIT)
        {
            state loadSettings;
        }
    }    
    on_rez(integer start_param)
    {
        llResetScript();
    } 
    timer()
    {
        llRequestPermissions(llGetOwner(), PERMISSION_DEBIT);
    }
    touch_start(integer total_number)
    {
        integer x;
        for (x = 0; x < total_number; x += 1)
        {
            if (llDetectedKey(x) == llGetOwner())
            {
                llResetScript();
            }
        }
        llSay(0, "Waiting to obtain Debit Permissions from Owner.");
    }
    state_exit()
    {
        llSetTimerEvent(0);
        llSay(0, "Initialized.");
    }
}

state loadSettings
{
    state_entry()
    {
        integer found = FALSE;
        integer x;
        
        count = 0;
        lineCount = 0;
        
        list savedList = llCSV2List(llGetObjectDesc());
        
        if (llGetListLength(savedList) == 4)
        {
            rentalGrade = llList2String(savedList, 0);
        }
        else
        {
            rentalGrade = llGetObjectDesc();
        }
        for (x = 0; x < llGetInventoryNumber(INVENTORY_NOTECARD); x += 1)
        {
            if (llGetInventoryName(INVENTORY_NOTECARD, x) == "Settings")
            {
                found = TRUE; 
            }
        }
        if (found)
        {
            llOwnerSay("Reading Settings Notecard...");
            readKey = llGetNotecardLine("Settings", lineCount); 
        }
        else
        {
            llOwnerSay("Settings Notecard Not Found.");
            llResetScript();
        }
    }
    dataserver(key requested, string data)
    {
        integer integerData;
        float   floatData;
        
        if (requested == readKey) 
        { 
            if (data != EOF)
            {
                if ((llSubStringIndex(data, "#") != 0) && (data != "") && (data != " "))
                {
                    integerData = (integer)data;
                    floatData   = (float)data;
                    
                    if (count == 0)
                    {
                        tierName = data;
                    }
                    else if (count == 1)
                    {
                        if (integerData >= 0)
                        {
                            rentalCost = integerData;
                        }
                        else
                        {
                            rentalCost = 0;
                        }
                    }
                    else if (count == 2)
                    {
                        if (integerData >= 1)
                        {
                            primCount = integerData;
                        }
                        else
                        {
                            primCount = 1;
                        }
                    }
                    else if (count == 3)
                    {
                        if (integerData >= 16)
                        {
                            rentalVolume = integerData;
                        }
                        else
                        {
                            rentalVolume = 16;
                        }
                    }
                    else if (count == 4)
                    {
                        if (integerData >= 0)
                        {
                            refundFee = integerData;
                        }
                        else
                        {
                            refundFee = 0;
                        }
                    }
                    else if (count == 5)
                    {
                        rentalOffset = (vector)data;
                    }
                    else if (count == 6)
                    {
                        infoNotecard = data;
                    }
                    count += 1;
                }
                lineCount += 1;
                readKey = llGetNotecardLine("Settings", lineCount);
            }
            else
            {
                llOwnerSay("===============");
                llOwnerSay("Settings Loaded");
                llOwnerSay("===============");
                llOwnerSay("Space Name: " + tierName);
                llOwnerSay("Rental Cost: L$" + (string)llRound(rentalCost));
                llOwnerSay("Prim Count: " + (string)primCount);
                llOwnerSay("Space Volume: " + (string)rentalVolume + " sqm");
                llOwnerSay("Refund Fee: L$" + (string)refundFee);
                llOwnerSay("===============");
                llOwnerSay("Ready for Service!");

                list savedList = llParseString2List(llGetObjectDesc(), ["|"], []);

                if (llGetListLength(savedList) == 6)
                {
                    renterID    = llList2Key(savedList, 01);
                    renterName  = llList2String(savedList, 1);
                    rentalTime  = llList2Integer(savedList, 2);
                    initPos     = (vector)llList2String(savedList, 3) / 1000;
                    initScale   = (vector)llList2String(savedList, 4) / 1000;
                    discountTime = llList2Integer(savedList, 5);
                    state rented;
                }
                else
                {
                    renterID   = NULL_KEY;
                    renterName = "Nobody";
                    rentalTime = 0;
                    initPos    = llGetPos();
                    initScale  = llGetScale();
                    discountTime = 0;
                    state idle;
                }
            }
        }
    }
}


state idle
{
    state_entry()
    {        
        llSetObjectDesc("");
        llSetTexture("rentthisspace", ALL_SIDES);
        llSetLinkPrimitiveParamsFast(LINK_SET,[PRIM_TYPE, PRIM_TYPE_BOX, 0, <0.000000, 1.000000, 0.000000>, 0.000000, <0.000000, 0.000000, 0.000000>, <1.000000, 1.000000, 0.000000>, <0.000000, 0.000000, 0.000000>]); 
        llSetScale(initScale);
        llSetPos(initPos);
        integer fourweekdiscount = (integer)(((float)rentalCost * 4.0) * (DISCOUNT_PERCENT / 100.0));
        integer fourweekrentalprice = (integer)(((float)rentalCost * 4.0) - fourweekdiscount);
        llSetPayPrice((integer)rentalCost, [ (integer)(rentalCost * 1.0), (integer)(rentalCost * 2.0), (integer)(rentalCost * 3.0), (integer)fourweekrentalprice]);
        llSetTimerEvent(updateInterval);

        dispString(tierName + "\nLease this space for L$" + (string)llRound(rentalCost) + " per week.\n" + (string)rentalVolume + " sq meters\n" + (string)primCount + " prims\nPay this Sign to begin your lease.");
    }
    moving_end()
    {
        initPos = llGetPos();
    }
    changed(integer change)
    {
        if (change & CHANGED_SCALE)
        {
            initScale = llGetScale();
        }
    }
    touch_start(integer num_detected)
    {
        integer x;
        integer chatChannel;
        
        for (x = 0; x < num_detected; x += 1)
        {
            if (llDetectedKey(x) == llGetOwner())
            {
                llDialog(llGetOwner(), "Owner Options.  Select one of the options below...", ["Info", "Reset"], setupDialogListen());
                return;
            } 
        }
               
        llSay(0, "Lease this space for L$" + (string)llRound(rentalCost) + " per week. " + (string)rentalVolume + " sq meters. " + (string)primCount + " prims. Pay this Sign to begin your lease.");
        
        for (x = 0; x < num_detected; x += 1)
        {
            llGiveInventory(llDetectedKey(x), infoNotecard);
        } 
    }
    listen(integer channel, string name, key id, string message)
    {
        if (message == "Reset")
        {
            llResetScript();
        }
        else if (message == "Info")
        {
            llListenRemove(listenQueryID);
            dispData();
            llSay(0, "Lease this space for L$" + (string)llRound(rentalCost) + " per week. " + (string)rentalVolume + " sq meters. " + (string)primCount + " prims. Pay this Sign to begin your lease.");
            llGiveInventory(id, infoNotecard);
        }
    }    
    money(key id, integer amount)
    {
        if (amount >= rentalCost)
        {
            renterID   = id;
            renterName = llKey2Name(renterID);
            integer fourweekdiscount = (integer)(((float)rentalCost * 4.0) * (DISCOUNT_PERCENT / 100.0));
            integer fourweekrentalprice = (integer)(((float)rentalCost * 4.0) - fourweekdiscount);
            if (fourweekrentalprice == amount)
            {
                rentalTime = ONE_WEEK * (rentalCost * 4) / rentalCost;
                discountTime = rentalTime;
            }
            else
            {
                rentalTime = ONE_WEEK * amount / rentalCost;
                discountTime = 0;
            }

            saveData();
            
            llSay(0, "Thank you " + renterName + " for leasing!  Your lease will expire in " + getTimeString((integer)rentalTime) + ".");
            
            state rented;
        }
        else
        {
            llSay(0, "This space costs L$" + (string)rentalCost + " to rent. Refunding paid balance.");
            llGiveMoney(id, amount);
        }
    }
}

state rented
{
    state_entry()
    {
        llSetTexture("infosign", ALL_SIDES);
        llSetScale(<0.5, 0.5, 0.5>);
        llSetPos(initPos + rentalOffset);
        
        updateTimeDisp();
        llResetTime();
        llSetTimerEvent(updateInterval);
    }
    touch_start(integer num_detected)
    {
        integer x;
        key     detectedKey;
        
        for (x = 0; x < num_detected; x += 1)
        {
            detectedKey = llDetectedKey(x);
            if (detectedKey == llGetOwner())
            {
                llDialog(detectedKey, "Lease Options. Select one of the options below...", ["Refund Time", "Info", "Release", "Reset"], setupDialogListen());
            }
            else if (detectedKey == renterID)
            {
                llDialog(detectedKey, "Lease Options. Select one of the options below...", ["Refund Time", "Info"], setupDialogListen());
            }
            else
            {
                dispData();
                llGiveInventory(detectedKey, infoNotecard);
            }
        }
    }
    money(key id, integer amount)
    {
        if ((id == renterID)||(id == llGetOwner()))
        {
            float addTime;
            
            integer fourweekdiscount = (integer)(((float)rentalCost * 4.0) * (DISCOUNT_PERCENT / 100.0));
            integer fourweekrentalprice = (integer)(((float)rentalCost * 4.0) - fourweekdiscount);
            if (fourweekrentalprice == amount)
            {
                addTime = ONE_WEEK * (rentalCost * 4) / rentalCost;
                discountTime += addTime;
            }
            else
                addTime = ONE_WEEK * amount / rentalCost;

            rentalTime += addTime;
            
            llInstantMessage(id, "Adding " + getTimeString(llRound(addTime)) + " to your lease. Lease Time is Now: " + getTimeString(llRound(rentalTime)) + ".");
            saveData();
            updateTimeDisp();
        }
        else
        {
            llInstantMessage(id, "Refunding Money...");
            llGiveMoney(id, amount);
            llInstantMessage(id, "This space is currently leased by " + renterName + ". This space will be open for lease in " + getTimeString(llRound(rentalTime)) + "."); 
        }
    }
    listen(integer channel, string name, key id, string message)
    {
        integer refundAmount;
        
        llListenRemove(listenQueryID);

        if (message == "Info")
        {
            dispData();
            llGiveInventory(id, infoNotecard);
        }
        else if (message == "Refund Time")
        {
            llDialog(id, "Are you sure you want to TERMINATE your lease and refund your money, minus a L$" + (string)((integer)refundFee) + " fee?", ["YES", "NO"], setupDialogListen());

        }
        else if (message == "YES")
        {
            float discount = (float)rentalCost * (DISCOUNT_PERCENT / 100.0);
            integer discountCost = (integer)((float)rentalCost - discount);
            refundAmount = llRound((((rentalTime - discountTime)/ ONE_WEEK) * rentalCost) + ((discountTime / ONE_WEEK) * discountCost) - refundFee);
            llInstantMessage(renterID, "Refunding L$" + (string)refundAmount + ", which includes a L$" + (string)refundFee + " termination fee.");
            llGiveMoney(renterID, refundAmount);
            llInstantMessage(llGetOwner(), "LEASE REFUNDED: leased by " + renterName + " located in " + llGetRegionName() + " (" + (string)initPos.x + "," + (string)initPos.y + "," + (string)initPos.z + ") has ended. Refunded L$" + (string)refundAmount + ".");
            state idle;
        }
        else if (message == "Release")
        {
            llDialog(id, "Are you sure you want to TERMINATE this lease with NO REFUND?", ["Yes", "No"], setupDialogListen());
        }
        else if (message == "Yes")
        {
            llInstantMessage(llGetOwner(), "LEASE TERMINATED: leased by " + renterName + " located in " + llGetRegionName() + " (" + (string)initPos.x + "," + (string)initPos.y + "," + (string)initPos.z + ") has ended. Refunded L$0.");
            state idle;            
        }
        else if (message == "Reset")
        {
            llResetScript();
        }
    }
    timer()
    {
        float timeElapsed = llGetAndResetTime();
        if (timeElapsed > (updateInterval * 4))
        {
            timeElapsed = updateInterval;
        }
        rentalTime -= timeElapsed * time_multiplier;
        
        saveData();
 
        updateTimeDisp(); 
        
        //Process Reminders
        if (rentalTime <= 0)
        {
            llInstantMessage(llGetOwner(), "LEASE EXPIRED: leased by " + renterName + " located in " + llGetRegionName() + " (" + (string)initPos.x + "," + (string)initPos.y + "," + (string)initPos.z + ") has expired.");

            state grace_period;
        }
        
        //if((rentalTime<(_48_HOURS+updateInterval))&&(rentalTime>(_48_HOURS-updateInterval))) 
        if((rentalTime <= _48_HOURS)&&(rentalTime >= _48_HOURS - (updateInterval*2)))
        {
            sendReminder("in two days.");
        }              
        //else if ((rentalTime<(_36_HOURS+updateInterval))&&(rentalTime>(_36_HOURS-updateInterval)))
        else if((rentalTime <= _36_HOURS)&&(rentalTime >= _36_HOURS - (updateInterval*2)))
        {
            sendReminder("in one day and a half.");
        }
        //else if((rentalTime<(_24_HOURS+updateInterval))&&(rentalTime>(_24_HOURS-updateInterval)))
        else if ((rentalTime <= _24_HOURS)&&(rentalTime >= _24_HOURS - (updateInterval*2)))
        {
            sendReminder("in one day.");
        }
        //else if ((rentalTime<(_12_HOURS+updateInterval))&&(rentalTime>(_12_HOURS-updateInterval)))
        else if((rentalTime <= _12_HOURS)&&(rentalTime >= _12_HOURS - (updateInterval*2)))
        {
            sendReminder("in 12 hours.");
        }
        //else if ((rentalTime<(_6_HOURS+updateInterval))&&(rentalTime>(_6_HOURS-updateInterval)))
        else if((rentalTime <= _6_HOURS)&&(rentalTime >= _6_HOURS - (updateInterval*2)))
        {
            sendReminder("in 6 hours.");
        }
       // else if ((rentalTime<(_1_HOUR+updateInterval))&&(rentalTime>(_1_HOUR-updateInterval)))
        else if((rentalTime <= _1_HOUR)&&(rentalTime >= _1_HOUR - (updateInterval*2)))
        {
            sendReminder("in one hour.");
        }        
    }
}


state grace_period
{
    state_entry()
    {
        llSetTexture(grace_period_unavailable, ALL_SIDES); // Set grace period texture.
        llSetPrimitiveParams([PRIM_TYPE, PRIM_TYPE_CYLINDER, 0, <0.000000, 1.000000, 0.000000>, 0.000000, <0.000000, 0.000000, 0.000000>, <1.000000, 1.000000, 0.000000>, <0.000000, 0.000000, 0.000000>]); 
        llSetScale(initScale);
        llSetTimerEvent(172800.0 / time_multiplier); // Set timer for 48 hours.
    } // End state_entry.
    
    
    timer()
    {
        llSetTimerEvent(0); // Stop timer.
        state idle; // Return to unrented state.
    } // End timer.
    
    
    money(key id, integer amount)
    {
        if ((id == renterID)||(id == llGetOwner()))
        {
            float addTime;
            
            integer fourweekdiscount = (integer)(((float)rentalCost * 4.0) * (DISCOUNT_PERCENT / 100.0));
            integer fourweekrentalprice = (integer)(((float)rentalCost * 4.0) - fourweekdiscount);
            if (fourweekrentalprice == amount)
            {
                addTime = ONE_WEEK * (rentalCost * 4) / rentalCost;
                discountTime += addTime;
            }
            else
                addTime = ONE_WEEK * amount / rentalCost;

            rentalTime += addTime;
            
            llInstantMessage(id, "Adding " + getTimeString(llRound(addTime)) + " to your lease. Lease Time is Now: " + getTimeString(llRound(rentalTime)) + ".");
            saveData();
            updateTimeDisp();
            
            llSetLinkPrimitiveParamsFast(LINK_SET,[PRIM_TYPE, PRIM_TYPE_BOX, 0, <0.000000, 1.000000, 0.000000>, 0.000000, <0.000000, 0.000000, 0.000000>, <1.000000, 1.000000, 0.000000>, <0.000000, 0.000000, 0.000000>]); 
            state rented;            
        }
        else
        {
            llInstantMessage(id, "Refunding Money...");
            llGiveMoney(id, amount);
            llInstantMessage(id, "This space is currently leased by " + renterName + ". This space will be open for lease in " + getTimeString(llRound(rentalTime)) + "."); 
        }
    } // End money.
    
} // End state_grace_period.

 

Link to comment
Share on other sites

At first glance, I don't see any XML-RPC code. It certainly requests positions.

My initial thought is, the script is losing / forgetting it's (money / debit owner) permissions between states. I say this because, the permission requests are in state "default", but the "not-working" llGiveMoney() is in another state.

I suspect someone with more time will  do some testing for you. Just in case, have you noticed if it may be working in some "release channel" regions but broken in other "release channels"? (If the "broken server code" is now in "all channels", you wouldn't find it working anyplace.)

Sorry I can't be more help but - I predict my suggestion will give others ideas.

Link to comment
Share on other sites

I don't think you've mentioned - is the script asking you initially for Debit permissions?

If not, that explains it: Let us know if you've tried resetting the script and if it works then - if so, that may indicate "existing running instances of the script forgot debit permissions".

Sorry, it was not clear from this what you tried: whether you tried resetting the script and if that worked.

 

Link to comment
Share on other sites

5 hours ago, Prokofy Neva said:

Since it would have to communicate with the web (presumably) to reflect a credit or debit, perhaps that's the issue. I can't tell from looking at it.

But of course it could be some unrelated problem.

Love's right. The script isn't using XML-RPC at all.  In fact, it's not communicating with anything outside of SL. It has no connection to a web site. If you are populating a web site with information, some other script is doing it.

I vaguely remember looking at this script for you years ago, although I have no specific memory of the details or (except for your note at the top) what I did with it. I do remember thinking that it was more complicated than it needed to be.  If you were just starting out today, I would recommend using a more robust system. I've considered changing my own rental boxes to Caspar, for example.

That doesn't address your problem with this system, though. The only place in the script that is dealing at all with PERMISSION_DEBIT is in state default, the block of code at the very top of the script, after the sets of user defined functions.  The code is quite simple and I don't see anything wrong with it. From what you say, though, it's clearly not recognizing when you give it permission. The only explanation I can think of is that it's not recognizing you as the script's owner.  I'd suggest two things.  First, check to be sure that you are, in fact, the owner of the rental boxes -- not an assistant, not a group, you personally.  The script has to debit YOUR account to give refunds.  Second, as a failsafe, you might consider adding the following small block of code in every single state in the script:

changed (integer change)
{
     if (change & CHANGED_OWNER)
     {
          llResetScript();
     }
}

As you might guess, this bit of code will reset the script if ownership changes.  Putting it in every state in the script would guarantee that it will be effective no matter where the script may be in its logic if ownership changes somehow.  This shouldn't truly be necessary, but it's all I can think of as a LSL approach to recovering if the script somehow forgets that you are the owner.

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

Just now, Rolig Loon said:

If you are populating a web site with information, some other script is doing it.

I kept scanning the code for "anything web" and couldn't see anything at all. Thanks, thought maybe there was some web calls I missed since they wrote:

6 hours ago, Prokofy Neva said:

Of course, the record is kept on the web site

..I assumed some non-LL site was meant.

  • Like 1
Link to comment
Share on other sites

2 minutes ago, Love Zhaoying said:

@Rolig Loon, do you agree that "broken" instances of the running script (current version without changes) probably won't work without a script reset to request the permissions again?

Yes, but the OP says that he is resetting the script. That's what the touch_state event in state default does.  He could restart it manually by clicking the Reset button at the bottom of the script or by using Build >>> Scripts >> Reset Scripts, but the effect should be the same. The script doesn't seem to be "broken." it's just not getting out of state default because it thinks the OP hasn't given PERMISSION_DEBIT. I suppose there's an outside chance that there's a LL problem behind it, but he has these boxes on several regions, and I don't see a furious outcry from other landlords with failing rental boxes. 

  • Like 1
Link to comment
Share on other sites

2 hours ago, Love Zhaoying said:

I don't think you've mentioned - is the script asking you initially for Debit permissions?

If not, that explains it: Let us know if you've tried resetting the script and if it works then - if so, that may indicate "existing running instances of the script forgot debit permissions".

Sorry, it was not clear from this what you tried: whether you tried resetting the script and if that worked.

 

Yes, of course, and no, that didn't change it.

Yes, I thought of the issue having to do with Release Channels. But it seems impossible to determine what your region's release channel is, now that they hide that information or don't put it openly in "About SL".

This occurred on 4 different regions I tested which *used* to be on different channels but I have no idea now. If you have a way to determine this you can tell me, but that wouldn't help necessarily, as it still means that if some release channels don't work and others do, the Lindens have changed their code in some way such that this no longer works.

Yes, I give it debit permissions. Otherwise it can't work at all, like any rental box.

 

  • Like 1
Link to comment
Share on other sites

37 minutes ago, Rolig Loon said:

Yes, but the OP says that he is resetting the script. That's what the touch_state event in state default does.  He could restart it manually by clicking the Reset button at the bottom of the script or by using Build >>> Scripts >> Reset Scripts, but the effect should be the same. The script doesn't seem to be "broken." it's just not getting out of state default because it thinks the OP hasn't given PERMISSION_DEBIT. I suppose there's an outside chance that there's a LL problem behind it, but he has these boxes on several regions, and I don't see a furious outcry from other landlords with failing rental boxes. 

I suspect if mine doesn't work, others on the same principle won't, either. Perhaps the most-used one, Casper, works on a different principle?

I am manually resetting and also when a customer attempted a refund, it reset to its original state, gave a message that it refunded, and then didn't refund.

Again, every single one has to get permission debit because it wouldn't work otherwise, so of course they all got it.

  • Like 1
Link to comment
Share on other sites

1 hour ago, Rolig Loon said:

Love's right. The script isn't using XML-RPC at all.  In fact, it's not communicating with anything outside of SL. It has no connection to a web site. If you are populating a web site with information, some other script is doing it.

I vaguely remember looking at this script for you years ago, although I have no specific memory of the details or (except for your note at the top) what I did with it. I do remember thinking that it was more complicated than it needed to be.  If you were just starting out today, I would recommend using a more robust system. I've considered changing my own rental boxes to Caspar, for example.

That doesn't address your problem with this system, though. The only place in the script that is dealing at all with PERMISSION_DEBIT is in state default, the block of code at the very top of the script, after the sets of user defined functions.  The code is quite simple and I don't see anything wrong with it. From what you say, though, it's clearly not recognizing when you give it permission. The only explanation I can think of is that it's not recognizing you as the script's owner.  I'd suggest two things.  First, check to be sure that you are, in fact, the owner of the rental boxes -- not an assistant, not a group, you personally.  The script has to debit YOUR account to give refunds.  Second, as a failsafe, you might consider adding the following small block of code in every single state in the script:

changed (integer change)
{
     if (change & CHANGED_OWNER)
     {
          llResetScript();
     }
}

As you might guess, this bit of code will reset the script if ownership changes.  Putting it in every state in the script would guarantee that it will be effective no matter where the script may be in its logic if ownership changes somehow.  This shouldn't truly be necessary, but it's all I can think of as a LSL approach to recovering if the script somehow forgets that you are the owner.

Some of the rental boxes are on my account and some on my son's. But it happens for either of us. And yes, I realize I can't reset his box; he has to reset it, even with having been granted all my permissions.

 

  • Like 1
Link to comment
Share on other sites

1 hour ago, Rolig Loon said:
changed (integer change)
{
     if (change & CHANGED_OWNER)
     {
          llResetScript();
     }

I appreciate this tip, but when you say "put it in every single state" I don't know where to put it exactly in the script. But this discussion prompted me to consider what the issue might be.

So recently I increased the rent by $5L or $10L because of the newly-imposed sales tax which for my in NYS is 8.875% I wanted to manually re-set the boxes because I don't like mass automated systems especially Casper for lots of reasons. I like to see what is going on in my rentals -- where someone has turned off scripts completely so the rental box will appear "paid" forever (I only found 2 cases in 2000+ units because people are basically decent); I like to see if a rental box got hidden which is why the unit isn't renting; to see if it has the wrong price compared to others in that area, etc. It's all part of why I do this: to observe life in SL.

Even so, it was a lot of work and my son and another helper also reset boxes. Since they have all my permissions, they could easily pick up any rental box, take it into inventory, then put it out again, intact, with the rent paid still showing -- the script is good that way. They then could proceed to refund it by granting it their own debit permissions. And that worked, and then they reset it and it paid them.

But perhaps something about that process made this eventually not work *now* because -- I can only speculate -- something changed in the Lindens' code.

So now I went and gave the script to my son, he then put it in a rental box that wasn't working, that had been mine and he had switched to his. Now he didn't just switch ownership of the box with the script in it; he deleted the script and put in a brand new copy. Then when he paid and refunded it, it had no permission errors; when I paid it, then refunded it, it actually then did refund to me and worked ok.

So it seems this same script as is could be replaced universally rather than just flipping the prim ownership. Or maybe put it all back on my account, except I had an "eat what you kill" arrangement for some areas my son set up and I also like to stagger the tier payments across a number of accounts through the month.

So I'll have to start doing that now as I don't want to start with a new system which may be only this script anyway with the same problem (others used Hank Ramos' script as well and adapted it). If you could put in that block of code where it goes and send it to me, that would be great but don't feel any obligation. I am happy to pay to get it done.

  • Like 1
Link to comment
Share on other sites

24 minutes ago, Prokofy Neva said:

Yes, of course, and no, that didn't change it.

Yes, I thought of the issue having to do with Release Channels. But it seems impossible to determine what your region's release channel is, now that they hide that information or don't put it openly in "About SL".

This occurred on 4 different regions I tested which *used* to be on different channels but I have no idea now. If you have a way to determine this you can tell me, but that wouldn't help necessarily, as it still means that if some release channels don't work and others do, the Lindens have changed their code in some way such that this no longer works.

Yes, I give it debit permissions. Otherwise it can't work at all, like any rental box.

 

If resetting the script did not change it, then it appears the permissions are not persisting across states. @Rolig Loon, was there any use-case / scenario where just "requesting" permissions in a state "validates" the permission? I seem to recall (perhaps it was with animations). My point being, could there be a 1-line code fix in the "subordinate" states of just requesting the permission again?

Link to comment
Share on other sites

4 minutes ago, Love Zhaoying said:

My point being, could there be a 1-line code fix in the "subordinate" states of just requesting the permission again?

Not much point to doing that.  Permissions, once granted, apply to the scripted object.

I really think, as Prok suggested, that something is being messed up when he takes a box to inventory and rezzes it again. It's not that anything has changed on LL's end of things --  first of all, it hasn't, and second, if it had, we would be hearing a loud cry from landlords across the grid -- it's that the script is not recognizing when ownership changes.  Other than being very careful about checking ownership, the best way to assure that the script will recognize a change in ownership is to include that tiny changed event.  

At heart, we are trying to treat a symptom, not trying to improve the script.  As I said before, if these were my rent boxes, I would set this old warhorse of a script to one side and use a more efficient modern one.  But that's me.

  • Like 2
Link to comment
Share on other sites

6 minutes ago, Rolig Loon said:

Not much point to doing that.  Permissions, once granted, apply to the scripted object.

I really think, as Prok suggested, that something is being messed up when he takes a box to inventory and rezzes it again. It's not that anything has changed on LL's end of things --  first of all, it hasn't, and second, if it had, we would be hearing a loud cry from landlords across the grid -- it's that the script is not recognizing when ownership changes.  Other than being very careful about checking ownership, the best way to assure that the script will recognize a change in ownership is to include that tiny changed event.  

At heart, we are trying to treat a symptom, not trying to improve the script.  As I said before, if these were my rent boxes, I would set this old warhorse of a script to one side and use a more efficient modern one.  But that's me.

Prok mentioned that others (such as his son) have rights and took the box into their inventory and re-rezzed it. That certainly would look like a change of ownership, right? Sure looks like a possible root cause.

I guess the only mystery to me then is, why script reset wasn't working (unless they were also trying the transfer / take / rerez after script reset). 

  • Like 1
Link to comment
Share on other sites

19 minutes ago, Love Zhaoying said:

Prok mentioned that others (such as his son) have rights and took the box into their inventory and re-rezzed it. That certainly would look like a change of ownership, right? Sure looks like a possible root cause.

I guess the only mystery to me then is, why script reset wasn't working (unless they were also trying the transfer / take / rerez after script reset). 

But the real mystery is why NOW, when it has worked after ownership change for several years now. And that when ownership changes, you have to re-give the debit permissions or it won't work. 

And that *does* suggest that there's something that changed in the Lindens' latest patch. How else to explain? And across release channels, if these sims are on different channels, and again, that's hidden now so I have no idea.

Yes, I realize it's a warhorse, and it's like Trishka's kaftan, it has been patched so many times.

I'm happy to get specific recommendations of a better one; the MP is filled with scripts with bad reviews, some of them reworked versions of this one as I can see. I don't want to use the monopolist one and would prefer an open-source one.

Thanks for all your help and comments!

 

  • Like 1
Link to comment
Share on other sites

40 minutes ago, Prokofy Neva said:

And across release channels, if these sims are on different channels, //that's hidden now so I have no idea.

Prok it is not hidden, it is just more difficult to ascertain.  Fequently when The Main Server Channel is running one veersion no.  The RC Channels are running another and that version number should be shown in your viewer's top bar.  I forget which preference it is (I know the FS version but I know you don't run it, and I have no idea whether it shows by default in the Linden viewer).  Of course on the weeks where the RC and Main channel run the same version you are stumped but a glance at the Release Thread in this forum can inform you, whether the post is official or from some community minded soul such as  Logan Elf.

Link to comment
Share on other sites

4 hours ago, Prokofy Neva said:

So recently I increased the rent by $5L or $10L [...]

Even so, it was a lot of work and my son and another helper also reset boxes. Since they have all my permissions, they could easily pick up any rental box, take it into inventory, then put it out again, intact, with the rent paid still showing -- the script is good that way. They then could proceed to refund it by granting it their own debit permissions. And that worked, and then they reset it and it paid them.

Let's say "A" owned by the box when it was originally set out, and gave it PERMISSION_DEBIT. Now another permitted avatar "B" takes it into inventory and puts it back out again and becomes the new owner. The box shouldn't be able to give a refund right away because its PERMISSION_DEBIT came from somebody other than its new owner. Once that new owner resets it and grants their own PERMISSION_DEBIT, it be capable of giving a refund, but of course that reset will have erased the information about what rent was paid—there's nothing left to refund.

Now, if it ever worked before that it would refund based on permissions granted by a different owner, that's a little scary. Is there any chance this particular situation has only been noticed now, with this mass conversion to the new rent? Maybe it rarely (or never?) happened before because a refund wasn't necessary on those occasions the box was taken and re-rezzed by someone other than the original owner?

If this is an operational arrangement that needs to be supported in the future, I'm thinking the script should use the new persistent LinkSetData functions to store the rent payment information across a reset, so the re-rezzed boxes can be reset (manually or preferably on CHANGED_OWNER) and granted PERMISSION_DEBIT by the new owner without losing that payment information.

  • Thanks 1
Link to comment
Share on other sites

3 hours ago, Qie Niangao said:

Let's say "A" owned by the box when it was originally set out, and gave it PERMISSION_DEBIT. Now another permitted avatar "B" takes it into inventory and puts it back out again and becomes the new owner. The box shouldn't be able to give a refund right away because its PERMISSION_DEBIT came from somebody other than its new owner. Once that new owner resets it and grants their own PERMISSION_DEBIT, it be capable of giving a refund, but of course that reset will have erased the information about what rent was paid—there's nothing left to refund.

Now, if it ever worked before that it would refund based on permissions granted by a different owner, that's a little scary. Is there any chance this particular situation has only been noticed now, with this mass conversion to the new rent? Maybe it rarely (or never?) happened before because a refund wasn't necessary on those occasions the box was taken and re-rezzed by someone other than the original owner?

If this is an operational arrangement that needs to be supported in the future, I'm thinking the script should use the new persistent LinkSetData functions to store the rent payment information across a reset, so the re-rezzed boxes can be reset (manually or preferably on CHANGED_OWNER) and granted PERMISSION_DEBIT by the new owner without losing that payment information.

The refunds are not that common, and the subset of refunds from boxes taken into new ownership is an even smaller class of events, but it surely would have been noticed. For one, two of the boxes with ownership transferred had been paid and refunded successfully even by several tenants before, and it was only this week it stopped working.

As it is now, with the new block of script Rolig added, it *cannot* survive the same state after new permission is granted -- obviously. It's a re-set. I don't see how it is "scary' if one avatar with all permissions from another avatar takes it into possession and puts it down again -- it's not like it's open to the public, and the permissions would have had to be granted to that avatar.

To add what you are suggesting re: LinkSetData is yet another wrinkle and at this point, I'm just going to use Rolig's script (which actually I'm called 1.94 so I can readily distinguish it from 1.93 which added the grace period).

I realize people think there's Casper and better systems out there. But if I don't want to use Casper, there actually aren't. I could identify only one on the MP which I will try but I'd rather stick with an open source script. I appreciate everyone's input.

 

  • Like 1
Link to comment
Share on other sites

7 hours ago, Aishagain said:

Prok it is not hidden, it is just more difficult to ascertain.  Fequently when The Main Server Channel is running one veersion no.  The RC Channels are running another and that version number should be shown in your viewer's top bar.  I forget which preference it is (I know the FS version but I know you don't run it, and I have no idea whether it shows by default in the Linden viewer).  Of course on the weeks where the RC and Main channel run the same version you are stumped but a glance at the Release Thread in this forum can inform you, whether the post is official or from some community minded soul such as  Logan Elf.

I appreciate your expansion of this issue. I'm aware that it is put out in the Release Thread -- when in fact it is. It isn't always. I've followed that. But then I can't tell from that alone. It's not on the regular SL viewer unless I'm missing it. I could fiddle with this some more but I don't really have a need for it. I used to look at the viewer to see what was going on to see where there were problems sims and why, but then it was constantly denied that there were any correlations with the release channel. Even so, I would move people off sims with problems that clearly seem related to the RC. 

Here's what is on my copy of the regular SL Viewer under "About SL" it just says "Second Life Server". 

 

Second Life Release 6.6.9.577968 (64bit)
Release Notes

You are at 177.5, 219.0, 2,576.1 in Rowling located at simhost-0268fa637d406630a.agni
SLURL: http://maps.secondlife.com/secondlife/Rowling/177/219/2576
(global coordinates 298,929.0, 255,195.0, 2,576.1)
Second Life Server 2023-03-17.578853
Release Notes

CPU: AMD Ryzen 5 1400 Quad-Core Processor            (3193.99 MHz)
Memory: 8120 MB
OS Version: Microsoft Windows 10 64-bit (Build 19044.2728)
Graphics Card Vendor: ATI Technologies Inc.
Graphics Card: Radeon RX 570 Series

Windows Graphics Driver Version: 31.0.14033.1012
OpenGL Version: 4.6.0 Compatibility Profile Context 23.2.2.230217

Window size: 1920x1017
Font Size Adjustment: 96pt
UI Scaling: 1
Draw distance: 208m
Bandwidth: 3000kbit/s
LOD factor: 4.225
Render quality: 5
Advanced Lighting Model: Disabled
Texture memory: 512MB
Disk cache: Max size 409.6 MB (100.0% used)

J2C Decoder Version: KDU v7.10.4
Audio Driver Version: FMOD Studio 2.02.09
Dullahan: 1.12.4.202209142021
  CEF: 91.1.21+g9dd45fe+chromium-91.0.4472.114
  Chromium: 91.0.4472.114
LibVLC Version: 3.0.16
Voice Server Version: Not Connected
Packets Lost: 966/464,504 (0.2%)
March 26 2023 18:30:44

Edited by Prokofy Neva
Link to comment
Share on other sites

6 hours ago, Prokofy Neva said:

I don't see how it is "scary' if one avatar with all permissions from another avatar takes it into possession and puts it down again -- it's not like it's open to the public, and the permissions would have had to be granted to that avatar.

Yeah, it's not particularly scary in your operation specifically, but it would be scary as a general behavior. The account that gave PERMISSION_DEBIT should always be the account that gives money using that permission, and that should always be the same account that owns the object—so if the object changes ownership, debit permission granted by the previous owner shouldn't be valid anymore.

Otherwise one of two potentially "scary" situations must arise when such an object changes ownership. Either:

  • the new owner is on the hook to pay the object's debits without having even been asked about it—and maybe never even knew the object pays out money, or
  • the old owner keeps paying debits by objects they no longer own, which may not be intended every time the previous owner lets somebody else take ownership of their objects.

If the first were true, then every item sold "original" (every resold gacha item, for example) could be a time bomb waiting for the previous owner (or alt) to come by and drain L$s from the unsuspecting buyer's account. It's hard to imagine it ever behaved that way.

In the second situation, the person still paying would be the person who gave the permission, but there are too many ways for objects to change ownership for that person to always know the implications. Maybe years ago I set out boxes that give money, forgot about them, then in an unrelated situation decided to give somebody permission to take my stuff: suddenly that person can exercise those give money boxes as owner, but not have responsibility for the money they pay out. That's not risky in this rental script giving tenant refunds, but there are undoubtedly scripts that have test operations that give unlimited L$s to the owner—why not? it's the owner's money, right? Except, oops, now it's the previous owner's money. It's been a while since I read it but if this is in that scary PERMISSION_DEBIT dialog, it's too forgettable for me.

Personally, I think I'd consider either of these to be a security bug that needed fixing. Mere residents (rightfully) can't see Security jiras they didn't file themselves, and I'm not sure they're all listed in release notes, lest the vulnerability be exploited before rollout is complete. I'm not really suggesting this happened (I still want to believe it never worked this way) but I guess it would explain what you're seeing.

(Incidentally, I too still use my own self-scripted rental boxes, but they're pretty stupid and there are only a few copies out now. If I were re-scripting them from scratch I might use linkset data but I don't want to touch that script if I can avoid it. I especially understand sticking with a script that's working for an operation at your scale: there are inevitable tacit process dependencies that will pop up when making such a big change.)

8 hours ago, Prokofy Neva said:

Here's what is on my copy of the regular SL Viewer under "About SL" it just says "Second Life Server". 

Yeah, they aren't using the RC names anymore, but they do give the release number, in your case "Second Life Server 2023-03-17.578853" and we can find that in last week's server deployment announcement. Turns out it's one of the RCs that were deployed last Wednesday. Nothing obviously relevant in the release notes but as I suggested above, they might ninja-in a security change and we'd never know… theoretically.

  • Like 1
  • Thanks 2
Link to comment
Share on other sites

Whatever has happened to the script is fairly recent, as I rent from Ravenglass and a few weeks ago when tier was increased I got a refund just before the new level kicked in. My parcel is on a region of mainland on the main server channel, in case you want to hammer nails into some poor RC's coffin.

FWIW I agree totally with Rolig's assessment that this script is far too complicated, debugging it and sorting out where the problem lies could take longer than actually starting out from scratch.

  • Like 1
Link to comment
Share on other sites

10 hours ago, Prokofy Neva said:

Here's what is on my copy of the regular SL Viewer under "About SL" it just says "Second Life Server". 

Second Life Server 2023-03-17.578853

As Qie points out, your server info is given in the line beginning "Second Life Server".  The version number is your key to whether you are Main Server or RC Channel, but you do have to keep abreast of which versions numbers are deployed where.  The only other clue is that Main Server is restarted or rolled on a Tuesday, RC channels on a Wednesday. Usually.

I agree totally with you that is is not clear and in another example of Linden Lab's total failure to understand their userbase, they actually seem to think that telling their userbase which type of server they are sitting on is in some way prejudicial to their business. I've been in SL for 15 years and their utter failure to grasp essentials of customer liason still baffles me.

  • Like 2
Link to comment
Share on other sites

8 hours ago, Aishagain said:

As Qie points out, your server info is given in the line beginning "Second Life Server".  The version number is your key to whether you are Main Server or RC Channel, but you do have to keep abreast of which versions numbers are deployed where.  The only other clue is that Main Server is restarted or rolled on a Tuesday, RC channels on a Wednesday. Usually.

I'm have used (and amusing for testing) an earlier version of that script:

Quote

//Rental Script v1.5.3
//Copyright 2003-2009 by Hank Ramos

So to add just a little bit to the topic: I just put out a fresh copy of a rent box that I have. I reset the script and granted debit permission.  I just verified that that it does refund (and debit my lindens) properly and as expected. I'm on a RC channel.

with my testing alt:

  • I tried to pay less than minimum.  It was immediately refunded in full. Confirmed in the transaction logs the lindens moving both ways.
  • I paid minimum rent, was confirmed as the renter, the box did its move/size/texture changes.
  • I requested the refund (minus processing fee) for time unused and got to the amount expected back. Confirmed in the transaction logs for "My Account".

Debit permissions persisted across states

==

and for what it's worth as a side comment re - the top quot:  I can, with a moderate degree of certainty, state that I'm on RC BlueSteel.  That was what was being reported for my mainland parcel as of 2019-08-27.  That was the last day I have record of the channel being announced when I teleported in. It had been BlueSteel for as long as I can remember, and i have no reason to believe it's not still BlueSteel, but admittedly no absolute proof.

That said, 'Second Life Server 2023-03-17.578853' is on a RC channel, but probably not BlueSteel.  My land got the other release "Second Life Server 2023-03-16.578844", the bot one.

Link to comment
Share on other sites

3 minutes ago, Anna Salyx said:

I'm have used (and amusing for testing) an earlier version of that script:

So to add just a little bit to the topic: I just put out a fresh copy of a rent box that I have. I reset the script and granted debit permission.  I just verified that that it does refund (and debit my lindens) properly and as expected. I'm on a RC channel.

with my testing alt:

  • I tried to pay less than minimum.  It was immediately refunded in full. Confirmed in the transaction logs the lindens moving both ways.
  • I paid minimum rent, was confirmed as the renter, the box did its move/size/texture changes.
  • I requested the refund (minus processing fee) for time unused and got to the amount expected back. Confirmed in the transaction logs for "My Account".

Debit permissions persisted across states

==

and for what it's worth as a side comment re - the top quot:  I can, with a moderate degree of certainty, state that I'm on RC BlueSteel.  That was what was being reported for my mainland parcel as of 2019-08-27.  That was the last day I have record of the channel being announced when I teleported in. It had been BlueSteel for as long as I can remember, and i have no reason to believe it's not still BlueSteel, but admittedly no absolute proof.

That said, 'Second Life Server 2023-03-17.578853' is on a RC channel, but probably not BlueSteel.  My land got the other release "Second Life Server 2023-03-16.578844", the bot one.

I assume your tester alt does NOT have your permissions.

I'm also assuming that whatever caused this script to stop refunding properly after the rental box changed owners (and was NOT re-set) happened AFTER Hank Ramos' original version you are using (it has gone through a dozen changes and hands in the mean time).

To reproduce the issue, you would have to use the last but one version (I had called it 1.93), and have the test alt take over the box (or rather, an avatar that has your permissions, so that it can take your objects) and then try to have another avatar pay it and get a refund. That was where it broke down -- after the change of ownership. It seems what you are doing is having the testing alt pay the cube which had NOT changed ownership.

 

  • Like 1
Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 401 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...