Author Topic: Queue/Stack of Objects - Possible in NwN?  (Read 956 times)

Legacy_Tarot Redhand

  • Hero Member
  • *****
  • Posts: 4165
  • Karma: +0/-0
Queue/Stack of Objects - Possible in NwN?
« on: May 27, 2015, 01:03:08 am »


               

I have a while loop. In that loop, a function is called that deletes the object passed to it. With the function, the script crashes with a "too many instructions" error, iterating through the while loop 1400+ times. If I comment out the function call the while loop only iterates 30 times which is what is supposed to happen.


 


I figure that if I can separate the gathering of the objects from the deletion of same I can eliminate the crash. i.e.


  1. create a list of valid objects.

  2.    
  3. step through the list, deleting as I go.

For this I would need a more complex data structure than the simple variables provided by vanilla NwN. Does anyone know how to go about this?


 


Thanks in advance for any help.


 


TR



               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
Queue/Stack of Objects - Possible in NwN?
« Reply #1 on: May 27, 2015, 01:34:23 am »


               

You have to fake it. There are a number of list implementations. One simple one can be found in Paul Speed's z-dialog package. You only need the pg_lists_i.nss file from it. But  you could easily roll your own for what you are doing. e.g.  list_object_0, list_object_1 ...   just keep a count and walk back through the variables in a for loop or some such.



               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Queue/Stack of Objects - Possible in NwN?
« Reply #2 on: May 27, 2015, 03:11:06 am »


               

Hmm,   I am not 100% sure what you are trying to do.    But I can see where trying to maintain a list of object,   regardless of sorting them or not,  can lead to a TMI error. 


 


The only Idea I can think of would be to create a  empty store or other container object to hold you list as actual objects.  Not necessarily the actual object.  any miscellaneous Small item would do.   Give the item a useful  Tag to your situation and a LocalObject Var to point to the item it represents in your list. 


 


That is the best I can think of without seeing your original script. 


 


 


Example:


 


object oListContainer =  GetObjectByTag( " bla bla");

 

void AddItemToList ( object oItem)

{

 

   SetLocalObject

     (

       CreateItemOnObject("gem001",oListContainer,1,ObjectToString(oItem)),

       "Me",

       oItem

      );

 

}

               
               

               
            

Legacy_Proleric

  • Hero Member
  • *****
  • Posts: 1750
  • Karma: +0/-0
Queue/Stack of Objects - Possible in NwN?
« Reply #3 on: May 27, 2015, 11:29:38 pm »


               Without seeing the script, it's hard to be certain why you're getting a TMI. DestroyObject is normally safe in loops, because it doesn't occur until end of script.


If you need to make a list, though, as Meaglyn says, pseudoarrays are good. In this case, it would be a set of local objects, to be destroyed in a subsequent loop.
               
               

               
            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Queue/Stack of Objects - Possible in NwN?
« Reply #4 on: May 28, 2015, 02:49:29 am »


               

TMI is based on instruction count, not on script completion time.  If your script takes too long, then there are other problems, such as lag.  DestroyObject(), like any other instruction, can contribute to a TMI.


 


What appears to be the issue is that when you are removing an element from the list, you are reindexing the entire list to preserve order and reference.  What might be better is to allow null entries when an element is removed.  Another method, similar to Lightfoot's, is to use items for each list element, but instead of storing a tag for reference, simply reference the newest to oldest element by GetFirst/NextItemInInventory().  However, reindexing usually should not cause more instruction problems than one or two loops through every object would.



               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
Queue/Stack of Objects - Possible in NwN?
« Reply #5 on: May 28, 2015, 02:56:17 am »


               

Hhm... WhiZard and Lightfoot, I think I read that differently. I don't believe TR has a list implementation but is asking about switching to one. I suspect he's hitting TMI because he's doing something in the loop that is messing up the iterator state. Although, as Proleric said, DestroyObject by itself would generally not do that. Maybe he's got nested GetFirst/NextItem or something.



               
               

               
            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Queue/Stack of Objects - Possible in NwN?
« Reply #6 on: May 28, 2015, 05:22:42 am »


               

Yes, DestroyObject() does not interfere with the loop iterator, but CopyObject() and similar commands would.  If TR is trying to replace a number of objects in a loop, this could be the problem.



               
               

               
            

Legacy_Tarot Redhand

  • Hero Member
  • *****
  • Posts: 4165
  • Karma: +0/-0
Queue/Stack of Objects - Possible in NwN?
« Reply #7 on: May 28, 2015, 09:41:02 am »


               

Thanks guys. While I fixed the TMI issue (adding a DelayCommand cured it), it looks like I'll have to go down the pseudo stack route anyway. Here is the problem section of code.


 


void ChangeWindow(object oOldObject, string sNewLetter)

{

    string sResRef;

    location lHere;

 

    sResRef = GetResRef(oOldObject);

    lHere = GetLocation(oOldObject);

    sResRef = GetStringLeft(sResRef, GetStringLength(sResRef) - 1) + sNewLetter;

 

    if(sResRef == sOldResRef)

        return;

    else

        sOldResRef = sResRef;

 

    debug(sResRef);

    DestroyObject(oOldObject);

    DelayCommand(0.1f, CreateObjectVoid(OBJECT_TYPE_PLACEABLE, sResRef, lHere));

}

 

void ChangeAllWindows(string sNewLetter)

{

    int iIndex = 0;

    string sLastChar;

    object oPC = GetFirstPC();

    object oWindow = GetNearestObjectByTag("ES_SG_Win", oPC, iIndex);

 

    while(oWindow != OBJECT_INVALID)

    {

        sLastChar = GetStringRight(GetResRef(oWindow), 1);

 

        if(sLastChar != sNewLetter)

            ChangeWindow(oWindow, sNewLetter);

 

        iIndex++;

        oWindow = GetNearestObjectByTag("ES_SG_Win", oPC, iIndex);

    }

}

 

It is part of an OnEnter script for the management of a set of placeables that I have created. This section of code is supposed to


 


step through all of the placeables in an area and identify those that need changing and change each one as identified.


(changing involves destroying a placeable and creating a new one in the old ones exact location)


 


Unfortunately the above code is only mostly successful. This section of code


 


    if(sResRef == sOldResRef)

        return;

    else

        sOldResRef = sResRef;

 

was my last attempt to fix it and it almost worked too. sOldResRef is a global variable used to hold the value of a variable from the previous call to the function. Cest la vie.

 

As usual all comments welcome.

 

TR

 

PS What the bleeps happened to the code/end code thingy. It is now wiping out everything after it. This is the third attempt to write this reply! 


               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
Queue/Stack of Objects - Possible in NwN?
« Reply #8 on: May 28, 2015, 02:01:23 pm »


               

Yep. It's the create of the new object that was messing it up.  If  "if(sLastChar != sNewLetter)" is enough to be sure you want to change that window then you could just do the delaycommand on the call the to subroutine instead.



  if(sLastChar != sNewLetter)
            DelayCommand(0.1, ChangeWindow(oWindow, sNewLetter));

That way you would not need the delay in the subroutine and the creation of the new object would not interfere with your iterator. And you could probably remove the sOldResRef hackery.


               
               

               
            

Legacy_Tarot Redhand

  • Hero Member
  • *****
  • Posts: 4165
  • Karma: +0/-0
Queue/Stack of Objects - Possible in NwN?
« Reply #9 on: May 29, 2015, 01:18:48 am »


               
Well I have now rewritten the above section of code so that it now uses a pseudo list. However, I still have the same problem - one of the placeables is not being updated. There is some weird bug in the following code.

 

void ChangeAllWindows(string sNewLetter)

{

    int iIndex = 1;

    int iMatchedCount = 0;

    string sLastChar;

    object oPC = GetFirstPC();

    object oWindow = GetNearestObjectByTag("ES_SG_Win", oPC, iIndex);

 

    while(oWindow != OBJECT_INVALID)

    {

        sLastChar = GetStringRight(GetResRef(oWindow), 1);

 

        debug("Index = " + IntToString(iIndex) + " - " + GetResRef(oWindow) + " - " + GetName(oWindow));

 

        if(sLastChar != sNewLetter)

        {

            PushDetails(oWindow, sNewLetter, iMatchedCount);

            iMatchedCount++;

        }

        iIndex++;

        oWindow = GetNearestObjectByTag("ES_SG_Win", oPC, iIndex);

    }

 

2 things to note. iIndex is initialised to 1 in preparation for it to be used as parameter nNth as per the lexicon. I have a very small debug function that sends messages to both the pc and the log file. The call to it in the above code snippet produced the following output (with 1 instance of each of the 27 placeables in the area). 

 

Index =  1 - es_sg_window05l - ES SG Window 05 (Kynareth) Light

Index =  2 - es_sg_window06l - ES SG Window 06 (Mara) Light

Index =  3 - es_sg_window04l - ES SG Window 04 (Julianos) Light

Index =  4 - es_sg_window05e - ES SG Window 05 (Kynareth) Dusk

Index =  5 - es_sg_window06e - ES SG Window 06 (Mara) Dusk

Index =  6 - es_sg_window07l - ES SG Window 07 (Stendarr) Light

Index =  7 - es_sg_window04e - ES SG Window 04 (Julianos) Dusk

Index =  8 - es_sg_window03l - ES SG Window 03 (Dibella) Light

Index =  9 - es_sg_window07e - ES SG Window 07 (Stendarr) Dusk

Index = 10 - es_sg_window05d - ES SG Window 05 (Kynareth) Dark

Index = 11 - es_sg_window06d - ES SG Window 06 (Mara) Dark

Index = 12 - es_sg_window06d - ES SG Window 06 (Mara) Dark

Index = 13 - es_sg_window04d - ES SG Window 04 (Julianos) Dark

Index = 14 - es_sg_window08l - ES SG Window 08 (Talos) Light

Index = 15 - es_sg_window07d - ES SG Window 07 (Stendarr) Dark

Index = 16 - es_sg_window02l - ES SG Window 02 (Arkay) Light

Index = 17 - es_sg_window08e - ES SG Window 08 (Talos) Dusk

Index = 18 - es_sg_window03d - ES SG Window 03 (Dibella) Dark

Index = 19 - es_sg_window02e - ES SG Window 02 (Arkay) Dusk

Index = 20 - es_sg_window08d - ES SG Window 08 (Talos) Dark

Index = 21 - es_sg_window09l - ES SG Window 09 (Zenithar) Light

Index = 22 - es_sg_window09e - ES SG Window 09 (Zenithar) Dusk

Index = 23 - es_sg_window02d - ES SG Window 02 (Arkay) Dark

Index = 24 - es_sg_window01l - ES SG Window 01 (Akatosh) Light

Index = 25 - es_sg_window01e - ES SG Window 01 (Akatosh) Dusk

Index = 26 - es_sg_window09d - ES SG Window 09 (Zenithar) Dark

Index = 27 - es_sg_window01d - ES SG Window 01 (Akatosh) Dark

 

The question is "What is causing the duplication on the 11th and 12th passes and why is the object with the resref of es_sg_window03e being missed? I cannot see any errors in the blueprints either. TBH I am stumped. Ideas anyone?

 

TR


               
               

               
            

Legacy_Proleric

  • Hero Member
  • *****
  • Posts: 1750
  • Karma: +0/-0
Queue/Stack of Objects - Possible in NwN?
« Reply #10 on: May 29, 2015, 09:35:01 am »


               

What is PushDetails doing? What is the value of sNewLetter in this example?


 


I guess you've checked that you haven't accidentally duplicated es_sg_window06d instead of placing es_sg_window03e?



               
               

               
            

Legacy_Tarot Redhand

  • Hero Member
  • *****
  • Posts: 4165
  • Karma: +0/-0
Queue/Stack of Objects - Possible in NwN?
« Reply #11 on: May 29, 2015, 05:06:09 pm »


               

Here is the code for PushDetails and a little function it calls


 


string TwoStringDigits(int iInValue)

{

    string sReturnMe;

 

    if(iInValue > 9)

        sReturnMe = IntToString(iInValue);

    else

        sReturnMe = "0" + IntToString(iInValue);

 

    return sReturnMe;

}

 

void PushDetails(object oOldObject, string sNewLetter, int iIndex)

{

    string sVarO = "oStore" + TwoStringDigits(iIndex);

    string sVarL = "lStore" + TwoStringDigits(iIndex);

    string sVarR = "rStore" + TwoStringDigits(iIndex);

    string sResRef;

    location lHere;

 

    SetLocalObject(OBJECT_SELF, sVarO, oOldObject);

 

    lHere = GetLocation(oOldObject);

    SetLocalLocation(OBJECT_SELF, sVarL, lHere);

 

    sResRef = GetResRef(oOldObject);

    sResRef = GetStringLeft(sResRef, GetStringLength(sResRef) - 1) + sNewLetter;

    SetLocalString(OBJECT_SELF, sVarR, sResRef);

}

 

It simply stores the details of the object itself, its location and the resref of the object that will replace it  later on, in a pseudo list without doing anything to the object at this point.

 

The value of sNewLetter in this example is "d", although I positioned the call to debug so that I could check every object that GetNearestObjectByTag found.  

 

I have double checked through all the blueprint resrefs but I thought that the toolset wouldn't allow 2 blueprints with the same resref anyway.

 

TR


               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
Queue/Stack of Objects - Possible in NwN?
« Reply #12 on: May 29, 2015, 06:05:52 pm »


               

It won't. Proleric is asking if you have accidentally painted es_sg_window06d twice in the area. And not painted es_sg_window03e at all.



               
               

               
            

Legacy_Proleric

  • Hero Member
  • *****
  • Posts: 1750
  • Karma: +0/-0
Queue/Stack of Objects - Possible in NwN?
« Reply #13 on: May 29, 2015, 06:10:11 pm »


               

True, you can't have two blueprints with the same resref, but you can accidentally have two instances of the same blueprint in an area.


 


Edit : what meaglyn said.



               
               

               
            

Legacy_Tarot Redhand

  • Hero Member
  • *****
  • Posts: 4165
  • Karma: +0/-0
Queue/Stack of Objects - Possible in NwN?
« Reply #14 on: May 29, 2015, 07:11:21 pm »


               

Nope, Just 1 instance of each one - I double checked that at the same time.


 


TR