Module:GameData: Difference between revisions

Amend to use alternative data pages
(sortByOrderTable: Initial implementation)
(Amend to use alternative data pages)
 
(10 intermediate revisions by the same user not shown)
Line 4: Line 4:
local p = {}
local p = {}


local GameData = mw.loadData('Module:GameData/data')
local GameData1 = mw.loadJsonData('Module:GameData/data')
local GameData2 = mw.loadJsonData('Module:GameData/data2')
-- Combine data into a single object
local GameData = {}
for _, data in ipairs({GameData1, GameData2}) do
for entityType, entityData in pairs(data) do
GameData[entityType] = entityData
end
end
 
local indexCache = {}
local indexCache = {}


-- Expose underlying data should other modules require it
-- Expose underlying data should other modules require it
p.rawData = GameData
p.rawData = GameData
-- If the entity ID is within the cache for the given entity type, then return it.
-- Otherwise, returns nil
local function getCache(entityType, ID)
if type(entityType) == 'string' and type(ID) == 'string' then
local cacheCat = indexCache[entityType]
if cacheCat ~= nil then
return cacheCat[ID]
end
end
end
-- Sets the cache for entity ID within the given entity type to idx.
local function setCache(entityType, ID, idx)
if type(entityType) == 'string' and type(ID) == 'string' and type(idx) == 'number' and idx == math.floor(idx) then
if indexCache[entityType] == nil then
indexCache[entityType] = {}
end
if indexCache[entityType][ID] == nil then
indexCache[entityType][ID] = idx
end
end
end


-- Given a namespace & local ID, returns a namespaced ID
-- Given a namespace & local ID, returns a namespaced ID
Line 55: Line 41:
end
end
return namespace, localID
return namespace, localID
end
local function populateSkillData()
local skillData = {}
for i, skillObj in ipairs(GameData.skillData) do
local _, localID = p.getLocalID(skillObj.skillID)
if localID ~= nil then
skillData[localID] = skillObj.data
end
end
return skillData
end
-- Expose an easy way to reference skill data by skill local ID
p.skillData = populateSkillData()
function p.skillDataTest()
for localID, data in pairs(p.skillData) do
mw.log(localID)
end
end
-- If the entity ID is within the cache for the given entity type, then return it.
-- Otherwise, returns nil
local function getCache(entityType, ID)
if type(entityType) == 'string' and type(ID) == 'string' then
local cacheCat = indexCache[entityType]
if cacheCat ~= nil then
return cacheCat[ID]
end
end
end
-- Sets the cache for entity ID within the given entity type to idx.
local function setCache(entityType, ID, idx)
if type(entityType) == 'string' and type(ID) == 'string' and type(idx) == 'number' then
if indexCache[entityType] == nil then
indexCache[entityType] = {}
end
if indexCache[entityType][ID] == nil then
indexCache[entityType][ID] = math.floor(idx)
end
end
end
end


Line 63: Line 92:
for idx, skill in ipairs(GameData.skillData) do
for idx, skill in ipairs(GameData.skillData) do
if skill.skillID == skillID then
if skill.skillID == skillID then
return skill
return skill.data
end
end
end
end
end
end


-- Takes an entity type & property name/value, returning an object representing the
-- Takes an entity type (or entity list) & property name/value, returning an object representing the
-- entity with the given property (if found). If not found, then nil is returned.
-- entity with the given property (if found). If not found, then nil is returned.
function p.getEntityByProperty(entityType, propName, propValue)
function p.getEntityByProperty(entityType, propName, propValue)
if type(entityType) ~= 'string' then
if type(entityType) ~= 'string' and type(entityType) ~= 'table' then
error('Entity type name must be a string', 2)
error('Entity type name must be a string or table', 2)
elseif type(propName) ~= 'string' then
elseif type(propName) ~= 'string' then
error('Property name must be a string', 2)
error('Property name must be a string', 2)
end
end
local entData = GameData[entityType]
local entData, useCache = nil, false
if type(entityType) == 'string' then
entData = GameData[entityType]
useCache = true
else
-- Function was passed a table of entities rather than a entity type
entData = entityType
end
if entData == nil then
if entData == nil then
error('No such entity type: ' .. entityType, 2)
error('No such entity type: ' .. entityType, 2)
elseif type(entData) ~= 'table' then
elseif type(entData) ~= 'table' then
error('Entity data is not a table: ' .. entityType, 2)
error('Entity data is not a table: ' .. entityType, 2)
elseif type(entData[1]) ~= 'table' or entData[1].id == nil then
elseif type(entData[1]) ~= 'table' or entData[1][propName] == nil then
error('Entity data is not composed of entities: ' .. entityType, 2)
error('Entity data is not composed of entities: ' .. entityType, 2)
end
end
-- Check if this ID is already cached
-- Check if this ID is already cached
if propName == 'id' then
if propName == 'id' and useCache then
local cacheIdx = getCache(entityType, propValue)
local cacheIdx = getCache(entityType, propValue)
if cacheIdx ~= nil then
if cacheIdx ~= nil then
Line 94: Line 130:
-- Cache miss or property isn't ID, so scan the entity data sequentially
-- Cache miss or property isn't ID, so scan the entity data sequentially
for idx, entity in ipairs(entData) do
for idx, entity in ipairs(entData) do
setCache(entityType, entity.id, idx)
if useCache then
setCache(entityType, entity.id, idx)
end
if entity[propName] == propValue then
if entity[propName] == propValue then
return entity
return entity
Line 116: Line 154:
local result = {}
local result = {}
local entityCount = 0
local entityCount = 0
if type(entityType) ~= 'string' then
if type(entityType) ~= 'string' and type(entityType) ~= 'table' then
error('Entity type name must be a string', 2)
error('Entity type name must be a string or table', 2)
elseif type(checkFunc) ~= 'function' then
elseif type(checkFunc) ~= 'function' then
error('Check function name must be a function', 2)
error('Check function name must be a function', 2)
end
end
local entData = GameData[entityType]
local entData, useCache = nil, false
if entData == nil then
if type(entityType) == 'string' then
entData = GameData[entityType]
useCache = true
else
-- Function was passed a table of entities rather than a entity type
entData = entityType
end
if entData == nil and type(entityType) == 'string' then
error('No such entity type: ' .. entityType, 2)
error('No such entity type: ' .. entityType, 2)
elseif type(entData) ~= 'table' then
elseif type(entData) ~= 'table' then
error('Entity data is not a table: ' .. entityType, 2)
error('Entity data is not a table: ' .. entityType, 2)
elseif type(entData[1]) ~= 'table' or entData[1].id == nil then
elseif type(entData[1]) ~= 'table' then
error('Entity data is not composed of entities: ' .. entityType, 2)
error('Entity data is not composed of entities: ' .. entityType, 2)
end
end
for idx, entity in ipairs(entData) do
for idx, entity in ipairs(entData) do
setCache(entityType, entity.id, idx)
if useCache then
setCache(entityType, entity.id, idx)
end
if checkFunc(entity) then
if checkFunc(entity) then
entityCount = entityCount + 1
entityCount = entityCount + 1
Line 144: Line 191:
-- idKey specifies the ID key to sort upon. Default: id
-- idKey specifies the ID key to sort upon. Default: id
-- orderFunc specifies a custom order function if the default behaviour is not desired
-- orderFunc specifies a custom order function if the default behaviour is not desired
-- Example - Sorts combat areas into the same order as displayed in game:
--   p.sortByOrderTable(p.rawData.combatAreas, p.rawData.combatAreaDisplayOrder)
function p.sortByOrderTable(dataTable, orderTable, keepUnsorted, idKey, orderFunc)
function p.sortByOrderTable(dataTable, orderTable, keepUnsorted, idKey, orderFunc)
    -- Create index table from orderTable
-- Create index table from orderTable
    local orderIdx = {}
local orderIdx = {}
    for idx, v in ipairs(orderTable) do
for idx, v in ipairs(orderTable) do
        orderIdx[v] = idx
orderIdx[v] = idx
    end
end
    -- Determine if user-specified or default paramater values are to be used
-- Determine if user-specified or default paramater values are to be used
    if type(keepUnsorted) ~= 'boolean' then
if type(keepUnsorted) ~= 'boolean' then
        keepUnsorted = true
keepUnsorted = true
    end
end
    if type(idKey) ~= 'string' then
if type(idKey) ~= 'string' then
        idKey = 'id'
idKey = 'id'
    end
end
    if type(orderFunc) ~= 'function' then
if type(orderFunc) ~= 'function' then
        orderFunc = function(k1, k2)
orderFunc = function(k1, k2)
            return orderIdx[k1[idKey]] < orderIdx[k2[idKey]]
local o1, o2 = orderIdx[k1[idKey]], orderIdx[k2[idKey]]
        end
if o1 == nil or o2 == nil then
    end
return false
else
return orderIdx[k1[idKey]] < orderIdx[k2[idKey]]
end
end
end


    -- Build unsorted result table, removing unsorted elements if requested
-- Build unsorted result table, removing unsorted elements if requested
    local resultTable = {}
local resultTable = {}
    local resultItemCount = 0
local resultItemCount = 0
    for idx, v in ipairs(dataTable) do
for idx, v in ipairs(dataTable) do
        local keyVal = v[idKey]
local keyVal = v[idKey]
        if keyVal ~= nil then
if keyVal ~= nil then
            if keepUnsorted or orderIdx[keyVal] ~= nil then
if keepUnsorted or orderIdx[keyVal] ~= nil then
                resultItemCount = resultItemCount + 1
resultItemCount = resultItemCount + 1
                resultTable[resultItemCount] = v
resultTable[resultItemCount] = v
            end
end
        end
end
    end
end
    -- Sort table
-- Sort table
    table.sort(resultTable, orderFunc)
table.sort(resultTable, orderFunc)
    return resultTable
return resultTable
end
end


return p
return p