MusaRai
LCPDFR
LCPDFR

patreon


Elaborating on Pursuits in LSPDFR 0.4

Pursuits have been the cornerstone of LSPDFR since our first release all the way back in 2016.  They shape the gameplay, providing most of the action in the mod, but above all, they shape the mod too - they’re the cogs that turn behind-the-scenes of LSPDFR, containing our most sophisticated artificial intelligence systems and are vital in so many different parts of our code, like traffic stops, dispatches and ambient events to name just a few.  

It’s no surprise, then, that from a purely technical perspective, it’s one of the most intricate and well developed systems within the mod.  To help put this into context for you, I thought it might be interesting and helpful to give a brief rundown of how everything in a pursuit actually works, so here goes.

The first thing to bear in mind is that in LSPDFR, a Pursuit isn’t necessarily a pursuit.  That might not make a whole lot of sense, but really what we mean is that the intention behind our Pursuit system is that it’s meant to be a generic container for a type of gameplay situation where you have a specific suspect, or group of suspects, with the desired outcome of those suspects being apprehended by the police.  When we think of a Pursuit in LSPDFR, it’s not always the case that you’re going to have four police cars tailing a fleeing vehicle, nor is it always the case that you’ll even have much of a chase at all.  It’s meant to be a bit more generic than that, it’s essentially just a way of handling the police response to a crime committed by a known suspect.

To give an example, imagine there’s a drunk pedestrian on the road who’s blocking traffic.  This could come into the gameplay as a result of a Dispatch (i.e. the player receiving a call about it), or it could be something that the player just spontaneously stumbles upon (an ambient encounter).  In either case, though, the way that this is represented behind-the-scenes in LSPDFR is as a Pursuit because there’s an actual, known suspect and the general idea is to apprehend, or otherwise ‘deal with’ this person (which in GTA V and LSPDFR, for simplicity’s sake usually means either to arrest or kill them).

Of course, the issue in the above scenario is that a drunk person on the road isn’t really a chase, is it?  At least not yet.  It could become one, like if he or she were to flee from the police when they get there, but we’re not really at that point yet, and this is where things get a little murkier.  GTA V is a game, and LSPDFR is a mod.  It’s not like we’re dealing with a hyper-realistic simulator, and it’s not like we have unlimited flexibility in what we can and can’t do as we are, at the end of the day, limited to a large extent by the content and capabilities of the game.  Likewise, the idea of LSPDFR has always been that you’re a cop in GTA, not necessarily that you’re a cop in the real world.  Sure, we take creative liberties here and there, but we do stay true to the original game in many areas, which we think helps to make the mod accessible and fun, but also gives players the freedom to define their own experiences, and install other mods and content which deviates from this path as they see fit.  Still, though, at least when it comes to Pursuits, most of our work thus far has been focused on this ‘core’, on making performance improvements, on making chases faster paced, on drastically improving the intelligence of officers and suspects.  They’re the big changes that make a real difference to the gameplay, and the ones that, in my opinion at least, make our Pursuit system - if you actually think about it for a moment and try to imagine all the moving pieces there are in doing something like this in an open world - perhaps one of the most impressive things made for any game mod ever.

With that being said, and as good as the chases in LSPDFR can be, the system itself doesn’t quite live up to the actual intention.  Because things are so geared towards actual chases (you know, with helicopters and people running and sirens screaming and whatnot), the result of the above situation with the drunken person is actually quite underwhelming.  Basically, the police only really have one ‘mode’ at the moment and that’s to quite aggressively chase the suspect down.  If we did use a Pursuit as the backbone of this particular call, as soon as the officers arrived at the suspect, they would follow our typical AI instruction set which was, as noted above, designed with an actively fleeing suspect in mind.

Taking this a little further, just to better illustrate the point, whenever we want someone to do something in LSPDFR, we assign them what’s known as a task.  These can either be tasks from the actual game itself which make someone do a specific thing (e.g. play an animation, equip a weapon, walk to a position), or they can be our own custom tasks which are basically ways of linking lots of these simple game tasks into more complex routines like handcuffing someone, which involves playing animations in sequence, lining things up, making people walk to the right positions, attaching the handcuff objects, and so on.

Now, in our example above about the chase, we assign our own tasks called TaskCopChasePedAdv and TaskEvadeCopsAdv to the officers and the suspect respectively, which obviously make the officers chase after the suspect, and the suspect flee from the officers and within TaskCopChasePedAdv specifically, there’s just over 50 conditional statements which we define, and these control the flow of instructions within the task.

To give an actual example from our code here, this is one of the conditionals in TaskCopChasePedAdv.  It’s very simply checking whether or not the officer is in ‘fighting range’ of the suspect, which we define simply to be within 50 metres of them.  We then use this information, and combine it with other conditionals where necessary, further down in the code to determine what course of action the officer should take in various situations.

All in all then, when you consider what’s actually happening behind-the-scenes, and what’s being continuously checked and evaluated, it’s quite an advanced system and it works relatively well when dealing with an actual chase.  If the suspect is shooting, it’s very important that we know whether or not each individual officer is within range to fire back, or if they should try to get to closer first - you can imagine that it probably doesn’t work very well when you instruct an officer to return fire at someone they can’t see who is 500 metres away.  It’s not so useful, though, in our situation with the drunken person on the road, and that’s the bit that we’re looking to improve.

Hopefully now, then, it’s easier to understand how underwhelming the Pursuit system is when faced with our scenario.  Since this isn’t actually a chase, and since nobody’s firing weapons or anything like that, all of our conditions and behaviors are basically redundant.  Instead, all that’s going to happen is the cops will arrive, hastily exit their vehicle, and arrest the drunken person at gunpoint as if he’s just led them on a high speed pursuit around the city.  Technically, the system is working as intended, but I think you’ll easily agree that we could do a lot better.

With this in mind, we’ve started to look at ways in which we can elaborate upon the Pursuit system so that it truly becomes more than just pursuits.  Not so much changing the chases themselves, but rather trying to accommodate situations and encounters other than actual chases, which might often necessitate different levels of force being used, or alternative dispositions like issuing tickets and giving warnings as opposed to pointing guns all the time, while still retaining the power and clear-purpose of the underlying system.

In the video above, we have included an example of what things might look like.  In this case, you can see that the suspect is sitting at a bus stop, so there's not exactly a need for a 'chase'.

Note that this is just an example, and we'd love to hear your feedback and ideas for how things could be improved.  You'll notice as well that NPCs are now making use of the new 'hand-on-holster' animations we discussed in our last post!

Sam.

Elaborating on Pursuits in LSPDFR 0.4

Comments

Linear executions certainly make many things easier to understand and less complex, so you should not necessarily avoid them. Just keep in mind that in the world of V after every yield, things can look vastly different. For simpler things, linear does make sense though. The same is true for fibers. They can be very useful and give it a lot of freedom. But for larger mods you then more or less introduce all the problems of multithreading and that can be hell to manage. Caching is simply just storing something, e.g. a ped's position and returning that value for the next x seconds. So certain conditions do not need to be evaluated every tick as them changing is less important, less likely, or both.

LCPDFR

So the first thing i learned is i should use repeating case checks (big while loops) instead of executing linear. Second thing is to use fibers as less as possible - Q: How do you cache conditions?

ziipzaaapM16A4

Pursuits use a decision tree with conditions like the one in the post above to evaluate what the officer should be doing at any given moment. This is evaluated every tick, but with most conditions cached except say, an is in vehicle check (as you really want to abort your vehicle logic then). For tasks, we have a custom task manager for each ped that manages tasks with three different priorities: Main, Sub and Permanent. Most tasks would use the main priority, whereas support tasks such as a "check if cop has visual" task would run as a subtask. Permanent tasks are rarely used and are assigned for things like "ped is a cop, do ambient cop logic". All tasks are executed every tick by default, but can themselves choose to defer processing when they do not need to run that often. So they are essentially "big while loops". Please note however, that LSPDFR is mostly single-threaded and does not use multiple game fibers for its core logic. Most tasks will use RPH tasks, but sometimes natives. An example of how they work (from RDRFR as I have it open just now): http://lms-dev.com/img/devenv_2020-09-16_16-00-03.png TaskSaySpeech then is a simple task, starting the speech and waiting for it to finish. Note that the Ended event could also be called because one or more of the peds ceased to exist, so we need to check for existence again.

LCPDFR

how would look the example code of an: "...they can be our own custom tasks which are basically ways of linking lots of these simple game tasks into more complex routines". Things that Interests me are: Are you using a big while loop where the officers repeating tasks until the condition changes or are they all just executing once? Are you mostly using RPH functions or natives? i would like to see an example code because maybe i find something that i could use to make my functions more efficient.

ziipzaaapM16A4


More Creators & Models