Skip to content

Commit

Permalink
Micro AIs: simplify unit variable handling functions
Browse files Browse the repository at this point in the history
The main reason for doing this, besides simplifying the code, is to avoid using the WML table dump __cfg, which is slow. This includes a change of the format in which the variables are stored, but since these are internal Micro AI utility functions, that does not matter.

(cherry-picked from commit 133568e)
  • Loading branch information
mattsc committed Oct 7, 2018
1 parent b5c8c60 commit 695fa69
Showing 1 changed file with 30 additions and 66 deletions.
96 changes: 30 additions & 66 deletions data/ai/micro_ais/micro_ai_unit_variables.lua
@@ -1,86 +1,50 @@
-- This set of functions provides a consistent way of storing Micro AI
-- variables in units. They need to be stored inside a [micro_ai] tag in a
-- unit's [variables] tag together with an ai_id= key, so that they can be
-- removed when the Micro AI gets deleted. Otherwise subsequent Micro AIs used
-- in the same scenario (or using the same units in later scenarios) might work
-- incorrectly or not at all.
-- Note that, with this method, there can only ever be one of these tags for each
-- ai_ca in each unit (but of course several when there are several Micro AIs
-- with different ai_CA values affecting the same unit)
-- For the time being, we only allow key=value style variables.
-- variables in units. Individual variables are stored inside a table with a
-- name specific to the MAI ('micro_ai-' .. ai_id). This table is removed when
-- the Micro AI is deleted in order to ensure that subsequent Micro AIs used
-- in the same scenario (or using the same units in later scenarios) work
-- correctly.
-- Note that, with this method, there can only ever be one of these tables for each
-- ai_id in each unit, but several tables are created for the same unit when there
-- are several Micro AIs with different ai_id values.
-- For the time being, we do not allow sub-tables. This is done because these
-- unit variables are required to be persistent across save-load cycles and
-- therefore need to be in WML table format. This could be extended to allow
-- sub-tables in WML format, but there is no need for that at this time.

local micro_ai_unit_variables = {}

function micro_ai_unit_variables.modify_mai_unit_variables(unit, ai_id, action, vars_table)
-- Modify [unit][variables][micro_ai] tags
-- @ai_id (string): the id of the Micro AI
-- @action (string): "delete", "set" or "insert"
-- @vars_table: table of key=value pairs with the variables to be set or inserted (not needed for @action="delete")

local variables = unit.variables.__cfg

-- Always delete the respective [variables][micro_ai] tag, if it exists
local existing_table
for i,mai in ipairs(variables) do
if (mai[1] == "micro_ai") and (mai[2].ai_id == ai_id) then
existing_table = mai[2]
table.remove(variables, i)
break
end
end

-- Then replace it, if the "set" action is selected
-- or add the new keys to it, overwriting old ones with the same name, if action == "insert"
if (action == "set") or (action == "insert") then
local tag = { "micro_ai" }

if (not existing_table) or (action == "set") then
tag[2] = vars_table
tag[2].ai_id = ai_id
else
for k,v in pairs(vars_table) do existing_table[k] = v end
tag[2] = existing_table
end

table.insert(variables, tag)
end

-- All of this so far was only on the table dump -> apply to unit
unit.variables.__cfg = variables
end

function micro_ai_unit_variables.delete_mai_unit_variables(unit, ai_id)
micro_ai_unit_variables.modify_mai_unit_variables(unit, ai_id, "delete")
unit.variables['micro_ai_' .. ai_id] = nil
end

function micro_ai_unit_variables.insert_mai_unit_variables(unit, ai_id, vars_table)
micro_ai_unit_variables.modify_mai_unit_variables(unit, ai_id, "insert", vars_table)
local mai_var = unit.variables['micro_ai_' .. ai_id] or {}
-- Restrict to top-level named fields
for k,v in pairs(vars_table) do mai_var[k] = v end
unit.variables['micro_ai_' .. ai_id] = mai_var
end

function micro_ai_unit_variables.set_mai_unit_variables(unit, ai_id, vars_table)
micro_ai_unit_variables.modify_mai_unit_variables(unit, ai_id, "set", vars_table)
local mai_var = {}
-- Restrict to top-level named fields
for k,v in pairs(vars_table) do mai_var[k] = v end
unit.variables['micro_ai_' .. ai_id] = mai_var
end

function micro_ai_unit_variables.get_mai_unit_variables(unit, ai_id, key)
-- Get the content of [unit][variables][micro_ai] tag for the given @ai_id
-- Get the content of [unit][variables]['micro_ai_' .. ai_id] tag
-- Return value:
-- - If tag is found: value of key if @key parameter is given, otherwise
-- table of key=value pairs (including the ai_id key)
-- - If no such tag is found: nil (if @key is set), otherwise empty table
-- - If tag is found: value of key if @key parameter is given, otherwise entire table
-- - If no such tag is found: nil if @key is given, otherwise empty table

for mai in wml.child_range(unit.variables.__cfg, "micro_ai") do
if (mai.ai_id == ai_id) then
if key then
return mai[key]
else
return mai
end
end
end
local mai_var = unit.variables['micro_ai_' .. ai_id] or {}

-- If we got here, no corresponding tag was found
-- Return empty table; or nil if @key was set
if (not key) then return {} end
if key then
return mai_var[key]
else
return mai_var
end
end

return micro_ai_unit_variables

0 comments on commit 695fa69

Please sign in to comment.