Skip to content

Instantly share code, notes, and snippets.

@BenLubar
Last active May 3, 2020 23:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BenLubar/a966506cb22186ef111c42210537e04e to your computer and use it in GitHub Desktop.
Save BenLubar/a966506cb22186ef111c42210537e04e to your computer and use it in GitHub Desktop.
local dfplex = Proto("dfplex", "Dwarf Fortress Multiplexer")
local cmds = {
[0x6e] = "update",
[0x6f] = "sendKey",
[0x73] = "connect",
[0x75] = "resize",
[0x76] = "requestTurn"
}
local colors = {
[0] = "black",
[1] = "blue",
[2] = "green",
[3] = "cyan",
[4] = "red",
[5] = "magenta",
[6] = "yellow",
[7] = "white"
}
local keys = {
[8] = "backspace",
[9] = "tab",
[12] = "num",
[13] = "enter",
[19] = "pause",
[20] = "caps",
[27] = "esc",
[32] = "space",
[33] = "pgup",
[34] = "pgdn",
[35] = "end",
[36] = "home",
[37] = "left",
[38] = "up",
[39] = "right",
[40] = "down",
[44] = "print",
[45] = "ins",
[46] = "del",
[48] = "0",
[49] = "1",
[50] = "2",
[51] = "3",
[52] = "4",
[53] = "5",
[54] = "6",
[55] = "7",
[56] = "8",
[57] = "9",
[59] = ";",
[65] = "a",
[66] = "b",
[67] = "c",
[68] = "d",
[69] = "e",
[70] = "f",
[71] = "g",
[72] = "h",
[73] = "i",
[74] = "j",
[75] = "k",
[76] = "l",
[77] = "m",
[78] = "n",
[79] = "o",
[80] = "p",
[81] = "q",
[82] = "r",
[83] = "s",
[84] = "t",
[85] = "u",
[86] = "v",
[87] = "w",
[88] = "x",
[89] = "y",
[90] = "z",
[91] = "cmd",
[92] = "cmd",
[93] = "cmd",
[96] = "num_0",
[97] = "num_1",
[98] = "num_2",
[99] = "num_3",
[100] = "num_4",
[101] = "num_5",
[102] = "num_6",
[103] = "num_7",
[104] = "num_8",
[105] = "num_9",
[106] = "num_multiply",
[107] = "num_add",
[108] = "num_enter",
[109] = "num_subtract",
[110] = "num_decimal",
[111] = "num_divide",
[124] = "print",
[144] = "num",
[145] = "scroll",
[186] = ";",
[187] = "=",
[188] = ",",
[189] = "-",
[190] = ".",
[191] = "/",
[192] = "`",
[219] = "[",
[220] = "\\",
[221] = "]",
[222] = "'",
[223] = "`",
[224] = "cmd",
[225] = "alt"
}
local modifierMap = {
[0] = "",
[1] = "shift+",
[2] = "ctrl+",
[3] = "ctrl+shift+",
[4] = "alt+",
[5] = "shift+alt+",
[6] = "ctrl+alt+",
[7] = "ctrl+alt+shift+"
}
local pf_command = ProtoField.uint8("dfplex.cmd", "Command", base.DEC_HEX, cmds)
local pf_sendkey = ProtoField.bytes("dfplex.sendkey", "Send Key")
local pf_sendkey_keycode = ProtoField.uint8("dfplex.sendkey.keycode", "Key Code", base.DEC_HEX, keys)
local pf_sendkey_charcode = ProtoField.char("dfplex.sendkey.charcode", "Char Code", base.HEX)
local pf_sendkey_mod_shift = ProtoField.bool("dfplex.sendkey.mod.shift", "Modifier: shift", 8, nil, 1)
local pf_sendkey_mod_ctrl = ProtoField.bool("dfplex.sendkey.mod.ctrl", "Modifier: ctrl", 8, nil, 2)
local pf_sendkey_mod_alt = ProtoField.bool("dfplex.sendkey.mod.alt", "Modifier: alt", 8, nil, 4)
local pf_resize = ProtoField.bytes("dfplex.resize", "Resize")
local pf_resize_gridw = ProtoField.uint8("dfplex.resize.gridw", "Grid Width", base.DEC)
local pf_resize_gridh = ProtoField.uint8("dfplex.resize.gridg", "Grid Height", base.DEC)
local pf_update = ProtoField.bytes("dfplex.update", "Update")
local pf_update_connected_client_count = ProtoField.uint8("dfplex.update.connected_client_count", "Connected Client Count", base.DEC)
local pf_update_is_active = ProtoField.bool("dfplex.update.is_active", "Is Active (unused)", base.NONE)
local pf_update_load = ProtoField.int32("dfplex.update.load", "Load / Sum of Frames (unused)", base.DEC)
local pf_update_dim_x = ProtoField.uint8("dfplex.update.dim_x", "Viewport Width", base.DEC)
local pf_update_dim_y = ProtoField.uint8("dfplex.update.dim_y", "Viewport Height", base.DEC)
local pf_update_info_len = ProtoField.uint8("dfplex.update.info_len", "Status Information (length)", base.DEC)
local pf_update_info = ProtoField.string("dfplex.update.info", "Status Information", base.ASCII)
local pf_update_debug_info_len = ProtoField.uint16("dfplex.update.debug_info_len", "Debug Information (length)", base.DEC)
local pf_update_debug_info = ProtoField.string("dfplex.update.debug_info", "Debug Information", base.ASCII)
local pf_update_modified_tile = ProtoField.bytes("dfplex.update.modified_tile", "Modified Tile")
local pf_update_modified_tile_x = ProtoField.uint8("dfplex.update.modified_tile.x", "X coordinate", base.DEC)
local pf_update_modified_tile_y = ProtoField.uint8("dfplex.update.modified_tile.y", "Y coordinate", base.DEC)
local pf_update_modified_tile_ch = ProtoField.char("dfplex.update.modified_tile.ch", "Tile Symbol", base.HEX)
local pf_update_modified_tile_bg = ProtoField.uint8("dfplex.update.modified_tile.bg", "Background Color", base.DEC, colors, 7)
local pf_update_modified_tile_bg_bright = ProtoField.bool("dfplex.update.modified_tile.bg_bright", "Background Color Brightness", 8, nil, 8)
local pf_update_modified_tile_is_text = ProtoField.bool("dfplex.update.modified_tile.is_text", "Is Text", 8, nil, 64)
local pf_update_modified_tile_is_overworld = ProtoField.bool("dfplex.update.modified_tile.is_overworld", "Is Overworld", 8, nil, 128)
local pf_update_modified_tile_fg = ProtoField.uint8("dfplex.update.modified_tile.fg", "Foreground Color", base.DEC, colors, 7)
local pf_update_modified_tile_fg_bright = ProtoField.bool("dfplex.update.modified_tile.fg_bright", "Foreground Color Brightness", 8, nil, 8)
dfplex.fields = { pf_command, pf_sendkey_keycode, pf_sendkey_charcode,
pf_sendkey_mod_shift, pf_sendkey_mod_ctrl, pf_sendkey_mod_alt,
pf_resize_gridw, pf_resize_gridh, pf_update_connected_client_count,
pf_update_is_active, pf_update_load, pf_update_dim_x, pf_update_dim_y,
pf_update_info_len, pf_update_info, pf_update_debug_info_len,
pf_update_debug_info, pf_update_modified_tile, pf_update_modified_tile_x,
pf_update_modified_tile_y, pf_update_modified_tile_ch,
pf_update_modified_tile_bg, pf_update_modified_tile_bg_bright,
pf_update_modified_tile_is_text, pf_update_modified_tile_is_overworld,
pf_update_modified_tile_fg, pf_update_modified_tile_fg_bright,
pf_sendkey, pf_resize, pf_update }
local command_field = Field.new("dfplex.cmd")
function dfplex.dissector(tvbuf, pktinfo, root)
pktinfo.cols.protocol:set("dfplex")
local pktlen = tvbuf:reported_length_remaining()
local tree = root:add(dfplex, tvbuf:range(0, pktlen))
tree:add(pf_command, tvbuf:range(0, 1))
local pos = 1
local cmd = command_field()()
if cmd == 0x6e then -- update
if pktlen == 1 then
pktinfo.cols.info:set("dfplex Update Request")
-- client (no payload)
else
local update = tree:add(pf_update, tvbuf:range(1, pktlen - 1))
-- server
update:add(pf_update_connected_client_count, tvbuf:range(1, 1))
update:add(pf_update_is_active, tvbuf:range(2, 1))
update:add(pf_update_load, tvbuf:range(3, 4))
update:add(pf_update_dim_x, tvbuf:range(7, 1))
update:add(pf_update_dim_y, tvbuf:range(8, 1))
local str_len = tvbuf:range(9, 1):uint()
update:add(pf_update_info_len, tvbuf:range(9, 1))
update:add(pf_update_info, tvbuf:range(10, str_len))
pos = 10 + str_len
str_len = tvbuf:range(pos, 2):uint()
update:add(pf_update_debug_info_len, tvbuf:range(pos, 2))
update:add(pf_update_debug_info, tvbuf:range(pos + 2, str_len))
pos = pos + 2 + str_len
pktinfo.cols.info:set("dfplex Update ("..((pktlen - pos)/5).." tiles)")
while pos + 5 <= pktlen do
local tile = update:add(pf_update_modified_tile, tvbuf:range(pos, 5))
tile:add(pf_update_modified_tile_x, tvbuf:range(pos, 1))
tile:add(pf_update_modified_tile_y, tvbuf:range(pos + 1, 1))
tile:add(pf_update_modified_tile_ch, tvbuf:range(pos + 2, 1))
tile:add(pf_update_modified_tile_bg, tvbuf:range(pos + 3, 1))
tile:add(pf_update_modified_tile_bg_bright, tvbuf:range(pos + 3, 1))
tile:add(pf_update_modified_tile_is_text, tvbuf:range(pos + 3, 1))
tile:add(pf_update_modified_tile_is_overworld, tvbuf:range(pos + 3, 1))
tile:add(pf_update_modified_tile_fg, tvbuf:range(pos + 4, 1))
tile:add(pf_update_modified_tile_fg_bright, tvbuf:range(pos + 4, 1))
pos = pos + 5
end
end
elseif cmd == 0x6f then -- sendKey
local keycode = tvbuf:range(1, 1):uint()
local charcode = tvbuf:range(2, 1):uint()
local modifiers = tvbuf:range(3, 1):uint()
if charcode == 0 or modifiers ~= 0 then
pktinfo.cols.info:set("dfplex Send Key "..(modifierMap[modifiers] or "ERR+")..(keys[keycode] or keycode))
else
pktinfo.cols.info:set("dfplex Send Key '"..chr(charcode).."'")
end
local sendkey = tree:add(pf_sendkey, tvbuf:range(1, 3))
sendkey:add(pf_sendkey_keycode, tvbuf:range(1, 1))
sendkey:add(pf_sendkey_charcode, tvbuf:range(2, 1))
sendkey:add(pf_sendkey_mod_shift, tvbuf:range(3, 1))
sendkey:add(pf_sendkey_mod_ctrl, tvbuf:range(3, 1))
sendkey:add(pf_sendkey_mod_alt, tvbuf:range(3, 1))
pos = 4
elseif cmd == 0x73 then -- connect
pktinfo.cols.info:set("dfplex Connect")
-- (no payload)
elseif cmd == 0x75 then -- resize
pktinfo.cols.info:set("dfplex Resize to "..tvbuf:range(1, 1):uint().."x"..tvbuf:range(2, 1):uint())
local resize = tree:add(pf_resize, tvbuf:range(1, 2))
resize:add(pf_resize_gridw, tvbuf:range(1, 1))
resize:add(pf_resize_gridh, tvbuf:range(2, 1))
pos = 3
elseif cmd == 0x76 then -- requestTurn
pktinfo.cols.info:set("dfplex Request Turn")
-- (no payload)
else
-- unknown/malformed
end
return pos
end
ws_dissector_table = DissectorTable.get("ws.protocol")
ws_dissector_table:add("DFPlex-v0.2", dfplex)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment