mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-16 21:33:46 +03:00
251 lines
5.8 KiB
Lua
251 lines
5.8 KiB
Lua
--[[
|
|
| 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.
|
|
-- License: https://github.com/Nak2/NikNaks/blob/main/LICENSE
|
|
|
|
-- Entities are stored in a KeyValues table.
|
|
-- However we can't use the KeyValuesToTablePreserveOrder function, since some BSPs have errors within Entity Lump.
|
|
|
|
--- @class EntityObject
|
|
--- @field origin? Vector
|
|
--- @field angles? Angle
|
|
--- @field rendercolor? Color
|
|
--- @field ontrigger? table
|
|
--- @field classname? string
|
|
--- @field model? string
|
|
--- @field targetname? string
|
|
--- @field world_mins? string
|
|
--- @field world_maxs? string
|
|
--- @field scale? number
|
|
--- @field coldworld? number
|
|
|
|
--- Locates the next enter-token
|
|
--- @param data string
|
|
--- @param pos number
|
|
--- @return number
|
|
local function findNextToken( data, pos )
|
|
for i = pos, #data do
|
|
if data[i] == "{" then return i end
|
|
end
|
|
|
|
return -1
|
|
end
|
|
|
|
--- Locates the next exit-token
|
|
local function findNextExitToken( data, pos )
|
|
local keypos = 0
|
|
local ignore = false
|
|
|
|
for i = pos, #data do
|
|
if data[i] == "\"" then ignore = not ignore
|
|
elseif ignore then continue end
|
|
|
|
if data[i] == "{" then keypos = keypos + 1
|
|
elseif data[i] == "}" then
|
|
keypos = keypos - 1
|
|
if keypos == 0 then return i end
|
|
end
|
|
end
|
|
end
|
|
|
|
--- Convert a few things to make it easier to read entities.
|
|
--- @param t EntityObject
|
|
local function postEntParse( t )
|
|
t.origin = util.StringToType( t.origin or "0 0 0", "Vector" )
|
|
t.angles = util.StringToType( t.angles or "0 0 0", "Angle" )
|
|
|
|
if t.rendercolor then
|
|
local c = util.StringToType( t.rendercolor or "255 255 255", "Vector" )
|
|
t.rendercolor = Color( c.x, c.y, c.z, 255 )
|
|
end
|
|
|
|
-- Make sure ontrigger is a table.
|
|
if t.ontrigger and type( t.ontrigger ) ~= "table" then
|
|
t.ontrigger = { t.ontrigger }
|
|
end
|
|
end
|
|
|
|
-- A list of data-keys that can have multiple entries.
|
|
local _tableTypes = {
|
|
["OnMapSpawn"] = true,
|
|
["OnTrigger"] = true,
|
|
["OnStartTouch"] = true,
|
|
["OnArrivedAtDestinationNode"] = true,
|
|
["OnPowered"] = true,
|
|
["OnUnpowered"] = true,
|
|
["OnExplode"] = true,
|
|
["OnAllTrue"] = true,
|
|
}
|
|
|
|
--- @return EntityObject
|
|
local function ParseEntity( str )
|
|
--- @class EntityObject
|
|
local t = {}
|
|
|
|
for key, value in string.gmatch( str, [["(.-)".-"(.-)"]] ) do
|
|
value = tonumber( value ) or value
|
|
if t[key] then
|
|
if type( t[key] ) ~= "table" then
|
|
t[key] = { t[key] }
|
|
else
|
|
table.insert( t[key], value )
|
|
end
|
|
elseif _tableTypes[key] then
|
|
t[key] = { value }
|
|
else
|
|
t[key] = value
|
|
end
|
|
end
|
|
|
|
postEntParse( t )
|
|
|
|
return t
|
|
end
|
|
|
|
--- Tries to parse the entity-data.
|
|
--- @param data string
|
|
--- @return EntityObject[]
|
|
local function parseEntityData( data )
|
|
-- Cut the data into bits
|
|
local charPos = 1
|
|
local tabData = {}
|
|
for _ = 1, #data do -- while true do
|
|
local nextToken = findNextToken( data, charPos )
|
|
if nextToken < 0 then
|
|
break -- No token found. EOF.
|
|
else
|
|
local exitToken = findNextExitToken( data, nextToken )
|
|
if exitToken then
|
|
tabData[#tabData + 1] = data:sub( nextToken, exitToken )
|
|
charPos = exitToken
|
|
else -- ERROR No exit token? Try and parse the rest.
|
|
tabData[#tabData + 1] = data:sub( nextToken ) .. "}"
|
|
NikNaks.Msg( [[[BSP] ParseEntity: No closing brace found!]] )
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
local tab = {}
|
|
for id, str in pairs( tabData ) do
|
|
local t = ParseEntity( str )
|
|
tab[id - 1] = t
|
|
end
|
|
|
|
return tab
|
|
end
|
|
|
|
--- @class BSPObject
|
|
local meta = NikNaks.__metatables["BSP"]
|
|
|
|
--- Returns a list of all raw-entity data within the BSP.
|
|
--- @return EntityObject[]
|
|
function meta:GetEntities()
|
|
if self._entities then return self._entities end
|
|
|
|
-- Since it is stringbased, it is best to keep it as a string.
|
|
local data = self:GetLumpString( 0 )
|
|
|
|
-- Parse all entities
|
|
self._entities = parseEntityData( data )
|
|
|
|
return self._entities
|
|
end
|
|
|
|
--- Returns the raw entity data said entity.
|
|
--- @param index number
|
|
--- @return EntityObject
|
|
function meta:GetEntity( index )
|
|
return self:GetEntities()[index]
|
|
end
|
|
|
|
--- Returns a list of entity data, matching the class.
|
|
--- @param class string
|
|
--- @return EntityObject[]
|
|
function meta:FindByClass( class )
|
|
local t = {}
|
|
|
|
for _, v in pairs( self:GetEntities() ) do
|
|
local vClass = v.classname
|
|
if class and string.match( vClass, class ) then
|
|
t[#t + 1] = v
|
|
end
|
|
end
|
|
|
|
return t
|
|
end
|
|
|
|
--- Returns a list of entity data, matching the model.
|
|
--- @param model string
|
|
--- @return EntityObject[]
|
|
function meta:FindByModel( model )
|
|
local t = {}
|
|
|
|
for _, v in pairs( self:GetEntities() ) do
|
|
if v.model == model then
|
|
t[#t + 1] = v
|
|
end
|
|
end
|
|
|
|
return t
|
|
end
|
|
|
|
--- Returns a list of entity data, matching the name ( targetname ).
|
|
--- @param name string
|
|
--- @return table
|
|
function meta:FindByName( name )
|
|
local t = {}
|
|
|
|
for _, v in pairs( self:GetEntities() ) do
|
|
if v.targetname == name then
|
|
t[#t + 1] = v
|
|
end
|
|
end
|
|
|
|
return t
|
|
end
|
|
|
|
--- Returns a list of entity data, within the specified box. Note: This (I think) is slower than ents.FindInBox
|
|
--- @param boxMins Vector
|
|
--- @param boxMaxs Vector
|
|
--- @return table
|
|
function meta:FindInBox( boxMins, boxMaxs )
|
|
local t = {}
|
|
|
|
for _, v in pairs( self:GetEntities() ) 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 entity data, within the specified sphere. Note: This (I think) is slower than ents.FindInSphere
|
|
--- @param origin Vector
|
|
--- @param radius number
|
|
function meta:FindInSphere( origin, radius )
|
|
radius = radius ^ 2
|
|
|
|
local t = {}
|
|
|
|
for _, v in pairs( self:GetEntities() ) do
|
|
local vOrigin = v.origin
|
|
if vOrigin and vOrigin:DistToSqr( origin ) <= radius then
|
|
t[#t + 1] = v
|
|
end
|
|
end
|
|
|
|
return t
|
|
end
|