• 🏆 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] Jass vs. GUI (speed)

Status
Not open for further replies.
Level 8
Joined
Aug 2, 2006
Messages
346
Hi, I'm starting a new map and I'm trying to use a lot of jass in it. I know a little bit of C++ so I'm not a complete newbie. But just to make things easier, I'm making the functions in the GUI, then converting them to text, then changing stuff around so it's not calling a whole new function just to check a friggen condition. Stuff like that.

If that's all I'm doing, is the speed gain going to be all that much?

I'm making a shooter map like Crimsonland, so all the speed I can get is needed.
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
Well, GUI uses BJ functions, which are effectively wrappers. Often, those functions call more wrappers in turn.

The time it takes to call a function (not native, those are much faster) (not including contents!) is more than the call time of Sin (including execution of course), so... ouch.

So if you clean up the BJs, it'll probably be a good deal more than twice as fast. (Unless you use a lot of stuff that doesn't have to do with function calling)

Oh, plus locals encourage less function calling, which is faster.
 
Level 11
Joined
Oct 13, 2005
Messages
233
Generally, you won't notice much of a speed difference in shifting from GUI to JASS unless you're making something that needs the performance, mainly things involving timers which can be something like a projectile system. One advantage JASS does have is allowing you to remove/destroy handles to prevent memory leaks that GUI actions won't allow. So if your code had a good amount of memory leaks, you'd usually notice some lag as the game went on from more and more memory being used.
 
Level 13
Joined
Nov 22, 2006
Messages
1,260
JASS is mainly used for periodical things, like spells. Leaks are not so important in one-shot triggers, but in spells they can screw up your map totally. So it is important that you learn how to clean leaks in JASS when learning how to make spells.

The only BJ I tend to use (personally) is TriggerRegisterAnyUnitEventBJ.

......and CinematicModeBJ, FadeFilterBJ, CreateQuestBJ, CountUnitsInGroup, those darn multiboard funcs..........

Thins you should avoid are mainly locations and BJs like GetSpellAbilityUnit() (actually not a BJ, but still.....), GetAttackedUnitBJ(), GetOrderedUnit() (again, not a BJ) and replace all those with GetTriggerUnit() (the fastest and the most simple one). Anyways, you have a lot to learn kid..... ;)
 
Level 8
Joined
Aug 2, 2006
Messages
346
Generally, you won't notice much of a speed difference in shifting from GUI to JASS unless you're making something that needs the performance, mainly things involving timers which can be something like a projectile system. One advantage JASS does have is allowing you to remove/destroy handles to prevent memory leaks that GUI actions won't allow. So if your code had a good amount of memory leaks, you'd usually notice some lag as the game went on from more and more memory being used.

Well for what I'm doing, I do need the speed. It's a shooter game (not a stupid tell-them-to-attack-here map, but a right click the ground to shoot there).

Oh man this is great! Now I can click the dialog buttons faster than ever! hehehe.

Well dang! I'm in the process of removing all those BJ things, and most of them you can get rid of just by deleting the 'BJ' part of it! Why did Blizzard even have the BJ things for the ones that are the same?
 
Last edited:
Level 40
Joined
Dec 14, 2005
Messages
10,532
Because they fail =/

The ones with different parameter orders make sense though; even GUI still has to put parameters in the correct order, so to make it legible in normal phrases the parameters are changed to make nice sentences.

Eg;

Add Ability to Unit

Reads a lot better than

Add to Unit the ability: Ability

(And that's even an example that would work both ways... many would not)
 
Level 11
Joined
Feb 18, 2004
Messages
394
Functions calls are expensive in JASS. They take allot of time.
Warcraft 3 has 3 scripts it uses when executing a map: common.j, blizzard.j, and w3map.j. The fist holds "natives" (functions which are implemented natively within the game itself) blizzard.j holds functions written in JASS. Most Actions in GUI are simply a single JASS function call, most often to a Blizzard.j function. Most Blizzard.j functions use the prefix or postfix "bj" for blizzard.j, i would assume.

Why are BJ's bad? Well, some are not. Some are actually rather useful. But as i noted earlier, function calls in JASS are slow. Some blizzard.j functions do absolutely nothing but call a native function, sometimes with the parameter lists being exactly the same, and sometimes, in the same order! Why did they do this? Well, i must presume that they got the mentally disabled to write the GUI coding system. (Note: I'm just joking around, its quite an achievement to make something as user-friendly as the triggering GUI)

Other reasons why GUI is slow include the way World Edit generates code for things like "If-The-Else" statements. Instead of doing:
JASS:
if IsUnitType(GetTriggerUnit(), UNIT_TYPE_STRUCTURE) then
// action
endif
It will generate something like:
JASS:
function Trig_Untitled_Trigger_001_Func001C takes nothing returns boolean
    if ( not ( IsUnitType(GetTriggerUnit(), UNIT_TYPE_STRUCTURE) == true ) ) then
        return false
    endif
    return true
endfunction

function Trig_Untitled_Trigger_001_Actions takes nothing returns nothing
    if ( Trig_Untitled_Trigger_001_Func001C() ) then
        call DoNothing(  )
    else
    endif
endfunction
... I have no fucking idea what they where smoking. "Don't do drugs, 'cause drugs are bad" ... don't do drugs 'cause it leads to stuff like this!


Anyway, the GUI is a method of using templates which you point-and-click to select templates, and fill in different values. Underneath the GUI is actual JASS code that the GUI is writing. Thats the biggest reason that the GUI generates much slower code: Its so much easier to write efficient, concise, simple, and generally good code when you actually write it, instead of letting a rather clunky and limited GUI write the actual code for you.


Edit: I totally forgot to mention... Handle creation (CreateUnit(), Location(), ext) is especially slow. Thus why using things like coordinates is very important in speed-critical code. Also recycling of already created handles is useful. (eg: moving a location instead of creating and destroying one)
 
Level 13
Joined
Nov 22, 2006
Messages
1,260
JASS:
function CinematicModeBJ takes boolean cineMode, force forForce returns nothing
    call CinematicModeExBJ(cineMode, forForce, bj_CINEMODE_INTERFACEFADE)
endfunction


JASS:
function CinematicModeExBJ takes boolean cineMode, force forForce, real interfaceFadeTime returns nothing
    if (not bj_gameStarted) then
        set interfaceFadeTime = 0
    endif

    if (cineMode) then
        if (not bj_cineModeAlreadyIn) then
            set bj_cineModeAlreadyIn = true
            set bj_cineModePriorSpeed = GetGameSpeed()
            set bj_cineModePriorFogSetting = IsFogEnabled()
            set bj_cineModePriorMaskSetting = IsFogMaskEnabled()
            set bj_cineModePriorDawnDusk = IsDawnDuskEnabled()
            set bj_cineModeSavedSeed = GetRandomInt(0, 1000000)
        endif

        if (IsPlayerInForce(GetLocalPlayer(), forForce)) then
            call ClearTextMessages()
            call ShowInterface(false, interfaceFadeTime)
            call EnableUserControl(false)
            call EnableOcclusion(false)
            call SetCineModeVolumeGroupsBJ()
        endif

        call SetGameSpeed(bj_CINEMODE_GAMESPEED)
        call SetMapFlag(MAP_LOCK_SPEED, true)
        call FogMaskEnable(false)
        call FogEnable(false)
        call EnableWorldFogBoundary(false)
        call EnableDawnDusk(false)

        call SetRandomSeed(0)
    else
        set bj_cineModeAlreadyIn = false

        if (IsPlayerInForce(GetLocalPlayer(), forForce)) then
            call ShowInterface(true, interfaceFadeTime)
            call EnableUserControl(true)
            call EnableOcclusion(true)
            call VolumeGroupReset()
            call EndThematicMusic()
            call CameraResetSmoothingFactorBJ()
        endif

        call SetMapFlag(MAP_LOCK_SPEED, false)
        call SetGameSpeed(bj_cineModePriorSpeed)
        call FogMaskEnable(bj_cineModePriorMaskSetting)
        call FogEnable(bj_cineModePriorFogSetting)
        call EnableWorldFogBoundary(true)
        call EnableDawnDusk(bj_cineModePriorDawnDusk)
        call SetRandomSeed(bj_cineModeSavedSeed)
    endif
endfunction


JASS:
function IsDawnDuskEnabled takes nothing returns boolean
    return bj_useDawnDuskSounds
endfunction


JASS:
function SetCineModeVolumeGroupsBJ takes nothing returns nothing
    if bj_gameStarted then
        call SetCineModeVolumeGroupsImmediateBJ()
    else
        call TimerStart(bj_volumeGroupsTimer, bj_GAME_STARTED_THRESHOLD, false, function SetCineModeVolumeGroupsImmediateBJ)
    endif
endfunction


JASS:
function SetCineModeVolumeGroupsImmediateBJ takes nothing returns nothing
    call VolumeGroupSetVolume(SOUND_VOLUMEGROUP_UNITMOVEMENT,  bj_CINEMODE_VOLUME_UNITMOVEMENT)
    call VolumeGroupSetVolume(SOUND_VOLUMEGROUP_UNITSOUNDS,    bj_CINEMODE_VOLUME_UNITSOUNDS)
    call VolumeGroupSetVolume(SOUND_VOLUMEGROUP_COMBAT,        bj_CINEMODE_VOLUME_COMBAT)
    call VolumeGroupSetVolume(SOUND_VOLUMEGROUP_SPELLS,        bj_CINEMODE_VOLUME_SPELLS)
    call VolumeGroupSetVolume(SOUND_VOLUMEGROUP_UI,            bj_CINEMODE_VOLUME_UI)
    call VolumeGroupSetVolume(SOUND_VOLUMEGROUP_MUSIC,         bj_CINEMODE_VOLUME_MUSIC)
    call VolumeGroupSetVolume(SOUND_VOLUMEGROUP_AMBIENTSOUNDS, bj_CINEMODE_VOLUME_AMBIENTSOUNDS)
    call VolumeGroupSetVolume(SOUND_VOLUMEGROUP_FIRE,          bj_CINEMODE_VOLUME_FIRE)
endfunction


JASS:
function EnableDawnDusk takes boolean flag returns nothing
    set bj_useDawnDuskSounds = flag
endfunction


JASS:
function CameraResetSmoothingFactorBJ takes nothing returns nothing
    call CameraSetSmoothingFactor(0)
endfunction

JASS:
function CinematicFadeBJ takes integer fadetype, real duration, string tex, real red, real green, real blue, real trans returns nothing
    if (fadetype == bj_CINEFADETYPE_FADEOUT) then
        call AbortCinematicFadeBJ()
        call CinematicFadeCommonBJ(red, green, blue, duration, tex, 100, trans)
    elseif (fadetype == bj_CINEFADETYPE_FADEIN) then
        call AbortCinematicFadeBJ()
        call CinematicFadeCommonBJ(red, green, blue, duration, tex, trans, 100)
        call FinishCinematicFadeAfterBJ(duration)
    elseif (fadetype == bj_CINEFADETYPE_FADEOUTIN) then
        if (duration > 0) then
            call AbortCinematicFadeBJ()
            call CinematicFadeCommonBJ(red, green, blue, duration * 0.5, tex, 100, trans)
            call ContinueCinematicFadeAfterBJ(duration * 0.5, red, green, blue, trans, tex)
            call FinishCinematicFadeAfterBJ(duration)
        endif
    else
    endif
endfunction


JASS:
function AbortCinematicFadeBJ takes nothing returns nothing
    if (bj_cineFadeContinueTimer != null) then
        call DestroyTimer(bj_cineFadeContinueTimer)
    endif

    if (bj_cineFadeFinishTimer != null) then
        call DestroyTimer(bj_cineFadeFinishTimer)
    endif
endfunction


JASS:
function CinematicFadeCommonBJ takes real red, real green, real blue, real duration, string tex, real startTrans, real endTrans returns nothing
    if (duration == 0) then
        set startTrans = endTrans
    endif
    call EnableUserUI(false)
    call SetCineFilterTexture(tex)
    call SetCineFilterBlendMode(BLEND_MODE_BLEND)
    call SetCineFilterTexMapFlags(TEXMAP_FLAG_NONE)
    call SetCineFilterStartUV(0, 0, 1, 1)
    call SetCineFilterEndUV(0, 0, 1, 1)
    call SetCineFilterStartColor(PercentTo255(red), PercentTo255(green), PercentTo255(blue), PercentTo255(100-startTrans))
    call SetCineFilterEndColor(PercentTo255(red), PercentTo255(green), PercentTo255(blue), PercentTo255(100-endTrans))
    call SetCineFilterDuration(duration)
    call DisplayCineFilter(true)
endfunction


JASS:
function ContinueCinematicFadeAfterBJ takes real duration, real red, real green, real blue, real trans, string tex returns nothing
    set bj_cineFadeContinueRed = red
    set bj_cineFadeContinueGreen = green
    set bj_cineFadeContinueBlue = blue
    set bj_cineFadeContinueTrans = trans
    set bj_cineFadeContinueDuration = duration
    set bj_cineFadeContinueTex = tex

    set bj_cineFadeContinueTimer = CreateTimer()
    call TimerStart(bj_cineFadeContinueTimer, duration, false, function ContinueCinematicFadeBJ)
endfunction


JASS:
function ContinueCinematicFadeBJ takes nothing returns nothing
    call DestroyTimer(bj_cineFadeContinueTimer)
    set bj_cineFadeContinueTimer = null
    call CinematicFadeCommonBJ(bj_cineFadeContinueRed, bj_cineFadeContinueGreen, bj_cineFadeContinueBlue, bj_cineFadeContinueDuration, bj_cineFadeContinueTex, bj_cineFadeContinueTrans, 100)
endfunction


JASS:
function FinishCinematicFadeAfterBJ takes real duration returns nothing
    set bj_cineFadeFinishTimer = CreateTimer()
    call TimerStart(bj_cineFadeFinishTimer, duration, false, function FinishCinematicFadeBJ)
endfunction

JASS:
function MultiboardSetItemColorBJ takes multiboard mb, integer col, integer row, real red, real green, real blue, real transparency returns nothing
    local integer curRow = 0
    local integer curCol = 0
    local integer numRows = MultiboardGetRowCount(mb)
    local integer numCols = MultiboardGetColumnCount(mb)
    local multiboarditem mbitem = null

    loop
        set curRow = curRow + 1
        exitwhen curRow > numRows

        if (row == 0 or row == curRow) then
            set curCol = 0
            loop
                set curCol = curCol + 1
                exitwhen curCol > numCols

                if (col == 0 or col == curCol) then
                    set mbitem = MultiboardGetItem(mb, curRow - 1, curCol - 1)
                    call MultiboardSetItemValueColor(mbitem, PercentTo255(red), PercentTo255(green), PercentTo255(blue), PercentTo255(100.0-transparency))
                    call MultiboardReleaseItem(mbitem)
                endif
            endloop
        endif
    endloop
endfunction

JASS:
function MultiboardSetItemIconBJ takes multiboard mb, integer col, integer row, string iconFileName returns nothing
    local integer curRow = 0
    local integer curCol = 0
    local integer numRows = MultiboardGetRowCount(mb)
    local integer numCols = MultiboardGetColumnCount(mb)
    local multiboarditem mbitem = null

    loop
        set curRow = curRow + 1
        exitwhen curRow > numRows

        if (row == 0 or row == curRow) then
            set curCol = 0
            loop
                set curCol = curCol + 1
                exitwhen curCol > numCols

                if (col == 0 or col == curCol) then
                    set mbitem = MultiboardGetItem(mb, curRow - 1, curCol - 1)
                    call MultiboardSetItemIcon(mbitem, iconFileName)
                    call MultiboardReleaseItem(mbitem)
                endif
            endloop
        endif
    endloop
endfunction

JASS:
function MultiboardSetItemStyleBJ takes multiboard mb, integer col, integer row, boolean showValue, boolean showIcon returns nothing
    local integer curRow = 0
    local integer curCol = 0
    local integer numRows = MultiboardGetRowCount(mb)
    local integer numCols = MultiboardGetColumnCount(mb)
    local multiboarditem mbitem = null

    loop
        set curRow = curRow + 1
        exitwhen curRow > numRows

        if (row == 0 or row == curRow) then
            set curCol = 0
            loop
                set curCol = curCol + 1
                exitwhen curCol > numCols

                if (col == 0 or col == curCol) then
                    set mbitem = MultiboardGetItem(mb, curRow - 1, curCol - 1)
                    call MultiboardSetItemStyle(mbitem, showValue, showIcon)
                    call MultiboardReleaseItem(mbitem)
                endif
            endloop
        endif
    endloop
endfunction

JASS:
function MultiboardSetItemValueBJ takes multiboard mb, integer col, integer row, string val returns nothing
    local integer curRow = 0
    local integer curCol = 0
    local integer numRows = MultiboardGetRowCount(mb)
    local integer numCols = MultiboardGetColumnCount(mb)
    local multiboarditem mbitem = null

    loop
        set curRow = curRow + 1
        exitwhen curRow > numRows

        if (row == 0 or row == curRow) then
            set curCol = 0
            loop
                set curCol = curCol + 1
                exitwhen curCol > numCols

                if (col == 0 or col == curCol) then
                    set mbitem = MultiboardGetItem(mb, curRow - 1, curCol - 1)
                    call MultiboardSetItemValue(mbitem, val)
                    call MultiboardReleaseItem(mbitem)
                endif
            endloop
        endif
    endloop
endfunction

JASS:
function MultiboardSetItemWidthBJ takes multiboard mb, integer col, integer row, real width returns nothing
    local integer curRow = 0
    local integer curCol = 0
    local integer numRows = MultiboardGetRowCount(mb)
    local integer numCols = MultiboardGetColumnCount(mb)
    local multiboarditem mbitem = null

    loop
        set curRow = curRow + 1
        exitwhen curRow > numRows

        if (row == 0 or row == curRow) then
            set curCol = 0
            loop
                set curCol = curCol + 1
                exitwhen curCol > numCols

                if (col == 0 or col == curCol) then
                    set mbitem = MultiboardGetItem(mb, curRow - 1, curCol - 1)
                    call MultiboardSetItemWidth(mbitem, width/100.0)
                    call MultiboardReleaseItem(mbitem)
                endif
            endloop
        endif
    endloop
endfunction

And he's calling me crazy.....
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
Notice how the BJs all operate on conditions, and that to do any one thing is very easy. Especially the multiboard ones, they would be 2-3 lines if not for the -1 option.

Eg;

JASS:
//to set multiple values;
function Bleh takes nothing returns nothing
    local multiboarditem mbi = MultiboardGetItem(someMB,1,1)
    call MultiboardSetItemIcon(mbi,"Blah.blp")
    call MultiboardSetItemWidth(mbi,3)
    call MultiboardSetItemValue(mbi,"Hello")
    set mbi = null
endfunction
//to set only 1 value;
function Bleh2 takes nothing returns nothing
    call MultiboardSetItemIcon(MultiboardGetItem(someMB,1,1),"Blah.blp")
endfunction
//to set all values;
function Bleh3 takes nothing returns nothing
    call MultiboardSetItemsIcon(someMB,"Blah.blp")
endfunction

I rest my case.
 
Level 13
Joined
Nov 22, 2006
Messages
1,260
You rest whatever you want, the multiboard functions were just a "by-the-way" example. The main things were those cinematic ones, but nevermind, you are right about the multiboard ones.

~Topic closed (always wanted to say that :p)
 
Level 4
Joined
Jun 8, 2004
Messages
66
Should definitely get rid of the BJ functions asap. I'm finding out the hard way how annoyingly tedius it is to replace bj functions with your own, especially when you're resorting the argument lists to either match natives or just be more intuitive.

The map will benefit from the work though.

For some more examples of how retarded the BJ functions are, in many of the places where you set an object's color, they assume that people can't convert percents to regular 0-255 RGB values, and they reverse 0-100 to 100-0 for the opacity percentages (which are later converted to 0-255 ranges) because they also assume that nobody has a clue what opacity is.

Some of the wrapper functions just reorder arguments - but they don't even do it intuitively. Columns before rows for multiboard item assignments? wtf.
 
Level 7
Joined
Nov 12, 2005
Messages
299
A wrapper usually takes twice the time a native call would take. Of course this is not a good estimation as the time natives take varies, but that's pretty much the case with the majority.
However this shouldn't worry you - most natives (exception being the game cache ones for example) are actually very fast and you'll generally never notice the difference between using natives and BJs.
 
Status
Not open for further replies.
Top