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

Legacy_Highv Priest

  • Full Member
  • ***
  • Posts: 170
  • Karma: +0/-0
What's the point?
« Reply #15 on: February 07, 2013, 04:45:56 pm »


               Even with 30 players actively moving around with multiple things running I've never had my server exceed 40% processor(though ocassionally it will super jump if a bunch of players are bouncing around eachother on walls,etc. which happens from pathfinding calls to the extreme degree). My AI doesn't overburden anything, but the TMI's will get thrown out anyway and I've actually done tests on this to find out. I used my poor processing laptop and spawned 200 of them in a single room, my computer never locked up despite the fact they are all trying to kill me and I'm spamming mantle scrolls and otherwise like crazy and this is with my laptop running BOTH the client and the server part instead of just a server which only deals with calculations.

I know you consider me some jackass, but lets pretend for a second I've taken programming classes and know SOMETHING about nwn(though certainly not everything). The TMI errors result purely from too many of the NPCs executing the same script without regards to the script being executed. I tested this out by having 200 NPCs execute one script that simply had them count to 100(using a while loop). One of them could do it easily, 40 of them still no issue, 100 of them still not a problem, but once I reached about 150 of them doing it the system immediately put out a TMI error.
               
               

               
            

Legacy_FunkySwerve

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


               

I know you consider me some jackass, but lets pretend for a second I've taken programming classes and know SOMETHING about nwn(though certainly not everything).

Ok, we can pretend that if you like. It doesn't change the fact that that the TMI limit is a per-script limit, or that nwn executes scripts serially, not in parallel.

The TMI errors result purely from too many of the NPCs executing the same script without regards to the script being executed. I tested this out by having 200 NPCs execute one script that simply had them count to 100(using a while loop). One of them could do it easily, 40 of them still no issue, 100 of them still not a problem, but once I reached about 150 of them doing it the system immediately put out a TMI error.


What that test indicates is that each execution is doing something that creates more work for later executions. Could be any number of things - anything that causes loops to iterate more.

Funky
               
               

               


                     Modifié par FunkySwerve, 07 février 2013 - 05:06 .
                     
                  


            

Legacy_ffbj

  • Hero Member
  • *****
  • Posts: 1097
  • Karma: +0/-0
What's the point?
« Reply #17 on: February 07, 2013, 05:47:46 pm »


               For the dead guys you can just put in a line at the top of the script if GetIsDead ClearAllActions TRUE return; in there on hb or combat rd end.
As far as TMI could be various causes. Clearly many npc's trying to do something at the same time can cause lag, but it is not necessarily a TMI problem. I mean to say you can get a TMI with just a single individual script that simply has Too Many Instructions. I am no expert in this area, but my scripting is sufficiently poor to have dealt with a number of TMI's over the years and it never involved just the number of npc's running the script. Although it does seem resonable to suppose with almost 200 individuals running a script you will have problems. Imo the game is just not designed to have that many individuals running scripts. I had bats spawning continuously once due to overlooking having the spawning script discontinue operation if no PC was in the area. So there were around 200 bats fluttering around, lagged like Heck, but no TMI.
Regarding the facility of execute script: I suppose that question has been answered in that it is extremely useful, for any number of occassions.
In reference to your not wanting to sound arrogant. I would not worry about that too much as almost everyone here does that, and certainly they do not appologise for it.

As far as the ai goes I have done quite a bit with that.  I think it is important to differentiate how the ai acts.  Thus they have cowardly, ambusher, archer, stealth, etc.. though the standard ai is woefully inadequate, the approach is valid. Thus I have some monsters that are more aggressive, more intelligent, etc.. so they act differently. Actually my more intelligent monsters are less aggressive, which is logical though not always.  So rather than try to the make the ai smart I merely give the more intelligent creatures more choices, which in some ways emulates intelligence as the player is less likely to be able to predict the behaviors of monsters or encounters with complete accuracy, thus making the ai seem intelligent.  If you catch my meaning, if you get my drift.
Cheers!
               
               

               


                     Modifié par ffbj, 07 février 2013 - 06:03 .
                     
                  


            

Legacy_FunkySwerve

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


               

ffbj wrote...

As far as TMI could be various causes.

No, it can't, not in the way he means. It's a very specific error put in by Bioware to halt execution of a script that exceeds 0x20000 instructions. It's an acronym for Too Many Instructions, and is meant as a last-resort block to prevent a runaway script from crashing a server. Acaos actually make a plugin for us that can lift the limit as high as 8 million, which you can find on the NWNX boards. It bears exactly zero relation to number of scripts executing at the same time, because nwn scripts cannot execute at the same time. The only thing in NWN that doesn't block is writes to bicfiles.

People tend to treat TMI as some kind of generic 'script overload' error. It isn't, though it's certainly possible to both overload your server to the point of crashing while firing TMIs.

Funky
               
               

               


                     Modifié par FunkySwerve, 07 février 2013 - 06:10 .
                     
                  


            

Legacy_ffbj

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


               I neant in the same way as you said this:
Could be any number of things - anything that causes loops to iterate more.

But I think what he was saying in this specific instance reagarding the 200 creatures was that a TMI was caused because there were too many creatures, while the script(s) that where running would not cause a TMI otherwise, and I can see that happening.
               
               

               


                     Modifié par ffbj, 07 février 2013 - 06:09 .
                     
                  


            

Legacy_FunkySwerve

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


               

ffbj wrote...

I neant in the same way as you said this:
Could be any number of things - anything that causes loops to iterate more.

Gotcha, thanks for the clarification.

Funky
               
               

               
            

Legacy_Highv Priest

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


               Is there a way I could determine whether or not nwn is capable of executing scripts at the same time? The reason I "know"(and I mean that in a non-narcissistic way) that nwn executes scripts at the same time develops from ONLY using OnHeartbeat for a spawn. A LONG time ago I decided "Why do all of these events need to be used on NPCs who have no use for them?", so I decided to simply give them there -very- simple instructions from a single heartbeat event. This was a POOR decision. The very simple heartbeat event(which literally was checking only if they had an attack target and if they didn't to attack) ACTUALLY caused lag! I then discovered if I were to delay the execution of said "heartbeat"(turned it into a pseudo-heartbeat at this point with each one executing at different times based on when they spawned) that the lag stopped and no issues resolved later.(I later decided to instead puppet them using the area, but that's besides the point)
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).
               
               

               
            

Legacy_FunkySwerve

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


               

ffbj wrote...
But I think what he was saying in this specific instance reagarding the 200 creatures was that a TMI was caused because there were too many creatures, while the script(s) that where running would not cause a TMI otherwise, and I can see that happening.


Sigh at dueling edits. '<img'> No, that was MY explanation. This is what he said, and it is not possible:

Highv Priest wrote...
If you've ever done heavy work on your
AI you'd know that TMI errors can be thrown out without infinite loops
as a result of too many AI executing the same script at the exact same
moment of time.


Funky
               
               

               
            

Legacy_ffbj

  • Hero Member
  • *****
  • Posts: 1097
  • Karma: +0/-0
What's the point?
« Reply #23 on: February 07, 2013, 06:20:00 pm »


               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:

#include "NW_I0_GENERIC"
#include "x3_inc_string"
void main()
{
int nCreature, nNumber;
string sCreature = "";
string sMessage = (StringToRGBString("\\n AMBUSH !! \\n",STRING_COLOR_RED));
object oPC = GetEnteringObject();
object oArea = GetArea(oPC);
if (!GetIsPC(oPC))
return;

if (GetLocalInt(oPC,"Safe") == 1)
return;

if (GetLocalInt(oPC,"Ran") > 2 +d4(1))
return;//script will only run 3 times,plus d4 default would be 4
int iHd = GetHitDice(oPC);
if (d100() < 60 + (iHd))//set between 50-75. Lower means fewer spawns.
return;

//if (GetDetectMode(oPC) == DETECT_MODE_PASSIVE)//not actively searching.
//return;

object oTarget = oPC;
float fDistance = 2.0 + (iHd/2);//higher level notice things futher away
location lWP = GetRandomLocation(oArea,oTarget,fDistance);
location lTarget = GetLocation(oTarget);

//Cycle through PCs in area

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

if (iHd < 10)
SetLocalInt(oPC,"Spawn",1);
else if (iHd < 20)
SetLocalInt(oPC,"Spawn",2);
else if (iHd < 30)
SetLocalInt(oPC,"Spawn",3);
else
SetLocalInt(oPC,"Spawn",4);

if (GetIsNight())
{
SetLocalInt(oPC,"Spawn", GetLocalInt(oPC,"Spawn")+1);
}

if ( GetStealthMode( oPC ) == STEALTH_MODE_ACTIVATED )
{
SetLocalInt(oPC,"Spawn", GetLocalInt(oPC,"Spawn")-1);
}

if ((GetLocalInt(oPC,"Spawn")== 1) && (GetIsSkillSuccessful(oPC, SKILL_LISTEN, 5)))//easy

{
SendMessageToPC(oPC, "You Hear Something!");
GiveXPToCreature(oPC, 25);

switch (d4())
{
case 1: sCreature = "thugcn"; break;//resref of creature
case 2: sCreature = "madcrow"; break;
case 3: sCreature = "townperson"; break;
case 4: sCreature = "monkbd"; break;
}
for (nNumber = 0; nNumber < d3(); nNumber++)
CreateObject(OBJECT_TYPE_CREATURE, sCreature, lWP, FALSE);

object oCreature = GetNearestObjectToLocation(OBJECT_TYPE_CREATURE, lWP);
float fDistance1 = GetDistanceBetweenLocations(lWP, lTarget);
string sDistance = FloatToString(fDistance1, 2,0);
DelayCommand (3.0,SendMessageToPC(oPC, " Some noise, over there! " + sDistance + " metres away."));
DelayCommand (6.0, TurnToFaceObject(oCreature, oPC));
}


if ((GetLocalInt(oPC,"Spawn")== 2) && (GetIsSkillSuccessful(oPC, SKILL_SPOT, 15)))//harder
{
SendMessageToPC(oPC, "You Spot Something!");
GiveXPToCreature(oPC, 50);
switch (d4())//should be tougher creatures below
{
case 1: sCreature = "thugcn"; break;//resref of creature
case 2: sCreature = "monkbd"; break;
case 3: sCreature = "townperson"; break;
case 4: sCreature = "rioter003"; break;
}


//Randomly generate the number of monsters//
for (nNumber = 0; nNumber < d4(); nNumber++)//change d4 for more
CreateObject(OBJECT_TYPE_CREATURE, sCreature, lWP, FALSE);
object oCreature = GetNearestObjectToLocation(OBJECT_TYPE_CREATURE, lWP);
float fDistance1 = GetDistanceBetweenLocations(lWP, lTarget);
string sDistance = FloatToString(fDistance1, 2,0);
DelayCommand (2.5,SendMessageToPC(oPC, " Something, over there! " + sDistance + " meters away."));
DelayCommand (5.0, TurnToFaceObject(oCreature, oPC));
}
else if ((GetStealthMode(oPC) == STEALTH_MODE_DISABLED) && (GetIsNight ()) && (GetLocalInt(oPC,"Ran") < 3))
{
CreateObject(OBJECT_TYPE_CREATURE, "robber", lWP, FALSE);
DelayCommand (2.0, FloatingTextStringOnCreature(sMessage, oPC, FALSE));

}


if ((GetLocalInt(oPC,"Spawn")==3) && (GetIsSkillSuccessful(oPC, SKILL_LISTEN, 20)))

{
SendMessageToPC(oPC, "A faint sound reaches you!");
GiveXPToCreature(oPC, 100);
switch (d6())
{
case 1: sCreature = "thugcn"; break;//resref of creature
case 2: sCreature = "rioter003"; break;
case 3: sCreature = "townperson"; break;
case 4: sCreature = "youth01"; break;
case 5: sCreature = "maddog"; break;
case 6: sCreature = "monkbd"; break;
}
for (nNumber = 0; nNumber < d6(); nNumber++)
CreateObject(OBJECT_TYPE_CREATURE, sCreature, lWP, FALSE);
object oCreature = GetNearestObjectToLocation(OBJECT_TYPE_CREATURE, lWP);
float fDistance1 = GetDistanceBetweenLocations(lWP, lTarget);
string sDistance = FloatToString(fDistance1, 2,0);
DelayCommand (1.5,SendMessageToPC(oPC, " Something is moving, over there! " + sDistance + " metres away."));
DelayCommand (4.0, TurnToFaceObject(oCreature, oPC));
}

if ((GetLocalInt(oPC,"Spawn") == 4) && (GetIsSkillSuccessful(oPC, SKILL_SPOT, 25)))//etc...

{
SendMessageToPC(oPC, "Your highly attuned senses are alerted!");
GiveXPToCreature(oPC, 150);
switch (d6())//should be tougher creatures
{
case 1: sCreature = "harpy"; break;//resref of creature
case 2: sCreature = "robber"; break;
case 3: sCreature = "townperson"; break;
case 4: sCreature = "skeletondart"; break;
case 5: sCreature = "maddog"; break;
case 6: sCreature = "skeletonrapier"; break;
}
for (nNumber = 0; nNumber < d4(); nNumber++)
CreateObject(OBJECT_TYPE_CREATURE, sCreature, lWP, FALSE);
object oCreature = GetNearestObjectToLocation(OBJECT_TYPE_CREATURE, lWP);
float fDistance1 = GetDistanceBetweenLocations(lWP, lTarget);
string sDistance = FloatToString(fDistance1, 2,0);
DelayCommand (1.0,SendMessageToPC(oPC, " Some movement, over there! " + sDistance + " metres away."));
DelayCommand (4.0, TurnToFaceObject(oCreature, oPC));
}

else if ((GetStealthMode(oPC) == STEALTH_MODE_DISABLED) && (GetIsNight ()) && (GetLocalInt(oPC,"Ran") < 3))
{
CreateObject(OBJECT_TYPE_CREATURE, "robber", lWP, FALSE);
DelayCommand (2.0, FloatingTextStringOnCreature(sMessage, oPC, FALSE));

}
else if ((GetStealthMode(oPC) == STEALTH_MODE_DISABLED) && (GetIsNight ()) && (GetLocalInt(oPC,"Ran") < 3))
{
CreateObject(OBJECT_TYPE_CREATURE, "harpy", lWP, FALSE);
DelayCommand (2.0, FloatingTextStringOnCreature(sMessage, oPC, FALSE));

}


SetLocalInt(oArea,"Ran", GetLocalInt(oArea,"Ran")+1);
DelayCommand (400.0/ d4(2), ExecuteScript("ranspslistenslum",oArea));
DelayCommand (300.0, DeleteLocalInt(oArea,"Ran"));

}


I have many similar scripts that work fine but this one seems to be cranky. Maybe I just have a bracket in the wrong place. Now that I look at it maybe these lines have an uneeded bracket:

{
if (oArea != GetArea(oPChp))
//{maybe no bracket needed here.
oPChp = GetNextPC();
}
               
               

               


                     Modifié par ffbj, 07 février 2013 - 06:24 .
                     
                  


            

Legacy_FunkySwerve

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


               

Highv Priest wrote...

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

Sure. You can read the forums and listen to people who know. Or ask people who have worked on the engine and know. Or you could use the Omnibus to look for posts by people who put the engine together and know. You could also devise an experiment designed to execute two scripts at the exact same instant to see for yourself, but clearly your experimentation thus far has only lead you astray, so you'd have to be a little more rigorous. That's not an indirect knock at you, by the way - just yesterday I managed to convince myself that the custom SetEffectCreator NWNX function was only returning a valid creator until the end of that script - because I wasn't rigorous enough in my testing, and didn't insert enough debug code to figure out what was really going on.

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).

Because the engine can only do so much in a given amount of time. Saying that scripts execute serially is not saying you can't jam up your server with too much code - it still takes time to execute, and some individual instructions can cause massive lag spikes, like object creation, because they require a lot of other things to happen. I won't pretend much expertise when it comes to computers, but I'm absolutely certain about this, and I have neither the time nor inclination to shoot down every anecdotal scrap of evidence you've accumulated in support of your erroneous conclusion. Virusman could probably give you a more technical explanation, if you're curious - he's dealt with the game clock, among many other things.

If it's any comfort, I made the same mistake, way back when, not understanding serial execution or blocking. It grants a lot of clarity once you do, and allows you to figure out more of what's really going on. I'll see if I can hunt down GZ on the omnibus talking about it, if I can do so quickly.

Funky
               
               

               
            

Legacy_Squatting Monk

  • Hero Member
  • *****
  • Posts: 776
  • Karma: +0/-0
What's the point?
« Reply #25 on: February 07, 2013, 06:40:08 pm »


               Please correct me if I'm wrong, Funky, but the exception to scripts running in parallel is when you call ExecuteScript(). The newly executed script gets run in the same timeslice and thus increases the instruction load on the parent script. Even then, this really isn't an exception to the rule, since the parent script is paused until the child finishes executing.
               
               

               
            

Legacy_FunkySwerve

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


               Here's GZ saying what I was saying about TMIs and load. He's a little more extreme, but bear in mind computers were less powerful back then:

It doesn't really matter, because you shouldn't create scripts that would cause
a TMI with either maximum setting, both will freeze the game for a visible
amount of time [/icon_smile.gif]
_________________
georg zoeller
senior
rules and systems monkey
[da | me]
My custom NWN
content
ceterum censeo ambulatiuncula esse delen


If that were still true, we wouldn't be getting away with our 8M limit. '<img'>

Here's another one that's tangentially relevant:

Makazasky
It seem to be a must to use Jasperre AI... but server
that i know that are using it keep getting TMI error... so i guess it also cause
lag, and the creature, even if they act more originally... dont seem to be more
smart
So ... considering im building a server not very focus on PvM... should
still use Jasperre AI?

FunkySwerve
We removed it after about a two years as it was just
too cumbersome with all the looping, and because we found the beholder ai (with
maxed magic int) to be more deadly in most cases. Jasperre's is still nice for
casters, but in the end we decided it just wasn't worth the
overhead.
Funky
_________________
Higher Ground
Higher
Ground Legendary Level System for levels 41-60

And one more:

Author
Message

DM_Spike
I have Jasperres AI scripts and have recently started
getting script errors in the window on the right.
They start with Too Many
Instrustions errors and are all creature script errors. They are random
creatures and nothing seems to trigger them.
It seems resetting the server
will settle them for a while, but there has been occasions when resetting from
inside the module, not hard resetting, makes them worse. Once they just scrolled
continuously, making the server unplayable.
Here is a link to the
screenshot.
Click
Here

666_SCARFACE_666
Same thing happens on my server from time to time, I
guess its to do with preformance after the server has been running for some
time.
_________________
Chaotic World Forums
Scarface's
Socketed Items V1.6

FunkySwerve
I've noticed the same phenomenon. It's seems to occur
most often on a few creatures, and I've been trying to deduce causes. On some
meleers it happens when their path to enemies is blocked (onblocked), but I've
seen a bunch of others that I cant yet explain, including some onperceived
wierdness from casters and meleers. What I've been wondering, but haven't had
time to check yet, is whether I have the same version of j_ai on all scripts.
The main version I use is 1.3, but I've seen a few that look different in
structure, enough so that they coul;d be an earlier version, and I could see
that playing havoc with includes etc. If you've had more than 1 version it might
be worth checking.
Best,
Funky
_________________
Higher Ground
Higher
Ground Legendary Level System for levels 41-60


Sorry, I couldn't find one of a dev explaining serial execution, though I did have a nice-if-overly-long trip down memory lane. '<img'>

If you don't want to take my word for it, ask vman or anothe NWNX dev.

Funky
               
               

               


                     Modifié par FunkySwerve, 07 février 2013 - 07:05 .
                     
                  


            

Legacy_FunkySwerve

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


               

Squatting Monk wrote...

Please correct me if I'm wrong, Funky, but the exception to scripts running in parallel is when you call ExecuteScript(). The newly executed script gets run in the same timeslice and thus increases the instruction load on the parent script. Even then, this really isn't an exception to the rule, since the parent script is paused until the child finishes executing.

That's another vman question. All I know is it falls under the same TMI limit as the calling script, so it's not really an exception as you say - the entire other script is executed, and then returns to the calling script. That's actually a pretty easy way to demonstrate serial execution (completion of ES before original continues), though it doesn't prove what the OP wants proved, since it could just be a behavior specific to ES.

Put another way, the scripts still execute serially rather than simultaneously, but more technical than that I can't get, sorry. '<img'>

Funky
               
               

               
            

Legacy_Lightfoot8

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


               

Squatting Monk wrote...

Please correct me if I'm wrong, Funky, but the exception to scripts running in parallel is when you call ExecuteScript(). The newly executed script gets run in the same timeslice and thus increases the instruction load on the parent script. Even then, this really isn't an exception to the rule, since the parent script is paused until the child finishes executing.


You are correct. As far as instruction count goes ExecuteScript() is the same as calling any other function within the script.   It executes the script and then returns to the calling script without reseting the instruction count.  

EDIT:  this is not really running in parallel,  It just runs the script as a subrutine, Using the same VM-stack that was being used by the calling script.    hence the reason the instruction count never gets cleared.  When a script is delayed a new VM-stack is created for the running of the script, clearing the instruction count back to 0.
               
               

               


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


            

Legacy_ffbj

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


               I get it about it not being possible. I was just trying to remember if I got a tmi when I had all those bats, and though tons of lag, no tmi. Though I did have a personal TMI reading through this thread.
               
               

               


                     Modifié par ffbj, 07 février 2013 - 07:28 .