Lots of stuff

Chat actions
Some fixes and improvements
Some refactoring
This commit is contained in:
Unknown 2018-03-26 13:24:28 +03:00
parent d1cdad8553
commit 6886e74fc9
24 changed files with 981 additions and 176 deletions

View file

@ -36,10 +36,12 @@ return {
ru = "Консоль разработчика", ru = "Консоль разработчика",
}, },
show_developer_console_tooltip = { show_developer_console_tooltip = {
en = "Opens up the new window showing game log in real time.\n\n" .. en = "Opens up the new window showing game log in real time.",
"In order to safely close this window, disable it from the menu options first, and then close the window.", ru = "Открывает новое окно, в которое в реальном времени выводится игровой лог.",
ru = "Открывает новое окно, в которое в реальном времени выводится игровой лог.\n\n" .. },
"Чтобы его закрыть, сначала выключите консоль из меню настроек, и потом закройте вручную.", toggle_developer_console = {
en = "Toggle Developer Console",
ru = "Открыть/закрыть консоль разработчика",
}, },
show_network_debug_info = { show_network_debug_info = {
en = "Log Network Calls", en = "Log Network Calls",
@ -109,4 +111,80 @@ return {
en = "Log & Chat", en = "Log & Chat",
ru = "Лог и чат", ru = "Лог и чат",
}, },
chat_history_enable = {
en = "Chat Input History",
ru = "История ввода чата",
},
chat_history_enable_tooltip = {
en = "Saves all the messages and commands you typed in the chat window.\n\n" ..
"You can browse your input history by opening the chat and pressing \"Arrow Up\" and \"Arrow Down\".",
ru = "Сохраняет все сообщения и команды, введённые в чате.\n\n" ..
"Чтобы пролистывать историю ввода, откройте чат и используйте клавиши \"стрелка вверх\" и \"стрелка вниз\".",
},
chat_history_save = {
en = "Save Input History Between Game Sessions",
ru = "Сохранять историю ввода между сеансами игры",
},
chat_history_save_tooltip = {
en = "Your chat input history will be saved even after reloading your game (or just VMF).",
ru = "Когда игрок выключает игру (или перезагружает VMF), VMF cохраняет историю ввода в файл настроек, чтобы загрузить её при следующем запуске игры.",
},
chat_history_buffer_size = {
en = "Input History Buffer Size",
ru = "Размер буфера истории ввода",
},
chat_history_buffer_size_tooltip = {
en = "Maximum number of saved entries.\n\n" ..
"WARNING: Changing this setting will erase your chat history.",
ru = "Максимальное количество сохраняемых записей.\n\n" ..
"ВНИМАНИЕ: изменение этой настройки очистит вашу историю ввода.",
},
chat_history_remove_dups = {
en = "Remove Duplicate Entries",
ru = "Удалять повторяющиеся записи",
},
chat_history_remove_dups_mode = {
en = "Removal Mode",
ru = "Режим удаления",
},
chat_history_remove_dups_mode_tooltip = {
en = "Which duplicate entries should be removed.\n\n" ..
"-- LAST --\nRemoves previous entry if it matches the last one.\n\n" ..
"-- ALL --\nRemoves all entries if it matches the last one.",
ru = "Повторяющиеся записи, которые будут удалены.\n\n" ..
"-- ПОСЛЕДНИЕ --\nПредпоследняя запись будет удалена, если она совпадает с последней.\n\n" ..
"-- ВСЕ --\nВсе записи, совпадающие с последней записью, будут удалены.",
},
settings_last = {
en = "Last",
ru = "Последние",
},
settings_all = {
en = "All",
ru = "Все",
},
chat_history_commands_only = {
en = "Save only executed commands",
ru = "Сохранять только выполненные команды",
},
chat_history_commands_only_tooltip = {
en = "Only successfully executed commands will be saved in the chat history.\n\n" ..
"WARNING: Changing this setting will erase your chat history.",
ru = "Только успешно выполненные команды будут сохранены в истории ввода.\n\n" ..
"ВНИМАНИЕ: изменение этой настройки очистит вашу историю ввода.",
},
clean_chat_history = {
en = "cleans chat input history",
ru = "очищает историю ввода",
},
dev_console_opened = {
en = "Developer console opened.",
ru = "Консоль разработчика открыта.",
},
dev_console_closed = {
en = "Developer console closed.",
ru = "Консоль разработчика закрыта.",
},
} }

View file

@ -19,6 +19,7 @@ lua = [
"scripts/mods/vmf/modules/core/*" "scripts/mods/vmf/modules/core/*"
"scripts/mods/vmf/modules/debug/*" "scripts/mods/vmf/modules/debug/*"
"scripts/mods/vmf/modules/gui/*" "scripts/mods/vmf/modules/gui/*"
"scripts/mods/vmf/modules/options_menu/*" "scripts/mods/vmf/modules/ui/options/*"
"scripts/mods/vmf/modules/mutators/*" "scripts/mods/vmf/modules/ui/chat/*"
"scripts/mods/vmf/modules/ui/mutators/*"
] ]

View file

@ -0,0 +1,166 @@
local vmf = get_mod("VMF")
--[[
* letters' case doesn't matter
* ctrl+c & ctrl+v
* very flexible chat history without any glitches that occured in the past
* commands are not shown if the mod is disabled
not sure about UI scaling
]]
-- @TODO: move 'vmf.check_wrong_argument_type' to somewhere else
local _COMMANDS = {}
-- ####################################################################################################################
-- ##### Local functions ##############################################################################################
-- ####################################################################################################################
vmf.check_wrong_argument_type = function(mod, vmf_function_name, argument_name, argument, ...)
local allowed_types = {...}
local argument_type = type(argument)
for _, allowed_type in ipairs(allowed_types) do
if allowed_type == argument_type then
return false
end
end
mod:error("(%s): argument '%s' should have the '%s' type, not '%s'", vmf_function_name, argument_name, table.concat(allowed_types, "/"), argument_type)
return true
end
-- ####################################################################################################################
-- ##### VMFMod #######################################################################################################
-- ####################################################################################################################
VMFMod.command = function (self, command_name, command_description, command_function)
if vmf.check_wrong_argument_type(self, "command", "command_name", command_name, "string") or
vmf.check_wrong_argument_type(self, "command", "command_description", command_description, "string", "nil") or
vmf.check_wrong_argument_type(self, "command", "command_function", command_function, "function") then
return
end
command_name = command_name:lower()
if _COMMANDS[command_name] and _COMMANDS[command_name].mod ~= self then
self:error("(command): command name '%s' is already used by another mod '%s'", command_name, _COMMANDS[command_name].mod:get_name())
return
end
_COMMANDS[command_name] = {
mod = self,
exec_function = command_function,
description = command_description,
is_enabled = true
}
end
VMFMod.command_remove = function (self, command_name)
if vmf.check_wrong_argument_type(self, "command_remove", "command_name", command_name, "string") then
return
end
_COMMANDS[command_name] = nil
end
VMFMod.command_disable = function (self, command_name)
if vmf.check_wrong_argument_type(self, "command_disable", "command_name", command_name, "string") then
return
end
if _COMMANDS[command_name] then
_COMMANDS[command_name].is_enabled = false
end
end
VMFMod.command_enable = function (self, command_name)
if vmf.check_wrong_argument_type(self, "command_enable", "command_name", command_name, "string") then
return
end
if _COMMANDS[command_name] then
_COMMANDS[command_name].is_enabled = true
end
end
VMFMod.remove_all_commands = function (self)
for command_name, command_entry in pairs(_COMMANDS) do
if command_entry.mod == self then
_COMMANDS[command_name] = nil
end
end
end
VMFMod.disable_all_commands = function (self)
for _, command_entry in pairs(_COMMANDS) do
if command_entry.mod == self then
command_entry.is_enabled = false
end
end
end
VMFMod.enable_all_commands = function (self)
for _, command_entry in pairs(_COMMANDS) do
if command_entry.mod == self then
command_entry.is_enabled = true
end
end
end
-- ####################################################################################################################
-- ##### VMF internal functions and variables #########################################################################
-- ####################################################################################################################
vmf.get_commands_list = function(name_contains, exact_match)
name_contains = name_contains:lower()
local commands_list = {}
for command_name, command_entry in pairs(_COMMANDS) do
if exact_match then
if command_name == name_contains and command_entry.is_enabled then
table.insert(commands_list, {name = command_name, description = command_entry.description})
break
end
else
if string.sub(command_name, 1, string.len(name_contains)) == name_contains and command_entry.is_enabled and command_entry.mod:is_enabled() then
table.insert(commands_list, {name = command_name, description = command_entry.description})
end
end
end
table.sort(commands_list, function(a, b) return a.name < b.name end)
return commands_list
end
vmf.run_command = function(command_name, ...)
local command_entry = _COMMANDS[command_name]
if command_entry then
local success, error_message = pcall(command_entry.exec_function, ...)
if not success then
command_entry.mod:error("(commands) in command '%s': %s", command_name, tostring(error_message))
end
else
vmf:error("(commands): command '%s' wasn't found.", command_name) -- should never see this
end
end

View file

@ -181,17 +181,17 @@ vmf.unsent_chat_messages = _UNSENT_CHAT_MESSAGES
vmf.load_logging_settings = function () vmf.load_logging_settings = function ()
_LOGGING_SETTINGS = { _LOGGING_SETTINGS = {
echo = vmf:get("logging_mode") == "custom" and vmf:get("output_mode_echo") or 3, echo = vmf:get("logging_mode") == "custom" and vmf:get("output_mode_echo"),-- or 3, @TODO: clean up?
error = vmf:get("logging_mode") == "custom" and vmf:get("output_mode_error") or 3, error = vmf:get("logging_mode") == "custom" and vmf:get("output_mode_error"),-- or 3,
warning = vmf:get("logging_mode") == "custom" and vmf:get("output_mode_warning") or 3, warning = vmf:get("logging_mode") == "custom" and vmf:get("output_mode_warning"),-- or 3,
info = vmf:get("logging_mode") == "custom" and vmf:get("output_mode_info") or 1, info = vmf:get("logging_mode") == "custom" and vmf:get("output_mode_info"),-- or 1,
debug = vmf:get("logging_mode") == "custom" and vmf:get("output_mode_debug") or 0, debug = vmf:get("logging_mode") == "custom" and vmf:get("output_mode_debug"),-- or 0,
} }
for method_name, logging_mode in pairs(_LOGGING_SETTINGS) do for method_name, logging_mode in pairs(_LOGGING_SETTINGS) do
_LOGGING_SETTINGS[method_name] = { _LOGGING_SETTINGS[method_name] = {
send_to_chat = logging_mode >= 2, send_to_chat = logging_mode and logging_mode >= 2,
send_to_log = logging_mode % 2 == 1 send_to_log = logging_mode and logging_mode % 2 == 1
} }
end end
end end

View file

@ -19,8 +19,8 @@ end
-- ##### VMF internal functions and variables ######################################################################### -- ##### VMF internal functions and variables #########################################################################
-- #################################################################################################################### -- ####################################################################################################################
-- call 'unload' for every mod which defined it -- call 'on_unload' for every mod which defined it
vmf.mods_unload_event = function() vmf.mods_unload_event = function(exit_game)
local event_name = "on_unload" local event_name = "on_unload"
@ -29,7 +29,7 @@ vmf.mods_unload_event = function()
local mod = _MODS[mod_name] local mod = _MODS[mod_name]
local event = mod[event_name] local event = mod[event_name]
if event then if event then
run_event(mod, event_name, event) run_event(mod, event_name, event, exit_game)
end end
end end
end end
@ -48,7 +48,7 @@ vmf.mods_update_event = function(dt)
end end
end end
-- call 'game_state_changed' for every mod which defined it -- call 'on_game_state_changed' for every mod which defined it
vmf.mods_game_state_changed_event = function(status, state) vmf.mods_game_state_changed_event = function(status, state)
local event_name = "on_game_state_changed" local event_name = "on_game_state_changed"
@ -115,3 +115,17 @@ vmf.mod_user_left_the_game = function(mod, player)
run_event(mod, event_name, event, player) run_event(mod, event_name, event, player)
end end
end end
vmf.all_mods_loaded_event = function()
local event_name = "on_all_mods_loaded"
for _, mod_name in ipairs(_MODS_UNLOADING_ORDER) do
local mod = _MODS[mod_name]
local event = mod[event_name]
if event then
run_event(mod, event_name, event)
end
end
end

View file

@ -67,8 +67,6 @@ local function create_hook_entry(mod, hooked_function_entry, hook_function)
hook_entry.is_enabled = true hook_entry.is_enabled = true
table.insert(hooked_function_entry.hooks, hook_entry) table.insert(hooked_function_entry.hooks, hook_entry)
--return hook_entry -- @TODO: do I need this return?
end end
@ -134,6 +132,7 @@ end
local function modify_hook(mod, hooked_function_name, action) local function modify_hook(mod, hooked_function_name, action)
-- @TODO: I guess I don't need this check?
if not get_function_by_name(hooked_function_name) then if not get_function_by_name(hooked_function_name) then
mod:error("(hook_%s): function [%s] doesn't exist", action, hooked_function_name) mod:error("(hook_%s): function [%s] doesn't exist", action, hooked_function_name)
return return

View file

@ -11,6 +11,8 @@ local _SHARED_RPCS_MAP = ""
local _NETWORK_MODULE_IS_INITIALIZED = false local _NETWORK_MODULE_IS_INITIALIZED = false
local _NETWORK_DEBUG = false
-- #################################################################################################################### -- ####################################################################################################################
-- ##### Local functions ############################################################################################## -- ##### Local functions ##############################################################################################
-- #################################################################################################################### -- ####################################################################################################################
@ -82,7 +84,7 @@ end
local function network_debug(rpc_type, action_type, peer_id, mod_name, rpc_name, data) local function network_debug(rpc_type, action_type, peer_id, mod_name, rpc_name, data)
if vmf.network_debug then if _NETWORK_DEBUG then
local debug_message = nil local debug_message = nil
@ -196,7 +198,7 @@ VMFMod.network_send = function (self, rpc_name, recipient, ...)
if recipient == "all" then if recipient == "all" then
for peer_id, _ in pairs(_VMF_USERS) do for peer_id, _ in pairs(_VMF_USERS) do
send_rpc_vmf_data(peer_id, self:get_name(), rpc_name, ...) send_rpc_vmf_data(peer_id, self:get_name(), rpc_name, ...)
end end
send_rpc_vmf_data_local(self:get_name(), rpc_name, ...) send_rpc_vmf_data_local(self:get_name(), rpc_name, ...)
@ -241,7 +243,7 @@ vmf:hook("ChatManager.rpc_chat_message", function(func, self, sender, channel_id
elseif channel_id == 4 then -- rpc_vmf_responce (@TODO: maybe I should protect it from sending by the player who's not in the game?) elseif channel_id == 4 then -- rpc_vmf_responce (@TODO: maybe I should protect it from sending by the player who's not in the game?)
network_debug("pong", "received", sender) network_debug("pong", "received", sender)
if vmf.network_debug then if _NETWORK_DEBUG then
vmf:info("[RECEIVED MODS TABLE]: " .. message) vmf:info("[RECEIVED MODS TABLE]: " .. message)
vmf:info("[RECEIVED RPCS TABLE]: " .. localization_param) vmf:info("[RECEIVED RPCS TABLE]: " .. localization_param)
end end
@ -329,8 +331,6 @@ end)
-- ##### VMF internal functions and variables ######################################################################### -- ##### VMF internal functions and variables #########################################################################
-- #################################################################################################################### -- ####################################################################################################################
vmf.network_debug = vmf:get("developer_mode") and vmf:get("show_network_debug_info")
vmf.create_network_dictionary = function() vmf.create_network_dictionary = function()
_SHARED_MODS_MAP = {} _SHARED_MODS_MAP = {}
@ -375,3 +375,13 @@ vmf.ping_vmf_users = function()
end end
end end
end end
vmf.load_network_settings = function()
_NETWORK_DEBUG = vmf:get("developer_mode") and vmf:get("show_network_debug_info")
end
-- ####################################################################################################################
-- ##### Script #######################################################################################################
-- ####################################################################################################################
vmf.load_network_settings()

View file

@ -29,7 +29,7 @@ end
-- #################################################################################################################### -- ####################################################################################################################
--[[ --[[
* setting_name [string] : setting name, can contain any characters lua-string can @TODO: check this * setting_name [string] : setting name, can contain any characters lua-string can
* setting_value [anything]: setting value, will be serialized to SJSON format, so you can save whole tables * setting_value [anything]: setting value, will be serialized to SJSON format, so you can save whole tables
* call_setting_changed_event [bool] : if 'true', when some setting will be changed, 'setting_changed' event will be called (if mod defined one) * call_setting_changed_event [bool] : if 'true', when some setting will be changed, 'setting_changed' event will be called (if mod defined one)
--]] --]]
@ -53,7 +53,7 @@ VMFMod.set = function (self, setting_name, setting_value, call_setting_changed_e
end end
--[[ --[[
* setting_name [string]: setting name, can contain any characters lua-string can @TODO: check this * setting_name [string]: setting name, can contain any characters lua-string can
--]] --]]
VMFMod.get = function (self, setting_name) VMFMod.get = function (self, setting_name)

View file

@ -36,6 +36,19 @@ local function close_dev_console()
print = PRINT_ORIGINAL_FUNCTION print = PRINT_ORIGINAL_FUNCTION
CommandWindow.close() CommandWindow.close()
-- CommandWindow won't close by itself, so it have to be closed manually
vmf:pcall(function()
local ffi = require("ffi")
ffi.cdef([[
void* FindWindowA(const char* lpClassName, const char* lpWindowName);
int64_t SendMessageA(void* hWnd, unsigned int Msg, uint64_t wParam, int64_t lParam);
]])
local WM_CLOSE = 0x10;
local hwnd = ffi.C.FindWindowA("ConsoleWindowClass", "Developer console")
ffi.C.SendMessageA(hwnd, WM_CLOSE, 0, 0)
end)
DEV_CONSOLE_ENABLED = false DEV_CONSOLE_ENABLED = false
end end
end end
@ -44,9 +57,26 @@ end
-- ##### VMF internal functions and variables ######################################################################### -- ##### VMF internal functions and variables #########################################################################
-- #################################################################################################################### -- ####################################################################################################################
vmf.toggle_developer_console = function (open_console) vmf.toggle_developer_console = function ()
if open_console then if vmf:get("developer_mode") then
local show_console = not vmf:get("show_developer_console")
vmf:set("show_developer_console", show_console)
vmf.load_dev_console_settings()
if show_console then
vmf:echo(vmf:localize("dev_console_opened"))
else
vmf:echo(vmf:localize("dev_console_closed"))
end
end
end
vmf.load_dev_console_settings = function()
if vmf:get("developer_mode") and vmf:get("show_developer_console") then
open_dev_console() open_dev_console()
else else
close_dev_console() close_dev_console()
@ -57,7 +87,4 @@ end
-- ##### Script ####################################################################################################### -- ##### Script #######################################################################################################
-- #################################################################################################################### -- ####################################################################################################################
if vmf:get("developer_mode") and vmf:get("show_developer_console") then vmf.load_dev_console_settings()
open_dev_console()
end

View file

@ -7,6 +7,8 @@ local _CUSTOM_UI_ATLAS_SETTINGS = {}
local _INJECTED_MATERIALS = {} local _INJECTED_MATERIALS = {}
local _SHOW_DEBUG_INFO = false
-- #################################################################################################################### -- ####################################################################################################################
-- ##### Local functions ############################################################################################## -- ##### Local functions ##############################################################################################
-- #################################################################################################################### -- ####################################################################################################################
@ -130,10 +132,15 @@ VMFMod.inject_materials = function (self, ui_renderer_creator, ...)
_INJECTED_MATERIALS[ui_renderer_creator] = injected_materials_list _INJECTED_MATERIALS[ui_renderer_creator] = injected_materials_list
-- recreate GUIs with injected materials for ui_renderers created by 'ui_renderer_creator' -- recreate GUIs with injected materials for ui_renderers created by 'ui_renderer_creator'
for ui_renderer, _ in pairs(UI_RENDERERS) do local vmf_data
if ui_renderer.vmf_data.ui_renderer_creator == ui_renderer_creator then
local new_materials_list = table.clone(ui_renderer.vmf_data.original_materials) for ui_renderer, _ in pairs(UI_RENDERERS) do
vmf_data = rawget(ui_renderer, "vmf_data")
if vmf_data.ui_renderer_creator == ui_renderer_creator then
local new_materials_list = table.clone(vmf_data.original_materials)
for _, injected_material in ipairs(injected_materials_list) do for _, injected_material in ipairs(injected_materials_list) do
table.insert(new_materials_list, "material") table.insert(new_materials_list, "material")
@ -192,7 +199,7 @@ vmf:hook("UIRenderer.create", function(func, world, ...)
-- DEBUG INFO -- DEBUG INFO
if vmf.custom_textures_debug then if _SHOW_DEBUG_INFO then
vmf:info("UI_RENDERER CREATED BY:") vmf:info("UI_RENDERER CREATED BY:")
vmf:info(" %s", ui_renderer_creator) vmf:info(" %s", ui_renderer_creator)
vmf:info("UI_RENDERER MATERIALS:") vmf:info("UI_RENDERER MATERIALS:")
@ -203,29 +210,19 @@ vmf:hook("UIRenderer.create", function(func, world, ...)
-- CREATING THE NEW UI_RENDERER AND SAVING SOME DATA INSIDE OF IT -- CREATING THE NEW UI_RENDERER AND SAVING SOME DATA INSIDE OF IT
ui_renderer_creating = true
local ui_renderer = func(world, unpack(ui_renderer_materials)) local ui_renderer = func(world, unpack(ui_renderer_materials))
UI_RENDERERS[ui_renderer] = true UI_RENDERERS[ui_renderer] = true
ui_renderer.vmf_data.original_materials = {...} local vmf_data = {}
ui_renderer.vmf_data.ui_renderer_creator = ui_renderer_creator vmf_data.original_materials = {...}
vmf_data.ui_renderer_creator = ui_renderer_creator
rawset(ui_renderer, "vmf_data", vmf_data)
return ui_renderer return ui_renderer
end) end)
vmf:hook("MakeTableStrict", function(func, t)
if ui_renderer_creating then
t.vmf_data = {}
ui_renderer_creating = false
end
return func(t)
end)
vmf:hook("UIRenderer.destroy", function(func, self, world) vmf:hook("UIRenderer.destroy", function(func, self, world)
UI_RENDERERS[self] = nil UI_RENDERERS[self] = nil
@ -261,4 +258,12 @@ end)
-- ##### VMF internal functions and variables ######################################################################### -- ##### VMF internal functions and variables #########################################################################
-- #################################################################################################################### -- ####################################################################################################################
vmf.custom_textures_debug = vmf:get("developer_mode") and vmf:get("log_ui_renderers_info") vmf.load_custom_textures_settings = function()
_SHOW_DEBUG_INFO = vmf:get("developer_mode") and vmf:get("log_ui_renderers_info")
end
-- ####################################################################################################################
-- ##### Script #######################################################################################################
-- ####################################################################################################################
vmf.load_custom_textures_settings()

View file

@ -1,28 +1,49 @@
-- If enabled, scale UI for resolutions greater than 1080p when necessary. Reports to a global when active, so that existing scaling can be disabled.
local vmf = get_mod("VMF") local vmf = get_mod("VMF")
-- If enabled, scale UI for resolutions greater than 1080p when necessary. Reports to a global when active, so that existing scaling can be disabled. local _UI_RESOLUTION = UIResolution
local ui_resolution = UIResolution local _UI_RESOLUTION_WIDTH_FRAGMENTS = UIResolutionWidthFragments
local ui_resolution_width_fragments = UIResolutionWidthFragments local _UI_RESOLUTION_HEIGHT_FRAGMENTS = UIResolutionHeightFragments
local ui_resolution_height_fragments = UIResolutionHeightFragments local _MATH_MIN = math.min
local math_min = math.min
local raw_set = rawset local _UI_SCALING_ENABLED
-- ####################################################################################################################
-- ##### Hooks ########################################################################################################
-- ####################################################################################################################
vmf:hook("UIResolutionScale", function (func, ...) vmf:hook("UIResolutionScale", function (func, ...)
local w, h = ui_resolution() local w, h = _UI_RESOLUTION()
if (w > ui_resolution_width_fragments() and h > ui_resolution_height_fragments() and vmf:get("ui_scaling")) then if (w > _UI_RESOLUTION_WIDTH_FRAGMENTS() and h > _UI_RESOLUTION_HEIGHT_FRAGMENTS() and _UI_SCALING_ENABLED) then
local max_scaling_factor = 4 local max_scaling_factor = 4
local width_scale = math_min(w / ui_resolution_width_fragments(), max_scaling_factor) -- Changed to allow scaling up to quadruple the original max scale (1 -> 4) local width_scale = _MATH_MIN(w / _UI_RESOLUTION_WIDTH_FRAGMENTS(), max_scaling_factor) -- Changed to allow scaling up to quadruple the original max scale (1 -> 4)
local height_scale = math_min(h / ui_resolution_height_fragments(), max_scaling_factor) -- Changed to allow scaling up to quadruple the original max scale (1 -> 4) local height_scale = _MATH_MIN(h / _UI_RESOLUTION_HEIGHT_FRAGMENTS(), max_scaling_factor) -- Changed to allow scaling up to quadruple the original max scale (1 -> 4)
raw_set(_G, "vmf_hd_ui_scaling_enabled", true) return _MATH_MIN(width_scale, height_scale)
return math_min(width_scale, height_scale)
else else
raw_set(_G, "vmf_hd_ui_scaling_enabled", false)
return func(...) return func(...)
end end
end) end)
-- ####################################################################################################################
-- ##### VMF internal functions and variables #########################################################################
-- ####################################################################################################################
vmf.load_ui_scaling_settings = function ()
_UI_SCALING_ENABLED = vmf:get("ui_scaling")
if _UI_SCALING_ENABLED then
RESOLUTION_LOOKUP.ui_scaling = true
else
RESOLUTION_LOOKUP.ui_scaling = false
end
end
-- ####################################################################################################################
-- ##### Script #######################################################################################################
-- ####################################################################################################################
vmf.load_ui_scaling_settings()

View file

@ -109,6 +109,12 @@ local options_widgets = {
mod:create_options(options_widgets, true, "Test", "Mod description") mod:create_options(options_widgets, true, "Test", "Mod description")
mod:command("whatever", "description whatever", function() mod:echo("whatever") end)
mod:command("what", "description what", function() mod:echo("what") end)
mod:command("wh", "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse tincidunt placerat nulla eget pharetra. Vivamus consequat tristique vestibulum. Nullam vitae feugiat arcu, non porta ante. Phasellus consequat facilisis quam quis dignissim.", function(a, b) mod:echo("wh, " .. tostring(a) .. ", " .. tostring(b)) end)
mod:command("whoa", "description whoa", function() mod:echo("whoa") end)
mod:command("wheat", "description wheat", function() mod:echo("wheat") end)
mod:command("test", "short command description\n params: [parameter1] [parameter2]\nparameter1 - string\nparameter2 - number", function(p1, p2) mod:echo("Test function executed.\nParameter1: " .. tostring(p1) .. "\nParameter2: " .. tostring(p2)) end)
-- chat_broadcast -- chat_broadcast
mod.whatever = function () mod.whatever = function ()
--mod:echo("whatever") --mod:echo("whatever")

View file

@ -0,0 +1,276 @@
--[[
* chat commands
* chat history
* ctrl + c, ctrl + v
]]
local vmf = get_mod("VMF")
local _CHAT_OPENED = false
local _COMMANDS_LIST = {}
local _COMMAND_INDEX = 0 -- 0 => nothing selected
local _COMMANDS_LIST_GUI_DRAW = nil
local _CHAT_HISTORY = {}
local _CHAT_HISTORY_INDEX = 0
local _CHAT_HISTORY_ENABLED = true
local _CHAT_HISTORY_SAVE = true
local _CHAT_HISTORY_MAX = 50
local _CHAT_HISTORY_REMOVE_DUPS_LAST = false
local _CHAT_HISTORY_REMOVE_DUPS_ALL = false
local _CHAT_HISTORY_SAVE_COMMANDS_ONLY = false
-- ####################################################################################################################
-- ##### Local functions ##############################################################################################
-- ####################################################################################################################
local function clean_chat_history()
_CHAT_HISTORY = {}
_CHAT_HISTORY_INDEX = 0
end
-- ####################################################################################################################
-- ##### Hooks ########################################################################################################
-- ####################################################################################################################
vmf:hook("WorldManager.create_world", function(func, self, name, ...)
local world = func(self, name, ...)
if name == "top_ingame_view" then
_COMMANDS_LIST_GUI_DRAW = dofile("scripts/mods/vmf/modules/ui/chat/commands_list_gui")
end
return world
end)
vmf:hook("ChatGui.block_input", function(func, ...)
func(...)
_CHAT_OPENED = true
end)
vmf:hook("ChatGui._update_input", function(func, self, input_service, menu_input_service, dt, no_unblock, chat_enabled)
local command_executed = false
-- if ENTER was pressed
if Keyboard.pressed(Keyboard.button_index("enter")) then
-- chat history
if _CHAT_HISTORY_ENABLED
and self.chat_message ~= ""
and not (_CHAT_HISTORY_REMOVE_DUPS_LAST and (self.chat_message == _CHAT_HISTORY[1]))
and (not _CHAT_HISTORY_SAVE_COMMANDS_ONLY or (_COMMAND_INDEX ~= 0)) then
table.insert(_CHAT_HISTORY, 1, self.chat_message)
if #_CHAT_HISTORY == _CHAT_HISTORY_MAX + 1 then
table.remove(_CHAT_HISTORY, #_CHAT_HISTORY)
end
if _CHAT_HISTORY_REMOVE_DUPS_ALL then
for i = 2, #_CHAT_HISTORY do
if _CHAT_HISTORY[i] == self.chat_message then
table.remove(_CHAT_HISTORY, i)
break
end
end
end
end
-- command execution
if _COMMAND_INDEX ~= 0 then
local args = {}
for arg in string.gmatch(self.chat_message, "%S+") do
table.insert(args, arg)
end
table.remove(args, 1)
vmf.run_command(_COMMANDS_LIST[_COMMAND_INDEX].name, unpack(args))
_COMMANDS_LIST = {}
_COMMAND_INDEX = 0
self.chat_message = ""
command_executed = true
end
end
local old_chat_message = self.chat_message
local chat_focused, chat_closed, chat_close_time = func(self, input_service, menu_input_service, dt, no_unblock, chat_enabled)
if chat_closed then
self.chat_message = ""
_CHAT_OPENED = false
_COMMANDS_LIST = {}
_COMMAND_INDEX = 0
_CHAT_HISTORY_INDEX = 0
if command_executed then
chat_closed = false
chat_close_time = nil
end
end
if _CHAT_OPENED then
-- getting state of 'tab', 'arrow up' and 'arrow down' buttons
local tab_pressed = false
local arrow_up_pressed = false
local arrow_down_pressed = false
for _, stroke in ipairs(Keyboard.keystrokes()) do
if stroke == Keyboard.TAB then
tab_pressed = true
-- game considers some "ctrl + [something]" combinations as arrow buttons, so I have to check for ctrl not pressed
elseif stroke == Keyboard.UP and Keyboard.button(Keyboard.button_index("left ctrl")) == 0 then
arrow_up_pressed = true
elseif stroke == Keyboard.DOWN and Keyboard.button(Keyboard.button_index("left ctrl")) == 0 then
arrow_down_pressed = true
end
end
-- chat history
if _CHAT_HISTORY_ENABLED then
-- message was modified by player
if self.chat_message ~= self.previous_chat_message then
_CHAT_HISTORY_INDEX = 0
end
if arrow_up_pressed or arrow_down_pressed then
local new_index = _CHAT_HISTORY_INDEX + (arrow_up_pressed and 1 or -1)
new_index = math.clamp(new_index, 0, #_CHAT_HISTORY)
if _CHAT_HISTORY_INDEX ~= new_index then
if _CHAT_HISTORY[new_index] then
self.chat_message = _CHAT_HISTORY[new_index]
self.chat_index = KeystrokeHelper.num_utf8chars(self.chat_message) + 1
self.chat_input_widget.content.text_index = 1
self.previous_chat_message = self.chat_message
_CHAT_HISTORY_INDEX = new_index
else -- new_index == 0
self.chat_message = ""
self.chat_index = 1
end
end
end
end
-- ctrl + v
if Keyboard.pressed(Keyboard.button_index("v")) and Keyboard.button(Keyboard.button_index("left ctrl")) == 1 then
self.chat_message = self.chat_message .. tostring(Clipboard.get()):gsub(string.char(0x0D), "") -- remove CR characters
self.chat_index = KeystrokeHelper.num_utf8chars(self.chat_message) + 1
end
-- ctrl + c
if Keyboard.pressed(Keyboard.button_index("c")) and Keyboard.button(Keyboard.button_index("left ctrl")) == 1 then
Clipboard.put(self.chat_message)
end
-- entered chat message starts with "/"
if string.sub(self.chat_message, 1, 1) == "/" then
if not string.find(self.chat_message, " ") -- if there's no space after '/part_of_command_name'
and tab_pressed -- if TAB was pressed
and (string.len(self.chat_message) + 1) == self.chat_index -- if TAB was pressed with caret at the end of the string
and (#_COMMANDS_LIST > 0) then -- if there are any commands matching entered '/part_of_command_name'
_COMMAND_INDEX = _COMMAND_INDEX % #_COMMANDS_LIST + 1
self.chat_message = "/" .. _COMMANDS_LIST[_COMMAND_INDEX].name
self.chat_index = KeystrokeHelper.num_utf8chars(self.chat_message) + 1
-- so the next block won't update the commands list
old_chat_message = self.chat_message
end
if self.chat_message ~= old_chat_message then
-- get '/part_of_command_name' without '/'
local command_name_contains = self.chat_message:match("%S+"):sub(2, -1)
if string.find(self.chat_message, " ") then
_COMMANDS_LIST = vmf.get_commands_list(command_name_contains, true)
else
_COMMANDS_LIST = vmf.get_commands_list(command_name_contains)
end
_COMMAND_INDEX = 0
if #_COMMANDS_LIST > 0 and command_name_contains:lower() == _COMMANDS_LIST[1].name then
_COMMAND_INDEX = 1
end
end
-- chat message was modified and doesn't start with '/'
elseif self.chat_message ~= old_chat_message and #_COMMANDS_LIST > 0 then
_COMMANDS_LIST = {}
_COMMAND_INDEX = 0
end
if #_COMMANDS_LIST > 0 then
_COMMANDS_LIST_GUI_DRAW(_COMMANDS_LIST, _COMMAND_INDEX)
end
end
return chat_focused, chat_closed, chat_close_time
end)
-- ####################################################################################################################
-- ##### VMF internal functions and variables #########################################################################
-- ####################################################################################################################
vmf.load_chat_history_settings = function(clean_chat_history_)
_CHAT_HISTORY_ENABLED = vmf:get("chat_history_enable")
_CHAT_HISTORY_SAVE = vmf:get("chat_history_save")
_CHAT_HISTORY_MAX = vmf:get("chat_history_buffer_size")
_CHAT_HISTORY_REMOVE_DUPS_LAST = vmf:get("chat_history_remove_dups")
_CHAT_HISTORY_REMOVE_DUPS_ALL = vmf:get("chat_history_remove_dups") and (vmf:get("chat_history_remove_dups_mode") == "all")
_CHAT_HISTORY_SAVE_COMMANDS_ONLY = vmf:get("chat_history_commands_only")
if _CHAT_HISTORY_ENABLED then
vmf:command("clean_chat_history", vmf:localize("clean_chat_history"), clean_chat_history)
else
vmf:command_remove("clean_chat_history")
end
if not _CHAT_HISTORY_SAVE then
vmf:set("chat_history", nil)
end
if clean_chat_history_ then
clean_chat_history()
end
end
vmf.save_chat_history = function()
if _CHAT_HISTORY_SAVE then
vmf:set("chat_history", _CHAT_HISTORY)
end
end
-- ####################################################################################################################
-- ##### Script #######################################################################################################
-- ####################################################################################################################
vmf.load_chat_history_settings()
if _CHAT_HISTORY_SAVE then
_CHAT_HISTORY = vmf:get("chat_history") or _CHAT_HISTORY
end
if Managers.world:has_world("top_ingame_view") then
-- @TODO: move this to local function?
_COMMANDS_LIST_GUI_DRAW = dofile("scripts/mods/vmf/modules/ui/chat/commands_list_gui")
end

View file

@ -0,0 +1,142 @@
local vmf = get_mod("VMF") --@TODO: remove it?
local _GUI = World.create_screen_gui(Managers.world:world("top_ingame_view"), "immediate", "material", "materials/fonts/gw_fonts", "material", "materials/ui/ui_1080p_ingame_common")
local _FONT_TYPE = "hell_shark_arial"
local _FONT_SIZE = 22
local _MULTISTRING_INDICATOR_TEXT = "[...]"
local _MAX_COMMANDS_VISIBLE = 5
local _STRING_HEIGHT = 25
local _STRING_Y_OFFSET = 7
local _STRING_X_MARGIN = 10
local _OFFSET_X = 0
local _OFFSET_Y = 200
local _OFFSET_Z = 880
local _WIDTH = 550
-- ####################################################################################################################
-- ##### Local functions ##############################################################################################
-- ####################################################################################################################
local function get_text_width(text, font_material, font_size)
local text_extent_min, text_extent_max = Gui.text_extents(_GUI, text, font_material, font_size)
local text_height = text_extent_max[1] - text_extent_min[1]
return text_height
end
local function word_wrap(text, font_material, font_size, max_width)
local whitespace = " "
local soft_dividers = "-+&/*"
local return_dividers = "\n"
local reuse_global_table = true
local scale = RESOLUTION_LOOKUP.scale
return Gui.word_wrap(_GUI, text, font_material, font_size, max_width * scale, whitespace, soft_dividers, return_dividers, reuse_global_table)
end
local function draw(commands_list, selected_command_index)
--vmf:pcall(function()
local selected_command_new_index = 0
-- pick displayed commands
local last_displayed_command = math.max(math.min(_MAX_COMMANDS_VISIBLE, #commands_list), selected_command_index)
local first_displayed_command = math.max(1, last_displayed_command - (_MAX_COMMANDS_VISIBLE - 1))
local displayed_commands = {}
for i = first_displayed_command, last_displayed_command do
local new_entry = {}
new_entry.name = "/" .. commands_list[i].name
new_entry.description = commands_list[i].description
new_entry.full_text = new_entry.name .. " " .. new_entry.description
if i == selected_command_index then
new_entry.selected = true
selected_command_new_index = #displayed_commands + 1
end
table.insert(displayed_commands, new_entry)
end
local scale = RESOLUTION_LOOKUP.scale
local selected_strings_number = 1
local font, font_size = UIFontByResolution({font_type = _FONT_TYPE, font_size = _FONT_SIZE})
local font_material = font[1]
local font_name = font[3]
for i, command in ipairs(displayed_commands) do
-- draw "/command_name" text
local string_position = Vector3((_OFFSET_X + _STRING_X_MARGIN) * scale, (_OFFSET_Y - _STRING_HEIGHT * (i + selected_strings_number - 1) + _STRING_Y_OFFSET) * scale, _OFFSET_Z + 2)
Gui.text(_GUI, command.name, font_material, font_size, font_name, string_position, Color(255, 100, 255, 100))
local command_text_strings = word_wrap(command.full_text, font_material, font_size, _WIDTH - _STRING_X_MARGIN * 2)
local multistring = #command_text_strings > 1
local first_description_string
if multistring then
if command.selected then
selected_strings_number = #command_text_strings
else
local multistring_indicator_width = get_text_width(_MULTISTRING_INDICATOR_TEXT, font_material, font_size)
command_text_strings = word_wrap(command.full_text, font_material, font_size, _WIDTH - _STRING_X_MARGIN * 2 - (multistring_indicator_width / scale))
-- draw that [...] thing
local multistring_indicator_position = Vector3((_OFFSET_X + _WIDTH) * scale - multistring_indicator_width, string_position.y, string_position.z)
Gui.text(_GUI, _MULTISTRING_INDICATOR_TEXT, font_material, font_size, font_name, multistring_indicator_position, Color(255, 100, 100, 100))
end
first_description_string = string.sub(command_text_strings[1], #command.name + 2)
else
first_description_string = command.description
end
-- draw command description text (1st string)
local first_description_string_width = get_text_width(command.name, font_material, font_size)
local first_description_string_position = Vector3(string_position.x + first_description_string_width, string_position.y, string_position.z)
Gui.text(_GUI, first_description_string, font_material, font_size, font_name, first_description_string_position, Color(255, 255, 255, 255))
-- draw command description text (2+ strings)
if command.selected and multistring then
for j = 2, selected_strings_number do
string_position.y = string_position.y - _STRING_HEIGHT * scale
Gui.text(_GUI, command_text_strings[j], font_material, font_size, font_name, string_position, Color(255, 255, 255, 255))
end
end
end
-- background rectangle
local bg_height = _STRING_HEIGHT * (#displayed_commands + selected_strings_number - 1)
local bg_pos_y = _OFFSET_Y - bg_height
local bg_position = Vector3(_OFFSET_X * scale, bg_pos_y * scale, _OFFSET_Z)
local bg_size = Vector2(_WIDTH * scale, bg_height * scale)
local bg_color = Color(200, 10, 10, 10)
Gui.rect(_GUI, bg_position, bg_size, bg_color)
-- selection rectangle
if selected_command_new_index > 0 then
local selection_height = _STRING_HEIGHT * selected_strings_number
local selection_pos_y = _OFFSET_Y - selection_height - _STRING_HEIGHT * (selected_command_new_index - 1)
local selection_position = Vector3(_OFFSET_X * scale, selection_pos_y * scale, _OFFSET_Z + 1)
local selection_size = Vector2(_WIDTH * scale, selection_height * scale)
local selection_color = Color(100, 120, 120, 120)
Gui.rect(_GUI, selection_position, selection_size, selection_color)
end
-- "selected command number / total commands number" indicator
if not ((#commands_list == 1) and (selected_command_index > 0)) then
local total_number_indicator = tostring(#commands_list)
if selected_command_index > 0 then
total_number_indicator = selected_command_index .. "/" .. total_number_indicator
end
local total_number_indicator_width = get_text_width(total_number_indicator, font_material, font_size)
local total_number_indicator_position = Vector3((_WIDTH) * scale - total_number_indicator_width, (_OFFSET_Y + _STRING_Y_OFFSET) * scale, _OFFSET_Z + 2)
Gui.text(_GUI, total_number_indicator, font_material, font_size, font_name, total_number_indicator_position, Color(255, 100, 100, 100))
end
--end)
end
return draw

View file

@ -6,7 +6,7 @@ local mutators = manager.mutators
manager:custom_textures("mutator_button", "mutator_button_hover") manager:custom_textures("mutator_button", "mutator_button_hover")
manager:inject_materials("ingame_ui", "materials/vmf/mutator_button", "materials/vmf/mutator_button_hover") manager:inject_materials("ingame_ui", "materials/vmf/mutator_button", "materials/vmf/mutator_button_hover")
local definitions = manager:dofile("scripts/mods/vmf/modules/mutators/mutator_gui_definitions") local definitions = manager:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_gui_definitions")
local PER_PAGE = definitions.PER_PAGE local PER_PAGE = definitions.PER_PAGE

View file

@ -11,7 +11,7 @@ local mutators = manager.mutators
-- Table of mutators' configs by name -- Table of mutators' configs by name
local mutators_config = {} local mutators_config = {}
local default_config = manager:dofile("scripts/mods/vmf/modules/mutators/mutator_default_config") local default_config = manager:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_default_config")
-- This lists mutators and which ones should be enabled after them -- This lists mutators and which ones should be enabled after them
-- This is populated via VMFMod.register_as_mutator -- This is populated via VMFMod.register_as_mutator
@ -35,9 +35,9 @@ local all_mutators_disabled = false
PRIVATE METHODS PRIVATE METHODS
]]-- ]]--
local mutators_view = manager:dofile("scripts/mods/vmf/modules/mutators/mutator_gui") local mutators_view = manager:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_gui")
local dice_manager = manager:dofile("scripts/mods/vmf/modules/mutators/mutator_dice") local dice_manager = manager:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_dice")
local set_lobby_data = manager:dofile("scripts/mods/vmf/modules/mutators/mutator_info") local set_lobby_data = manager:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_info")
-- Adds mutator names from enable_these_after to the list of mutators that should be enabled after the mutator_name -- Adds mutator names from enable_these_after to the list of mutators that should be enabled after the mutator_name
local function update_mutators_sequence(mutator_name, enable_these_after) local function update_mutators_sequence(mutator_name, enable_these_after)
@ -454,6 +454,6 @@ mutators_view:init(mutators_view:get_map_view())
--[[ --[[
Testing Testing
--]] --]]
-- manager:dofile("scripts/mods/vmf/modules/mutators/mutator_test") -- manager:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_test")
-- manager:dofile("scripts/mods/vmf/modules/mutators/mutators/mutation") -- manager:dofile("scripts/mods/vmf/modules/ui/mutators/mutators/mutation")
-- manager:dofile("scripts/mods/vmf/modules/mutators/mutators/deathwish") -- manager:dofile("scripts/mods/vmf/modules/ui/mutators/mutators/deathwish")

View file

@ -2355,6 +2355,8 @@ end
local SETTINGS_LIST_WIDGETS_DEFINITIONS = {} -- numerical sorting [ipairs] local SETTINGS_LIST_WIDGETS_DEFINITIONS = {} -- numerical sorting [ipairs]
local _DEFAULT_SCROLL_STEP = 40
local _SCROLL_STEP
-- #################################################################################################################### -- ####################################################################################################################
-- ##### INITIALIZATION ############################################################################################### -- ##### INITIALIZATION ###############################################################################################
@ -2366,14 +2368,11 @@ VMFOptionsView.init = function (self, ingame_ui_context)
self.current_setting_list_offset_y = 0 self.current_setting_list_offset_y = 0
self.default_scroll_step = 40
self.scroll_step = self.default_scroll_step / 100 * (vmf:get("vmf_options_scrolling_speed") or 100)
self.is_setting_changes_applied_immidiately = true self.is_setting_changes_applied_immidiately = true
self.definitions = {} self.definitions = {}
self.definitions.scenegraph = scenegraph_definition self.definitions.scenegraph = scenegraph_definition
self.definitions.scenegraph_2nd_layer = {} self.definitions.scenegraph_2nd_layer = {}
self.definitions.menu_widgets = menu_widgets_definition self.definitions.menu_widgets = menu_widgets_definition
self.definitions.settings_list_widgets = SETTINGS_LIST_WIDGETS_DEFINITIONS self.definitions.settings_list_widgets = SETTINGS_LIST_WIDGETS_DEFINITIONS
@ -3564,7 +3563,7 @@ VMFOptionsView.update_mousewheel_scroll_area_input = function (self)
if mouse_scroll_value ~= 0 then if mouse_scroll_value ~= 0 then
local new_offset = self.current_setting_list_offset_y + mouse_scroll_value * self.scroll_step local new_offset = self.current_setting_list_offset_y + mouse_scroll_value * _SCROLL_STEP
self.current_setting_list_offset_y = math.clamp(new_offset, 0, self.max_setting_list_offset_y) self.current_setting_list_offset_y = math.clamp(new_offset, 0, self.max_setting_list_offset_y)
@ -3833,6 +3832,33 @@ VMFOptionsView.unsuspend = function (self)
self.input_manager:block_device_except_service("vmf_options_menu", "gamepad", 1) self.input_manager:block_device_except_service("vmf_options_menu", "gamepad", 1)
end end
-- ####################################################################################################################
-- ##### VMF internal functions and variables #########################################################################
-- ####################################################################################################################
vmf.load_vmf_options_view_settings = function()
if vmf:get("vmf_options_scrolling_speed") then
_SCROLL_STEP = _DEFAULT_SCROLL_STEP / 100 * vmf:get("vmf_options_scrolling_speed")
end
end
-- ####################################################################################################################
-- ##### Script #######################################################################################################
-- ####################################################################################################################
vmf.load_vmf_options_view_settings()
@ -3920,7 +3946,7 @@ VMFMod.create_options = function (self, widgets_definition, is_mod_toggable, rea
new_widget_definition.widget_type = current_widget.widget_type -- all new_widget_definition.widget_type = current_widget.widget_type -- all
new_widget_definition.widget_index = new_widget_index -- all [gen] new_widget_definition.widget_index = new_widget_index -- all [gen]
new_widget_definition.widget_level = level -- all [gen] new_widget_definition.widget_level = level -- all [gen]
new_widget_definition.mod_name = self:get_name() -- all [gen] new_widget_definition.mod_name = self:get_name() -- all [gen]
new_widget_definition.setting_name = current_widget.setting_name -- all new_widget_definition.setting_name = current_widget.setting_name -- all
new_widget_definition.text = current_widget.text -- all new_widget_definition.text = current_widget.text -- all
new_widget_definition.tooltip = current_widget.tooltip -- all [optional] new_widget_definition.tooltip = current_widget.tooltip -- all [optional]
@ -4011,43 +4037,6 @@ VMFMod.create_options = function (self, widgets_definition, is_mod_toggable, rea
table.insert(SETTINGS_LIST_WIDGETS_DEFINITIONS, mod_settings_list_widgets_definitions) table.insert(SETTINGS_LIST_WIDGETS_DEFINITIONS, mod_settings_list_widgets_definitions)
end end
if type(vmf:get("options_menu_favorite_mods")) ~= "table" then if type(vmf:get("options_menu_favorite_mods")) ~= "table" then
vmf:set("options_menu_favorite_mods", {}) vmf:set("options_menu_favorite_mods", {})
end end

View file

@ -42,6 +42,13 @@ local options_widgets = {
vmf:localize("show_developer_console_tooltip"), vmf:localize("show_developer_console_tooltip"),
["default_value"] = false ["default_value"] = false
}, },
{
["setting_name"] = "toggle_developer_console",
["widget_type"] = "keybind",
["text"] = vmf:localize("toggle_developer_console"),
["default_value"] = {},
["action"] = "toggle_developer_console"
},
{ {
["setting_name"] = "show_network_debug_info", ["setting_name"] = "show_network_debug_info",
["widget_type"] = "checkbox", ["widget_type"] = "checkbox",
@ -57,14 +64,7 @@ local options_widgets = {
["tooltip"] = vmf:localize("log_ui_renderers_info") .. "\n" .. ["tooltip"] = vmf:localize("log_ui_renderers_info") .. "\n" ..
vmf:localize("log_ui_renderers_info_tooltip"), vmf:localize("log_ui_renderers_info_tooltip"),
["default_value"] = false ["default_value"] = false
}, }
-- {
-- ["setting_name"] = "toggle_developer_console",
-- ["widget_type"] = "keybind",
-- ["text"] = "Toggle Developer Console",
-- ["default_value"] = {},
-- ["action"] = "toggle_developer_console"
-- }
} }
}, },
{ {
@ -148,79 +148,139 @@ local options_widgets = {
["default_value"] = 0 ["default_value"] = 0
} }
} }
},
{
["setting_name"] = "chat_history_enable",
["widget_type"] = "checkbox",
["text"] = vmf:localize("chat_history_enable"),
["tooltip"] = vmf:localize("chat_history_enable") .. "\n" ..
vmf:localize("chat_history_enable_tooltip"),
["default_value"] = true,
["sub_widgets"] = {
{
["setting_name"] = "chat_history_save",
["widget_type"] = "checkbox",
["text"] = vmf:localize("chat_history_save"),
["tooltip"] = vmf:localize("chat_history_save") .. "\n" ..
vmf:localize("chat_history_save_tooltip"),
["default_value"] = true
},
{
["setting_name"] = "chat_history_buffer_size",
["widget_type"] = "numeric",
["text"] = vmf:localize("chat_history_buffer_size"),
["tooltip"] = vmf:localize("chat_history_buffer_size") .. "\n" ..
vmf:localize("chat_history_buffer_size_tooltip"),
["range"] = {10, 200},
["default_value"] = 50
},
{
["setting_name"] = "chat_history_remove_dups",
["widget_type"] = "checkbox",
["text"] = vmf:localize("chat_history_remove_dups"),
["default_value"] = false,
["sub_widgets"] = {
{
["setting_name"] = "chat_history_remove_dups_mode",
["widget_type"] = "dropdown",
["text"] = vmf:localize("chat_history_remove_dups_mode"),
["tooltip"] = vmf:localize("chat_history_remove_dups_mode") .. "\n" ..
vmf:localize("chat_history_remove_dups_mode_tooltip"),
["options"] = {
{text = vmf:localize("settings_last"), value = "last"},
{text = vmf:localize("settings_all"), value = "all"},
},
["default_value"] = "last"
}
}
},
{
["setting_name"] = "chat_history_commands_only",
["widget_type"] = "checkbox",
["text"] = vmf:localize("chat_history_commands_only"),
["tooltip"] = vmf:localize("chat_history_commands_only") .. "\n" ..
vmf:localize("chat_history_commands_only_tooltip"),
["default_value"] = false
}
}
} }
} }
vmf:create_options(options_widgets, false, "Vermintide Mod Framework")
-- ####################################################################################################################
-- ##### VMF internal functions and variables #########################################################################
-- ####################################################################################################################
vmf.on_setting_changed = function (setting_name) vmf.on_setting_changed = function (setting_name)
if setting_name == "vmf_options_scrolling_speed" then if setting_name == "vmf_options_scrolling_speed" then
local ingame_ui_exists, ingame_ui = pcall(function () return Managers.player.network_manager.matchmaking_manager.matchmaking_ui.ingame_ui end) vmf.load_vmf_options_view_settings()
if ingame_ui_exists then
local vmf_options_view = ingame_ui.views["vmf_options_view"]
if vmf_options_view then
vmf_options_view.scroll_step = vmf_options_view.default_scroll_step / 100 * vmf:get(setting_name)
end
end
elseif setting_name == "developer_mode" then elseif setting_name == "developer_mode" then
Managers.mod._settings.developer_mode = vmf:get(setting_name) vmf.load_developer_mode_settings()
Application.set_user_setting("mod_settings", Managers.mod._settings) vmf.load_network_settings()
vmf.load_custom_textures_settings()
vmf.network_debug = vmf:get(setting_name) and vmf:get("show_network_debug_info") vmf.load_dev_console_settings()
vmf.custom_textures_debug = vmf:get(setting_name) and vmf:get("log_ui_renderers_info")
local show_developer_console = vmf:get(setting_name) and vmf:get("show_developer_console")
vmf.toggle_developer_console(show_developer_console)
elseif setting_name == "show_developer_console" then elseif setting_name == "show_developer_console" then
vmf.toggle_developer_console(vmf:get(setting_name)) vmf.load_dev_console_settings()
elseif setting_name == "show_network_debug_info" then elseif setting_name == "show_network_debug_info" then
vmf.network_debug = vmf:get("developer_mode") and vmf:get(setting_name) vmf.load_network_settings()
elseif setting_name == "log_ui_renderers_info" then elseif setting_name == "log_ui_renderers_info" then
vmf.custom_textures_debug = vmf:get("developer_mode") and vmf:get(setting_name) vmf.load_custom_textures_settings()
elseif setting_name == "logging_mode" then elseif setting_name == "ui_scaling" then
vmf.load_ui_scaling_settings()
elseif setting_name == "logging_mode"
or setting_name == "output_mode_echo"
or setting_name == "output_mode_error"
or setting_name == "output_mode_warning"
or setting_name == "output_mode_info"
or setting_name == "output_mode_debug" then
vmf.load_logging_settings() vmf.load_logging_settings()
elseif setting_name == "output_mode_echo" then elseif setting_name == "chat_history_enable"
or setting_name == "chat_history_save"
or setting_name == "chat_history_buffer_size"
or setting_name == "chat_history_remove_dups"
or setting_name == "chat_history_remove_dups_mode"
or setting_name == "chat_history_commands_only" then
vmf.load_logging_settings() vmf.load_chat_history_settings(setting_name == "chat_history_enable" or setting_name == "chat_history_buffer_size" or setting_name == "chat_history_commands_only")
elseif setting_name == "output_mode_error" then
vmf.load_logging_settings()
elseif setting_name == "output_mode_warning" then
vmf.load_logging_settings()
elseif setting_name == "output_mode_info" then
vmf.load_logging_settings()
elseif setting_name == "output_mode_debug" then
vmf.load_logging_settings()
end end
end end
vmf.load_developer_mode_settings = function () --@TODO: maybe move it to somewhere else?
Managers.mod._settings.developer_mode = vmf:get("developer_mode")
Application.set_user_setting("mod_settings", Managers.mod._settings)
end
-- #################################################################################################################### -- ####################################################################################################################
-- ##### Script ####################################################################################################### -- ##### Script #######################################################################################################
-- #################################################################################################################### -- ####################################################################################################################
local mod_developer_mode = Managers.mod._settings.developer_mode vmf:create_options(options_widgets, false, "Vermintide Mod Framework")
local vmf_developer_mode = vmf:get("developer_mode")
if mod_developer_mode ~= vmf_developer_mode then -- first VMF initialization
Managers.mod._settings.developer_mode = vmf_developer_mode -- it will be run only 1 time, when the player launch the game with VMF for the first time
Application.set_user_setting("mod_settings", Managers.mod._settings) if not vmf:get("vmf_initialized") then
vmf.load_logging_settings()
vmf.load_developer_mode_settings()
vmf.load_network_settings()
vmf.load_custom_textures_settings()
vmf.load_dev_console_settings()
vmf.load_chat_history_settings()
vmf.load_ui_scaling_settings()
vmf:set("vmf_initialized", true)
end end

View file

@ -16,16 +16,24 @@ return {
dofile("scripts/mods/vmf/modules/core/chat") dofile("scripts/mods/vmf/modules/core/chat")
dofile("scripts/mods/vmf/modules/core/localization") dofile("scripts/mods/vmf/modules/core/localization")
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/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_menus")
dofile("scripts/mods/vmf/modules/gui/ui_scaling") dofile("scripts/mods/vmf/modules/gui/ui_scaling")
dofile("scripts/mods/vmf/modules/options_menu/vmf_options_view") dofile("scripts/mods/vmf/modules/ui/chat/chat_actions")
dofile("scripts/mods/vmf/modules/ui/options/vmf_options_view")
dofile("scripts/mods/vmf/modules/vmf_options") dofile("scripts/mods/vmf/modules/vmf_options")
dofile("scripts/mods/vmf/modules/mutators/mutator_manager") dofile("scripts/mods/vmf/modules/ui/mutators/mutator_manager")
object.vmf = get_mod("VMF") object.vmf = get_mod("VMF")
object.vmf:hook("ModManager.destroy", function(func, self)
object.vmf.mods_unload_event(true)
func(self)
end)
-- temporary solution: -- temporary solution:
dofile("scripts/mods/vmf/modules/testing_stuff_here") dofile("scripts/mods/vmf/modules/testing_stuff_here")
end, end,
@ -43,12 +51,16 @@ return {
object.vmf.create_network_dictionary() object.vmf.create_network_dictionary()
object.vmf.ping_vmf_users() object.vmf.ping_vmf_users()
object.vmf.all_mods_loaded_event()
object.vmf.all_mods_were_loaded = true object.vmf.all_mods_were_loaded = true
end end
end, end,
on_unload = function(object) on_unload = function(object)
print("VMF:ON_UNLOAD()") print("VMF:ON_UNLOAD()")
object.vmf.save_chat_history()
object.vmf.save_unsaved_settings_to_file()
object.vmf = nil object.vmf = nil
end, end,
@ -59,7 +71,6 @@ return {
object.vmf.delete_keybinds() object.vmf.delete_keybinds()
object.vmf.mods_unload_event() object.vmf.mods_unload_event()
object.vmf.hooks_unload() object.vmf.hooks_unload()
object.vmf.save_unsaved_settings_to_file()
end, end,
on_game_state_changed = function(object, status, state) on_game_state_changed = function(object, status, state)