Project: Serpent - Server Platform for Entity Management

With OneSync getting more and more features this might actually be planned at some point, still I’d like to hear your opinions and ask for help developing this idea.
There have been quite a few experiments over the last years on the behavior of NPCs with no players nearby. Not much progress has been made, most likely due to the fact that the GTA V-natives are not written with long-range actions in mind. This post and Serpent itself present an idea that WILL work (as I’ve already proven with a few videos which are linked below).

The idea is easiest described like this:
I want an NPC be able to drive around Paleto Bay and act normally even if every player on a server is inside Los Santos.


Disclaimer

I am posting this as several posts due to the length of each.
Dear mods, I hope this is ok as this thread will desperately need some structure…

The first post outlines the general idea of the project. The pictures and code in there might be a little outdated.
The second post outlines what already has been created, what is in a working state and what isn’t.
This will also contain the link to the github-repo with the currently existing code.
The third post describes what needs to be done, what I can offer and what you could do to help this project be realized.


Why would you want this?
You might be familiar with FivePD, the multiplayer police mod released over a year ago. It has gained a lot of traction and is imo a fantastic mod. The callouts however have been quite limited in possibilities the last time I checked the mod. FivePD uses (or atleast - used) a system similar to LSPDFR in that you can accept missions and they are only spawned afterwards which presents a problem regarding the timing of missions.
In single player you don’t need to rely on mission timing (simply hardcode the timing in a proper way). In a multiplayer environment you absolutely need consistent time and space. It would be pretty strange, if a mission in a police mod called out Attack on Paleto Bay PD and one officer would be like Ehh no? I'm standing inside it , only to be murdered by five NPCs that spawned as soon as the mission got accepted.
In order to get around that I want to give the NPCs their own agency. I want to make sure that the NPCs can move on their own and do their own decision-making independent of players or even players being near the place (have an attack on Paleto Bay PD triggered while everyone is on Route 69?).
Now you could work around this problem by checking if a player currently is inside Paleto Bay PD and suppress the mission that would result in spawning NPCs running rampage. However imagine this mission:

CalloutTeaser

You could hardcode the vehicle to appear at a specific point when police gets near (this is how every police-mod would do it). But that defeats a in my opinion very important part of police work: Search for the criminal. Without properly simulating the car driving down Great Ocean Highway this will always feel bullshit to an extent (I was at the entrance to Paleto Bay and drove down Great Ocean Highway when the mission triggered. I never saw a dark grey Oracle speeding towards me...). Simulating NPC movement over the map will actually make this mission playable in the way it is supposed to work. This would be a huge factor for immersion and a fun yet challenging gameplay.

This isn’t possible client side, since the LongRange functions don’t work properly and most of the time the entities simply get deleted upon creation. Trying to force the issue will render non-moving NPCs that do not react to any movement command. This gets exponentially worse with multiple players on the server. While one player on the server will have the ped working sometimes, with multiple players it’s essentially never working.

The main idea for a solution
My suggestion for Serpent should simulate the NPC-movement completely serverside. Relying only on self-created data it wouldn’t need problem-riddled Natives. Instead the server creates and controls these entities. While no player is near the entity is never spawned and exists purely as a bunch of variables. Only when a player gets near the server issues a SpawnCommand to the player in question. It remains in control of the entity in the sense that it sends every action the entity should make to the client that spawned the entity (e.g. move here, attack this, …).

Now am I completely insane? Well, yes, probably. But the system still can work. A possible design would look like this:

PedList = {}
VehicleList = {}

first off initialize the main lists that will carry the data for every single object to be simulated.
Now data for any ped could look like this:

local ExamplePed = {
  PedIID = 1, -- Mod-Internal ID: This is the main ID of any entity used in this system. It is persistent and will be used to identify the ped, issue tasks, change its data etc etc
  x = x, -- current position: x coord
  y = y, -- current position: y coord
  z = z, -- current position: z coord
  IsSpawnedBool = false, -- checks if the ped currently is available client side
  OwnerClientNetID = 0, -- NetID of the client that spawned the ped
  PedNetID = 0, -- NetID of the Ped when spawned
  PedModel = "a_f_m_beach_01", -- Ped Model
  PedVisualData = {}, -- Components and Props of that model
  CurrObjective = "DriveToCoord", -- the currently issued task
  ObjectiveData = { -- the data of said task
    tarx = 2000.0,
    tary = 2000.0,
    tarz = 2000.0,
  },
  PathfindingData = {}, -- if the task is a moving-task you'll need pathfinding data. If you need to store this data this is the place
  IsInVeh = false, -- bool if the ped currently is in a vehicle
  VehIID = 0, -- Mod-Internal ID of the vehicle
  . -- possibly a shitload of other variables that need to be saved
  .
  .
}

Yes, I’m insane, you probably got that by now. Yes, this would be a full-scale entity handler done serverside. Now what code would need to run serverside in order to actually make such a system work?

Player-Position
The position of every player needs to be known to the server. Let every player send their position to the server by using a serverside while loop on a Wait(500) + events.

Entity-Position
The position of every controlled entity needs to be updated. Could be done by using a serverside while loop on a Wait(500) and executing serverside events for every entity (e.g. Event “DriveToCoord” for the above entity). See below for these “action-events”.

“Action-Events”
The actions of the entities get controlled serverside. This is done by using events that simulate the behavior. Let’s assume that we want to send an entity to a specific coordinate, using a “DriveToCoord”-event.
We need to check whether the entity is spawned or not. If the entity is spawned, this is trivial: Let the server send a command (using TriggerClientEvent) to the client responsible for the entity. That Client event should make the client trigger the Native DriveToCoord for the respective entity (note that the server got every required variable for that native saved in the above list).
If the entity is not spawned, this is harder, but certainly possible. First of all, we need

The pathfinding algorithm
I am very much certain that GTA V uses A-Star for pathfinding albeit in a very complex way. With 70000 nodes you wouldn’t want to have an algorithm venture through all of them to find the best way.
However for the goal here this massive amount of nodes isn’t necessary at all. GTA V simulates movement up to the specific lane a car is driving on. For DISTANT peds all that is necessary is a broad approximation. For this, a simple implementation of A-Star should suffice. I already implemented A-Star and tested it successfully for Paleto Bay:

This is a picture of Paleto Bay that I put out with path nodes. Neighboring pathnodes are connected, so the system can recognize every single road. Note that I included every by-street and parking lot, and got a total of 72 nodes. Excluding parking lots will bring this number down to approx. 25 nodes.
A single node looks like this:

Node

It has a specific ID, coordinates, and has every possible exit to another node given in a list. The number after behind the id is the speed limit of that piece of road (unit is mph). Also you can use different booleans, e.g. intersection, highway, pedestrianOnly, …, that could later be used to modify the behavior of that pathnode.
Note how these pathnodes have MUCH fewer variables and information than Rockstars’ system.

Yes, you’ll never get me back, now that I showed you that I do not only produce insane ideas but actually do parts of it.
Is creating pathnodes for the rest of the map insane? Yes, but it’s only time intensive, you can very well
create a small ingame script for it.

A result for the A-star algorithm looks like this:

Liste

It’s simply a list of the IDs of the pathnodes the entity needs to cross.

Serverside movement
While client-side movement needs to be smooth, you can simulate the serverside movement using a while loop on a Wait(500) and simply assume the paths between two pathnodes to be linear. No one is ever going to see movement that only happens serverside. As soon as you try to get near the entity, Rockstars’ system takes over. That way it shouldn’t be too much of a problem to actually simulate entity movement.

With this base-idea in mind let’s check what I have already published and what I intentionally hid from the public :smiling_imp:

7 Likes

You scrolled until here and might even have read as far, so without further ado, here’s the github link :smiley:

https://github.com/xSilvermanx/serpent

The last update I did in public about this was in January. So take the time and look into the Youtube-video to see how Serpent acts ingame.
So looking at the github, where the hell do I start?

Let’s go through it and check what of the description above can be found in the scripts.

The startup
When loading the resource the most important parts happen in the files Def/def_sv.lua, Startup/startup_sv.lua and of course Main/main_sv.lua.

As explained in The main idea for a solution the peds and vehicles get created serverside and every bit of information is saved in serpent itself. def_sv.lua creates the tables that will be filled with every serpent-ped (a ped that is controlled by serpent; this is opposed to your normal ped that will be spawned and despawned by GTA and which has nothing to do with this resource).
The file startup_sv.lua starts the main-loop inside main_sv.lua and creates event handlers for when players connect. This makes it possible for serpent to store the player information as described in Player-Position above.

The serverside main thread
Main/main_sv.lua lines 173 to 215 is the central piece of code for serpent. This is a loop triggered every 500 ms. Every single serpent-ped is controlled from here, by asking the very same question:

Is any player close enough to the ped so that it has to be spawned in the game?
If yes, spawn the ped and move the responsibility over to a client. (more on that later)
If no, execute the task the the ped has been assigned.

Let’s go through the code using an example. Let’s create a ped utilizing serpent:

local ModelName = 'a_f_m_beach_01'
local ModelHash = GetHashKey(ModelName)

local SID = exports.serpent:ssv_nat_CreatePed(26, ModelHash, -180.0, 6190.0, 31.2, 66.0)

Yes, this is serverside code resembling the FiveM-native CreatePed. The executed code is found in Main/main_sv.lua lines 3 to 154. Note how we can define the position, the model hash and everything else and have it saved in the serpent ´ssv_PedList` (ssv is short for serpent serverside).

Now the server knows the ped and utilizing the SID (short for Serpent ID) you can assign commands to that ped from the server.

Let’s assume that two players are on the server, both in Los Santos. Let (x = 0, y = 0, z = 69) and (x = 30, y = -50, z = 100) be the positions for those players.
The main thread will calculate the distance from the spawned ped to both players and will determine whether a player is in spawning range. That isn’t the case as the spawnrange has been set to 175 meters.
Now when a player moves closer the script would be able to recognize that, thus eventually spawning the ped (more on that later).

The clientside main tasks
Every spawned client has one main task: Continually inform the server about your position. In serpent this is solved in the main loop in Main/main_cl.lua line 7 (The rest of the loop will be explained further down). So every single player will be broadcasting his position to the server every 500 ms.
That’s it. The rest is handled by the server.

Executing commands for serverhandled peds - how do peds act on the server?
For the enduser this is trivially easy. Take the SID we have fetched above and do this:

exports.serpent:ssv_nat_TaskFollowNavMeshToCoord(SID, -224.0, 6149.0, 31.2, ,1.0, -1, 2.0, true, 'Curr', false)

This is serverside code and emulates TaskFollowNavMeshToCoord.
How is this done?
Assuming that our ped is not near a player the Main Server Loop will trigger the Main Task Handler at Main/main_sv.lua line 207, main task handler is located same file at lines 217 - 236.
The task of the MainTaskHandler is to understand which task the ped should be doing currently and triggering the correct serpent event. For that it reads the data saved for the serpent-ped and sends the necessary data further to the next event.
In this case we are triggering a so called Current event TaskFollowNavMeshToCoord, so the main task handler will trigger the event ssv:nat:TaskFollowNavMeshToCoord.

Handlers for the serverside tasks
Our next stop is the file Natives/Handler/TaskFollowNavMeshToCoord.lua. The first function (lines 1 - 66) define the export that we have already used above. This function only saves data into the ped-table and can be ignored for now.
The important part starts at line 68:
The task FollowNavMeshToCoord knows two states (out of three possible): Init or Initialize and Continue (the third state would be Ignore).
This does what it says on the tin: Init will create much of the data that can be reused later, so Continue will in general be shorter.
The event starting line 68 will check for the current state and trigger the appropriate function, then change the state appropriately. It also includes a check for successful termination of the task, located at lines 85 - 93 (checking for the distance needed to be travelled and finishing the event).

As we have only just entered the command, the script will execute Init.

Initialising a task
FollowNavMeshToCoord needs pathfinding. I have implemented a working version of A-Star and pathnodes for Paleto Bay. It’s already been stated in the first post so I’ll not comment on this even though a bit has changed since the main assumption is still the same.
First we are checking whether PathfindingData is already existing. If not we create the pathfinding data for the current task (lines 110 - 162, the main function is line 145). Note line 152, which will send the created data to a client if the ped is currently spawned.
After the pathfinding data has been created the function will read out the next target position for the ped. This will in general be the next node in the pathfinding data, so a set of coordinates x, y and z (lines 179 - 215). It also checks whether the node has been reached and the next node should be targeted (lines 164 - 177).
Lastly it checks whether the ped is spawned or not and executes either the server-version or the client-version of the native.
As our ped is not spawned it executes ssv:nat:res:TaskFollowNavMeshToCoord:Init as in line 226.

Moving the ped on the server
The file is Natives/Server/TaskFollowNavMeshToCoord_sv.lua. This is classic linear algebra. I’m fetching the current position and the end position. From that I calculate the vector between them and normalize that vector (so that I got a vector pointing to my goal with a length of 1 m). Now I’ll multiply the vector with the speed of my ped (i.e. 1.0 m/s).
The resulting vector is the distance the ped moves in 1 second. So in order to get the new position of the ped I’ll add half of that vector to the current position (reason for half the value is because the main loop works on 500 ms or half a second).
I’m already finished here and got my ped moving whereever I want as long as pathnodes exist for that place.

Continuing the task
After the ped has moved one step (the distance in half a second) the main loop continues and will at some point get to my ped again. The task handler gets triggered just as described above, this time however the task is set to Continue. This doesn’t change too much; however the script can fetch saved values instead of recreating them thus hopefully speeding up quite a bit.

The real task will come however when
Players get closer to the ped
At this point the Main Server Loop will not trigger the Main Task Handler but rather the function ssv:SpawnPed (Main/main_sv.lua line 204, function lines 238 - 250). This saves necessary data and shoves all of it to the player who got close to the ped.

Now it’s time for the Main Client Loop to take over (Main/main_cl.lua lines 1 to 32). The client loop will check for every ped in the clients’ responsibility whether it is still inside the despawning range (200 meters). For now this is only our ped we spawned but later on there might be multiple peds that the client controls.
The functionality of this loop is the same as the main server loop. Check whether the player is still close. If yes, trigger the task handler, if no, trigger the despawning function.
Let’s assume the player is close, triggering the clients’ main task handler.

A word on distance
You might have noticed that the spawning range 175.0 is different from the despawing range 200.0 . This is to avoid cases of player’s edging in and out of spawning range with every tick, meaning the serpent-ped spawns and despawns every 500 ms. Having different distances eliminates this issue.

Triggering the clientside task handler
This function (Main/main_cl.lua lines 34 to 54) does the same as the serverside task handler. Note that the client task handler still triggers the serverside event handler as described above.
This is because the event itself checks whether the ped is spawned.

Tasks triggering clientside
Check Natives/Handler/TaskFollowNavMeshToCoord.lua lines 219 - 224. This is what is triggered for the Init-version of the native but is the same for Continue. The script checks for the entity ownership and triggers the clientside function for the entity owner.
Note that entity ownership (i.e. FiveM / GTA V-assigned ownership) and serpent-ownership might be two different clients!

Tasks executing clientside
The file is Natives/Client/TaskFollowNavMeshToCoord_cl.lua. We’ll disregard the boolean persistFollowing for now so assume that one is set to false. We’ll thus check lines 3 to 33. Basically the script will check for a safe end coordinate for the ped (lines 6 to 15, so it doesn’t stop in the middle of the street) and then trigger the GTA V-native just normally (line 33).
That’s it, task is executing on the client.

Players moving away
Now let’s assume that the player who has first spawned the ped (and thus has serpent ownership) moves out of the despawning range. The players’ main client loop notices this and triggers a despawning function (Main/main_cl.lua lines 129 - 138). Unlike the name suggests this does NOT despawn the ped. Instead it merely deletes the information on the client and sends control back to the server (line 135).

Now the server takes over (Main/main_sv.lua lines 263 - 304). It resets a few informations and then checks if any other player is still near said ped. If yes it’ll transfer ownership over to that player. If no it’ll despawn the ped and resume ownership itself, thus making the main server loop responsible again.


That was quite technical here. I hope to have explained the code in a way that it’s understandable what is happening behind the scenes.
If you want to test out the script, you are welcome to use the following server side code:

local ModelName = 'a_f_m_beach_01'
local ModelHash = GetHashKey(ModelName)

local SID = exports.serpent:ssv_nat_CreatePed(26, ModelHash, -180.0, 6190.0, 31.2, 66.0)

Goals = {
  {x=-224.0, y=6149.0, z=31.2, h=66.0},
  {x=-180.0, y=6190.0, z=31.2, h=246.0}
}

local goalcoordinate = 1

RegisterCommand("movetocoord", function(source, args)
  local x = Goals[goalcoordinate].x
  local y = Goals[goalcoordinate].y
  local z = Goals[goalcoordinate].z
  local h = Goals[goalcoordinate].h

  print('Triggering export function')
  exports.serpent:ssv_nat_TaskFollowNavMeshToCoord(SID, x, y, z, 1.0, -1, 2.0, true, 'Curr', false)

  if goalcoordinate == 1 then
    goalcoordinate = 2
  elseif goalcoordinate == 2 then
    goalcoordinate = 1
  end
end)

Load in serpent, load in the above code as a separate resource and use the chatcommand /movetocoord. It might bug a bit but a ped should be moving between two coords on the main street of Paleto Bay.

Have fun testing it out and finding bugs :smiley:

In order to see what the server is doing you can enable server prints in Startup/startup_sv.lua. Uncomment lines 35 to 47 and you are good to go.
Beware: I was able to bluescreen my PC several times when running a local server and filling my console with printed data…

Again, any questions feel free to post here in this topic or hit me up :slight_smile:
Thanks for sticking by to this point, yes it’s a VERY long one. Hope it’s worth the read (and I hope that you don’t want to admit me to psychiatry due to obvious insanity, I mean who would seriously commit to such a project?).

6 Likes

To boldly fail where others have failed before…

That was the correct Star Trek quote, wasn’t it? Anyways, sadly I’m unable to commit much time to this project thus it’s stagnating for quite a while. Realizing that I’ll never finish this I decided to make it public (thus you getting the github-link; already forgot it? Here it is again: GitHub - xSilvermanx/serpent)

So, spawning and despawning of peds is in a working state, without known problems even for multiple players. There might be an issue crashing the game if too many peds get spawned at once, I only got that while spawning 100 peds inside of each other so that was to be expected…

Edited - However Serpent is currently missing the following features:
There are no functions related to vehicles.
There is no DeletePed()-function.
There’s no natives to sync appearance of peds.
There’s next to no Task-natives.
There are no nodes outside of Paleto Bay.

This is all something that needs time which I sadly cannot allocate.
Now I know I’m basically asking for people to finish my project…
But I hope that the possibilites of this project are a motivation to collaborate to get this done. I can offer every bit of advice I can give, ideas and how to create them in code. Also I do believe that I’m quite strong in bugfixing and finding errors in scripts.
So if you are interested in this project I’d be thrilled to talk to you above possible contributions. If you have zero experience coding but want to learn I’d be more than happy to have you on board as well! Creating the nodes will require no coding experience so there’s something to do for everyone!

If people are interested in this project I’ll set up a list of goals on the github in the next few days.

As usual, comments, feedback, ideas, slander are all appreciated.
Thanks for your timing reading this (or most likely skimming over it… :-P), hope to be talking to you soon.
Best,
Sebastian

3 Likes

Thank you for this post, dude. It was the best read I had on this forum so far, and you showed up just as I was about to try this myself.

What I am more concerned right now is the node issue.

While writing the coords “by hand” sound ok-ish in practice, scaling this for LS, or the entire map might be…hard…if not borderline impossible. Orrrr…you could (I think) get all nodes data from gtav using OpenIV, but again, have fun managing that in a script…

Then it comes to actual server movement, which is what kept me from ever trying this on a large(r) scale:

Yep, no one is going to see it, but you also have to make sure that whatever calculations you do to move between 2 nodes doesn’t send the ped under the map. If the idea is to have a seamless ped movement, we have to be prepared to load that ped at any time, and to make sure it doesn’t fall through the map because he was in between 2 nodes on different heights.

GetGroundZAndNormalFor_3dCoord - FiveM Natives @ Cfx.re Docs might help with that, to run it when a player loads that ped, but honestly I never managed to make this work properly…

Other than that, this sounds like a really useful project, and looking at the “issues” that you have, some of them might be really easy to fix / implement.

  • There are no functions related to vehicles. - I think vehicles need to be implement as “components / accessories” of a ped. Because you still need one to make the car drive.
  • There is no DeletePed()-function. I recently wrote a “MakeServerEntityAsNoLongerNeeded” function, here: Mark Server Entity As No Longer Needed · GitHub
    With a bit of planning, this should be enough…I think…
  • There’s no natives to sync appearance of peds. - I think you might need to just set ped components server-side, and they should sync. Maybe with SetPedRandomComponentVariation - FiveM Natives @ Cfx.re Docs

I believe CodeWalker has an XML export, though obviously it’s by sector.

Also, the actual game’s path nodes have a variety of height data for proper interpolation. :stuck_out_tongue:

I’d link reVC as a reference of how a basic variant (w/o sector logic, this was introduced in SA) of CPathFind looks, but >DMCA takedown :confused: Google "pathfind.cpp" re3 miami for some info I guess.

DeleteEntity works, but no obvious no-longer-needed thing built-in nor an equivalent of IsSphereVisibleToAnotherMachine - FiveM Natives @ Cfx.re Docs yet.

…now that I’m thinking… what if the server doesn’t have to care about nodes? Could we force a client (at gunpoint if needed) to calculate the next nodes for us, and send those directly to server? Maybe with GetNthClosestVehicleNodeFavourDirection - FiveM Natives @ Cfx.re Docs or similar?

Not if they’re not nearby enough to have it loaded and you don’t want to burden them with loading everything ever at all times.

Good project.

@Silverman Great work! Excited to see this come out finally. More people need to see this and beta test, collaborate etc…

I wouldn’t be too worried about that. It should easily be possible to set up a small script so you can run around and have the nodes created by pressing a button, completely configured. That is pretty easily visualizable as seen below and having a few people collaborate should see San Andreas filling up with nodes quickly.
As for the total scope:
GTA V has around 70.000 pathnodes hence the need to group them to zones.
I’d estimate the total amount of serpent-pathnodes to be around 7.000, so a factor 10 smaller and most likely going to work without zones. Atleast I’d hope so: We are only ever talking single NPCs, not filling the map with serpent-npcs. I hope that A* will manage that with 7k nodes.

Actually no :smiley:
You see, I’m only roughly assuming the position of the ped and intend to get away with that. So I have zero problems with triggering the native GetSafeCoordForPed() or GetClosestVehicleNode() ensuring no one falls under the map. And the small offset will be easily synced without anyone ever noticing.

I have edited the third post to be more clear. My “issues” aren’t issues but things that aren’t done yet. E.g. you can’t currently delete a serpent ped from the server ped list :smiley:
Everything is mostly easily doable. However here’s my problem - I really, really don’t have the time to do all this on my own.

So yeah - I’m looking for you and hope that you’d be interested in helping out as much as possible. And if you now think “Yeah, he’s talking to CritteR” - right and wrong. I mean CritteR and you :stuck_out_tongue:

Bubble also answered this - I actually have tried getting this to work but couldn’t get the natives to work properly. The one you link might be possible but then again it’d be hugely expensive to calculate.

So if you followed my post history you’ll notice that I posted serpent-related things two times, both times failing massively thanks to natives not working like I want them to :smiley:

But there’s been progress, and I want to tease said progress with a small game:

Which location on the map is depicted with the following picture?

3 Likes

Its grapeseed, I think an aerial from above the airport?

Is this still a project?

Well kind of. So the pathfinding part is done, as is the code for TaskVehicleDriveToCoord.
This means that the main thing missing currently is connecting and debugging the pathnodes. Then qol functions etc. and generally making this usable.
My issue: Way to few time thanks to numerous other projects. Also I broke my wrist three months ago basically right when I was starting to code on this again. Perfect timing as usual.

If you want to help, shoot me a DM :slight_smile:

This project is brilliant. I will be lurking in the background, but the writeup was phenomenal, and solves an awesome problem regarding general entity management. I assume this would be friggin psychotic getting this working for something like aircraft (with a full 3 dimensional range of motion and varying degrees of speed), but still an awesome project nonetheless.

Hey everyone,

just a heads up - after over 3 years I think that a first kinda usable version is ready. Didn’t pack this up as a release, didn’t document too much (or anything really), but I did quite a few updates over the last two weeks. Note that I obviously couldn’t run full scale tests so there might be a few resource-breaking bugs in there.
Usage: Easy - import serpent and look into the file serpent_event_exports.lua. You can check which natives are currently usable in fxmanifest.lua. Most of them behave just like the natives with the sole exception that you use the SerpentID for the Ped (PedSID) or Vehicle (VehSID), not the NetID or local ID.
E.g. TaskVehicleDriveToCoord(ped, vehicle, x, y, z, speed, p6, vehicleModel, drivingMode, stopRange, p10 can be used in serpent like this:
exports.serpent:ssv_nat_TaskVehicleDriveToCoord(PedSID, VehSID, x, y, z, speed, drivingStyle, stopRange, ObjType) where ObjType is ‘Curr’ for Current, ‘Next’ or ‘Override’. When in doubt set ‘Override’.

local ped = CreatePed(pedType, modelHash, x, y, z, heading, isNetwork, bScriptHostPed)
would be
local PedSID = exports.serpent:ssv_nat_CreatePed(pedType, modelHash, x, y, z, heading).

To check out some simple stuff, use the following commands:

local VehModelName = 'Police'
local VehModelHash = GetHashKey(VehModelName)
local VehSID = 0

RegisterCommand('CreateVeh', function(source, args)
  VehSID = exports.serpent:ssv_nat_CreateVehicle(VehModelHash, -459.79, 5878.41, 33.25, 321.11)
  print(VehSID)
end)

RegisterCommand("DeleteVeh", function(source, args)
  exports.serpent:ssv_nat_DeleteVehicle(VehSID)
end)

local PedModelName = 'a_f_m_beach_01'
local PedModelHash = GetHashKey(PedModelName)
local PedSID = 0

RegisterCommand('CreatePed', function(source, args)
  PedSID = exports.serpent:ssv_nat_CreatePed(26, PedModelHash, -454.34, 5882.84, 33.15, 72.14)
end)

RegisterCommand('DeletePed', function(source, args)
  exports.serpent:ssv_nat_DeletePed(PedSID)
end)

RegisterCommand('EnterVehicle', function(source, args)
  exports.serpent:ssv_nat_TaskEnterVehicle(PedSID, VehSID, -1, -1, 1.0, 1, 0, 'Curr')
end)

RegisterCommand('TaskVehicleDriveToCoord', function(source, args)
  exports.serpent:ssv_nat_TaskVehicleDriveToCoord(PedSID, VehSID, 219.32, 6572.94, 31.89, 30.00, 524988, 2.0, 'Next')
end)

Have fun trying this out. Would love to hear about all the game-breaking bugs you encounter while testing :smiley:

2 Likes

I’m glad I got a notification for this. I’m working on trying to figure out taxi navigation for planes in game, and realized I had to do some variant of BFS, A*, or dijkstras. But before I could get to that, I forgot that I had to create some undirected graphs and was having a looot of trouble trying to figure out a way to store all of the information. Then, like magic, all of a sudden, you made a post and I re-read through this finding exactly the example I needed for the graph representation.

I may use this resource for my use case if my idea fails, but please know, the value in you sharing your thought process is priceless as is! Cheers!

1 Like

I think that serpent should cover your problem basically already. Only thing necessary is to set the necessary nodes for planes.
I added a ToDo to my list to allow custom nodes to be added to A* or to use custom node list as a whole. Might also free up A* to be accessible as an export if that is interesting?

1 Like

I agree, but I have to deal with flight data which is a whole other can of worms (runway alignment, airspace avoidance, handling envelope, etc) - I wanna try to tackle this clientside as a networked entity. If this crashes and burns (pun intended), I will try to make serpent work!

Also, A* as an export is a good idea, but at that point, it may need to be its own resource in that case (but that’s just my uneducated two-cents).