Home   Help Search Login Register  

Author Topic: Performance Considerations of Long Scripts  (Read 498 times)

0 Members and 1 Guest are viewing this topic.

Rocko Bonaparte

  • Guest
Performance Considerations of Long Scripts
« on: 09 Dec 2004, 07:59:56 »
I'm developing some AI for a multiplayer mission.  Specifically, I've given each AI unit independent control on what it does after each spawn.  Granted, I haven't coded how to react to death and respawning quite yet, but that's easy enough.

The code I'm writing is like a state machine.  The script will run for a few commands to set up a state, and then wait until that state had been fulfilled before continuing.  With some random chance and known waypoints, the units can move around and perform tasks.

The problem is the code is growing substantially, and I'm curious if I'll hit a performance barrier before it completes.  That would ruin my script.  I think it might be happening a little already.  In the init.sqs file, some of the units don't seem to respond to the script at all.  I'm thinking the units aren't created by the time they are sent to the script, so nothing happens.  I haven't proven it yet.

If you're curious, this is the code I have so far:
Code: [Select]
_player = _this select 0

_Defend_Rear_Town = [7173.221680,8997.596680]
_South_Forest_Defense = [7027.380371,8679.646484]
_North_1 = [6831.774414,9219.046875]
_North_2 = [6268.325195,9307.347656]
_North_3 = [5961.371582,9130.744141]
_North_4 = [5979.678223,9001.433594]
_North_5 = [6029.248047,8955.028320]
_Enemy_Flag = [6023.320313,8600.478516]
_Defend_Center = [6623.063965,8759.747070]
_Center = [6618.985840,8791.207031]
_North_Snipe = [6418.076172,9284.750977]
_South_Road = [6278.738281,8568.501953]
_Enemy_South_Rear = [5991.031738,8519.553711]
_Cent_North_1 = [6749.277344,8916.504883]
_Cent_North_2 = [6379.270996,8815.067383]
_Enemy_Top = [6036.661621,8675.635742]
_rand = 0.0
_waypoint = "Logic" createVehicle [9632.477539,3865.032227]

#Spawn
_rand = random 1
?(_rand > 0.8) : goto "_Spawn_to_North1"
?(_rand > 0.2) : goto "_Spawn_toCenter"
?(_rand > 0.1) : goto "_Spawn_to_Defend_Rear_Town"
goto "_Spawn_to_South_Forest_Defense"

   #_Spawn_toCenter
   _player move _Center;
   _waypoint setpos _Center;
   @((_player distance _waypoint) < 9.0);
   goto "_Center"

   #_Spawn_to_North1
   _player move _North_1
   _waypoint setpos _North_1
   @((_player distance _waypoint) < 9.0)
   goto "_North_1"

   #_Spawn_to_Defend_Rear_Town"
   _player move _Defend_Rear_Town
   _waypoint setpos _Defend_Rear_Town
   @((_player distance _waypoint) < 9.0)
   goto "_Defend_Rear_Town"

   "_Spawn_to_South_Forest_Defense"
   _player move _South_Forest_Defense
   _waypoint setpos _South_Forest_Defense
   @((_player distance _waypoint) < 9.0)
   goto "_South_Forest_Defense"

#_Defend_Rear_Town
~20
goto "_Spawn"

#_South_Forest_Defense
~20
_rand = random 1
?(_rand > 0.6) : goto "_South_Forest_Defense_to_Center"
goto "_South_Forest_Defense"

   #_South_Forest_Defense_to_Center
   _player move _Center;
   _waypoint setpos _Center;
   @((_player distance _waypoint) < 9.0);
   goto "_Center"

#_North_1
rand = random 1
?(rand > 0.6) goto "_North_1_to_North_2"
goto "_North_1_to_North_Snipe"

   #_North1_to_North_2
   _player move _North_2
   _waypoint setpos _North_2
   @((_player distance _waypoint) < 9.0)
   goto "_North_2"

   #_North_1_to_North_Snipe
   _player move _North_Snipe
   _waypoint setpos _North_Snipe
   @((_player distance _waypoint) < 9.0)
   goto "_North_Snipe"

#_North_2
_player move _North_3
_waypoint setpos _North_3
@((_player distance _waypoint) < 9.0)
goto "_North_3"

#_North_Snipe
; This is a good sniping position, so we should hang around awhile.
~30
_rand = random 1
?(_rand > 0.6) : goto "_North2_to_North_3"
goto "_North_Snipe"

#_North_3
_player move _North_4
_waypoint setpos _North_4
@((_player distance _waypoint) < 9.0)
goto "_North_4"

#_North_4
_player move _North_5
_waypoint setpos _North_5
@((_player distance _waypoint) < 9.0)
goto "_North_5"

#_North_5
_player move _Enemy_Flag
_waypoint setpos _Enemy_Flag
@((_player distance _waypoint) < 9.0)
goto "_Enemy_Flag"

# Center
_player move _Enemy_Flag
_waypoint setpos _Enemy_Flag
@((_player distance _waypoint) < 9.0)
goto "_Enemy_Flag"

#_Center
_rand = random 1
?(rand > 0.5) : goto "_Center_to_Enemy_Flag"
?(rand > 0.4) : goto "_Center_to_Enemy_Top"
?(rand > 0.2) : goto "_Center_to_Enemy_South_Rear"
goto "_Center_to_Defend_Center"

   #_Center_to_Enemy_Flag
   _player move _Enemy_Flag
   _waypoint setpos _Enemy_Flag
   @((_player distance _waypoint) < 9.0)
   goto "_Enemy_Flag"
   
   #_Center_to_Enemy_Top
   _player move _Enemy_Top
   _waypoint setpos _Enemy_Top
   @((_player distance _waypoint) < 9.0)
   goto "_Enemy_Top"
   
   #_Center_to_Enemy_South_Rear
   _player move _Enemy_South_Rear
   _waypoint setpos _Enemy_South_Rear
   @((_player distance _waypoint) < 9.0)
   goto "_Enemy_South_Rear"
   
   #_Center_to_Defend_Center
   _player move _Defend_Center
   _waypoint setpos _Defend_Center
   @((_player distance _waypoint) < 9.0)
   goto "_Defend_Center"

#_Defend_Center
hint format["%1 _Defend_Center", (name _player)]
; Wait ten seconds before reconsidering
~10
goto "_Center"

#_Enemy_Flag
hint format["%1 _Enemy_Flag", (name _player)]

#_Enemy_Top
hint format["%1 _Enemy_Top", (name _player)]

#_Enemy_South_Rear
hint format["%1 _Enemy_South_Rear", (name _player)]

There are some problems.  I might get away without putting positions into variables like that and have a logic item for comparing distances.  The hints at the end will all print out in one big swoop.  As mentioned before, respawning hasn't been considered yet.  Nor has flag-capture events been added (it's a CTF mission).  Finally, I'm not sure if I like the state-machine format I have used here.  There are a few approaches to it (noteably mealy or moore), and I could get real carried away with it.  

When testing on a normal load, I will have 8 units on each side, with me being one of them.  The opposing side will have their own script like this to control them.  Each unit would run that script.

I think the script will at least double, and possibly triple.  Am I asking for trouble?

Offline Fragorl

  • Coding Team
  • Former Staff
  • ****
Re:Performance Considerations of Long Scripts
« Reply #1 on: 09 Dec 2004, 09:51:06 »
lolz i am working on just about EXactly the same thing. Taking ages though.
What every dev doesn't really like to hear...  ;)

To begin with my script was similar to yours, until i rewrote it, because it was getting out of hand, too long.

I notice you have a lot of repeating stuff:
Code: [Select]
  #_Spawn_toCenter
   _player move _Center;
   _waypoint setpos _Center;
   @((_player distance _waypoint) < 9.0);
   goto "_Center"

   #_Spawn_to_North1
   _player move _North_1
   _waypoint setpos _North_1
   @((_player distance _waypoint) < 9.0)
   goto "_North_1"

   #_Spawn_to_Defend_Rear_Town"
   _player move _Defend_Rear_Town
   _waypoint setpos _Defend_Rear_Town
   @((_player distance _waypoint) < 9.0)
   goto "_Defend_Rear_Town"
An idea that worked for me was to make it more generic: e.g.
Code: [Select]

_i = 0
_positionsarray = [_north_1,_north_2,_north_3,_Defend_centre,_Centre...]

#Spawn
_rand = random 1
?(_rand > 0.8) : _i = 0
?(_rand > 0.2) : _i = 4
?(_rand > 0.1) : _i = 3
;Choose a random point
goto "MOVEWP"

   #MOVEWP
   ?_i > count _positionsarray : _i = 0
   _pos = _positionsarray select _i
   _player move _pos;
   _waypoint setpos _pos;
   @((_player distance _waypoint) < 9.0);
   _i = _i + 1
   goto "MOVEWP"
Of course this will just cycle waypoints, but you can tailor #MOVEWP to suit your needs, maybe choose a random place from _positionarray and have random patrols...

If you want to have units move separately then you might have to put them into separate groups, otherwise they'll just follow thier leader.

Another point: regarding use of @. If you are going to have the script re-run everytime a unit dies, you'll end up with a lot of scripts running (i think, but i could be wrong), all stuck at the @ waiting for the dead ai to reach his wp ;D
Even if this isn't right, you might want to consider adding another few conditions to the @, in case you have something else that you want the ai to respond to, apart from doggedly pursuing his waypoint (e.g. under fire)

Anyways enough from me
« Last Edit: 09 Dec 2004, 09:53:33 by Fragorl »

Rocko Bonaparte

  • Guest
Re:Performance Considerations of Long Scripts
« Reply #2 on: 10 Dec 2004, 03:05:19 »
The units are already grouped separately -- that was taken care of.  I didn't want to cycle waypoints because I wanted the units to seemingly perform objectives.  A random waypoint cycle would have moved them around, but it wouldn't have been so interesting.  Also, not all waypoints link very well together, so some of them are in a chain.  

Finally, at some waypoints I have the tank "defend." That is, they sit there for a little bit.  I haven't set their direction yet, which I should.  

The bing thing I might do is have some global events.  Upon respawn, no matter what they were doing before, they'd be sent back to the _spawn code block.  There would also be some other settings for flag captures.  

When the unit dies, there is something that can be done to bring them back and keep them in the script.  I did this with another script for respawning select units into a vehicle every single time.  There won't be a growing chain of hanged scripts.

Offline ACF

  • Members
  • *
  • Llama?? Ain't that French for tanks?
Re:Performance Considerations of Long Scripts
« Reply #3 on: 10 Dec 2004, 13:03:44 »
Might be worth seeing if the fickle

@ Unitready _player

works any better than the distance check.

Alternatively, @ is a very fast checking loop, so stacking a lot of these may hit performance.  You could free up CPU time by using scripted checking loops with decent pauses in them: ~30 might be often enough to check if a group has reached its WP.