Module:GameData: Difference between revisions

Amend to use alternative data pages
(Initial implementation)
 
(Amend to use alternative data pages)
 
(13 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
-- Given a namespace & local ID, returns a namespaced ID
function p.getNamespacedID(namespace, localID)
if string.find(localID, ':') == nil then
return namespace .. ':' .. localID
else
-- ID already appears to be namespaced
return localID
end
end
-- Given a namespaced ID, returns both the namespace & local ID
function p.getLocalID(ID)
local namespace, localID = nil, nil
local sepIdx = string.find(ID, ':')
if sepIdx == nil then
-- Provided ID doesn't appear to be namespaced
localID = ID
else
namespace = string.sub(ID, 1, sepIdx - 1)
localID = string.sub(ID, sepIdx + 1, string.len(ID))
end
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.
-- If the entity ID is within the cache for the given entity type, then return it.
-- Otherwise, returns nil
-- Otherwise, returns nil
function getCache(entityType, ID)
local function getCache(entityType, ID)
if type(entityType) == 'string' and type(ID) == 'string' then
if type(entityType) == 'string' and type(ID) == 'string' then
local cacheCat = indexCache[entityType]
local cacheCat = indexCache[entityType]
Line 22: Line 75:


-- Sets the cache for entity ID within the given entity type to idx.
-- Sets the cache for entity ID within the given entity type to idx.
function setCache(entityType, ID, 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 type(entityType) == 'string' and type(ID) == 'string' and type(idx) == 'number' then
if indexCache[entityType] == nil then
if indexCache[entityType] == nil then
indexCache[entityType] = {}
indexCache[entityType] = {}
end
end
if indexCache[entityType][ID] == nil then
if indexCache[entityType][ID] == nil then
indexCache[entityType][ID] = idx
indexCache[entityType][ID] = math.floor(idx)
end
end
end
end
end
function p.getCategoryData(entityType)
return GameData[entityType]
end
end


Line 43: 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 74: 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 96: 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 119: Line 186:
end
end


-- TODO Temporary function for testing
-- Sorts the given dataTable by ID into the same order as orderTable
function p.test()
-- keepUnsorted specifies whether unsorted elements are included within the output. Default: true
local t = p.getEntityByID('items', 'melvorF:Tidal_Edge')
--  unsorted elements will be at the end of the array, order is not guaranteed
return 'ok'
-- idKey specifies the ID key to sort upon. Default: id
-- 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)
-- Create index table from orderTable
local orderIdx = {}
for idx, v in ipairs(orderTable) do
orderIdx[v] = idx
end
-- Determine if user-specified or default paramater values are to be used
if type(keepUnsorted) ~= 'boolean' then
keepUnsorted = true
end
if type(idKey) ~= 'string' then
idKey = 'id'
end
if type(orderFunc) ~= 'function' then
orderFunc = function(k1, k2)
local o1, o2 = orderIdx[k1[idKey]], orderIdx[k2[idKey]]
if o1 == nil or o2 == nil then
return false
else
return orderIdx[k1[idKey]] < orderIdx[k2[idKey]]
end
end
end
 
-- Build unsorted result table, removing unsorted elements if requested
local resultTable = {}
local resultItemCount = 0
for idx, v in ipairs(dataTable) do
local keyVal = v[idKey]
if keyVal ~= nil then
if keepUnsorted or orderIdx[keyVal] ~= nil then
resultItemCount = resultItemCount + 1
resultTable[resultItemCount] = v
end
end
end
-- Sort table
table.sort(resultTable, orderFunc)
return resultTable
end
end


return p
return p