[Custom Views] Complete overhaul (basic)

This commit is contained in:
Azumgi 2018-11-01 10:45:00 +03:00
parent 0b7af2d48b
commit 199a174a57
5 changed files with 227 additions and 229 deletions

View file

@ -215,7 +215,7 @@ local function perform_keybind_action(data, is_pressed)
call_function(data.mod, data.function_name, is_pressed)
return true
elseif data.type == "view_toggle" and data.mod:is_enabled() then
vmf:echo("KEYBIND [VIEW_TOGGLE] " .. (is_pressed and "PRESSED" or "RELEASED") .. ": " .. data.view_name)
vmf.keybind_toggle_view(data.view_name, can_perform_action)
return true
end
end

View file

@ -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("VMF")
local original_is_blocked = input_service:is_blocked()
if original_is_blocked then
Managers.input:device_unblock_service("keyboard", 1, "VMF")
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, "VMF")
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

View file

@ -0,0 +1,218 @@
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 functions ###############################################################################################
-- #####################################################################################################################
local function find_view_owner(view_name)
end
local function find_transition_owner(transition_name)
end
-- Throws error.
local function inject_elements(view_name)
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
-- @TODO: throw error
end
for transition_name, _ in pairs(transitions) do
if _ingame_ui_transitions[transition_name] then
-- @TODO: throw error
end
end
-- Initialize and inject view.
local success, view = vmf.xpcall(mod, "calling init_view_function", init_view_function, _ingame_ui.ingame_ui_context)
if success then
_ingame_ui.views[view_name] = view
else
-- @TODO: throw error
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_elements(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.xpcall_no_return_values(view_data.mod, "(custom menus) destroy view", view.destroy)
end
_ingame_ui.views[view_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
-- Remove injected transitions.
for _, view_data in pairs(_views_data) do
for transition_name, _ in pairs(view_data.view_transitions) do
_ingame_ui_transitions[transition_name] = nil
end
end
end
-- Throws error.
-- Make, so blocked transitions can be only the one from this view, so they won't need further checks
local function validate_view_data(view_data)
end
-- #####################################################################################################################
-- ##### VMFMod ########################################################################################################
-- #####################################################################################################################
function VMFMod:handle_transition(transition_name, transition_params, fade)
if _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
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
_ingame_ui:transition_with_fade(transition_name, transition_params)
else
_ingame_ui:handle_transition(transition_name, transition_params)
end
return true
end
end
function VMFMod:register_view(view_data)
if vmf.check_wrong_argument_type(self, "register_view", "view_data", view_data, "table") then
return
end
if vmf.catch_errors(self, "(register_view) view data validating: %s", validate_view_data, view_data) then
return
end
_views_data[view_data.view_name] = {
mod = self,
view_settings = table.clone(view_data.view_settings),
view_transitions = table.clone(view_data.view_transitions)
}
if _ingame_ui then
if vmf.catch_errors(self, "(custom views) view injection: %s", inject_elements, view_data.view_name) then
_views_data[view_data.view_name] = nil
end
end
end
-- #####################################################################################################################
-- ##### Hooks #########################################################################################################
-- #####################################################################################################################
vmf:hook_safe(IngameUI, "init", function(self)
_ingame_ui = self
for view_name, _ in pairs(_views_data) do
if vmf.catch_errors(self, "(custom views) view injection: %s", inject_elements, view_name) then
_views_data[view_name] = nil
end
end
end)
vmf:hook_safe(IngameUI, "destroy", function()
_ingame_ui = nil
remove_injected_elements(false)
end)
-- #####################################################################################################################
-- ##### VMF internal functions and variables ##########################################################################
-- #####################################################################################################################
function vmf.remove_custom_views()
remove_injected_elements(true)
end
function vmf.keybind_toggle_view(view_name, can_be_opened)
--@TODO: check if there's the custom view at all. If not, show error.
if _ingame_ui then
local mod = _views_data[view_name].mod
local keybind_transitions = _views_data[view_name].view_settings.keybind_transitions
if not _ingame_ui.menu_suspended then
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)
end
elseif can_be_opened 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)
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

View file

@ -4288,32 +4288,16 @@ local view_data = {
},
blocked_transitions = {
inn = {},
ingame = {
--vmf_options_view = true,
--vmf_options_view_force = true
ingame = {}
},
keybind_transitions = {
open_view_transition = "vmf_options_view",
close_view_transition = "exit_menu",
}
},
hotkey_name = "open_vmf_options",
hotkey_action_name = "open_vmf_options",
hotkey_transition_name = "vmf_options_view",
transition_fade = false
},
view_transitions = {
vmf_options_view = function (self)
self.current_view = "vmf_options_view"
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
}
}
@ -4435,7 +4419,7 @@ end
vmf.initialize_vmf_options_view = function ()
vmf:register_new_view(view_data)
vmf:register_view(view_data)
_button_injection_data.mod_options_button_disabled = false
end

View file

@ -31,7 +31,7 @@ function vmf_mod_object:init()
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_menus")
dofile("scripts/mods/vmf/modules/gui/custom_views")
dofile("scripts/mods/vmf/modules/gui/ui_scaling")
dofile("scripts/mods/vmf/modules/ui/chat/chat_actions")
dofile("scripts/mods/vmf/modules/ui/options/vmf_options_view")
@ -57,7 +57,6 @@ end
function vmf_mod_object:update(dt)
vmf.mods_update_event(dt)
vmf.check_keybinds()
vmf.check_custom_menus_close_keybinds(dt)
vmf.execute_queued_chat_command()
if VT1 then vmf.check_mutators_state() end
@ -88,9 +87,9 @@ end
function vmf_mod_object:on_reload()
print("VMF:ON_RELOAD()")
vmf.disable_mods_options_button()
vmf.close_opened_custom_menus()
if VT1 then vmf.reset_map_view() end
vmf.mods_unload_event(false)
vmf.remove_custom_views()
vmf.hooks_unload()
vmf.reset_guis()
end