Well, the TriggerEvaluate (or something) function will return the return value of your trigger function; so if you plan on using it, make sure, it will return the right thing.
One last question and then (I think) I got it. Is there a way to have more than one initialization function per custom script page? It seems silly that I have to open up a different page for every function I want to run at map init.
Well, an argument against it might be, that we have a trigger event triggering every .0625 all the time, regardless of a spell instance currently being in use or not.
Whoops, I forgot to mention, the periodic timer is only created whenever a spell instance occurs. Once the spell instance is complete, it is destroyed. So yeah, there will be 1 timer for every spell instance, just like how it was in vJass last time.
Quote:
Also for few spell instances running like 2 or 3 trigger events, followed by a loop containing waits might still be more efficient than 0.0625 events triggered per second (assuming triggering 1 event takes more time than 1 wait + 1 loop step)
This actually gives me an idea for how we can do a comparison. We create 2 functions that count from 1 to 10000 with 0.0625 second intervals.
First function uses periodic timed event. (I'll code this part)
Second function uses for loop and wait. (You code this part)
Method:
We do a Tic of current game time.
Use a loop to run 10000 instances of the first function.
Toc when all 10000 instances complete their iterations.
We do the same thing for the second function, then we compare the run time.
No, there is not, unfortuantely.
There is a AIGetTime() native that will return the same value the game timer in the bottom left shows you (in seconds). But because the game is effectively frozen when the game is running through the script, it cannot be used as a benchmark.
No, there is not, unfortuantely. There is a AIGetTime() native that will return the same value the game timer in the bottom left shows you (in seconds). But because the game is effectively frozen when the game is running through the script, it cannot be used as a benchmark.
So we need to use the method gex used for his jass speed test; do enough stuff so the game is busy at least 30 seconds and use a stopwatch :D
@Kueken531: Go
This actually gives me an idea for how we can do a comparison. We create 2 functions that count from 1 to 10000 with 0.0625 second intervals.
First function uses periodic timed event. (I'll code this part)
Second function uses for loop and wait. (You code this part)
Method:
We do a Tic of current game time.
Use a loop to run 10000 instances of the first function.
Toc when all 10000 instances complete their iterations.
We do the same thing for the second function, then we compare the run time.
What do you think?
I thought of something similar. However to compare the results we should definitely put both methods in the same map and run it on the same machine (best would be multiple ones to verify results)
€ well, its not that easy. In wc3 it was pretty easy to make the game lag like 30 seconds by using 0 timers or trigger executes to bypass the script micro operations limit per thread; however sc2 has a maximum thread limit as well, so before I can make the game lag more than 1 or 2 seconds, I hit either one of them, it seems.
So we need to use the method gex used for his jass speed test; do enough stuff so the game is busy at least 30 seconds and use a stopwatch :D
Not sure what the method is for what you refer to here >_>
My bad, didn't read properly: "Do enough stuff so the game is busy at least 30 seconds". Then use a stopwatch to time how long it takes to complete the actions with a stopwatch?
Quote:
I thought of something similar. However to compare the results we should definitely put both methods in the same map and run it on the same machine (best would be multiple ones to verify results)
My thoughts exactly. I think sequence will matter as well. If method 1 is called before method 2, or method 2 called before method 1, there might be a difference. Might be a good idea to run a best or 10 as well, just to ensure the results aren't biased.
Quote:
€ well, its not that easy. In wc3 it was pretty easy to make the game lag like 30 seconds by using 0 timers or trigger executes to bypass the script micro operations limit per thread; however sc2 has a maximum thread limit as well, so before I can make the game lag more than 1 or 2 seconds, I hit either one of them, it seems.
I wonder what that thread limit is, and how we might be able to work our way around them. I recall someone around the forum mentioned something about trigger events not firing in their map.. wonder if its caused by the thread limit being reached.
Some more testing showed, the thread limit is 1023 threads. I was able to start 1023 empty triggers simultaneously without error message, 1024 shows the thread limit reached message once, each higher number shows it multiple times (maybe there is 1 main thread running, so the overall thread limit would be 1024)
Used code:
constintRUNS=1023;boolTrigger1(boola,boolb){returntrue;}triggert1=TriggerCreate("Trigger1");boolTestFunction(boola,boolb){inti=0;Print("Tests an empty trigger, "+IntToString(RUNS)+" Runs.");Print("Test started");while(i<RUNS){TriggerEvaluate(t1);i+=1;}Print("Test finished");returntrue;}
I will investigate this further.
€ testing an empty loop using this code:
constintRUNS2=999990;boolTestFunction2(boola,boolb){inti=0;Print("Test2 started");Print("Test an empty loop, "+IntToString(RUNS2)+" Runs.");while(i<RUNS2){i+=1;}Print("Test2 finished");returntrue;}
determined, that the execution time limit is reached at roughly 1 million runs. 999900 runs doesn't give an error message, 999990 does; so my guess is the limit is reached at 1 million actions (like 1 million function calls or variable sets; the rest of the function fills the remaining time to reach the limit).
€
Combining those 2 results, I started a trigger 1023 times, which started an empty loop 999900 times, I was able to freeze my SC2 for about 2 minutes without popping any error message :D.
Does anyone know how to write functions inside of structs? It keeps giving me an error whenever I try.
Also does anyone know what the syntax for referring to the object in question inside of a struct is? (like "this." in jass). What I mean is, when I call a function inside a struct using a certain object, how do I refer to the object I called with?
Hm.. kays, anyway, heres my part. I'm not sure whether I did the tic and toc right. Since it's using player exclusive game time, I'm not sure if it'll count correctly if fps drops to 0 for a good 10 seconds or more.
I've set the loop limit to 200 for now. Unfortunately I couldn't find a way to get all the threads to run at once, the game engine seems to go into a deadlock (even when theres only 2 periodic events, it still hangs :/) if I don't put a wait function inside my while loop that creates the periodic event triggers. Do take a look, if theres any mistakes I probably overlooked it cos I'm half asleep at the moment lol.
It is defined behavior that executing a Trigger will first run the trigger (until waits appear anywhere in it) before it will return to the calling trigger.
So uh.. what happens if I'm not executing the trigger, but creating a new one with each loop?
Code used, complete version in the map in the last post:
//VARIABLESconstintc_loopLimit=100;//Just change this number to testintg_instanceCounter=0;////SUPPORT//Find trigger index in data tablestringDTGetTriggerKey(triggert){inti=1;while(t!=DTGetTrigger(DTName(i))){i+=1;}returnDTName(i);}//Retrieves a new key for the spell instancestringnewKey(intplayer){returnf2s(libNtve_gf_GamePlayTime(player),4);}////MAIN TRIGGER FUNCTIONS//Method A uses timer to count up to c_loopLimitboolMethodA(boola,boolb){//Variablesstringkey=DTGetTriggerKey(TriggerGetCurrent());//Retrieve keyinti=DTGetInt(key+"i");//Retrieve count//Actionsi+=1;//If limit, increment instance completionif(i==c_loopLimit){g_instanceCounter+=1;//Increment to indicate instance completionTriggerDestroy(TriggerGetCurrent());//Destroy trigger//Remove values from data tablesDTRemove(key);DTRemove(key+"i");}else{DTSetInt(key+"i",i);}//Toc if all instances completeif(g_instanceCounter==c_loopLimit){toc();}returntrue;}//Method A Launcher, Press A keyboolLaunchA(boola,boolb){//Variablesinti=0;strings;//Recycled string variabletriggert;//Recycled trigger variable//Actions - Prevent Multiple executionsTriggerDestroy(TriggerGetCurrent());//Destroy the launchertic();while(i<c_loopLimit){t=TriggerCreate("MethodA");TriggerAddEventTimePeriodic(t,c_tPeriod,0);s=newKey(1);//Assign unique keyDTSetTrigger(s,t);//Save trigger to data tableDTSetInt(s+"i",0);//Save int to data tableWait(c_tPeriod,0);//Code hangs without this =_= No idea why, Deadlock?i+=1;}tDebug("All instances launched");returntrue;}//voidInitSlider(){triggert=TriggerCreate("LaunchA");TriggerAddEventKeyPressed(t,-1,c_keyA,true,c_keyModifierStateIgnore,c_keyModifierStateIgnore,c_keyModifierStateIgnore);}
@Kueken531: Go
I tried 1000 instances which count to 1000 yesterday, my sc2 locked for more than 5 minutes.. lol. Probably because there were roughly 20x1000 trigger events firing during the maximum period of load. As opposed to only 1000 firing and sitting there.
I won't jump to conclusions, but based on theory, looks like loops are the more efficient way to go, put aside the possibility of 1024 threads running at once. What I do wonder though, is in the scenario where there are no waits, what's going to happen?
1000 players cast the spell at the same split second. One thread is created for each one. They all occur in parallel? Or will the first spellcaster's spell complete before the second and the third and so on?
What about if a periodic trigger is used? How would it affect this?
I imagine whats actually happens with the method I used is that there will be 1000 periodic event triggers sitting there, creating and destroying threads at a very fast rate, thus the thread limit should theoretically never be reached. The downside of course would be performance loss due to the volley of events firing. Still wondering how we can draw a conclusion from all this @_@ well at least we've found out what the thread limits and loop limits are :D
Edit: Hmm.. think I'll attempt an empty trigger test as well. Could use trigger evaluation count to determine whether or not to destroy it.
Of course this isn't how it internally REALLY works, but that's the order of execution. Triggers are called after each other. Each trigger function runs uninterupted until it finds a wait or calls a function by itself. After that this function sleeps (or ends) and the next trigger function starts running. As soon as the sleep time for the first function ends the game frees some time to execute the next statements in the function until another sleep has been reached.
PS: Just a disclaimer. I'm theorycrafting a little bit here. I can only know as much about Sc2's triggering as I can read from observations, tests, debugging and how Trigger-action systems are almost always constructed (in fact I'm about to build one myself ^.^).
So everything I'm blabbling is probably right, but I can't guaranee it :)
Well, the TriggerEvaluate (or something) function will return the return value of your trigger function; so if you plan on using it, make sure, it will return the right thing.
Ah I see, ty
One last question and then (I think) I got it. Is there a way to have more than one initialization function per custom script page? It seems silly that I have to open up a different page for every function I want to run at map init.
Whoops, I forgot to mention, the periodic timer is only created whenever a spell instance occurs. Once the spell instance is complete, it is destroyed. So yeah, there will be 1 timer for every spell instance, just like how it was in vJass last time.
This actually gives me an idea for how we can do a comparison. We create 2 functions that count from 1 to 10000 with 0.0625 second intervals.
Method:
We do the same thing for the second function, then we compare the run time.
What do you think?
I do believe this is a question for s3rius :P
No, there is not, unfortuantely. There is a AIGetTime() native that will return the same value the game timer in the bottom left shows you (in seconds). But because the game is effectively frozen when the game is running through the script, it cannot be used as a benchmark.
So we need to use the method gex used for his jass speed test; do enough stuff so the game is busy at least 30 seconds and use a stopwatch :D
I thought of something similar. However to compare the results we should definitely put both methods in the same map and run it on the same machine (best would be multiple ones to verify results)
€ well, its not that easy. In wc3 it was pretty easy to make the game lag like 30 seconds by using 0 timers or trigger executes to bypass the script micro operations limit per thread; however sc2 has a maximum thread limit as well, so before I can make the game lag more than 1 or 2 seconds, I hit either one of them, it seems.
Not sure what the method is for what you refer to here >_>My bad, didn't read properly: "Do enough stuff so the game is busy at least 30 seconds". Then use a stopwatch to time how long it takes to complete the actions with a stopwatch?My thoughts exactly. I think sequence will matter as well. If method 1 is called before method 2, or method 2 called before method 1, there might be a difference. Might be a good idea to run a best or 10 as well, just to ensure the results aren't biased.
I wonder what that thread limit is, and how we might be able to work our way around them. I recall someone around the forum mentioned something about trigger events not firing in their map.. wonder if its caused by the thread limit being reached.
Some more testing showed, the thread limit is 1023 threads. I was able to start 1023 empty triggers simultaneously without error message, 1024 shows the thread limit reached message once, each higher number shows it multiple times (maybe there is 1 main thread running, so the overall thread limit would be 1024)
Used code:
I will investigate this further.
€ testing an empty loop using this code:
determined, that the execution time limit is reached at roughly 1 million runs. 999900 runs doesn't give an error message, 999990 does; so my guess is the limit is reached at 1 million actions (like 1 million function calls or variable sets; the rest of the function fills the remaining time to reach the limit).
€
Combining those 2 results, I started a trigger 1023 times, which started an empty loop 999900 times, I was able to freeze my SC2 for about 2 minutes without popping any error message :D.
Does anyone know how to write functions inside of structs? It keeps giving me an error whenever I try.
Also does anyone know what the syntax for referring to the object in question inside of a struct is? (like "this." in jass). What I mean is, when I call a function inside a struct using a certain object, how do I refer to the object I called with?
Hm.. kays, anyway, heres my part. I'm not sure whether I did the tic and toc right. Since it's using player exclusive game time, I'm not sure if it'll count correctly if fps drops to 0 for a good 10 seconds or more.
I've set the loop limit to 200 for now. Unfortunately I couldn't find a way to get all the threads to run at once, the game engine seems to go into a deadlock (even when theres only 2 periodic events, it still hangs :/) if I don't put a wait function inside my while loop that creates the periodic event triggers. Do take a look, if theres any mistakes I probably overlooked it cos I'm half asleep at the moment lol.
@Raven0: Go
Galaxy doesn't support OOP unfortunately. So you can't have functions inside structs.
@Kueken531: Go
Remember that you're calling a loop which is running in it's own thread? :D There's your 1024'th thread :p
@FuzzYD: Go
It is defined behavior that executing a Trigger will first run the trigger (until waits appear anywhere in it) before it will return to the calling trigger.
This code (all syntax errors are copyrighted by me) will basically run like this:
Galaxy doesn't support OOP unfortunately. So you can't have functions inside structs.
WHAAUUUHHHHHH????
@s3rius: Go
So uh.. what happens if I'm not executing the trigger, but creating a new one with each loop?
Code used, complete version in the map in the last post:
@Kueken531: Go I tried 1000 instances which count to 1000 yesterday, my sc2 locked for more than 5 minutes.. lol. Probably because there were roughly 20x1000 trigger events firing during the maximum period of load. As opposed to only 1000 firing and sitting there.
I won't jump to conclusions, but based on theory, looks like loops are the more efficient way to go, put aside the possibility of 1024 threads running at once. What I do wonder though, is in the scenario where there are no waits, what's going to happen?
1000 players cast the spell at the same split second. One thread is created for each one. They all occur in parallel? Or will the first spellcaster's spell complete before the second and the third and so on?
What about if a periodic trigger is used? How would it affect this?
I imagine whats actually happens with the method I used is that there will be 1000 periodic event triggers sitting there, creating and destroying threads at a very fast rate, thus the thread limit should theoretically never be reached. The downside of course would be performance loss due to the volley of events firing. Still wondering how we can draw a conclusion from all this @_@ well at least we've found out what the thread limits and loop limits are :D
Edit: Hmm.. think I'll attempt an empty trigger test as well. Could use trigger evaluation count to determine whether or not to destroy it.
Things cannot happen "at once". They always happen in quick succession.
Let's say we have following functions:
Now both are created as triggers and called right after each other.
This is how it'll be run in the end:
Of course this isn't how it internally REALLY works, but that's the order of execution. Triggers are called after each other. Each trigger function runs uninterupted until it finds a wait or calls a function by itself. After that this function sleeps (or ends) and the next trigger function starts running. As soon as the sleep time for the first function ends the game frees some time to execute the next statements in the function until another sleep has been reached.
PS: Just a disclaimer. I'm theorycrafting a little bit here. I can only know as much about Sc2's triggering as I can read from observations, tests, debugging and how Trigger-action systems are almost always constructed (in fact I'm about to build one myself ^.^).
So everything I'm blabbling is probably right, but I can't guaranee it :)