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

Optimize Multiboard BJ functions

Status
Not open for further replies.
Level 20
Joined
Jul 14, 2011
Messages
3,213
Hi!

I'm checking on Multiboard functions but I can't get to understand them. I just can't figure out the way to do the multiboard functions manuallly, to avoid the BJ thing.

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 over rows, using 1-based index
    loop
        set curRow = curRow + 1
        exitwhen curRow > numRows

        // Apply setting to the requested row, or all rows (if row is 0)
        if (row == 0 or row == curRow) then
            // Loop over columns, using 1-based index
            set curCol = 0
            loop
                set curCol = curCol + 1
                exitwhen curCol > numCols

                // Apply setting to the requested column, or all columns (if col is 0)
                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
 
Level 16
Joined
Oct 12, 2008
Messages
1,570
This can be done easier, depending on the parameters. The thing is, when you do:
MultiboardSetItemValueBJ(mb, col, row, val), where neither row nor col are 0, ( col != 0 and row != 0), then you can just do the following:
JASS:
local multiboarditem mbitem = MultiboardGetItem(mb, row - 1, col - 1)
call MultiboardSetItemValue(mbitem, val)
call MultiboardReleaseItem(mbitem)'
set mbitem = null
(This assumes the parameters row and col are 1-based index variables, meaning if you have 5 rows and you want to edit the 2nd row, you enter the value 2 as row )

However, when either col or row are 0 (or both), then you will have to loop, like they do above..

Hope this is clear enough..
 
Level 20
Joined
Jul 14, 2011
Messages
3,213
Well.. I had this trigger updating the multiboard, running everytime a value in the multiboard changes... So I changed
JASS:
function Trig_Multiboard_Update_Func008A takes nothing returns nothing
    set udg_Rows = ( udg_Rows + 1 )
    set udg_Player = GetEnumPlayer()
    set udg_Integer1 = GetConvertedPlayerId(udg_Player)
    call MultiboardSetItemValueBJ( udg_MB, 2, udg_Rows, ( udg_Color[udg_Integer1] + ( I2S(udg_PlayerKills[udg_Integer1]) + "|r" ) ) )
    call MultiboardSetItemValueBJ( udg_MB, 3, udg_Rows, ( udg_Color[udg_Integer1] + ( I2S(udg_PlayerDeads[udg_Integer1]) + "|r" ) ) )
    call MultiboardSetItemValueBJ( udg_MB, 4, udg_Rows, ( udg_Color[udg_Integer1] + ( I2S(udg_PlayerScore[udg_Integer1]) + "|r" ) ) )
endfunction

function Trig_Multiboard_Update_Func016A takes nothing returns nothing
    set udg_Rows = ( udg_Rows + 1 )
    set udg_Player = GetEnumPlayer()
    set udg_Integer1 = GetConvertedPlayerId(udg_Player)
    call MultiboardSetItemValueBJ( udg_MB, 2, udg_Rows, ( udg_Color[udg_Integer1] + ( I2S(udg_PlayerKills[udg_Integer1]) + "|r" ) ) )
    call MultiboardSetItemValueBJ( udg_MB, 3, udg_Rows, ( udg_Color[udg_Integer1] + ( I2S(udg_PlayerDeads[udg_Integer1]) + "|r" ) ) )
    call MultiboardSetItemValueBJ( udg_MB, 4, udg_Rows, ( udg_Color[udg_Integer1] + ( I2S(udg_PlayerScore[udg_Integer1]) + "|r" ) ) )
endfunction

function Trig_Multiboard_Update_Actions takes nothing returns nothing
    set udg_Rows = 1
    // Team 1 Totals
    set udg_Rows = ( udg_Rows + 1 )
    call MultiboardSetItemValueBJ( udg_MB, 2, udg_Rows, ( "|cff7fff00" + ( I2S(udg_GoodiesKills) + "|r" ) ) )
    call MultiboardSetItemValueBJ( udg_MB, 3, udg_Rows, ( "|cff7fff00" + ( I2S(udg_GoodiesDeads) + "|r" ) ) )
    call MultiboardSetItemValueBJ( udg_MB, 4, udg_Rows, ( "|cff7fff00" + ( I2S(( udg_GoodiesKills - udg_GoodiesDeads )) + "|r" ) ) )
    // Team 1 Names / Kills / Deads / Score
    call ForForce( udg_Goodies, function Trig_Multiboard_Update_Func008A )
    set udg_Rows = ( udg_Rows + 1 )
    // Team 2 Totals
    set udg_Rows = ( udg_Rows + 1 )
    call MultiboardSetItemValueBJ( udg_MB, 2, udg_Rows, ( "|cff800080" + ( I2S(udg_BaddiesKills) + "|r" ) ) )
    call MultiboardSetItemValueBJ( udg_MB, 3, udg_Rows, ( "|cff800080" + ( I2S(udg_BaddiesDeads) + "|r" ) ) )
    call MultiboardSetItemValueBJ( udg_MB, 4, udg_Rows, ( "|cff800080" + ( I2S(( udg_BaddiesKills - udg_BaddiesDeads )) + "|r" ) ) )
    // Team 2 Names / Kills / Deads / Score
    call ForForce( udg_Baddies, function Trig_Multiboard_Update_Func016A )
endfunction

//===========================================================================
function InitTrig_Multiboard_Update takes nothing returns nothing
    set gg_trg_Multiboard_Update = CreateTrigger(  )
    call TriggerAddAction( gg_trg_Multiboard_Update, function Trig_Multiboard_Update_Actions )
endfunction
For this
JASS:
// Multiboard Update
function GooodiesUpdate takes nothing returns nothing
    local integer i = GetPlayerId(GetEnumPlayer())+1
    set udg_Rows = ( udg_Rows + 1 )
    call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 2 - 1), udg_Color[i] + I2S(udg_PlayerKills[i]) + "|r")
    call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 3 - 1), udg_Color[i] + I2S(udg_PlayerDeads[i]) + "|r")
    call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 4 - 1), udg_Color[i] + I2S(udg_PlayerScore[i]) + "|r")
endfunction

function BaddiesUpdate takes nothing returns nothing
    local integer i = GetPlayerId(GetEnumPlayer())+1
    set udg_Rows = ( udg_Rows + 1 )
    call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 2 - 1), udg_Color[i] + I2S(udg_PlayerKills[i]) + "|r")
    call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 3 - 1), udg_Color[i] + I2S(udg_PlayerDeads[i]) + "|r")
    call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 4 - 1), udg_Color[i] + I2S(udg_PlayerScore[i]) + "|r")
endfunction

function MBUpdate takes nothing returns nothing
    set udg_Rows = 1
    // Team 1 Totals
    set udg_Rows = ( udg_Rows + 1 )
    call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 2 - 1), "|cff7fff00" + I2S(udg_GoodiesKills) + "|r")
    call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 3 - 1), "|cff7fff00" + I2S(udg_GoodiesDeads) + "|r")
    call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 4 - 1), "|cff7fff00" + I2S(udg_GoodiesKills - udg_GoodiesDeads) + "|r")
    // Team 1 Names / Kills / Deads / Score
    call ForForce( udg_Goodies, function GooodiesUpdate )
    set udg_Rows = ( udg_Rows + 1 )
    // Team 2 Totals
    set udg_Rows = ( udg_Rows + 1 )
    call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 2 - 1), "|cff800080" + I2S(udg_BaddiesKills) + "|r")
    call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 3 - 1), "|cff800080" + I2S(udg_BaddiesDeads) + "|r")
    call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 4 - 1), "|cff800080" + I2S(udg_BaddiesKills - udg_BaddiesDeads) + "|r")
    // Team 2 Names / Kills / Deads / Score
    call ForForce( udg_Baddies, function BaddiesUpdate )
endfunction

<< EDIT >> I removed all the call MultiboardReleaseItem(mbitem) and still works fine. I wonder what does that function does.

<< EDIT >> Avoid the use of the mbitem local creation and constantly setting and null'ing by directly setting the Itemvalue in the MultiboardSetItemValue

It works fine, but I'd like to know if there's still any other way to optimize it? Actually, i'd like to update just the row of the players that died/killed and both team totals. That would reduce multiboard updates from a max of 12 to just 4, but each player row is detected with the udg_Row global during all the updates =/
 
Last edited:
Level 13
Joined
Sep 13, 2010
Messages
550
JASS:
function MBUpdate takes nothing returns nothing
    local multiboarditem mbi
    local integer i = 0
    set udg_Rows = 1
    // Team 1 Totals
    set mbi = MultiboardGetItem( udg_MB , udg_Rows , 1 )
    call MultiboardSetItemValue( mbi , "|cff7fff00" + I2S(udg_GoodiesKills) + "|r")
    call MultiboardReleaseItem( mbi )
    set mbi = MultiboardGetItem( udg_MB , udg_Rows , 2 )
    call MultiboardSetItemValue( mbi , "|cff7fff00" + I2S(udg_GoodiesDeads) + "|r")
    call MultiboardReleaseItem( mbi )
    set mbi = MultiboardGetItem( udg_MB , udg_Rows , 3 )
    call MultiboardSetItemValue( mbi , "|cff7fff00" + I2S(udg_GoodiesKills - udg_GoodiesDeads) + "|r")
    // Team 1 Names / Kills / Deads / Score
    loop
        set i = i + 1
        if IsPlayerInForce( Player( i - 1 ) , udg_Goodies ) then
            set udg_Rows = udg_Rows + 1
            set mbi = MultiboardGetItem( udg_MB , udg_Rows , 1 )
            call MultiboardSetItemValue( mbi , udg_Color[i] + I2S(udg_PlayerKills[i]) + "|r")
            call MultiboardReleaseItem( mbi )
            set mbi = MultiboardGetItem( udg_MB , udg_Rows , 2 )
            call MultiboardSetItemValue( mbi , udg_Color[i] + I2S(udg_PlayerDeads[i]) + "|r")
            call MultiboardReleaseItem( mbi )
            set mbi = MultiboardGetItem( udg_MB , udg_Rows , 3 )
            call MultiboardSetItemValue( mbi , udg_Color[i] + I2S(udg_PlayerScore[i]) + "|r")
            call MultiboardReleaseItem( mbi )
        endif
        exitwhen i == 12 // change it to any max( except over 12 ofc )
    endloop
    // Team 2 Totals
    set udg_Rows = udg_Rows + 1
    set mbi = MultiboardGetItem( udg_MB , udg_Rows , 1 )
    call MultiboardSetItemValue( mbi , "|cff7fff00" + I2S(udg_BaddiesKills) + "|r")
    call MultiboardReleaseItem( mbi )
    set mbi = MultiboardGetItem( udg_MB , udg_Rows , 2 )
    call MultiboardSetItemValue( mbi , "|cff7fff00" + I2S(udg_BaddiesDeads) + "|r")
    call MultiboardReleaseItem( mbi )
    set mbi = MultiboardGetItem( udg_MB , udg_Rows , 3 )
    call MultiboardSetItemValue( mbi , "|cff7fff00" + I2S(udg_BaddiesKills - udg_BaddiesDeads) + "|r")
    // Team 2 Names / Kills / Deads / Score
    set i = 0
    loop
        set i = i + 1
        if IsPlayerInForce( Player( i - 1 ) , udg_Baddies ) then
            set udg_Rows = udg_Rows + 1
            set mbi = MultiboardGetItem( udg_MB , udg_Rows , 1 )
            call MultiboardSetItemValue( mbi , udg_Color[i] + I2S(udg_PlayerKills[i]) + "|r")
            call MultiboardReleaseItem( mbi )
            set mbi = MultiboardGetItem( udg_MB , udg_Rows , 2 )
            call MultiboardSetItemValue( mbi , udg_Color[i] + I2S(udg_PlayerDeads[i]) + "|r")
            call MultiboardReleaseItem( mbi )
            set mbi = MultiboardGetItem( udg_MB , udg_Rows , 3 )
            call MultiboardSetItemValue( mbi , udg_Color[i] + I2S(udg_PlayerScore[i]) + "|r")
            call MultiboardReleaseItem( mbi )
        endif
        exitwhen i == 12
    endloop
    set mbi = null
endfunction
This have some optimizations, like not force iterations( vjassers there are mad of forgroup and forforce stuff, cause they create few instances, etc. ), also a lot of unnecessarily repeated math operations.

Also, the MultiboardReleaseItem is like RemoveUnit or RemoveLocation, it frees up the mbi, and can be nulled to avoid ugly things called handle leaks. I don't know if this was a bug in 1.24, or it is still there in 1.26( sadly I couldn't reproduce this :< ) but warcraft punishes lazy nondestroying dudes:

99098d1299606260-multiboard-bug-ftw.jpg


This is the reason to release multiboarditems. ;D
 
Level 20
Joined
Jul 14, 2011
Messages
3,213
So.. getting rid of using the mbi, and instead set the value of mbi directly as an argument in MultiboardSetItemValue (as I did) would leak? Why?

Also, since Goodies goes from Jassed 0-4 and Baddies from 5-9, I didn't set i = 0 between loops, and didn't loop 'till 12 in both. Tested and works (at lest for 1 player on testmap)

This is what I got. Almost same than yours, but you're using the mbitem and i'm setting that value directly in the MultiboardSetItemValue(). Also, manually set the column values to avoid all that Col-1 thing.
JASS:
// Multiboard Update
function MBUpdate takes nothing returns nothing
    local integer i = 0
    set udg_Rows = 1
    // Team 1 Totals
    set udg_Rows = ( udg_Rows + 1 )
    call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 1), "|cff7fff00" + I2S(udg_GoodiesKills) + "|r")
    call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 2), "|cff7fff00" + I2S(udg_GoodiesDeads) + "|r")
    call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 3), "|cff7fff00" + I2S(udg_GoodiesKills - udg_GoodiesDeads) + "|r")
    // Team 1 Names / Kills / Deads / Score
    loop
        set i = i+1
        if IsPlayerInForce(Player(i-1), udg_Goodies) then
            set udg_Rows = ( udg_Rows + 1 )
            call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 1), udg_Color[i] + I2S(udg_PlayerKills[i]) + "|r")
            call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 2), udg_Color[i] + I2S(udg_PlayerDeads[i]) + "|r")
            call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 3), udg_Color[i] + I2S(udg_PlayerScore[i]) + "|r")
        endif
        exitwhen i == 5
    endloop
    set udg_Rows = ( udg_Rows + 2 )
    // Team 2 Totals
    call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 1), "|cff800080" + I2S(udg_BaddiesKills) + "|r")
    call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 2), "|cff800080" + I2S(udg_BaddiesDeads) + "|r")
    call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 3), "|cff800080" + I2S(udg_BaddiesKills - udg_BaddiesDeads) + "|r")
    // Team 2 Names / Kills / Deads / Score
        loop
        set i = i+1
        if IsPlayerInForce(Player(i-1), udg_Baddies) then
            set udg_Rows = ( udg_Rows + 1 )
            call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 1), udg_Color[i] + I2S(udg_PlayerKills[i]) + "|r")
            call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 2), udg_Color[i] + I2S(udg_PlayerDeads[i]) + "|r")
            call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 3), udg_Color[i] + I2S(udg_PlayerScore[i]) + "|r")
        endif
        exitwhen i == 10
    endloop
endfunction
 
Level 13
Joined
Sep 13, 2010
Messages
550
Why? As I explained, MultiboardReleaseItem is like RemoveLocation or any other handle destructor native. You know why you have to remove locations after use, right? If you do know, then you may know the "Handle leaks" as well. If not, I can explain it shortly.


Whenever a handle is assigned to a value Warcraft will not recycle the handle ID till every variable it is stored in is nulled, or other value is assigned to it. Globals usually get reused, so handle IDs in globals get recycled sooner or later. But the locals, are dangerous this way, since when function ends, Warcraft does not realize that the local is not existing anymore and handle is not assigned to it, to avoid, at the end of a function you have to null them.

*since 1.26( or 1.24? ) argument locals does not leak, so you don't have to null the "g" of a function XYZ takes group g returns nothing call.


And, multiboarditem extends handle so they DO LEAK if they are not destroyed, not even nulled. Just test it, I made a test map for you with leaking the mbi, and tracking the handle's count( of course the two different library does not call each other and I am not cheating this way :p )

Also you are repeating integer operations again:
JASS:
set udg_Rows = ( udg_Rows + 1 ) 
call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 1), "|cff7fff00" + I2S(udg_GoodiesKills) + "|r") 
call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 2), "|cff7fff00" + I2S(udg_GoodiesDeads) + "|r") 
call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows - 1, 3), "|cff7fff00" + I2S(udg_GoodiesKills - udg_GoodiesDeads) + "|r")
instead of

JASS:
call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows, 1), "|cff7fff00" + I2S(udg_GoodiesKills) + "|r") 
call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows, 2), "|cff7fff00" + I2S(udg_GoodiesDeads) + "|r") 
call MultiboardSetItemValue(MultiboardGetItem(udg_MB, udg_Rows, 3), "|cff7fff00" + I2S(udg_GoodiesKills - udg_GoodiesDeads) + "|r")
set udg_Rows = ( udg_Rows + 1 )
can you see the change, right? Overall I recommend you to use mine, with changing exitwhen and removing the set i = 0 I put there cause I didn't know how your players used :)
 

Attachments

  • MBILeaktest.w3x
    13.5 KB · Views: 57
Level 20
Joined
Jul 14, 2011
Messages
3,213
Ok... I think I got ti so far... I got rid of the whole MBUpdate function and made it specific for each player. When the Multiboard is created, the Row of each player/team is stored in arrays based on player index. When a player kills/dies, both players and both team scores are updated. This improves a lot of things, but I've been here like 5 hours trying to make it work xD
 
Status
Not open for further replies.
Top