SoUI 0.5版本占坑
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

249 lines
7.2 KiB

local mt = {}
mt.__index = mt
local function switch(value)
return function (mapping)
if mapping[value] then
mapping[value]()
end
end
end
local function str_trim(str, p)
return str:gsub('^'..p..'*(.-)$', '%1'):gsub('^(.-)'..p..'*$', '%1')
end
local function str_split(str, p)
local rt = {}
local l = 1
local state = 0
for i = 1, #str do
local c = str:sub(i,i)
if state == 0 then
if c == '"' then
state = 1
elseif c == p then
table.insert(rt, str:sub(l, i - 1))
l = i + 1
end
elseif state == 1 then
if c == '"' then
state = 0
end
end
end
if l <= #str then
table.insert(rt, str:sub(l, #str))
end
return rt
end
function mt:accept_ui(type, name, key, value)
if not self.ui[type][name] then
self.ui[type][name] = { name = name }
end
local ui = self.ui[type][name]
switch(key) {
args = function ()
local r = str_split(value, ',')
if type == 'call' then
ui.use_in_event = r[2]
ui.returns = r[3]
table.remove(r, 1)
table.remove(r, 1)
table.remove(r, 1)
else
table.remove(r, 1)
end
ui.args = {}
for _, v in ipairs(r) do
table.insert(ui.args, { type = v })
end
end,
default = function ()
local r = str_split(value, ',')
for i, v in ipairs(ui.args) do
if r[i] and r[i] ~= '_' then
v.default = r[i]
end
end
end,
limit = function ()
local r = str_split(value, ',')
for i, v in ipairs(ui.args) do
if r[2*i-1] and r[2*i-1] ~= '_' then
v.min = r[2*i-1]
end
if r[2*i] and r[2*i] ~= '_' then
v.max = r[2*i]
end
end
end,
category = function ()
ui.category = value
if not self.categories[type][ui.category] then
self.categories[type][ui.category] = {}
table.insert(self.categories[type], ui.category)
end
table.insert(self.categories[type][ui.category], ui)
end,
script_name = function ()
ui.script_name = value
end,
description = function ()
if not ui.title then
ui.title = str_trim(value, '"')
return
end
if ui.description then
return
end
local str = ''
local r = str_split(value, ',')
for _, s in ipairs(r) do
s = str_trim(s, '%s')
if s:sub(1,1) == '~' then
str = str .. '${' .. s:sub(2) .. '}'
else
str = str .. str_trim(s, '"')
end
end
ui.description = str
end,
comment = function ()
ui.comment = str_trim(value, '"')
end,
}
end
function mt:parse_ui(type, subtype, key, value)
if subtype == 'data' then
if key:sub(1,1) ~= '_' then
self:accept_ui(type, key, 'args', value)
elseif key:sub(- #'_Defaults', -1) == '_Defaults' then
self:accept_ui(type, key:sub(2, -1 - #'_Defaults'), 'default', value)
elseif key:sub(- #'_Limits', -1) == '_Limits' then
self:accept_ui(type, key:sub(2, -1 - #'_Limits'), 'limit', value)
elseif key:sub(- #'_Category', -1) == '_Category' then
self:accept_ui(type, key:sub(2, -1 - #'_Category'), 'category', value)
elseif key:sub(- #'_ScriptName', -1) == '_ScriptName' then
self:accept_ui(type, key:sub(2, -1 - #'_ScriptName'), 'script_name', value)
elseif key:sub(- #'_UseWithAI', -1) == '_UseWithAI' then
elseif key:sub(- #'_AIDefaults', -1) == '_AIDefaults' then
else
error('无法解析: ' .. key)
end
elseif subtype == 'string' then
if key:sub(- #'Hint', -1) == 'Hint' then
self:accept_ui(type, key:sub(1, -1 - #'Hint'), 'comment', value)
else
self:accept_ui(type, key, 'description', value)
end
else
error('未知类型: ' .. subtype)
end
end
function mt:parse_define(section, key, value)
if not self.ui.define[section] then
self.ui.define[section] = {}
end
table.insert(self.ui.define[section], {key, value})
end
function mt:parse(section, key, value)
switch(section) {
TriggerEvents = function ()
self:parse_ui('event', 'data', key, value)
end,
TriggerEventStrings = function ()
self:parse_ui('event', 'string', key, value)
end,
TriggerConditions = function ()
self:parse_ui('condition', 'data', key, value)
end,
TriggerConditionStrings = function ()
self:parse_ui('condition', 'string', key, value)
end,
TriggerActions = function ()
self:parse_ui('action', 'data', key, value)
end,
TriggerActionStrings = function ()
self:parse_ui('action', 'string', key, value)
end,
TriggerCalls = function ()
self:parse_ui('call', 'data', key, value)
end,
TriggerCallStrings = function ()
self:parse_ui('call', 'string', key, value)
end,
TriggerCategories = function ()
self:parse_define(section, key, value)
end,
TriggerTypes = function ()
self:parse_define(section, key, value)
end,
TriggerTypeDefaults = function ()
self:parse_define(section, key, value)
end,
TriggerParams = function ()
self:parse_define(section, key, value)
end,
DefaultTriggerCategories = function ()
self:parse_define(section, key, value)
end,
DefaultTriggers = function ()
self:parse_define(section, key, value)
end,
AIFunctionStrings = function ()
self:parse_define(section, key, value)
end,
}
end
function mt:readfile(path)
local f = assert(io.open(path, "r"))
local section = nil
for line in f:lines() do
if line:sub(1,1) == "[" then
section = line:sub(2, #line - 1)
elseif line:sub(1,2) == "//" then
elseif line ~= "" then
local first = line:find("=")
if first then
local key = line:sub(1, first - 1)
local value = line:sub(first + 1) or ""
self:parse(section, key, value)
end
end
end
f:close()
end
function mt:reset()
self.ui = {
define = {},
event = {},
condition = {},
action = {},
call = {},
}
self.categories = {
event = {},
condition = {},
action = {},
call = {},
}
end
function mt:read(path)
self:reset()
self:readfile(path / [[TriggerData.txt]])
self:readfile(path / [[TriggerStrings.txt]])
end
return function(path)
local obj = setmetatable({}, mt)
obj:read(path)
return obj
end