• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Does my workaround work? Workaround because of a glitch related to timers. Most probably "TimeGetElapsed" function is the glitched one.

Status
Not open for further replies.
Level 6
Joined
Jul 12, 2021
Messages
97
Hello everyone. I have a very difficult question.
What I'm about to describe is part of a complex system I'm creating. Some of my triggers or code might look pointless, but I really need it to function the way I'm describing. This is because it's the only way that it will fit the system I'm creating.

Map description:
-I have a unit with an ability.
-Whenever the ability is used the trigger "Its this one attack" forces the player to press the key "Z". It also starts the timer "t4".
-Trigger "OSKEYPressZ" has the event: "Key 'Z' is pressed". This same trigger has the action "Execute the trigger 'ZPressed'".
-Trigger "ZPressed" uses the function "TimeGetElapsed". This function tells you how much time has passed since the specified timer started.
-Trigger "ZPressed" has an action that prints the time elapsed since timer "t4" started. The time elapsed is multiplied by 1000 before it is printed. Here is the custom script:
call QuestMessageBJ( GetPlayersAll(), bj_QUESTMESSAGE_UPDATED, R2S(TimerGetElapsed(udg_t4)*1000))

Here is where the glitch occurs. The printed message should always be the same but it isn't. Here is what is printed:
-If the elapsed time of the game is between 00:05 and 00:10, the printed message is: 99.993
-If the elapsed time of the game is between 00:10 and 00:35, the printed message is: 99.983
-If the elapsed time of the game is between 00:35 and 02:05, the printed message is: 99.945
-If the elapsed time of the game is between 02:05 and 04:15, the printed message is: 99.792
-If the elapsed time of the game is between 04:15 and 8:30, the printed message is: 99.487
-If the elapsed time of the game is between 08:30 and ??:??, the printed message is: 99.877
Format used: Minutes:Seconds

As you noticed, the printed message varies according to the elapsed time of the game. This makes no sense, therefore, I labeled it as a glitch. The printed message is consistent only if it is between the specified time. For example: If the elapsed time of the game is between 00:10 and 00:35, the printed number will always be 99.983

If you are wondering why do I care what the message printed is, it is because the trigger "ZPressed" does the following:
"If the elapsed time of the timer is 99.983 then do an action."
Since the TimeGetElapsed function gives me inconsistent numbers, then the action in the above line will only occur between the time frames 00:10 and 00:35. I need the action to be executed all of the times.

The workaround I propose is to play for around 10 hours and observe which numbers are printed in which time frames. Then create triggers that adjust to the time frames. Example:
If the elapsed time is between 00:10 and 00:35 then do the action if the TimeGetElapsed function returns 99.983 seconds. If the elapsed time is between 00:35 and 02:05 then do the action if the TimeGetElapsed function returns 99.945. And so on for about 10 hours.

The workaround works but I still wanted to consult with you all to know what do you think. Since timers are asynchronous I think my workaround will work even if playing online.

Other information:
-I'm planning to use this system on a 24 player map.
-I've tested this triggers in 2 different maps and the printed numbers were consistent.
-After you give me your opinion I'm planning on testing in different maps to see if the numbers remain consistent. I'm also planning to test it online with other players.




If you are going to test the map here is what you need to know:
-The trigger ZPressed executes an action when the TimerGetElapsed function returns 99.983. This should only work for the time frame 00:10 and 00:35. However, it works from the time frame 00:00 to 00:35, even though the numbers returned in the first 10 seconds aren't 99.983.
-Trigger "Its this one attack" runs when an attack order is given. I said above that it is run only when I use a specified ability because in the original map the button for Attack is removed. Because of this, the trigger only runs when the specified ability is used. This ability, of course, has the order "Attack".
-I omitted something in the explanation above for simplicity's sake. There's actually 2 numbers that can be printed in the each time frame, not just one. For the time frame 00:10 and 00:35 this number is 124.979. This second number shares the same consistency rules as the first number, and it is printed only about 4% of the times the ability is used.
-The ability of this test map is named "Attack" and it is inside a spell the Paladin has which is named "Spellbook".
 

Attachments

  • Isolated.w3m
    19.3 KB · Views: 4
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,892
Try making the timer run once every 0.01 seconds and have an integer counter that increases by 1 each interval. Then replace the TimeGetElapsed() function with a custom function that returns you the integer counter. You can link each new integer counter to each new timer using a Hashtable.

Also, Forcing the "Z" key has a delay which would probably need to be accounted for.
 
Last edited:
Level 6
Joined
Jul 12, 2021
Messages
97
Uncle, as always, you gave a great answer - and you did it really fast! I'm amazed not only by your solution, but by your full comprehension of the problem. I have to admit that I, myself, wasn't able to come up with that solution. Unfortunately it doesn't work because, as I mentioned before, my first post describes only a part of a system I'm creating. If my whole system was what I described in the first post it would really work like a charm. I'll need to explain another chunk of my system. Sorry for this, I tought it wouldn't be necessary.

There are 2 ways to use the ability I talked about in my first post:
"Way 1"-. Press the ability button and click on a point or a unit. This will immediately print a message with a number.
"Way 2"-. Hold shift and give several clicks on points. This will print a message with a number every time the unit is issued an order (not when it is given).

What I'm seeking in my entire system is to be able to detect when "Way 1" happens and when "Way 2" happens. The only way I found to do this is with the small system described in my first post.
If you use the ability as the "Way 1" describes, the printed numbers will be the ones described in my first post. Here they are in case you guys and gals don't remember:

-If the elapsed time of the game is between 00:05 and 00:10, the printed message is: 99.993
-If the elapsed time of the game is between 00:10 and 00:35, the printed message is: 99.983
-If the elapsed time of the game is between 00:35 and 02:05, the printed message is: 99.945
-If the elapsed time of the game is between 02:05 and 04:15, the printed message is: 99.792
-If the elapsed time of the game is between 04:15 and 8:30, the printed message is: 99.487
-If the elapsed time of the game is between 08:30 and ??:??, the printed message is: 99.877
Format used: Minutes:Seconds
If you use the ability as the "Way 2" describes, the printed numbers will be randomly choosen between the values 5.074 and 174.628. This means "Way 2" has 169,554 possible results (174628-5074). This numbers are independent, the time frame doesn't matter.
There is a 0.00000589782 chance (1/(174628-5074)) that the printed number will be the same as the number printed by the "Way 1".

The last line I wrote is incredibly important. Since there is no way to differentiate between "Way 1" and "Way 2"; this means there is a 0.00000589782 chance that "Way 2" will print the same number as "Way 1". This should not happen; this will cause "Way 2" to perform the action of "Way 1"; nevertheless I found it impossible to not make it happen.


If I use the method you described, "Way 1" will always print the number 10. "Way 2" will always print a number between 0 and 17. This means "Way 2" has 17 possible results (17-0). This numbers are independent, the time frame doesn't matter.
There is a 0.05882352941 chance (1/17) that the printed number by "Way 2" will be the same as the number printed by "Way 1".
1/17 is extremely big compared to (1/(174628-5074)). Because of this, that method doesn't work for my whole system.

I experimented with the method you described. The only way I found it useful was by using Real numbers instead of Integers and with a timer that runs once every 0.0001 seconds. Unfortunately, the same thing happened as when using the GetTimeElapsed function; "Way 1" printed numbers depending on the elapsed time of the game.



The delay of forcing the key "Z" is being accounted for.
You can test "Way 1" and "Way 2" in the map I attached on my first post.



So far, the workaround I described in my first post remains the best workaround. Here it is, in case you guys and gals don't remember:
The workaround I propose is to play for around 10 hours and observe which numbers are printed in which time frames. Then create triggers that adjust to the time frames. Example:
If the elapsed time is between 00:10 and 00:35 then do the action if the TimeGetElapsed function returns 99.983 seconds. If the elapsed time is between 00:35 and 02:05 then do the action if the TimeGetElapsed function returns 99.945. And so on for about 10 hours.




Random information:
I've been working in nothing else but this system for the past 9 months. At this point, I really want my system to work, I don't want my last 9 months of work to be for nothing. I'm willing to do the workaround I described even if it takes around 20 hours of manual routinary work.
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,892
You can detect when a user is holding Shift, so you should be able to know if they're Shift-queuing an ability or not.

Of course you need to be on 1.31+.
 
Level 6
Joined
Jul 12, 2021
Messages
97
Thank you for your answer.

You can really detect when someone is holding Shift. However, that doesn't work for my system. Because you'll only be able to detect when the order is given, not when it is taken. Here is the workflow:
1-. Click the ability.
2-. Hold Shift.
3-. Click on 5 points; this is what I refer when I say the order is given. This won't print any numbers with the GetTimeElapsed function.
4-. Release Shift.
5-. The 5 orders are taken, one by one; this is what I refer when I say the order is taken. Each time an order is taken a number will be printed with the GetTimeElapsed function.

The numbers printed with the GetTimeElapsed function are different if the unit takes an order as described in the above line (in my previous post I labeled this as "Way 2") and if you click the ability and then a point without using shift (in my previous post I labeled this as "Way 1").
 
Last edited:
Level 21
Joined
Jan 3, 2022
Messages
366
First of all, I hope you're familiar with this thread about timers: Issues with timer functions
Secondly, to help you test the map at 2x/4x/8x... speed: WGC Utility (Test maps at high game speed)
Bash:
#!/bin/sh

lua "wgc-launch.lua" \
--gameroot "X:/SteamLibrary/WC3-Reforged-Retail/Warcraft III/_retail_/" \
--gameexe "X:/SteamLibrary/WC3-Reforged-Retail/Warcraft III/_retail_/x86_64/Warcraft III.exe" \
--map 'C:/Users/User/Documents/Warcraft III/Maps/Development/hugopope-timerbug/Isolated.w3m' \
--slot slot0,team0,raceRandom,color2,health100,human \
--gameargs "-windowed -launch" \
--gamespeed 2
Thirdly, I bet the root cause is the exact same that was found in Petrosyanshina (a russian map, Петросянщина) where it was found that the periods of 0-tick attack speed were offset in Reforged. And the general timer-based time tracking was off by 10 seconds after ~50 minutes (your usual game clock hh:mm:ss using timers). The author "fixed" the map for Reforged by adding extra seconds, but this broke the previously working timers for 1.26 etc. versions.
Fourthly, the above issues is why I wanted to create a single custom timer, that'd tick exactly once every game simulation tick: Using game events as a clock source instead of timers?

Unrelated: ForceUI does not do what you think it does. Original thread with discussion, jassdoc: ForceUIKey, ForceUICancel. It'll bug for custom hotkey layouts. There're ways to disable/hide a specific unit's ability, if that's what you need.

🥲 I can reproduce it but it gets worse because TimerGetElapsed gets even more broken at custom game speeds...
What you need to do on the test map: click the green icon (spell book) and use the spell anywhere.
1x: 99.998 then 99.983 then 99.945
2x: 199.966 then 199.890
4x: 399.780 then 399.170
8x: 799.561 then 798.340
16x: 1000.000
 
Level 6
Joined
Jul 12, 2021
Messages
97

Hello, thank you for your post, and sorry for the late answer.

I just started experimenting with that method, seems really interesting.

I have a doubt though. Can this method work if I need the time elapsed to be really precise? For example, lets assume a unit gets attacked 50 times per second. This means there are 0.02 seconds between each attack. If I start measuring at a random period of time, this means it's extremely probable I will start measuring when the tick has started. Let's assume I start when there the time elapsed since the last attack is 0.01 seconds. This means the second tick will occur in 0.01 seconds, and not 0.02 seconds, and the third tick will ocure in 0.03 seconds and not 0.02 seconds. What can I do if I want to measure something precisely?

To solve the above I attempted to put two units next to each other. With triggers I disabled and enabled the attack of the unit which attacks will be measured. However, the time elapsed between enabling its attack and its first attack wasn't precise. It varies.


Here is an update to the workaround I proposed, in case someone is curious about it.

When I copy all the triggers, units, abilities, etc. to a new map, the workaround works. However, when I do it in my map, the workaround doesn't work. I noticed some triggers interfere with the printed numbers. For example, using the GUI action: "Cinematic - Transmission for Unit", causes the printed numbers to vary. There are other triggers that interfere with the printed numbers, but I am not aware of them.

I tried the workaround in my map, and when the elapsed time of the game is between 04:15 and 8:30, many times lot of different numbers were printed. I identified which triggers cause the numbers printed to misbehave and when I deleted them, the printed numbers behaved properly.

This means to make my workaround work I would have to delete some triggers, but I'm not willing to do it. I ahve to find a different method that fulfills the needs of my project or if there isn't, then I'll have to change the scope of my project.
 
Status
Not open for further replies.
Top