| 08-21-2005, 10:18 AM | #1 |
I am thinking about possibilities to optimize a heavily triggered map which a friend gave up on due to the lag in multiplayer, and I came here seeking some suggestions, explanations, and just general guidance. The map sports a triggered projectile system that moves all projectile objects about on a periodic event. There can be about 8-12 projectiles flying about per player (this is a rarely achieved maximum, though, let's say in peak conditions it's an average of 6-8 per player), with up to 8 players in the game. Together with computer controlled units, I would say there can be no more than 100 projectiles flying around at the same time (this is (hopefully) again a bit of an over-estimate, perhaps the game wouldn't exceed 75 projectiles in worst conditions). However, so far, the lag has been experienced in a 5 player test game already, with (I'm guessing) about two dozens of projectiles at a time (don't know what kind of machines it was running on, though). The game-tick is already at 0.04 seconds, and anything more would just seem too unsmooth to look nice, so I wouldn't want to optimize here. I assume the main problem is the move unit function. Moving units about is expensive because the CPU needs to recalculate pathing and all that stuff whenever you move it. However, the problem refuses to fix itself if I make the units locust, which should make the game ignore the entire pathing calculation. If no simple solution exists to make instant unit movement eat less CPU cycles, I am thinking about alternatives. In an entirely triggered game enviroment, the projectiles don't need to be units, they could be just special effects. However, here I come to two new considerations: can you define a special effect's z offset, and can you move it? If you can't move it, then I would need to continiously destroy and recreate the special effect, meaning a lot of changes on the handle stack, and again, I don't know demanding that is compared to unit instant moving. Another thing I could consider besides special effects is lightning. I know that has z offset, but I have absolutely no experience with it, so I don't know how much it demands from the CPU and all the functions it may require, like locations, the creation of which also wreaks havoc on the handle stack. This brings me to other points. Unit instant moving is supposedly the most consuming function, however, there are other less consuming that may be run more often, though. For example, I am thinking about abolishing all use of location objects and doing everything with x y z coordinates. The last thing remaining is all the math. Math functions are incredibly fast, but when calculating collision in a 3D enviroment, you tend to use a lot of it, so I am guessing it could add up to something more (I don't know, though). Maybe I should use some sort of algorythm to rule out units that are clearly not in collision range out before doing the math for those that remain. I was thinking maybe about geting a "units in range" group, but that doesn't sound to good, it would create a handle, and when figuring out which units are in the group it would have to do the math that I would otherwise have to do anyway. So, what are my chances for optimization? Do I have enough possibilities to make this work? Should I just give up? Or is it on the edge where it could work, but only on good machines and a good network? |
| 08-21-2005, 11:58 PM | #2 |
Well 0.04 seconds triggers doing a lot of stuff have to be a lag out, Anyways if you have one timer of 0.04 seconds moving every projectile, it would be 100 times better than 100 timers of 0.04 seconds moving each unit? Do the projectiles use gamecache? And tell him to try using low poly models for the missiles |
| 08-22-2005, 09:04 AM | #3 |
My map uses a 'ammo' system, that all weapons fire out a missile (unit) and moves it using a 0.04 sec timer. My machine gun which fires about 30 of them at the same time has experienced minimal lag, which is at the most. Try shortening all the movement functions as much as you can, expecially the function that is called from the timer. Code:
function m takes unit v, real a, real s returns nothing
call SetUnitX(v,GetUnitX(v)+(s*0.03)*Cos(a*bj_DEGTORAD))
call SetUnitY(v,GetUnitY(v)+(s*0.03)*Sin(a*bj_DEGTORAD))
call SetUnitFacing(v,a)
endfunctionTry this, its the movement function im using. |
| 08-22-2005, 09:42 AM | #4 |
The game has a 0.04 periodic trigger that loops through all the projectiles and then moves them and checks collision with the terrain and all the game objects they can collide with. I suppose, for starters, I could move collision detection to happen only every 0.08 seconds (or even 0.12) and then do a collision check for half (or third) of all the projectiles each loop. The map uses game cache, but from the replies I got in a recent thread I gathered that the difference in speed between gamecache and global variables is insignificant compared to functions like SetUnitPositionLoc(). I know I can optimize this a bit by not using locations, but xy coordinates instead. However, now I have a question for EdwardSwollenToe: is using SetUnitX() and SetUnitY() faster than just using SetUnitPosition()? I would guess SetUnitPosition() would be faster, as it only moves a unit once... I guess my problem is also that I have to calculate things in 3D... takes a lot more computing time. I guess I could also optimize the movement of straight line projectiles by not having to recalculate their xyz vector every time from their angle and speed, but by storing the xyz vector coordinates instead. I think the projectile models are low poly already... but... what about alternatives to using units as projectiles. Special effects or Lightning. could creating and destroying them be faster than moving units? And can the special effects have Z offset? |
| 08-22-2005, 11:03 AM | #5 |
The model size is hardly gonna affect it, the reason i use set unit x is because it is far superior to setunitposition. It seems to be less laggy, and 2 the unit can still move/attack! That is the opposite with setunitpos, as you cant attack or basically do anything. |
| 08-22-2005, 01:14 PM | #6 |
Well, for this map I don't need the units to be able to do anything while moving, all that really matters to me is the speed. If you say SetUnitX + Y is less laggy then I'll go with that for starters. I suppose I can always test the two options out later. |
| 08-22-2005, 01:40 PM | #7 | |
Quote:
Godamn I didn't know that, I guess that SetUnitPosition pauses the unit and SetUnitX doesn't and that's the reason of the advantages. Thanks for this. My inferno/artic blast/lightning inferno spells use thousands of missiles and their lag is minimal. Avoid using BJ functions. Make sure your gamecache access doesn't have memory leaks. Don't use handle variables , H2I is sloow, it is actually slower than storing/loading stuff from gamecache, I got able to make a variation of handle variables that is called attachable variables and also allow tables that work like handle variables but take a string as argument instead of a handle, I found out that if you only call H2I once instead of a lot of times (by using handle variables) it does optimize the performance a lot. Proof A : http://vexorian.wc3campaigns.com/spells/articblast.w3x The ultimate performance fix is using pure gamecache natives btw |
| 08-22-2005, 07:45 PM | #8 |
Hmm... what kind of leaks can game cache access have? Anyway, I won't be using it at all for the most critical part, that are the straight-line projectiles. I'll use an assortment of global arrays to store all the relevant data for them, that being their xyz coordinates and their xyz vector (as opposed to homing missles and players who will have their movement defined with speed, direction and angle), making the movement of the projectiles require as litle computation as possible. The second part is collision detection. I think that preliminary comparison of individual coordinates of the projectile against the coordinates of every hitable object will quickly diminish the number of more detailed impact calculations required, with little strain for the CPU, as it will only need to substract two values and check if the result is within bounds for one coordinate, and one coordinate check will often be enough to rule out a possible collision. The only thing which I don't yet know precisely how to do is the colission with terrain detection. Due to the problems the blizzard cliffs cause the camera, the ground itself is flat, requireing doodads to construct higher ground. I suppose this means that there'll be no way to get terrain height of a point unless I specify it with regions, or if I just write a series of if-then-elses that check if the unit's coordinates are at any special part of the map. Except that I got another idea... you can now get the tile at a location, right? So, perhaps I should add a special tile under the terrain-doodads, and another different one under higher doodads, and use that to determine what the terrain's height is at the projectile's position. The only question is how fast is the get tile function... |
| 08-23-2005, 01:33 AM | #9 |
Well just using InitGamecache everytime instead of keeping it on a variable I can confirm SetUnitX and SetUnitY are faster than SetUnitPosition. They are also magical, they don't check pathing, they don't stop the unit from casting spells/ attacking / moving / playing animations. The only bad thing is that they allow to go out of the map wounds and that causes a crash. |
| 08-23-2005, 05:50 AM | #10 | |
Quote:
Forgot to mention that :P It took me ages to find out why the hell my map kept crashing, so to avoid it, i made a region that killed any unit the went out of it ~ out of the map. Yeah set unit x/y is simply the best function. Although the weird thing is that i cant seem to get them working individually, they only seem to work when used in a pair. |
| 08-23-2005, 09:09 PM | #11 |
Thanks, this has all been quite helpful. Last thing I'm wondering about is how to do the terrain colission detection, some ideas already crossed my mind, I posted them in my last post... any comments/suggestions regarding that? |
| 08-23-2005, 10:13 PM | #12 | ||
Quote:
That's odd. |
| 10-01-2005, 10:58 AM | #13 |
I was wondering, what kind of crash does SetUnitX/Y cause? The map I'm optimizing tends to crash, and crash badly, it freezes the system and I need to restart the computer... but that's not the main problem. The main problem is that the crash is very erratic. First time the game just froze after a few minutes, and I had to restart. Second time, the screen froze, but I could still hear the game running in the background, it responded to my commands, if I pressed the downarrow I could hear my plane crash etc... After some time, that froze too and I had to restart. The third time I tried it, I played it for so long I thought it finally wasn't going to crash, and it crashed. The fourth time, however, I was playing it for 45 minutes and it just wouldn't crash, despite my most valliant efforts. Edit: the latest, fifth atempt again failed to cause the game to crash. This time, I was trying for about 30 minutes before I gave up. Edit2: got the map to crash again, similar as in second case, except that it took longer. I forgot to time it, but I'm quite certain it happens at no specific time. However, I'm not sure if SetUnitX is to be blamed at all. In an earlier version of the map, I was using global variables instead of storing projectile data to gamecache with H2I, and that doesn't crash on me (at least not anymore, it had a similar crash once but I think I fixed that). So, the problem I'm having is figuring out what exactly causes the crash, because it just happens at one point, under no specific conditions. I assume something in the projectile movement engine gets messed up, but what, I cannot say. It could be even old systems interfering with the new, because I have them running at the same time, because I haven't yet migrated enough functionality to the new systems to be able to turn the old ones off. In such a case, there would be no problem, once I would turn the old systems off, the bug would be fixed, but the problem of course is that I can't know for certain this is to be blamed, and the way the map crashes only occasionaly, I can never know if I managed to get rid of the bug or if I'm just being lucky that the map doesn't crash. So... which functions could cause such a crash? Game cache? SetUnitX? Something else? |
| 10-03-2005, 01:24 AM | #14 |
I think its something to do with a leak or some sort of loop. The crash caused by set unit x just exits warcraft and displays the ERROR! msg. Anyways im working on a custom projectile engine. Its not quite done, but if you want to take a look and see how it works, visit this thread: http://www.seiken.co.uk/momm/forum/index.php?showtopic=5395&st=0&#entry76504 |
| 10-03-2005, 04:33 PM | #15 |
There's another odd thing about this newer optimized version I did (the one that crashes)... it's also laggy. At first I thought that I have optimized everything else so much already that the 4 times speed difference between game cache and globals is finaly starting to show, but... in that case, the original code, which used I2S on every gamecache call, used locations everywhere, dynamically creating and destroying them all the time,... that code would have lagged a whole lot more than it did. So the difference between my two versions has to be something other than the "cache vs globals" issue, but I just can't find what it is. I mean, the functions are fairly simple, they just load a bunch of reals from GC/globals for each projectile, do some simple calculations, move the projectile and it's flying height accordingly, and store the new position data back to where they got it. The only difference I can find is cache/globals, the way the functions work should be the same... but where does the lag difference come from? Could it be from the same source that causes the crash? |
