Keybinds and custom views modules overhaul (#28)
This commit is contained in:
commit
70e726f090
16 changed files with 1039 additions and 817 deletions
|
@ -154,7 +154,7 @@ function vmf.run_command(command_name, ...)
|
||||||
local command_data = _commands[command_name]
|
local command_data = _commands[command_name]
|
||||||
if command_data then
|
if command_data then
|
||||||
local error_prefix = "(commands) " .. tostring(command_name)
|
local error_prefix = "(commands) " .. tostring(command_name)
|
||||||
vmf.xpcall_no_return_values(command_data.mod, error_prefix, command_data.exec_function, ...)
|
vmf.safe_call_nr(command_data.mod, error_prefix, command_data.exec_function, ...)
|
||||||
else
|
else
|
||||||
vmf:error("(commands): command '%s' wasn't found.", command_name) -- Should never see this
|
vmf:error("(commands): command '%s' wasn't found.", command_name) -- Should never see this
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,7 +10,7 @@ local _mods_unloading_order = vmf.mods_unloading_order
|
||||||
local function run_event(mod, event_name, ...)
|
local function run_event(mod, event_name, ...)
|
||||||
local event = mod[event_name]
|
local event = mod[event_name]
|
||||||
if event then
|
if event then
|
||||||
vmf.xpcall_no_return_values(mod, "(event) " .. event_name, event, ...)
|
vmf.safe_call_nr(mod, "(event) " .. event_name, event, ...)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -164,7 +164,7 @@ local function create_specialized_hook(mod, orig, hook_type)
|
||||||
elseif hook_type == HOOK_TYPE_SAFE then
|
elseif hook_type == HOOK_TYPE_SAFE then
|
||||||
func = function(...)
|
func = function(...)
|
||||||
if hook_data.active then
|
if hook_data.active then
|
||||||
vmf.xpcall_no_return_values(mod, "(safe_hook)", hook_data.handler, ...)
|
vmf.safe_call_nr(mod, "(safe_hook)", hook_data.handler, ...)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,358 +1,382 @@
|
||||||
local vmf = get_mod("VMF")
|
local vmf = get_mod("VMF")
|
||||||
|
|
||||||
VMFModsKeyMap = {
|
local PRIMARY_BINDABLE_KEYS = {
|
||||||
win32 = {
|
KEYBOARD = {
|
||||||
["ctrl"] = {"keyboard", "left ctrl", "held"},
|
[8] = {"Backspace", "backspace"},
|
||||||
["alt"] = {"keyboard", "left alt", "held"},
|
[9] = {"Tab", "tab"},
|
||||||
["shift"] = {"keyboard", "left shift", "held"}
|
[13] = {"Enter", "enter"},
|
||||||
|
[20] = {"Caps Lock", "caps lock"},
|
||||||
|
[32] = {"Space", "space"},
|
||||||
|
[33] = {"Page Up", "page up"},
|
||||||
|
[34] = {"Page Down", "page down"},
|
||||||
|
[35] = {"End", "end"},
|
||||||
|
[36] = {"Home", "home"},
|
||||||
|
[37] = {"Left", "left"},
|
||||||
|
[38] = {"Up", "up"},
|
||||||
|
[39] = {"Right", "right"},
|
||||||
|
[40] = {"Down", "down"},
|
||||||
|
[45] = {"Insert", "insert"},
|
||||||
|
[46] = {"Delete", "delete"},
|
||||||
|
[48] = {"0", "0"},
|
||||||
|
[49] = {"1", "1"},
|
||||||
|
[50] = {"2", "2"},
|
||||||
|
[51] = {"3", "3"},
|
||||||
|
[52] = {"4", "4"},
|
||||||
|
[53] = {"5", "5"},
|
||||||
|
[54] = {"6", "6"},
|
||||||
|
[55] = {"7", "7"},
|
||||||
|
[56] = {"8", "8"},
|
||||||
|
[57] = {"9", "9"},
|
||||||
|
[65] = {"A", "a"},
|
||||||
|
[66] = {"B", "b"},
|
||||||
|
[67] = {"C", "c"},
|
||||||
|
[68] = {"D", "d"},
|
||||||
|
[69] = {"E", "e"},
|
||||||
|
[70] = {"F", "f"},
|
||||||
|
[71] = {"G", "g"},
|
||||||
|
[72] = {"H", "h"},
|
||||||
|
[73] = {"I", "i"},
|
||||||
|
[74] = {"J", "j"},
|
||||||
|
[75] = {"K", "k"},
|
||||||
|
[76] = {"L", "l"},
|
||||||
|
[77] = {"M", "m"},
|
||||||
|
[78] = {"N", "n"},
|
||||||
|
[79] = {"O", "o"},
|
||||||
|
[80] = {"P", "p"},
|
||||||
|
[81] = {"Q", "q"},
|
||||||
|
[82] = {"R", "r"},
|
||||||
|
[83] = {"S", "s"},
|
||||||
|
[84] = {"T", "t"},
|
||||||
|
[85] = {"U", "u"},
|
||||||
|
[86] = {"V", "v"},
|
||||||
|
[87] = {"W", "w"},
|
||||||
|
[88] = {"X", "x"},
|
||||||
|
[89] = {"Y", "y"},
|
||||||
|
[90] = {"Z", "z"},
|
||||||
|
[91] = {"Win", "win"},
|
||||||
|
[92] = {"RWin", "right win"},
|
||||||
|
[96] = {"Num 0", "numpad 0"},
|
||||||
|
[97] = {"Num 1", "numpad 1"},
|
||||||
|
[98] = {"Num 2", "numpad 2"},
|
||||||
|
[99] = {"Num 3", "numpad 3"},
|
||||||
|
[100] = {"Num 4", "numpad 4"},
|
||||||
|
[101] = {"Num 5", "numpad 5"},
|
||||||
|
[102] = {"Num 6", "numpad 6"},
|
||||||
|
[103] = {"Num 7", "numpad 7"},
|
||||||
|
[104] = {"Num 8", "numpad 8"},
|
||||||
|
[105] = {"Num 9", "numpad 9"},
|
||||||
|
[106] = {"Num *", "numpad *"},
|
||||||
|
[107] = {"Num +", "numpad +"},
|
||||||
|
[109] = {"Num -", "numpad -"},
|
||||||
|
[110] = {"Num .", "numpad ."},
|
||||||
|
[111] = {"Num /", "numpad /"},
|
||||||
|
[112] = {"F1", "f1"},
|
||||||
|
[113] = {"F2", "f2"},
|
||||||
|
[114] = {"F3", "f3"},
|
||||||
|
[115] = {"F4", "f4"},
|
||||||
|
[116] = {"F5", "f5"},
|
||||||
|
[117] = {"F6", "f6"},
|
||||||
|
[118] = {"F7", "f7"},
|
||||||
|
[119] = {"F8", "f8"},
|
||||||
|
[120] = {"F9", "f9"},
|
||||||
|
[121] = {"F10", "f10"},
|
||||||
|
[122] = {"F11", "f11"},
|
||||||
|
[123] = {"F12", "f12"},
|
||||||
|
[144] = {"Num Lock", "num lock"},
|
||||||
|
[145] = {"Scroll Lock", "scroll lock"},
|
||||||
|
[166] = {"Browser Back", "browser back"},
|
||||||
|
[167] = {"Browser Forward", "browser forward"},
|
||||||
|
[168] = {"Browser Refresh", "browser refresh"},
|
||||||
|
[169] = {"Browser Stop", "browser stop"},
|
||||||
|
[170] = {"Browser Search", "browser search"},
|
||||||
|
[171] = {"Browser Favorites", "browser favorites"},
|
||||||
|
[172] = {"Browser Home", "browser home"},
|
||||||
|
[173] = {"Volume Mute", "volume mute"},
|
||||||
|
[174] = {"Volume Down", "volume down"},
|
||||||
|
[175] = {"Volume Up", "volume up"},
|
||||||
|
[176] = {"Next Track", "next track"},
|
||||||
|
[177] = {"Previous Track", "previous track"},
|
||||||
|
[178] = {"Stop", "stop"},
|
||||||
|
[179] = {"Play/Pause", "play pause"},
|
||||||
|
[180] = {"Mail", "mail"},
|
||||||
|
[181] = {"Media", "media"},
|
||||||
|
[182] = {"Start Application 1", "start app 1"},
|
||||||
|
[183] = {"Start Application 2", "start app 2"},
|
||||||
|
[186] = {";", ";"},
|
||||||
|
[187] = {"=", "="},
|
||||||
|
[188] = {",", ","},
|
||||||
|
[189] = {"-", "-"},
|
||||||
|
[190] = {".", "."},
|
||||||
|
[191] = {"/", "/"},
|
||||||
|
[192] = {"`", "`"},
|
||||||
|
[219] = {"[", "["},
|
||||||
|
[220] = {"\\", "\\"},
|
||||||
|
[221] = {"]", "]"},
|
||||||
|
[222] = {"'", "'"},
|
||||||
|
--?[226] = {"\", "oem_102 (> <)"},
|
||||||
|
[256] = {"Num Enter", "numpad enter"}
|
||||||
},
|
},
|
||||||
xb1 = {}
|
MOUSE = {
|
||||||
}
|
[0] = {"Mouse Left", "mouse left"},
|
||||||
|
[1] = {"Mouse Right", "mouse right"},
|
||||||
-- ["mod_name"]["setting_id"] = {
|
[2] = {"Mouse Middle", "mouse middle"},
|
||||||
-- "function_name",
|
[3] = {"Mouse Extra 1", "mouse extra 1"},
|
||||||
-- {"primary_key", "special_key", "special_key", "special_key"}
|
[4] = {"Mouse Extra 2", "mouse extra 2"},
|
||||||
-- }
|
[10] = {"Mouse Wheel Up", "mouse wheel up"},
|
||||||
-- Special Keys: "ctrl" / "shift" / "alt"
|
[11] = {"Mouse Wheel Down", "mouse wheel down"},
|
||||||
local _raw_keybinds = {}
|
[12] = {"Mouse Wheel Left", "mouse wheel left"},
|
||||||
|
[13] = {"Mouse Wheel Right", "mouse wheel right"}
|
||||||
-- ["primary_key"] = {
|
|
||||||
-- {"mod_name", "function_name", ctrl_used(bool), alt_used(bool), shift_used(bool)},
|
|
||||||
-- {},
|
|
||||||
-- {},
|
|
||||||
-- ...
|
|
||||||
-- }
|
|
||||||
local _optimized_keybinds = {}
|
|
||||||
|
|
||||||
local _activated_pressed_key
|
|
||||||
|
|
||||||
-- ####################################################################################################################
|
|
||||||
-- ##### Local functions ##############################################################################################
|
|
||||||
-- ####################################################################################################################
|
|
||||||
|
|
||||||
local function apply_keybinds()
|
|
||||||
|
|
||||||
_optimized_keybinds = {}
|
|
||||||
|
|
||||||
for mod_name, mod_keybinds in pairs(_raw_keybinds) do
|
|
||||||
for _, keybind in pairs(mod_keybinds) do
|
|
||||||
local function_name = keybind[1]
|
|
||||||
local primary_key = keybind[2][1]
|
|
||||||
|
|
||||||
local special_key1 = keybind[2][2]
|
|
||||||
local special_key2 = keybind[2][3]
|
|
||||||
local special_key3 = keybind[2][4]
|
|
||||||
|
|
||||||
local special_keys = {}
|
|
||||||
|
|
||||||
if special_key1 then
|
|
||||||
special_keys[special_key1] = true
|
|
||||||
end
|
|
||||||
if special_key2 then
|
|
||||||
special_keys[special_key2] = true
|
|
||||||
end
|
|
||||||
if special_key3 then
|
|
||||||
special_keys[special_key3] = true
|
|
||||||
end
|
|
||||||
|
|
||||||
_optimized_keybinds[primary_key] = _optimized_keybinds[primary_key] or {}
|
|
||||||
table.insert(_optimized_keybinds[primary_key], {
|
|
||||||
mod_name, function_name,
|
|
||||||
special_keys["ctrl"],
|
|
||||||
special_keys["alt"],
|
|
||||||
special_keys["shift"]
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ####################################################################################################################
|
|
||||||
-- ##### VMFMod #######################################################################################################
|
|
||||||
-- ####################################################################################################################
|
|
||||||
|
|
||||||
-- use it directly only for dedugging purposes, otherwise use keybind widget
|
|
||||||
-- setting_id [string] - keybind identifyer for certain mod
|
|
||||||
-- function_name [string] - name of some mod.function which will be called when keybind is pressed
|
|
||||||
-- keys [table] = {"primary_key", "2nd_key" [optional], "3rd_key" [optional], "4th_key" [optional]}
|
|
||||||
-- 2, 3, 4 keys can contain words "ctrl", "alt", "shift" (lowercase)
|
|
||||||
VMFMod.keybind = function (self, setting_id, function_name, keys)
|
|
||||||
|
|
||||||
if keys[1] then
|
|
||||||
|
|
||||||
local mod_keybinds = _raw_keybinds[self:get_name()] or {}
|
|
||||||
|
|
||||||
mod_keybinds[setting_id] = {function_name, keys}
|
|
||||||
|
|
||||||
_raw_keybinds[self:get_name()] = mod_keybinds
|
|
||||||
else
|
|
||||||
|
|
||||||
local mod_keybinds = _raw_keybinds[self:get_name()]
|
|
||||||
|
|
||||||
if mod_keybinds and mod_keybinds[setting_id] then
|
|
||||||
mod_keybinds[setting_id] = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if vmf.keybind_input_service then
|
|
||||||
apply_keybinds()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ####################################################################################################################
|
|
||||||
-- ##### VMF internal functions and variables #########################################################################
|
|
||||||
-- ####################################################################################################################
|
|
||||||
|
|
||||||
vmf.initialize_keybinds = function()
|
|
||||||
Managers.input:create_input_service("VMFMods", "VMFModsKeyMap")
|
|
||||||
Managers.input:map_device_to_service("VMFMods", "keyboard")
|
|
||||||
Managers.input:map_device_to_service("VMFMods", "mouse")
|
|
||||||
|
|
||||||
vmf.keybind_input_service = Managers.input:get_service("VMFMods")
|
|
||||||
|
|
||||||
apply_keybinds()
|
|
||||||
end
|
|
||||||
|
|
||||||
vmf.check_pressed_keybinds = function()
|
|
||||||
|
|
||||||
local input_service = vmf.keybind_input_service
|
|
||||||
if input_service then
|
|
||||||
|
|
||||||
-- don't check for the pressed keybindings until player will release already pressed keybind
|
|
||||||
if _activated_pressed_key then
|
|
||||||
if input_service:get(_activated_pressed_key) then
|
|
||||||
return
|
|
||||||
else
|
|
||||||
_activated_pressed_key = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local key_has_active_keybind = false
|
|
||||||
local input_ctrl = input_service:get("ctrl")
|
|
||||||
local input_shift = input_service:get("shift")
|
|
||||||
local input_alt = input_service:get("alt")
|
|
||||||
|
|
||||||
for key, key_bindings in pairs(_optimized_keybinds) do
|
|
||||||
if input_service:get(key) then
|
|
||||||
|
|
||||||
for _, binding_info in ipairs(key_bindings) do
|
|
||||||
if (not binding_info[3] and not input_ctrl or binding_info[3] and input_ctrl) and
|
|
||||||
(not binding_info[4] and not input_alt or binding_info[4] and input_alt) and
|
|
||||||
(not binding_info[5] and not input_shift or binding_info[5] and input_shift) then
|
|
||||||
|
|
||||||
local mod = get_mod(binding_info[1])
|
|
||||||
|
|
||||||
if binding_info[2] == "toggle_mod_state" and not mod:get_internal_data("is_mutator") then
|
|
||||||
|
|
||||||
vmf.mod_state_changed(mod:get_name(), not mod:is_enabled())
|
|
||||||
|
|
||||||
key_has_active_keybind = true
|
|
||||||
_activated_pressed_key = key
|
|
||||||
|
|
||||||
elseif mod:is_enabled() then
|
|
||||||
|
|
||||||
local action_exists, action_function = pcall(function() return mod[binding_info[2]] end)
|
|
||||||
if action_exists then
|
|
||||||
local error_prefix = "(keybindings) " .. tostring(binding_info[2])
|
|
||||||
vmf.xpcall_no_return_values(mod, error_prefix, action_function)
|
|
||||||
else
|
|
||||||
mod:error("(keybindings): function '%s' wasn't found.", tostring(binding_info[2]))
|
|
||||||
end
|
|
||||||
|
|
||||||
key_has_active_keybind = true
|
|
||||||
_activated_pressed_key = key
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- return here because some other mods can have the same keybind which also need to be executed
|
|
||||||
if key_has_active_keybind then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
vmf.delete_keybinds = function()
|
|
||||||
VMFModsKeyMap = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
local keyboard_buton_name = Keyboard.button_name
|
|
||||||
local mouse_buton_name = Mouse.button_name
|
|
||||||
|
|
||||||
vmf.keys = {
|
|
||||||
keyboard = {
|
|
||||||
[8] = {"Backspace", "backspace", keyboard_buton_name(8)},
|
|
||||||
[9] = {"Tab", "tab", keyboard_buton_name(9)},
|
|
||||||
[13] = {"Enter", "enter", keyboard_buton_name(13)},
|
|
||||||
[20] = {"Caps Lock", "caps lock", keyboard_buton_name(20)},
|
|
||||||
[32] = {"Space", "space", keyboard_buton_name(32)},
|
|
||||||
[33] = {"Page Up", "page up", keyboard_buton_name(33)},
|
|
||||||
[34] = {"Page Down", "page down", keyboard_buton_name(34)},
|
|
||||||
[35] = {"End", "end", keyboard_buton_name(35)},
|
|
||||||
[36] = {"Home", "home", keyboard_buton_name(36)},
|
|
||||||
[37] = {"Left", "left", keyboard_buton_name(37)},
|
|
||||||
[38] = {"Up", "up", keyboard_buton_name(38)},
|
|
||||||
[39] = {"Right", "right", keyboard_buton_name(39)},
|
|
||||||
[40] = {"Down", "down", keyboard_buton_name(40)},
|
|
||||||
[45] = {"Insert", "insert", keyboard_buton_name(45)},
|
|
||||||
[46] = {"Delete", "delete", keyboard_buton_name(46)},
|
|
||||||
[48] = {"0", "0", keyboard_buton_name(48)},
|
|
||||||
[49] = {"1", "1", keyboard_buton_name(49)},
|
|
||||||
[50] = {"2", "2", keyboard_buton_name(50)},
|
|
||||||
[51] = {"3", "3", keyboard_buton_name(51)},
|
|
||||||
[52] = {"4", "4", keyboard_buton_name(52)},
|
|
||||||
[53] = {"5", "5", keyboard_buton_name(53)},
|
|
||||||
[54] = {"6", "6", keyboard_buton_name(54)},
|
|
||||||
[55] = {"7", "7", keyboard_buton_name(55)},
|
|
||||||
[56] = {"8", "8", keyboard_buton_name(56)},
|
|
||||||
[57] = {"9", "9", keyboard_buton_name(57)},
|
|
||||||
[65] = {"A", "a", keyboard_buton_name(65)},
|
|
||||||
[66] = {"B", "b", keyboard_buton_name(66)},
|
|
||||||
[67] = {"C", "c", keyboard_buton_name(67)},
|
|
||||||
[68] = {"D", "d", keyboard_buton_name(68)},
|
|
||||||
[69] = {"E", "e", keyboard_buton_name(69)},
|
|
||||||
[70] = {"F", "f", keyboard_buton_name(70)},
|
|
||||||
[71] = {"G", "g", keyboard_buton_name(71)},
|
|
||||||
[72] = {"H", "h", keyboard_buton_name(72)},
|
|
||||||
[73] = {"I", "i", keyboard_buton_name(73)},
|
|
||||||
[74] = {"J", "j", keyboard_buton_name(74)},
|
|
||||||
[75] = {"K", "k", keyboard_buton_name(75)},
|
|
||||||
[76] = {"L", "l", keyboard_buton_name(76)},
|
|
||||||
[77] = {"M", "m", keyboard_buton_name(77)},
|
|
||||||
[78] = {"N", "n", keyboard_buton_name(78)},
|
|
||||||
[79] = {"O", "o", keyboard_buton_name(79)},
|
|
||||||
[80] = {"P", "p", keyboard_buton_name(80)},
|
|
||||||
[81] = {"Q", "q", keyboard_buton_name(81)},
|
|
||||||
[82] = {"R", "r", keyboard_buton_name(82)},
|
|
||||||
[83] = {"S", "s", keyboard_buton_name(83)},
|
|
||||||
[84] = {"T", "t", keyboard_buton_name(84)},
|
|
||||||
[85] = {"U", "u", keyboard_buton_name(85)},
|
|
||||||
[86] = {"V", "v", keyboard_buton_name(86)},
|
|
||||||
[87] = {"W", "w", keyboard_buton_name(87)},
|
|
||||||
[88] = {"X", "x", keyboard_buton_name(88)},
|
|
||||||
[89] = {"Y", "y", keyboard_buton_name(89)},
|
|
||||||
[90] = {"Z", "z", keyboard_buton_name(90)},
|
|
||||||
[91] = {"Win", "win", keyboard_buton_name(91)},
|
|
||||||
[92] = {"RWin", "right win", keyboard_buton_name(92)},
|
|
||||||
[96] = {"Num 0", "numpad 0", keyboard_buton_name(96)},
|
|
||||||
[97] = {"Num 1", "numpad 1", keyboard_buton_name(97)},
|
|
||||||
[98] = {"Num 2", "numpad 2", keyboard_buton_name(98)},
|
|
||||||
[99] = {"Num 3", "numpad 3", keyboard_buton_name(99)},
|
|
||||||
[100] = {"Num 4", "numpad 4", keyboard_buton_name(100)},
|
|
||||||
[101] = {"Num 5", "numpad 5", keyboard_buton_name(101)},
|
|
||||||
[102] = {"Num 6", "numpad 6", keyboard_buton_name(102)},
|
|
||||||
[103] = {"Num 7", "numpad 7", keyboard_buton_name(103)},
|
|
||||||
[104] = {"Num 8", "numpad 8", keyboard_buton_name(104)},
|
|
||||||
[105] = {"Num 9", "numpad 9", keyboard_buton_name(105)},
|
|
||||||
[106] = {"Num *", "numpad *", keyboard_buton_name(106)},
|
|
||||||
[107] = {"Num +", "numpad +", keyboard_buton_name(107)},
|
|
||||||
[109] = {"Num -", "numpad -", keyboard_buton_name(109)},
|
|
||||||
[110] = {"Num .", "numpad .", keyboard_buton_name(110)},
|
|
||||||
[111] = {"Num /", "numpad /", keyboard_buton_name(111)},
|
|
||||||
[112] = {"F1", "f1", keyboard_buton_name(112)},
|
|
||||||
[113] = {"F2", "f2", keyboard_buton_name(113)},
|
|
||||||
[114] = {"F3", "f3", keyboard_buton_name(114)},
|
|
||||||
[115] = {"F4", "f4", keyboard_buton_name(115)},
|
|
||||||
[116] = {"F5", "f5", keyboard_buton_name(116)},
|
|
||||||
[117] = {"F6", "f6", keyboard_buton_name(117)},
|
|
||||||
[118] = {"F7", "f7", keyboard_buton_name(118)},
|
|
||||||
[119] = {"F8", "f8", keyboard_buton_name(119)},
|
|
||||||
[120] = {"F9", "f9", keyboard_buton_name(120)},
|
|
||||||
[121] = {"F10", "f10", keyboard_buton_name(121)},
|
|
||||||
[122] = {"F11", "f11", keyboard_buton_name(122)},
|
|
||||||
[123] = {"F12", "f12", keyboard_buton_name(123)},
|
|
||||||
[144] = {"Num Lock", "num lock", keyboard_buton_name(144)},
|
|
||||||
[145] = {"Scroll Lock", "scroll lock", keyboard_buton_name(145)},
|
|
||||||
[166] = {"Browser Back", "browser back", keyboard_buton_name(166)},
|
|
||||||
[167] = {"Browser Forward", "browser forward", keyboard_buton_name(167)},
|
|
||||||
[168] = {"Browser Refresh", "browser refresh", keyboard_buton_name(168)},
|
|
||||||
[169] = {"Browser Stop", "browser stop", keyboard_buton_name(169)},
|
|
||||||
[170] = {"Browser Search", "browser search", keyboard_buton_name(170)},
|
|
||||||
[171] = {"Browser Favorites", "browser favorites", keyboard_buton_name(171)},
|
|
||||||
[172] = {"Browser Home", "browser home", keyboard_buton_name(172)},
|
|
||||||
[173] = {"Volume Mute", "volume mute", keyboard_buton_name(173)},
|
|
||||||
[174] = {"Volume Down", "volume down", keyboard_buton_name(174)},
|
|
||||||
[175] = {"Volume Up", "volume up", keyboard_buton_name(175)},
|
|
||||||
[176] = {"Next Track", "next track", keyboard_buton_name(176)},
|
|
||||||
[177] = {"Previous Track", "previous track", keyboard_buton_name(177)},
|
|
||||||
[178] = {"Stop", "stop", keyboard_buton_name(178)},
|
|
||||||
[179] = {"Play/Pause", "play pause", keyboard_buton_name(179)},
|
|
||||||
[180] = {"Mail", "mail", keyboard_buton_name(180)},
|
|
||||||
[181] = {"Media", "media", keyboard_buton_name(181)},
|
|
||||||
[182] = {"Start Application 1", "start app 1", keyboard_buton_name(182)},
|
|
||||||
[183] = {"Start Application 2", "start app 2", keyboard_buton_name(183)},
|
|
||||||
[186] = {";", ";", keyboard_buton_name(186)},
|
|
||||||
[187] = {"=", "=", keyboard_buton_name(187)},
|
|
||||||
[188] = {",", ",", keyboard_buton_name(188)},
|
|
||||||
[189] = {"-", "-", keyboard_buton_name(189)},
|
|
||||||
[190] = {".", ".", keyboard_buton_name(190)},
|
|
||||||
[191] = {"/", "/", keyboard_buton_name(191)},
|
|
||||||
[192] = {"`", "`", keyboard_buton_name(192)},
|
|
||||||
[219] = {"[", "[", keyboard_buton_name(219)},
|
|
||||||
[220] = {"\\", "\\", keyboard_buton_name(220)},
|
|
||||||
[221] = {"]", "]", keyboard_buton_name(221)},
|
|
||||||
[222] = {"'", "'", keyboard_buton_name(222)},
|
|
||||||
--?[226] = {"\", "oem_102 (> <)", keyboard_buton_name(226)},
|
|
||||||
[256] = {"Num Enter", "numpad enter", keyboard_buton_name(256)}
|
|
||||||
},
|
|
||||||
mouse = {
|
|
||||||
[0] = {"Mouse Left", "mouse left", mouse_buton_name(0)},
|
|
||||||
[1] = {"Mouse Right", "mouse right", mouse_buton_name(1)},
|
|
||||||
[2] = {"Mouse Middle", "mouse middle", mouse_buton_name(2)},
|
|
||||||
[3] = {"Mouse Extra 1", "mouse extra 1", mouse_buton_name(3)},
|
|
||||||
[4] = {"Mouse Extra 2", "mouse extra 2", mouse_buton_name(4)},
|
|
||||||
[10] = {"Mouse Wheel Up", "mouse wheel up", mouse_buton_name(10)},
|
|
||||||
[11] = {"Mouse Wheel Down", "mouse wheel down", mouse_buton_name(11)},
|
|
||||||
[12] = {"Mouse Wheel Left", "mouse wheel left", mouse_buton_name(12)},
|
|
||||||
[13] = {"Mouse Wheel Right", "mouse wheel right", mouse_buton_name(13)}
|
|
||||||
},--[[ -- will work on this if it will be needed
|
},--[[ -- will work on this if it will be needed
|
||||||
gamepad = {
|
GAMEPAD = {
|
||||||
[0] = {"", "d_up", gamepad_buton_name(0)},
|
[0] = {"", "d_up"},
|
||||||
[1] = {"", "d_down", gamepad_buton_name(1)},
|
[1] = {"", "d_down"},
|
||||||
[2] = {"", "d_left", gamepad_buton_name(2)},
|
[2] = {"", "d_left"},
|
||||||
[3] = {"", "d_right", gamepad_buton_name(3)},
|
[3] = {"", "d_right"},
|
||||||
[4] = {"", "start", gamepad_buton_name(4)},
|
[4] = {"", "start"},
|
||||||
[5] = {"", "back", gamepad_buton_name(5)},
|
[5] = {"", "back"},
|
||||||
[6] = {"", "left_thumb", gamepad_buton_name(6)},
|
[6] = {"", "left_thumb"},
|
||||||
[7] = {"", "right_thumb", gamepad_buton_name(7)},
|
[7] = {"", "right_thumb"},
|
||||||
[8] = {"", "left_shoulder", gamepad_buton_name(8)},
|
[8] = {"", "left_shoulder"},
|
||||||
[9] = {"", "right_shoulder", gamepad_buton_name(9)},
|
[9] = {"", "right_shoulder"},
|
||||||
[10] = {"", "left_trigger", gamepad_buton_name(10)},
|
[10] = {"", "left_trigger"},
|
||||||
[11] = {"", "right_trigger", gamepad_buton_name(11)},
|
[11] = {"", "right_trigger"},
|
||||||
[12] = {"", "a", gamepad_buton_name(12)},
|
[12] = {"", "a"},
|
||||||
[13] = {"", "b", gamepad_buton_name(13)},
|
[13] = {"", "b"},
|
||||||
[14] = {"", "x", gamepad_buton_name(14)},
|
[14] = {"", "x"},
|
||||||
[15] = {"", "y", gamepad_buton_name(15)},
|
[15] = {"", "y"},
|
||||||
}]]
|
}]]
|
||||||
}
|
}
|
||||||
|
|
||||||
vmf.readable_key_names = {}
|
local OTHER_KEYS = {
|
||||||
|
-- modifier keys
|
||||||
|
["shift"] = {160, "Shift", "KEYBOARD", 161},
|
||||||
|
["ctrl"] = {162, "Ctrl", "KEYBOARD", 163},
|
||||||
|
["alt"] = {164, "Alt", "KEYBOARD", 165},
|
||||||
|
-- hack for 'vmf.build_keybind_string' function
|
||||||
|
["no_button"] = {-1, ""}
|
||||||
|
}
|
||||||
|
|
||||||
-- ####################################################################################################################
|
local KEYS_INFO = {}
|
||||||
-- ##### Script #######################################################################################################
|
-- Populate KEYS_INFO:
|
||||||
-- ####################################################################################################################
|
for input_device_name, input_device_keys in pairs(PRIMARY_BINDABLE_KEYS) do
|
||||||
|
for key_index, key_info in pairs(input_device_keys) do
|
||||||
|
KEYS_INFO[key_info[2]] = {key_index, key_info[1], input_device_name}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for key_id, key_data in pairs(OTHER_KEYS) do
|
||||||
|
KEYS_INFO[key_id] = key_data
|
||||||
|
end
|
||||||
|
|
||||||
for _, controller_keys in pairs(vmf.keys) do
|
-- Can't use 'Device.released' because it will break keybinds if button is released when game window is not active.
|
||||||
for _, key_info in pairs(controller_keys) do
|
local CHECK_INPUT_FUNCTIONS = {
|
||||||
vmf.readable_key_names[key_info[2]] = key_info[1]
|
KEYBOARD = {
|
||||||
|
PRESSED = function(key_id) return Keyboard.pressed(KEYS_INFO[key_id][1]) end,
|
||||||
|
RELEASED = function(key_id) return Keyboard.button(KEYS_INFO[key_id][1]) == 0 end
|
||||||
|
},
|
||||||
|
MOUSE = {
|
||||||
|
PRESSED = function(key_id) return Mouse.pressed(KEYS_INFO[key_id][1]) end,
|
||||||
|
RELEASED = function(key_id) return Mouse.button(KEYS_INFO[key_id][1]) == 0 end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
local _raw_keybinds_data = {}
|
||||||
|
local _keybinds = {}
|
||||||
|
local _pressed_key
|
||||||
|
|
||||||
|
local ERRORS = {
|
||||||
|
PREFIX = {
|
||||||
|
function_call = "[Keybindings] function_call 'mod.%s'"
|
||||||
|
},
|
||||||
|
REGULAR = {
|
||||||
|
function_not_found = "[Keybindings] function_call 'mod.%s': function was not found."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-- #####################################################################################################################
|
||||||
|
-- ##### Local functions ###############################################################################################
|
||||||
|
-- #####################################################################################################################
|
||||||
|
|
||||||
|
local function is_vmf_input_service_active()
|
||||||
|
local input_service = Managers.input:get_service("VMF")
|
||||||
|
return input_service and not input_service:is_blocked()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Executes function for 'function_call' keybinds.
|
||||||
|
local function call_function(mod, function_name, keybind_is_pressed)
|
||||||
|
if type(mod[function_name]) == "function" then
|
||||||
|
vmf.safe_call_nr(mod, {ERRORS.PREFIX["function_call"], function_name}, mod[function_name], keybind_is_pressed)
|
||||||
|
else
|
||||||
|
mod:error(ERRORS.PREFIX["function_not_found"], function_name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
vmf.readable_key_names["ctrl"] = "Ctrl"
|
|
||||||
vmf.readable_key_names["alt"] = "Alt"
|
|
||||||
vmf.readable_key_names["shift"] = "Shift"
|
|
||||||
|
|
||||||
for _, key_info in pairs(vmf.keys.keyboard) do
|
-- If check of keybind's conditions is successful, performs keybind's action and returns 'true'.
|
||||||
VMFModsKeyMap.win32[key_info[2]] = {"keyboard", key_info[3], "held"}
|
local function perform_keybind_action(data, is_pressed)
|
||||||
|
local can_perform_action = is_vmf_input_service_active() or data.global or data.release_action
|
||||||
|
|
||||||
|
if data.type == "mod_toggle" and can_perform_action and not data.mod:get_internal_data("is_mutator") then
|
||||||
|
vmf.mod_state_changed(data.mod:get_name(), not data.mod:is_enabled())
|
||||||
|
return true
|
||||||
|
elseif data.type == "function_call" and can_perform_action and data.mod:is_enabled() then
|
||||||
|
call_function(data.mod, data.function_name, is_pressed)
|
||||||
|
return true
|
||||||
|
elseif data.type == "view_toggle" and data.mod:is_enabled() then
|
||||||
|
vmf.keybind_toggle_view(data.mod, data.view_name, can_perform_action, is_pressed)
|
||||||
|
return true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for i = 0, 4 do
|
-- #####################################################################################################################
|
||||||
local key_info = vmf.keys.mouse[i]
|
-- ##### VMF internal functions and variables ##########################################################################
|
||||||
VMFModsKeyMap.win32[key_info[2]] = {"mouse", key_info[3], "held"}
|
-- #####################################################################################################################
|
||||||
|
|
||||||
|
-- Checks for pressed and released keybinds, performs keybind actions.
|
||||||
|
-- * Checks for both right and left key modifiers (ctrl, alt, shift).
|
||||||
|
-- * If some keybind is pressed, won't check for other keybinds until this keybing is released.
|
||||||
|
-- * If several mods bound the same keys, keybind action will be performed for all of them, when keybind is pressed.
|
||||||
|
-- * Keybind is considered released, when its primary key is released.
|
||||||
|
function vmf.check_keybinds()
|
||||||
|
local ctrl_pressed = (Keyboard.button(KEYS_INFO["ctrl"][1]) + Keyboard.button(KEYS_INFO["ctrl"][4])) > 0
|
||||||
|
local alt_pressed = (Keyboard.button(KEYS_INFO["alt"][1]) + Keyboard.button(KEYS_INFO["alt"][4])) > 0
|
||||||
|
local shift_pressed = (Keyboard.button(KEYS_INFO["shift"][1]) + Keyboard.button(KEYS_INFO["shift"][4])) > 0
|
||||||
|
|
||||||
|
if not _pressed_key then
|
||||||
|
for primary_key, keybinds_data in pairs(_keybinds) do
|
||||||
|
if keybinds_data.check_pressed(primary_key) then
|
||||||
|
for _, keybind_data in ipairs(keybinds_data) do
|
||||||
|
if (not keybind_data.ctrl and not ctrl_pressed or keybind_data.ctrl and ctrl_pressed) and
|
||||||
|
(not keybind_data.alt and not alt_pressed or keybind_data.alt and alt_pressed) and
|
||||||
|
(not keybind_data.shift and not shift_pressed or keybind_data.shift and shift_pressed)
|
||||||
|
then
|
||||||
|
if perform_keybind_action(keybind_data, true) then
|
||||||
|
if keybind_data.trigger == "held" then
|
||||||
|
keybind_data.release_action = true
|
||||||
|
end
|
||||||
|
_pressed_key = primary_key
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if _pressed_key then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for i = 10, 13 do
|
if _pressed_key then
|
||||||
local key_info = vmf.keys.mouse[i]
|
if _keybinds[_pressed_key].check_released(_pressed_key) then
|
||||||
VMFModsKeyMap.win32[key_info[2]] = {"mouse", key_info[3], "pressed"}
|
for _, keybind_data in ipairs(_keybinds[_pressed_key]) do
|
||||||
|
if keybind_data.release_action then
|
||||||
|
perform_keybind_action(keybind_data, false)
|
||||||
|
keybind_data.release_action = nil
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
_pressed_key = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Converts managable (raw) table of keybinds data to the table designed for the function checking for pressed and
|
||||||
|
-- released keybinds. After initial call requires to be called every time some keybind is added/removed.
|
||||||
|
function vmf.generate_keybinds()
|
||||||
|
_keybinds = {}
|
||||||
|
|
||||||
|
for mod, mod_keybinds in pairs(_raw_keybinds_data) do
|
||||||
|
for _, raw_keybind_data in pairs(mod_keybinds) do
|
||||||
|
|
||||||
|
local keys = raw_keybind_data[4]
|
||||||
|
local primary_key = keys[1]
|
||||||
|
local modifier_keys = {}
|
||||||
|
for i = 2, #keys do
|
||||||
|
modifier_keys[keys[i]] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
local keybind_data = {
|
||||||
|
mod = mod,
|
||||||
|
global = raw_keybind_data[1],
|
||||||
|
trigger = raw_keybind_data[2],
|
||||||
|
type = raw_keybind_data[3],
|
||||||
|
ctrl = modifier_keys["ctrl"],
|
||||||
|
alt = modifier_keys["alt"],
|
||||||
|
shift = modifier_keys["shift"],
|
||||||
|
|
||||||
|
function_name = raw_keybind_data[5],
|
||||||
|
view_name = raw_keybind_data[6]
|
||||||
|
}
|
||||||
|
|
||||||
|
_keybinds[primary_key] = _keybinds[primary_key] or {
|
||||||
|
check_pressed = CHECK_INPUT_FUNCTIONS[KEYS_INFO[primary_key][3]].PRESSED,
|
||||||
|
check_released = CHECK_INPUT_FUNCTIONS[KEYS_INFO[primary_key][3]].RELEASED
|
||||||
|
}
|
||||||
|
table.insert(_keybinds[primary_key], keybind_data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Adds/removes keybinds.
|
||||||
|
function vmf.add_mod_keybind(mod, setting_id, global, trigger, type, keys, function_name, view_name)
|
||||||
|
if #keys > 0 then
|
||||||
|
_raw_keybinds_data[mod] = _raw_keybinds_data[mod] or {}
|
||||||
|
_raw_keybinds_data[mod][setting_id] = {global, trigger, type, keys, function_name, view_name}
|
||||||
|
elseif _raw_keybinds_data[mod] and _raw_keybinds_data[mod][setting_id] then
|
||||||
|
_raw_keybinds_data[mod][setting_id] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Keybind is changed from Mod Options.
|
||||||
|
if vmf.all_mods_were_loaded then
|
||||||
|
vmf.generate_keybinds()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Creates VMF input service. It is required to know when non-global keybinds can be triggered.
|
||||||
|
-- (Called every time a level is loaded, or on mods reload)
|
||||||
|
function vmf.create_keybinds_input_service()
|
||||||
|
-- VMF input has to be created only during the actual game
|
||||||
|
if Managers.state.game_mode and not Managers.input:get_service("VMF") then
|
||||||
|
rawset(_G, "EmptyKeyMap", {win32 = {}, xb1 = {}})
|
||||||
|
Managers.input:create_input_service("VMF", "EmptyKeyMap")
|
||||||
|
rawset(_G, "EmptyKeyMap", nil)
|
||||||
|
|
||||||
|
-- Synchronize state of VMF input service with Player input service
|
||||||
|
local is_blocked = Managers.input:get_service("Player"):is_blocked()
|
||||||
|
Managers.input:get_service("VMF"):set_blocked(is_blocked)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Converts key_index to readable key_id, which is used by VMF to idenify keys.
|
||||||
|
-- (Used for capturing keybinds)
|
||||||
|
function vmf.get_key_id(device, key_index)
|
||||||
|
local key_info = PRIMARY_BINDABLE_KEYS[device][key_index]
|
||||||
|
return key_info and key_info[2]
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Simply tells if key with key_id can be binded as primary key.
|
||||||
|
-- (Used for verifying keybind widgets)
|
||||||
|
function vmf.can_bind_as_primary_key(key_id)
|
||||||
|
return KEYS_INFO[key_id] and not OTHER_KEYS[key_id]
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Builds string with readable keys' names to look like "Primary Key + Ctrl + Alt + Shift".
|
||||||
|
-- (Used in keybind widget)
|
||||||
|
function vmf.build_keybind_string(keys)
|
||||||
|
local readable_key_names = {}
|
||||||
|
for _, key_id in ipairs(keys) do
|
||||||
|
table.insert(readable_key_names, KEYS_INFO[key_id][2])
|
||||||
|
end
|
||||||
|
return table.concat(readable_key_names, " + ")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- #####################################################################################################################
|
||||||
|
-- ##### Script ########################################################################################################
|
||||||
|
-- #####################################################################################################################
|
||||||
|
|
||||||
|
-- In case mods reloading was performed right at the moment of entering 'StateInGame'.
|
||||||
|
vmf.create_keybinds_input_service()
|
|
@ -27,7 +27,3 @@ function vmf.check_old_vmf()
|
||||||
"Either remove old mods or disable workshop mods.")
|
"Either remove old mods or disable workshop mods.")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function vmf.throw_error(error_message, ...)
|
|
||||||
error(string.format(error_message, ...), 0)
|
|
||||||
end
|
|
|
@ -176,7 +176,7 @@ local function send_rpc_vmf_data_local(mod_name, rpc_name, ...)
|
||||||
network_debug("data", "local", nil, mod_name, rpc_name, {...})
|
network_debug("data", "local", nil, mod_name, rpc_name, {...})
|
||||||
|
|
||||||
local error_prefix = "(local rpc) " .. tostring(rpc_name)
|
local error_prefix = "(local rpc) " .. tostring(rpc_name)
|
||||||
vmf.xpcall_no_return_values(mod, error_prefix, _rpc_callbacks[mod_name][rpc_name], Network.peer_id(), ...)
|
vmf.safe_call_nr(mod, error_prefix, _rpc_callbacks[mod_name][rpc_name], Network.peer_id(), ...)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -307,7 +307,7 @@ vmf:hook("ChatManager", "rpc_chat_message",
|
||||||
|
|
||||||
-- can be error in both callback_function() and deserialize_data()
|
-- can be error in both callback_function() and deserialize_data()
|
||||||
local error_prefix = "(network) " .. tostring(rpc_name)
|
local error_prefix = "(network) " .. tostring(rpc_name)
|
||||||
vmf.xpcall_no_return_values(
|
vmf.safe_call_nr(
|
||||||
get_mod(mod_name),
|
get_mod(mod_name),
|
||||||
error_prefix,
|
error_prefix,
|
||||||
function() _rpc_callbacks[mod_name][rpc_name](sender, deserialize_data(rpc_data2)) end
|
function() _rpc_callbacks[mod_name][rpc_name](sender, deserialize_data(rpc_data2)) end
|
||||||
|
|
|
@ -301,7 +301,7 @@ local allowed_keybind_types = {
|
||||||
view_toggle = true,
|
view_toggle = true,
|
||||||
mod_toggle = true
|
mod_toggle = true
|
||||||
}
|
}
|
||||||
local allowed_special_keys = {
|
local allowed_modifier_keys = {
|
||||||
ctrl = true,
|
ctrl = true,
|
||||||
alt = true,
|
alt = true,
|
||||||
shift = true
|
shift = true
|
||||||
|
@ -339,12 +339,12 @@ local function validate_keybind_data(data)
|
||||||
vmf.throw_error("[widget \"%s\" (keybind)]: table stored in 'default_value' field can't exceed 4 elements",
|
vmf.throw_error("[widget \"%s\" (keybind)]: table stored in 'default_value' field can't exceed 4 elements",
|
||||||
data.setting_id)
|
data.setting_id)
|
||||||
end
|
end
|
||||||
if default_value[1] and (not vmf.readable_key_names[default_value[1]] or allowed_special_keys[default_value[1]]) then
|
if default_value[1] and not vmf.can_bind_as_primary_key(default_value[1]) then
|
||||||
vmf.throw_error("[widget \"%s\" (keybind)]: 'default_value[1]' must be a valid key name", data.setting_id)
|
vmf.throw_error("[widget \"%s\" (keybind)]: 'default_value[1]' must be a valid key name", data.setting_id)
|
||||||
end
|
end
|
||||||
if default_value[2] and not allowed_special_keys[default_value[2]] or
|
if default_value[2] and not allowed_modifier_keys[default_value[2]] or
|
||||||
default_value[3] and not allowed_special_keys[default_value[3]] or
|
default_value[3] and not allowed_modifier_keys[default_value[3]] or
|
||||||
default_value[4] and not allowed_special_keys[default_value[4]]
|
default_value[4] and not allowed_modifier_keys[default_value[4]]
|
||||||
then
|
then
|
||||||
vmf.throw_error("[widget \"%s\" (keybind)]: 'default_value [2], [3] and [4]' can be only strings: \"ctrl\", " ..
|
vmf.throw_error("[widget \"%s\" (keybind)]: 'default_value [2], [3] and [4]' can be only strings: \"ctrl\", " ..
|
||||||
"\"alt\" and \"shift\" (in no particular order)", data.setting_id)
|
"\"alt\" and \"shift\" (in no particular order)", data.setting_id)
|
||||||
|
@ -542,7 +542,8 @@ local function initialize_default_settings_and_keybinds(mod, initialized_widgets
|
||||||
mod:set(data.setting_id, data.default_value)
|
mod:set(data.setting_id, data.default_value)
|
||||||
end
|
end
|
||||||
if data.type == "keybind" then
|
if data.type == "keybind" then
|
||||||
mod:keybind(data.setting_id, data.function_name, mod:get(data.setting_id))
|
vmf.add_mod_keybind(mod, data.setting_id, data.keybind_global, data.keybind_trigger, data.keybind_type,
|
||||||
|
mod:get(data.setting_id), data.function_name, data.view_name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,17 +17,29 @@ local function print_error_callstack(error_message)
|
||||||
return error_message
|
return error_message
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function show_error(mod, error_prefix_data, error_message)
|
||||||
|
local error_prefix
|
||||||
|
if type(error_prefix_data) == "table" then
|
||||||
|
error_prefix = string.format(error_prefix_data[1], error_prefix_data[2], error_prefix_data[3], error_prefix_data[4])
|
||||||
|
else
|
||||||
|
error_prefix = error_prefix_data
|
||||||
|
end
|
||||||
|
|
||||||
|
mod:error("%s: %s", error_prefix, error_message)
|
||||||
|
end
|
||||||
|
|
||||||
-- #####################################################################################################################
|
-- #####################################################################################################################
|
||||||
-- ##### VMFMod ########################################################################################################
|
-- ##### VMFMod ########################################################################################################
|
||||||
-- #####################################################################################################################
|
-- #####################################################################################################################
|
||||||
|
|
||||||
function VMFMod:pcall(...)
|
function VMFMod:pcall(...)
|
||||||
return vmf.xpcall(self, "(pcall)", ...)
|
return vmf.safe_call(self, "(pcall)", ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function VMFMod:dofile(file_path)
|
function VMFMod:dofile(file_path)
|
||||||
local _, return_values = pack_pcall(vmf.xpcall_dofile(self, "(dofile)", file_path))
|
local _, return_values = pack_pcall(vmf.safe_call_dofile(self, "(dofile)", file_path))
|
||||||
return unpack(return_values, 1, return_values.n)
|
return unpack(return_values, 1, return_values.n)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -35,29 +47,48 @@ end
|
||||||
-- ##### VMF internal functions and variables ##########################################################################
|
-- ##### VMF internal functions and variables ##########################################################################
|
||||||
-- #####################################################################################################################
|
-- #####################################################################################################################
|
||||||
|
|
||||||
function vmf.xpcall(mod, error_prefix, func, ...)
|
-- Safe Call
|
||||||
|
function vmf.safe_call(mod, error_prefix_data, func, ...)
|
||||||
local success, return_values = pack_pcall(xpcall(func, print_error_callstack, ...))
|
local success, return_values = pack_pcall(xpcall(func, print_error_callstack, ...))
|
||||||
if not success then
|
if not success then
|
||||||
mod:error("%s: %s", error_prefix, return_values[1])
|
show_error(mod, error_prefix_data, return_values[1])
|
||||||
return success
|
return success
|
||||||
end
|
end
|
||||||
return success, unpack(return_values, 1, return_values.n)
|
return success, unpack(return_values, 1, return_values.n)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function vmf.xpcall_no_return_values(mod, error_prefix, func, ...)
|
-- Safe Call [No return values]
|
||||||
|
function vmf.safe_call_nr(mod, error_prefix_data, func, ...)
|
||||||
local success, error_message = xpcall(func, print_error_callstack, ...)
|
local success, error_message = xpcall(func, print_error_callstack, ...)
|
||||||
if not success then
|
if not success then
|
||||||
mod:error("%s: %s", error_prefix, error_message)
|
show_error(mod, error_prefix_data, error_message)
|
||||||
end
|
end
|
||||||
return success
|
return success
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function vmf.xpcall_dofile(mod, error_prefix, file_path)
|
-- Safe Call [No return values and error callstack]
|
||||||
|
function vmf.safe_call_nrc(mod, error_prefix_data, func, ...)
|
||||||
|
local success, error_message = pcall(func, ...)
|
||||||
|
if not success then
|
||||||
|
show_error(mod, error_prefix_data, error_message)
|
||||||
|
end
|
||||||
|
return success
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Safe Call [dofile]
|
||||||
|
function vmf.safe_call_dofile(mod, error_prefix_data, file_path)
|
||||||
if type(file_path) ~= "string" then
|
if type(file_path) ~= "string" then
|
||||||
mod:error("%s: file path should be a string.", error_prefix)
|
show_error(mod, error_prefix_data, "file path should be a string.")
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
return vmf.xpcall(mod, error_prefix, dofile, file_path)
|
return vmf.safe_call(mod, error_prefix_data, dofile, file_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Format error message and throw error.
|
||||||
|
function vmf.throw_error(error_message, ...)
|
||||||
|
error(string.format(error_message, ...), 0)
|
||||||
end
|
end
|
|
@ -1,203 +0,0 @@
|
||||||
local vmf = get_mod("VMF")
|
|
||||||
|
|
||||||
local ingame_ui = nil
|
|
||||||
|
|
||||||
-- needed to protect opened menus from being closed right away and vice versa
|
|
||||||
local closing_keybind_is_pressed = false
|
|
||||||
local opening_keybind_is_pressed = true
|
|
||||||
|
|
||||||
local views_settings = {}
|
|
||||||
|
|
||||||
-- ####################################################################################################################
|
|
||||||
-- ##### VMFMod #######################################################################################################
|
|
||||||
-- ####################################################################################################################
|
|
||||||
|
|
||||||
VMFMod.register_new_view = function (self, new_view_data)
|
|
||||||
|
|
||||||
new_view_data.view_settings.mod_name = self:get_name()
|
|
||||||
|
|
||||||
views_settings[new_view_data.view_name] = new_view_data.view_settings
|
|
||||||
|
|
||||||
-- there's no direct access to local variable 'transitions' in ingame_ui
|
|
||||||
local transitions = require("scripts/ui/views/ingame_ui_settings").transitions
|
|
||||||
|
|
||||||
for transition_name, transition_function in pairs(new_view_data.view_transitions) do
|
|
||||||
transitions[transition_name] = transition_function
|
|
||||||
end
|
|
||||||
|
|
||||||
if new_view_data.view_settings.hotkey_action_name then
|
|
||||||
-- create function mod.hotkey_action_name()
|
|
||||||
-- so the menu will open when the keybind is pressed
|
|
||||||
self[new_view_data.view_settings.hotkey_action_name] = function()
|
|
||||||
|
|
||||||
if not closing_keybind_is_pressed
|
|
||||||
and ingame_ui
|
|
||||||
and not ingame_ui:pending_transition()
|
|
||||||
and not ingame_ui:end_screen_active()
|
|
||||||
and not ingame_ui.menu_active
|
|
||||||
and not ingame_ui.leave_game
|
|
||||||
and not ingame_ui.return_to_title_screen
|
|
||||||
-- V2 doesn't have 'popup_join_lobby_handler'
|
|
||||||
and not (ingame_ui.popup_join_lobby_handler and ingame_ui.popup_join_lobby_handler.visible)
|
|
||||||
then
|
|
||||||
ingame_ui:handle_transition(new_view_data.view_settings.hotkey_transition_name)
|
|
||||||
end
|
|
||||||
|
|
||||||
closing_keybind_is_pressed = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- if reloading mods, ingame_ui exists and hook "IngameUI.setup_views" won't work
|
|
||||||
-- so set new variables and create new menu manually
|
|
||||||
if ingame_ui then
|
|
||||||
|
|
||||||
-- set 'ingame_ui.views'
|
|
||||||
local new_view_name = new_view_data.view_name
|
|
||||||
local new_view_init_function = new_view_data.view_settings.init_view_function
|
|
||||||
|
|
||||||
--if new_view_name ~= "vmf_options_view" then
|
|
||||||
ingame_ui.views[new_view_name] = new_view_init_function(ingame_ui.ingame_ui_context)
|
|
||||||
--end
|
|
||||||
-- set 'ingame_ui.blocked_transitions'
|
|
||||||
local blocked_transitions = new_view_data.view_settings.blocked_transitions
|
|
||||||
local current_blocked_transitions = ingame_ui.is_in_inn and blocked_transitions.inn or blocked_transitions.ingame
|
|
||||||
|
|
||||||
for blocked_transition_name, _ in pairs(current_blocked_transitions) do
|
|
||||||
ingame_ui.blocked_transitions[blocked_transition_name] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ####################################################################################################################
|
|
||||||
-- ##### Hooks ########################################################################################################
|
|
||||||
-- ####################################################################################################################
|
|
||||||
|
|
||||||
vmf:hook_safe(IngameUI, "setup_views", function(self, ingame_ui_context)
|
|
||||||
|
|
||||||
for view_name, view_settings in pairs(views_settings) do
|
|
||||||
|
|
||||||
if self.is_in_inn then
|
|
||||||
if view_settings.active.inn then
|
|
||||||
self.views[view_name] = view_settings.init_view_function(ingame_ui_context)
|
|
||||||
end
|
|
||||||
|
|
||||||
for blocked_transition_name, _ in pairs(view_settings.blocked_transitions.inn) do
|
|
||||||
self.blocked_transitions[blocked_transition_name] = true
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if view_settings.active.ingame then
|
|
||||||
self.views[view_name] = view_settings.init_view_function(ingame_ui_context)
|
|
||||||
end
|
|
||||||
|
|
||||||
for blocked_transition_name, _ in pairs(view_settings.blocked_transitions.ingame) do
|
|
||||||
self.blocked_transitions[blocked_transition_name] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
vmf:hook_safe(IngameUI, "init", function(self)
|
|
||||||
ingame_ui = self
|
|
||||||
end)
|
|
||||||
|
|
||||||
vmf:hook_safe(IngameUI, "destroy", function()
|
|
||||||
ingame_ui = nil
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- ####################################################################################################################
|
|
||||||
-- ##### VMF internal functions and variables #########################################################################
|
|
||||||
-- ####################################################################################################################
|
|
||||||
|
|
||||||
vmf.check_custom_menus_close_keybinds = function()
|
|
||||||
if ingame_ui then
|
|
||||||
if views_settings[ingame_ui.current_view] then
|
|
||||||
local opened_view_settings = views_settings[ingame_ui.current_view]
|
|
||||||
local mod_name = opened_view_settings.mod_name
|
|
||||||
local hotkey_name = opened_view_settings.hotkey_name
|
|
||||||
|
|
||||||
if not hotkey_name then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local close_keybind = get_mod(mod_name):get(hotkey_name)
|
|
||||||
|
|
||||||
-- vmf keybinds input service
|
|
||||||
local input_service = Managers.input:get_service("VMFMods")
|
|
||||||
local original_is_blocked = input_service:is_blocked()
|
|
||||||
|
|
||||||
if original_is_blocked then
|
|
||||||
Managers.input:device_unblock_service("keyboard", 1, "VMFMods")
|
|
||||||
end
|
|
||||||
|
|
||||||
if opening_keybind_is_pressed and not input_service:get(close_keybind[1]) then
|
|
||||||
opening_keybind_is_pressed = false
|
|
||||||
end
|
|
||||||
|
|
||||||
local input_ctrl = input_service:get("ctrl")
|
|
||||||
local input_shift = input_service:get("shift")
|
|
||||||
local input_alt = input_service:get("alt")
|
|
||||||
|
|
||||||
local close_menu = false
|
|
||||||
if not opening_keybind_is_pressed then
|
|
||||||
if input_service:get(close_keybind[1]) and
|
|
||||||
(not close_keybind[2] and not input_ctrl or close_keybind[2] and input_ctrl) and
|
|
||||||
(not close_keybind[3] and not input_alt or close_keybind[3] and input_alt) and
|
|
||||||
(not close_keybind[4] and not input_shift or close_keybind[4] and input_shift) then
|
|
||||||
|
|
||||||
close_menu = not ingame_ui.views[ingame_ui.current_view]:input_service():is_blocked()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if original_is_blocked then
|
|
||||||
Managers.input:device_block_service("keyboard", 1, "VMFMods")
|
|
||||||
end
|
|
||||||
|
|
||||||
if close_menu then
|
|
||||||
ingame_ui:handle_transition("exit_menu")
|
|
||||||
|
|
||||||
closing_keybind_is_pressed = true
|
|
||||||
end
|
|
||||||
else
|
|
||||||
opening_keybind_is_pressed = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
vmf.close_opened_custom_menus = function()
|
|
||||||
if ingame_ui then
|
|
||||||
local current_view = ingame_ui.current_view
|
|
||||||
if views_settings[current_view] then
|
|
||||||
ingame_ui:handle_transition("exit_menu")
|
|
||||||
|
|
||||||
if ingame_ui.views[current_view].destroy and get_mod(views_settings[ingame_ui.current_view].mod_name) then
|
|
||||||
|
|
||||||
local mod = get_mod(views_settings[current_view].mod_name)
|
|
||||||
local destroy_method = ingame_ui.views[current_view].destroy
|
|
||||||
vmf.xpcall_no_return_values(mod, "(custom menus) destroy view", destroy_method)
|
|
||||||
end
|
|
||||||
|
|
||||||
ingame_ui.views[current_view] = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ####################################################################################################################
|
|
||||||
-- ##### Script #######################################################################################################
|
|
||||||
-- ####################################################################################################################
|
|
||||||
|
|
||||||
|
|
||||||
local ingame_ui_exists, ingame_ui_return
|
|
||||||
if VT1 then
|
|
||||||
ingame_ui_exists, ingame_ui_return = pcall(function()
|
|
||||||
return Managers.player.network_manager.matchmaking_manager.matchmaking_ui.ingame_ui
|
|
||||||
end)
|
|
||||||
else
|
|
||||||
ingame_ui_exists, ingame_ui_return = pcall(function()
|
|
||||||
return Managers.player.network_manager.matchmaking_manager._ingame_ui
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- if VMF is reloaded mid-game
|
|
||||||
if ingame_ui_exists then
|
|
||||||
ingame_ui = ingame_ui_return
|
|
||||||
end
|
|
409
vmf/scripts/mods/vmf/modules/gui/custom_views.lua
Normal file
409
vmf/scripts/mods/vmf/modules/gui/custom_views.lua
Normal file
|
@ -0,0 +1,409 @@
|
||||||
|
local vmf = get_mod("VMF")
|
||||||
|
|
||||||
|
local _ingame_ui = nil
|
||||||
|
-- There's no direct access to local variable 'transitions' in ingame_ui.
|
||||||
|
local _ingame_ui_transitions = require("scripts/ui/views/ingame_ui_settings").transitions
|
||||||
|
local _views_data = {}
|
||||||
|
|
||||||
|
local ERRORS = {
|
||||||
|
THROWABLE = {
|
||||||
|
-- inject_view:
|
||||||
|
view_already_exists = "view with name '%s' already persists in original game.",
|
||||||
|
transition_already_exists = "transition with name '%s' already persists in original game.",
|
||||||
|
view_initializing_failed = "view initialization failed due to error during 'init_view_function' execution.",
|
||||||
|
-- validate_view_data:
|
||||||
|
view_name_wrong_type = "'view_name' must be a string, not %s.",
|
||||||
|
view_transitions_wrong_type = "'view_transitions' must be a table, not %s.",
|
||||||
|
view_settings_wrong_type = "'view_settings' must be a table, not %s.",
|
||||||
|
transition_wrong_type = "all transitions inside 'view_transitions' must be functions, but '%s' transition is %s.",
|
||||||
|
transition_name_taken = "transition name '%s' is already used by '%s' mod for '%s' view.",
|
||||||
|
init_view_function_wrong_type = "'view_settings.init_view_function' must be a function, not %s.",
|
||||||
|
active_wrong_type = "'view_settings.active' must be a table, not %s.",
|
||||||
|
active_missing_element = "'view_settings.active' must contain 2 elements: 'inn' and 'ingame'.",
|
||||||
|
active_element_wrong_name = "the only allowed names for 'view_settings.active' elements are 'inn' and 'ingame'; " ..
|
||||||
|
"you can't name your element '%s'.",
|
||||||
|
active_element_wrong_type = "'view_settings.active.%s' must be boolean, not %s.",
|
||||||
|
blocked_transitions_wrong_type = "'view_settings.blocked_transitions' (optional) must be a table, not %s.",
|
||||||
|
blocked_transitions_missing_element = "'view_settings.blocked_transitions' must contain 2 table elements: " ..
|
||||||
|
"'inn' and 'ingame'.",
|
||||||
|
blocked_transitions_element_wrong_name = "the only allowed names for 'view_settings.active' elements are " ..
|
||||||
|
"'inn' and 'ingame'; you can't name your element '%s'.",
|
||||||
|
blocked_transitions_element_wrong_type = "'view_settings.blocked_transitions.%s' must be a table, not %s.",
|
||||||
|
blocked_transition_invalid = "you can't put transition '%s' into 'view_settings.blocked_transitions.%s', " ..
|
||||||
|
"because it's not listed in 'view_transitions'.",
|
||||||
|
blocked_transition_wrong_value = "invalid value for 'view_settings.blocked_transitions.%s.%s'; must be 'true'.",
|
||||||
|
keybind_transitions_wrong_type = "'view_settings.keybind_transitions' (optional) must be a table, not %s.",
|
||||||
|
open_view_transition_wrong_type = "'view_settings.keybind_transitions.open_view_transition' (optional) must be " ..
|
||||||
|
"a string, not %s.",
|
||||||
|
transition_fade_wrong_type = "'view_settings.keybind_transitions.transition_fade' (optional) must be a boolean, " ..
|
||||||
|
"not %s.",
|
||||||
|
},
|
||||||
|
REGULAR = {
|
||||||
|
view_data_wrong_type = "[Custom Views] (register_view) Loading view data file '%s': returned view data must be " ..
|
||||||
|
"a table, not %s.",
|
||||||
|
view_not_registered = "[Custom Views] Opening view with keybind: view '%s' wasn't registered for this mod."
|
||||||
|
},
|
||||||
|
PREFIX = {
|
||||||
|
view_initializing = "[Custom Views] Calling 'init_view_function'",
|
||||||
|
view_destroying = "[Custom Views] Destroying view '%s'",
|
||||||
|
register_view_open_file = "[Custom Views] (register_view) Opening view data file '%s'",
|
||||||
|
register_view_validating = "[Custom Views] (register_view) View data validating '%s'",
|
||||||
|
register_view_injection = "[Custom Views] (register_view) View injection '%s'",
|
||||||
|
ingameui_hook_injection = "[Custom Views] View injection '%s'",
|
||||||
|
handle_transition_fade = "[Custom Views] (handle_transition) executing 'ingame_ui.transition_with_fade' for " ..
|
||||||
|
"transition '%s'",
|
||||||
|
handle_transition_no_fade = "[Custom Views] (handle_transition) executing 'ingame_ui.handle_transition' for " ..
|
||||||
|
"transition '%s'"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-- #####################################################################################################################
|
||||||
|
-- ##### Local functions ###############################################################################################
|
||||||
|
-- #####################################################################################################################
|
||||||
|
|
||||||
|
local function is_view_active_for_current_level(view_name)
|
||||||
|
local active = _views_data[view_name].view_settings.active
|
||||||
|
if _ingame_ui.is_in_inn and active.inn or not _ingame_ui.is_in_inn and active.ingame then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- @THROWS_ERRORS
|
||||||
|
local function inject_view(view_name)
|
||||||
|
if not is_view_active_for_current_level(view_name) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local view_settings = _views_data[view_name].view_settings
|
||||||
|
|
||||||
|
local mod = _views_data[view_name].mod
|
||||||
|
local init_view_function = view_settings.init_view_function
|
||||||
|
local transitions = _views_data[view_name].view_transitions
|
||||||
|
local blocked_transitions = view_settings.blocked_transitions[_ingame_ui.is_in_inn and "inn" or "ingame"]
|
||||||
|
|
||||||
|
-- Check for collisions.
|
||||||
|
if _ingame_ui.views[view_name] then
|
||||||
|
vmf.throw_error(ERRORS.THROWABLE["view_already_exists"], view_name)
|
||||||
|
end
|
||||||
|
for transition_name, _ in pairs(transitions) do
|
||||||
|
if _ingame_ui_transitions[transition_name] then
|
||||||
|
vmf.throw_error(ERRORS.THROWABLE["transition_already_exists"], transition_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Initialize and inject view.
|
||||||
|
local success, view = vmf.safe_call(mod, ERRORS.PREFIX["view_initializing"], init_view_function,
|
||||||
|
_ingame_ui.ingame_ui_context)
|
||||||
|
if success then
|
||||||
|
_ingame_ui.views[view_name] = view
|
||||||
|
else
|
||||||
|
vmf.throw_error(ERRORS.THROWABLE["view_initializing_failed"], view_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Inject view transitions.
|
||||||
|
for transition_name, transition_function in pairs(transitions) do
|
||||||
|
_ingame_ui_transitions[transition_name] = transition_function
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Inject view blocked transitions.
|
||||||
|
for blocked_transition_name, _ in pairs(blocked_transitions) do
|
||||||
|
_ingame_ui.blocked_transitions[blocked_transition_name] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function remove_injected_views(on_reload)
|
||||||
|
-- These elements should be removed only on_reload, because, otherwise, they will be deleted automatically.
|
||||||
|
if on_reload and _ingame_ui then
|
||||||
|
-- If some custom view is active, close it.
|
||||||
|
if _views_data[_ingame_ui.current_view] then
|
||||||
|
_ingame_ui:handle_transition("exit_menu")
|
||||||
|
end
|
||||||
|
|
||||||
|
for view_name, view_data in pairs(_views_data) do
|
||||||
|
-- Remove injected views.
|
||||||
|
local view = _ingame_ui.views[view_name]
|
||||||
|
if view then
|
||||||
|
if type(view.destroy) == "function" then
|
||||||
|
vmf.safe_call_nr(view_data.mod, {ERRORS.PREFIX["view_destroying"], view_name}, view.destroy)
|
||||||
|
end
|
||||||
|
_ingame_ui.views[view_name] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, view_data in pairs(_views_data) do
|
||||||
|
-- Remove injected transitions.
|
||||||
|
for transition_name, _ in pairs(view_data.view_transitions) do
|
||||||
|
_ingame_ui_transitions[transition_name] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Remove blocked transitions
|
||||||
|
local blocked_transitions = view_data.view_settings.blocked_transitions[_ingame_ui.is_in_inn and "inn" or "ingame"]
|
||||||
|
for blocked_transition_name, _ in pairs(blocked_transitions) do
|
||||||
|
_ingame_ui.blocked_transitions[blocked_transition_name] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- @THROWS_ERRORS
|
||||||
|
local function validate_view_data(view_data)
|
||||||
|
-- Basic checks.
|
||||||
|
if type(view_data.view_name) ~= "string" then
|
||||||
|
vmf.throw_error(ERRORS.THROWABLE["view_name_wrong_type"], type(view_data.view_name))
|
||||||
|
end
|
||||||
|
if type(view_data.view_transitions) ~= "table" then
|
||||||
|
vmf.throw_error(ERRORS.THROWABLE["view_transitions_wrong_type"], type(view_data.view_transitions))
|
||||||
|
end
|
||||||
|
if type(view_data.view_settings) ~= "table" then
|
||||||
|
vmf.throw_error(ERRORS.THROWABLE["view_settings_wrong_type"], type(view_data.view_settings))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- VIEW TRANSITIONS
|
||||||
|
|
||||||
|
local view_transitions = view_data.view_transitions
|
||||||
|
for transition_name, transition_function in pairs(view_transitions) do
|
||||||
|
if type(transition_function) ~= "function" then
|
||||||
|
vmf.throw_error(ERRORS.THROWABLE["transition_wrong_type"], transition_name, type(transition_function))
|
||||||
|
end
|
||||||
|
for another_view_name, another_view_data in pairs(_views_data) do
|
||||||
|
for another_transition_name, _ in pairs(another_view_data.view_transitions) do
|
||||||
|
if transition_name == another_transition_name then
|
||||||
|
vmf.throw_error(ERRORS.THROWABLE["transition_name_taken"], transition_name, another_view_data.mod:get_name(),
|
||||||
|
another_view_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- VIEW SETTINGS
|
||||||
|
|
||||||
|
local view_settings = view_data.view_settings
|
||||||
|
|
||||||
|
-- Use default values for optional fields if they are not defined.
|
||||||
|
view_settings.blocked_transitions = view_settings.blocked_transitions or {inn = {}, ingame = {}}
|
||||||
|
view_settings.keybind_transitions = view_settings.keybind_transitions or {}
|
||||||
|
|
||||||
|
-- Verify everything.
|
||||||
|
if type(view_settings.init_view_function) ~= "function" then
|
||||||
|
vmf.throw_error(ERRORS.THROWABLE["init_view_function_wrong_type"], type(view_settings.init_view_function))
|
||||||
|
end
|
||||||
|
|
||||||
|
local active = view_settings.active
|
||||||
|
if type(active) ~= "table" then
|
||||||
|
vmf.throw_error(ERRORS.THROWABLE["active_wrong_type"], type(active))
|
||||||
|
end
|
||||||
|
if active.inn == nil or active.ingame == nil then
|
||||||
|
vmf.throw_error(ERRORS.THROWABLE["active_missing_element"])
|
||||||
|
end
|
||||||
|
for level_name, value in pairs(active) do
|
||||||
|
if level_name ~= "inn" and level_name ~= "ingame" then
|
||||||
|
vmf.throw_error(ERRORS.THROWABLE["active_element_wrong_name"], level_name)
|
||||||
|
end
|
||||||
|
if type(value) ~= "boolean" then
|
||||||
|
vmf.throw_error(ERRORS.THROWABLE["active_element_wrong_type"], level_name, type(value))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local blocked_transitions = view_settings.blocked_transitions
|
||||||
|
if type(blocked_transitions) ~= "table" then
|
||||||
|
vmf.throw_error(ERRORS.THROWABLE["blocked_transitions_wrong_type"], type(blocked_transitions))
|
||||||
|
end
|
||||||
|
if not blocked_transitions.inn or not blocked_transitions.ingame then
|
||||||
|
vmf.throw_error(ERRORS.THROWABLE["blocked_transitions_missing_element"])
|
||||||
|
end
|
||||||
|
for level_name, level_blocked_transitions in pairs(blocked_transitions) do
|
||||||
|
if level_name ~= "inn" and level_name ~= "ingame" then
|
||||||
|
vmf.throw_error(ERRORS.THROWABLE["blocked_transitions_element_wrong_name"], level_name)
|
||||||
|
end
|
||||||
|
if type(level_blocked_transitions) ~= "table" then
|
||||||
|
vmf.throw_error(ERRORS.THROWABLE["blocked_transitions_element_wrong_type"], level_name,
|
||||||
|
type(level_blocked_transitions))
|
||||||
|
end
|
||||||
|
for transition_name, value in pairs(level_blocked_transitions) do
|
||||||
|
if not view_transitions[transition_name] then
|
||||||
|
vmf.throw_error(ERRORS.THROWABLE["blocked_transition_invalid"], transition_name, level_name)
|
||||||
|
end
|
||||||
|
if value ~= true then
|
||||||
|
vmf.throw_error(ERRORS.THROWABLE["blocked_transition_wrong_value"], level_name, transition_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local keybind_transitions = view_settings.keybind_transitions
|
||||||
|
if type(keybind_transitions) ~= "table" then
|
||||||
|
vmf.throw_error(ERRORS.THROWABLE["keybind_transitions_wrong_type"], type(keybind_transitions))
|
||||||
|
end
|
||||||
|
if keybind_transitions.open_view_transition and type(keybind_transitions.open_view_transition) ~= "string" then
|
||||||
|
vmf.throw_error(ERRORS.THROWABLE["open_view_transition_wrong_type"], type(keybind_transitions.open_view_transition))
|
||||||
|
end
|
||||||
|
if keybind_transitions.close_view_transition and type(keybind_transitions.close_view_transition) ~= "string" then
|
||||||
|
vmf.throw_error(ERRORS.THROWABLE["close_view_transition_wrong_type"],
|
||||||
|
type(keybind_transitions.close_view_transition))
|
||||||
|
end
|
||||||
|
if keybind_transitions.transition_fade and type(keybind_transitions.transition_fade) ~= "boolean" then
|
||||||
|
vmf.throw_error(ERRORS.THROWABLE["transition_fade_wrong_type"], type(keybind_transitions.transition_fade))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- #####################################################################################################################
|
||||||
|
-- ##### VMFMod ########################################################################################################
|
||||||
|
-- #####################################################################################################################
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Wraps ingame_ui transition handling calls in a lot of safety checks. Returns 'true', if call is successful.
|
||||||
|
* transition_name [string] : name of a transition that should be perfomed
|
||||||
|
* transition_params [anything]: parameter, which will be passed to callable transition function, 'on_exit' method of
|
||||||
|
the old view and 'on_enter' method of the new view
|
||||||
|
* fade [boolean] : if transition should be performed with fade
|
||||||
|
* ignore_active_menu [boolean] : if 'ingame_ui.menu_active' should be ignored
|
||||||
|
--]]
|
||||||
|
function VMFMod:handle_transition(transition_name, transition_params, fade, ignore_active_menu)
|
||||||
|
if vmf.check_wrong_argument_type(self, "handle_transition", "transition_name", transition_name, "string") then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if _ingame_ui
|
||||||
|
and not _ingame_ui:pending_transition()
|
||||||
|
and not _ingame_ui:end_screen_active()
|
||||||
|
and (not _ingame_ui.menu_active or ignore_active_menu)
|
||||||
|
and not _ingame_ui.leave_game
|
||||||
|
and not _ingame_ui.menu_suspended
|
||||||
|
and not _ingame_ui.return_to_title_screen
|
||||||
|
and (
|
||||||
|
VT1
|
||||||
|
and not _ingame_ui.popup_join_lobby_handler.visible
|
||||||
|
or not VT1
|
||||||
|
and not _ingame_ui.ingame_hud.ingame_player_list_ui:is_active()
|
||||||
|
and not Managers.transition:in_fade_active()
|
||||||
|
and not _ingame_ui:cutscene_active()
|
||||||
|
and not _ingame_ui:unavailable_hero_popup_active()
|
||||||
|
)
|
||||||
|
then
|
||||||
|
if fade then
|
||||||
|
vmf.safe_call_nr(self, ERRORS.PREFIX["handle_transition_fade"], _ingame_ui.transition_with_fade, _ingame_ui,
|
||||||
|
transition_name, transition_params)
|
||||||
|
else
|
||||||
|
vmf.safe_call_nr(self, ERRORS.PREFIX["handle_transition_no_fade"], _ingame_ui.handle_transition, _ingame_ui,
|
||||||
|
transition_name, transition_params)
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Opens a file with a view data and validates it. Registers the view and returns 'true' if everything is correct.
|
||||||
|
* view_data_file_path [string]: path to a file returning view_data table
|
||||||
|
--]]
|
||||||
|
function VMFMod:register_view(view_data_file_path)
|
||||||
|
local success, view_data = vmf.safe_call_dofile(self, {ERRORS.PREFIX["register_view_open_file"], view_data_file_path},
|
||||||
|
view_data_file_path)
|
||||||
|
if success then
|
||||||
|
if type(view_data) ~= "table" then
|
||||||
|
self:error(ERRORS.REGULAR["view_data_wrong_type"], view_data_file_path, type(view_data))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
view_data = table.clone(view_data)
|
||||||
|
else
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local view_name = view_data.view_name
|
||||||
|
|
||||||
|
if not vmf.safe_call_nrc(self, {ERRORS.PREFIX["register_view_validating"], view_name}, validate_view_data,
|
||||||
|
view_data) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
_views_data[view_name] = {
|
||||||
|
mod = self,
|
||||||
|
view_settings = view_data.view_settings,
|
||||||
|
view_transitions = view_data.view_transitions
|
||||||
|
}
|
||||||
|
|
||||||
|
if _ingame_ui then
|
||||||
|
if not vmf.safe_call_nrc(self, {ERRORS.PREFIX["register_view_injection"], view_name}, inject_view, view_name) then
|
||||||
|
_views_data[view_data.view_name] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- #####################################################################################################################
|
||||||
|
-- ##### Hooks #########################################################################################################
|
||||||
|
-- #####################################################################################################################
|
||||||
|
|
||||||
|
vmf:hook_safe(IngameUI, "init", function(self)
|
||||||
|
_ingame_ui = self
|
||||||
|
for view_name, _ in pairs(_views_data) do
|
||||||
|
if not vmf.safe_call_nrc(self, {ERRORS.PREFIX["ingameui_hook_injection"], view_name}, inject_view, view_name) then
|
||||||
|
_views_data[view_name] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
vmf:hook_safe(IngameUI, "destroy", function()
|
||||||
|
remove_injected_views(false)
|
||||||
|
_ingame_ui = nil
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- #####################################################################################################################
|
||||||
|
-- ##### VMF internal functions and variables ##########################################################################
|
||||||
|
-- #####################################################################################################################
|
||||||
|
|
||||||
|
function vmf.remove_custom_views()
|
||||||
|
remove_injected_views(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Opens/closes a view if all conditions are met. Since keybinds module can't do UI-related checks, all the cheks are
|
||||||
|
-- done in this function. This function is called every time some view-toggling keybind is pressed.
|
||||||
|
function vmf.keybind_toggle_view(mod, view_name, can_be_opened, is_keybind_pressed)
|
||||||
|
if _ingame_ui then
|
||||||
|
if not _views_data[view_name] or (_views_data[view_name].mod ~= mod) then
|
||||||
|
mod:error(ERRORS.REGULAR["view_not_registered"], view_name)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if is_view_active_for_current_level(view_name) then
|
||||||
|
local keybind_transitions = _views_data[view_name].view_settings.keybind_transitions
|
||||||
|
if _ingame_ui.current_view == view_name then
|
||||||
|
if keybind_transitions.close_view_transition then
|
||||||
|
mod:handle_transition(keybind_transitions.close_view_transition,
|
||||||
|
keybind_transitions.close_view_transition_params,
|
||||||
|
keybind_transitions.transition_fade, true)
|
||||||
|
end
|
||||||
|
-- Can open views only when keybind is pressed.
|
||||||
|
elseif can_be_opened and is_keybind_pressed then
|
||||||
|
if keybind_transitions.open_view_transition then
|
||||||
|
mod:handle_transition(keybind_transitions.open_view_transition,
|
||||||
|
keybind_transitions.close_view_transition_params,
|
||||||
|
keybind_transitions.transition_fade, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- #####################################################################################################################
|
||||||
|
-- ##### Script ########################################################################################################
|
||||||
|
-- #####################################################################################################################
|
||||||
|
|
||||||
|
-- If VMF is reloaded mid-game, get ingame_ui.
|
||||||
|
local ingame_ui_exists, ingame_ui_return
|
||||||
|
if VT1 then
|
||||||
|
ingame_ui_exists, ingame_ui_return = pcall(function()
|
||||||
|
return Managers.player.network_manager.matchmaking_manager.matchmaking_ui.ingame_ui
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
ingame_ui_exists, ingame_ui_return = pcall(function()
|
||||||
|
return Managers.player.network_manager.matchmaking_manager._ingame_ui
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
if ingame_ui_exists then
|
||||||
|
_ingame_ui = ingame_ui_return
|
||||||
|
end
|
|
@ -94,9 +94,25 @@ vmf.initialize_mod_options_legacy = function (mod, widgets_definition)
|
||||||
end
|
end
|
||||||
|
|
||||||
if current_widget.widget_type == "keybind" then
|
if current_widget.widget_type == "keybind" then
|
||||||
|
new_widget_definition.keybind_trigger = "pressed"
|
||||||
|
if current_widget.action == "toggle_mod_state" then
|
||||||
|
new_widget_definition.keybind_type = "mod_toggle"
|
||||||
|
new_widget_definition.function_name = nil
|
||||||
|
else
|
||||||
|
new_widget_definition.keybind_type = "function_call"
|
||||||
|
end
|
||||||
|
|
||||||
local keybind = mod:get(current_widget.setting_name)
|
local keybind = mod:get(current_widget.setting_name)
|
||||||
if current_widget.action then
|
if current_widget.action then
|
||||||
mod:keybind(current_widget.setting_name, current_widget.action, keybind)
|
vmf.add_mod_keybind(
|
||||||
|
mod,
|
||||||
|
new_widget_definition.setting_id,
|
||||||
|
nil,
|
||||||
|
new_widget_definition.keybind_trigger,
|
||||||
|
new_widget_definition.keybind_type,
|
||||||
|
keybind,
|
||||||
|
new_widget_definition.function_name
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
126
vmf/scripts/mods/vmf/modules/ui/options/mod_options.lua
Normal file
126
vmf/scripts/mods/vmf/modules/ui/options/mod_options.lua
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
local vmf = get_mod("VMF")
|
||||||
|
|
||||||
|
local _button_injection_data = vmf:persistent_table("button_injection_data")
|
||||||
|
|
||||||
|
|
||||||
|
if VT1 then
|
||||||
|
|
||||||
|
|
||||||
|
-- Disable Mod Options button during mods reloading
|
||||||
|
vmf:hook_safe(IngameView, "update_menu_options", function (self)
|
||||||
|
for _, button_info in ipairs(self.active_button_data) do
|
||||||
|
if button_info.transition == "vmf_options_view" then
|
||||||
|
button_info.widget.content.disabled = _button_injection_data.mod_options_button_disabled
|
||||||
|
button_info.widget.content.button_hotspot.disabled = _button_injection_data.mod_options_button_disabled
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
-- Inject Mod Options button in current ESC-menu layout
|
||||||
|
-- Disable localization for button widget
|
||||||
|
vmf:hook(IngameView, "setup_button_layout", function (func, self, layout_data, ...)
|
||||||
|
local mods_options_button = {
|
||||||
|
display_name = vmf:localize("mods_options"),
|
||||||
|
transition = "vmf_options_view",
|
||||||
|
fade = false
|
||||||
|
}
|
||||||
|
for i = 1, #layout_data do
|
||||||
|
if layout_data[i].transition == "options_menu" and layout_data[i + 1].transition ~= "vmf_options_view" then
|
||||||
|
table.insert(layout_data, i + 1, mods_options_button)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
func(self, layout_data, ...)
|
||||||
|
|
||||||
|
for _, button_info in ipairs(self.active_button_data) do
|
||||||
|
if button_info.transition == "vmf_options_view" then
|
||||||
|
button_info.widget.style.text.localize = false
|
||||||
|
button_info.widget.style.text_disabled.localize = false
|
||||||
|
button_info.widget.style.text_click.localize = false
|
||||||
|
button_info.widget.style.text_hover.localize = false
|
||||||
|
button_info.widget.style.text_selected.localize = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
|
||||||
|
local function get_mod_options_button_index(layout_logic)
|
||||||
|
for button_index, button_data in ipairs(layout_logic.active_button_data) do
|
||||||
|
if button_data.transition == "vmf_options_view" then
|
||||||
|
return button_index
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Disable localization for Mod Options button widget for pc version of ESC-menu
|
||||||
|
-- Widget definition: ingame_view_definitions.lua -> UIWidgets.create_default_button
|
||||||
|
vmf:hook_safe(IngameView, "on_enter", function (self)
|
||||||
|
self.layout_logic._ingame_view = self
|
||||||
|
end)
|
||||||
|
vmf:hook_safe(IngameViewLayoutLogic, "setup_button_layout", function (self)
|
||||||
|
if self._ingame_view then
|
||||||
|
local mod_options_button_index = get_mod_options_button_index(self)
|
||||||
|
local button_widget = self._ingame_view.stored_buttons[mod_options_button_index]
|
||||||
|
button_widget.style.title_text.localize = false
|
||||||
|
button_widget.style.title_text_shadow.localize = false
|
||||||
|
button_widget.style.title_text_disabled.localize = false
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
-- Disable localization for Mod Options button widget for console version of ESC-menu
|
||||||
|
-- Widget definition: hero_window_ingame_view_definitions.lua -> create_title_button
|
||||||
|
vmf:hook_safe(HeroWindowIngameView, "on_enter", function (self)
|
||||||
|
local button_widget = self._title_button_widgets[get_mod_options_button_index(self.layout_logic)]
|
||||||
|
button_widget.style.text.localize = false
|
||||||
|
button_widget.style.text_hover.localize = false
|
||||||
|
button_widget.style.text_shadow.localize = false
|
||||||
|
button_widget.style.text_disabled.localize = false
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
-- Disable Mod Options button during mods reloading
|
||||||
|
vmf:hook_safe(IngameViewLayoutLogic, "_update_menu_options_enabled_states", function (self)
|
||||||
|
local mod_options_button_index = get_mod_options_button_index(self)
|
||||||
|
local mod_options_button_data = self.active_button_data[mod_options_button_index]
|
||||||
|
mod_options_button_data.disabled = _button_injection_data.mod_options_button_disabled
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
-- Inject Mod Options button in all possible ESC-menu layouts (except for developer's one, because it will increase
|
||||||
|
-- the number of buttons to 10, when the hard limit is 9, which will crash the game)
|
||||||
|
vmf:hook_safe(IngameViewLayoutLogic, "init", function (self)
|
||||||
|
local mod_options_button = {
|
||||||
|
display_name = vmf:localize("mods_options"),
|
||||||
|
transition = "vmf_options_view",
|
||||||
|
fade = false
|
||||||
|
}
|
||||||
|
for _, layout in pairs(self.layout_list) do
|
||||||
|
for i = 1, #layout do
|
||||||
|
if layout[i].transition == "options_menu" and layout[i + 1].transition ~= "vmf_options_view" then
|
||||||
|
table.insert(layout, i + 1, mod_options_button)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
vmf.initialize_vmf_options_view = function ()
|
||||||
|
vmf:register_view("scripts/mods/vmf/modules/ui/options/vmf_options_view")
|
||||||
|
_button_injection_data.mod_options_button_disabled = false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
vmf.disable_mods_options_button = function ()
|
||||||
|
_button_injection_data.mod_options_button_disabled = true
|
||||||
|
end
|
|
@ -2482,22 +2482,6 @@ end
|
||||||
-- ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═════╝ ╚═╝╚═╝ ╚═══╝╚═════╝
|
-- ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═════╝ ╚═╝╚═╝ ╚═══╝╚═════╝
|
||||||
|
|
||||||
|
|
||||||
local function build_keybind_string(keys)
|
|
||||||
|
|
||||||
local keybind_string = ""
|
|
||||||
|
|
||||||
for i, key in ipairs(keys) do
|
|
||||||
if i == 1 then
|
|
||||||
keybind_string = keybind_string .. vmf.readable_key_names[key]
|
|
||||||
else
|
|
||||||
keybind_string = keybind_string .. " + " .. vmf.readable_key_names[key]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return keybind_string
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function create_keybind_widget(widget_definition, scenegraph_id)
|
local function create_keybind_widget(widget_definition, scenegraph_id)
|
||||||
|
|
||||||
local widget_size = SETTINGS_LIST_REGULAR_WIDGET_SIZE
|
local widget_size = SETTINGS_LIST_REGULAR_WIDGET_SIZE
|
||||||
|
@ -2654,7 +2638,12 @@ local function create_keybind_widget(widget_definition, scenegraph_id)
|
||||||
setting_id = widget_definition.setting_id,
|
setting_id = widget_definition.setting_id,
|
||||||
widget_type = widget_definition.type,
|
widget_type = widget_definition.type,
|
||||||
|
|
||||||
action = widget_definition.function_name,
|
keybind_global = widget_definition.keybind_global,
|
||||||
|
keybind_trigger = widget_definition.keybind_trigger,
|
||||||
|
keybind_type = widget_definition.keybind_type,
|
||||||
|
function_name = widget_definition.function_name,
|
||||||
|
view_name = widget_definition.view_name,
|
||||||
|
|
||||||
keybind_text = widget_definition.keybind_text,
|
keybind_text = widget_definition.keybind_text,
|
||||||
default_value = widget_definition.default_value,
|
default_value = widget_definition.default_value,
|
||||||
parent_widget_number = widget_definition.parent_index,
|
parent_widget_number = widget_definition.parent_index,
|
||||||
|
@ -3302,97 +3291,76 @@ VMFOptionsView.callback_change_setting_keybind_state = function (self, widget_co
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function set_new_keybind(keybind_widget_content)
|
||||||
VMFOptionsView.callback_setting_keybind = function (self, widget_content)
|
vmf.add_mod_keybind(
|
||||||
|
get_mod(keybind_widget_content.mod_name),
|
||||||
if not widget_content.first_pressed_button and (Keyboard.any_pressed() or Mouse.any_pressed()) then
|
keybind_widget_content.setting_id,
|
||||||
|
keybind_widget_content.keybind_global,
|
||||||
local first_pressed_button_info = nil
|
keybind_widget_content.keybind_trigger,
|
||||||
local first_pressed_button_index = nil
|
keybind_widget_content.keybind_type,
|
||||||
local first_pressed_button_type = nil
|
keybind_widget_content.keys,
|
||||||
|
keybind_widget_content.function_name,
|
||||||
if Keyboard.any_pressed() then
|
keybind_widget_content.view_name
|
||||||
|
)
|
||||||
first_pressed_button_info = vmf.keys.keyboard[Keyboard.any_pressed()]
|
|
||||||
first_pressed_button_index = Keyboard.any_pressed()
|
|
||||||
first_pressed_button_type = "keyboard"
|
|
||||||
|
|
||||||
elseif Mouse.any_pressed() then
|
|
||||||
|
|
||||||
first_pressed_button_info = vmf.keys.mouse[Mouse.any_pressed()]
|
|
||||||
first_pressed_button_index = Mouse.any_pressed()
|
|
||||||
first_pressed_button_type = "mouse"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if first_pressed_button_info then
|
VMFOptionsView.callback_setting_keybind = function (self, widget_content)
|
||||||
widget_content.first_pressed_button = first_pressed_button_info[2]
|
if not widget_content.first_pressed_button_id then
|
||||||
widget_content.first_pressed_button_index = first_pressed_button_index
|
if Keyboard.any_pressed() then
|
||||||
widget_content.first_pressed_button_type = first_pressed_button_type
|
widget_content.first_pressed_button_id = vmf.get_key_id("KEYBOARD", Keyboard.any_pressed())
|
||||||
|
widget_content.first_pressed_button_index = Keyboard.any_pressed()
|
||||||
|
widget_content.first_pressed_button_type = "keyboard"
|
||||||
|
elseif Mouse.any_pressed() then
|
||||||
|
widget_content.first_pressed_button_id = vmf.get_key_id("MOUSE", Mouse.any_pressed())
|
||||||
|
widget_content.first_pressed_button_index = Mouse.any_pressed()
|
||||||
|
widget_content.first_pressed_button_type = "mouse"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local pressed_buttons = {}
|
local pressed_buttons = {}
|
||||||
local preview_string = ""
|
if widget_content.first_pressed_button_id then
|
||||||
|
table.insert(pressed_buttons, widget_content.first_pressed_button_id)
|
||||||
if widget_content.first_pressed_button then
|
else
|
||||||
table.insert(pressed_buttons, widget_content.first_pressed_button)
|
table.insert(pressed_buttons, "no_button")
|
||||||
preview_string = vmf.readable_key_names[widget_content.first_pressed_button]
|
|
||||||
end
|
end
|
||||||
if Keyboard.button(Keyboard.button_index("left ctrl")) == 1 then
|
if Keyboard.button(Keyboard.button_index("left ctrl")) + Keyboard.button(Keyboard.button_index("right ctrl")) > 0 then
|
||||||
preview_string = preview_string .. " + Ctrl"
|
|
||||||
table.insert(pressed_buttons, "ctrl")
|
table.insert(pressed_buttons, "ctrl")
|
||||||
end
|
end
|
||||||
if Keyboard.button(Keyboard.button_index("left alt")) == 1 then
|
if Keyboard.button(Keyboard.button_index("left alt")) + Keyboard.button(Keyboard.button_index("right alt")) > 0 then
|
||||||
preview_string = preview_string .. " + Alt"
|
|
||||||
table.insert(pressed_buttons, "alt")
|
table.insert(pressed_buttons, "alt")
|
||||||
end
|
end
|
||||||
if Keyboard.button(Keyboard.button_index("left shift")) == 1 then
|
if Keyboard.button(Keyboard.button_index("left shift")) + Keyboard.button(Keyboard.button_index("right shift")) > 0 then
|
||||||
preview_string = preview_string .. " + Shift"
|
|
||||||
table.insert(pressed_buttons, "shift")
|
table.insert(pressed_buttons, "shift")
|
||||||
end
|
end
|
||||||
|
|
||||||
if preview_string ~= "" then
|
local preview_string = vmf.build_keybind_string(pressed_buttons)
|
||||||
|
|
||||||
|
widget_content.keybind_text = preview_string ~= "" and preview_string or "_"
|
||||||
widget_content.keys = pressed_buttons
|
widget_content.keys = pressed_buttons
|
||||||
widget_content.keybind_text = preview_string
|
|
||||||
else
|
|
||||||
widget_content.keybind_text = "_"
|
|
||||||
end
|
|
||||||
|
|
||||||
if widget_content.first_pressed_button then
|
if widget_content.first_pressed_button_id then
|
||||||
if (widget_content.first_pressed_button_type == "keyboard" and Keyboard.released(widget_content.first_pressed_button_index) or
|
if widget_content.first_pressed_button_type == "keyboard" and Keyboard.released(widget_content.first_pressed_button_index) or
|
||||||
widget_content.first_pressed_button_type == "mouse" and Mouse.released(widget_content.first_pressed_button_index)) then
|
widget_content.first_pressed_button_type == "mouse" and Mouse.released(widget_content.first_pressed_button_index)
|
||||||
|
then
|
||||||
widget_content.keybind_text = build_keybind_string(widget_content.keys)
|
widget_content.first_pressed_button_id = nil
|
||||||
|
|
||||||
widget_content.first_pressed_button = nil
|
|
||||||
widget_content.first_pressed_button_index = nil
|
widget_content.first_pressed_button_index = nil
|
||||||
widget_content.first_pressed_button_type = nil
|
widget_content.first_pressed_button_type = nil
|
||||||
|
|
||||||
if widget_content.action then
|
set_new_keybind(widget_content)
|
||||||
get_mod(widget_content.mod_name):keybind(widget_content.setting_id, widget_content.action, widget_content.keys)
|
|
||||||
end
|
|
||||||
|
|
||||||
self:callback_change_setting_keybind_state(widget_content)
|
self:callback_change_setting_keybind_state(widget_content)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
else
|
elseif Keyboard.released(Keyboard.button_index("esc")) then
|
||||||
if Keyboard.released(Keyboard.button_index("esc")) then
|
widget_content.keybind_text = ""
|
||||||
|
|
||||||
widget_content.keys = {}
|
widget_content.keys = {}
|
||||||
|
|
||||||
widget_content.keybind_text = build_keybind_string(widget_content.keys)
|
set_new_keybind(widget_content)
|
||||||
|
|
||||||
if widget_content.action then
|
|
||||||
get_mod(widget_content.mod_name):keybind(widget_content.setting_id, widget_content.action, widget_content.keys)
|
|
||||||
end
|
|
||||||
|
|
||||||
self:callback_change_setting_keybind_state(widget_content)
|
self:callback_change_setting_keybind_state(widget_content)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
VMFOptionsView.callback_change_dropdown_menu_visibility = function (self, widget_content)
|
VMFOptionsView.callback_change_dropdown_menu_visibility = function (self, widget_content)
|
||||||
|
@ -3867,7 +3835,7 @@ VMFOptionsView.update_picked_option_for_settings_list_widgets = function (self)
|
||||||
widget_content.keys = widget_content.default_value
|
widget_content.keys = widget_content.default_value
|
||||||
end
|
end
|
||||||
|
|
||||||
widget_content.keybind_text = build_keybind_string(widget_content.keys)
|
widget_content.keybind_text = vmf.build_keybind_string(widget_content.keys)
|
||||||
|
|
||||||
elseif widget_type == "numeric" then
|
elseif widget_type == "numeric" then
|
||||||
|
|
||||||
|
@ -4309,7 +4277,7 @@ vmf.load_vmf_options_view_settings()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local view_data = {
|
return {
|
||||||
view_name = "vmf_options_view",
|
view_name = "vmf_options_view",
|
||||||
view_settings = {
|
view_settings = {
|
||||||
init_view_function = function (ingame_ui_context)
|
init_view_function = function (ingame_ui_context)
|
||||||
|
@ -4319,160 +4287,15 @@ local view_data = {
|
||||||
inn = true,
|
inn = true,
|
||||||
ingame = true
|
ingame = true
|
||||||
},
|
},
|
||||||
blocked_transitions = {
|
keybind_transitions = {
|
||||||
inn = {},
|
open_view_transition = "vmf_options_view",
|
||||||
ingame = {
|
close_view_transition = "exit_menu",
|
||||||
--vmf_options_view = true,
|
|
||||||
--vmf_options_view_force = true
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
hotkey_name = "open_vmf_options",
|
|
||||||
hotkey_action_name = "open_vmf_options",
|
|
||||||
hotkey_transition_name = "vmf_options_view",
|
|
||||||
transition_fade = false
|
|
||||||
},
|
|
||||||
view_transitions = {
|
view_transitions = {
|
||||||
|
|
||||||
vmf_options_view = function (self)
|
vmf_options_view = function (self)
|
||||||
self.current_view = "vmf_options_view"
|
self.current_view = "vmf_options_view"
|
||||||
|
self.menu_active = true
|
||||||
return
|
|
||||||
end,
|
|
||||||
|
|
||||||
vmf_options_view_force = function (self)
|
|
||||||
|
|
||||||
ShowCursorStack.push()
|
|
||||||
|
|
||||||
self.current_view = "vmf_options_view"
|
|
||||||
|
|
||||||
self.views[self.current_view].exit_to_game = true -- why?
|
|
||||||
return
|
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
local _button_injection_data = vmf:persistent_table("button_injection_data")
|
|
||||||
|
|
||||||
|
|
||||||
if VT1 then
|
|
||||||
|
|
||||||
|
|
||||||
-- Disable Mod Options button during mods reloading
|
|
||||||
vmf:hook_safe(IngameView, "update_menu_options", function (self)
|
|
||||||
for _, button_info in ipairs(self.active_button_data) do
|
|
||||||
if button_info.transition == "vmf_options_view" then
|
|
||||||
button_info.widget.content.disabled = _button_injection_data.mod_options_button_disabled
|
|
||||||
button_info.widget.content.button_hotspot.disabled = _button_injection_data.mod_options_button_disabled
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
|
|
||||||
-- Inject Mod Options button in current ESC-menu layout
|
|
||||||
-- Disable localization for button widget
|
|
||||||
vmf:hook(IngameView, "setup_button_layout", function (func, self, layout_data, ...)
|
|
||||||
local mods_options_button = {
|
|
||||||
display_name = vmf:localize("mods_options"),
|
|
||||||
transition = "vmf_options_view",
|
|
||||||
fade = false
|
|
||||||
}
|
|
||||||
for i = 1, #layout_data do
|
|
||||||
if layout_data[i].transition == "options_menu" and layout_data[i + 1].transition ~= "vmf_options_view" then
|
|
||||||
table.insert(layout_data, i + 1, mods_options_button)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
func(self, layout_data, ...)
|
|
||||||
|
|
||||||
for _, button_info in ipairs(self.active_button_data) do
|
|
||||||
if button_info.transition == "vmf_options_view" then
|
|
||||||
button_info.widget.style.text.localize = false
|
|
||||||
button_info.widget.style.text_disabled.localize = false
|
|
||||||
button_info.widget.style.text_click.localize = false
|
|
||||||
button_info.widget.style.text_hover.localize = false
|
|
||||||
button_info.widget.style.text_selected.localize = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
|
|
||||||
local function get_mod_options_button_index(layout_logic)
|
|
||||||
for button_index, button_data in ipairs(layout_logic.active_button_data) do
|
|
||||||
if button_data.transition == "vmf_options_view" then
|
|
||||||
return button_index
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- Disable localization for Mod Options button widget for pc version of ESC-menu
|
|
||||||
-- Widget definition: ingame_view_definitions.lua -> UIWidgets.create_default_button
|
|
||||||
vmf:hook_safe(IngameView, "on_enter", function (self)
|
|
||||||
self.layout_logic._ingame_view = self
|
|
||||||
end)
|
|
||||||
vmf:hook_safe(IngameViewLayoutLogic, "setup_button_layout", function (self)
|
|
||||||
if self._ingame_view then
|
|
||||||
local mod_options_button_index = get_mod_options_button_index(self)
|
|
||||||
local button_widget = self._ingame_view.stored_buttons[mod_options_button_index]
|
|
||||||
button_widget.style.title_text.localize = false
|
|
||||||
button_widget.style.title_text_shadow.localize = false
|
|
||||||
button_widget.style.title_text_disabled.localize = false
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
|
|
||||||
-- Disable localization for Mod Options button widget for console version of ESC-menu
|
|
||||||
-- Widget definition: hero_window_ingame_view_definitions.lua -> create_title_button
|
|
||||||
vmf:hook_safe(HeroWindowIngameView, "on_enter", function (self)
|
|
||||||
local button_widget = self._title_button_widgets[get_mod_options_button_index(self.layout_logic)]
|
|
||||||
button_widget.style.text.localize = false
|
|
||||||
button_widget.style.text_hover.localize = false
|
|
||||||
button_widget.style.text_shadow.localize = false
|
|
||||||
button_widget.style.text_disabled.localize = false
|
|
||||||
end)
|
|
||||||
|
|
||||||
|
|
||||||
-- Disable Mod Options button during mods reloading
|
|
||||||
vmf:hook_safe(IngameViewLayoutLogic, "_update_menu_options_enabled_states", function (self)
|
|
||||||
local mod_options_button_index = get_mod_options_button_index(self)
|
|
||||||
local mod_options_button_data = self.active_button_data[mod_options_button_index]
|
|
||||||
mod_options_button_data.disabled = _button_injection_data.mod_options_button_disabled
|
|
||||||
end)
|
|
||||||
|
|
||||||
|
|
||||||
-- Inject Mod Options button in all possible ESC-menu layouts (except for developer's one, because it will increase
|
|
||||||
-- the number of buttons to 10, when the hard limit is 9, which will crash the game)
|
|
||||||
vmf:hook_safe(IngameViewLayoutLogic, "init", function (self)
|
|
||||||
local mod_options_button = {
|
|
||||||
display_name = vmf:localize("mods_options"),
|
|
||||||
transition = "vmf_options_view",
|
|
||||||
fade = false
|
|
||||||
}
|
|
||||||
for _, layout in pairs(self.layout_list) do
|
|
||||||
for i = 1, #layout do
|
|
||||||
if layout[i].transition == "options_menu" and layout[i + 1].transition ~= "vmf_options_view" then
|
|
||||||
table.insert(layout, i + 1, mod_options_button)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
vmf.initialize_vmf_options_view = function ()
|
|
||||||
vmf:register_new_view(view_data)
|
|
||||||
_button_injection_data.mod_options_button_disabled = false
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
vmf.disable_mods_options_button = function ()
|
|
||||||
_button_injection_data.mod_options_button_disabled = true
|
|
||||||
end
|
|
|
@ -53,7 +53,7 @@ function new_mod(mod_name, mod_resources)
|
||||||
|
|
||||||
-- Load localization data file
|
-- Load localization data file
|
||||||
if mod_resources.mod_localization then
|
if mod_resources.mod_localization then
|
||||||
local success, localization_table = vmf.xpcall_dofile(mod, "(new_mod)('mod_localization' initialization)",
|
local success, localization_table = vmf.safe_call_dofile(mod, "(new_mod)('mod_localization' initialization)",
|
||||||
mod_resources.mod_localization)
|
mod_resources.mod_localization)
|
||||||
if success then
|
if success then
|
||||||
vmf.load_mod_localization(mod, localization_table) -- @TODO: return here if not sucessful? rename to "initialize_"
|
vmf.load_mod_localization(mod, localization_table) -- @TODO: return here if not sucessful? rename to "initialize_"
|
||||||
|
@ -64,7 +64,7 @@ function new_mod(mod_name, mod_resources)
|
||||||
|
|
||||||
-- Load mod data file
|
-- Load mod data file
|
||||||
if mod_resources.mod_data then
|
if mod_resources.mod_data then
|
||||||
local success, mod_data_table = vmf.xpcall_dofile(mod, "(new_mod)('mod_data' initialization)",
|
local success, mod_data_table = vmf.safe_call_dofile(mod, "(new_mod)('mod_data' initialization)",
|
||||||
mod_resources.mod_data)
|
mod_resources.mod_data)
|
||||||
if success and not vmf.initialize_mod_data(mod, mod_data_table) then
|
if success and not vmf.initialize_mod_data(mod, mod_data_table) then
|
||||||
return
|
return
|
||||||
|
@ -72,7 +72,7 @@ function new_mod(mod_name, mod_resources)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Load mod @TODO: what will happen if mod_resources.mod_script == nil?
|
-- Load mod @TODO: what will happen if mod_resources.mod_script == nil?
|
||||||
if not vmf.xpcall_dofile(mod, "(new_mod)('mod_script' initialization)", mod_resources.mod_script) then
|
if not vmf.safe_call_dofile(mod, "(new_mod)('mod_script' initialization)", mod_resources.mod_script) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,8 @@ vmf_mod_data.options = {
|
||||||
type = "keybind",
|
type = "keybind",
|
||||||
default_value = {"f4"},
|
default_value = {"f4"},
|
||||||
keybind_trigger = "pressed",
|
keybind_trigger = "pressed",
|
||||||
keybind_type = "function_call",
|
keybind_type = "view_toggle",
|
||||||
function_name = "open_vmf_options"
|
view_name = "vmf_options_view"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
setting_id = "vmf_options_scrolling_speed",
|
setting_id = "vmf_options_scrolling_speed",
|
||||||
|
@ -38,6 +38,7 @@ vmf_mod_data.options = {
|
||||||
setting_id = "toggle_developer_console",
|
setting_id = "toggle_developer_console",
|
||||||
type = "keybind",
|
type = "keybind",
|
||||||
default_value = {},
|
default_value = {},
|
||||||
|
keybind_global = true,
|
||||||
keybind_trigger = "pressed",
|
keybind_trigger = "pressed",
|
||||||
keybind_type = "function_call",
|
keybind_type = "function_call",
|
||||||
function_name = "toggle_developer_console"
|
function_name = "toggle_developer_console"
|
||||||
|
@ -239,7 +240,7 @@ if not vmf:get("vmf_initialized") then
|
||||||
vmf.load_dev_console_settings()
|
vmf.load_dev_console_settings()
|
||||||
vmf.load_chat_history_settings()
|
vmf.load_chat_history_settings()
|
||||||
vmf.load_ui_scaling_settings()
|
vmf.load_ui_scaling_settings()
|
||||||
vmf.load_vmf_options_view_settings()
|
--vmf.load_vmf_options_view_settings()
|
||||||
|
|
||||||
vmf:set("vmf_initialized", true)
|
vmf:set("vmf_initialized", true)
|
||||||
end
|
end
|
|
@ -31,10 +31,10 @@ function vmf_mod_object:init()
|
||||||
dofile("scripts/mods/vmf/modules/core/network")
|
dofile("scripts/mods/vmf/modules/core/network")
|
||||||
dofile("scripts/mods/vmf/modules/core/commands")
|
dofile("scripts/mods/vmf/modules/core/commands")
|
||||||
dofile("scripts/mods/vmf/modules/gui/custom_textures")
|
dofile("scripts/mods/vmf/modules/gui/custom_textures")
|
||||||
dofile("scripts/mods/vmf/modules/gui/custom_menus")
|
dofile("scripts/mods/vmf/modules/gui/custom_views")
|
||||||
dofile("scripts/mods/vmf/modules/gui/ui_scaling")
|
dofile("scripts/mods/vmf/modules/gui/ui_scaling")
|
||||||
dofile("scripts/mods/vmf/modules/ui/chat/chat_actions")
|
dofile("scripts/mods/vmf/modules/ui/chat/chat_actions")
|
||||||
dofile("scripts/mods/vmf/modules/ui/options/vmf_options_view")
|
dofile("scripts/mods/vmf/modules/ui/options/mod_options")
|
||||||
dofile("scripts/mods/vmf/modules/vmf_options")
|
dofile("scripts/mods/vmf/modules/vmf_options")
|
||||||
|
|
||||||
if VT1 then
|
if VT1 then
|
||||||
|
@ -56,14 +56,13 @@ end
|
||||||
|
|
||||||
function vmf_mod_object:update(dt)
|
function vmf_mod_object:update(dt)
|
||||||
vmf.mods_update_event(dt)
|
vmf.mods_update_event(dt)
|
||||||
vmf.check_pressed_keybinds()
|
vmf.check_keybinds()
|
||||||
vmf.check_custom_menus_close_keybinds(dt)
|
|
||||||
vmf.execute_queued_chat_command()
|
vmf.execute_queued_chat_command()
|
||||||
if VT1 then vmf.check_mutators_state() end
|
if VT1 then vmf.check_mutators_state() end
|
||||||
|
|
||||||
if not vmf.all_mods_were_loaded and Managers.mod._state == "done" then
|
if not vmf.all_mods_were_loaded and Managers.mod._state == "done" then
|
||||||
|
|
||||||
vmf.initialize_keybinds()
|
vmf.generate_keybinds()
|
||||||
vmf.initialize_vmf_options_view()
|
vmf.initialize_vmf_options_view()
|
||||||
vmf.create_network_dictionary()
|
vmf.create_network_dictionary()
|
||||||
vmf.ping_vmf_users()
|
vmf.ping_vmf_users()
|
||||||
|
@ -88,10 +87,9 @@ end
|
||||||
function vmf_mod_object:on_reload()
|
function vmf_mod_object:on_reload()
|
||||||
print("VMF:ON_RELOAD()")
|
print("VMF:ON_RELOAD()")
|
||||||
vmf.disable_mods_options_button()
|
vmf.disable_mods_options_button()
|
||||||
vmf.close_opened_custom_menus()
|
|
||||||
if VT1 then vmf.reset_map_view() end
|
if VT1 then vmf.reset_map_view() end
|
||||||
vmf.delete_keybinds()
|
|
||||||
vmf.mods_unload_event(false)
|
vmf.mods_unload_event(false)
|
||||||
|
vmf.remove_custom_views()
|
||||||
vmf.hooks_unload()
|
vmf.hooks_unload()
|
||||||
vmf.reset_guis()
|
vmf.reset_guis()
|
||||||
end
|
end
|
||||||
|
@ -105,7 +103,7 @@ function vmf_mod_object:on_game_state_changed(status, state)
|
||||||
vmf.apply_delayed_hooks(status, state)
|
vmf.apply_delayed_hooks(status, state)
|
||||||
|
|
||||||
if status == "enter" and state == "StateIngame" then
|
if status == "enter" and state == "StateIngame" then
|
||||||
vmf.initialize_keybinds()
|
vmf.create_keybinds_input_service()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue