Mods IAP Shop Mod - funovus/editor-wiki GitHub Wiki
The IAP Shop Mod is used to create and manage in-game shop UI for IAP and currency spending.
- Create and manage in-game shop page UI
- Hookup shop items as IAP or custom currency (such as gems)
- Customizable UI for shop items via XML
- Supports portrait and landscape games
Need a feature prioritized or a feature missing from this list? Let @coffee know!
Download the demo maps HERE or play them on the arcade:
- To use this mod, add the
shop
registry module to your project using the latest version^1.0.0
.
Shop Mod 2.0.0 has some significant changes that break compatibility with earlier versions. Here are the key changes to look out for when upgrading from an earlier version.
- Initialize the shop ui with shop.NewShopUI() instead of NewLandscapeShopUI or NewPortraitShopUI.
- Initialize the shop sections and default items with ui.shop:Initialize() instead of creating sections and items individually.
- Update shop.InitializeIAP() parameters as table keys.
- Get product items data with item_data:GetItemsData() instead of
item_data.items
. - Get product price data with item_data:GetPriceData() instead of
item_data.price
. - Replace any direct local calls to OnAnyItemPurchase() with shop.OnAnyItemPurchase.
- Customize item layouts by adding and referencing custom XML and remove any item:UpdateSize() or item:UpdateWidthPreset() calls.
For ease of use, the shop layout (as created by NewShopUI will be referenced as ui.shop
throughout this documentation.
The following functions can be used such as:
local shop = require("shop")
local ui = {
root = DCEI.GetUiRoot()
}
-- product definitions
local product_list = {
{
product_id = "com.wildsky.example.iap.gold01",
label = "Handful of Gold",
display = "shop_gold_lv2",
price = { usd = 2.99 },
items = { gold = 1000 }
},
{
product_id = "com.wildsky.example.iap.gold02",
label = "Barrel of Gold",
display = "shop_gold_lv4",
price = { usd = 4.99 },
items = { gold = 5000 }
}
}
-- initialize IAP items
shop.InitializeIAP({
on_purchase_attempt_callback = AttemptAnyItemPurchase,
on_purchase_success_callback = OnAnyItemPurchase,
product_list = product_list,
})
-- creates a new shop UI
ui.shop = shop.NewShopUI({ parent = ui.root })
-- initializes a shop with a "Gold" section and gold items
local shop_data = {
{
name = "gold",
display_name = "Gold",
rows = {
{
"com.wildsky.example.iap.gold01",
"com.wildsky.example.iap.gold02",
}
}
}
}
ui.shop:Initialize(shop_data)
-- show the shop after it's been initialized
ui.shop:Show()
Shows the in-game shop UI.
Hides the in-game shop UI. Note that is automatically called when the close button (ui.shop.CloseButton
) on the upper right of the shop UI is pressed.
Initializes the shop layout and generates the shop's sections and starting items. The shop_data
parameter should be a list of section_data
tables that describe each shop section.
In portrait games, shop sections are created in a vertical list separated by banners. In landscape games, shop sections are created as individual shop tabs. Whether a shop is landscape or portrait is automatically determined by the resolution of the game window.
local shop_data = {
{
name = "bundles",
display_name = "Value Packs",
navigation = {
use_display_name = true,
},
rows = {
{
"com.wildsky.test.iap.bundle.starter01"
}
},
custom = {
layout = "Portrait/Shop/Section_StarterPack"
}
},
{
name = "chests",
display_name = "Chests",
navigation = {
use_display_name = true,
},
display_timer = {
label = "Next free chest in:"
},
rows = {
{
"com.wildsky.test.shop.chest01",
"com.wildsky.test.shop.chest02"
}
}
},
}
ui.shop:Initialize(shop_data)
-
string
name
defines the section name so it can be referenced elsewhere. -
string
display_name
determines the text to display on the shop section banner. This is a separate value fromname
so that it can use localized text. -
table
rows
a list ofrow
tables that determine the items displayed in each row.-
table
row
a list of product id's to display in the row.
-
table
- (optional) table
items
a list of product id's to display that can be used instead ofrows
when a section contains only one row (such as for landscape shops). - (optional) bool
scrollable
if true, sets the section to be scrollable horizontally. Only works with landscape shops. Useful for displaying more than 5 items per row. - (optional) table
navigation
used in portrait shops to generate a navigation button for the section with additional parameters.- (optional) bool
use_display_name
if true, the navigation button will use the section's display name. - (optional) string
display_name
if set, the navigation button will use this text. Cannot be used withuse_display_name
- (optional) string
icon
if set, the navigation button will display this icon in addition to any displayed text.
- (optional) bool
- (optional) table
display_timer
creates a timer display for the shop section that counts down to the next server day.-
string
label
sets the text of the timer display.
-
string
- (optional) table
custom
used to define custom attributes of the section.- (optional) string
layout
the name of the XML layout to use for this shop section. - (optional) string
layout_func
this function will be run using the section layout as self when the section is created.
- (optional) string
Dynamically adds items to a shop section. By default, these items will added to the current row for landscape shops and added to a new row for portrait shops.
Items added to the shop in this way can be set to expire at a given time using the expires_at
and expires_in
options, which will save the expiry time of the item to player save data. An item's expiration time can be cleared with ClearItemTimerData(). Note that item expiry time is tracked with local OS time and NOT with server time, and thus can used without needing to call InitializeServer().
If an item is given an expiry time and its layout contains a frame with the id TimerFrame
, it will attempt to hookup and activate the TimerFrame
to display the time remaining. If the timer frame has a TimerValueLabel
text frame, this text will display the remaining time using FormatTimeDHM() formatting. If the timer frame has a ClockHand
frame, it will become animated. The included UI templates Landscape/Template/TimerFrame
and Portrait/Template/TimerFrame
are for this expressed purpose.
-- adds an item that will expire in 3 days
local day_length_in_seconds = 86400
local options = { expires_in = day_length_in_seconds * 3 }
ui.shop:AddItemsToSection("bundles", { "com.wildsky.test.iap.bundle.starter01" }, options)
-
string
section_name
the section to add the items to. -
table
items_list
a list of product id's to add to the section. - (optional) table
options
- (optional) number
expires_at
if set, the items will be removed from the shop at the time of the given unix timestamp. - (optional) number
expires_in
if set, the items will be removed from the shop after this many seconds have passed. - (optional) number
row
if set, the items will be added to the specified row index.
- (optional) number
Dynamically removes items from the shop. Rows with no items will be removed. Sections with no items will be hidden until they have items again.
local items_list = {
"com.wildsky.test.iap.bundle.starter01",
"com.wildsky.test.iap.bundle.starter02",
}
ui.shop:RemoveItems(items_list)
Dynamically removes all items from the specified shop section.
ui.shop:RemoveAllItemsFromSection("gold")
Dynamically removes ALL items from the shop.
ui.shop:RemoveAllItems()
Adds an update function to the shop's update timer. The shop's update timer is a Real Timer that pauses itself when the shop is hidden and resumes itself when the shop is shown. Any update functions added in this way will be executed each time the shop's update timer ticks, using the global tick rate.
This can be useful for creating your own custom timer displays or otherwise want to constantly update something while the shop is open.
local TIME_SPENT_WITH_SHOP_OPEN = 0
local GLOBAL_TICK_RATE = 0.0625
local timer_id = "shop_time_tracking_timer"
function UpdateShopTimeTracking()
TIME_SPENT_WITH_SHOP_OPEN = TIME_SPENT_WITH_SHOP_OPEN + GLOBAL_TICK_RATE
end
-- adds a timer that tracks the total time the shop has been open
ui.shop:AddTimerUpdateFunction(timer_id, UpdateShopTimeTracking)
Removes an existing update function from the shop's update timer.
-- stop tracking the total time the shop has been open
local timer_id = "shop_time_tracking_timer"
ui.shop:RemoveTimerUpdateFunction(timer_id)
For ease of use, the popup layout (as created by NewPopupUI will be referenced as ui.popup
throughout this documentation.
The following functions can be used such as:
local shop = require("shop")
local ui = {
root = DCEI.GetUiRoot()
}
-- product definitions
local product_list = {
{
product_id = "com.wildsky.example.iap.gold01",
label = "Handful of Gold",
display = "shop_gold_lv2",
price = { usd = 2.99 },
items = { gold = 1000 }
},
{
product_id = "com.wildsky.example.iap.gold02",
label = "Barrel of Gold",
display = "shop_gold_lv4",
price = { usd = 4.99 },
items = { gold = 5000 }
}
}
-- initialize IAP items
shop.InitializeIAP({
on_purchase_attempt_callback = AttemptAnyItemPurchase,
on_purchase_success_callback = OnAnyItemPurchase,
product_list = product_list,
})
-- creates a new popup UI
ui.popup = shop.NewPopupUI()
-- shows a popup with the "Handful of Gold" item
local items_list = { "com.wildsky.example.iap.gold01" }
local options = { display_name = "Deal of the Day" }
ui.popup:Show(items_list, options)
Shows the UI popup with the given items and display options.
local items_list = { "com.wildsky.example.iap.gold01" }
local options = { display_name = "Deal of the Day" }
ui.popup:Show(items_list, options)
-
table
items_list
a list of product id's to add to the popup. - (optional) table
options
- (optional) string
display_name
determines the banner text to display on the popup. The default text is "Daily Deals".
- (optional) string
Removes all existing items in the popup and replaces them with the given items.
local items_list = { "com.wildsky.example.iap.gold02" }
ui.popup:Update(items_list)
-
table
items_list
a list of product id's to update the popup with.
Hides the popup. Note that is automatically called when the close button (ui.popup.CloseButton
) on the upper right of the popup UI is pressed.
Adds an update function to the popup's update timer. Functions the same as the shop update timer, but instead pauses when the popup is hidden.
Removes an existing update function from the popup's update timer.
These methods can be used on item layouts in the shop or popup UI. Use shop.GetItemLayout() to get an item's shop layout and shop.GetItemLayoutFromPopup() to get an item's popup layout.
Removes an item, similiar to calling ui.shop.RemoveItems() with a single product id.
local product_id = "com.wildsky.example.iap.gold01"
local item = shop.GetItemLayout(product_id)
item:Remove()
Shows a red pip on the top left of item's layout and the item's section banner. All pips are cleared when the shop is closed.
Hide's an item's red pip.
These are the functions exported by the shop mod. They can be used such as:
local shop = require("shop")
local ui = {
root = DCEI.GetUiRoot()
}
-- creates and shows the shop UI
ui.shop = shop.NewShopUI({ parent = ui.root })
-- initialize IAP data
shop.InitializeIAP({
on_purchase_attempt_callback = AttemptAnyItemPurchase,
on_purchase_success_callback = OnAnyItemPurchase,
product_list = GetProductList(),
currency_list = CURRENCIES
})
Initializes IAP from IAP data. This requires a product list, functions for purchase attempt and purchase success, and can optionally initialize currencies. This should be called in OnMapStart()
.
local shop = require("shop")
local ui = {
root = DCEI.GetUiRoot()
}
-- product definitions
local product_list = {
{
product_id = "com.wildsky.example.iap.gold01",
label = "1,000 Gold",
display = "shop_gold_lv2",
price = { usd = 2.99 },
items = { gold = 1000 }
},
{
product_id = "com.wildsky.example.iap.gold02",
label = "5,000 Gold",
display = "shop_gold_lv4",
price = { usd = 4.99 },
items = { gold = 5000 }
}
}
-- currency definitions
local currency_list = {
{
name = "gold",
icon = "icon_item_coin"
}
}
function AttemptAnyItemPurchase(product_id)
-- if your game has products that can be purchased for in-game currency or by watching ads, you should include the purchase attempt logic for those items here
if DCEI.Platform == "WindowsPlayer" then
-- simulate successful purchase when using editor
-- NOTE: shop.OnAnyItemPurchase() calls the on_purchase_success_callback after updating the item's layout and stock data
shop.OnAnyItemPurchase(product_id)
else
-- otherwise continue standard IAP flow
-- NOTE: DCEI.PurchaseIapProduct() takes a few seconds to execute and thus acts similarly to a DCEI.Wait() so avoid subsequent code in the same thread
DCEI.PurchaseIapProduct(product_id)
end
end
function OnAnyItemPurchase(product_id)
local item_data = shop.GetProductData(product_id)
-- deliver purchased items to player
local items = item_data:GetItemsData()
if items and items.gold then
local player_id = 1
DCEI.AddGold(player_id, items.gold)
end
end
-- initialize IAP data
shop.InitializeIAP({
on_purchase_attempt_callback = AttemptAnyItemPurchase,
on_purchase_success_callback = OnAnyItemPurchase,
product_list = product_list,
currency_list = currency_list
})
-- creates a new shop UI
ui.shop = shop.NewShopUI({ parent = ui.root })
-- initializes a shop with a "Gold" section and gold items
local shop_data = {
{
name = "gold",
display_name = "Gold",
rows = {
{
"com.wildsky.example.iap.gold01",
"com.wildsky.example.iap.gold02",
}
}
}
}
ui.shop:Initialize(shop_data)
-- show the shop after it's been initialized
ui.shop:Show()
-
function
on_purchase_attempt_callback
this function is called when an item purchase button is pressed, with the item'sproduct_id
as the first argument. See Purchase Attempt Function for more details. -
function
on_purchase_success_callback
this function is called whenDCEI.PurchaseIapProduct(product_id)
succeeds, with the item'sproduct_id
as the first argument. See Purchase Success Function for more details. -
table
product_list
the list of IAP initem_data
format. - (optional) table
currency_list
the list of currencies used in the shop. - (optional) bool
is_game_localized
if set, uses localized text for all built-in text values of the shop instead of the hardcoded english text (ex: DHM formatting). Set this to true if your game is using localization.
Use this function instead of the on_purchase_success_callback
defined in InitializeIAP() when you need to directly call your item purchase function, such as when simulating successful purchase in editor play mode or when successfully purchasing items that cost in-game currency or watching ads.
This function will update the item's layout and stock data before calling the locally defined on_purchase_success_callback
.
Initializes server time tracking from the given data. This is useful for creating items that refresh stock on a daily basis or rotate depending on the day of the week. In server data you can define a callback that occurs whenever server time is fetched or a new day occurs, along with some additional debugging options.
A new server day occurs at 6AM PST. Note that the editor uses your local OS time as it's not connected to the game server.
Once initalized, the shop will attempt to fetch server time whenever any of the following occurs:
- When ui.shop:Initialize() is called
- When a new server day occurs (at 6AM PST)
- The next time the shop is opened IF the previous fetch failed
You can manually call a shop fetch server attempt with AttemptGetServerTime().
-
function
on_server_time_update_callback
this function is called whenever server time is successfully fetched, regardless of whether a new day has occurred. This is where you want to add "daily deal" items to the shop, though take care to not add duplicate items. -
function
on_new_server_day_callback
this function is called when a new server day is detected. This typically occurs when the shop is initialized during the player's first session of the day but can also occur at 6AM PST. This where you want to advance any "daily deal" index and reset the stock limit of items that refresh on a daily basis. - (optional) table
options
- (optional) number
update_delay
this debug option will add a delay on shop fetch server time calls to simulate network latency. - (optional) bool
update_fails
this debug option will cause all shop fetch server time calls to fail. - (optional) bool
use_os_time
this debug option will cause shop fetch server time calls to use local OS time. This is only useful for publishing to arcade, where server time currently fails.
- (optional) number
function OnShopFetchNewDay()
-- reset daily ads chest
local product_id = "com.wildsky.test.shop.chest01"
local layout = shop.GetItemLayout(product_id)
shop.ClearItemPurchaseData(product_id)
layout:Update()
ui.shop.sections["chests"].timer_display:Reset()
end
-- initialize server data
shop.InitializeServer({
on_new_server_day_callback = OnShopFetchNewDay
})
Manually attempts to fetch server time for shop server time tracking using the data given in InitializeServer(). If successful this will call the on_server_time_update_callback
. If successful and a new day has occurred since the last server time check, this will call the on_new_server_day_callback
.
Initializes and returns the shop UI layout
. If no parent frame is specified by options.parent
, the shop will be created in ui.root. By default, whether a shop is landscape or portrait is automatically determined by the resolution of the game window.
The shop UI must be initialized before any shop methods can be used.
- (optional) table
options
- (optional) tranform
parent
sets the parent frame for the shop UI. - (optional) bool
is_landscape
if true, the shop will be created using landscape mode regardless of game resolution. If false, the shop will be created using portrait mode regardless of game resolution.
- (optional) tranform
Initializes and returns the popup UI layout
. If no parent frame is specified by options.parent
, the shop will be created in ui.root.
The popup UI must be initialized before any popup methods can be used.
- (optional) table
options
- (optional) tranform
parent
sets the parent frame for the popup UI. - (optional) string
display_name
if set, this display name will be used on the popup's banner label.
- (optional) tranform
Creates and returns a new item info UI layout
. This is the UI that displays when an item's info button is pressed. One is created automatically when the shop is created, but this function can be used to overwrite the existing item info UI under a new parent.
- (optional) table
options
- (optional) tranform
parent
sets the parent frame for the item info UI.
- (optional) tranform
The Item Info UI has a builtin OnReset() method that gets called when the item info layout is updated with its item data. You can overwrite this function for your own purposes, which is useful for reseting any additional UI added to this UI in its update_func
.
Returns an item_data
table from its product_id
.
Returns an item's USD price from its product_id
.
Returns an item's localized price from its product_id
, if available.
Note that this will only work for published mobile game builds, as it relies on mobile IAP configurations. This will always return nil
in editor play mode.
Returns an item's price table from its product_id
if the price table contains type
and amount
values (thus indicating it uses a custom currency).
Returns the item's layout from its product_id
if the item exists in the Shop UI.
Returns the item's layout from its product_id
if the item exists in the Popup UI.
Returns the number of stock available for an item from its product_id
. Stock available is equal to number of times the player has purchased this item subtracted from its stock_limit
. Stock available can be reset to its stock limit using ClearItemPurchaseData().
Returns -1
if the item doesn't have a stock limit.
Resets the purchase count of an item from its product_id
. Purchase count is only tracked for items that have a stock_limit
.
Returns a table of an item's timed offer data from its product_id
. If the item was added to the shop with an expires_at
or expires_in
option, the returned table will have a key for expires_at
with a timestamp of when the item expires.
Returns true
if the item specified by the product_id
has timed offer data and has not expired yet.
Returns true
if no timed offer data exists for the item.
Removes the item specified by the product_id
's timer data, preventing such items from expiring.
Returns a formatted string in hours and minutes from the given duration in seconds.
local duration = 4500
local display_time = shop.FormatTimeHM(duration)
local label = DCEI.NewText(DCEI.GetUiRoot())
DCEI.SetText(label, display_time)
-- displays time as 1H 15M
Returns a formatted string in days, hours, and minutes from the given duration in seconds.
local duration = 240000
local display_time = shop.FormatTimeDHM(duration)
local label = DCEI.NewText(DCEI.GetUiRoot())
DCEI.SetText(label, display_time)
-- displays time as 2D 18H 40M
This function is automatically called to initiate an item purchase when a product is selected in the shop UI using either IAP or custom currency.
For IAP items, this function should call DCEI.PurchaseIapProduct(product_id)
. Note that DCEI.PurchaseIapProduct()
will not succeed in the editor so you may want to provide code path for testing (such as in the example below).
For custom currency items, this function should check if the player can afford the item and should subtract the currency amount and call shop.OnAnyItemPurchase() function on success. Be sure to call the mod's shop.OnAnyItemPurchase() function and not the locally declared OnAnyItemPurchase().
function AttemptAnyItemPurchase( product_id )
DCEI.LogMessage("> Attempt Purchase " .. tostring(product_id))
local custom_price_data = shop.GetProductCustomPriceData( product_id )
if custom_price_data then
-- check conditions for items with custom currency cost
if custom_price_data.type == "gems" then
-- for currency gems
local cost = custom_price_data.amount
if Player:GetGems() >= cost then
-- if player can afford purchase, subtract cost and deliver items
Player:AddGems( -1 * cost )
shop.OnAnyItemPurchase(product_id)
else
-- display feedback for not enough gems
local text = "Not Enough Gems!"
DCEI.ShowFeedbackMessage("<color=red>" .. text)
end
end
else
-- otherwise attempt standard IAP flow
if DCEI.Platform == "WindowsPlayer" then
-- simulate successful purchase when using editor
shop.OnAnyItemPurchase(product_id)
else
-- otherwise continue standard IAP flow
DCEI.PurchaseIapProduct(product_id)
end
end
end
This function is automatically called via shop.OnAnyItemPurchase() when DCEI.PurchaseIapProduct()
succeeds. This function should be used to deliver items for IAP or custom currency purchases.
This function is also a good place to log item purchases.
function OnAnyItemPurchase( product_id )
DCEI.LogMessage("> Successful Purchase " .. tostring(product_id))
local item_data = shop.GetProductData( product_id )
-- deliver purchased items to player
local items = item_data.items
if items then
-- deliver gold
if items.gold then
Player:AddGold( items.gold )
end
-- deliver gems
if items.gems then
Player:AddGems( items.gems )
end
-- deliver hero shards
local shards = GetProductShards( items )
if shards then
for _, shard in pairs(shards) do
Player:AddShards( shard.name, shard.count )
end
end
-- roll gacha results and deliver hero shards
local gacha = GetProductGacha( items )
if gacha then
local rolled_shards = ConvertGachaToShards( gacha )
local shards = GetProductShards( rolled_shards )
for _, shard in pairs(shards) do
Player:AddShards( shard.name, shard.count )
end
end
end
-- log item purchase
local event_name = "Buy Item"
local props = {product_id = product_id}
local price_data = item_data.price
for k, v in pairs(price_data) do
props[k] = v
end
DCEI.Event.Log(name, props)
end
Item data defines each IAP (and custom currency purchase) and allows for customization of the item layout in the shop UI. Item data has 5 required properties.
local item_data = {
product_id = "com.wildsky.example.iap.gold01",
label = "Handful of Gold",
display = "shop_gold_lv2",
price = { usd = 2.99 },
items = { gold = 1000 }
}
The product ID of the item. For IAP this must match the item's product ID in the product configuration (such as on Google Play Console or App Store Connect).
The product_id can also be used to reference the item_data
or item layout through the various Mod Functions.
Determines the label displayed at the top of the item layout (such as "Starter Pack" or "💎 500"). Using a string here will set the name
property.
- (optional) string
name
used to directly set the text of the display label. Cannot be used withitem_type
. - (optional) string
color
used to set the color of the display label. Note that this accepts a color tag value such as"<color=yellow>"
or"<color=#42cdff>"
. - (optional) string
icon
used to display an icon to the left of the display label. - (optional) string
item_type
used to display a value fromitems
as the display label, usingitem_type
as theitems
key. Cannot be used withname
. - (optional) bool
format_with_commas
used in conjunction withitem_type
to format a number with commas (eg,12345
will display as12,345
).
{
product_id = "com.wildsky.example.shop.gold02",
label = {
icon = "icon_coin00",
item_type = "gold",
color = "<color=yellow>",
format_with_commas = true
},
display = "shop_gold_lv4",
items = {
gold = 10000
},
price = {
type = "gems",
amount = 500
}
}
Determines the image display of the item layout. Using a string here will set the image
property.
-
string
image
sets the displayed image of the item layout. Cannot be used withuse_item_bundle
. - (optional) number
scale
used to adjust the size of the displayed image as a percent (egscale = 2
is 200%). - (optional) table
offset
used to adjust the offset of the displayed image (egoffset = {x = 0, y = 10}
moves the image up by 10). - (optional) bool
use_item_bundle
when set, generates a bundle display using the listeditems
. Only items registered as currency_list will be displayed. - (optional) bool
use_stock_display
when set, enables the layout'sStockFrame
if it has one and attempts to update theStockFrame.StockLabel
with the remaining stock. - (optional) bool
format_with_commas
used in conjunction withuse_item_bundle
to format bundle item values with commas (eg,12345
will display as12,345
). - (optional) bool
disable_rtl_support
when set, disables RTL language support for the layout'sTitleLabel
. This is useful for displaying formatted numeric text (ex:"1,234k"
) correctly in RTL languages (such as Arabic).
{
product_id = "com.wildsky.test.iap.bundle.starter02",
label = "Founder's Pack",
display = {
use_item_bundle = true,
format_with_commas = true
},
items = {
gold = 20000,
hero_shards_windknight = 8,
hero_shards_icemage = 8
},
price = {
usd = 9.99
}
}
Determines if the item is purchased as an IAP or with custom currency.
The usd
price must be set for IAP using the corresponding value in the product configuration (such as on Google Play Console or App Store Connect). If the product configuration is correct, regional pricing will be displayed. The usd
price must still be set for proper revenue logging.
When using custom currency_list, you will have to configure how these are checked in your purchase attempt function.
Note that a product's price data must be retrieved at runtime with item_data:GetPriceData and cannot be retrieved with item_data.price
. This is enforced as anti-cheat method as static data is vulnerable to memory hacking on mobile builds.
-
number
usd
used to mark items as IAP with revenue logging. Cannot be used withtype
andamount
. -
string
type
used to set the custom currency type used to purchase the item using a registered currency. Cannot be used withusd
. -
number
amount
used in conjunction withtype
to set the cost of custom currency purchases. Cannot be used withusd
.
The list of items (such as gold, gems, chests, etc) delivered to the player on purchase. These items can be used to construct bundle displays by using a registered currency and the display.use_item_bundle option.
You will have to configure how these items are handled in your purchase success function.
Note that a product's items data must be retrieved at runtime with item_data:GetItemsData and cannot be retrieved with item_data.items
. This is enforced as anti-cheat method as static data is vulnerable to memory hacking on mobile builds.
If set, attempts to hookup and show an item's InfoPip
and InfoButton
frame. When the InfoButton
frame is selected, the shop's item info frame will be shown.
-
string
label
text to be displayed in the item info frame. - (optional) function
update_func
this function will be run using the item info frame layout asself
when the info frame is shown for an item.
local product_list = {
product_id = "com.wildsky.test.shop.chest01",
label = {
name = "Rare Chest",
color = "<color=#00ffff>",
},
display = {
image = "hero_chest_t1",
scale = 1.1,
offset = { y = 4 }
},
items = {
hero_shards_gacha_rare = 8,
},
price = {
type = "gems",
amount = 250,
},
info = {
update_func = CustomizeStoreItemInfo_Chest,
label = "Contains 8 [[Rare]] hero shards."
.. "\n\n" .. "Drop Rates:"
.. "\n" .. "[50%] - [[Wind Knight]]"
.. "\n" .. "[50%] - [[Ice Mage]]"
},
}
function CustomizeStoreItemInfo_Chest( self )
-- format text colors
local text = self.item_data.info.label
text = text:gsub("%[%[", COLORS.rare)
text = text:gsub("%]%]", "</color>")
text = text:gsub("%[", COLORS.yellow)
text = text:gsub("%]", "</color>")
DCEI.SetText(self.InfoLabel, text)
end
>
Used to indicate an item has limited stock. Can be used in conjunction with the display.use_stock_display
parameter to show the remaining stock for items using the standard layouts.
Note that items are not automatically removed or disabled when they have 0 stock remaining. You can customize this behavior yourself by checking the item's available stock in its custom update function.
Used to customize an item layout. You may find it useful to define your IAP list with a function, rather than a variable declaration when using layout_func
to avoid having to juggle declaration ordering.
It's suggested to put any of your own custom item properties (such as subtitles or additional callback functionality) here for organizational purposes.
- (optional) string
layout
if set, this XML layout will be used rather than the default../Shop/Section/Item/..
XML for the item's layout. Use this to customize the look of shop items. - (optional) function
layout_func
this function will be run using the item layout asself
when the item is created. - (optional) function
update_func
this function will be run using the item layout asself
when the item is created or updated (such as on purchase). - (optional) function
remove_func
this function will be run using the item layout asself
when the item is removed. - (optional) function
onshow_func
this function will be run using the item layout asself
when the shop is opened. This is useful for updating products that scale with game progress.
These methods can be called with a product's item_data.
local product_id = "com.wildsky.test.shop.chest01"
local item_data = shop.GetProductData(product_id)
-- gets the product's price data
local price_data = item_data:GetPriceData()
Gets a product's price data. This must be retrieved as a function rather than directly as item_data.price
as an anti-cheat measure as static data is vulnerable to memory hacking in mobile builds.
Gets a product's items data. This must be retrieved as a function rather than directly as item_data.items
as an anti-cheat measure as static data is vulnerable to memory hacking in mobile builds.
Sets a product's price data in case you want to dynamically change the price of an item during gameplay. This may be useful for items that are free or an ads reward once per day and then use a normal IAP or in-game currency price.
Sets a product's items data in case you want to dynamically change the items contained in a product during gameplay. This may be useful for bundles with rotating item availability without needing to create multiple unique product ids.
The currency table is used to associate a currency with an icon for shop display purposes.
-
string
name
the name of the registered currency to be referenced elsewhere. -
string
icon
the icon to use for this currency (used in custom currency prices and bundle displays). - (optional) string
bundle_layout
if set, this XML layout will be used for this currency in bundle displays instead of the defaultShared/Shop/Section/Item/BundleItem
XML. - (optional) string
bundle_image
if set, this image will be used for this currency in bundle displays instead of theicon
(which will still be used for price displays) - (optional) string
bundle_label_format
used to customize currency formatting in bundle displays. The"{[x]}"
key will be replaced with the currency value (see example below). - (optional) string
bundle_label_format_single
used to customize currency formatting in bundle displays if the currency value is1
. The"{[x]}"
key will be replaced with the currency value (see example below). - (optional) number
priority
if set, these items will be ordered from highpriority
to low in bundle displays, otherwise they will be ordered by the alphabet of thename
. The item withpriority
nil will be counted as lowest priority vs an item withpriority
parameter.
local CURRENCY_LIST = {
{
name = "gold",
icon = "icon_item_coin",
priority = 10
},
{
name = "gems",
icon = "icon_item_gem",
priority = 9
},
{
name = "hero_shards_windknight",
icon = "shard_hero_wind_knight",
bundle_label_format = "{[x]} shards",
bundle_label_format_single = "{[x]} shard",
},
{
name = "hero_shards_icemage",
icon = "shard_hero_traveling_mage",
bundle_label_format = "{[x]} shards",
bundle_label_format_single = "{[x]} shard",
},
{
name = "hero_shards_tinker",
icon = "shard_hero_lava_chef",
bundle_label_format = "{[x]} shards",
bundle_label_format_single = "{[x]} shard",
}
}
Any piece of the shop UI can be customized by forking and overwriting the original layout XML in the ui tab. Individual items in the shop can be customized by using the custom layout
properties.
- added
layout_func
option tosection_data.custom
in ui.shop:Initialize - Fixed an issue where some items indices weren't updated properly on removal
- Fixed popups that wouldn't update correctly after the first time they're shown
- Fixed localized prices not being initialized correctly
- Fixed an issue that could re-arrange UI layers unexpectedly when NewItemInfoUI is created under a non-root parent
- Add item_data option for
custom.onshow_func
that runs an update function when the shop or popup is shown - Add item_data option for
label.disable_rtl_support
that forces off RTL support for the item's title text - Add currency_data option for
bundle_label_format
andbundle_label_format_single
for customizing bundle display text - Add
is_game_localized
argument toiap_data
in shop.InitializeIAP() - Fix an issue that created additional "+" icons when using non-currency values in
item_data.items
- Reworked shop data initialization and removed ui.shop:AddItem() and ui.shop:AddSection()
- Converted all built-in UI to XML for better customization options
- Add support for dynamically adding and removing shop items at runtime
- Add anti-cheat features that move item and price data out of static variables and into functions
- Add support for info popups for items to display more information
- Add support for limited time offer items, rotating stock, and timer displays
- Add support for limited stock items
- Add support for sales offer popups
- Add support for navigation bar in portrait mode shops
- Support displaying localized currency prices
- Added GetProductPriceLocalized() mod function
- Added landscape shop support
- IAP Shop Mod released