--[[ | This file was obtained through the combined efforts | of Madbluntz & Plymouth Antiquarian Society. | | Credits: lifestorm, Gregory Wayne Rossel JR., | Maloy, DrPepper10 @ RIP, Atle! | | Visit for more: https://plymouth.thetwilightzone.ru/ --]] -- Copyright © 2022-2072, Nak, https://steamcommunity.com/id/Nak2/ -- All Rights Reserved. Not allowed to be reuploaded. local band = bit.band local meta = NikNaks.__metatables["BSP"] --- @class StaticProp --- @field Index number --- @field version number --- @field Origin Vector --- @field Angles Angle --- @field PropType string --- @field First_leaf number --- @field LeafCount number --- @field Solid number --- @field Flags? number --- @field Skin number --- @field FadeMinDist number --- @field FadeMaxDist number --- @field LightingOrigin Vector --- @field ForcedFadeScale? number --- @field MinDXLevel? number --- @field MaxDXLevel? number --- @field lightmapResolutionX? number --- @field lightmapResolutionY? number --- @field MinCPULevel? number --- @field MaxCPULevel? number --- @field MinGPULevel? number --- @field MaxGPULevel? number --- @field DiffuseModulation? Color --- @field DisableX360? boolean --- @field FlagsEx? number --- @field UniformScale? number local meta_staticprop = {} meta_staticprop.__index = meta_staticprop meta_staticprop.__tostring = function(self) return "Static Prop" .. (self.PropType and " [" .. self.PropType .. "]" or "") end meta_staticprop.MetaName = "StaticProp" NikNaks.__metatables["StaticProp"] = meta_staticprop local version = {} -- Base version from Wiki. Most HL2 maps are version 5. version[4] = function( f, obj, m ) obj.Origin = f:ReadVector() -- Vector (3 float) 12 bytes obj.Angles = f:ReadAngle() -- Angle (3 float) 12 bytes obj.PropType = m[f:ReadUShort() + 1] -- unsigned short 2 bytes obj.First_leaf = f:ReadUShort() -- unsigned short 2 bytes obj.LeafCount = f:ReadUShort() -- unsigned short 2 bytes obj.Solid = f:ReadByte() -- unsigned char 1 byte obj.Flags = f:ReadByte() -- unsigned char 1 byte obj.Skin = f:ReadLong() -- int 4 bytes obj.FadeMinDist = f:ReadFloat() -- float 4 bytes obj.FadeMaxDist = f:ReadFloat() -- float 4 bytes obj.LightingOrigin = f:ReadVector() -- Vector (3 float) 12 bytes return 448 end -- Fade scale added. version[5] = function( f, obj, m) version[4]( f, obj, m ) obj.ForcedFadeScale = f:ReadFloat() -- float 4 bytes return 480 end -- Minimum and maximum DX-level version[6] = function( f, obj, m) version[5]( f, obj, m ) obj.MinDXLevel = f:ReadUShort() -- unsigned short 2 bytes obj.MaxDXLevel = f:ReadUShort() -- unsigned short 2 bytes return 512 end -- Color modulation added version[7] = function( f, obj, m ) version[6]( f, obj, m ) obj.DiffuseModulation = f:ReadColor() return 544 end -- Removal of DX-Level. Possible for Linux and console support. version[8] = function( f, obj, m ) version[5]( f,obj, m ) obj.MinCPULevel = f:ReadByte() -- unsigned char 1 byte obj.MaxCPULevel = f:ReadByte() -- unsigned char 1 byte obj.MinGPULevel = f:ReadByte() -- unsigned char 1 byte obj.MaxGPULevel = f:ReadByte() -- unsigned char 1 byte obj.DiffuseModulation = f:ReadColor() return 544 end -- Added Dissable-flag for X360 version[9] = function( f, obj, m ) version[8]( f, obj, m ) -- The first byte seems to be the indecator. -- All maps have the first byte as 0x00, where the L4D2 map; 'c2m4_barns.bsp', tells us it is 0x01 is true. obj.DisableX360 = f:ReadByte() == 1 -- The first byte is the indecator -- The last 3 bytes seems to be random data, to fill out the 32bit network-limit f:Skip( 24 ) return 576 end -- This version is for TF2 and some CS:S maps. -- Was build on version 6. Guess they where never meant to be released on consoles and only PC ( Since they use DXLevel ) version[10] = function( f, obj, m ) version[6]( f, obj, m ) obj.lightmapResolutionX = f:ReadLong() obj.lightmapResolutionY = f:ReadLong() return 576 end -- ( Version 7* ) This version is for some CSGO maps. I guess it was for the console support. version["10A"] = function( f, obj, m ) version[9]( f, obj, m ) obj.FlagsEx = f:ReadULong() return 608 end -- The newest CSGO maps. Might have left the console's behind with the newest map versions. version[11] = function( f, obj, m ) local q = version[9]( f, obj, m ) obj.FlagsEx = f:ReadULong() obj.UniformScale = f:ReadFloat() return q + 64 end --- @class StaticProp --- @param f BitBuffer --- @param ver number --- @return StaticProp, number local function CreateStaticProp( f, ver, m ) local obj = {} local startTell = f:Tell() version[ver]( f, obj, m ) obj.version = ver local sizeUsed = f:Tell() - startTell return setmetatable( obj, meta_staticprop ), sizeUsed end --- Returns a list of staticprops. --- @return StaticProp[] function meta:GetStaticProps() if self._staticprops then return self._staticprops end local gameLump = self:GetGameLump( 1936749168 ) -- 1936749168 == "sprp" local b = gameLump.buffer local propVersion = gameLump.version if b:Size() < 1 or not NikNaks._Source:find( "niknak" ) then -- This map doesn't have staticprops, or doesn't support them. self._staticprops = {} self._staticprops_mdl = {} return self._staticprops end if propVersion > 11 then ErrorNoHalt( self._mapfile .. " has an unknown static-prop version!" ) self._staticprops = {} self._staticprops_mdl = {} return self._staticprops end -- Load the model list. This list is used by the static_props. --- @type string[] self._staticprops_mdl = {} local n = b:ReadLong() if n > 16384 then -- Check if we overread the max static props. ErrorNoHalt( self._mapfile .. " has more than 16384 models!" ) self._staticprops = {} return self._staticprops end for i = 1, n do -- All model-paths are saved as char[128]. Any overflow are nullbytes. local model = "" for i2 = 1, 128 do local c = string.char( b:ReadByte() ) if string.match( c,"[%w_%-%.%/]" ) then -- Just in case, we check for "valid" chars instead. model = model .. c end end self._staticprops_mdl[i] = model end -- Read the leaf-array. (Unused atm). Prob an index for the static props. However each static-prop already hold said data. b:Skip( 16 * b:ReadLong() ) -- Read static props local count = b:ReadLong() if count > 16384 then -- Check if we are above the max staticprop. ErrorNoHalt( self._mapfile .. " has more than 16384 staticprops!" ) self._staticprops = {} return self._staticprops end -- We calculate the amount of static props within this space. It is more stable. local staticStart = b:Tell() local endPos = b:Size() local staticSize = ( endPos - staticStart ) / count local staticUsed --- @type StaticProp[] self._staticprops = {} -- Check for the 7* version. if staticSize == 608 and propVersion == 10 then propVersion = "10A" end for i = 0, count - 1 do -- This is to try and get as much valid data we can. b:Seek( staticStart + staticSize * i ) local sObj, sizeused = CreateStaticProp( b, propVersion, self._staticprops_mdl, staticSize ) staticUsed = staticUsed or sizeused sObj.Index = i self._staticprops[i] = sObj end if staticUsed and staticUsed ~= staticSize then ErrorNoHalt( "Was unable to parse " .. self._mapfile .. "'s StaticProps correctly!" ) end return self._staticprops end --- Returns the static-prop object from said index. --- @param index number --- @return StaticProp function meta:GetStaticProp( index ) return self:GetStaticProps()[index] end --- Returns a list of all static-prop models used by the map. --- @return string[] function meta:GetStaticPropModels() if self._staticprops_mdl then return self._staticprops_mdl end self:GetStaticProps() -- If no model list, then load the gamelump. return self._staticprops_mdl end --- Returns a list of all static-props matching the model. --- @param model string --- @return StaticProp[] function meta:FindStaticByModel( model ) local t = {} for _, v in pairs( self:GetStaticProps() ) do if v.PropType == model then t[#t + 1] = v end end return t end --- Returns a list of all static-props, within the specified box. --- @param boxMins Vector --- @param boxMaxs Vector --- @return StaticProp[] function meta:FindStaticInBox( boxMins, boxMaxs ) local t = {} for _, v in pairs( self:GetStaticProps() ) do local origin = v.Origin if origin and v.Origin:WithinAABox( boxMins, boxMaxs ) then t[#t + 1] = v end end return t end --- Returns a list of all static-props, within the specified sphere. --- @param origin Vector --- @param radius number --- @return StaticProp[] function meta:FindStaticInSphere( origin, radius ) radius = radius ^ 2 local t = {} for _, v in pairs( self:GetStaticProps() ) do local spOrigin = v.Origin if spOrigin and spOrigin:DistToSqr( origin ) <= radius then t[#t + 1] = v end end return t end --- Returns the StaticProp index function meta_staticprop:GetIndex() return self.Index end --- Returns the origin function meta_staticprop:GetPos() return self.Origin end --- Returns the angles function meta_staticprop:GetAngles() return self.Angles end --- Returns the model path function meta_staticprop:GetModel() return self.PropType end --- Returns the skin index function meta_staticprop:GetSkin() return self.Skin or 0 end --- @return Color function meta_staticprop:GetColor() return self.DiffuseModulation or color_white end function meta_staticprop:GetScale() return self.UniformScale or 1 end meta_staticprop.GetModelScale = meta_staticprop.GetScale --- Returns the solid enum. See: https://wiki.facepunch.com/gmod/Enums/SOLID function meta_staticprop:GetSolid() return self.Solid end --- Returns the lighting origin function meta_staticprop:GetLightingOrigin() return self.LightingOrigin end --- Returns the flags function meta_staticprop:GetFlags() return self.Flags end --- Returns true if the staticprop has a flag. --- @param flag number --- @return boolean function meta_staticprop:HasFlag( flag ) return band( self:GetFlags(), flag ) ~= 0 end --- Returns true if the static prop is disabled on X360. --- @return boolean function meta_staticprop:GetDisableX360() return self.DisableX360 or false end --- Returns the model bounds. --- @return Vector --- @return Vector function meta_staticprop:GetModelBounds() local a, b = NikNaks.ModelSize( self:GetModel() ) local s = self:GetScale() return a * s, b * s end meta_staticprop.GetModelRenderBounds = meta_staticprop.GetModelBounds meta_staticprop.GetRenderBounds = meta_staticprop.GetModelBounds -- Fade Functions function meta_staticprop:GetFadeMinDist() return self.FadeMinDist end function meta_staticprop:GetFadeMaxDist() return self.FadeMaxDist end function meta_staticprop:GetForceFadeScale() return self.ForcedFadeScale or 1 end -- "Other" --[[ DXLevel 0 = Ignore 70 = DirectX 7 80 = DirectX 8 81 = DirectX 8.1 90 = DirectX 9 95 = DirectX 9+ ( 9.3 ) 98 = DirectX 9Ex ]] function meta_staticprop:GetDXLevel() return self.MinDXLevel or 0, self.MaxDXLevel or 0 end if CLIENT then -- Checks to see if the client has the directX level required to render the static prop. function meta_staticprop:HasDXLevel() local num = render.GetDXLevel() if self.MinDXLevel ~= 0 and num < self.MinDXLevel then return false end if self.MaxDXLevel ~= 0 and num > self.MaxDXLevel then return false end return true end end --[[ There must be a list of CPU's and what level they are. CPU Level 0 = Ignore 1 = "Low" 2 = "Medium" 3 = "High" ]] function meta_staticprop:GetCPULevel() return self.MinCPULevel or 0, self.MaxCPULevel or 0 end --[[ There must be a list of GPU's and what level they are. GPU Level 0 = Ignore 1 = "Low" 2 = "Medium" 3 = "High" ]] function meta_staticprop:GetGPULevel() return self.MinGPULevel or 0, self.MaxGPULevel or 0 end -- Allows to set the lightmap resolution for said static-prop. -- Checkout https://tf2maps.net/threads/guide-lightmap-optimization.33113/ for more info function meta_staticprop:GetLightMapResolution() return self.lightmapResolutionX, self.lightmapResolutionY end --- Returns the "Further" BitFlags. Seems to be only used for the "STATIC_PROP_FLAGS_EX_DISABLE_CSM" flag. --- @return number function meta_staticprop:GetFlagExs() return self.FlagsEx or 0 end --- Returns true if the staticprop has an exflag. --- @param flag number --- @return boolean function meta_staticprop:HasFlagEx( flag ) return band( self:GetFlagExs(), flag ) ~= 0 end --- Returns the version of the static props. --- Note: version 7* will be returned as a string: "10A" function meta_staticprop:GetVersion() return self.version end