Merge pull request #27 from fortressforever/collection-impl-lua

Move Collection implementation to Lua
This commit is contained in:
Ryan Liptak 2015-03-26 20:47:22 -07:00
commit 230f52bd87
3 changed files with 299 additions and 0 deletions

View file

@ -7,7 +7,9 @@
-- Do not change this file. -- Do not change this file.
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
require "util.utils"
Class = require "util.class" Class = require "util.class"
Collection = require "util.collection"
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- defines -- defines
@ -48,6 +50,47 @@ function baseclass:new (o)
end end
-----------------------------------------------------------------------------
-- set up pairs and ipairs for iterating the global entity list
--
-- Example usage:
--
-- for ent_id, ent in pairs(GlobalEntityList) do
-- print(ent_id, ent)
-- end
--
-- Note: The order of iteration is always arbitrary
-----------------------------------------------------------------------------
local GlobalEntityListIterator = function()
local entity = GlobalEntityList:FirstEntity()
return function()
local cur_ent = entity
entity = GlobalEntityList:NextEntity(cur_ent)
if cur_ent then
return cur_ent:GetId(), cur_ent
else
return nil
end
end
end
local ipairs_base = ipairs
ipairs = function(t)
if t == GlobalEntityList then
return GlobalEntityListIterator()
end
return ipairs_base(t)
end
local pairs_base = pairs
pairs = function(t)
if t == GlobalEntityList then
return GlobalEntityListIterator()
end
return pairs_base(t)
end
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- make luabind's class_info function safer -- make luabind's class_info function safer
-- (don't crash if class_info() is called on non-luabind objects) -- (don't crash if class_info() is called on non-luabind objects)

View file

@ -0,0 +1,228 @@
-- backwards compatibility for the Collection class
local Class = require "util.class"
require "util.utils"
local function setup_items_key(self)
-- keep a usable reference to the base metatable
local real_obj = setmetatable({}, getmetatable(self))
-- add special handling of the items key
setmetatable(self, {
-- the items key returns an iterator
__index = function(t, k)
if k == "items" then
local i = 0
local n = self:Count()
return function()
i = i + 1
if i <= n then return self.entities[i] end
end
end
return real_obj[k]
end,
-- protect the items key from being assigned
__newindex = function(t, k, v)
if k == "items" then
return
end
real_obj[k] = v
end
})
end
local function get_param_as_table(param)
if param == nil then return {} end
if type(param) == "table" then return param end
return {param}
end
-- lua tables start at index 1
local function to_lua_index(collection_index)
return collection_index+1
end
-- Collection started at index 0
local function to_collection_index(lua_index)
return lua_index-1
end
local Collection = Class(function(self, entity_or_entities)
setup_items_key(self)
self.entities = get_param_as_table(entity_or_entities)
end)
Collection.filters = {
[CF.kNone] = function(entity) return true end,
[CF.kPlayers] = function(entity) return IsPlayer(entity) end,
[CF.kHumanPlayers] = function(entity) return IsPlayer(entity) and not CastToPlayer(entity):IsBot() end,
[CF.kBotPlayers] = function(entity) return IsPlayer(entity) and CastToPlayer(entity):IsBot() end,
[CF.kPlayerScout] = function(entity) return IsPlayer(entity) and CastToPlayer(entity):GetClass() == Player.kScout end,
[CF.kPlayerSniper] = function(entity) return IsPlayer(entity) and CastToPlayer(entity):GetClass() == Player.kSniper end,
[CF.kPlayerSoldier] = function(entity) return IsPlayer(entity) and CastToPlayer(entity):GetClass() == Player.kSoldier end,
[CF.kPlayerDemoman] = function(entity) return IsPlayer(entity) and CastToPlayer(entity):GetClass() == Player.kDemoman end,
[CF.kPlayerMedic] = function(entity) return IsPlayer(entity) and CastToPlayer(entity):GetClass() == Player.kMedic end,
[CF.kPlayerHWGuy] = function(entity) return IsPlayer(entity) and CastToPlayer(entity):GetClass() == Player.kHwguy end,
[CF.kPlayerPyro] = function(entity) return IsPlayer(entity) and CastToPlayer(entity):GetClass() == Player.kPyro end,
[CF.kPlayerSpy] = function(entity) return IsPlayer(entity) and CastToPlayer(entity):GetClass() == Player.kSpy end,
[CF.kPlayerEngineer] = function(entity) return IsPlayer(entity) and CastToPlayer(entity):GetClass() == Player.kEngineer end,
[CF.kPlayerCivilian] = function(entity) return IsPlayer(entity) and CastToPlayer(entity):GetClass() == Player.kCivilian end,
[CF.kPlayerScout] = function(entity) return IsPlayer(entity) and CastToPlayer(entity):GetClass() == Player.kScout end,
[CF.kTeams] = function(entity) return IsEntity(entity) and entity:GetTeamId() >= Team.kSpectator and entity:GetTeamId() <= Team.kGreen end,
[CF.kTeamSpec] = function(entity) return IsEntity(entity) and entity:GetTeamId() == Team.kSpectator end,
[CF.kTeamBlue] = function(entity) return IsEntity(entity) and entity:GetTeamId() == Team.kBlue end,
[CF.kTeamRed] = function(entity) return IsEntity(entity) and entity:GetTeamId() == Team.kRed end,
[CF.kTeamYellow] = function(entity) return IsEntity(entity) and entity:GetTeamId() == Team.kYellow end,
[CF.kTeamGreen] = function(entity) return IsEntity(entity) and entity:GetTeamId() == Team.kGreen end,
[CF.kProjectiles] = function(entity) return IsProjectile(entity) end,
[CF.kGrenades] = function(entity) return IsGrenade(entity) end,
[CF.kInfoScipts] = function(entity) return IsInfoScript(entity) end,
[CF.kInfoScript_Carried] = function(entity) return IsInfoScript(entity) and CastToInfoScript(entity):IsCarried() end,
[CF.kInfoScript_Dropped] = function(entity) return IsInfoScript(entity) and CastToInfoScript(entity):IsDropped() end,
[CF.kInfoScript_Returned] = function(entity) return IsInfoScript(entity) and CastToInfoScript(entity):IsReturned() end,
[CF.kInfoScript_Active] = function(entity) return IsInfoScript(entity) and CastToInfoScript(entity):IsActive() end,
[CF.kInfoScript_Inactive] = function(entity) return IsInfoScript(entity) and CastToInfoScript(entity):IsInactive() end,
[CF.kInfoScript_Removed] = function(entity) return IsInfoScript(entity) and CastToInfoScript(entity):IsRemoved() end,
[CF.kTraceBlockWalls] = function(entity) return true end, -- not applicable for this type of filtering
[CF.kBuildables] = function(entity) return IsBuildable(entity) end,
[CF.kDispenser] = function(entity) return IsDispenser(entity) end,
[CF.kSentrygun] = function(entity) return IsSentrygun(entity) end,
[CF.kDetpack] = function(entity) return IsDetpack(entity) end,
[CF.kJumpPad] = function(entity) return IsJumpPad(entity) end,
}
function Collection.PassesFilter(entity, filter)
if not filter then filter = CF.kNone end
assert(Collection.filters[filter], "Unknown filter: "..tostring(filter))
return Collection.filters[filter](entity)
end
function Collection.PassesFilters(entity, filters)
if not filters then return true end
filters = get_param_as_table(filters)
for _,filter in ipairs(filters) do
if not Collection.PassesFilter(entity, filter) then
return false
end
end
return true
end
function Collection:AddItem(entity_or_entities)
local entities_to_add = get_param_as_table(entity_or_entities)
for i,entity_to_add in ipairs(entities_to_add) do
table.insert(self.entities, entity_to_add)
end
end
function Collection:AddFiltered(entity_or_entities, filters)
local entities_to_add = get_param_as_table(entity_or_entities)
for i,entity_to_add in ipairs(entities_to_add) do
if Collection.PassesFilters(entity_to_add, filters) then
table.insert(self.entities, entity_to_add)
end
end
end
function Collection:RemoveItem(entity_or_entities)
local entities_to_find = get_param_as_table(entity_or_entities)
for i,entity_to_find in ipairs(entities_to_find) do
local i = self:FindItemIndex(entity_to_find)
if i then
table.remove(self.entities, to_lua_index(i))
end
end
end
function Collection:RemoveAllItems()
table.clear(self.entities)
end
function Collection:Count()
return #self.entities
end
function Collection:NumItems()
return self:Count()
end
function Collection:IsEmpty()
return self:Count() == 0
end
function Collection:HasItem(entity_or_entities)
local entities_to_find = get_param_as_table(entity_or_entities)
for i,entity_to_find in ipairs(entities_to_find) do
if self:FindItemIndex(entity_to_find) then
return true
end
end
return false
end
-- this is a strange function
function Collection:GetItem(entity_or_entities)
local entities_to_find = get_param_as_table(entity_or_entities)
for i,entity_to_find in ipairs(entities_to_find) do
local i = self:FindItemIndex(entity_to_find)
if i then
return self:Element(i)
end
end
end
function Collection:FindItemIndex(entity_to_find)
for i,entity in ipairs(self.entities) do
if entity:GetId() == entity_to_find:GetId() then
return to_collection_index(i)
end
end
return nil
end
function Collection:Element(i)
return self.entities[to_lua_index(i)]
end
function Collection:GetByFilter(filters)
filters = get_param_as_table(filters)
-- optimization for players
local players_only = false
for _,filter in ipairs(filters) do
if filter >= CF.kPlayers and filter <= CF.kPlayerScout then
players_only = true
break
end
end
if players_only then
self:AddFiltered(GetPlayers(), filters)
else
for ent_id, entity in ipairs(GlobalEntityList) do
self:AddFiltered(entity, filters)
end
end
end
function Collection:GetByName(name_or_names, filters)
local names_to_find = get_param_as_table(name_or_names)
filters = get_param_as_table(filters)
for i,name_to_find in ipairs(names_to_find) do
self:AddFiltered(GetEntitiesByName(name_to_find), filters)
end
end
function Collection:GetInSphere(entity_or_origin, radius, filters)
filters = get_param_as_table(filters)
local origin = IsEntity(entity_or_origin) and entity_or_origin:GetOrigin() or entity_or_origin
local ignore_walls = not table.contains(filters, CF.kTraceBlockWalls)
self:AddFiltered(GetEntitiesInSphere(origin, radius, ignore_walls), filters)
end
return Collection

View file

@ -0,0 +1,28 @@
function table.clear(tbl)
for k in pairs(tbl) do
tbl[k] = nil
end
end
function table.contains(tbl, element)
if tbl == nil then return false end
for _, value in pairs(tbl) do
if value == element then
return true
end
end
return false
end
function table.contains_any(tbl, elements)
if tbl == nil or elements == nil then return false end
for _, value in pairs(tbl) do
for _, element in pairs(elements) do
if value == element then
return true
end
end
end
return false
end