PlaceObjectOnGroundProperly? I don't think so!

Hey there, folks,

I’m facing a slight issue at the moment, I’m trying to have objects generated randomly around the map, which ideally will be placed on the ground correctly, hence why I wish to use the PlaceObjectOnGroundProperly() function.

My issue however, is that despite generating the object, using this method, having the object account for gravity, having a blip to identify the object still exists, even using a debug line to show the distance to the object… it doesn’t always show on the “ground”.

					datapack = CreateObject(model, nx, ny, GetGroundZFor_3dCoord(nx, ny, 1000), true, true, true)
					PlaceObjectOnGroundProperly(datapack)
					SetModelAsNoLongerNeeded(model)
					SetEntityAsMissionEntity(datapack, true, true)
					
					
					datapack_blip = AddBlipForEntity(datapack)
					SetBlipSprite(datapack_blip, 161)
					SetBlipColour(datapack_blip, 4)
					-- SetBlipAlpha(datapack_blip, 0.5)
					SetBlipAsShortRange(datapack_blip, true)
					
					
					BeginTextCommandSetBlipName("STRING")
					AddTextComponentString("Unknown Signal")
					EndTextCommandSetBlipName(datapack_blip)

(Not sure why it’s not formatting correctly, my apologies)

But yes, despite attempting to get the highest Z point, then placing on the ground correctly (removing this line doesn’t fix the issue), just seems like I’m going around in circles.

You should be using 1000.0 not 1000. Also you may want to check what’s being returned from that function. Collision is streamed so you might be trying to get the ground for an area where the collision isn’t currently loaded.

Ah I see, thank you for this,

Originally I was simply spawning it at say… x, y, 1000.0, then placing on the ground properly (rather than GetGroundZFor_3dCoord, which I assume may be what that function does anyway), however the point you make about collision being streamed and having not correctly loaded does make me wonder.

Would there be anyway to “load” this particular region? Perhaps through a while loop until the area is correctly loaded THEN create the object?

An interesting concept.

Yes there is REQUEST_COLLISION_AT_COORD. People usually pair that with the groundz native to determine when the area has loaded. However I’m not sure how well that will work if you are trying to request a bunch of areas around the map. Also I don’t know how the game decides to unload the requested collision. Though to work around collision unloading you could freeze the object after you place it on the ground.

So it certainly seems to be an issue regarding distance and loading of areas, simply lowering the radius from 1000 to 500 seems to have resolved this.

Of course I’m not sure if it’s different for every player?

Alright, so in regards to an update for this…

This generates the object, however I find that it remains firmly underground.

datapack = CreateObject(model, nx, ny, z - 100.0, true, false, true)
					
RequestCollisionAtCoord(nx, ny, z)
while not HasCollisionLoadedAroundEntity(datapack) do
	RequestCollisionAtCoord(nx, ny, z)
	Citizen.Wait(0)
end
PlaceObjectOnGroundProperly(datapack)

However this, where I’m attempting to get the ground level for the point (while still loading the area and whatnot), I find that the objects don’t even generate (this is within a 100 meter radius, so I’m clearly near enough)

datapack = CreateObject(model, nx, ny, z - 100, true, false, true)
					
RequestCollisionAtCoord(nx, ny, GetGroundZCoordWithOffsets(nx, ny, z))
while not HasCollisionLoadedAroundEntity(datapack) do
	RequestCollisionAtCoord(nx, ny, GetGroundZCoordWithOffsets(nx, ny, z))
	Citizen.Wait(0)
end
PlaceObjectOnGroundProperly(datapack)

It could be I’m missing something very obvious, which wouldn’t be the first time, but granted, this particular bit is new to me, so it’s a learning experience non the less.

Update: I’ve also tried using the standard GetGroundZFor_3dCoord function instead, however this still results in Objects staying underground.

datapack = CreateObject(model, nx, ny, GetGroundZFor_3dCoord(nx, ny, z), true, false, true)
FreezeEntityPosition(datapack, true)
					
RequestCollisionAtCoord(nx, ny, GetGroundZFor_3dCoord(nx, ny, z))
while not HasCollisionLoadedAroundEntity(datapack) do
	RequestCollisionAtCoord(nx, ny, GetGroundZFor_3dCoord(nx, ny, z))
	Citizen.Wait(0)
end
					
FreezeEntityPosition(datapack, false)
PlaceObjectOnGroundProperly(datapack)

I have test it with random props and different heights for you.It work but i don’t know if this is exactly what you need.
This is not some much different to your’s but props don’t fall through the ground.

local positions = {
{x= 266.79,y= -570.0,z= 43.31,h=340.78},   
{x= 277.58,y= -553.66,z= 43.31,h=342.44},
{x= -1728.26,y= 43.02,z= 67.29,h=35.35},
{x= -434.33,y= -1552.94,z= 38.74,h=156.67},
{x= 456.93,y= -2101.35,z= 21.94,h=319.39},
{x= -1106.95,y= 261.65,z= 63.70,h=264.80},
{x= -229.12,y= -612.21,z= 33.18,h=341.27},
{x=-1193.14,y=-849.12,z=14.11,h=127.46},	 
{x=936.45,y=5510.12,z=551.83,h=127.46},	
{x=-1088.77,y=3662.23,z=293.14,h=127.46}	
}





local objects = {
"PROP_BAR_PUMP_09",
"PROP_BAR_PUMP_10",
"PROP_BAR_SINK_01",
"PROP_BAR_STOOL_01",
"PROP_BASEJUMP_TARGET_01",
"PROP_BASKETBALL_NET",
"PROP_BATH_DIRT_01",
"PROP_BATTERY_01",
"PROP_BATTERY_02",
"PROP_BBALL_ARCADE_01",
"PROP_BBQ_2",
"PROP_BBQ_3",
"PROP_BEACHBAG_01",
"PROP_BEACHBAG_02",
"PROP_BEACHBAG_03",
"PROP_BEACHBAG_04",
"PROP_BEACHBAG_05",
"PROP_BEACHBAG_06",
"PROP_BEACHBAG_COMBO_01",
"PROP_BEACHBAG_COMBO_02",
"PROP_BEACHBALL_02",
"PROP_BEGGERS_SIGN_01",
"PROP_BEGGERS_SIGN_02",
"PROP_BEGGERS_SIGN_03",
"PROP_BEGGERS_SIGN_04",
"PROP_BENCH_01B",
"PROP_BENCH_01C",
"PROP_BENCH_04",
"PROP_BENCH_05",
"PROP_BENCH_09",
"PROP_BETA_TAPE",
"PROP_BEWARE_DOG_SIGN",
"PROP_BH1_03_GATE_L",
"PROP_BEACHFLAG_LE",
"PROP_BEACH_BARS_01",
"PROP_BEACH_BARS_02",
"PROP_BEACH_BBQ",
"PROP_BEACH_DIP_BARS_01",
"PROP_BEACH_DIP_BARS_02",
"PROP_BEACH_FIRE",
"PROP_BEACH_LG_FLOAT",
"PROP_BEACH_LG_STRETCH",
"PROP_BEACH_LG_SURF",
"PROP_BEACH_LOTION_01",
"PROP_BEACH_LOTION_02",
"PROP_BEACH_LOTION_03",
"PROP_BEACH_PUNCHBAG"
}

local test = false
Citizen.CreateThread(function()			 

  while true do
   Wait(0)		
  if not test then 
    
	for k,v in pairs(positions) do 
	  local model = objects[math.random(1, #objects)]		  
	  
	    obj = CreateObject (GetHashKey(model),v.x, v.y,v.z ,true, false, false)
			  PlaceObjectOnGroundProperly(obj)
		      FreezeEntityPosition(obj,1)			  		  
			  objblip =	 AddBlipForEntity(obj)
			  SetBlipSprite(objblip,270)
			  SetBlipColour(objblip,24)
			  SetBlipFlashes(objblip,true)
			  BeginTextCommandSetBlipName("STRING")
			  AddTextComponentString("Object")
			  EndTextCommandSetBlipName(objblip)
			  test = true
	end		  
  end
end
end)

Without FreezeEntityPosition some props fall others not.Maybe due directly to the way that each prop is suppose to be used?

In my case the location will always be a random location within a 500 meter radius of the player, so I can understand why sometimes the area hasn’t loaded in yet.

So on theory I should be able to translate this to my needs, using that rather than set locations, my only concern is with the ground, as it always seems to struggle to find the highest point at the given X and Y coordinates,

I’m not currently able to test this, but I shall do shortly!

You are using GetGroundZFor_3dCoord incorrectly, it returns 2 values. You want something like this(untested). I did a little bit of testing and the collision unloads almost immediately if there is nothing near it. I didn’t check if it stays loaded when there is a mission entity near by.

RequestCollisionAtCoord(nx, ny, 0.0)

local start = GetGameTimer()
local foundZ, z
local check = function() foundZ, z = GetGroundZFor_3dCoord(nx, ny, 2000.0) return foundZ end
while not check() do
	Citizen.Wait(0)
	RequestCollisionAtCoord(nx, ny, 0.0)
	if (GetGameTimer() - start) > 10000 then --Giveup after waiting 10 seconds
		break -- or return
	end
end

if not foundZ then
--Collision didn't load
end

--Spawn object
datapack = CreateObject(model, nx, ny, z, true, false, true)
--To check, does the collision get unloaded when there is an object there?

Alternatively you could spawn the objects frozen underground and occasionally check for underground objects to move them above ground when the groundz returns true.

1 Like

My apologies, I’m using this Native Reference page and it doesn’t really explain much on what it’s actually returning.

(I’m using natives.lua also to hopefully find useful functions, but that also doesn’t help me too much)

I shall test this shortly, thank you :blush:

I use ActivatePhysics when simulating airdrops, maybe that can help you?

Thank you very much for that code snippet, and sorry for not getting back to you sooner!

I’ve had a go with this, tweaked with some of the radius variables also, just to see if it can improve performance, however I’m finding that objects are still occasionally spawning under the ground :sleepy:

There was a mistake in my code. It looks like RequestCollisionAtCoord only works if you include it in the loop.

Aaaah that would explain that,

Now, is there a chance that these objects could be spawning on the “ground”, but inside of a hollow interior? I only ask as I’m still occasionally finding objects underground in areas which would lead me to believe it’s on the “ground” underneath.

I have make a lot of tests with GetEntityHeightAboveGround with object spawned on ground and other under.Difficult for me to explain with my bad english but i will try.
With GetEntityHeightAboveGround the results are for me clear but maybe i’m mistaken.
When an object is spawned on the ground(where we can walk,drive ect) the result of the native is ~1.0.
And when it spawn underground the results are also ~1.0…
I think that can explain why PlaceObjectOnGroundProperly don’t work like we suppose,
because the ground seems to be considered like 2 floors.
Just an idea i don’t affirm anything ^^.
And the props don’t seems to interact the same way because when a bench is spawned and we touch it ,it don’t fall through the ground and an other props spawned at the same location by the exact same way fall through.
For my test i’ve spawned 10 beach balloons and not any had fall through and at any locations.Also test with a 1000.0 radius.
You really need an expert :grin: .

I’m not sure. If you can provide some isolated code that I can test then I can look into it some more.

This is the entire thread for the spawning of “DataPacks”, I use a table which keeps track of the DataPacks, however I have another Thread which places markers over nearby DataPacks, however that also isn’t working.

(If the entity was to be removed, the blip would also dissapear, so I know it’s still there)

Citizen.CreateThread(function()
	while true do
		
		Citizen.Wait(5000)

		if #datapacks < 10 then
			
			x,y,z = table.unpack(GetEntityCoords(GetPlayerPed(-1), true))
			repeat
					
				Wait(1)
				
				if spawned == true then
					
					nx = x + math.random(-500,500)
					ny = y + math.random(-500,500)
						
					RequestCollisionAtCoord(nx, ny, 0.0)

					local start = GetGameTimer()
					local foundZ, nz
					local check = function() foundZ, nz = GetGroundZFor_3dCoord(nx, ny, 2000.0) return foundZ end
					while not check() do
						Citizen.Wait(0)
						RequestCollisionAtCoord(nx, ny, 0.0)
						if (GetGameTimer() - start) > 10000 then --Giveup after waiting 10 seconds
							break -- or return
						end
					end
					
					spawning = true
					--[[
					for player = 0,64 do
						if NetworkIsPlayerActive(player) then
							local player_ped = GetPlayerPed(player)
							px,py,pz = table.unpack(GetEntityCoords(player_ped, true))
							if (nx > (px - 20)) and (nx < (px + 20)) and (ny > (py - 20)) and (ny < (py + 20)) then
								spawning = false
							end
						end
					end
					]]
					
					if spawning then
					
					
						-- prop_laptop_02_closed
						local model = GetHashKey("prop_drug_package")
						RequestModel(model)
						while not HasModelLoaded(model) or not HasCollisionForModelLoaded(model) do
							Wait(1)
						end
						
						datapack = CreateObject(model, nx, ny, nz, true, false, true)
						FreezeEntityPosition(datapack, false)
						SetEntityAsMissionEntity(datapack, true, true)
						

						
						datapack_blip = AddBlipForEntity(datapack)
						SetBlipSprite(datapack_blip, 1)
						SetBlipColour(datapack_blip, 1)
						SetBlipAsShortRange(datapack_blip, true)
						
						BeginTextCommandSetBlipName("STRING")
						AddTextComponentString("Unknown Signal")
						EndTextCommandSetBlipName(datapack_blip)
											
						table.insert(datapacks, datapack)
					
					end

				end
			
				
			until (#datapacks == 10)
		end
	end
end)

Okay so the problem might be that the collision is unloading by the time the object’s model is ready. You should spawn the object underground, do the collision loading and then place the object on the ground. That will let us know if the issue is that the collision is unloading even though a mission entity is in the area.

Also unrelated, for player = 0,64 do should be for player = 0,255 do

Hi!

You don’t seems to care about what i say but you can try this :wink: :

local datapacks = {}
Citizen.CreateThread(function()			 

  while true do
   Wait(0)		
  local player = GetPlayerPed(-1)
  local pos = GetEntityCoords(player,1)
  local ground 
  
  if #datapacks < 15 then
    
	RequestModel("prop_drug_package")
	while not HasModelLoaded("prop_drug_package") or not HasCollisionForModelLoaded("prop_drug_package") do
	Wait(1)
	end			    
			    
    dataX = pos.x+math.random(-2000,2000)
	dataY = pos.y+math.random(-2000,2000)
	Z = pos.z+999.0
			        
	ground,dataZ = GetGroundZFor_3dCoord(dataX+.0,dataY+.0,Z,1)
				 
    if(ground) then
       
	   datapack = CreateObject(GetHashKey("prop_drug_package"),dataX,dataY,dataZ,true, false, true)
       SetEntityAsMissionEntity(datapack, true, true)
	   table.insert(datapacks,datapack)
	   --test = tostring(#datapacks)
	   --Citizen.Trace(test)
       local blip = AddBlipForEntity(datapack)
			 SetBlipSprite(blip,270)
			 SetBlipColour(blip,24)
			 BeginTextCommandSetBlipName("STRING")
			 AddTextComponentString("Object")
			 EndTextCommandSetBlipName(blip)
    end		              			   
   end
      	
end
end)

Tested with player in air drop.
Tested on chilliad.
Tested in the city.
Tested with different radius.
tested with 50 props.(can’t more,else my pc became laggy :smile: )

Tell me if it work for you please.

1 Like

That’s not the case at all, so I’m not sure why you’d make such accusations, but whatever works for you,

I shall test this out when I get the chance, however I’m curious as to what the “ground” boolean actually is. I’m aware GetGroundZFor_3dCoord returns two values, but does the first value corrospond to it being “safe” to place it, or perhaps it’s solid ground and not water? Something along those lines?