MantisBT - opensim
View Issue Details
0008706opensim[REGION] OpenSim Corepublic2020-05-22 19:352020-05-29 20:09
mewtwo0641 
 
normalmajorrandom
newopen 
 
 
Grid (Multiple Regions per Sim)
ubODE
YEngine
.NET / Windows64
None
0008706: Various exceptions thrown with scripts, attachments, NPCs, etc.
As of commit 8b7716, I am experiencing various exceptions being thrown with scripts, failed attachments, etc.

The script exceptions happen most often when teleporting, sim crossing, or logging off. I am unsure what exactly is causing these exceptions but at the very least, they seem to be making the scripts involved stop working. This is most noticeable on scripts that users are using in attachments (vs. scripts NPCs are using)

There are several NPCs that auto load after the sim starts and the failed attachments exceptions are happening on them; although the consequences of these exceptions are as of right now, unknown, since visibly the attachments appear to be attached to the NPCs.

I have tried the usual steps to see if it's an issue on my end and possibly resolve (in no particular order): relog, restart OS, reboot server, delete viewer cache, delete OpenSim caches, delete ScriptEngines folder, reset the affected scripts, recompile the affected scripts, etc.

I ran git bisect and found that these issues start happening at commit 8b7716. Reverting this commit does partially fix the issue for me. The script exceptions stop happening and the scripts no longer quit functioning after the above mentioned scenarios; although the attachment exceptions still occur, so I suspect another commit after 8b7716 is causing this.

If I checkout a revision before commit 8b7716 then everything is fine; no issues at all.

===================================
Moved Additional Information here:
===================================

Git Bisect Result:

$ git bisect good
8b771620203b0cafc851934a2514166dac1b2923 is the first bad commit
commit 8b771620203b0cafc851934a2514166dac1b2923
Author: UbitUmarov <ajlduarte@sapo.pt>
Date: Thu May 14 12:02:46 2020 +0100

    make sog, sop and sop inventory IDisposable

 .../Avatar/Attachments/AttachmentsModule.cs | 4 +-
 OpenSim/Region/Framework/Scenes/Scene.cs | 2 +-
 .../Region/Framework/Scenes/SceneObjectGroup.cs | 53 ++++++++++++++++------
 OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 36 ++++++++++++++-
 .../Framework/Scenes/SceneObjectPartInventory.cs | 28 +++++++++++-
 5 files changed, 104 insertions(+), 19 deletions(-)


Exceptions (There are many of these exceptions, but they all say the same thing, just the attachments and script names are changed):

Script Exceptions:

2020-05-20 21:47:45,293 INFO [YEngine]: Exception while running dbf4b8f1-57ce-43c4-a2ac-f407c334a7f8
NullReferenceException: Object reference not set to an instance of an object.
Prim: <AO v7.0.3>, Script: <* AO v7.0.3>, Location: Test Region <0,-1,-1>
Script must be Reset to re-enable.
  at OpenSim.Region.ScriptEngine.Shared.Api.LSL_Api.llGetInventoryType(String name) in LSL_Api.cs:line 13531
  at OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass.llGetInventoryType(String name) in LSL_Stub.cs:line 546
  at handleEvent(string)
  at timerTick()
  at default timer
  at OpenSim.Region.ScriptEngine.Yengine.XMRInstAbstract.CallSEH() in XMRInstAbstract.cs:line 525
  at OpenSim.Region.ScriptEngine.Yengine.XMRInstance.StartEx() in XMRScriptUThread.cs:line 51
System.NullReferenceException: Object reference not set to an instance of an object.
   at OpenSim.Region.ScriptEngine.Shared.Api.LSL_Api.llGetInventoryType(String name) in E:\opensim\OpenSim\Region\ScriptEngine\Shared\Api\Implementation\LSL_Api.cs:line 13531
   at OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass.llGetInventoryType(String name) in E:\opensim\OpenSim\Region\ScriptEngine\Shared\Api\Runtime\LSL_Stub.cs:line 546
   at handleEvent(string)(XMRInstanceSuperType , String )
   at timerTick()(XMRInstanceSuperType )
   at default timer(XMRInstAbstract )
   at OpenSim.Region.ScriptEngine.Yengine.XMRInstAbstract.CallSEH() in E:\opensim\OpenSim\Region\ScriptEngine\YEngine\XMRInstAbstract.cs:line 525
   at OpenSim.Region.ScriptEngine.Yengine.XMRInstance.StartEx() in E:\opensim\OpenSim\Region\ScriptEngine\YEngine\XMRScriptUThread.cs:line 51


Attachment Exceptions:

2020-05-22 21:00:47,061 ERROR [ATTACHMENTS MODULE]: Failed to attach Bracer 62d5e8fa-ebf5-438a-b58f-7f590c9991d1 for Helper NPC, exception Value cannot be null. at System.Threading.Monitor.Enter(Object obj)
   at OpenSim.Region.Framework.Scenes.ScenePresence.AddAttachment(SceneObjectGroup gobj) in E:\opensim\OpenSim\Region\Framework\Scenes\ScenePresence.cs:line 5462
   at OpenSim.Region.CoreModules.Avatar.Attachments.AttachmentsModule.AttachToAgent(IScenePresence sp, SceneObjectGroup so, UInt32 attachmentpoint, Vector3 attachOffset, Boolean silent) in E:\opensim\OpenSim\Region\CoreModules\Avatar\Attachments\AttachmentsModule.cs:line 1083
   at OpenSim.Region.CoreModules.Avatar.Attachments.AttachmentsModule.AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, UInt32 attachmentPt, Boolean silent, Boolean addToInventory, Boolean resumeScripts, Boolean append) in E:\opensim\OpenSim\Region\CoreModules\Avatar\Attachments\AttachmentsModule.cs:line 665
   at OpenSim.Region.CoreModules.Avatar.Attachments.AttachmentsModule.RezSingleAttachmentFromInventoryInternal(IScenePresence sp, UUID itemID, UUID assetID, UInt32 attachmentPt, Boolean append, XmlDocument doc) in E:\opensim\OpenSim\Region\CoreModules\Avatar\Attachments\AttachmentsModule.cs:line 1291
2020-05-22 21:00:47,084 ERROR [ATTACHMENTS MODULE]: Unable to rez attachment with itemID aa432743-671d-4620-b546-cd2260058287, assetID d5276939-7158-4ac4-bd0a-30e9ca81ee5e, point 19 for 00000000-0000-0000-0000-000000000000: Value cannot be null.
   at System.Threading.Monitor.Enter(Object obj)
   at OpenSim.Region.Framework.Scenes.ScenePresence.RemoveAttachment(SceneObjectGroup gobj) in E:\opensim\OpenSim\Region\Framework\Scenes\ScenePresence.cs:line 5597
   at OpenSim.Region.CoreModules.Avatar.Attachments.AttachmentsModule.RezSingleAttachmentFromInventoryInternal(IScenePresence sp, UUID itemID, UUID assetID, UInt32 attachmentPt, Boolean append, XmlDocument doc) in E:\opensim\OpenSim\Region\CoreModules\Avatar\Attachments\AttachmentsModule.cs:line 1304
   at OpenSim.Region.CoreModules.Avatar.Attachments.AttachmentsModule.RezAttachments(IScenePresence sp) in E:\opensim\OpenSim\Region\CoreModules\Avatar\Attachments\AttachmentsModule.cs:line 455
Note: This was reproduced on YEngine. I have no idea if this affects XEngine or not.

1. Make new script and copy script from Additional Information to it
    a. I made mine as a HUD so that it's easier to watch the set text counter on it

2. Detach the HUD to save script state, object state, etc.

3. Reattach it

4. Teleport and region cross between 2 (or more) regions on OSGrid running at least commit 8b7716
    a. This issue is easier to trigger on OSGrid/across WAN than it is with a grid running local to you.

    b. It may take a few teleports to trigger; it's very inconsistent

    c. Once the issue triggers; One of two possible things should happen: The counter will freeze and the script will be unresponsive until relog/teleport, or The script will just completely reset itself. In both instances the script eventually has it's script state reset... Which is not great for attachment scripts that need to be long running.
float interval = 0.5;
integer count = 0;

default
{
    state_entry()
    {
        llOwnerSay("Script reset");
        llSetTimerEvent(interval);
    }

    timer()
    {
        llSetTimerEvent(0.0);

        count++;
        llSetText((string)count, <0,1,0>, 1.0);

        llSetTimerEvent(interval);
    }
}
No tags attached.
Issue History
2020-05-22 19:35mewtwo0641New Issue
2020-05-22 19:37mewtwo0641Description Updatedbug_revision_view_page.php?rev_id=9051#r9051
2020-05-24 00:58tampaNote Added: 0036487
2020-05-24 04:11mewtwo0641Note Added: 0036489
2020-05-24 04:12mewtwo0641Note Added: 0036490
2020-05-24 04:15mewtwo0641Note Added: 0036491
2020-05-24 04:16UbitUmarovNote Added: 0036492
2020-05-24 04:18mewtwo0641Note Edited: 0036489bug_revision_view_page.php?bugnote_id=36489#r9055
2020-05-24 08:38mewtwo0641Note Added: 0036495
2020-05-24 09:03UbitUmarovNote Added: 0036496
2020-05-24 09:13UbitUmarovNote Added: 0036497
2020-05-24 16:14UbitUmarovNote Added: 0036498
2020-05-24 17:53mewtwo0641Note Added: 0036499
2020-05-24 17:56mewtwo0641Script EngineXEngine => YEngine
2020-05-25 04:03mewtwo0641Note Added: 0036500
2020-05-29 19:59mewtwo0641Description Updatedbug_revision_view_page.php?rev_id=9064#r9064
2020-05-29 19:59mewtwo0641Steps to Reproduce Updatedbug_revision_view_page.php?rev_id=9066#r9066
2020-05-29 19:59mewtwo0641Additional Information Updatedbug_revision_view_page.php?rev_id=9068#r9068
2020-05-29 19:59mewtwo0641Note Added: 0036520
2020-05-29 20:09mewtwo0641Steps to Reproduce Updatedbug_revision_view_page.php?rev_id=9069#r9069

Notes
(0036487)
tampa   
2020-05-24 00:58   
Can you perhaps post a script that can reproduce this so we can test it?
(0036489)
mewtwo0641   
2020-05-24 04:11   
(edited on: 2020-05-24 04:18)
I have just posted an AO script and an NPC script that I've been using on OSGrid that seems to trigger these issues pretty consistently for me (And have never been a problem before the mentioned commit in this mantis). These have been posted in 2 separate comments so that things don't run together and make it hard to sort out.

The reason I didn't post any scripts originally was because it seems to be random the scripts it happens with.

As a side note, the YEngine exceptions involving teleports and logging out seems to trigger a lot more often on OSGrid than it does with a local installation of OS. So you would need to test latest master on OSGrid with a minimum of 2 regions to test teleporting/region crossing back and forth between.

The NPC script triggers the attachments issue on both local grids and OSGrid that I have seen.

(0036490)
mewtwo0641   
2020-05-24 04:12   
Script to test teleport/logging off:

float typeCheckTime = 0.5;
float stillSittingCheckTime = 0.5;

list stands = [];
list walks = [];
list runs = [];
list jumps = [];
list sits = [];
list gsits = [];
list hovers = [];

string animStanding;
string animWalking;
string animRunning;
string animJumping;
string animPreJumping;
string animFlying;
string animFalling;
string animStandUp;
string animLanding;
string animCrouch;
string animCrouchWalk;
string animTyping;
string animHover;
string animHoverUp;
string animHoverDown;
string animSit;
string animGroundSit;
string animTurnLeft;
string animTurnRight;

string lastAnim;
integer isTyping = FALSE;

float StandTime = 60.0;
integer WalkChangeAnim = TRUE;
integer RandomWalk = TRUE;
integer RandomRun = TRUE;
integer RandomJump = TRUE;
integer RandomSit = TRUE;
integer RandomGSit = TRUE;
integer RandomHover = TRUE;

//Note card variables loader -------------------------------------------------
string NoteName;

string CFNC_TIMER = "StandTime";
string CFNC_WALKCHANGE = "WalkChange";
string CFNC_RANDOMWALK = "RandomWalk";
string CFNC_RANDOMRUN = "RandomRun";
string CFNC_RANDOMJUMP = "RandomJump";
string CFNC_RANDOMSIT = "RandomSit";
string CFNC_RANDOMGSIT = "RandomGSit";
string CFNC_RANDOMHOVER = "RandomHover";

string CFNC_STANDING = "Standing";
string CFNC_WALKING = "Walking";
string CFNC_RUNNING = "Running";
string CFNC_JUMPING = "Jumping";
string CFNC_PREJUMPING = "PreJumping";
string CFNC_FLYING = "Flying";
string CFNC_FALLING = "Falling";
string CFNC_STANDUP = "StandUp";
string CFNC_LANDING = "Landing";
string CFNC_CROUCH = "Crouch";
string CFNC_CROUCHWALK = "CrouchWalk";
string CFNC_TYPING = "Typing";
string CFNC_HOVER = "Hover";
string CFNC_HOVERUP = "HoverUp";
string CFNC_HOVERDOWN = "HoverDown";
string CFNC_SIT = "Sit";
string CFNC_GROUNDSIT = "GroundSit";
string CFNC_TURNLEFT = "TurnLeft";
string CFNC_TURNRIGHT = "TurnRight";

integer AoActive = TRUE;

key owner;

debug(string str)
{
    //llOwnerSay("DEBUG: " + str);
}

inform(string str)
{
    llOwnerSay(str);
}

PreInit()
{
    owner = llGetOwner();

    if(NoteName == "")
        ParseConfig(llGetInventoryName(INVENTORY_NOTECARD, 0));

    else
        ParseConfig(NoteName);

    MainInit();
}

MainInit()
{
    AoActive = TRUE;

    llRequestPermissions(owner, PERMISSION_TRIGGER_ANIMATION | PERMISSION_OVERRIDE_ANIMATIONS);

    llResetAnimationOverride("ALL");

    if(!IsSitting())
        PickRandomAnim("Standing", stands);

    else
        setTimer(idStillSitting, stillSittingCheckTime);

    PickRandomAnim("Walking", walks);
    PickRandomAnim("Running", runs);

    ResetTimers();

    inform("AO is on! Loaded: " + NoteName);

    debug("Stand Time: " + (string)StandTime);
    debug("Walk Change: " + (string)WalkChangeAnim);
    debug("Standing: " + llDumpList2String(stands, ","));
    debug("Walking: " + animWalking);
    debug("Running: " + animRunning);
}

ParseConfig(string notecard)
{
    SoftReset();
    NoteName = notecard;

    inform("Getting configuration from notecard '" + NoteName + "'. Please wait...");

    integer i = 0;
    integer numLines = osGetNumberOfNotecardLines(notecard);

    for(i = 0; i < numLines; i++)
    {
        string curLine = osGetNotecardLine(notecard, i);

        if (!(llStringLength(curLine) == 0 || llGetSubString(curLine, 0, 0) == "#"))
        {
            list nvpair = llParseString2List(curLine, ["="], []);
            string setting = llList2String(nvpair, 0);
            string value = llList2String(nvpair, 1);

            setting = llStringTrim(setting, STRING_TRIM);
            value = llStringTrim(value, STRING_TRIM);

            if(llToLower(value) == "true") value = "1";
            else if(llToLower(value) == "false") value = "0";

            if(setting == CFNC_TIMER) StandTime = (float)value;
            if(setting == CFNC_WALKCHANGE) WalkChangeAnim = (integer)value;
            if(setting == CFNC_RANDOMWALK) RandomWalk = (integer)value;
            if(setting == CFNC_RANDOMRUN) RandomRun = (integer)value;
            if(setting == CFNC_RANDOMJUMP) RandomJump = (integer)value;
            if(setting == CFNC_RANDOMSIT) RandomSit = (integer)value;
            if(setting == CFNC_RANDOMGSIT) RandomGSit = (integer)value;
            if(setting == CFNC_RANDOMHOVER) RandomHover = (integer)value;

            if(setting == CFNC_STANDING)
            {
                stands += llCSV2List(value);
                animStanding = llList2String(stands, 0);
                AnimCheck(stands);
            }

            if(setting == CFNC_WALKING)
            {
                walks += llCSV2List(value);
                animWalking = llList2String(walks, 0);
                AnimCheck(walks);
            }

            if(setting == CFNC_RUNNING)
            {
                runs += llCSV2List(value);
                animRunning = llList2String(runs, 0);
                AnimCheck(runs);
            }

            if(setting == CFNC_JUMPING)
            {
                jumps += llCSV2List(value);
                animJumping = llList2String(jumps, 0);
                AnimCheck(jumps);
            }

            if(setting == CFNC_SIT)
            {
                sits += llCSV2List(value);
                animSit = llList2String(sits, 0);
                AnimCheck(sits);
            }

            if(setting == CFNC_GROUNDSIT)
            {
                gsits += llCSV2List(value);
                animGroundSit = llList2String(gsits, 0);
                AnimCheck(gsits);
            }

            if(setting == CFNC_HOVER)
            {
                hovers += llCSV2List(value);
                animHover = llList2String(hovers, 0);
                AnimCheck(hovers);
            }

            if(setting == CFNC_PREJUMPING)
            {
                animPreJumping = value;
                AnimCheck([value]);
            }

            if(setting == CFNC_FLYING)
            {
                animFlying = value;
                AnimCheck([value]);
            }

            if(setting == CFNC_FALLING)
            {
                animFalling = value;
                AnimCheck([value]);
            }

            if(setting == CFNC_STANDUP)
            {
                animStandUp = value;
                AnimCheck([value]);
            }

            if(setting == CFNC_LANDING)
            {
                animLanding = value;
                AnimCheck([value]);
            }

            if(setting == CFNC_CROUCH)
            {
                animCrouch = value;
                AnimCheck([value]);
            }

            if(setting == CFNC_CROUCHWALK)
            {
                animCrouchWalk = value;
                AnimCheck([value]);
            }

            if(setting == CFNC_TYPING)
            {
                animTyping = value;
                AnimCheck([value]);
            }

            if(setting == CFNC_HOVERUP)
            {
                animHoverUp = value;
                AnimCheck([value]);
            }

            if(setting == CFNC_HOVERDOWN)
            {
                animHoverDown = value;
                AnimCheck([value]);
            }

            if(setting == CFNC_TURNLEFT)
            {
                animTurnLeft = value;
                AnimCheck([value]);
            }

            if(setting == CFNC_TURNRIGHT)
            {
                animTurnRight = value;
                AnimCheck([value]);
            }
        }
    }

    //Don't bother with a stand time timer if there is only one stand anim
    if(llGetListLength(stands) <= 1)
        StandTime = 0;
}

PickRandomAnim(string cmd, list animations)
{
    list ValidStates =
    [
        "Standing", "Walking", "Running", "Jumping",
        "Sitting", "Sitting on Ground", "Hovering"
    ];

    if(llListFindList(ValidStates, [cmd]) == -1)
    {
        inform("Unknown PickRandomAnim() command: " + cmd);
        return;
    }

    string RandomAnim = llList2String(animations, (integer)llFrand(llGetListLength(animations)));

    if(cmd == "Standing") animStanding = RandomAnim;
    else if(cmd == "Walking" && RandomWalk) animWalking = RandomAnim;
    else if(cmd == "Running" && RandomRun) animRunning = RandomAnim;
    else if(cmd == "Jumping" && RandomJump) animJumping = RandomAnim;
    else if(cmd == "Sitting" && RandomSit) animSit = RandomAnim;
    else if(cmd == "Sitting on Ground" && RandomGSit) animGroundSit = RandomAnim;
    else if(cmd == "Hovering" && RandomHover) animHover = RandomAnim;

    //Don't set stand animation if we're sitting
    if(cmd == "Standing" && IsSitting())
    {
        debug("Not setting stand animation because agent is sitting");
        setTimer(idStillSitting, stillSittingCheckTime);
        return;
    }

    SetAOAnim(cmd, RandomAnim);

    debug("Picked new " + cmd + " animation: " + RandomAnim);
}

RefreshAO(string anim)
{
    //Multiple config anims
    if(anim == "Standing" && WalkChangeAnim) PickRandomAnim("Standing", stands);
    else if(anim == "Walking") PickRandomAnim(anim, walks);
    else if(anim == "Running") PickRandomAnim(anim, runs);
    else if(anim == "Jumping") PickRandomAnim(anim, jumps);
    else if(anim == "Sitting") PickRandomAnim(anim, sits);
    else if(anim == "Sitting on Ground") PickRandomAnim(anim, gsits);
    else if(anim == "Hovering") PickRandomAnim(anim, hovers);

    //Single config anims
    else if(anim == "Turning Left") SetAOAnim(anim, animTurnLeft);
    else if(anim == "Turning Right") SetAOAnim(anim, animTurnRight);
    else if(anim == "PreJumping") SetAOAnim(anim, animPreJumping);
    else if(anim == "Flying") SetAOAnim(anim, animFlying);
    else if(anim == "Falling Down") SetAOAnim(anim, animFalling);
    else if(anim == "Standing Up") SetAOAnim(anim, animStandUp);
    else if(anim == "Landing" || anim == "Soft Landing") SetAOAnim(anim, animLanding);
    else if(anim == "Crouching") SetAOAnim(anim, animCrouch);
    else if(anim == "CrouchWalking") SetAOAnim(anim, animCrouchWalk);
    else if(anim == "Hovering Up") SetAOAnim(anim, animHoverUp);
    else if(anim == "Hovering Down") SetAOAnim(anim, animHoverDown);

    else
    {
        if(anim != "Standing")
            debug("RefreshAO(): Unknown animation state: " + anim);

        if(llStringTrim(anim, STRING_TRIM) == "")
            inform("RefreshAO(): Got a blank animation state: '" + anim + "'");
    }
}

SetAOAnim(string CurAnimType, string NewAnim)
{
    //Ignore blank animations as can be the case with
    //non configured anim states in the notecard
    if(llStringTrim(NewAnim, STRING_TRIM) == "")
        return;

    if(llGetInventoryType(NewAnim) != -1)
    {
        if(llGetPermissions() & PERMISSION_OVERRIDE_ANIMATIONS)
        {
            //Only set AO if the requested animation is different from current
            if(llGetAnimationOverride(CurAnimType) != NewAnim)
            {
                llSetAnimationOverride(CurAnimType, NewAnim);
                debug("Set override for " + CurAnimType + " to " + NewAnim);
            }
        }

        else
            inform("No permission set to override animations!");
    }

    else
        inform("Could not find the animation named '" + NewAnim + "'");
}

AnimCheck(list anims)
{
    integer i = 0;
    integer length = llGetListLength(anims);

    for(i = 0; i < length; i++)
    {
        string thisAnim = llList2String(anims, i);

        if(llGetInventoryType(thisAnim) == -1 && thisAnim != "")
            inform("Animation: '" + thisAnim + "' not found!");
    }
}

integer IsSitting()
{
    string AnimState = llGetAnimation(owner);
    return AnimState == "Sitting" || AnimState == "Sitting on Ground";
}

ResetTimers()
{
    setTimer(idNewStandAnim, StandTime);
    setTimer(idTyping, typeCheckTime);
}

SoftReset()
{
    // Clear out animations when switching AO notecards
    llResetAnimationOverride("ALL");

    stands = [];
    walks = [];
    runs = [];
    jumps = [];
    sits = [];
    gsits = [];
    hovers = [];

    animStanding = "";
    animWalking = "";
    animRunning = "";
    animJumping = "";
    animPreJumping = "";
    animFlying = "";
    animFalling = "";
    animStandUp = "";
    animLanding = "";
    animCrouch = "";
    animCrouchWalk = "";
    animTyping = "";
    animHover = "";
    animHoverUp = "";
    animHoverDown = "";
    animSit = "";
    animGroundSit = "";
    animTurnLeft = "";
    animTurnRight = "";
}

toggleAo(integer toggle)
{
    AoActive = toggle;

    if(toggle)
        MainInit();

    else if(!toggle)
    {
        timerData = [];
        llResetAnimationOverride("ALL");
        inform("AO is off!");
    }
}

float timerRefresh = 0.5;

list timerData;

string idNewStandAnim = "newStandAnim";
string idTyping = "isTypingCheck";
string idStillSitting = "stillSittingCheck";

setTimer(string id, float time)
{
    if(timerData == [])
        llSetTimerEvent(timerRefresh);

    integer idIndex = llListFindList(timerData, [id]);

    if (idIndex != -1)
        timerData = llDeleteSubList(timerData, idIndex - 1, idIndex);

    if (time != 0)
    {
        timerData += (string)(llGetTime() + time);
        timerData += id;
    }

    timerData = llListSort(timerData, 2, TRUE);
}

timerTick()
{
    float curTime = llGetTime();

    integer i;
    integer numTimers = llGetListLength(timerData);

    string showTime = "";

    for (i = 0; i < numTimers; i += 2)
    {
        float triggerTime = (float)llList2String(timerData, i);
        string id = llList2String(timerData, i + 1);

        if (triggerTime - curTime <= 0)
        {
            timerData = llDeleteSubList(timerData, i, i + 1);
            handleEvent(id);

            if(timerData == [])
                llSetTimerEvent(0);
        }
    }
}

handleEvent(string id)
{
    if(id == "")
        return;

    if(id == idNewStandAnim)
    {
        if(AoActive)
        {
            PickRandomAnim("Standing", stands);
            setTimer(idNewStandAnim, StandTime);
        }
    }

    else if(id == idTyping)
    {
        //We don't have a typing anim. Disable the timer.
        if(llGetInventoryType(animTyping) == -1)
        {
            setTimer(idTyping, 0.0);
            return;
        }

        if(AoActive)
        {
            if(llGetAgentInfo(owner) & AGENT_TYPING)
            {
                if(!isTyping)
                {
                    isTyping = TRUE;
                    llStartAnimation(animTyping);
                }
            }

            else
            {
                if(isTyping)
                {
                    isTyping = FALSE;
                    llStopAnimation(animTyping);
                }
            }

            setTimer(idTyping, typeCheckTime);
        }
    }

    else if(id == idStillSitting)
    {
        if(IsSitting())
            setTimer(idStillSitting, stillSittingCheckTime);

        else
            PickRandomAnim("Standing", stands);
    }
}

default
{
    state_entry()
    {
        PreInit();
    }

    on_rez(integer params)
    {
        if(owner != llGetOwner())
        {
            llResetScript();
            return;
        }

        if(AoActive)
            MainInit();
    }

    attach(key id)
    {
        if(id == NULL_KEY)
        {
            llResetAnimationOverride("ALL");
        }
    }

    timer()
    {
        timerTick();
    }

    changed( integer change )
    {
        if (change & CHANGED_REGION)
            ResetTimers();

        else if (change & CHANGED_ANIMATION)
        {
            //AO is off. Don't process animations.
            if(!AoActive)
                return;

            string anim = llGetAnimation(owner);

            //Ignore any repeated animation states
            if(anim == lastAnim)
                return;

            //Turning states don't clear if walk/run left/right so ignore them for this instance
            if(lastAnim == "Walking" || lastAnim == "Running")
            {
                if(anim == "Turning Left" || anim == "Turning Right")
                    return;
            }

            RefreshAO(anim);

            lastAnim = anim;
        }
    }
}
(0036491)
mewtwo0641   
2020-05-24 04:15   
Script to test NPCs with attachments (This is a slightly modified version of the "NPC Persist" script that can be found on OpenSim's OSSL wiki. It loads an NPC upon region startup):


string firstname = "Test";
string lastname = "NPC";
string npcNote = "test npc notecard name";

list anims = []; // List animations to play at random here

integer sitOnThisObj = TRUE;

integer npcPersist = TRUE;

key npc = NULL_KEY;
float timerRefresh = 1.0;
vector offset = <0.5, 0.0, 0.0>;

string chatInit;
string chatKill;
string chatStillHere;

init()
{
    // Chat set up is done in its own function so that variables
    // can be used thus avoiding Error CS0236.
    chatInit = firstname + " " + lastname + ", at your service.";
    chatKill = "I'm leaving.";
    chatStillHere = "I'm already here.";
    
    // Setup and rez the NPC.
    
    //An NPC matching the UUID stored in the object
    //description already exists, so just retrieve the UUID.
    if (npcExists())
        npc = (key)llGetObjectDesc();
        
    // Create NPC if one doesn't exist
    else if (!npcExists())
        createNpc();
    
    llListen(0, "", NULL_KEY, "");
}

integer npcExists()
{
    key tempKey = (key)llGetObjectDesc();
    
    if(llGetAgentSize(tempKey) != ZERO_VECTOR && tempKey != NULL_KEY)
        return TRUE;
    
    else
        return FALSE;
}

createNpc()
{
    llSetTimerEvent(0.0);
    
    if(!npcPersist)
    {
        llOwnerSay("Not creating NPC because npcPersist = FALSE");
        return;
    }
        
    //Check that npc notecard exists
    if(llGetInventoryType(npcNote) == -1)
    {
        llOwnerSay("Can not find NPC note '" + npcNote + "'");
        return;
    }
    
    // Create a new instance of the NPC, set flag for persistance checks,
    // record the UUID in the object's description, and set starting rotation.
    // NPC rotation and location are inherited from the controlling object with an offset.
    npc = osNpcCreate(firstname, lastname, llGetPos() + offset, npcNote);
    llSetObjectDesc((string)npc);
    osNpcSetRot(npc, llGetRot() * (llEuler2Rot(<0, 0, 90> * DEG_TO_RAD)));
    osNpcSay(npc, chatInit);
    
    if(llGetListLength(anims) > 0)
    {
        string anim = llList2String(anims, (integer)llFrand(llGetListLength(anims)));
        osAvatarPlayAnimation(npc, anim);
    }
    
    // Sit on this object if required
    if(sitOnThisObj)
        osNpcSit(npc, llGetKey(), OS_NPC_SIT_NOW);
        
    // Set up persistance timer
    llSetTimerEvent(timerRefresh);
}
 
killNpc(integer notify)
{
    llSetTimerEvent(0.0);
    
    if(notify)
        osNpcSay(npc, chatKill);
        
    //Remove NPC
    osNpcRemove(npc);
    
    //Null the keys
    npc = NULL_KEY;
    llSetObjectDesc((string)NULL_KEY);
}

default
{
    state_entry()
    {
        init();
    }
    
    changed(integer change)
    {
        if(change & CHANGED_REGION_START)
        {
            llSetTimerEvent(0.0);
            killNpc(FALSE);
            createNpc();
        }
    }
 
    timer()
    {
        if (!npcExists())
            createNpc();
    }
 
    listen(integer channel, string name, key id, string msg)
    {
        // Kill the NPC and set a flag so it stays off.
        if (llToLower(msg) == "kill")
        {
            npcPersist = FALSE;
            killNpc(TRUE);
        }
        
        // Create a new NPC
        else if (llToLower(msg) == "start" && !npcExists())
        {
            npcPersist = TRUE;
            createNpc();
        }
        
        // NPC still exists
        else if (llToLower(msg) == "start" && npcExists())
            osNpcSay(npc, chatStillHere);
    }
}
(0036492)
UbitUmarov   
2020-05-24 04:16   
guess that code change just exposed things that kept running on deleted objects
(0036495)
mewtwo0641   
2020-05-24 08:38   
Just tried master at commit 5f52de. I tried teleporting with the AO script I posted earlier and the logging is gone now... But the side effects of the issue is still there; The script is still left in a non functioning state until it is recompiled.
(0036496)
UbitUmarov   
2020-05-24 09:03   
could not repo with your script
in fact the expection i did avoid does not even happen

my region is of course empty, cpu doing nothing
(0036497)
UbitUmarov   
2020-05-24 09:13   
repeated the test with tps btw osgrid regions sandbox plaza and dev outreach ( both on Yengine, without last change) and see timer kicking...
( had to by pass reading the notecard bc i have none)

can you try there with the full thing?

( no idea abotu the npcs case, guess similar things)
(0036498)
UbitUmarov   
2020-05-24 16:14   
what is your mono version? ( if it is mono..)
(0036499)
mewtwo0641   
2020-05-24 17:53   
My regions do have a few things on them, but as far as scripts are concerned they are near empty. Just a few things are scripted, such as door scripts, a few pose scripts, and a few instances of the NPC Persist script in the second comment that has an example script in it... Nothing too crazy or overly ambitious.

CPU use is low; I see it ticking between 0% and 3% once in a while mostly.

I am using .NET 4.7.2 on Windows 7 x64 and do not have Mono installed.
(0036500)
mewtwo0641   
2020-05-25 04:03   
I was able to reproduce with the AO script between Dev Outreach and Sandbox Plaza within a few teleports back and forth. The script stopped working until relog. But once I relogged, the script was completely reset, losing its previous script state.
(0036520)
mewtwo0641   
2020-05-29 19:59   
I think I've boiled the issue down to a much simpler script. Please check the updated Steps to Reproduce and Additional Information.