---------------------------------------------------- -- SamUI v0.3.3 -- Eine vollständige UI-Alternative -- WoW Classic Anniversary TBC -- Interface 20506 -- Build 69110 ---------------------------------------------------- local addon_name, ns = ... ns.addon_name = addon_name ns.version = "v0.3.3" ns.tbc = WOW_PROJECT_ID == WOW_PROJECT_BURNING_CRUSADE_CLASSIC local module_registry = {} local initial_module_order = {} local module_order = {} local registered_phase = {} local initialized_modules = {} ns.module_registry = module_registry ns.module_errors = {} ns.bootstrap_errors = {} function ns:chat_message(message, is_warning) local palette = self.palette if not palette or not DEFAULT_CHAT_FRAME or type(DEFAULT_CHAT_FRAME.AddMessage) ~= "function" then return false end local prefix = palette:wrap("teal", "SamUI " .. self.version .. ": ") local message_token = is_warning and "gold" or "text" DEFAULT_CHAT_FRAME:AddMessage(prefix .. palette:wrap(message_token, tostring(message))) return true end local function error_handler(error_value) return tostring(error_value) end function ns:new_module(name) if type(name) ~= "string" or name == "" then return nil end if module_registry[name] then return nil end local module = { name = name, } module_registry[name] = module return module end function ns:register_initial_module(name) if not module_registry[name] or registered_phase[name] then return false end registered_phase[name] = "initial" initial_module_order[#initial_module_order + 1] = name return true end function ns:register_module(name) if not module_registry[name] or registered_phase[name] then return false end registered_phase[name] = "normal" module_order[#module_order + 1] = name return true end local function initialize_module(name) if initialized_modules[name] then return true end local module = module_registry[name] if not module then return false end local initialize = module.initialize if type(initialize) ~= "function" then initialized_modules[name] = true return true end local success, error_message = xpcall(function() initialize(module) end, error_handler) initialized_modules[name] = true if not success then ns.module_errors[name] = error_message return false end return true end function ns:initialize_initial_modules() for index = 1, #initial_module_order do initialize_module(initial_module_order[index]) end end function ns:initialize_modules() for index = 1, #module_order do initialize_module(module_order[index]) end end local event_frame = CreateFrame("Frame") local event_table = {} local event_order = {} local event_order_index = {} local event_generation = {} local event_dispatch_depth = {} local event_order_dirty = {} ns.event_table = event_table local function compact_event_order(event, listeners) local order = event_order[event] local order_index = event_order_index[event] if not order or not order_index then return end local write_index = 1 local order_count = #order for read_index = 1, order_count do local object = order[read_index] order_index[object] = nil if listeners[object] ~= nil then order[write_index] = object order_index[object] = write_index write_index = write_index + 1 end end for index = write_index, order_count do order[index] = nil end event_order_dirty[event] = nil end local function call_event_listener(object, event, entry, ...) local func = entry[1] local stored_argument_count = entry.argument_count or 0 if stored_argument_count == 0 then return func(object, event, ...) elseif stored_argument_count == 1 then return func(object, event, entry[2], ...) elseif stored_argument_count == 2 then return func(object, event, entry[2], entry[3], ...) elseif stored_argument_count == 3 then return func(object, event, entry[2], entry[3], entry[4], ...) elseif stored_argument_count == 4 then return func(object, event, entry[2], entry[3], entry[4], entry[5], ...) end local event_argument_count = select("#", ...) local callback_arguments = {} local callback_argument_count = 0 for argument_index = 1, stored_argument_count do callback_argument_count = callback_argument_count + 1 callback_arguments[callback_argument_count] = entry[argument_index + 1] end for argument_index = 1, event_argument_count do callback_argument_count = callback_argument_count + 1 callback_arguments[callback_argument_count] = select(argument_index, ...) end return func(object, event, unpack(callback_arguments, 1, callback_argument_count)) end local function dispatch_event(_, event, ...) local listeners = event_table[event] local order = event_order[event] if not listeners or not order then return end local generation = (event_generation[event] or 0) + 1 event_generation[event] = generation event_dispatch_depth[event] = (event_dispatch_depth[event] or 0) + 1 local dispatch_count = #order for index = 1, dispatch_count do local object = order[index] local entry = listeners[object] if entry and (entry.first_generation or 0) <= generation then call_event_listener(object, event, entry, ...) end end local depth = (event_dispatch_depth[event] or 1) - 1 if depth > 0 then event_dispatch_depth[event] = depth return end event_dispatch_depth[event] = nil if event_table[event] == listeners and event_order_dirty[event] then compact_event_order(event, listeners) end end event_frame:SetScript("OnEvent", dispatch_event) function ns:register_event(event, object, func, ...) if type(event) ~= "string" or event == "" or object == nil or type(func) ~= "function" then return false end local listeners = event_table[event] if not listeners then event_frame:RegisterEvent(event) listeners = {} event_table[event] = listeners event_order[event] = {} event_order_index[event] = {} event_generation[event] = 0 end local order = event_order[event] local order_index = event_order_index[event] if order_index[object] == nil then local index = #order + 1 order[index] = object order_index[object] = index end local entry = { func, ..., } entry.argument_count = select("#", ...) local generation = event_generation[event] or 0 if (event_dispatch_depth[event] or 0) > 0 then entry.first_generation = generation + 1 else entry.first_generation = generation end listeners[object] = entry return true end function ns:unregister_event(event, object, func) local listeners = event_table[event] if not listeners then return false end local entry = listeners[object] if not entry or entry[1] ~= func then return false end listeners[object] = nil if not next(listeners) then event_frame:UnregisterEvent(event) event_table[event] = nil event_order[event] = nil event_order_index[event] = nil event_generation[event] = nil event_dispatch_depth[event] = nil event_order_dirty[event] = nil return true end if (event_dispatch_depth[event] or 0) > 0 then event_order_dirty[event] = true else compact_event_order(event, listeners) end return true end local bootstrap = {} local function addon_loaded(_, _, loaded_addon_name) if loaded_addon_name ~= addon_name then return end ns:unregister_event("ADDON_LOADED", bootstrap, addon_loaded) if type(ns.initialize_database) == "function" then local success, error_message = xpcall(function() ns:initialize_database() end, error_handler) if not success then ns.bootstrap_errors.database = error_message end else ns.bootstrap_errors.database = "initialize_database is not available" end ns:initialize_initial_modules() end local function player_login() ns:unregister_event("PLAYER_LOGIN", bootstrap, player_login) ns:initialize_modules() ns:chat_message(ns:get_random_welcome_message()) if type(ns.initialize_base_profiles) == "function" then local success, error_message = xpcall(function() ns:initialize_base_profiles() end, error_handler) if not success then ns.bootstrap_errors.profiles = error_message end end if type(ns.get_active_profile) == "function" then local active_profile = ns:get_active_profile() if active_profile == nil then if type(ns.show_profile_start_window) == "function" then ns:show_profile_start_window() end elseif type(ns.load_profile) == "function" then local success, load_result, load_error = xpcall(function() return ns:load_profile(active_profile) end, error_handler) if not success then ns.bootstrap_errors.active_profile = load_result elseif not load_result then ns.bootstrap_errors.active_profile = load_error or "Profil konnte nicht geladen werden" else ns:chat_message("Einstellungen geladen") end end end end ns:register_event("ADDON_LOADED", bootstrap, addon_loaded) ns:register_event("PLAYER_LOGIN", bootstrap, player_login)