canary/data/modules/scripts/gamestore/catalog_loader.lua
Eduardo Dantas 61d0b6e9db
refactor: add gamestore catalog modules (#3738)
This refactors a comprehensive set of modules for the GameStore system,
including constants, helpers, and parsers. The changes establish a
robust foundation for handling store offers, user actions, and
transactions in a modular and maintainable way. The most important
changes are the addition of a detailed constants file, helper functions
for offer handling, and a parser module that manages all store-related
protocol events and purchase logic.

**GameStore System Foundation**

* Added a new `gamestore.constants.lua` file containing all core
constants for the GameStore, such as offer types, sub-actions, action
types, coin types, error codes, packet codes, default values,
descriptions, and item limits. This centralizes configuration and
improves maintainability.

**Helper Functions**

* Introduced `gamestore.helpers.lua` with utility functions for
converting offer types to display types and determining if an offer
requires configuration, improving code reuse and clarity in offer
handling.

**Store Event and Purchase Parsing**

* Added `gamestore.parsers.lua` which handles all GameStore protocol
events, including opening the store, searching offers, buying offers,
transferring coins, and transaction history. This module coordinates
with helpers and senders to process requests and responses, including
error handling and purchase validation.

These changes collectively lay out the structure for a feature-rich,
extensible GameStore system, making future enhancements and debugging
easier.

---------

Co-authored-by: GitHub Actions <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-06 12:33:07 -03:00

96 lines
3.4 KiB
Lua

local loader = {}
local categories = {}
local function ensureType(value, expectedType, context)
if type(value) ~= expectedType then
error(string.format("Invalid %s: expected %s but got %s", context, expectedType, type(value)))
end
end
local function ensureArrayOfStrings(list, context)
ensureType(list, "table", context)
if #list == 0 then
error(string.format("%s must not be empty", context))
end
for index, entry in ipairs(list) do
if type(entry) ~= "string" then
error(string.format("Invalid %s[%d]: expected string but got %s", context, index, type(entry)))
end
end
end
local function ensureBoolean(value, context)
if type(value) ~= "boolean" then
error(string.format("Invalid %s: expected boolean but got %s", context, type(value)))
end
end
local function ensureOptionalString(value, context)
if value ~= nil and type(value) ~= "string" then
error(string.format("Invalid %s: expected string but got %s", context, type(value)))
end
end
function loader.registerOffer(categoryName, offer, offerIndex)
offerIndex = offerIndex or #offer
if type(offer) ~= "table" then
error(string.format("Invalid offer in %s at position %d", categoryName, offerIndex))
end
ensureArrayOfStrings(offer.icons, string.format("%s offer %d icons", categoryName, offerIndex))
ensureType(offer.name, "string", string.format("%s offer %d name", categoryName, offerIndex))
ensureType(offer.price, "number", string.format("%s offer %d price", categoryName, offerIndex))
if offer.id ~= nil and type(offer.id) ~= "number" then
error(string.format("Invalid %s offer %d id: expected number but got %s", categoryName, offerIndex, type(offer.id)))
end
if offer.type ~= nil and type(offer.type) ~= "number" then
error(string.format("Invalid %s offer %d type: expected number but got %s", categoryName, offerIndex, type(offer.type)))
end
if offer.coinType ~= nil and type(offer.coinType) ~= "number" then
error(string.format("Invalid %s offer %d coinType: expected number but got %s", categoryName, offerIndex, type(offer.coinType)))
end
GameStore.normalizeOffer(offer)
return offer
end
function loader.registerCategory(category, source)
source = source or "catalog"
if type(category) ~= "table" then
error(string.format("Invalid Game Store category from %s", source))
end
ensureArrayOfStrings(category.icons, string.format("%s.icons", source))
ensureType(category.name, "string", string.format("%s.name", source))
ensureBoolean(category.rookgaard, string.format("%s.rookgaard", source))
ensureOptionalString(category.parent, string.format("%s.parent", source))
if category.subclasses ~= nil then
ensureArrayOfStrings(category.subclasses, string.format("%s.subclasses", source))
end
if category.offers == nil and category.subclasses == nil then
error(string.format("Category %s must define offers or subclasses", category.name))
end
if category.offers ~= nil then
ensureType(category.offers, "table", string.format("%s.offers", source))
local normalizedOffers = {}
for index, offer in ipairs(category.offers) do
normalizedOffers[#normalizedOffers + 1] = loader.registerOffer(category.name, offer, index)
end
category.offers = normalizedOffers
end
category.state = GameStore.resolveState(category.state, string.format("%s.state", category.name))
categories[#categories + 1] = category
return category
end
function loader.getCategories()
return categories
end
return loader