• 🏆 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] Problem with an auto index system not deindexing

Status
Not open for further replies.
I recently stumbled upon a problem with this auto mui system by Ruke where it eventually climbs past max array size... limit is set in the variable manager to 10 and instance is this part
JASS:
    local timer expiredTimer = GetExpiredTimer()
    local integer expiredTimerId = GetHandleId(expiredTimer)

    local integer instance = LoadInteger(udg_hashtable, expiredTimerId, 0)
call MUI_RecycleInstance(instance)
The part that's bugging, it only continues to increase until it can no longer work past max array size.
JASS:
function MUI_RecycleInstance takes integer instance returns nothing
    set instance = instance / udg_limit

    set udg_recycleNext[instance] = udg_recycle
    set udg_recycle = instance
endfunction


JASS:
// allocator
// thanks nestharus/vexorian c:
function MUI_CreateInstance takes nothing returns integer
    local integer instance

    if ( udg_recycle == 0 ) then
        set udg_instanceCount = udg_instanceCount + 1
        set instance = udg_instanceCount
    else
        set instance = udg_recycle
        set udg_recycle = udg_recycleNext[udg_recycle]
    endif

    // reserving space
    set instance = instance * udg_limit

    return instance
endfunction

// deallocator
// thanks nestharus/vexorian c:
function MUI_RecycleInstance takes integer instance returns nothing
    set instance = instance / udg_limit

    set udg_recycleNext[instance] = udg_recycle
    set udg_recycle = instance
endfunction

function MUI_ShowOverLimitError takes nothing returns nothing
    call BJDebugMsg("No puedes guardar mas de " + I2S(udg_limit) + ". Si necesitas mas, modifica la variable limit.\nYou can't save more than " + I2S(udg_limit) + ". If you need more, modify the variable called 'limit'")
endfunction

// private
function MUI_SaveUnits takes integer instance returns nothing
    local integer i = 1

    loop
        set udg_mui_unit[instance + i] = udg_set_unit[i]
        set udg_set_unit[i] = null

        exitwhen i == udg_used_units
        set i = i + 1
    endloop

    set udg_mui_used_units[instance] = udg_used_units
endfunction

// private
function MUI_SaveReals takes integer instance returns nothing
    local integer i = 1

    loop
        set udg_mui_real[instance + i] = udg_set_real[i]
        set udg_set_real[i] = 0.

        exitwhen i == udg_used_reals
        set i = i + 1
    endloop

    set udg_mui_used_reals[instance] = udg_used_reals
endfunction

// private
function MUI_SavePlayers takes integer instance returns nothing
    local integer i = 1

    loop
        set udg_mui_player[instance + i] = udg_set_player[i]
        set udg_set_player[i] = null

        exitwhen i == udg_used_players
        set i = i + 1
    endloop

    set udg_mui_used_players[instance] = udg_used_players
endfunction

// private
function MUI_SavePoints takes integer instance returns nothing
    local integer i = 1

    loop
        set udg_mui_point[instance + i] = udg_set_point[i]
        set udg_set_point[i] = null

        exitwhen i == udg_used_points
        set i = i + 1
    endloop

    set udg_mui_used_points[instance] = udg_used_points
endfunction

// private
function MUI_SaveEffects takes integer instance returns nothing
    local integer i = 1

    loop
        set udg_mui_effect[instance + i] = udg_set_effect[i]
        set udg_set_effect[i] = null

        exitwhen i == udg_used_effects
        set i = i + 1
    endloop

    set udg_mui_used_effects[instance] = udg_used_effects
endfunction

// private
function MUI_SaveIntegers takes integer instance returns nothing
    local integer i = 1

    loop
        set udg_mui_integer[instance + i] = udg_set_integer[i]
        set udg_set_integer[i] = 0

        exitwhen i == udg_used_integers
        set i = i + 1
    endloop

    set udg_mui_used_integers[instance] = udg_used_integers
endfunction

// private
function MUI_SaveUnitGroups takes integer instance returns nothing
    local integer i = 1

    loop
        set udg_mui_group[instance + i] = udg_set_group[i]
        set udg_set_group[i] = null

        exitwhen i == udg_used_groups
        set i = i + 1
    endloop

    set udg_mui_used_groups[instance] = udg_used_groups
endfunction

// private
function MUI_SaveBooleans takes integer instance returns nothing
    local integer i = 1

    loop
        set udg_mui_boolean[instance + i] = udg_set_boolean[i]
        set udg_set_boolean[i] = false

        exitwhen i == udg_used_booleans
        set i = i + 1
    endloop

    set udg_mui_used_booleans[instance] = udg_used_booleans
endfunction

// private
function MUI_SaveDestructibles takes integer instance returns nothing
    local integer i = 1

    loop
        set udg_mui_destructible[instance + i] = udg_set_destructible[i]
        set udg_set_destructible[i] = null

        exitwhen i == udg_used_destructibles
        set i = i + 1
    endloop

    set udg_mui_used_destructibles[instance] = udg_used_destructibles
endfunction

// private
function MUI_Periodic takes nothing returns nothing
    local timer expiredTimer = GetExpiredTimer()
    local integer expiredTimerId = GetHandleId(expiredTimer)

    local integer instance = LoadInteger(udg_hashtable, expiredTimerId, 0)

    local integer i
   
    // avoid recursion problems
    local unit array prevGetUnit
    local real array prevGetReal
    local player array prevGetPlayer
    local location array prevGetPoint
    local effect array prevGetEffect
    local integer array prevGetInteger
    local group array prevGetGroup
    local boolean array prevGetBoolean
    local destructable array prevGetDestructible

    local boolean prevAutomaticClean = udg_automaticClean
    local boolean prevFinish = udg_finish

    // unit
    if ( udg_mui_used_units[instance] > 0 ) then
        set i = 1

        loop
            set prevGetUnit[i] = udg_get_unit[i]
            set udg_get_unit[i] = udg_mui_unit[instance + i]

            exitwhen i == udg_mui_used_units[instance]
            set i = i + 1
        endloop
    endif

    // real
    if ( udg_mui_used_reals[instance] > 0 ) then
        set i = 1

        loop
            set prevGetReal[i] = udg_get_real[i]
            set udg_get_real[i] = udg_mui_real[instance + i]

            exitwhen i == udg_mui_used_reals[instance]
            set i = i + 1
        endloop
    endif

    // player
    if ( udg_mui_used_players[instance] > 0 ) then
        set i = 1

        loop
            set prevGetPlayer[i] = udg_get_player[i]
            set udg_get_player[i] = udg_mui_player[instance + i]

            exitwhen i == udg_mui_used_players[instance]
            set i = i + 1
        endloop
    endif

    // location
    if ( udg_mui_used_points[instance] > 0 ) then
        set i = 1

        loop
            set prevGetPoint[i] = udg_get_point[i]
            set udg_get_point[i] = udg_mui_point[instance + i]

            exitwhen i == udg_mui_used_points[instance]
            set i = i + 1
        endloop
    endif

    // effect
    if ( udg_mui_used_effects[instance] > 0 ) then
        set i = 1

        loop
            set prevGetEffect[i] = udg_get_effect[i]
            set udg_get_effect[i] = udg_mui_effect[instance + i]

            exitwhen i == udg_mui_used_effects[instance]
            set i = i + 1
        endloop
    endif

    // integer
    if ( udg_mui_used_integers[instance] > 0 ) then
        set i = 1

        loop
            set prevGetInteger[i] = udg_get_integer[i]
            set udg_get_integer[i] = udg_mui_integer[instance + i]

            exitwhen i == udg_mui_used_integers[instance]
            set i = i + 1
        endloop
    endif

    // group
    if ( udg_mui_used_groups[instance] > 0 ) then
        set i = 1

        loop
            set prevGetGroup[i] = udg_get_group[i]
            set udg_get_group[i] = udg_mui_group[instance + i]

            exitwhen i == udg_mui_used_groups[instance]
            set i = i + 1
        endloop
    endif

    // boolean
    if ( udg_mui_used_booleans[instance] > 0 ) then
        set i = 1

        loop
            set prevGetBoolean[i] = udg_get_boolean[i]
            set udg_get_boolean[i] = udg_mui_boolean[instance + i]

            exitwhen i == udg_mui_used_booleans[instance]
            set i = i + 1
        endloop
    endif
   
    // destructible
    if ( udg_mui_used_destructibles[instance] > 0 ) then
        set i = 1

        loop
            set prevGetDestructible[i] = udg_get_destructible[i]
            set udg_get_destructible[i] = udg_mui_destructible[instance + i]

            exitwhen i == udg_mui_used_destructibles[instance]
            set i = i + 1
        endloop
    endif

    call TriggerExecute(LoadTriggerHandle(udg_hashtable, expiredTimerId, 1))

    // unit
    if ( udg_mui_used_units[instance] > 0 ) then
        set i = 1

        loop
            if ( udg_finish ) then
                set udg_mui_unit[instance + i] = null
            else
                set udg_mui_unit[instance + i] = udg_get_unit[i]
            endif

            set udg_get_unit[i] = prevGetUnit[i]
            set prevGetUnit[i] = null

            exitwhen i == udg_mui_used_units[instance]
            set i = i + 1
        endloop
    endif

    // real
    if ( udg_mui_used_reals[instance] > 0 ) then
        set i = 1

        loop
            if ( udg_finish ) then
                set udg_mui_real[instance + i] = 0.
            else
                set udg_mui_real[instance + i] = udg_get_real[i]
            endif

            set udg_get_real[i] = prevGetReal[i]

            exitwhen i == udg_mui_used_reals[instance]
            set i = i + 1
        endloop
    endif

    // player
    if ( udg_mui_used_players[instance] > 0 ) then
        set i = 1

        loop
            if ( udg_finish ) then
                set udg_mui_player[instance + i] = null
            else
                set udg_mui_player[instance + i] = udg_get_player[i]
            endif

            set udg_get_player[i] = prevGetPlayer[i]
            set prevGetPlayer[i] = null

            exitwhen i == udg_mui_used_players[instance]
            set i = i + 1
        endloop
    endif

    // location
    if ( udg_mui_used_points[instance] > 0 ) then
        set i = 1

        loop
            if ( udg_finish ) then
                if ( udg_automaticClean ) then
                    call RemoveLocation(udg_mui_point[instance + i])
                    call RemoveLocation(udg_get_point[i])
                endif

                set udg_mui_point[instance + i] = null
            else
                if ( udg_mui_point[instance + i] != udg_get_point[i] ) then
                    call RemoveLocation(udg_mui_point[instance + i])
                    set udg_mui_point[instance + i] = udg_get_point[i]
                endif
            endif

            set udg_get_point[i] = prevGetPoint[i]
            set prevGetPoint[i] = null

            exitwhen i == udg_mui_used_points[instance]
            set i = i + 1
        endloop
    endif

    // effect
    if ( udg_mui_used_effects[instance] > 0 ) then
        set i = 1

        loop
            if ( udg_finish ) then
                if ( udg_automaticClean ) then
                    call DestroyEffect(udg_mui_effect[instance + i])
                    call DestroyEffect(udg_get_effect[i])
                endif

                set udg_mui_effect[instance + i] = null
            else
                if ( udg_mui_effect[instance + i] != udg_get_effect[i] ) then
                    call DestroyEffect(udg_mui_effect[instance + i])
                    set udg_mui_effect[instance + i] = udg_get_effect[i]
                endif
            endif

            set udg_get_effect[i] = prevGetEffect[i]
            set prevGetEffect[i] = null

            exitwhen i == udg_mui_used_effects[instance]
            set i = i + 1
        endloop
    endif

    // integer
    if ( udg_mui_used_integers[instance] > 0 ) then
        set i = 1

        loop
            if ( udg_finish ) then
                set udg_mui_integer[instance + i] = 0
            else
                set udg_mui_integer[instance + i] = udg_get_integer[i]
            endif

            set udg_get_integer[i] = prevGetInteger[i]

            exitwhen i == udg_mui_used_integers[instance]
            set i = i + 1
        endloop
    endif

    // groups
    if ( udg_mui_used_groups[instance] > 0 ) then
        set i = 1

        loop
            if ( udg_finish ) then
                if ( udg_automaticClean ) then
                    call DestroyGroup(udg_mui_group[instance + i])
                    call DestroyGroup(udg_get_group[i])
                endif
                set udg_mui_group[instance + i] = null
            else
                if ( udg_mui_group[instance + i] != udg_get_group[i] ) then
                    call DestroyGroup(udg_mui_group[instance + i])
                    set udg_mui_group[instance + i] = udg_get_group[i]
                endif
            endif

            set udg_get_group[i] = prevGetGroup[i]
            set prevGetGroup[i] = null

            exitwhen i == udg_mui_used_groups[instance]
            set i = i + 1
        endloop
    endif

    // boolean
    if ( udg_mui_used_booleans[instance] > 0 ) then
        set i = 1

        loop
            if ( udg_finish ) then
                set udg_mui_boolean[instance + i] = false
            else
                set udg_mui_boolean[instance + i] = udg_get_boolean[i]
            endif

            set udg_get_boolean[i] = prevGetBoolean[i]

            exitwhen i == udg_mui_used_booleans[instance]
            set i = i + 1
        endloop
    endif
   
    // destructible
    if ( udg_mui_used_destructibles[instance] > 0 ) then
        set i = 1

        loop
            if ( udg_finish ) then
                if ( udg_automaticClean ) then
                    call RemoveDestructable(udg_mui_destructible[instance + i])
                    call RemoveDestructable(udg_get_destructible[instance + i])
                endif
                set udg_mui_destructible[instance + i] = null
            else
                set udg_mui_destructible[instance + i] = udg_get_destructible[i]
            endif

            set udg_get_destructible[i] = prevGetDestructible[i]

            exitwhen i == udg_mui_used_destructibles[instance]
            set i = i + 1
        endloop
    endif

    if ( udg_finish ) then
        set udg_mui_used_units[instance] = 0
        set udg_mui_used_reals[instance] = 0
        set udg_mui_used_players[instance] = 0
        set udg_mui_used_points[instance] = 0
        set udg_mui_used_effects[instance] = 0
        set udg_mui_used_integers[instance] = 0
        set udg_mui_used_groups[instance] = 0
        set udg_mui_used_booleans[instance] = 0
        set udg_mui_used_destructibles[instance] = 0
   
        call MUI_RecycleInstance(instance)
        call FlushChildHashtable(udg_hashtable, expiredTimerId)

        call PauseTimer(expiredTimer)
        call DestroyTimer(expiredTimer)
    endif

    set udg_automaticClean = prevAutomaticClean
    set udg_finish = prevFinish

    set expiredTimer = null
endfunction

// private
function MUI_OnTimeoutChange takes nothing returns nothing
    local timer periodicTimer = CreateTimer()
    local integer instance = MUI_CreateInstance()
           
    // units
    if ( udg_used_units > 0 ) then
        if ( udg_used_units > udg_limit ) then
            call MUI_ShowOverLimitError()
        else
            call MUI_SaveUnits(instance)
            set udg_used_units = 0
        endif
    endif
   
    // reals
    if ( udg_used_reals > 0 ) then
        if ( udg_used_reals > udg_limit ) then
            call MUI_ShowOverLimitError()
        else
            call MUI_SaveReals(instance)
            set udg_used_reals = 0
        endif
    endif
   
    // players
    if ( udg_used_players > 0 ) then
        if ( udg_used_players > udg_limit ) then
            call MUI_ShowOverLimitError()
        else
            call MUI_SavePlayers(instance)
            set udg_used_players = 0
        endif
    endif
   
    // points
    if ( udg_used_points > 0 ) then
        if ( udg_used_points > udg_limit ) then
            call MUI_ShowOverLimitError()
        else
            call MUI_SavePoints(instance)
            set udg_used_points = 0
        endif
    endif
   
    // effects
    if ( udg_used_effects > 0 ) then
        if ( udg_used_effects > udg_limit ) then
            call MUI_ShowOverLimitError()
        else
            call MUI_SaveEffects(instance)
            set udg_used_effects = 0
        endif
    endif
   
    // integers
    if ( udg_used_integers > 0 ) then
        if ( udg_used_integers > udg_limit ) then
            call MUI_ShowOverLimitError()
        else
            call MUI_SaveIntegers(instance)
            set udg_used_integers = 0
        endif
    endif
   
    // groups
    if ( udg_used_groups > 0 ) then
        if ( udg_used_groups > udg_limit ) then
            call MUI_ShowOverLimitError()
        else
            call MUI_SaveUnitGroups(instance)
            set udg_used_groups = 0
        endif
    endif
   
    // boolean
    if ( udg_used_booleans > 0 ) then
        if ( udg_used_booleans > udg_limit ) then
            call MUI_ShowOverLimitError()
        else
            call MUI_SaveBooleans(instance)
            set udg_used_booleans = 0
        endif
    endif
   
    // destructibles
    if ( udg_used_destructibles > 0 ) then
        if ( udg_used_destructibles > udg_limit ) then
            call MUI_ShowOverLimitError()
        else
            call MUI_SaveDestructibles(instance)
            set udg_used_destructibles = 0
        endif
    endif

    call SaveInteger(udg_hashtable, GetHandleId(periodicTimer), 0, instance)
    call SaveTriggerHandle(udg_hashtable, GetHandleId(periodicTimer), 1, udg_trigger)

    call TimerStart(periodicTimer, udg_timeout, true, function MUI_Periodic)

    set udg_timeout = 0.
    set udg_trigger = null

    set periodicTimer = null
endfunction

// initializer
function InitTrig_MUI takes nothing returns nothing
    set gg_trg_MUI = CreateTrigger()
    set udg_hashtable = InitHashtable()
   
    call TriggerRegisterVariableEvent(gg_trg_MUI, "udg_timeout", GREATER_THAN, 0)
    call TriggerAddAction(gg_trg_MUI, function MUI_OnTimeoutChange)
endfunction

Pretty sure the normal reply is not to use such a silly system but it has proven useful in lowering variable count and keeping stuff manageable with GUI triggers. Not sure how to add deindexing to this if that is the problem?
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,201
You will need to post an example of how you are using this system. I suspect the issue might be you are not setting udg_finish to be true in the periodic trigger when the index is no longer useful.

To rule out the issue being an error with using the system in just 1 of many triggers, I suggest recreating the index leak as simply as possible with a single trigger and posting that to be checked.
 

It'll happen with anything eventually, for fastest results I decided to use the explosion example.


edit: working on a better example and rechecking stuff, might be just user error so nvm for now...

There is a problem but I can't seem to get it in a testmap, RecycleNext is the problem if the system stays in constant usage it'll only continue to climb until it gets stuck past max array size.

edit2: finally captured the bug in the testmap, you'll notice RecycleNext stays at a constant number and won't decrease which is the problem of how it eventually goes past 8190.

likely final edit, appears i shouldn't be starting new instances in the ending instances. if anyone has any idea's on how to keep that feature without breaking the system i really would like to know.
 

Attachments

  • mui getting stuck.w3x
    56.8 KB · Views: 28
Last edited:
Status
Not open for further replies.
Top