HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Large amounts of units resulting in total order lag

10-23-2009, 05:50 AM#1
iRFNA
I'm aware this is a fairly known problem, but I haven't seen any solutions for fixing this general problem on a map with a ton of units. It can't simply be fixed by doing delayed orders bit by bit because just the existence of the units lags all unit commands made by players. Is there any simple solution to this pretty silly problem? If not, I'm just gonna turn pathing off on every unit and implement my own dumb A* algorithm, but I was just wondering if there was any simpler way, such as a setting value to make the game engine spend more time on pathing per iteration? Surely WC3 isn't completely hard coded into not supporting pathing with hundreds of units on today's processors, which can easily handle that...
10-23-2009, 07:52 AM#2
Anachron
I suggest delayed orders, its surely a better way to just let wc3 handle it.
10-23-2009, 08:14 AM#3
iRFNA
I would, but many of the occurrences of this are either from rally points or players actually doing orders. In my tests, even doing an order that doesn't require movement as a player will still result in the delay before the order is completed.
10-23-2009, 08:25 AM#4
Earth-Fury
Quote:
Originally Posted by iRFNA
I'm aware this is a fairly known problem, but I haven't seen any solutions for fixing this general problem on a map with a ton of units. It can't simply be fixed by doing delayed orders bit by bit because just the existence of the units lags all unit commands made by players. Is there any simple solution to this pretty silly problem? If not, I'm just gonna turn pathing off on every unit and implement my own dumb A* algorithm, but I was just wondering if there was any simpler way, such as a setting value to make the game engine spend more time on pathing per iteration? Surely WC3 isn't completely hard coded into not supporting pathing with hundreds of units on today's processors, which can easily handle that...

Simple: Split up the ownership.

For some ungodly reason, 500+ units owned by one player lags to all hell. However, 5 players owning 100+ units each works fine. (Numbers are completely made up. Actual number of units that cause lag / work properly will vary.)
10-23-2009, 08:41 AM#5
iRFNA
Quote:
Originally Posted by Earth-Fury
Simple: Split up the ownership.

For some ungodly reason, 500+ units owned by one player lags to all hell. However, 5 players owning 100+ units each works fine. (Numbers are completely made up. Actual number of units that cause lag / work properly will vary.)

That's interesting.. If only I had extra players to put ownership in, I'd do it. I've already tried having units remove themselves from a player's total unit group then reissuing their order in an attempt to circumvent this, as I suspected the cap was on a per-player basis, but it didn't work. I'm not sure if that could work and I just did it wrong, or it is a futile attempt, though.

edit:

When I did the reissue orders thing, it was on an event for any issued order, but it either reset the unit custom value if it was at 1 or set the value to 1 as well as redoing the order if not. I don't think it was resulting in any crazy infinite loops, and it didn't seem to have any beneficial/detrimental effect at all. It was just totally useless. The group I used and removed the ordered unit from before redoing its order was only the units owned by the player owning the ordered unit. I'm really not sure if attempting to do this in this way is useless or not (it probably is, I'd guess the engine would be regenerating or using an unaltered version of the player unit groups), but I had to try.


I'm eying a constant value in Blizzard.j named bj_MAX_QUEUED_TRIGGERS that is set to 100. Perhaps this is the culprit? Is there a way to override a constant value so I can check it out?
10-23-2009, 09:55 AM#6
Captain Griffen
WC3 pathing just fails for that number of units.

Quote:
Originally Posted by Earth-Fury
Simple: Split up the ownership.

For some ungodly reason, 500+ units owned by one player lags to all hell. However, 5 players owning 100+ units each works fine. (Numbers are completely made up. Actual number of units that cause lag / work properly will vary.)

My theory is that they factor in the player's own units, so that they try and walk around each other better, but don't do that for other units.
10-23-2009, 10:51 AM#7
Anachron
I made this in a few minutes, and I didn't compiled this, but maybe it helps you.

This automaticly orders all units to do your order, just with a little delay.

Collapse JASS:
library MassOrder

    struct MassOrder
        private unit array units
        private integer index = 0
        
        private boolean f = false
        
        private string s = ""
        private real x = 0.
        private real y = 0.
        private widget tw = null
        private widget itw = null
        private string act = ""
        
        private static timer t = CreateTimer() 
        private static thistype array instances
        private static integer i = 0
        
        public method create takes nothing returns thistype
            local thistype this = thistype.allocate()
            
            set thistype.instances[thistype.i] = this
            set thistype.i = thistype.i + 1
            
            if thistype.i == 1 then
                call TimerStart(thistype.t, 0.001, true, function thistype.onOrder)    
            endif
            
            return this
        endmethod
        
        public static method onOrder takes nothing returns nothing
            local integer i = 0
            
            
            if thistype.i > 0 then
                loop
                    exitwhen i <= thistype.i
                
                    if i <= thistype.i then
                        if thistype.instances[i].f then
                            if not thistype.instances[i].order() then
                                call thistype.instances[i].destroy
                                set thistype.instances[i] = thistype.instances[thistype.i]
                                set i = i - 1
                            endif
                        endif
                    endif
                    set i = i + 1
                endloop
            else
                call PauseTimer(thistype.t)
            endif    
        endmethod
        
        public method order takes nothing returns boolean
            if .index > 0 then
            
                if .act == "iO" then
                    call IssueImmediateOrder(.units[.index], .s)
                elseif .act == "pO" then
                    call IssuePointOrder(.units[.index], .s, .x, .y)
                elseif .act == "tO" then
                    call IssueTargetOrder(.units[.index], .s, .tw)
                endif
                
                set .units[.index] = null
            
                set .index = .index - 1
                return true
            else
                return false
            endif
            
        endmethod
        
        private method giveOrder takes string s returns boolean
            if not f then
                set f = true
                
                set .act = s
                return true
            else
                return false
            endif
        endmethod
        
        public method immediateOrder takes string order returns nothing
            if .giveOrder("iO")
                set .s = order
            endif    
        endmethod
        
        public method pointOrder takes string order, real x, real y returns nothing
            if .giveOrder("pO")
                set .s = order
                set .x = x
                set .y = y
            endif    
        endmethod
        
        public method targetOrder takes string order, widget targetWidget returns nothing
            if .giveOrder("tO")
                set .s = order
                set .tw = targetWidget
            endif    
        endmethod
        
        public method addUnit takes unit u returns nothing
            set .units[.index] = u
            set .index = .index + 1
        endmethod
        
        public method addGroup takes group g returns nothing
            local unit u
            
            loop
                set u = FirstOfGroup(g)
                exitwhen u == null
                
                call .addUnit(u)
                
                call GroupRemoveUnit(g, u)
            endloop
        endmethod
        
    endstruct
 
endlibrary

Steps you need:

Collapse JASS:
local MassOrder mo = MassOrder.create()
call mo.addGroup(YourGroup)
call mo.pointOrder('smart', pointX, pointY)
10-23-2009, 01:56 PM#8
Rising_Dusk
No, Anachron, that won't work. You need to understand the nature of the bug to understand the nature of how not to induce it. The problem arises from WC3's internal pathing checks. You can have 100 units ordered by the same player without problem if the pathing for their orders is incredibly simple. (Such as straight lines only and no having to check around each other) However, 40 units can cause this bug to occur if the pathing that they're following is incredibly complex.

The only solution is to split up ownership of the units, as EF said. Your code will do nothing to help.
10-23-2009, 03:33 PM#9
DioD
disable patching for units and control its patch manually.
10-23-2009, 08:39 PM#10
iRFNA
Alright, I'm probably gonna try just rewriting the pathing system. It's gonna be pretty hilarious if this ends up working in bytecode "better" than the native WC3 libraries (on a good processor) due to their limitations... I suppose I can take a couple shortcuts to favor swarming behavior better and perhaps cut down on the operations typically being used.

One question, though... Building pathing maps. I'm guessing the IsTerrainPathable function doesn't deal with them, correct? So is placing a dummy unit on the building/checking position the most efficient way to check the pathing maps? I don't mind complexity such as manually preparsing their data or anything, this map is a distraction from doing self-modifying hand-coded assembly...

edit:

It's a shame that pathing maps are .tga files and WC3 supports images... Except actually getting data from them, only setting and displaying. Anyone messed with this before? Is there a method for directly reading these maps in some niche library? I guess if all else fails, I could parse all the pathing maps into const arrays and just put them directly into JASS.
10-25-2009, 05:12 AM#11
Deaod
turning pathing off for units wont actually do much (havent tested thoroughly, so this might be wrong, its just what ive seen from that little bit of playing around with it). If you order them to move, they will follow those orders.

To my knowledge, theres no way to fix this, besides splitting up ownership (you have 16 players, remember? 12 of them can be humans, leaves 4 that can only be computer controlled).
10-25-2009, 02:11 PM#12
Earth-Fury
Quote:
Originally Posted by Deaod
turning pathing off for units wont actually do much (havent tested thoroughly, so this might be wrong, its just what ive seen from that little bit of playing around with it). If you order them to move, they will follow those orders.

To my knowledge, theres no way to fix this, besides splitting up ownership (you have 16 players, remember? 12 of them can be humans, leaves 4 that can only be computer controlled).

This is true, as far as I can recall. Units who have had their pathing disabled still do path finding.

You could turn all units in to flying units with a fly height of 0, but even then they still do some path finding. There is also the issue that when flying units are flying, they will fly in to each other. They only separate when stopped.

Really, reducing the number of players your map uses so you can split up ownership further is the only way that will work well enough...
10-25-2009, 06:07 PM#13
iRFNA
I've found that turning off pathing and giving every unit a visible version of ghost turns off enough pathfinding to seriously remove the stuttering problem. They only somewhat move around terrain unwalkable but ignore everything else, and having 500+ units with one player didn't cause probs. Of course, this is completely without trigger based pathing as well.

I keep working on other parts of the map besides the A* pathing replacement, but it's almost done. Hopefully it won't be horribly laggy, haha

edit:

I guess I should add that the A* pathfinding is also coming with collision checks. It'd be pretty dumb to do it otherwise
10-25-2009, 06:45 PM#14
Rising_Dusk
It's the ghost that does it, not really the pathing disabling. The ghost lets units path through the ghosted unit, so they don't have to calculate paths around it instead. I don't really consider that a solution, though, since it looks really lame if your footmen are walking through each other.

Anyways, 500+ units on screen at once will cause way more problems with your map than the pathing checks, so be careful.
11-02-2009, 05:24 PM#15
Vexorian
Quote:
Originally Posted by Captain Griffen
WC3 pathing just fails for that number of units.



My theory is that they factor in the player's own units, so that they try and walk around each other better, but don't do that for other units.
Isn't there a trigger to mess with the formation settings?