feat: 2.3.2
This commit is contained in:
@@ -0,0 +1,244 @@
|
||||
local nk = require("nakama")
|
||||
local utils = require("lua.utils")
|
||||
|
||||
local economy = {}
|
||||
|
||||
local SHOP_CATALOG_DEFS = {
|
||||
{ id = "oldpop-blue-hat", name = "Oldpop Blue Hat", category = "head", gold = 100, star = 0, rarity = "Common", character = "Oldpop" },
|
||||
{ id = "oldpop-green-hat", name = "Oldpop Green Hat", category = "head", gold = 100, star = 0, rarity = "Common", character = "Oldpop" },
|
||||
{ id = "oldpop-red-hat", name = "Oldpop Red Hat", category = "head", gold = 100, star = 0, rarity = "Common", character = "Oldpop" },
|
||||
{ id = "oldpop-yellow-hat", name = "Oldpop Yellow Hat", category = "head", gold = 100, star = 0, rarity = "Common", character = "Oldpop" },
|
||||
{ id = "oldpop-og-pant", name = "Copper OG Pant", category = "costume", gold = 0, star = 0, rarity = "Common", character = "Oldpop" },
|
||||
{ id = "oldpop-grey-pant", name = "Copper Grey Pant", category = "costume", gold = 150, star = 0, rarity = "Common", character = "Oldpop" },
|
||||
{ id = "oldpop-red-pant", name = "Copper Red Pant", category = "costume", gold = 150, star = 0, rarity = "Common", character = "Oldpop" },
|
||||
{ id = "oldpop-yellow-pant", name = "Copper Yellow Pant", category = "costume", gold = 150, star = 0, rarity = "Common", character = "Oldpop" },
|
||||
{ id = "oldpop-blue-gloves", name = "Oldpop Blue Gloves", category = "glove", gold = 75, star = 0, rarity = "Common", character = "Oldpop" },
|
||||
{ id = "oldpop-green-gloves", name = "Oldpop Green Gloves", category = "glove", gold = 75, star = 0, rarity = "Common", character = "Oldpop" },
|
||||
{ id = "oldpop-red-gloves", name = "Oldpop Red Gloves", category = "glove", gold = 75, star = 0, rarity = "Common", character = "Oldpop" },
|
||||
{ id = "oldpop-yellow-gloves", name = "Oldpop Yellow Gloves", category = "glove", gold = 75, star = 0, rarity = "Common", character = "Oldpop" }
|
||||
}
|
||||
|
||||
local function build_shop_catalog()
|
||||
local catalog = {}
|
||||
for _, def in ipairs(SHOP_CATALOG_DEFS) do
|
||||
local cat = def.category
|
||||
if not catalog[cat] then catalog[cat] = {} end
|
||||
local entry = {
|
||||
id = def.id,
|
||||
name = def.name,
|
||||
gold = def.gold or 0,
|
||||
star = def.star or 0,
|
||||
rarity = def.rarity or "Common",
|
||||
character = def.character
|
||||
}
|
||||
table.insert(catalog[cat], entry)
|
||||
end
|
||||
return catalog
|
||||
end
|
||||
|
||||
function economy.rpc_get_shop_catalog(context, payload)
|
||||
if not context.user_id then error("Not authenticated") end
|
||||
|
||||
local result = { catalog = build_shop_catalog(), featured_banners = {} }
|
||||
|
||||
local status, objs = pcall(nk.storage_read, {{ collection = "shop_config", key = "featured_banners", user_id = "00000000-0000-0000-0000-000000000000" }})
|
||||
if status and objs and #objs > 0 then
|
||||
local val = objs[1].value
|
||||
if val.banners then result.featured_banners = val.banners end
|
||||
end
|
||||
|
||||
return nk.json_encode(result)
|
||||
end
|
||||
|
||||
function economy.rpc_buy_currency(context, payload)
|
||||
if not context.user_id then error("Not authenticated") end
|
||||
|
||||
local request = nk.json_decode(payload)
|
||||
local packageId = request.package_id
|
||||
local receipt = request.receipt
|
||||
local idempotencyKey = request.idempotency_key
|
||||
|
||||
if not packageId or packageId == "" then error("Package ID required") end
|
||||
if not idempotencyKey or idempotencyKey == "" then error("Idempotency key required") end
|
||||
|
||||
local status, existing = pcall(nk.storage_read, {{ collection = "receipts", key = idempotencyKey, user_id = context.user_id }})
|
||||
if status and existing and #existing > 0 then
|
||||
return nk.json_encode({ success = true, package_id = packageId, duplicate = true, status = existing[1].value.status })
|
||||
end
|
||||
|
||||
local changeset = { gold = 0, star = 0 }
|
||||
local requiresVerification = false
|
||||
|
||||
if packageId == "gold_100" then changeset.gold = 100; requiresVerification = true
|
||||
elseif packageId == "gold_500" then changeset.gold = 550; requiresVerification = true
|
||||
elseif packageId == "gold_1000" then changeset.gold = 1150; requiresVerification = true
|
||||
elseif packageId == "gold_2000" then changeset.gold = 2400; requiresVerification = true
|
||||
elseif packageId == "gold_5000" then changeset.gold = 6250; requiresVerification = true
|
||||
elseif packageId == "gold_10000" then changeset.gold = 13000; requiresVerification = true
|
||||
elseif packageId == "star_100" then changeset.star = 100; changeset.gold = -500
|
||||
elseif packageId == "star_250" then changeset.star = 250; changeset.gold = -1100
|
||||
elseif packageId == "star_600" then changeset.star = 600; changeset.gold = -2500
|
||||
else error("Invalid package ID") end
|
||||
|
||||
if requiresVerification and not receipt then
|
||||
nk.storage_write({{
|
||||
collection = "receipts",
|
||||
key = idempotencyKey,
|
||||
user_id = context.user_id,
|
||||
value = { type = "currency", package_id = packageId, status = "pending", created_at = os.date("!%Y-%m-%dT%H:%M:%S.000Z") },
|
||||
permission_read = 1,
|
||||
permission_write = 0
|
||||
}})
|
||||
return nk.json_encode({ success = true, status = "pending", package_id = packageId })
|
||||
end
|
||||
|
||||
local s, err = pcall(function()
|
||||
if changeset.gold ~= 0 or changeset.star ~= 0 then
|
||||
nk.wallet_update(context.user_id, changeset, {}, true)
|
||||
end
|
||||
nk.storage_write({{
|
||||
collection = "receipts",
|
||||
key = idempotencyKey,
|
||||
user_id = context.user_id,
|
||||
value = { type = "currency", package_id = packageId, changeset = changeset, receipt = receipt or nk.json_null(), status = "verified", processed_at = os.date("!%Y-%m-%dT%H:%M:%S.000Z") },
|
||||
permission_read = 1,
|
||||
permission_write = 0
|
||||
}})
|
||||
end)
|
||||
|
||||
if not s then
|
||||
nk.logger_error("Currency purchase failed: " .. tostring(err))
|
||||
error("NotEnoughFunds")
|
||||
end
|
||||
|
||||
nk.logger_info("User " .. context.user_id .. " bought currency package " .. packageId)
|
||||
return nk.json_encode({ success = true, status = "verified", package_id = packageId })
|
||||
end
|
||||
|
||||
function economy.rpc_purchase_item(context, payload)
|
||||
if not context.user_id then error("Not authenticated") end
|
||||
|
||||
local request = nk.json_decode(payload)
|
||||
local itemId = request.item_id
|
||||
local quantity = request.quantity or 1
|
||||
local idempotencyKey = request.idempotency_key
|
||||
|
||||
if not itemId or itemId == "" then error("Item ID required") end
|
||||
if quantity < 1 then error("Invalid quantity") end
|
||||
if not idempotencyKey or idempotencyKey == "" then error("Idempotency key required") end
|
||||
|
||||
local status, existing = pcall(nk.storage_read, {{ collection = "receipts", key = idempotencyKey, user_id = context.user_id }})
|
||||
if status and existing and #existing > 0 then
|
||||
return nk.json_encode({ success = true, item = itemId, duplicate = true })
|
||||
end
|
||||
|
||||
local itemDef = nil
|
||||
for _, def in ipairs(SHOP_CATALOG_DEFS) do
|
||||
if def.id == itemId then
|
||||
itemDef = def
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not itemDef then error("ItemNotFound") end
|
||||
|
||||
local priceGold = (itemDef.gold or 0) * quantity
|
||||
local priceStar = (itemDef.star or 0) * quantity
|
||||
local category = itemDef.category or "accessory"
|
||||
|
||||
local s, err = pcall(function()
|
||||
local changeset = {}
|
||||
if priceGold > 0 then changeset.gold = -priceGold end
|
||||
if priceStar > 0 then changeset.star = -priceStar end
|
||||
|
||||
if priceGold > 0 or priceStar > 0 then
|
||||
nk.wallet_update(context.user_id, changeset, {}, true)
|
||||
end
|
||||
end)
|
||||
if not s then
|
||||
nk.logger_error("Wallet update failed: " .. tostring(err))
|
||||
error("NotEnoughFunds")
|
||||
end
|
||||
|
||||
local s2, err2 = pcall(function()
|
||||
local writes = {
|
||||
{
|
||||
collection = "inventory",
|
||||
key = itemId,
|
||||
user_id = context.user_id,
|
||||
value = { category = category, purchased_at = os.date("!%Y-%m-%dT%H:%M:%S.000Z"), quantity = quantity },
|
||||
permission_read = 1,
|
||||
permission_write = 0
|
||||
},
|
||||
{
|
||||
collection = "receipts",
|
||||
key = idempotencyKey,
|
||||
user_id = context.user_id,
|
||||
value = { type = "item", item_id = itemId, quantity = quantity, cost = { gold = priceGold, star = priceStar }, processed_at = os.date("!%Y-%m-%dT%H:%M:%S.000Z") },
|
||||
permission_read = 1,
|
||||
permission_write = 0
|
||||
}
|
||||
}
|
||||
nk.storage_write(writes)
|
||||
end)
|
||||
if not s2 then
|
||||
nk.logger_error("Purchase failed: " .. tostring(err2))
|
||||
error("PurchaseFailed")
|
||||
end
|
||||
|
||||
nk.logger_info("User " .. context.user_id .. " purchased " .. itemId)
|
||||
return nk.json_encode({ success = true, item = itemId })
|
||||
end
|
||||
|
||||
function economy.rpc_admin_set_featured_banners(context, payload)
|
||||
utils.require_admin(context)
|
||||
local req = nk.json_decode(payload or "{}")
|
||||
local banners = req.banners or {}
|
||||
|
||||
local finalBanners = {}
|
||||
for i = 1, math.min(#banners, 3) do
|
||||
table.insert(finalBanners, banners[i])
|
||||
end
|
||||
|
||||
for _, b in ipairs(finalBanners) do
|
||||
local itemId = b.item_id or ""
|
||||
if itemId ~= "" then
|
||||
local found = false
|
||||
for _, def in ipairs(SHOP_CATALOG_DEFS) do
|
||||
if def.id == itemId then found = true; break end
|
||||
end
|
||||
if not found then error("Item not found in catalog: " .. itemId) end
|
||||
end
|
||||
end
|
||||
|
||||
nk.storage_write({{
|
||||
collection = "shop_config",
|
||||
key = "featured_banners",
|
||||
user_id = "00000000-0000-0000-0000-000000000000",
|
||||
value = { banners = finalBanners },
|
||||
permission_read = 2,
|
||||
permission_write = 0
|
||||
}})
|
||||
|
||||
nk.logger_info("Featured banners updated by admin " .. context.user_id)
|
||||
return nk.json_encode({ success = true, banners = finalBanners })
|
||||
end
|
||||
|
||||
function economy.rpc_admin_get_featured_banners(context, payload)
|
||||
utils.require_admin(context)
|
||||
local status, objs = pcall(nk.storage_read, {{ collection = "shop_config", key = "featured_banners", user_id = "00000000-0000-0000-0000-000000000000" }})
|
||||
if status and objs and #objs > 0 then
|
||||
return nk.json_encode({ banners = objs[1].value.banners or {} })
|
||||
end
|
||||
return nk.json_encode({ banners = {} })
|
||||
end
|
||||
|
||||
nk.register_rpc(economy.rpc_get_shop_catalog, "get_shop_catalog")
|
||||
nk.register_rpc(economy.rpc_buy_currency, "buy_currency")
|
||||
nk.register_rpc(economy.rpc_purchase_item, "purchase_item")
|
||||
nk.register_rpc(economy.rpc_admin_set_featured_banners, "admin_set_featured_banners")
|
||||
nk.register_rpc(economy.rpc_admin_get_featured_banners, "admin_get_featured_banners")
|
||||
|
||||
nk.logger_info("LUA TEST: economy module loaded successfully")
|
||||
|
||||
return economy
|
||||
Reference in New Issue
Block a user