• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Game crash during DPS test

Status
Not open for further replies.
Level 5
Joined
Jan 23, 2020
Messages
86
• I have a final wave on my tower defense map that calculates the DPS and Total Damage on a single unit for 2 minutes.

• The issue I am facing is that 95% of the time, players are crashing at some stage (seems random) in the 2 minute period.

• It does not happen at any other point of the game. I have also tried to make the unit spell immune.

• Is there anything here that could be causing an infinite loop, passing value limits, or other crash-related calculations?

• The crash is not a desync (kicked to menu) its a complete lockup (have to force close game)

Here are the DPS/Total Dmg calculation triggers:
  • Sheep Update DPS
    • Events
      • Time - Sheep_DPSTimer expires
    • Conditions
    • Actions
      • Custom script: local integer scoreIndex = 0
      • Custom script: local real currentValue = 0.0
      • Custom script: local string currentDPSValue = ""
      • Custom script: local integer pn = 0
      • -------- --------
      • Custom script: set udg_TotalSheepDamage = 0
      • -------- --------
      • Custom script: loop
      • Custom script: exitwhen pn >= 8
      • Custom script: set pn = pn + 1
      • Custom script: if IsPlayerInForce(Player(pn-1), udg_ActivePlayers) then
      • Custom script: set udg_TotalSheepDamage = udg_TotalSheepDamage + udg_PlayerDPS_TotalDamage[pn]
      • -------- --------
      • -------- Current DPS: --------
      • Custom script: set scoreIndex = 0
      • Custom script: set currentValue = udg_PlayerDPS[pn]
      • Custom script: loop
      • Custom script: exitwhen currentValue < 1000 or scoreIndex == 4
      • Custom script: set scoreIndex = scoreIndex + 1
      • Custom script: set currentValue = currentValue / 1000
      • Custom script: endloop
      • Custom script: set currentDPSValue = R2SW(currentValue,3,2) + udg_NumberFormatSufixArray[scoreIndex]
      • -------- --------
      • -------- Total Damage (Individual): --------
      • Custom script: set currentValue = udg_PlayerDPS_TotalDamage[pn]
      • Custom script: set scoreIndex = 0
      • Custom script: loop
      • Custom script: exitwhen currentValue < 1000 or scoreIndex == 4
      • Custom script: set scoreIndex = scoreIndex + 1
      • Custom script: set currentValue = currentValue / 1000
      • Custom script: endloop
      • -------- --------
      • -------- Leaderboard Setup --------
      • Custom script: set udg_TempPlayer = Player(pn-1)
      • Custom script: call LeaderboardSetPlayerItemLabelBJ(udg_TempPlayer, udg_Sheep_Leaderboard, SubString(GetPlayerName(udg_TempPlayer),10,16) + " " + currentDPSValue + " - (Total: " + R2SW(currentValue,3,2) + udg_NumberFormatSufixArray[scoreIndex] + ")" )
      • -------- --------
      • Custom script: endif
      • Custom script: endloop
      • -------- --------
      • -------- Overall Team Damage: --------
      • Custom script: set scoreIndex = 0
      • Custom script: loop
      • Custom script: exitwhen udg_TotalSheepDamage < 1000 or scoreIndex == 4
      • Custom script: set scoreIndex = scoreIndex + 1
      • Custom script: set udg_TotalSheepDamage = udg_TotalSheepDamage / 1000
      • Custom script: endloop
      • Custom script: set udg_OverallScoreSufix = udg_NumberFormatSufixArray[scoreIndex]
      • -------- --------
      • Custom script: call LeaderboardSetPlayerItemLabelBJ(Player(21), udg_Sheep_Leaderboard, ( "Total Team Damage: " + ( R2SW(udg_TotalSheepDamage, 3, 2) + udg_OverallScoreSufix ) ))

  • Sheep Damage Event
    • Events
      • Game - DamageEvent becomes Equal to 1.00
    • Conditions
      • (Unit-type of DamageEventTarget) Equal to Sheep lvl 66
    • Actions
      • Custom script: local player dmgPlayer = GetOwningPlayer(udg_DamageEventSource)
      • Custom script: local integer pn = GetConvertedPlayerId(dmgPlayer)
      • Custom script: local real dmg = udg_DamageEventAmount
      • -------- --------
      • -------- This Trigger runs whenever a unit takes damage. --------
      • -------- ============================= --------
      • -------- Use these Variables in your Conditions/Actions: --------
      • -------- --------
      • -------- DamageEventSource = The unit that dealt the damage. --------
      • -------- DamageEventTarget = The unit that was damaged. --------
      • -------- DamageEventAmount = The amount of damage dealt. --------
      • -------- ============================= --------
      • -------- --------
      • Custom script: set udg_PlayerDPS[pn] = udg_PlayerDPS[pn] + dmg
      • -------- --------
      • Custom script: if udg_PlayerDPS[pn] > udg_PlayerDPSB[pn] then
      • Custom script: set udg_PlayerDPSB[pn] = udg_PlayerDPS[pn]
      • Custom script: endif
      • Custom script: set udg_PlayerDPS_TotalDamage[pn] = udg_PlayerDPS_TotalDamage[pn] + dmg
      • Wait 1.00 seconds
      • Custom script: set udg_PlayerDPS[pn] = udg_PlayerDPS[pn] - dmg
      • Custom script: if udg_PlayerDPS[pn] < 0 then
      • Custom script: set udg_PlayerDPS[pn] = 0
      • Custom script: endif

  • function DamageWasDealt takes nothing returns nothing
    • set udg_DamageEventSource = GetEventDamageSource()
    • set udg_DamageEventTarget = BlzGetEventDamageTarget()
    • set udg_DamageEventAmount = GetEventDamage()
    • set udg_DamageEvent = 1.00
    • set udg_DamageEvent = 0.00
  • endfunction
  • function EnableDamageDetection takes nothing returns nothing
    • local trigger t = CreateTrigger()
    • call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DAMAGING)
    • call TriggerAddAction(t, function DamageWasDealt)
  • endfunction

  • Get Best DPS
    • Events
    • Conditions
    • Actions
      • Custom script: local integer scoreIndex = 0
      • Custom script: local real currentValue = 0.0
      • Custom script: local string currentDPSValue = ""
      • Custom script: local integer pn = 0
      • -------- --------
      • Custom script: loop
      • Custom script: exitwhen pn >= 8
      • Custom script: set pn = pn + 1
      • Custom script: if IsPlayerInForce(Player(pn-1), udg_ActivePlayers) then
      • -------- --------
      • -------- Best DPS: --------
      • Custom script: set scoreIndex = 0
      • Custom script: set currentValue = udg_PlayerDPSB[pn]
      • Custom script: loop
      • Custom script: exitwhen currentValue < 1000 or scoreIndex == 4
      • Custom script: set scoreIndex = scoreIndex + 1
      • Custom script: set currentValue = currentValue / 1000
      • Custom script: endloop
      • Custom script: set udg_BESTDPSstring[pn] = R2SW(currentValue,3,2) + udg_NumberFormatSufixArray[scoreIndex]
      • -------- --------
      • -------- Total DMG: --------
      • Custom script: set currentValue = udg_PlayerDPS_TotalDamage[pn]
      • Custom script: set scoreIndex = 0
      • Custom script: loop
      • Custom script: exitwhen currentValue < 1000 or scoreIndex == 4
      • Custom script: set scoreIndex = scoreIndex + 1
      • Custom script: set currentValue = currentValue / 1000
      • Custom script: endloop
      • Custom script: set udg_TOTALDMGstring[pn] = R2SW(currentValue,3,2) + udg_NumberFormatSufixArray[scoreIndex]
      • -------- --------
      • Custom script: endif
      • Custom script: endloop

  • Sheep End
    • Events
      • Time - sheepEndTimer expires
    • Conditions
    • Actions
      • Countdown Timer - Pause Sheep_DPSTimer
      • -------- --------
      • -------- Update dps one last time: --------
      • Trigger - Run Sheep Update DPS <gen> (ignoring conditions)
      • -------- --------
      • -------- Since Best DPS doesn't display on the Leaderboard until the very end we only need to calculate it once: --------
      • Trigger - Run Get Best DPS <gen> (ignoring conditions)
      • -------- --------
      • Wait 1.00 seconds
      • -------- --------
      • Set VariableSet PlayerWins = 1
      • -------- --------
      • Player Group - Pick every player in ActivePlayers and do (Actions)
        • Loop - Actions
          • Set VariableSet PN = (Player number of (Picked player))
          • Unit Group - Pick every unit in (Units of type Sheep lvl 66) and do (Actions)
            • Loop - Actions
              • Unit - Remove (Picked unit) from the game
          • -------- --------
          • Set VariableSet OldRank = PlayerRank[PN]
          • -------- --------
          • For each (Integer RankLoop) from 1 to RankTotal, do (Actions)
            • Loop - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • PlayerDPS_TotalDamage[PN] Greater than or equal to ((Real(RankValues[0])) + ((Real(RankValues[1])) x ((((Real(RankLoop)) x ((Real(RankLoop)) + 1.00)) / 2.00) - 1.00)))
                  • PlayerRank[PN] Less than RankLoop
                • Then - Actions
                  • Set VariableSet PlayerRank[PN] = RankLoop
                • Else - Actions
          • -------- --------
          • Set VariableSet TempPG = (Player group((Player(PN))))
          • -------- --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • PlayerRank[PN] Greater than OldRank
            • Then - Actions
              • Game - Display to TempPG for 50.00 seconds the text: (((Name of (Player(PN))) + achieved rank: ) + (|cffffff00 + (String(PlayerRank[PN]))))
            • Else - Actions
              • Game - Display to TempPG for 40.00 seconds the text: |cff00ff00No new ra...
          • -------- --------
          • Game - Display to TempPG for 50.00 seconds the text: (((Name of (Player(PN))) + time: ) + (|cffffff00 + (Game_Hours_String + (Game_Minutes_String + (Game_Minutes_String + Game_Seconds_String)))))
          • Game - Display to TempPG for 50.00 seconds the text: (((Name of (Player(PN))) + best DPS: ) + (|cffffff00 + (BESTDPSstring[PN] + |r)))
          • Game - Display to TempPG for 50.00 seconds the text: (((Name of (Player(PN))) + total Damage: ) + (|cffffff00 + TOTALDMGstring[PN]))
          • Game - Display to TempPG for 50.00 seconds the text: (((Name of (Player(PN))) + selected difficulty:) + (|cffffff00 + MBDiffString))
          • -------- --------
          • Game - Display to TempPG for 15.00 seconds the text:
          • Game - Display to TempPG for 35.00 seconds the text: |cff00ff00Player st...
          • Game - Display to TempPG for 15.00 seconds the text:
          • Game - Display to TempPG for 50.00 seconds the text: |cffffff00You can i...
          • -------- --------
          • Custom script: call DestroyForce (udg_TempPG)
      • Trigger - Run Autosave <gen> (ignoring conditions)
      • -------- --------
      • -------- Reset the players names before defeating them (Should fix the scoreboard at least in this case) --------
      • Player Group - Pick every player in ActivePlayers and do (Actions)
        • Loop - Actions
          • Player - Set name of (Picked player) to Player_OldName[(Player number of (Picked player))]
 
Last edited:
I think that the "Wait" in the "SheepDamageEvent" looks real sus.
I think you're not allowed to do that.
If you have TimerUtils you can "bind" an integer to a timer so you can get it from the expired timer, that way, you can keep track of the "pn", get it from the expired timer.

Edit: You also need to keep track of the dmg, so there are 2 variables to keep track of... My suggestion doesn't work without modifications
 
Level 5
Joined
Jan 23, 2020
Messages
86
I think that the "Wait" in the "SheepDamageEvent" looks real sus.
I think you're not allowed to do that.
If you have TimerUtils you can "bind" an integer to a timer so you can get it from the expired timer, that way, you can keep track of the "pn", get it from the expired timer.

Edit: You also need to keep track of the dmg, so there are 2 variables to keep track of... My suggestion doesn't work without modifications

I don't have the knowledge to implement that, this system was created by someone else. Is there a way I can achieve the above without using TimerUtils?

Or could you show me how to implement TimerUtils to these triggers?
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,565
You can avoid using TimerUtils and use the system I attached. It's a GUI friendly timer system, you just need to figure out how to use the Custom script for each function it provides. There's instructions in the Setup trigger and examples for every single one. Don't forget to disable the example triggers so that they don't interfere with your map. You can delete them and their variables if you'd like (or better yet just disable them and delete the variables).

In this case you'd use this action in your DPS trigger instead of doing the Wait stuff:
  • Custom script: call TS_StartIntReal(pn, dmg, 1.00, false, 0, gg_trg_YourTriggerName)

Then have a trigger called YourTriggerName which will adjust the player's dps using this action:
  • Set Variable PlayerDPS[TS_Integer] = PlayerDPS[TS_Integer] - TS_Real

So the TS_StartIntReal function starts a timer which will expire in X seconds. It also saves the provided integer and real in a Hashtable, linking them to the timer. Once the timer expires it will run the YourTriggerName trigger while also giving you access to the integer/real that you saved, in the form of global variables TS_Integer and TS_Real. So it's quite similar to TimerUtils but is GUI focused so that you don't have to touch any code. Some other important things to note, the information saved to the timer can't be changed/lost so you don't have to worry about anything like that. Also, unlike standard GUI timers, this system creates a brand new timer every single time you use one of it's functions. So it's not like you're starting the same timer over and over again, it's a brand new timer each time that will run independently from any other timers. That being said, if you wanted the "same timer" functionality then you could use the key system (read more about it in the Setup trigger). This can come in handy for effects that shouldn't "stack", for example if you wanted to mimic the Acid Bomb ability. Multiple Acid Bombs on the same target don't stack their damage/duration, instead the most recent cast replaces the last. This is what a Key allows you to mimic.

In this case TS_Integer is equal to pn and TS_Real is equal to dmg. Obviously you can change the trigger's name, just make sure that they match and that spaces in the trigger's name are written as _ in the custom script.

That aside, didn't your old map use that same trigger without any crashing issues? It had that Wait as well.

Also, did you change how you manage Total Damage now? I see that it's calculated in the Get Best DPS trigger which happens AFTER the Sheep round is over, not during. Did you remove it from the Leaderboard or something?
 

Attachments

  • GUI Timer System 4.w3m
    26.8 KB · Views: 10
Last edited:
Level 5
Joined
Jan 23, 2020
Messages
86
@Uncle
That aside, didn't your old map use that same trigger without any crashing issues? It had that Wait as well.
It did, not 100% sure if it's the cause, will test and report back
Also, did you change how you manage Total Damage now? I see that it's calculated in the Get Best DPS trigger which happens AFTER the Sheep round is over, not during. Did you remove it from the Leaderboard or something?
I only moved both Strings (BESTDPSstring[pn] and TOTALDMGstring[pn]) to the Get best, as its just for the end stat massages. Or are you referring to something else?
 
Status
Not open for further replies.
Top