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

[vJASS] Effective way for units to detect a nearby item and pick it up

Status
Not open for further replies.
Level 2
Joined
May 24, 2019
Messages
21
Hi guys, so I want to write a function which should let neutral units detect a nearby item and pick it up.
Since the units are moving and the items aren't always at the same location, I was trying to index the location of every item as well as of every unit and compare if these two locations are within a certain range to each other. Since there are many units and items on the map and I was running the check every second, it did lead to heavy lagging.

Do you know of a more effective way of conducting this check? Maybe there is a native I do not know of which I can use?

Thanks!
 
Basically it sounds fine.

Location object isn't needed, since JASS used. x/y coordinates are fine for calculating distance.
If you watch for add/remove items that are being checked, you might store x/y in a struct instance, and then also getting x/y of item might become not needed in each iteration.

If there are a lot of items on the map, you might try to use EnumItemsInRect with one small rect, which you always move to the current unit being checked. (never need to destroy this rect)

How many units are being indexed, and might you show code?
 
Last edited:
Level 2
Joined
May 24, 2019
Messages
21
Thanks Iceman!
So it would be around 50 items on the map and in the beginning there were only like 5 units and still it lagged heavily already (probably because of my bad coding, since I used too many loops).

Moving one small rect from unit to unit sounds very interesting as well, will definitely check this one out! If it still lags, I'll post the code as well. At the moment I'm a bit too embarrassed about posting the current version of it, since it could be approved by a lot, but I don't know how :(
 
Level 2
Joined
May 24, 2019
Messages
21
Alright, so I've reworked the code (since the other one was laggy and also didn't work as intended) and used IcemanBo's idea of moving a rect.
Fortunately now there is no lag but unfortunately also no effect. Maybe someone can take a quick look what's wrong with it?

JASS:
scope CreepsPickUpDroppedCoins initializer init

  
    private function con takes nothing returns boolean
    return GetOwningPlayer(GetTriggerUnit()) == nh
    endfunction
  

  
  
    private function unitsnum takes nothing returns nothing
        local unit u = GetEnumUnit()
        local real ulocx = GetUnitX(u)
        local real ulocy = GetUnitY(u)
        local item it
                        
        if ( con() ) then                  

        call MoveRectTo(gg_rct_PickupReg,ulocx,ulocy)
        set it = RandomItemInRectSimpleBJ(gg_rct_PickupReg)
        call UnitAddItem(u,it)
        call BJDebugMsg("in range")

        else
        endif

        set u = null
        set it = null

    endfunction

    private function actions takes nothing returns nothing    
        call ForGroupBJ( GetUnitsInRectAll(GetPlayableMapRect()), function unitsnum )
    endfunction



    private function init takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterTimerEventPeriodic( t, 1 )
        call TriggerAddAction(t, function actions)
        set t = null
    endfunction

endscope

Quick comments: Only player "nh" should pick up items, it can pick up any item (since there's only type of item in the game) and it soon as it picks up any item, some other stuff should happen. The units which might pick up items also only have one item slot. The rect is a square with around 250x250 and when I've tested the function, the units moved directly through the item, so in my opinion the function "unitsnum" should have definitely fired until its end.
Thanks for any input!
 
use the EnumItemsInRect native, native EnumItemsInRect takes rect r, boolexpr filter, code actionFunc returns nothing

->

call EnumItemsInRect(r, null, gg_rct_PickupReg function callback)

Don't use "ForGroupBJ( GetUnitsInRectAll(GetPlayableMapRect())". It is very inperformant to get concrete units like this. Store them into variable, or variable[array] instead, the units you wanna check. Or best, attach the unit to check directly to a timer. (you can see JASS Class for timers/hashtable if it's new topic)

At best create a very small demo map only for this issue, and play around, and you can attach it here, too!
 
Level 2
Joined
May 24, 2019
Messages
21
There is no GetTriggerUnit() in the context of a periodic event. con() always returns false and so the item search never runs. I also do not see where nh is declared.

To prevent stutter lag every second you might need to stagger the searches.

I see, that was a pretty stupid copy&paste issue, now it works, thanks!


use the EnumItemsInRect native, native EnumItemsInRect takes rect r, boolexpr filter, code actionFunc returns nothing

->

call EnumItemsInRect(r, null, gg_rct_PickupReg function callback)

Don't use "ForGroupBJ( GetUnitsInRectAll(GetPlayableMapRect())". It is very inperformant to get concrete units like this. Store them into variable, or variable[array] instead, the units you wanna check. Or best, attach the unit to check directly to a timer. (you can see JASS Class for timers/hashtable if it's new topic)

At best create a very small demo map only for this issue, and play around, and you can attach it here, too!

Thanks, very interesting point! I was unaware of the performance difference between loading values from hashtables and just checking the map for it, so that's very valuable for me.

As we're already speaking about performance:
I'm also trying to set up a multiboard and testing it alone it works fine without lags, but with just two additional friends who have joined, it makes the map completely unplayable.
So I was trying to find a good multiboard tutorial, but everything I've found was GUI with heavy BJ uses.
Maybe you (or someone else) could quickly link me multiboard JASS tutorial for efficient updating? Thanks!
 
You're welcome!
The BJs are most likely not the (major) problem. Actions like "Pick All Units On Map" are big operations, and should be reduced to a minimum - that's why using for example variable or hashtable load would be much better to "get" a unit in the item case above.

I would do it in GUI, and if needed in JASS, then convert step by step to custom script, and re-produce it paralelly in self-written JASS. To see what converted functions do:
 
Level 2
Joined
May 24, 2019
Messages
21
You're welcome!
The BJs are most likely not the (major) problem. Actions like "Pick All Units On Map" are big operations, and should be reduced to a minimum - that's why using for example variable or hashtable load would be much better to "get" a unit in the item case above.

I would do it in GUI, and if needed in JASS, then convert step by step to custom script, and re-produce it paralelly in self-written JASS. To see what converted functions do:

I see! Just to clarify, that's what I did already and it led to the heavy lagging part, since I'm using the GUI BJs for the multiboard, for example to set/update the value of an item (i.e. a field). What I'd need would be a guide how to use the natives/commons functions for multiboard since I don't really unterstand how to use them (how to use them to pick the exact field in the board I'd like to modify for example). I'd appreciate if you link me any thread like the JASS classes about that topic, since these helped a lot!
 
As said,
I would do it in GUI, and if needed in JASS, then convert step by step to custom script, and re-produce it paralelly in self-written JASS. To see what converted functions do:
You see what to do in GUI, so you will see what it does behind the scenes, in converted text/JASS. From there you can start and optimize. The JASS Class has a bunch of tutorial links etc how to start with JASS.
 
Level 2
Joined
May 24, 2019
Messages
21
As said,

You see what to do in GUI, so you will see what it does behind the scenes, in converted text/JASS. From there you can start and optimize. The JASS Class has a bunch of tutorial links etc how to start with JASS.

Yes, I've already did that.. and this lead to the JASS code below which works fine for me but lags in multiplayer. And now I don't know what things I need to change in order to make it work (since I also can't test it regularly because for that I need to wait for my mates to be available).

I've found this thread: [code=jass] - multiboarditem?
Is this (the first post) a good way to set the board up or will it also cause lags with more than 1 player?
I guess my problem is the "MultiboardSetItemValueBJ", right?
Thanks!

My current code:

JASS:
scope UpdateMultiboard initializer init

private function actions takes nothing returns nothing
    local integer nor = noap + 3        // number of rows = number of active players + 3
    local integer i = 1
    local integer i2 = 0

    call MultiboardSetItemValueBJ( board, 1, 2, I2S(wc ) )
    call MultiboardSetItemValueBJ( board, 2, 2, I2S(count_gc ))
    call MultiboardSetItemValueBJ( board, 3, 2, I2S(count_lifes ))
    call MultiboardSetItemValueBJ( board, 4, 2, I2S(count_lifes - count_gc ))
      
    loop
        exitwhen i > nor
        set i = 4
        call MultiboardSetItemValueBJ( board, 2, i, I2S(capp[i2] ))
        call MultiboardSetItemValueBJ( board, 3, i, I2S(killcount[i2] ))              
        set i = i + 1
        set i2 = i2 + 1
    endloop
  
    set i = 1
  
  
endfunction


private function init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterTimerEventPeriodic( t, 0.50 )
    call TriggerAddAction( t, function actions )
    set t = null
endfunction



endscope
 
Please use descriptive variable names, it's hard to understand the meaning.

This is obviously not the entire relevant code, major part is missing, the way how values are being calculated.

I guess my problem is the "MultiboardSetItemValueBJ", right?
No. Again, as said:
The BJs are most likely not the (major) problem. Actions like "Pick All Units On Map" are big operations, and should be reduced to a minimum
But if you want to see what the BJ does behind, look at the blizzard.j file, like also already said. You will see the which logics is used, or which native function (from common.j) is used, so you might use it directly, instead of the BJ, if it makes sense.
 
Level 38
Joined
Feb 27, 2007
Messages
4,951
My guess is that loop is never exiting and you’re getting a threadcrash. This would cause the horrendous lag because the engine loops indefinitely until hitting the OP limit. Here’s why:

The loop exits when i > nor, which is noap + 3. The line at the end of the loop increments i by 1 properly, but the line directly after the exitwhen line sets i=4. Thus every time after the first time the loop checks the exitwhen line the comparison is ‘5 > 3+noap’. We can’t see what noap is but if it’s 3 or greater that line will never be true.
 
Level 2
Joined
May 24, 2019
Messages
21
Thanks at all, very helpful indeed, I'll look into it asap!
Sorry Iceman that my code/vars are rather indescriptive and I didn't post everything, I'm gonna need to get the hang of it how to present everything in a comprehensive way for third-person-viewers...
 
Status
Not open for further replies.
Top