1
votes

I'm working on an Addon rewrite, basically turning the old addon Wtacher for WildStar into a newer version that's more easy to maintain due a new modular structure. The original author gave me permission for this, but told me to rewrite the addon to understand it better, as I'm quite new to this.

So the original Addon can be found here: http://www.curse.com/ws-addons/wildstar/221782-watcher

My source code can be found here: https://github.com/NekoNova/WatcherEx

The error message I am getting ingame is the following:

...aming\NCSOFT\WildStar\Addons\WatcherEx\WatcherEx.lua:1433: bad argument #1 to 'ipairs' (table expected, got nil) stack trace: [C]: in function 'ipairs' ...aming\NCSOFT\WildStar\Addons\WatcherEx\WatcherEx.lua:1433: in function 'FillFiltersList' ...aming\NCSOFT\WildStar\Addons\WatcherEx\WatcherEx.lua:886: in function <...aming\NCSOFT\WildStar\Addons\WatcherEx\WatcherEx.lua:867>

So I took a look at my source code at the mentioned lines, and basically this piece of code is causing problems:

-- Fills the list of Filters available to be used in the Addon.
function WatcherEx:FillFiltersList()
    if self.wndMain == nil then
        return 
    end

    local filtersList = self.wndMain:FindChild("filters_list")
    filtersList:DestroyChildren()

    for i, filterClass in ipairs(self.tFilters) do
        local filterItem = Apollo.LoadForm(self.xmlDoc, "filter_item", filtersList, self)
        filterItem:SetData({ filter = filterClass })
        filterItem:FindChild("name"):SetText(filterClass.name)
    end

    return filtersList:ArrangeChildrenVert()
end

So basically I try to use my internal tFilters variable, but it's nil and should be a table. As I said, I'm quite new to Lua programming for games, but from what I understand, I probably have something wrong set up in my __init metafunction, as I copied this from the original and tries to clean this a bit. This is code metatable code:

function WatcherEx:new(tObject)
    tObject = tObject or {}
    setmetatable(tObject, self)
    self.__index = self

    -- Initialization
    self.tSettings = {}
    self.tDefaults = {}
    self.tAbilities = {}
    self.tInnates = {}
    self.tEngineerSpells = {}
    self.tActiveRules = {}

    local tClass = setmetatable({
        __init = function(self)         
            self.tActiveRules = { }
            self.bUnlockAll = false
            self.eventsHidden = nil
            self.tFilters = {
                AvailabilityFilter,
                TimeFilter,
                CombatFilter,
                ActionSetFilter,
                SpecialFilter,
                HPFilter,
                MPFilter,
                ShieldFilter,
                ChargeFilter,
                ResourcesFilter,
                BuffFilter,
                LuaFilter}
        end,
        __base = self,
        __name = "WatcherEx"
    }, {
        __index = self,
        __call = function(cls, ...)
            local tTable = setmetatable({}, self)
            cls.__init(tTable, ...)
            return tTable
        end})

    self.__class = tClass
    return tObject
end

Could someone tell me what I did wrong, and explain the problem? I'm trying to learn more about Lua, but this part about inheritance and metaclasses is a bit confusing.

EDIT: When I look at it now, I'm actually thinking I can cut out the metatable structure and just set the variables directly as members of my WatcherEx Table....

1
My guess is __init never got called and so the tFilter is never set. Stick a print in there to see if that's the case. A second guess is that the outter self is different from the inner self. - greatwolf
I'll try the Print function and see if it does anything - codingbunny

1 Answers

0
votes

Okay, finally figured it out....

Here's a snippet of my AvailabilityFilter Class that inherits from BaseFilter and now my fields are properly set through my metatables:

local AvailabilityFilter = {}
local AvailabilityFilterClass = {
    __init = function(self, ...) return BaseFilter.__init(self, ...) end,
    __base = AvailabilityFilter,
    __name = "AvailabilityFilter",
    __parent = BaseFilter
}
local AvailabilityFilterClassMt = {
    __index = function(cls, strName)
                local val = rawget(AvailabilityFilter, strName)

                if val == nil then
                    return BaseFilter[strName]
                else
                    return val
                end
            end,
    __call = function(cls, ...)
                local _self = setmetatable({}, AvailabilityFilter)  
                cls.__init(_self, ...)
                return _self
            end
}
AvailabilityFilter.mt = {}
AvailabilityFilter.tDefaults = {
    strName = "Availability",
    strWindowName = "AvailabilityFilter",
    bInActionSet = true,
    tParent = BaseFilter
}
AvailabilityFilter.mt.__index = AvailabilityFilter.tDefaults
-----------------------------------------------------------------------------------------------
-- Constructor
-----------------------------------------------------------------------------------------------
function AvailabilityFilter:new()
    local tInstance = {}

    setmetatable(AvailabilityFilter.mt, BaseFilter.__base)
    setmetatable(tInstance, AvailabilityFilter.mt)
    setmetatable(AvailabilityFilterClass, AvailabilityFilterClassMt)

    tInstance.__class = AvailabilityFilterClass

    if BaseFilter.__inherited then
        BaseFilter.__inherited(BaseFilter, AvailabilityFilterClass)
    end

    return tInstance
end

Basically what I did was:

  • Create BaseFilter
  • Create metatable for it
  • Create default values table for it
  • Create new object + metatable
  • link them: Object -> object metatable -> basefilter meta table

And now it works:

> a = _G["WatcherExLibs"]["ActionSetFilter"].new()
inspect a.strName
"Action Set"