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

[AI] SuicideOnPlayer crashes the game on Reforged - only on some maps

Macielos

Hosted Project: W3E
Level 23
Joined
Jul 9, 2010
Messages
396
Hey, here's a problem with AI on Reforged:

  • AI script calls SuicideOnPlayer()
  • It prepares an attack wave
  • Debug shows the attack wave is sent and SuicideOnPlayer() is called - but no units from its base move
  • After a few seconds the game crashes

What I determined so far:
  • It occurs on Reforged only - but on maps created both on Reforged and 1.31. On 1.31 it doesn't occur.
  • It seems to be map-related - so far it occured on two maps only, both are quite big, the same AI launched on a test map works. It looks like on some maps AI can't find the enemy buildings to attack
  • it's not specific for a single AI - during testing I killed the AI base before it sent an attack, but then the first attack of a second base also caused the crash
  • It happens with SuicideOnPlayer(), SuicideOnPoint() works

Any ideas? I'm pretty much stuck on this.

I'm enclosing an example AI with this problem (although AI seems pretty standard). As for the map - Alteraci Chapter from Exodus: The Violet Gate (the campaign file is not protected).

I have some modifications in common.ai, but mostly extra functions, constants and some sleep calls added to avoid infinite loops.
 

Attachments

  • OgrePeach.ai
    3.9 KB · Views: 7

Macielos

Hosted Project: W3E
Level 23
Joined
Jul 9, 2010
Messages
396
Okay, apparently the map size seems to be the issue. I started cutting the map until the AI starts working. I replaced AI with the simplest one, I removed all other AIs, I removed all custom units, I left the player one building only... but the crash continued to happen.

Then I downscaled the map from 256x192 to 160x192. And it fucking fixed the issue.

Seriously, fuck Reforged.

EDIT: 224x192 also works.

I wonder if this can be fixed in some other way than by cutting the map. Is there some game constant or something else that can be changed? I doubt I'm the first one with this issue.
 

Attachments

  • 07yBrokenAi224.w3x
    724.4 KB · Views: 2
  • 07yBrokenAi256.w3x
    764.9 KB · Views: 2
Last edited:
Level 19
Joined
Apr 20, 2014
Messages
616
Hi, I had the same issue on Reforged. I haven't tested it on older patches though.

In my case, the problem isn't the map size itself but rather the pathing. It seems to crash when the AI starts calculating its path.
In my test, a completely blank map worked fine. However, when I added large, irregularly shaped path blockers, it crashed.

You might be able to keep your map size by placing bases closer together or by creating easier roads?

(Here my old thread about it: JASS Campaign AI - pathing problem / too long distance)
 

Macielos

Hosted Project: W3E
Level 23
Joined
Jul 9, 2010
Messages
396
Thanks for the trail. That was my suspicion too. However, to verify it on my test maps I used path blockers to cut off most part of the map, and left just a small part surrounding my base and the enemy base, and the problem still occured. And when I reduced map size, I only cut off far edges. Unless this pathfinding algorithm is stupid and checks unwalkable areas too, but that would be weird. I guess it's A-star or some other standard pathfinding algorithm.

And still, the fact that it works perfectly on 1.31...

On a second map where I had this issue, a workaround was to use SuicideOnPoint with the location of townhalls rather than SuicideOnPlayer.

Here's the entire walkable area. Unless there's a pathfinding hole I didn't notice...

1742659339929.png


EDIT: Okay, removing all pathblockers from the map also made it work...

EDIT2: After some more testing: shrinking the map from 256 to 224 seems to fix the issue in all cases, without removing any pathblockers (enemy base was put at the beginning of the arrow and player base at the end):
1742669375456.png

The attackers were stopping once in a while, but in all cases they found a path and followed it. And it never crashed the game, which for width 256 happened every time.
 

Attachments

  • 07yBrokenAi256Empty.w3x
    645 KB · Views: 2
Last edited:

Macielos

Hosted Project: W3E
Level 23
Joined
Jul 9, 2010
Messages
396
I may have another solution. I replaced usage with SuicideOnPlayer() with the code below.

JASS:
call FormGroup(3, true)
call AttackMoveKillA(GetBuilding(targetPlayer))

It doesn't have a fixed delay (apart from waiting till attack group is ready), but that's perfectly fine for this map. So far it's working. It's possible that AI will be a little dumber and won't continue an attack after killing that particular building, but maybe with dense bases it won't be a problem.
 

Macielos

Hosted Project: W3E
Level 23
Joined
Jul 9, 2010
Messages
396
Have you tried SuicideOnPlayerEx()? It is the same function but you can put different values for different difficulties in, with no difficulty it defaults to Normal.
Nope, it calls SuicideOnPlayer internally, which calls SuicidePlayer native function, which crashes the game.

I think I'll just prepare an alternate version of SuicideOnPlayer.
 
Last edited:

Macielos

Hosted Project: W3E
Level 23
Joined
Jul 9, 2010
Messages
396
Well, sometimes when we order a unit to move to the other corner of a very complex map, it fails to do so and stacks somewhere in the middle of its path. That is expected. But it shouldn't crash the game. Fortunately the alternative above seems to work, so I wrote an alternate SuicideOnPlayerSafe() function and today will be re-testing Alteraci Chapter with it.
 
Level 3
Joined
Apr 20, 2022
Messages
17
I want to know how you debug, can you tell me the method
If you have a large number of AI and debugging information is like a tide, how can you see through it?


I have been debugging AMAI's scripts ( this script doesn't use Suicide API at all ), but no matter how I modify them, I cannot fix the crash issue of the 24 person map
I couldn't avoid it in both 1.31 and 2.01, but it doesn't seem to crash in the 1.26 version with 12 people

I want to know if it's a low-level issue. I tried all excretions to avoid the API obtaining hidden units. Before deleting units, I killed them first
I am currently suspecting whether the maximum number of unit groups cannot exceed 1200

What I know is that AI doesn't attack and doesn't seem to collapse when staying at home all the time
 

Macielos

Hosted Project: W3E
Level 23
Joined
Jul 9, 2010
Messages
396
I want to know how you debug, can you tell me the method
It's a pathway through hell, unfortunately. There were plenty of tiny things I had to figure out or read somewhere that made debugging process a little bit less painful.

You can look through my modifications of common.ai. The file is huge, but check out functions under EXODUS CUSTOM FUNCTIONS tag - there are three such blocks. In the first one there are some functions to print variable values.

Also, always use Jass Syntax Checker tool to make sure your script even compiles.

Unfortunately, it's still often trial and error method. In case above I copied the map and started removing stuff from it to the moment my AI started working. I switched off other AIs, I pathblocked parts of the map, removed custom units, eventually I downsized the map and only this worked. Then fortunately I found a way not call this crashing function.

If you have a large number of AI and debugging information is like a tide, how can you see through it?
I think I just commented out some debugs in common.ai file that were too frequent. The rest I modified to call my Print() function which only prints them if trace_on = true.

I have been debugging AMAI's scripts ( this script doesn't use Suicide API at all ), but no matter how I modify them, I cannot fix the crash issue of the 24 person map
I couldn't avoid it in both 1.31 and 2.01, but it doesn't seem to crash in the 1.26 version with 12 people
First thing that comes to my mind - check if the game just instantly crashes, or if it freezes and becomes unresponsive. In the case from this topic it was an instant crash. But in the beginning of my struggle with scripted AI majority of crashes were in fact freezes caused by loops without sleep calls inside them. So I had a code like this:
loop
doSomething()
if something()
doSomethingElse()
Sleep()
endif
exitwhen something()
end
and under certain conditions it omitted the if and just repeated the loop without calling a Sleep() inside, which made it freeze the game. Tracking down all those cases in common.ai file made my scripts faaar more stable.

I want to know if it's a low-level issue. I tried all excretions to avoid the API obtaining hidden units. Before deleting units, I killed them first
Just RemoveUnit() should be sufficient. Killing units doesn't make them invisible for AI, they are still in unit groups.

What do you mean by obtaining hidden units? Did you call HideUnit() on them? If such, they are still valid units and can be used by AI. There are trigger actions (and functions underneath) to make AI ignore positions of units.

I sometimes have a second player with the same name and color and whenever I want to exclude some units from AI control, I just change their owner to this second player. That way I also don't have to worry about AI food cap.

I am currently suspecting whether the maximum number of unit groups cannot exceed 1200
No idea, but perhaps you can optimize your script not to need that many groups. It sounds like hell too many. You should also call DestroyGroup(g) on groups you no longer need.

What I know is that AI doesn't attack and doesn't seem to collapse when staying at home all the time
That is correct, 99% of crashes is related to attack logic. Which is kinda expected.
 

Attachments

  • common_TVG.ai
    116.1 KB · Views: 3
Level 3
Joined
Apr 20, 2022
Messages
17
When there are more than 12 AI tests - I have been testing 23 AI , and I can't even see the logs. Will you crash even if you test a few AI?
 
Level 28
Joined
Feb 2, 2006
Messages
1,631
I just have them logged on the screen. I've never used any custom logging in WC3, although it would be extremely useful.
So for tracing into files I did something like this in a modified scripts/common.ai for my map:

JASS:
globals
    // traces
    integer traceLineCounter = 0
    integer traceCounter = 0
    boolean trace_enabled = false
endglobals

//============================================================================
// https://www.hiveworkshop.com/threads/i2s-without-natives-for-use-in-ai-scripts.348472/

function I2C2 takes integer i returns string
    if i == 0 then
        return "0"
    elseif i == 1 then
        return "1"
    elseif i == 2 then
        return "2"
    elseif i == 3 then
        return "3"
    elseif i == 4 then
        return "4"
    elseif i == 5 then
        return "5"
    elseif i == 6 then
        return "6"
    elseif i == 7 then
        return "7"
    elseif i == 8 then
        return "8"
    elseif i == 9 then
        return "9"
    endif
    return ""
endfunction

function I2S2 takes integer i returns string
    local integer j = i
    local string s = ""
    local integer k = 0
    local boolean is_negative = false
    local integer MAX_DIGITS = 20
    if i < 0 then
        set is_negative = true
        set j = -j
    endif
    loop
        set s = I2C2(j - (j / 10) * 10) + s
        set j = j / 10
        set k = k + 1
        exitwhen j == 0 or k >= MAX_DIGITS
    endloop
    if is_negative then
        set s = "-" + s
    endif
    return s
endfunction

function FileStart takes nothing returns nothing
    call PreloadGenClear()
    call PreloadGenStart()
endfunction

function FileWriteLine takes string whichString returns nothing
    call Preload(whichString)
endfunction

function FileSave takes string fileName returns nothing
    // The line below creates the file at the specified location
    call PreloadGenEnd(fileName)
endfunction

function FileTraceSave takes nothing returns nothing
    call FileSave("Trace " + I2S2(traceCounter) + GetPlayerName(Player(GetAiPlayer())) + ".txt")
    set traceCounter = traceCounter + 1
    set traceLineCounter = 0
endfunction

function FileTrace takes string message returns nothing
    if (trace_enabled) then
        call FileWriteLine(message)
        set traceLineCounter = traceLineCounter + 1
        if (traceLineCounter >= 20) then
            call FileTraceSave()
        endif
    endif
endfunction

//============================================================================
// recipient: changes the type of chat channel prefix shown. It has no effect on the message's visibility.
// 0: "All" chat prefix
// 1: "Allies"
// 2: "Observers"
// 3+: "Private"

function NotifySpecificPlayer takes integer playerIndex, string message returns nothing
    call BlzDisplayChatMessage(Player(GetAiPlayer()), 3 + playerIndex, message)
endfunction

function NotifyOtherPlayers takes string message returns nothing
    call BlzDisplayChatMessage(Player(GetAiPlayer()), 0, message)
endfunction

//============================================================================
function Trace takes string message returns nothing
    local integer i = 0
    if (trace_enabled) then
        loop
            exitwhen (i == GetBJMaxPlayers())
            if trace_on[i] then
                call DisplayText(i, message)
                call NotifySpecificPlayer(i, message)
            endif
            set i = i + 1
        endloop
        call FileTrace(message)
    endif
endfunction

trace_on[X] will be enabled via AI commands but could be true for all.
This will send chat messages and write stuff into a text file TraceXPlayerName.txt.
However, when AI crashes it probably won't write the current stuff since I buffer about 20 lines.
Still gives some info and you can change 20 to 1 which will create more files.
 
Top