[Remote Streaming / Focus] How can I achieve distant missile effectiveness?

Hello everyone!

When it comes to rockets in GTA V, they work great, HOWEVER, when it comes to rockets mounted on aircraft, there’s a pretty obvious problem:

LODS.

Context on Lods:

LOD means level of detail and it allows systems to render the GTA V map, vehicles, and entities ONLY when the player is near. This saves players from needing to have to render everything at once.

The problem:

Imagine a scenario where you want to conduct an airstrike from a long distance with a longrange missile.

Based on what you now know about LODS, when the missile strikes the ground, it will simply pass through because the collision and associated entities haven’t yet rendered. This is because the player’s not close to the entity yet. (hope this is clear)

This is problematic because you have to be close to the target in order to use your missiles, otherwise air-to-ground attacks become pointless.

Potential ideas:

When it comes to snipers, when zooming in on a far land, the entities and objects, vehicles, peds, etc all magically render.
This is due to something called “Focus” which allows the player to ‘render in’ the area in question allowing them to see everything clearly, and more importantly, HIT anything that can be hit.

More info here:

The question:

Since I need to be able to render a specific area of interest (based on where a launched missile is going, OR based on a static location), HOW can I allow for remote rendering of ‘areas of interest’ dynamically so that I can blow up a convoy, or take out a ped from a distance, or allow ped code to run while the player’s not necessarily nearby?

I may be missing something, so let me know if there are any natives, or if anyone has solved for a similar problem!

Cheers
-Wet

SetFocusEntity SetFocusEntity - FiveM Natives @ Cfx.re Docs
You need to freeze the PlayerPedId so they dont fall through the non rendered map they are standing on when focus moves. The missile I believe would be an entity you can focus, so they would see properly near the missile all the time. If the missile is somehow not an actual entity, probably easiest to make a faux entity that is invisible that is the missile.

For sure. Do you know if the focus can exist for more than one entity at a time? Like simultaneously a player and the additional map data he wants to render?

RequestCollisionAtCoord - FiveM Natives @ Cfx.re Docs and HasCollisionLoadedAroundEntity - FiveM Natives @ Cfx.re Docs ?

1 Like

99% sure you can only have a single focus (entity) for a player at any one time, you’ll have to find workarounds there

1 Like

As far as I know, not properly. You could swap focus every other/few frames maybe but I think that wouldn’t function as desired if at all.

1 Like

Swapping focus every few frames will crash the game, or at least lag it out severely - not a good idea lol

1 Like

I believe this doesn’t load drawables at their nearest LOD

If I may ask though, why would you want to load both?

Damn, I summoned the avengers, LMAO

Imagine a single player minigame where there’s a regular gunbattle between goons and good guys, and as the aerial unit, your job is to tip the scales in your teams favor.

In this case, you’d want your code to be able to run (gun battle, flanking, etc) without having to worry about despawning, falling through collisions, drawables derendering, etc.

For that, you’d need at least TWO focus areas. ONE for the player as they fly through, and another one for the target area. So no matter what altitude the pilot strikes from, the shots will always hit.

Another example is the new titan 250D.

You should be at a reasonable altitude, but still be able to strike your targets from above. It’s hard to do that without entities, collisions, and focus areas.

As far as I understand a player flying a plane doesn’t need focus to continue flying “properly” as the physics still runs relatively fine just no collisions. As for having the battle wage on, it probably wouldn’t be great but I think you would have to essentially move the battle with the player and keep them in the players standard focus area. You could focus the main battlefield and then the player would start to see weird LODs when they started to leave the field and know to turn back.

a player flying a plane doesn’t need focus to continue flying “properly” as the physics still runs relatively fine just no collisions.

Yes and no. The player as they swoop down low to avoid other aircraft, or navigate a complex path, they’d also need their own focus (collisions, entities, drawables, etc) so that it doesn’t look like crap, as explained by your next sentence:

You could focus the main battlefield and then the player would start to see weird LODs when they started to leave the field and know to turn back.

Yeah, that was what I was afraid of… :frowning:

Thanks for your input though! Sad this is the case.

I did see something pertaining to SRL’s. BeginSrl - FiveM Natives @ Cfx.re Docs. Not sure if htis is useful, but I have yet to test it…

Maybe it’s a good alternative to focus!

here’s some of the natives I’m going to experiment with:

To test throughout the week(end)

SRL stuff - Streaming Request Lists. Must be started, preloaded, begun, and ended from what I see…

Load_Scene (and variations) - Loads a scene at a position (not sure what the constraints are)

New_Load_Scene_Start_sphere - Loads a location (could be within an interior or not).

[Shoutout @Kiminaze ] Request_additional_collision_at_coord - (Must be called every frame). Streams collision and IPL’s near the coordinate

Set_HD_AREA - apparently sets a radius where assets will have their HD versions pinned.

STREAMVOL_CREATE_FRUSTUM - Creates an odd shaped area where streaming requests can be called

Streamvol_create_sphere - Creates the same as the above, but in a sphere.

These look pretty damn promising and seem to al lhave their own resource costs. I’ll post the results I get later…

2 Likes

First things first:
Tracking. I needed to make sure I had a way of tracking peds when they got near / left the focus area. To do so, I used a script I like to call “Lookiehere” which heavily borrows from a player called @anders - Much thanks for the resource!

listofpeds = {}












--LOOKIE HERE CODE!

local function RotationToDirection(rotation)
        local adjustedRotation =
        {
                x = (math.pi / 180) * rotation.x,
                y = (math.pi / 180) * rotation.y,
                z = (math.pi / 180) * rotation.z
        }
        local direction =
        {
                x = -math.sin(adjustedRotation.z) * math.abs(math.cos(adjustedRotation.x)),
                y = math.cos(adjustedRotation.z) * math.abs(math.cos(adjustedRotation.x)),
                z = math.sin(adjustedRotation.x)
        }
        return direction
end

local function RayCastGamePlayCamera(distance)
        local cameraRotation = GetGameplayCamRot()
        local cameraCoord = GetGameplayCamCoord()
        local direction = RotationToDirection(cameraRotation)
        local destination =
        {
                x = cameraCoord.x + direction.x * distance,
                y = cameraCoord.y + direction.y * distance,
                z = cameraCoord.z + direction.z * distance
        }
        local a, b, c, d, e = GetShapeTestResult(StartShapeTestRay(cameraCoord.x, cameraCoord.y, cameraCoord.z, destination.x, destination.y, destination.z, -1, -1, 1))
        return b, c, e
end



Citizen.CreateThread(function()
        while not NetworkIsPlayerActive do
                Citizen.Wait(0)
        end

        while true do
                Citizen.Wait(0)

                hit, coords, entity = RayCastGamePlayCamera(1000.0)

                if hit then
                        local position = GetEntityCoords(GetPlayerPed(-1))
                        DrawLine(position.x, position.y, position.z, coords.x, coords.y, coords.z, 255, 0, 0, 255)
                end
        end
end)

RegisterCommand("targetped", function(source, args)
        print(coords, entity)
        table.insert(listofpeds, entity)
        pedblip = AddBlipForEntity(entity)
end)

--LOOKIE HERE CODE ENDS!

Citizen.CreateThread(function()
        while true do
                if #listofpeds then
                        for _, v in ipairs(listofpeds) do
                                pedpos = GetEntityCoords(v)
                                DrawMarker(20, pedpos.x, pedpos.y, pedpos.z + 3.0, 0.0, 0.0, 0.0, 0.0, 180.0, 0.0, 5.0, 5.0, 5.0, 255, 0, 0, 50, 1, 1, 2, 0, 0)
                        end
                end
        Wait()
        end
end)

If you’re an active follower of fiveM posts, most of this should make sense to you already. The only thing that I’ve added was the table at the beginning and the thread for processing any peds added to the table. fairly simple stuff.
I’ve also added blips so that the entity can be tracked on the minimap.

The result?

Now that THAT’S out of the way, we can start testing the natives;

The first one:
Streamvol_create_sphere

Sounds promising.

To start, we create a command that registers the streamvol to a variable. Then we can play with the ID that’s assigned to that variable.

Context of Native:

//INFO:	This native Creates a sphere where streaming requests can be called.  
//		Returns index of volume if successful, or -1 otherwise

Arguments:

NATIVE(v3-position, float-radius, int-asset_type_Flags, int-lod_type_flags)

Asset Type Flags:

asset_type_Flags:

1 - Collision_mover
2 - Collisions_Weapons
12 - MapData? (Not sure what this means)

Lod Flags:

33 - High quality
94 - Low quality
127 - All types of quality

Generally speaking, flags can be added together to combine the usage of different flags. You can tell this by the types of individual numbers used in flags. A good rule of thumb is:
“Can I add any sets of numbers and be able to figure out which flags were used without any ‘overlap?’” If so, those are likely addable flags. (A good example of this is the unix user permission flags)

The code:

The best way to do something like this is to use a command, and that’s just what I did:

RegisterCommand('streamsphere', function(source, args)
        plyrad = 5000 --Radius
        ply = GetPlayerPed(-1)
        plyloc = GetEntityCoords(ply)
        print("Player Location is: " .. plyloc)

        print("Adding Streamsphere to queue")

        streamindex = StreamvolCreateSphere(plyloc, plyrad, 15, 33)

        if streamindex == -1 then
                print("Something's wrong! The stream was unable to be generated")
        else
                print("Success! - Your stream volume ID is: " .. streamindex)
        end

end)



RegisterCommand('checkstream', function(source, args)
        if #args > 1 or #args < 1 then
                print("[OneArgOnly] - Command requires exactly ONE argument!")
        else
                sstatus = StreamvolHasLoaded(args[1])

                if sstatus == false then
                        print("Stream Volume hasn't loaded")
                elseif sstatus then
                        print("Stream Volume is stream voluming (success!)")
                end

                --Streamvolume Valid/Active checks;
                sactive = StreamvolIsValid(args[1])
                if sactive then
                        print("Stream Volume is active and valid")
                else
                        print("Error: Stream Volume is NOT active nor valid")
                end
        end
end)

RegisterCommand('killstream', function(source, args)
        if #args > 1 or #args < 1 then
                print("[OneArgOnly] - Command requires exactly ONE argument!")
        else
                print("Deleting Stream Volume!")

                StreamvolDelete(args[1])
        end

end)

Code is simple enough (if you’re unsure of what it does, please reply to this thread with the quote!) - Simply invoke the command with /streamsphere and it’ll create a Streamvolume.

After performing this test, noclipping a few hundred meters away and back…

no luck

The ped disappeared when I came back. Sadface.
Oh well! On to the next native.

SetHDArea

This one is pretty basic.

HDarea sets a sphere where all assets will have their HD assets triggered.

You should also use ClearHDArea as well (which doesn’t seem to take any arguments…)

Time for another command:

RegisterCommand('hdarea', function(source, args)
        ply = GetPlayerPed(-1)
        plyloc = GetEntityCoords(ply)
        print("Player Location is: " .. plyloc)

        print("Setting HD Area")
        SetHdArea(plyloc, 5000)

end)


RegisterCommand('clearhdarea', function(source, args)
        ClearHdArea()
        print("HD Area Cleared")

end)

Results:

No luck :frowning:

Entities and peds seemed to disappear after going a distance from the originating area and returning.

On to the next test…

RequestAdditionalCollisionAtCoord

Another basic native. Must be called every frame.

// have game stream extra collision and IPL files around this coordinate. 

Not sure what the range for this is…

Anyways, here’s the command I have for this

reqcolflag = 0

RegisterCommand('racac', function(source, args)
        if #args > 1 or #args < 1 then
                print("Error, only one argument - on or off")
        end
        if args[1] == 'on' then
                ply = GetPlayerPed(-1)
                plyloc = GetEntityCoords(ply)
                reqcolflag = 1

        elseif args[1] == 'off' then
                reqcolflag = 0
        end
end)

Citizen.CreateThread(function()
        while true do
                if reqcolflag == 1 then
                        RequestAdditionalCollisionAtCoord(plyloc)
                        --print("Debug - Coll requested")
                end
                Wait(0)
        end
end)

Simple enough. 2 parts - a thread that runs the code checking for the toggleswitch being on, and the command itself to toggle the switch.

Results:
Still no luck :frowning:

More derendering of entities…

Next up…