• 🏆 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!

[JASS] Preloading Abilities with Loop

Status
Not open for further replies.
Level 6
Joined
Feb 12, 2008
Messages
207
Well... I'm trying to preload all my abilities as they are a lot and when a hero is selected, each of them having at least 40 abilities (counting that they have spellbooks), it lags for something around 2 or 3 seconds for the 1st time.

So I decided to do a preload in map init but I get a wc3 crash if I get the loop limit to more than 50.

Heres the code, I can't get what is wrong here.
JASS:
    local unit      dummy       = CreateUnit(Player(0), 'n00V', 0, 0, 0)
    call PreloadAbilities(dummy, 100)

function PreloadAbilities takes unit u, integer limit returns nothing    
    local integer i = 0
    local integer a = 'A000'
    //call Preload("path/sfx.mdx")
    //set bj_lastCreatedItem = UnitAddItemById(u, 'I000')
    //set bj_lastCreatedItem = null
    loop
    exitwhen i > limit
        call UnitAddAbility(u, a)
        call UnitRemoveAbility(u, a)
        set a = a + 1
        set i = i + 1
    endloop
    call RemoveUnit(u)
endfunction

Note that the "100" its just an example, I have 300+ abilities ATM and I think of creating more later. If I put a small number like "20" it doesn't crash but tried with "80" and it crashes my wc3 at the moment of the trigger being executed. What am I doing wrong? Is this loop thing possible? If not, is there another way to preload all my abilities at once so I don't have to make a code of 300+ lines just to preload abilities?

EDIT: Trying with numbers, at "40" the trigger doesn't crash, but the game lags for 1.5 sec and then it starts normally. I'll try to use waits. Please help me in this one XD
 
Last edited:
Level 18
Joined
Jan 21, 2006
Messages
2,552
You're going to need to use a timer to pace the rate at which abilities are preloaded.

JASS:
globals

    timer       preloadClock            = CreateTimer( )
    real        preloadInterval         = 0.2
    integer     preloadLimit            = 500
    integer     preloadClockCounter     = 0
    integer     preloadAbilityID        = 'A000'
    unit        preloadUnit             = null
    
    boolean     preloading              = false
    
endglobals

function PreloadAbilities_OnTimer takes nothing returns boolean
    local integer limit = preloadClockCounter
    local boolean end   = false
    set preloadClockCounter = preloadClockCounter + 30
    if preloadClockCounter == preloadLimit then
        set preloadClockCounter = preloadLimit
        set end = true
    endif
    loop
        exitwhen limit == preloadClockCounter
        call UnitAddAbility(preloadUnit, preloadAbilityID)
        call UnitRemoveAbility(preloadUnit, preloadAbilityID)
        set preloadAbilityID = preloadAbilityID + 1
        set limit = limit + 1
    endloop
    if end then
        call PauseTimer(preloadClock)
        call RemoveUnit(preloadUnit)
        set preloading = false
    endif
    return end
endfunction

function PreloadAbilities takes unit u returns nothing
    set preloadUnit = u
    
    call PreloadAbilities_OnTimer( )
    call TimerStart(preloadClock, preloadInterval, true, function PreloadAbilities_OnTimer)
    set preloading = true
    
endfunction

I helped you out a little, don't know if you'll need it or not.
 
Level 6
Joined
Feb 12, 2008
Messages
207
Berb thats really helpful! +rep, thanks a lot for that!

But still.... there's a problem. With your functions I've been able to check that when the preloading tries to preload the Ability Integer "52" or when the "preloadClockCounter" reaches 52 or 53 it crashes my wc3. So I've noticed now that the ability 52 is bugging.

I'll use BJDebugMsg and AbilityId2String to see if the ability doesn't exists or something that can tell me what the heck is bugging here.

hmmm I can't find the problem Berb. From what I can calculate myself, 'A026' is the ability when the counter reaches 52. Checked my abilities and from 'A020' to 'A030' all the abilities seem to be OK, even when a unit with those abilities is created, the game lags a bit and it gets loaded fine with no crashes. Just the non preloaded issue that I had before. Can't get what is the problem causing this to crash at "52". Any help with it?

oh, also BJDebugMsj(AbilityId2String(preloadAbilityID)) returns a (null) string
 
Last edited:
Level 6
Joined
Feb 12, 2008
Messages
207
Yeah, the game crash stopped. By the way, I made the counter slower so I could see that it was the 52 that was crashing and not another around that number. Also, tried starting from ability "30" and it still crashes at 52. It's that damn ability.

Some random info, the dummy is a flying one, has no model (.mdl) and has no abilities. Maybe something wrong with the dummy? I dunno just wondering

Got something:

JASS:
function Trig_Untitled_Trigger_001_Actions takes nothing returns nothing
    local integer abi = 'A000' + S2I(SubString(GetEventPlayerChatString(), 1, 3))

    call BJDebugMsg( SubString(GetEventPlayerChatString(), 1, 3) )
    call BJDebugMsg(I2S(abi))
    call UnitAddAbilityBJ( abi, udg_Survivor[GetConvertedPlayerId(GetTriggerPlayer())] )
endfunction

when I place the number 51 ability it crashes... still trying to see what the heck is going on with this but at least now I can confirm that the ability is the one causing this trouble. How can i get the ability name from this number?
 
Last edited:
Level 6
Joined
Feb 12, 2008
Messages
207
It's only that ability. Using the scratch trigger to manually add the abilities it crashes only when I type 51.
50, 52, 53 doesn't crash.

Edit: Shit! 64 and 65 at least crashes too!
 
Level 6
Joined
Feb 12, 2008
Messages
207
Don't know, I calculated that it is this one, based on Roar:

If there's some way to get the ability index from a simple integer like "51" it would be good to know.
 

Attachments

  • DamnAbi.jpg
    DamnAbi.jpg
    154.2 KB · Views: 194
Level 18
Joined
Jan 21, 2006
Messages
2,552
Well that's easy, just do this:

JASS:
local integer rawcode = 'A051' // this is your ability's rawcode

call BJDebugMsg(I2S('A000'+51))
call BJDebugMsg(I2S(rawcode))

Or even better, you can just use GetObjectName.

JASS:
call BJDebugMsg(GetObjectName('A000'+51))

See what ability exactly is causing it to bug-out.
 
Level 6
Joined
Feb 12, 2008
Messages
207
call BJDebugMsg(GetObjectName('A000'+i)) gives "Default String" no matter the number I give
call BJDebugMsg(I2S('A000'+51)) gives 1093677155. That's because Ability integers are integers in base 256 or something like that I think.

and I think 'A051' isn't the ability with index 51, I suppose the ability indexes are A000 through A009 and then what should be "A010" its actually A00A.
So A00A < A00Z < A010 if I'm not wrong.




OK, at last found someone who had a problem similar to me:

http://www.thehelper.net/forums/showthread.php?p=1252887

It seems that A00a and A00b it's not the same and that he had the same problem as me... pretty strange though.


-----------------
I'm giving up for today, I can't find a way to do a safe preload without crashing on some abilities. If there's someone who already did a safe preload for abilities woud be very nice to know a how to or something. Thanks for the help Berb, but this time Blizzard wins :B
I'll give it a try tomorrow, but for now my head is going to blow up if I don't rest.
 
Last edited:
Level 18
Joined
Jan 21, 2006
Messages
2,552
The problem is that you were adding/removing an ability that did not exist. It isn't the raw-code that is bugged, it is the fact that there is no ability [lass]'A000'+51[/icode] in your map. If you had been showing the raw-codes in the screen-shot it might have been more obvious.

When you're looping through abilities like this (incrementing an ability ID to cover an array of abilities) you have to be careful you don't exceed an increment that goes beyond what you have set into existence in the Object Editor.
 
Level 6
Joined
Feb 12, 2008
Messages
207
What is really annoying is that 'A051' does exist, and the equivalent 'A000'+51 should be 'A018', and it does exist too... Sometimes WE annoys me.

If it helps, I have abilities rawcodes used up to A063, so I'm 98% sure that there IS an ability with that rawcode.

THIS IS IMPORTANT:
Adding an ability that doesn't exists to a unit does NOT crash the game. Just tried adding the ability 'A100' which doesn't exists in the map and it just returns a Default String when using GetObjectName() and UnitAddAbility() works just fine with no crashes. No ability is added
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Oh; that's strange. In the link you gave me the author's problem was with adding/removing ability IDs that do not occupy any object, whether it be an ability, a unit or anything else. This was causing his Warcraft to crash, or experience a fatal error (whatever the symptoms were).

How about this, try isolating that ability ID. What happens when all you do is add/remove the ability with ID 'A018', and see if that causes the game to crash.

When I execute BJDebugMsg(I2S(('A000')+51)) it prints "1093677155". When I execute BJDebugMsg(I2S('A018')) it prints "1093677368", indicating that these are not the same IDs.

Okay, after doing a little bit of math I've come to the conclusion that "A000" plus "51" is "A00c". It is not "A018". This is how it counts:

Code:
A00W
A00X
A00Y
A00Z
A00[
A00.
A00]
A00^
A00_
A00`
A00a
A00b

And so on. If you're using a keyboard you can easily figure out the 256 characters simply by going into a text editor and holding ALT and pressing 1, then 2, then 3, and so on. In notepad I get the results:

Code:
UVWXYZ[\]^_`a

So instead of a "." it shows a "\". What ability IDs do you have?
 
Level 6
Joined
Feb 12, 2008
Messages
207
Berb you're a genius, you saved me a lot of time. I had found the ability which was causing the first crash... After deleting lots of abilities that were causing crashes, I came here to post something about it and after reading your post I had to go back and take a look at the deleted abilities rawcodes... You want to know what was the 1st ability? Yeah it was the A00C!
So now you have the formula to get all the bugged abilities. Now I only have to delete every ability that causes this to crash. Though I still don't know why do they crash when adding them to a unit, but it makes some sense when I remember that blizzard screwed some maps with release of 1.23 (I think it was 1.23). Even when my map never got affected by the changes I'm starting to think that it has something to do with it.

So, if you please could post a formula to get the IDs would be great. My brain is fried after all of this. Even we can chat (msn, hive chat, anything) so we can have a faster communication. That would speed up things a lot.

What I have to do now, is to delete every ability that crashes one by one, I have a blank map with the abilities and your code imported so I can do it faster. I just need a formula to get the SpellIDs more quickly. After that maybe I could see if they have something in common to find a reason for the crashes. I just hope that when remaking the abilities the problem can be solved.


Look at this, this is the clean map with the code where you can see by testing it that it crashes on 51. That will help a lot in order to catch all the buggy abilities
 

Attachments

  • A.w3x
    70.6 KB · Views: 85
Level 18
Joined
Jan 21, 2006
Messages
2,552
I'm not sure what formula blizzard uses. I can try to see if I can figure out which ASCII characters they try to use, though; it may take a few minutes.

The pattern by which object raw codes are allocated (abilities) goes as follows:
Code:
A000
A001
A002
A003
...
A009
A00A
A00B
A00C
...
A00Z
A010
A011
A012
...
A019
A01A
A01B
A01C
...
A020
A021
A022
A023

And so on; I didn't bother to go further. The only rule that seems to stand out is the use of only capital letters and numbers - this limits the ASCII characters used from 48 (0) to 57 (9) and from 65 (A) to 90 (Z).

So this is the character map (in a string) that they use: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" - notice this is only 36 symbols (which means you can count in base 36 to achieve their results).
 
Level 6
Joined
Feb 12, 2008
Messages
207
Well... As far as I've gotten before coming back here to read the response from before was somewhere near 300. After 315 or so it was crashing seriously. So with this offsets it means that the 'limit' variable has to be of at least 1000 or more. It's difficult at this time for me to get the Abilities ID from a simple integer but if I'm not wrong:


AbilityID
'A000' 'A009' 'A00A' 'A00Z' 'A00a' 'A00z'

+Int
0 9 17 42 49 74

If that's right, then it sounds pretty complicated to make a formula or something to "jump" those so the code runs only on the abilities that exist.
It would be nice if I can make something to show the ID ingame. I think I'll have to use some functions to convert BASE10 to BASE256. I'm into it right now.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
There is already a function that does that in the xepreload library, but you have to make it (and the keyword) public so they can be referenced outside of that library. It basically takes an integer and gives you a four-character value that shows the conversion.

I am thinking that the Object Editor counts up in base-36 but has support for base-256 characters. The first character is some sort of "type" flag because units/abilities all have a different beginning letter. This letter is followed by three characters, which are counted in base-36.

I'm curious how Grimoire changes the object raw codes, because that means you can give an ability the raw code of a different type of object. Abilities act strangely, though, I can give an ability the ID 'Hpal' and it doesn't seem to conflict with the Paladin in any major way.

I think you only need to worry about converting numbers of base-10 to base-36, which is really simple. Once you do that you'll need to take the base-36 string (integers cannot have letters or other non numeric characters) and concatenate it to the end of the string "A" for results from "A000" to "A01A" and on.

Try this code out, see if it doesn't help:

JASS:
library Base10To36 initializer init
globals
    private string charMap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
endglobals

function B10to36 takes integer intB10 returns string
    local string result = ""
    local integer r
    
    loop
        set r = ModuloInteger(intB10, 36)
        set result = SubString(charMap, r, r+1)+result
        set intB10 = intB10 / 36
        
        exitwhen (intB10 == 0)
    endloop
    loop
        exitwhen StringLength(result) >= 3
        set result = "0"+result
    endloop
    return result
endfunction

public function init takes nothing returns nothing
    call BJDebugMsg("A"+B10to36(36))
    call BJDebugMsg("A"+B10to36(72))
    call BJDebugMsg("A"+B10to36(552))
    
endfunction

endlibrary

This displays "A010", "A020", and "A0FC" in-game.
 
Last edited:
Level 6
Joined
Feb 12, 2008
Messages
207
I did something similar but from base 10 to 256.

JASS:
function I2ASCII takes integer i returns string
    local string charmap = "??????????????¤????¶§?????????? !?#$%&'()*+,-.?0123456789:;<=>??ABCDEFGHIJKLMNOPQRSTUVWXYZ[?]^_`abcdefghijklmnopqrstuvwxyz{|}~¦ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø×’áíóúñѪº¿®¬½¼¡«»¦¦¦¦¦ÁÂÀ©¦¦++¢¥++--+-+ãÃ++--¦-+¤ðÐÊËÈiÍÎÏ++¦_¦Ì¯ÓßÔÒõÕµþÞÚÛÙýݯ´*±=¾¶§÷¸°¨·¹³²¦*"
    local string ascii
    
    set ascii = SubString(charmap, i, i+1)
    
    return ascii
endfunction

function Base10to256 takes integer num returns string
    local integer a
    local integer b
    local integer c
    local integer d
    local string id
    
    set d = ModuloInteger(num, 256)
    set num = ( num / 256 )
    set c = ModuloInteger(num, 256)
    set num = ( num / 256 )
    set b = ModuloInteger(num, 256)
    set num = ( num / 256 )
    set a = ModuloInteger(num, 256)
    set id = I2ASCII(a)+I2ASCII(b)+I2ASCII(c)+I2ASCII(d)
    return id
endfunction
 
Level 6
Joined
Feb 12, 2008
Messages
207
No, it just helped me to find the bugged abilities by their ids. Now it doesn't crash anymore! And mostly thanks to you.
 
Status
Not open for further replies.
Top