Getting data from world props?

I recently made a stealth system that lets players walk into bushes to become less visible that works for any entity using a bush/tallgrass model.

I later noticed how it didn’t work with the bushes built into maps so I tried to get the entity of those bushes using EyeTrace but it kept returning worldspawn, even at static models. Not even ents.GetAll() has a single prop_static in it.

Is there any way at all to get a static props model/position?

Either it is a different type of prop, check https://developer.valvesoftware.com/wiki/Prop_Types_Overview , or it cannot be acquired by Lua, but I believe there should be a way to do it.

I honestly don’t think there is a way to do it, I just ran my own map using all entities from that list and I couldn’t get prop_detail or prop_static using lua.

Edit: Only way I could see it working would be by making some module but I have no idea how to do that. :disappoint:

You can probably still grab what texture and or material from the trace and work off of that

Yep thats what im trying right now, my custom footstep system seems to detect when i walk in a bush.

Edit: Strange enough, prop_ragdoll is the only entity I can use to make a fully functional bush for my script.
prop_static works like it should, only problem is that it doesn’t affect the players visibility.
prop_detail turns into a fully static model that is impossible to go through and has a few hundred layers of shadows from the looks of it.
prop_physics works like it should but you cant shoot through it.
prop_ragdoll works like it should.

the HitBox key in TraceResult contains the internal index for the static prop – if you’re desperate enough, you could try parsing model/origin/angle from the bsp file.

if you/somebody still needs a way to get the location of a prop_static, you can use this:



local GAMELUMP_STATIC_PROPS = "sprp"
local STATIC_PROP_NAME_LENGTH  = 128
local LUMP_GAME_LUMP = 35
local LUMP_HEADER_SIZE = 16

-- size of StaticPropLump_t excluding origin/angle/proptype
-- todo: use the actual size of StaticPropLump_t...
local SUPPORTED_VERSIONS = {
--	[4] = 30,  untested
	[5] = 34,
	[6] = 38,
--	[7] = 42, untested
--	[8] = 42  untested
}


local function ReadInteger(f, numBytes) 
	local bytes = f:Read(numBytes)
	local shift = 8*(numBytes-1)
	local number = 0
	for i = 1, numBytes do
		number = number + bit.lshift(string.byte(bytes, numBytes - i + 1), shift - (i-1)*8)
	end
	return number
end


local function ReadStaticPropDict(f)
	local dict = {}
	local count = ReadInteger(f, 4)
	for i = 0, count - 1 do
		local bname = f:Read(STATIC_PROP_NAME_LENGTH)
		local name = string.sub(bname, 1, string.find(bname, "\0"))
		dict* = name
	end
	return dict
end

local function ReadStaticPropLump(f, dict, version)
	local propLump = {}
	local count = ReadInteger(f, 4)
	for i = 1, count do
		local origin = Vector(f:ReadFloat(), f:ReadFloat(), f:ReadFloat())
		local angle = Angle(f:ReadFloat(), f:ReadFloat(), f:ReadFloat())
		local proptype = ReadInteger(f, 2)
		f:Skip(SUPPORTED_VERSIONS[version])
		propLump* = { origin = origin, angle = angle, model = dict[proptype]}
	end
	return propLump
end


function GetStaticPropInfo(map)
	if not map then
		map = "maps/" .. game.GetMap() .. ".bsp"
	end
	
	local f = file.Open(map, "rb", "GAME")
	if not f then
		error("Couldn't open map: " .. map)
	end

	f:Skip(4 + 4) -- ident + version
	f:Skip(LUMP_HEADER_SIZE * LUMP_GAME_LUMP)

	local fileofs = ReadInteger(f, 4)
	f:Seek(fileofs)

	local lumpCount = ReadInteger(f, 4)
	for i = 1, lumpCount do
		local crc = f:Read(4)

		if crc == string.reverse(GAMELUMP_STATIC_PROPS) then
			f:Skip(2) -- flags 
			local version = ReadInteger(f, 2)

			if not SUPPORTED_VERSIONS[version] then 
				f:Close()
				error("Unsupported LUMP_GAME_LUMP version: " .. version )
			end

			local fileofs = ReadInteger(f, 4)
			local filelen = ReadInteger(f, 4)
			f:Seek(fileofs)

			-- todo: single function for GAMELUMP_STATIC_PROPS parsing?
			local dict = ReadStaticPropDict(f)

			f:Skip(ReadInteger(f, 4) * 2) -- skip leaf list
	
			local propLump = ReadStaticPropLump(f, dict, version)
			local pos = f:Tell()
			f:Close()
			assert(pos == fileofs + filelen)
			return propLump
		end
		f:Skip(2 + 2 + 4 + 4) -- flags + version + fileofs +  filelen
	end
	f:Close()
end


It’s a bit unpolished and might not work for every map (some source engine games use a different/updated format to store static props)

Example usage:



local propInfo = GetStaticPropInfo()
concommand.Add("static_prop_info", function(ply, cmd, args)
	local tr = ply:GetEyeTrace()
	if tr.Entity == game.GetWorld() and tr.HitBox ~= 0 then
		local info = propInfo[tr.HitBox]
		ply:ChatPrint("Model: " .. info.model)
		ply:ChatPrint("Origin: " .. tostring(info.origin))
		ply:ChatPrint("Angle: " .. tostring(info.angle))
	end
end)