diff --git a/README.md b/README.md index de234c9..5e290b3 100644 --- a/README.md +++ b/README.md @@ -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. \ No newline at end of file diff --git a/clickabledata_extract_functions.lua b/clickabledata_extract_functions.lua new file mode 100644 index 0000000..349f79a --- /dev/null +++ b/clickabledata_extract_functions.lua @@ -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 diff --git a/extract_module_main.lua b/extract_module_main.lua new file mode 100644 index 0000000..de7c2a3 --- /dev/null +++ b/extract_module_main.lua @@ -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 diff --git a/i_18n.lua b/i_18n.lua new file mode 100644 index 0000000..5c87871 --- /dev/null +++ b/i_18n.lua @@ -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 \ No newline at end of file