Skip to content

Commit

Permalink
Add lua scripts for clickabledata extract
Browse files Browse the repository at this point in the history
  • Loading branch information
charlestytler committed Apr 18, 2020
1 parent 8553439 commit 12de603
Show file tree
Hide file tree
Showing 4 changed files with 251 additions and 1 deletion.
32 changes: 31 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,32 @@
# dcs-clickabledata-extract
A tool for extracting clickabledata elements from DCS World modules
A tool for extracting clickabledata elements from installed DCS World modules.

## Instructions for use

### Download files
Download the files by cloning this repository via the green "Clone or download" button to the top-right or downloading the zip from the "Releases" tab.

### Extract clickabledata to csv
- Open the file `extract_module_main.lua` and specify the DCS Install Path and Module name to query.
- Double-click `LuaRunScript.exe` to run the lua scripts and create a CSV file in the same directory.

*Example: Running with `A-10C` specified as the module will generate a file: `A-10C_clickabledata.csv`*

### (Optional) Run interactive Lua Console
If you'd like to open an interactive Lua console you can double-click the `LuaConsole.exe` executable.
You can then include the functions used for extraction with the following line:
```
dofile("extract_functions.lua")
```

You can then interactively call the functions instead of `extract_module_main.lua` calling them.

## Building from source

### Lua scripts
The lua scripts can be modified and run without compiling as it is a scripting language.

### LuaConsole and LuaRunScript
These are C++ functions that can be built using the Visual Studio solution within `LuaConsole\`
- LuaConsole - is simply a compiled executable of the `lua-5.1.5` package for Win32.
- LuaRunScript - also compiles `lua-5.1.5`, but adds a `main.cpp` file which calls the `extract_module_main.lua` script instead of opening an interactive console.
166 changes: 166 additions & 0 deletions clickabledata_extract_functions.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
-- Define global class type for clickabledata.
class_type =
{
NULL = 0,
BTN = 1,
TUMB = 2,
SNGBTN = 3,
LEV = 4
}

-- Mock out the get_option_value and get_aircraft_type functions that don't exist in this environment.
function get_option_value(x)
return nil
end

-- Protect against relative path "dofile" calls by inspecting paths before running.
-- All should use the configured "LockOn_Options.script_path" variable.
call_dofile = dofile
function inspect_and_dofile(path)
local is_absolute_path = (string.match(path, "DCS") and string.match(path, "World"))
if is_absolute_path then
call_dofile(path)
else

call_dofile(dcs_install_path .. path)
end
end
--Overwrite function so any dofile function calls by module scripts will go through inspect first.
dofile = inspect_and_dofile

-- Function to get length of a table
function len(table)
local count = 0
for _ in pairs(table) do
count = count + 1
end
return count
end

-- Function to safely get device name, default return of "".
function get_device_name(device_id)
device_name = ""
for device,id in pairs(devices) do
if (id == device_id) then
if (device ~= nil) then
device_name = device
end
end
end
return device_name
end

-- Conversion from class number to enum label.
function get_class_enum_label(class)
if class == 0 then
return "NULL"
elseif class == 1 then
return "BTN"
elseif class == 2 then
return "TUMB"
elseif class == 3 then
return "SNGBTN"
elseif class == 4 then
return "LEV"
else
return ""
end
end

-- Function to safely get index of a table, default return of "".
function get_index_value(table, index)
if (table ~= nil) then
value = table[index]
if (value ~= nil) then
return value
end
end
return ""
end

--[
-- Function will extract attributes for each clickabledata item from the elements table generated from the
-- clickabledata.lua script.
--
-- return: collect_element_attributes A table of elements with their attributes
--]
function collect_element_attributes(elements)
collected_element_attributes = {}
local count = 0
for element_id,_ in pairs(elements) do
local element_name = element_id
local hint = elements[element_id].hint
local classes = elements[element_id].class
local args = elements[element_id].arg
local arg_values = elements[element_id].arg_value
local arg_lims = elements[element_id].arg_lim
local device_id = elements[element_id].device
local device_name = get_device_name(device_id)
local command_ids = elements[element_id].action

-- Iterate through classes
for idx,class in pairs(classes) do
local class_name = get_class_enum_label(class)
local command_id = get_index_value(command_ids,idx)
local arg = get_index_value(args,idx)
local arg_value = get_index_value(arg_values,idx)
local arg_lim = get_index_value(arg_lims,idx)
local arg_lim1 = ""
local arg_lim2 = ""
if (arg_lim ~= nil) then
if (type(arg_lim) == "table") then
arg_lim1 = arg_lim[1]
arg_lim2 = arg_lim[2]
-- Repeat this for further nesting (found in JF-17)
if (type(arg_lim1) == "table") then
arg_lim = arg_lim1
arg_lim1 = arg_lim[1]
arg_lim2 = arg_lim[2]
end
elseif (type(arg_lim) == "number") then
arg_lim1 = arg_lim
end
end
if (device_id == nil) then
device_id = ""
end
count = count + 1
collected_element_attributes[count] = string.format("%s(%s),%s,%s,%s,%s,%s,%s,%s,%s",
device_name, device_id, command_id, element_name, class_name, arg, arg_value, arg_lim1, arg_lim2, hint)
end
end
return collected_element_attributes
end


--[
-- Function handles variations between module directories and aircraft variants within modules and runs the module's
-- clickabledata.lua script wihtin its Cockpit directory.
--
-- return: element_list A table of strings, where each string is a comma-separated definition of a clickabledata item.
--]
function load_module(dcs_install_path, module_name)
LockOn_Options = {}

-- Specialty case handling for odd multi-version modules.
if string.match(module_name,"C-101") then
LockOn_Options.script_path = dcs_install_path..[[\Mods\aircraft\C-101\Cockpit\]]..module_name..[[\]]
elseif string.match(module_name,"L-39") then
L_39ZA = string.match(module_name, "L-39ZA")
LockOn_Options.script_path = dcs_install_path..[[\Mods\aircraft\L-39C\Cockpit\]]
dofile(LockOn_Options.script_path.."devices.lua")
else
LockOn_Options.script_path = dcs_install_path..[[\Mods\aircraft\]]..module_name..[[\Cockpit\]]
end

file_loaded = loadfile(LockOn_Options.script_path.."clickabledata.lua")
if file_loaded == nil then
LockOn_Options.script_path = LockOn_Options.script_path..[[Scripts\]]
file_loaded = loadfile(LockOn_Options.script_path.."clickabledata.lua")
end

file_loaded()

element_list = collect_element_attributes(elements)
return element_list
end
26 changes: 26 additions & 0 deletions extract_module_main.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
-- Instructions:
-- Specify DCS Installation path and module to extract below
dcs_install_path = [[C:\Program Files\Eagle Dynamics\DCS World OpenBeta]]
module_name = "A-10C"

-- Modules:
-- A-10C, AJS37, AV8BNA, Bf-109K-4, C-101CC, C-101EB, Christen Eagle II,
-- F-16C, F-5E, F-86, F14, FA-18C, FW-190A8, FW-190D9, I-16, JF-17, Ka-50,
-- L-39C, L-39ZA, M-2000C, MIG-21bis, Mi-8MTV2, MiG-15bis, MiG-19P, P-51D,
-- SA342, SpitfireLFMkIX, Su-25T, Su-33, TF-51D, Uh-1H, Yak-52

-- End of user configurable data

-- Include functions needed to extract data
dofile("clickabledata_extract_functions.lua")

list = load_module(dcs_install_path, module_name)
table.sort(list)

-- Write extracted clickabledata elements to a CSV file
local csv_file = io.open(module_name .. "_clickabledata.csv", "w")
header = "Device (ID),Command ID,Element ID,Class Type,Arg ID,Value,Limit Min,Limit Max,Hints\n"
csv_file:write(header)
for _,row in pairs(list) do
csv_file:write(row .. "\n")
end
28 changes: 28 additions & 0 deletions i_18n.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
--
-- NOTE: MOCK FILE
-- This file only included to mock out i_18n requirements in DCS modules
--

local i_18n = { locales = {} }

local currentLocale = 'en' -- the default language

function i_18n.setLocale(newLocale)
currentLocale = newLocale
assert(i_18n.locales[currentLocale], ("The locale %q was unknown"):format(newLocale))
end

function i_18n.get_locale()
return "en", "US"
end

local function translate(id)
local result = id
return result
end

i_18n.translate = translate

setmetatable(i_18n, {__call = function(_,...) return translate(id) end})

return i_18n

0 comments on commit 12de603

Please sign in to comment.