Author Topic: What's the point?  (Read 1491 times)

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
What's the point?
« Reply #30 on: February 07, 2013, 07:27:39 pm »


               

ffbj wrote...

Np, and thanks for the definition. I wonder why sometimes I get a script that will TMI, it's a spawn script, but not always. I'd say about 1 out of 5 times it fires it TMI's. Well here it is:

I stopped reading at the first potential problem point, because the lack of indents was driving me nuts. This:


    object oPChp = GetFirstPC();
    while (GetIsObjectValid(oPChp)||(oArea == GetArea(oPChp))){
        if (oArea != GetArea(oPChp)){
            oPChp = GetNextPC();
        }
        iHd++;
        iHd += GetHitDice(oPChp); //trying to add the pc's in the area hp
        oPChp = GetNextPC();
    }
Looks suspect to me, because you iterate oPChp twice in some loops. I can't guaranteed it's the cause, as I haven't tested, but I would write this as a for loop instead, to make use of continue.

    for (oPChp = GetFirstPC(); GetIsObjectValid(oPChp); oPChp = GetNextPC()) {
        if (oArea != GetArea(oPChp))
            continue;
        iHd++;
        iHd += GetHitDice(oPChp); //trying to add the pc's in the area hp
    }

If you're using the default compiler, however, I don't think it'll let you, so you woud instead use:

    object oPChp = GetFirstPC();
    while (GetIsObjectValid(oPChp)||(oArea == GetArea(oPChp))){
        if (oArea != GetArea(oPChp)){
            oPChp = GetNextPC();
        } else {
            iHd++;
            iHd += GetHitDice(oPChp); //trying to add the pc's in the area hp
            oPChp = GetNextPC();
        }
    }
If, in fact, that's the functionality you intended.

If you indent the rest properly I'll be happy to take a look at the rest and find the problem, if the above isn't it.

Funky
               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
What's the point?
« Reply #31 on: February 07, 2013, 07:52:09 pm »


               ffbj and funky,

I was about to comment on the loop too but for different reasons. That logical OR in the loop
condition looks suspect to me. I think you mean it to be AND.

If for some reason oArea was invalid what you have is an infinite loop as soon as oPChp goes
invalid.

Cheers,

Meaglyn
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
What's the point?
« Reply #32 on: February 07, 2013, 08:15:13 pm »


               Bah, I didn't even look at that - left it out of the for loop. Very strange thing to do. Maybe you should describe what that loop is supposed to do. '<img'>

Funky
               
               

               
            

Legacy_leo_x

  • Sr. Member
  • ****
  • Posts: 403
  • Karma: +0/-0
What's the point?
« Reply #33 on: February 07, 2013, 08:46:05 pm »


               From what I remember the virtual machine has a recursion level that is incremented when you call ExecuteScript.  If you called more than 7 nested ExecuteScripts it would error out.  All these share the same TMI counter.  

AssignCommand, DelayCommand, etc all create new 'run script' events that are added to the server's event queue and so they get executed on their own, at recursion level zero if that makes sense.

NWN server is definitely single-threaded nothing can run in paralell.
               
               

               


                     Modifié par pope_leo, 07 février 2013 - 08:48 .
                     
                  


            

Legacy_Highv Priest

  • Full Member
  • ***
  • Posts: 170
  • Karma: +0/-0
What's the point?
« Reply #34 on: February 07, 2013, 08:46:24 pm »


               Georg Zoeller said a lot of things >.>

I've created 2 engines in my programming classes, it was me and 3 others. I know -exactly- how my particular part of the engine works, but how they did their parts... Not so much. I wasn't particularly eager to commit it all to memory. Georg likely knows a lot, but some of it he probably only has a jist of the idea. I'm doubtful even he knows many of the things we've learned over time. For instance that icons can be hidden using a method you've prescribed, that small size creatures can equip large sized weapons by changing appearance from medium to small, or my personal favorite, that people can produce weird little centaur like things as a result of horse glitches with appearance.(you really wouldn't expect it since horses are THEMSELVES nothing but a part based appearance of the normal one...)

However other then my little quip, I found out that this is indeed the case '<img'> .

I performed a test to timestamp each triggered script which explained it does infact trigger at different times.(though you can only tell with TONS of scripts set to fire at the same time as the computer is likely performing them in microseconds and timestamp doesn't record that far).
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
What's the point?
« Reply #35 on: February 07, 2013, 10:23:39 pm »


               

pope_leo wrote...

From what I remember the virtual machine has a recursion level that is incremented when you call ExecuteScript. If you called more than 7 nested ExecuteScripts it would error out. All these share the same TMI counter.

AssignCommand, DelayCommand, etc all create new 'run script' events that are added to the server's event queue and so they get executed on their own, at recursion level zero if that makes sense.

NWN server is definitely single-threaded nothing can run in paralell.


The recursion level level is 0x100 or 256,   It applies to all recersive function calls not just scripts.    Extending it is a little more difficult then increasing the instruction count counter because its limit is based on the size of the buffer originally allocated for the storage of the return pointers.    
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
What's the point?
« Reply #36 on: February 07, 2013, 10:46:51 pm »


               

Highv Priest wrote...

Lightfoot8 wrote...

Highv Priest wrote...

It doesn't transfer ownership(at least for effects which are the only things that have "GetCreator" anyway). For instance if you use executescript on a PC from a module event. The effect applied is applied under the module and not the PC. The executescript as far as I can tell only sets the OBJECT_SELF to be the thing it's running on, but doesn't flag it as the owner of the script being run.


It does transfer ownership,   Even for effects.    If from a module event you execute a script on the PC and the script that is now running on the PC creates an effect, the PC will be the creator not the module.  


You must forgive me if I sound arrogant, but I know for certain that executescript does not change "GetEffectCreator" which is how I determine "ownership" of the script. Example =

if(GetLevelByclass(class_TYPE_ASSASSIN, oPC) >= 3)
        {
        ExecuteScript("bloodoath", oPC);
        }

This script is applied both onrest and when weapons are unequipped, because we give an AC bonus for dual weilding and using large weapons(not that uncommonly). Assassins on our server receive an AC bonus relative to int mod(learned observation of combat methods and effective ability to deflect oncoming attacks based on perceived patterns is the explanation as to why they are given an AC bonus) Both events are module defined. On the weapon unequip this check is put to remove the AC bonus for weapons being removed:

while(GetIsEffectValid(eRemove))
        {
            if(GetEffectSubType(eRemove) == SUBTYPE_EXTRAORDINARY)
            {
                if(GetEffectType(eRemove) == EFFECT_TYPE_AC_INCREASE)
                {
                    if(GetEffectDurationType(eRemove) == DURATION_TYPE_PERMANENT)
                    {
                    if(GetEffectCreator(eRemove) == oSelf) oSelf is the module here.
                    {
                        RemoveEffect(oPC,eRemove);
                    }
                    }
                }
            }
            eRemove = GetNextEffect(oPC);
        }
Now as you saw the executescript is being applied to the PC, which SHOULD transfer ownership of the effect to the PC, because the PC is defining, creating, and applying the effect. However it -doesn't-, the module is still considered the creator of the effect and between being stuck in exams and other problems I just decided to reapply the effect after weapon removal instead of figuring out what fool-proof method DOES transfer ownership. Although according to nwnlexicon(which is usually a pretty good resource) assigning an inner-include block of code with assigncommand does this, I couldn't be arsed to take the time testing it to find out until I get these real life problems out of the way.


Well it does not matter if you sound arrogant or not.  Execute script does transferr the ownership.   
As for your argument I only see the script getting ran on an object pointed to by the var oPC, I have now way to comfirm that it is a PC.   There is really not enough of the application of the effect for me to tell who is applying it or how it is applyed.   


To show that ownership does transfer  I  wrote two simple script. The first I placed in the OnEnter event for the first area.  It  is:   

void main()
{
  object oObj = GetFirstObjectInArea(OBJECT_SELF);
  while (GetIsObjectValid(oObj))
  {
    ExecuteScript("effect",oObj);
    oObj = GetNextObjectInArea(OBJECT_SELF);
  }
}

The effect script that it runs on every object in the area is: 

void main()
{
effect test = EffectCurse();
string Creator = ObjectToString(GetEffectCreator(test));
SendMessageToPC(GetFirstPC(),"Creator ="+Creator);
}

The output was as follows. 

[CHAT WINDOW TEXT] [Thu Feb 07 17:32:51] Creator =d
[CHAT WINDOW TEXT] [Thu Feb 07 17:32:51] Creator =a
[CHAT WINDOW TEXT] [Thu Feb 07 17:32:51] Creator =4
[CHAT WINDOW TEXT] [Thu Feb 07 17:32:51] Creator =3
[CHAT WINDOW TEXT] [Thu Feb 07 17:32:51] Creator =b
[CHAT WINDOW TEXT] [Thu Feb 07 17:32:51] Creator =7
[CHAT WINDOW TEXT] [Thu Feb 07 17:32:51] Creator =2
[CHAT WINDOW TEXT] [Thu Feb 07 17:32:51] Creator =7ffffffe
[CHAT WINDOW TEXT] [Thu Feb 07 17:32:51] Creator =c
[CHAT WINDOW TEXT] [Thu Feb 07 17:32:51] Creator =6
[CHAT WINDOW TEXT] [Thu Feb 07 17:32:51] Creator =8
[CHAT WINDOW TEXT] [Thu Feb 07 17:32:51] Creator =9
[CHAT WINDOW TEXT] [Thu Feb 07 17:32:51] Creator =5


As you can see every effect was created by a differant object.  

I am not shure what is causing the problem in your script.   I can only tell you that it is not a problem with executeScript not changing ownership.
               
               

               


                     Modifié par Lightfoot8, 07 février 2013 - 10:48 .
                     
                  


            

Legacy_ffbj

  • Hero Member
  • *****
  • Posts: 1097
  • Karma: +0/-0
What's the point?
« Reply #37 on: February 07, 2013, 11:26:52 pm »


               Tks meaglyn and F.S. D'oh and jahaha..it is supposed to be an and and that would be why I am getting that damn tmi. I have a dozen of these of various flavors, for different spawning and this was the only one to Tmi. I had always assumed the problem was elsewhere could not find it with a quick look and just learned a lesson, there. Good spotting meaglyn, exactly. as all the other ones that work have and. I know I am terrible at coding things so people can read them. No training. It's supposed to add up the levels of the PC's in the area and spawn monsters according to the total levels within a range, being 1 variable, and the most weighted, to create encounters.  Later I went to a more party centric method. Adding only party members hd in the area. 
Sorry to semi-highjack the thread.

Oh thought of a reaper strolling into town and everything, animals, people, etc.. would die/or save vrs.effect death, as the reaper approached them.  Spawned from Lightfoots effect idea.
Something like that has been done too death, (sorry), I suppose like the plague in WarCraft.  When all these PC's where just dropping over falling from the skies etc...That was amusing.  Of course probably not to those to whom it happened.

Btw he did say it the script ran on unequiped and rest so it's just missing that those definitions.  I think we can then assume that oPC refers to a PC.  
               
               

               


                     Modifié par ffbj, 08 février 2013 - 12:26 .
                     
                  


            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
What's the point?
« Reply #38 on: February 08, 2013, 01:10:51 am »


               

Highv Priest wrote...

My idea is to have 5-10 scripts that simply have ExecuteScript("highv_smart_ai", OBJECT_SELF). Yes I'm extremely vain and I put highv in the name of all my original scripts >.>. Although highv_smart_ai is being executed, it's being done so under the code block of "smart_ai_1".

My idea is to have "smart_ai_1", "smart_ai_2", "smart_ai_3", etc. All of these essentially running "highv_smart_ai" in an attempt to circumvent the TMI error being triggered from many AI triggering the same script.

As I said before and even few day ago to another guy. ExecuteScript shares the same code block and instruction limit. Thus you will notavoid TMI by this approach, to do that you would have to use some delay.

Anyway, using executescript function for AI is definitely good idea from customization reasons. The AI is called in several scripts and everytime someone wants to commit a change inside AI he have to rewrite all those scripts. If the AI was handled as a ExecuteScript, this problem would be eliminated entirely. But only one script is enough actually at the begining of the DetermineCombatRound. I wonder why I didnt thought about this, would be perfect feature for my community patch as Ive done many changes into the default AI.

Highv Priest wrote...

Is there a way I could determine
whether or not nwn is capable of executing scripts at the same time?

This is wrong. Scripts are executed instantly and the original script waits for them to being finished.

So if nwn doesn't execute scripts at
the same time, why would 40 very simple heartbeats cause massive lag
when 40 very slightly differently timed heartbeats would not.(the delay
was between .01 to .40 based on their objecttostring ID in relation to
the first).

This is hard to believe. Can you prove it? Sorry but Im not willing to test it myself, according that everything you've written so far turned to be incorrect and that you are base your knowledge on the results without debugging what cause that.

I can tell you for sure that if you spawn 50npcs at once, your heartbeat lag does not happen. Adding one or two lines of code, assuming this is not endless loop, cannot change this. BUT cast a fireball into this group of NPCs and your server might hang out for hours (at least on linux) due to the "cross-shout" issue I described in the threat about AI somewhere.
               
               

               


                     Modifié par ShaDoOoW, 08 février 2013 - 01:12 .
                     
                  


            

Baaleos

  • Administrator
  • Hero Member
  • *****
  • Posts: 1916
  • Karma: +0/-0
What's the point?
« Reply #39 on: February 08, 2013, 01:54:27 am »


               

So if nwn doesn't execute scripts at
the same time, why would 40 very simple heartbeats cause massive lag
when 40 very slightly differently timed heartbeats would not.(the delay
was between .01 to .40 based on their objecttostring ID in relation to
the first).

This isnt actually far off from what I have heard said on the legacy forums and from personal experience.

I've seen first hand that if you have for instance an AI Script - which is say - 400 lines long - or something like that

And then 5 NPC's start fighting - thats in effect 5x AI Scripts being triggered in combat state at sorta the same time.
Granted - the engine is single threaded, so each one has to finish its execution before the next one finishes.
But I remember once - I had some monsters that cast Summon Creature X or something like that, which caused my encounter of 5-6 monsters to become 12 - and then suddenly TMI frenzi.

The AI Script didnt suddenly become larger, it was just that there was more calls being made to the same script by more NPC's.
More memory/data was trying to be passed through the one script than the engine allowed.
I suppose technically - it might have allowed it to work - if half the mobs had 1 script being used for AI and the others had a differently named script being used.

Someone posted on the forums years ago explaining that the engine has a memory bandwidth limit of sorts -
That a certain amount of KB of data can only pass through a script at any one time - even if it is separate calls to that script.
I wont lie and say I understand it fully myself - but I have found that good ways to get away from the TMI error is to span the execution of large quantities of scripts with an incrementing integer changed to a float.

eg

for(int i =1;i<=5000;i++)
{
     DelayCommand(IntToFloat(i)*0.05,ExecuteScript("BLAHBLAH"));
}

Opposed to this - which might cause TMI in a vanilla setup

for(int i =1;i<=5000;i++)
{
     ExecuteScript("BLAHBLAH");
}


They are both doing sorta the same thing - except one is giving a second of dedicated execution time to the previous iteration of the script.
I will say that for this principal to actually work and be of use - the Script that is being executed, but be of significant size for this to provide any use.
Eg: If your script is tiny, and does execute and finish within a matter of miliseconds - then this wont provide benefit.
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
What's the point?
« Reply #40 on: February 08, 2013, 02:57:34 am »


               i dont think you can simulate this by that method baaleos

executecommand is instruction (or rather more than one instruction) that itself count to the TMI limit, with 5000iterations you would reach tmi with almost anything else

since nwn is single-threated, it means that no script can run at the same time (mean executed by game engine not within another script)
               
               

               


                     Modifié par ShaDoOoW, 08 février 2013 - 03:11 .
                     
                  


            

Legacy_Squatting Monk

  • Hero Member
  • *****
  • Posts: 776
  • Karma: +0/-0
What's the point?
« Reply #41 on: February 08, 2013, 03:20:04 am »


               And DelayCommand() will move the instruction to a new timeslice, regardless of the delay given, even if the delay is less than the current script needs to finish executing.
               
               

               


                     Modifié par Squatting Monk, 08 février 2013 - 03:20 .
                     
                  


            

Legacy_leo_x

  • Sr. Member
  • ****
  • Posts: 403
  • Karma: +0/-0
What's the point?
« Reply #42 on: February 08, 2013, 07:47:26 am »


               

Lightfoot8 wrote...
The recursion level level is 0x100 or 256,   It applies to all recersive function calls not just scripts.    Extending it is a little more difficult then increasing the instruction count counter because its limit is based on the size of the buffer originally allocated for the storage of the return pointers.    


I went back and double checked... there is a separate script execution recursion level that has a hard coded limit of 8.

Script a:

void main()
{
    object mod = GetModule();
    int recurse_lvl = GetLocalInt(mod, "RECURSION_LEVEL");
    SpeakString("Recursion Level: " + IntToString(recurse_lvl), TALKVOLUME_SHOUT);
    SetLocalInt(mod, "RECURSION_LEVEL", ++recurse_lvl);
    ExecuteScript("b", mod);
}

Script b:

void main()
{
    object mod = GetModule();
    int recurse_lvl = GetLocalInt(mod, "RECURSION_LEVEL");
    SpeakString("Recursion Level: " + IntToString(recurse_lvl), TALKVOLUME_SHOUT);
    SetLocalInt(mod, "RECURSION_LEVEL", ++recurse_lvl);
    ExecuteScript("a", mod);
}

The final print would be "Recursion Level: 7".  There will be no feedback if it throws an error.
               
               

               


                     Modifié par pope_leo, 08 février 2013 - 07:48 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
What's the point?
« Reply #43 on: February 08, 2013, 08:42:16 pm »


               

Highv Priest wrote...

Georg Zoeller said a lot of things >.>

I beg your WHAT? You expect us to take you on your word based on some ai work and some programming classes, and get testy when I don't, but then refuse to accept the HotU project lead as an authority? The only salient difference I can see between the two appeals to authority is that I've never known HIM to be wrong. Oh, that, and a metric crapton more experience with all things NWN. Give me a break with this stuff, already. '<img'>

Funky
               
               

               


                     Modifié par FunkySwerve, 08 février 2013 - 08:43 .
                     
                  


            

Legacy_Highv Priest

  • Full Member
  • ***
  • Posts: 170
  • Karma: +0/-0
What's the point?
« Reply #44 on: February 08, 2013, 10:06:06 pm »


               That message wasn't intended to appear condescending. It was a quip(a witty or funny observation or response usually made on the spur of the moment) intended to simply state some things in games can't be reliably predicted without adequate testing(such as horses performing exceptionally strange glitches, such as a human being walking inside the body of a horse while the tail is sticking out of his head). Often times these glitches arise because one of the programmers made a few short cuts to just get his end of the project completed.(and we often see this in scripting in nwn as well and many, many other games... Superman 64 anyone?) //END OF SECOND QUIP

My testing is indeed flawed in many ways. However I can assure you that the 40 heartbeats were not utilizing enough code to adequately cause lag on their own. It's quite literally only composed of 3 commands(the spawns have true seeing so no check of visibility was necessary). GetAttackTarget, ActionAttack, and GetNearestCreature. The GetNearestCreature is only defined once GetAttackTarget returns object invalid(and it's very rare they will have no attack target).

As for Lightfoot I actually have gained respect for you. I found the problem was non-existent. Evidently originally that while loop must of not have contained a check for GetEffectCreator. Apparently some time in the past I fixed this check, but not until after I had come to the conclusion that executescript was faulty. So in an ironic twist I had fixed the problem without realizing what the problem was.(most likely during my reorganizing days where I recompile inefficient scripts into better versions).

I appreciate you taking the time to prove me wrong, giving me the ambition to re-assess the original proof that had originally driven me to that conclusion.