Skip to content

Instantly share code, notes, and snippets.

@Kaidrick
Last active March 12, 2023 01:58
Show Gist options
  • Save Kaidrick/e0a0967cbdb7562ec275ad66be847e28 to your computer and use it in GitHub Desktop.
Save Kaidrick/e0a0967cbdb7562ec275ad66be847e28 to your computer and use it in GitHub Desktop.
DCS World超级航母着舰LSO评分分析插件
-- 两个文件放入C:\Users\Administrator\Saved Games\DCS.openbeta\Scripts\Hooks中
-- 按Ctrl+Shift+X呼出记录窗口
function scratchpad_load()
package.path = package.path..";.\\LuaSocket\\?.lua;"..'.\\Scripts\\?.lua;'.. '.\\Scripts\\UI\\?.lua;'
package.cpath = package.cpath..";.\\LuaSocket\\?.dll;"
local JSON = loadfile("Scripts\\JSON.lua")()
local lfs = require('lfs')
local U = require('me_utilities')
local Skin = require('Skin')
local DialogLoader = require('DialogLoader')
local Tools = require('tools')
local Input = require('Input')
local isHidden = true
local keyboardLocked = false
local window = nil
local windowDefaultSkin = nil
local windowSkinHidden = Skin.windowSkinChatMin()
local panel = nil
local textarea = nil
local scratchpad = {
logFile = io.open(lfs.writedir()..[[Logs\Scratchpad.log]], "w")
}
function scratchpad.loadConfiguration()
scratchpad.log("Loading config file...")
local tbl = Tools.safeDoFile(lfs.writedir() .. 'Config/ScratchpadConfig.lua', false)
if (tbl and tbl.config) then
scratchpad.log("Configuration exists...")
scratchpad.config = tbl.config
else
scratchpad.log("Configuration not found, creating defaults...")
scratchpad.config = {
hotkey = "Ctrl+Shift+x",
windowPosition = { x = 200, y = 200 },
windowSize = { w = 350, h = 150 },
content = "Carrier Landing Score",
}
scratchpad.saveConfiguration()
end
end
function scratchpad.saveConfiguration()
U.saveInFile(scratchpad.config, 'config', lfs.writedir() .. 'Config/ScratchpadConfig.lua')
end
function scratchpad.log(str)
if not str then
return
end
if scratchpad.logFile then
scratchpad.logFile:write("["..os.date("%H:%M:%S").."] "..str.."\r\n")
scratchpad.logFile:flush()
end
end
local function unlockKeyboardInput(releaseKeyboardKeys)
if keyboardLocked then
DCS.unlockKeyboardInput(releaseKeyboardKeys)
keyboardLocked = false
end
end
local function lockKeyboardInput()
if keyboardLocked then
return
end
local keyboardEvents = Input.getDeviceKeys(Input.getKeyboardDeviceName())
DCS.lockKeyboardInput(keyboardEvents)
keyboardLocked = true
end
function scratchpad.createWindow()
window = DialogLoader.spawnDialogFromFile(lfs.writedir() .. 'Scripts\\\Hooks\\ScratchpadWindow.dlg', cdata)
windowDefaultSkin = window:getSkin()
panel = window.Box
textarea = panel.ScratchpadEditBox
-- setup textarea
textarea:setText(scratchpad.config.content)
textarea:addChangeCallback(function(self)
scratchpad.config.content = self:getText()
scratchpad.saveConfiguration()
end)
textarea:addFocusCallback(function(self)
if self:getFocused() then
lockKeyboardInput()
else
unlockKeyboardInput(true)
end
end)
textarea:addKeyDownCallback(function(self, keyName, unicode)
if keyName == 'escape' then
self:setFocused(false)
unlockKeyboardInput(true)
end
end)
-- setup window
window:setBounds(
scratchpad.config.windowPosition.x,
scratchpad.config.windowPosition.y,
scratchpad.config.windowSize.w,
scratchpad.config.windowSize.h
)
scratchpad.handleResize(window)
window:addHotKeyCallback(scratchpad.config.hotkey, function()
if isHidden == true then
scratchpad.show()
else
scratchpad.hide()
end
end)
window:addSizeCallback(scratchpad.handleResize)
window:addPositionCallback(scratchpad.handleMove)
window:setVisible(true)
scratchpad.hide()
scratchpad.log("Scratchpad Window created")
end
function scratchpad.setVisible(b)
window:setVisible(b)
end
function scratchpad.handleResize(self)
local w, h = self:getSize()
panel:setBounds(0, 0, w, h - 20)
textarea:setBounds(0, 0, w, h - 20)
scratchpad.config.windowSize = { w = w, h = h }
scratchpad.saveConfiguration()
end
function scratchpad.handleMove(self)
local x, y = self:getPosition()
scratchpad.config.windowPosition = { x = x, y = y }
scratchpad.saveConfiguration()
end
function scratchpad.show()
if window == nil then
local status, err = pcall(scratchpad.createWindow)
if not status then
net.log("[Scratchpad] Error creating window: " .. tostring(err))
end
end
window:setVisible(true)
window:setSkin(windowDefaultSkin)
panel:setVisible(true)
window:setHasCursor(true)
isHidden = false
end
function scratchpad.hide()
window:setSkin(windowSkinHidden)
panel:setVisible(false)
textarea:setFocused(false)
window:setHasCursor(false)
-- window.setVisible(false) -- if you make the window invisible, its destroyed
unlockKeyboardInput(true)
isHidden = true
end
function scratchpad.onSimulationFrame()
if scratchpad.config == nil then
scratchpad.loadConfiguration()
end
if not window then
scratchpad.log("Creating Scratchpad window hidden...")
scratchpad.createWindow()
end
end
--------------------------------------------------------------------
local GRADE = {
["WO"] = "复飞",
["OWO"] = "主动放弃着舰",
["_OK_"] = "完美的降落",
["OK"] = "优秀,及时进行了修正",
["(OK)"] = "及格,一次或多次偏差",
["---"] = "不及格,总体上处于在安全范围",
["C"] = "危险,超出安全范围",
["B"] = "脱钩"
}
local ACTION = {
["WO"] = "复飞",
}
local ERROR = {
["AFU"] = "全程“犯规”",
["DL"] = "向左偏移",
["DR"] = "向右偏移",
["EG"] = "着舰时缺乏推力",
["FD"] = "甲板阻塞",
["LL"] = "着舰位置偏左",
["LO"] = "过低",
["LR"] = "着舰位置偏右",
["LUL"] = "中线偏左",
["LUR"] = "中线偏右",
["NERD"] = "下降率不足",
["NSU"] = "未建立着舰构型",
["SLO"] = "过慢",
["TMRD"] = "下降率过大",
["LLWD"] = "左起落架先着舰",
["LRWD"] = "右起落架先着舰",
["LNF"] = "前轮先着舰",
["3PTS"] = "机轮三点同时着舰",
}
local ERROR_S = {
["F"] = "过快",
["H"] = "过高",
["N"] = "机头不稳",
["W"] = "坡度不稳",
["P"] = "油门不足",
}
local DISTMARK = {
["BC"] = "目视确认时",
["X"] = "起点",
["IM"] = "中段",
["IC"] = "接近阶段",
["AR"] = "船艉坡道上",
["TL"] = "着舰阶段",
["IW"] = "着舰区",
["AW"] = "全程",
}
local WIRE = {
["WIRE# 1"] = "第 1 根",
["WIRE# 2"] = "第 2 根",
["WIRE# 3"] = "第 3 根",
["WIRE# 4"] = "第 4 根",
}
function splitString(message, c)
chunks = {}
for substring in message:gmatch("%s?[^" .. c .. "]+%s-") do
table.insert(chunks, substring)
end
return chunks
end
function getSpace(comp)
local len = 12
local res = ""
local count = string.len(comp)
while count < len do
res = res .. " "
count = count + 1
end
return res
end
function parseMessage(checkString)
local record = ""
local dist = ""
local err = ""
local grade = ""
local wire_num = ""
local raw = checkString
-- get wire number if exists
if checkString:match("WIRE#") then
wire_num = checkString:match("WIRE#%s%d")
if wire_num ~= "" then
wire_num = WIRE[wire_num]
end
checkString = checkString:gsub("WIRE#%s%d", "")
end
-- for each error, match error name then error distance marker, then match brackets and underscore
local res = splitString(checkString, ":")
-- match grade using GRADE:[whatever]%s
grade = checkString:match("GRADE:.-:-%s"):gsub("GRADE:", ""):gsub(":", ""):gsub("%s+", "")
-- destruct string
checkString = checkString:gsub("LSO", ""):gsub("GRADE:.-:-%s", ""):gsub(":", "")
grade = grade .. "(" .. GRADE[grade] .. ")"
local errors = splitString(checkString, "%s")
local drop_first = false
for _, pick in pairs(errors) do
local ex = {}
local full = pick:gsub("%s+", "")
local fst = pick:gsub("%s+", "")
local error_assertion = false
-- waveoff action?
if fst:match("WO") then
table.insert(ex, ACTION["WO"])
fst = fst:gsub("WO", "")
end
for k, v in pairs(DISTMARK) do
if fst:match(k) then
table.insert(ex, v)
-- remove from string
fst = fst:gsub(k, "")
break
end
end
for k, v in pairs(ERROR) do
if fst:match(k) then
table.insert(ex, v)
error_assertion = true
break
end
end
if not error_assertion then
for k, v in pairs(ERROR_S) do
if fst:match(k) then
table.insert(ex, v)
break
end
end
end
if fst:match("%[") then
table.insert(ex, "(不规范呼叫)")
end
if fst:match("_") then
table.insert(ex, "(严重)")
end
if fst:match("%(") then
table.insert(ex, "(轻微)")
end
record = record .. full .. getSpace(full) .. table.concat(ex, " ") .. "\n" .. dist
end
return raw .. "\n" .. grade .. "" .. wire_num .. "\n" .. record
end
function scratchpad.stringStartWiths(checkString, expectedString)
local length = string.len(expectedString)
-- get substring from 1 to length
return string.sub(checkString, 1, length) == expectedString
end
-- log trigger message if message string starts with LSO: GRADE:
function scratchpad.onTriggerMessage(message, duration, clearView)
if(scratchpad.stringStartWiths(message, "LSO: GRADE:")) then
textarea:setText(parseMessage(message))
end
-- textarea:setText(textarea:getText() .. "\n" .. a_text)
end
DCS.setUserCallbacks(scratchpad)
net.log("[Scratchpad] Loaded ...")
end
local status, err = pcall(scratchpad_load)
if not status then
net.log("[Scratchpad] Load Error: " .. tostring(err))
end
dialog = {
["type"] = "Window",
["params"] = {
["bounds"] = {
[1] = {
["h"] = 200,
["w"] = 350,
["x"] = 0,
["y"] = 0,
},
},
["draggable"] = true,
["enabled"] = true,
["hasCursor"] = true,
["lockFlow"] = false,
["modal"] = false,
["offscreen"] = false,
["resizable"] = true,
["zOrder"] = 111,
["text"] = "着舰评分记录",
},
["skin"] = {
["params"] = {
["name"] = "windowSkin",
},
["skins"] = {
["header"] = {
["skinData"] = {
["params"] = {
["hasCloseButton"] = false,
["insets"] = {
["bottom"] = 2,
["left"] = 2,
["right"] = 2,
["top"] = 2,
},
},
["states"] = {
["released"] = {
[1] = {
["bkg"] = {
["center_center"] = "0x00000066",
},
["text"] = {
["color"] = "0xffffffaa",
},
},
[2] = {
["bkg"] = {
["center_center"] = "0x00000066",
},
["text"] = {
["color"] = "0xffffffaa",
},
},
},
},
},
},
},
["states"] = {
["released"] = {
[1] = {
["bkg"] = {
["center_center"] = "0x00000000",
},
},
},
},
},
["children"] = {
["Box"] = {
["children"] = {
["ScratchpadEditBox"] = {
["params"] = {
["acceptDecimalPoint"] = false,
["bounds"] = {
["h"] = 100,
["w"] = 250,
["x"] = 0,
["y"] = 0,
},
["enabled"] = true,
["multiline"] = true,
["numeric"] = false,
["password"] = false,
["readOnly"] = false,
["tabOrder"] = 80,
["text"] = "...",
["textWrapping"] = true,
["tooltip"] = "",
["visible"] = true,
["zindex"] = 0,
},
["skin"] = {
["params"] = {
["name"] = "editBoxNew",
},
["states"] = {
["released"] = {
[1] = {
["bkg"] = {
["center_center"] = "0x00000080",
},
},
},
},
},
["type"] = "EditBox",
},
},
["params"] = {
["bounds"] = {
[1] = {
["h"] = 467,
["w"] = 360,
["x"] = 0,
["y"] = 55,
},
},
["enabled"] = true,
["text"] = "",
["tooltip"] = "",
["visible"] = true,
["zindex"] = 0,
},
["skin"] = {
["params"] = {
["name"] = "panelSkin",
},
},
["type"] = "Panel",
},
["pNoVisible"] = {
["children"] = {
["windowModeMin"] = {
["params"] = {
["bounds"] = {
["h"] = 36,
["w"] = 40,
["x"] = 13,
["y"] = 203,
},
["enabled"] = true,
["text"] = "Panel1",
["tooltip"] = "",
["visible"] = true,
["zindex"] = 0,
},
["skin"] = {
["params"] = {
["name"] = "panelSkin",
},
},
["type"] = "Panel",
},
["windowModeFull"] = {
["params"] = {
["bounds"] = {
["h"] = 36,
["w"] = 40,
["x"] = 13,
["y"] = 203,
},
["enabled"] = true,
["text"] = "panel0",
["tooltip"] = "",
["visible"] = true,
["zindex"] = 0,
},
["skin"] = {
["params"] = {
["name"] = "panelSkin",
},
["states"] = {
["released"] = {
[1] = {
["bkg"] = {
["center_center"] = "0x00000064",
},
},
},
},
},
["type"] = "Panel",
},
},
["params"] = {
["bounds"] = {
["h"] = 435,
["w"] = 228,
["x"] = 442,
["y"] = 31,
},
["enabled"] = true,
["text"] = "panel0",
["tooltip"] = "",
["visible"] = false,
["zindex"] = 0,
},
["skin"] = {
["params"] = {
["name"] = "panelSkin",
},
},
["type"] = "Panel",
},
},
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment