Rewrote custom textures module

This commit is contained in:
Unknown 2018-03-08 02:08:47 +03:00
parent c861e19f2e
commit e688b5bd91

View file

@ -1,90 +1,252 @@
local vmf = get_mod("VMF") local vmf = get_mod("VMF")
local injected_materials = {} local _CUSTOM_NONE_ATLAS_TEXTURES = {}
local none_atlas_textures = {} local _CUSTOM_UI_ATLAS_SETTINGS = {}
-- @TODO: can several materials be specified via 1 material file? Figure it out. local _UI_RENDERERS = {}
function inject_material(material_path, material_name, ...) local _INJECTED_MATERIALS = {}
--print("[FUCK]: Mods.gui.inject_material " .. material_path .. material_name) -- ####################################################################################################################
-- ##### Local functions ##############################################################################################
-- ####################################################################################################################
local material_users = {...} local original_gasbtn_function = UIAtlasHelper.get_atlas_settings_by_texture_name
if #material_users == 0 then local function check_texture_availability(mod, texture_name)
material_users = {"all"}
end
for _, material_user in ipairs(material_users) do local texture_exists, texture_settings = pcall(original_gasbtn_function, texture_name)
if not injected_materials[material_user] then if texture_exists then
injected_materials[material_user] = {}
if type(texture_settings) == "nil" then
mod:error("(custom texture/atlas): texture name '%s' is already used by Fatshark in 'none_atlas_textures'", texture_name)
else
mod:error("(custom texture/atlas): texture name '%s' is already used by Fatshark in atlas '%s'", texture_name, tostring(texture_settings.material_name))
end end
table.insert(injected_materials[material_user], material_path) return false
end end
none_atlas_textures[material_name] = true if _CUSTOM_NONE_ATLAS_TEXTURES[texture_name] then
mod:error("(custom texture/atlas): texture name '%s' is already used by the mod '%s' as none atlas texture", texture_name, _CUSTOM_NONE_ATLAS_TEXTURES[texture_name])
return false
end
if _CUSTOM_UI_ATLAS_SETTINGS[texture_name] then
texture_settings = _CUSTOM_UI_ATLAS_SETTINGS[texture_name]
mod:error("(custom texture/atlas): texture name '%s' is already used by the mod '%s' in atlas '%s'", texture_name, texture_settings.mod_name, tostring(texture_settings.material_name))
return false
end
return true
end end
-- ####################################################################################################################
-- ##### VMFMod #######################################################################################################
-- ####################################################################################################################
--table.dump(injected_materials, "injected_materials", 2) VMFMod.custom_textures = function (self, ...)
for i, texture_name in ipairs({...}) do
if type(texture_name) == "string" then
if check_texture_availability(self, texture_name) then
_CUSTOM_NONE_ATLAS_TEXTURES[texture_name] = self:get_name()
end
else
self:error("(custom_textures): all arguments should have the string type, but the argument #%s is %s", i, type(texture_name))
end
end
end
VMFMod.custom_atlas = function (self, material_settings_file, material_name, masked_material_name, point_sample_material_name,
masked_point_sample_material_name, saturated_material_name)
-- @TODO: this check is legit... is it?
if type(material_settings_file) ~= "string" or
type(material_name) ~= "string" or
type(masked_material_name) ~= "string" or
type(point_sample_material_name) ~= "string" or
type(masked_point_sample_material_name) ~= "string" or
type(saturated_material_name) ~= "string" then
self:error("(custom_atlas): all the arguments have to have the string type")
return
end
local material_settings = self:dofile(material_settings_file)
if material_settings then
local mod_name = self:get_name()
for texture_name, texture_settings in pairs(material_settings) do
if check_texture_availability(self, texture_name) then
texture_settings.mod_name = mod_name
texture_settings.material_name = material_name
texture_settings.masked_material_name = masked_material_name
texture_settings.point_sample_material_name = point_sample_material_name
texture_settings.masked_point_sample_material_name = masked_point_sample_material_name
texture_settings.saturated_material_name = saturated_material_name
_CUSTOM_UI_ATLAS_SETTINGS[texture_name] = texture_settings
end
end
else
self:error("(custom_atlas): can't load 'material_settings'")
end
end
VMFMod.inject_materials = function (self, ui_renderer_creator, ...)
if type(ui_renderer_creator) ~= "string" then
self:error("(inject_materials): argument 'ui_renderer_creator' should have the string type, not %s", type(ui_renderer_creator))
return
end
local injected_materials_list = _INJECTED_MATERIALS[ui_renderer_creator] or {}
local can_inject = true
for i, new_injected_material in ipairs({...}) do
if type(new_injected_material) == "string" then
can_inject = true
-- check if injected_materials_list already contains current material
for _, injected_material in ipairs(injected_materials_list) do
if new_injected_material == injected_material then
can_inject = false
break
end
end
if can_inject then
table.insert(injected_materials_list, new_injected_material)
end
else
self:error("(inject_materials): all arguments should have the string type, but the argument #%s is %s", i + 1, type(new_injected_material))
end
end
_INJECTED_MATERIALS[ui_renderer_creator] = injected_materials_list
-- recreate GUIs with injected materials for ui_renderers created by 'ui_renderer_creator'
for ui_renderer, _ in pairs(_UI_RENDERERS) do
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 _, injected_material in ipairs(injected_materials_list) do
table.insert(new_materials_list, "material")
table.insert(new_materials_list, injected_material)
end
World.destroy_gui(ui_renderer.world, ui_renderer.gui)
World.destroy_gui(ui_renderer.world, ui_renderer.gui_retained)
ui_renderer.gui = World.create_screen_gui(ui_renderer.world, "immediate", unpack(new_materials_list))
ui_renderer.gui_retained = World.create_screen_gui(ui_renderer.world, unpack(new_materials_list))
end
end
end
-- ####################################################################################################################
-- ##### Hooks ########################################################################################################
-- ####################################################################################################################
local ui_renderer_creating = false
vmf:hook("UIRenderer.create", function(func, world, ...) vmf:hook("UIRenderer.create", function(func, world, ...)
-- FINDING OUT WHO CREATED UI_RENDERER
local ui_renderer_creator = nil local ui_renderer_creator = nil
-- extract the part with actual callstack local callstack = debug.traceback()
local callstack = Script.callstack():match('Callstack>(.-)<') -- get the name of lua script which called 'UIRenderer.create'
if callstack then -- it's always the 3rd string of the 'debug.traceback()' output
local i = 0
-- get the name of lua script which called 'UIRenderer.create' for s in callstack:gmatch("(.-)\n") do
-- it's always the 4th string of callstack ([ ] [0] [1] >[2]<) i = i + 1
-- print(callstack) -- @DEBUG if i == 3 then
local i = 0 ui_renderer_creator = s:match("([^%/]+)%.lua:")
for s in callstack:gmatch("(.-)\n") do break
i = i + 1
if i == 4 then
ui_renderer_creator = s:match("([^%/]+)%.lua")
break --@TODO: uncomment after debugging or ... (?)
end
--EchoConsole(s) -- @DELETEME
end end
end end
if ui_renderer_creator then if not ui_renderer_creator then
print("UI_RENDERER CREATED BY: " .. ui_renderer_creator) -- @DEBUG print(Script.callstack())
else vmf:error("(UIRenderer.create): ui_renderer_creator not found. You're never supposed to see this message. " ..
--EchoConsole("You're never supposed to see this.") "If you see this, please, save the game log and report about this incident to the VMF team.")
--assert(true, "That's not right. That's not right at all!")
--EchoConsole(callstack)
return func(world, ...) return func(world, ...)
end end
-- CREATING THE LIST OF TEXTURES FOR THE NEW UI_RENDERER
local ui_renderer_materials = {...} local ui_renderer_materials = {...}
if injected_materials[ui_renderer_creator] then if _INJECTED_MATERIALS[ui_renderer_creator] then
for _, material in ipairs(injected_materials[ui_renderer_creator]) do for _, injected_material in ipairs(_INJECTED_MATERIALS[ui_renderer_creator]) do
table.insert(ui_renderer_materials, "material") table.insert(ui_renderer_materials, "material")
table.insert(ui_renderer_materials, material) table.insert(ui_renderer_materials, injected_material)
end end
end end
if injected_materials["all"] then -- DEBUG INFO
for _, material in ipairs(injected_materials["all"]) do
table.insert(ui_renderer_materials, "material") print("UI_RENDERER CREATED BY: " .. ui_renderer_creator) -- @DEBUG
table.insert(ui_renderer_materials, material) vmf:dump(ui_renderer_materials, "UI_RENDERER MATERIALS", 1) -- @DEBUG
end
-- 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))
_UI_RENDERERS[ui_renderer] = true
ui_renderer.vmf_data.original_materials = {...}
ui_renderer.vmf_data.ui_renderer_creator = ui_renderer_creator
return ui_renderer
end)
vmf:hook("MakeTableStrict", function(func, t)
if ui_renderer_creating then
t.vmf_data = {}
ui_renderer_creating = false
end end
table.dump(ui_renderer_materials, "UI_RENDERER MATERIALS", 2) -- @DEBUG return func(t)
end)
return func(world, unpack(ui_renderer_materials))
vmf:hook("UIRenderer.destroy", function(func, self, world)
_UI_RENDERERS[self] = nil
func(self, world)
end)
vmf:hook("UIAtlasHelper.has_atlas_settings_by_texture_name", function(func, texture_name)
if _CUSTOM_UI_ATLAS_SETTINGS[texture_name] then
return true
end
return func(texture_name)
end) end)
vmf:hook("UIAtlasHelper.get_atlas_settings_by_texture_name", function(func, texture_name) vmf:hook("UIAtlasHelper.get_atlas_settings_by_texture_name", function(func, texture_name)
if none_atlas_textures[texture_name] then if _CUSTOM_NONE_ATLAS_TEXTURES[texture_name] then
return return
end end
if _CUSTOM_UI_ATLAS_SETTINGS[texture_name] then
return _CUSTOM_UI_ATLAS_SETTINGS[texture_name]
end
return func(texture_name) return func(texture_name)
end) end)