• 🏆 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] BJ Functions

Status
Not open for further replies.
Level 14
Joined
Apr 20, 2009
Messages
1,543
hey all, I heard that it's better to avoid BJ functions in your map...

So can anybody give me a list of BJ functions that you can better avoid in your map by replacing it with original functions?

example:

DestroySpecialEffectBJ -> DestroySpecialEffect

I need this because I am going to change every single BJ function in my GUI into normal functions and I need to know which ones I can change :)
 
Level 14
Joined
Apr 20, 2009
Messages
1,543
ok thanks, thats the only thing I needed to know... Now I can change every BJ function... (Thought maybe there are some BJ functions that doesn't have their native functions)

may I ask why they have to be changed b.t.w.?
 
Level 14
Joined
Apr 20, 2009
Messages
1,543
They have a "BJ" in their name... how hard to find.

You can check what a function does and see if it is worth it too, seeing as there are some BJs that will look exactly like your code without them.

I know that they are not hard to find, but I am changing every action that I have in my trigger editor (in GUI) to change into a function without the BJ added. That's taking me a lot of time and I wanted to be sure to change it correctly...
 
Level 11
Joined
May 16, 2007
Messages
288
I know that they are not hard to find, but I am changing every action that I have in my trigger editor (in GUI) to change into a function without the BJ added. That's taking me a lot of time and I wanted to be sure to change it correctly...

You should be careful with that, there are BJ functions that you can inline (turn into a native function, basically what you're doing) just by removing the BJ, but there are others like PolarProjectionBJ that are different and just removing the BJ won't work, for example:

A function that can be inlined simply by removing BJ:

JASS:
function StopMusicBJ takes boolean fadeOut returns nothing
    call StopMusic(fadeOut)
endfunction
//this BJ function simply calls a native with the same name
//removing the BJ is enough to inline it

A function that can't be inlined simply removing the BJ, you have to do more to properly inline it:

JASS:
function PolarProjectionBJ takes location source, real dist, real angle returns location
    local real x = GetLocationX(source) + dist * Cos(angle * bj_DEGTORAD)
    local real y = GetLocationY(source) + dist * Sin(angle * bj_DEGTORAD)
    return Location(x, y)
endfunction
//removing the BJ won't work here
//since the function PolarProjection doesn't exist
//to inline this you'll have to write the function's code
//in your trigger, while paying attention to remove
//any unecessary part (the return location, for example)

Hope this helped you.
 
Level 14
Joined
Apr 20, 2009
Messages
1,543
but why? why should they be avoided??

EDIT: I'm NOT creating a script in jass.... I'm changing the trigger editor to my needs by removing all BJ functions in GUI.... This is what I mean:

http://world-editor-tutorials.thehelper.net/cat_usersubmit.php?view=79059

so I want to know why we should avoid BJ functions, because almost every single action in GUI is a BJ function...
Look in that tutorial if you want to know what I mean...

EDIT:
You should be careful with that, there are BJ functions that you can inline (turn into a native function, basically what you're doing) just by removing the BJ, but there are others like PolarProjectionBJ that are different and just removing the BJ won't work, for example:

A function that can be inlined simply by removing BJ:

JASS:
function StopMusicBJ takes boolean fadeOut returns nothing
    call StopMusic(fadeOut)
endfunction
//this BJ function simply calls a native with the same name
//removing the BJ is enough to inline it

A function that can't be inlined simply removing the BJ, you have to do more to properly inline it:

JASS:
function PolarProjectionBJ takes location source, real dist, real angle returns location
    local real x = GetLocationX(source) + dist * Cos(angle * bj_DEGTORAD)
    local real y = GetLocationY(source) + dist * Sin(angle * bj_DEGTORAD)
    return Location(x, y)
endfunction
//removing the BJ won't work here
//since the function PolarProjection doesn't exist
//to inline this you'll have to write the function's code
//in your trigger, while paying attention to remove
//any unecessary part (the return location, for example)

Hope this helped you.

I am not trying to inline... I just want to know what the BJ function means... Does it mean that it slows down something? Does it mean that it leaks?? I have no idea... Please inform me....

EDIT:
(ow sry I didn't read correctly.... so what would you suggest me to do? which BJ functions should I remove and which one should I not? How can I see that the function exists?)
 
Last edited:
Level 6
Joined
Apr 16, 2007
Messages
177
Every time you call a function in JASS, it needs some processing time.
Since most BJs are proxies (just calling another function with almost the same arguments), you get 2 function calls where you'ld just need one (the native call + the bj that is calling the native).
Those BJ's that aren't proxies are often quite useful.
 
Level 11
Joined
May 16, 2007
Messages
288
Why should we avoid BJs? Well, think for a moment.
What would be faster:

Ask someone to get an apple for you.

Ask someone to ask someone to get an apple for you.

BJ functions are basically this, you are calling a function that simply calls another function, wouldn't it be faster to just call the function itself instead of calling the BJ?

Why all GUI functions are BJs? Hell if I know, Blizzard does some crazy things with JASS.

But as SerraAvenger said, there are a few BJs that could be useful, for example, TriggerRegisterAnyUnitEventBJ is a BJ, but since it does a lot more than just calling TriggerRegisterAnyUnitEvent, it can be useful (and in some cases, faster), than inlining the function.

Hashjie said:
which BJ functions should I remove and which one should I not? How can I see that the function exists?

JassCraft (http://www.wc3c.net/showthread.php?t=80051) is a great program for this, it has a function list and allows you to see the code of each function (except for natives, but you shouldn't worry about that).
 
Level 14
Joined
Apr 20, 2009
Messages
1,543
Why should we avoid BJs? Well, think for a moment.
What would be faster:

Ask someone to get an apple for you.

Ask someone to ask someone to get an apple for you.

BJ functions are basically this, you are calling a function that simply calls another function, wouldn't it be faster to just call the function itself instead of calling the BJ?

Why all GUI functions are BJs? Hell if I know, Blizzard does some crazy things with JASS.

But as SerraAvenger said, there are a few BJs that could be useful, for example, TriggerRegisterAnyUnitEventBJ is a BJ, but since it does a lot more than just calling TriggerRegisterAnyUnitEvent, it can be useful (and in some cases, faster), than inlining the function.



JassCraft (http://www.wc3c.net/showthread.php?t=80051) is a great program for this, it has a function list and allows you to see the code of each function (except for natives, but you shouldn't worry about that).

ok thanks a lot for explaining I fully understand now +rep to you....

and does this mean that whenever a BJ function has a native function that it can be replaced??
 

Cokemonkey11

Spell Reviewer
Level 29
Joined
May 9, 2006
Messages
3,534
ok thanks a lot for explaining I fully understand now +rep to you....

and does this mean that whenever a BJ function has a native function that it can be replaced??

I've found certain excuses. Using GetDyingDestructable() simply returns GetTriggerWidget(), however replacing the fore with the latter can and will cause problems.

Here is a simple trigger in a map of mine:

JASS:
function Trig_Regrow_Trees_Actions takes nothing returns nothing
    call TriggerSleepAction(1)
    call SetDestructableAnimation(GetDyingDestructable(),"Birth")//GetDyingDestructable cannot be simplified to it's native...why?
    call SetDestructableAnimationSpeed(GetDyingDestructable(),3)
    call TriggerSleepAction(19.6)
    call SetDestructableAnimation(GetDyingDestructable(),"stand")
    call SetDestructableAnimationSpeed(GetDyingDestructable(),1)
    call DestructableRestoreLife(GetDyingDestructable(),GetDestructableMaxLife(bj_lastCreatedDestructable),false)
endfunction

function InitTrig_regrowTrees takes nothing returns nothing
    set gg_trg_regrowTrees = CreateTrigger()
    call TriggerRegisterDestDeathInRegionEvent(gg_trg_regrowTrees,bj_mapInitialPlayableArea)
    call TriggerAddAction(gg_trg_regrowTrees,function Trig_Regrow_Trees_Actions)
endfunction
 
Level 14
Joined
Apr 20, 2009
Messages
1,543
Not at all, it hardly takes any time. But it happens hundreds of thousands times, which over time does consume time (now isn't this a silly-paradox looking sentence?).

yes it is and that sentence is exactly the reason why I want it out of my GUI triggers...
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
The typical TriggerRegisterEvent only happens once per game (exceptions are very rare), and thus being a BJ doesn't really matter. Other BJ functions worth using would be BJDebugMsg, which too is an additional call, but nobody cares about that because it's used for debugging...

Also, getting rid of BJ functions in GUI triggers is, to say the least, pretty stupid. Just write directly in jass or stick to gui, because BJ's aren't the only reason why GUI leads to inefficient triggers.
 
Level 6
Joined
Sep 5, 2007
Messages
264
I've found certain excuses. Using GetDyingDestructable() simply returns GetTriggerWidget(), however replacing the fore with the latter can and will cause problems.

Here is a simple trigger in a map of mine:

JASS:
function Trig_Regrow_Trees_Actions takes nothing returns nothing
    call TriggerSleepAction(1)
    call SetDestructableAnimation(GetDyingDestructable(),"Birth")//GetDyingDestructable cannot be simplified to it's native...why?
    call SetDestructableAnimationSpeed(GetDyingDestructable(),3)
    call TriggerSleepAction(19.6)
    call SetDestructableAnimation(GetDyingDestructable(),"stand")
    call SetDestructableAnimationSpeed(GetDyingDestructable(),1)
    call DestructableRestoreLife(GetDyingDestructable(),GetDestructableMaxLife(bj_lastCreatedDestructable),false)
endfunction

function InitTrig_regrowTrees takes nothing returns nothing
    set gg_trg_regrowTrees = CreateTrigger()
    call TriggerRegisterDestDeathInRegionEvent(gg_trg_regrowTrees,bj_mapInitialPlayableArea)
    call TriggerAddAction(gg_trg_regrowTrees,function Trig_Regrow_Trees_Actions)
endfunction

Well I can tell you, at a glance, why that doesn't work...
JASS:
    call TriggerSleepAction(1)
    call SetDestructableAnimation(GetDyingDestructable(),"Birth")//GetDyingDestructable
The GetDyingDestructable() function checks for the last dying destructable, and after a wait.... well, things aren't always what you think. You'd just have to use a local variable:
JASS:
    local destructable tree = GetDyingDestructable()
    call TriggerSleepAction(1)
    call SetDestructableAnimation(tree, "Birth")//GetDyingDestructable
Now THAT would work. :thumbs_up:
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
BJs were fail functions made by blizzard for their GUI engine. They basically were redirectors allowing them to change how they were used in GUI. Blizzard never meant triggers to be heavily used and have to actually need speed, so them being so slow was no problem. However complex spells and systems can be quite demanding, thus as much optimization as possiable is required for maps to be playable.

Just like leaks, WC3 was not made to support so many of them occuring.
 

Cokemonkey11

Spell Reviewer
Level 29
Joined
May 9, 2006
Messages
3,534
Well I can tell you, at a glance, why that doesn't work...
JASS:
    call TriggerSleepAction(1)
    call SetDestructableAnimation(GetDyingDestructable(),"Birth")//GetDyingDestructable
The GetDyingDestructable() function checks for the last dying destructable, and after a wait.... well, things aren't always what you think. You'd just have to use a local variable:
JASS:
    local destructable tree = GetDyingDestructable()
    call TriggerSleepAction(1)
    call SetDestructableAnimation(tree, "Birth")//GetDyingDestructable
Now THAT would work. :thumbs_up:

Can't believe I didn't notice the non instanceability there. But regardless I was talking about the fact that Dying Destructable is a BJ function which simply calls Trigger Widget, but if you simplify it to that native it stops working.
 
Level 14
Joined
Apr 20, 2009
Messages
1,543
Also, getting rid of BJ functions in GUI triggers is, to say the least, pretty stupid. Just write directly in jass or stick to gui, because BJ's aren't the only reason why GUI leads to inefficient triggers.

and why is that? You don't want gui users to become as powerfull as jass users some day? I'm just trying to improve my gui to make it more efficient... If you dissagree with that then I don't care... As long as it improves my experiences AND my triggers I don't care what you think about the differences between them :)
 
Level 14
Joined
Nov 18, 2007
Messages
816
GUI uses triggers for every fucking thing you can find (heck, even dynamic triggers, which are considered really bad practice among vJass coders). JASS uses triggers as well, but not as extensively. Understanding where to apply what solution is crucial to writing safe and efficient code. You will never write good JASS code by converting and optimizing GUI generated code (unless you actually rewrite everything, in which case you dont need to write anything in GUI anymore).
 
Last edited:
Level 14
Joined
Nov 18, 2007
Messages
816
damage detection is an exception, since blizzard forgot adding EVENT_PLAYER_UNIT_DAMAGED (then again, there are exceptions to this exception, in cases like conditional damage detection, where you only add those units you want to detect damage for; either you detect damage for all units or none). I believe the unit state events also fall in this category.
 
Level 13
Joined
Nov 22, 2006
Messages
1,260
I don't think anyone mentioned that BJs don't always have to end with "BJ", they can end with Swapped or they don't even have to have a characteristic suffix at all. Just to note one really stupid BJ:

JASS:
function IsUnitAliveBJ takes unit whichUnit returns boolean

    return not IsUnitDeadBJ(whichUnit)

endfunction

JASS:
function IsUnitDeadBJ takes unit whichUnit returns boolean

    return GetUnitState(whichUnit, UNIT_STATE_LIFE) <= 0

endfunction

Well, ain't that dumb... This checks if the unit is alive by checking if unit is not dead, which then checks if the unit's health is less than or equal to 0.

Also, here's an example of a useful BJ:

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

        // Fade out to the requested color.

        call AbortCinematicFadeBJ()

        call CinematicFadeCommonBJ(red, green, blue, duration, tex, 100, trans)

    elseif (fadetype == bj_CINEFADETYPE_FADEIN) then

        // Fade in from the requested color.

        call AbortCinematicFadeBJ()

        call CinematicFadeCommonBJ(red, green, blue, duration, tex, trans, 100)

        call FinishCinematicFadeAfterBJ(duration)

    elseif (fadetype == bj_CINEFADETYPE_FADEOUTIN) then

        // Fade out to the requested color, and then fade back in from it.

        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

        // Unrecognized fadetype - ignore the request.

    endif

endfunction

Look what list of BJs it uses:

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

        // If the fade is instant, use the same starting and ending values,

        // so that we effectively do a set rather than a fade.

        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 FinishCinematicFadeAfterBJ takes real duration returns nothing

    // Create a timer to end the cinematic fade.

    set bj_cineFadeFinishTimer = CreateTimer()

    call TimerStart(bj_cineFadeFinishTimer, duration, false, function FinishCinematicFadeBJ)

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



    // Create a timer to continue the cinematic fade.

    set bj_cineFadeContinueTimer = CreateTimer()

    call TimerStart(bj_cineFadeContinueTimer, duration, false, function ContinueCinematicFadeBJ)

endfunction

JASS:
function PercentTo255 takes real percentage returns integer

    return PercentToInt(percentage, 255)

endfunction

JASS:
function PercentToInt takes real percentage, integer max returns integer

    local integer result = R2I(percentage * I2R(max) * 0.01)



    if (result < 0) then

        set result = 0

    elseif (result > max) then

        set result = max

    endif



    return result

endfunction

Not to mention how much times those BJs are called. Note that these are only BJs that are used, there are also thousands of natives called too.

I mean sweet jesus.
 
Status
Not open for further replies.
Top