根据原来项目的商店和需求整合了商城系统,记述下开发的思路
普通的商店功能,但为了后续更有效的添加商店,做了优化处理
数据库结构异常简单,其实在初始化的时候加载数据
function StorePlug:Init()
for k,v in pairs(StoreConfig.Config) do
local store = Store.new(self.player)
local storeId = v.type
if not self.cache[storeId] then
self.cache[storeId] = {}
end
store:Init(storeId, self.cache[storeId])
self.storeList[storeId] = store
end
end
self.cache 读取数据库store数据,StoreConfig配置好商店列表对应storeid
function Store:Init(storeId, InitData)
--debug
lua_app.log_debug("Store:Init", storeId)
self.storeId = storeId
self.goodsRecords = InitData.goodsRecords or {}
self.updatetime = InitData.updatetime or 0
end
storeplug为商店管理类,store商店实体类,goodsrecords储存购买物品id和数量。
这是商城系统最重要的部分,但其实并不难。
1.购买传商店storeid,物品id和数量num,获取store实体类数据
--购买物品
function StorePlug:Buy(storeId, id, num)
-- debug
lua_app.log_debug("StorePlug:Buy", storeId, id, num)
if not num or num == 0 then
num =1
end
local store = self.storeList[storeId]
if not store then
return false
end
if not self:CheckBuy(storeId, id, num) then
return false
end
--通用商店new
return store:Buy(id, num)
end
2.读取商店配置,验证判定并保存数据
function Store:Buy(id, num)
--debug
lua_app.log_debug("Store:Buy", id, num)
local cfg = self:GoodsRecordsConfig(id)
if not self.player.bag:PutNewItemIn(cfg.item.item, cfg.item.count * num) then
server.sendErr(self.player, "can't put into bag")
return false
end
local pricecount = cfg.price.count
--判断是否存在折扣
if self.storeId == StoreConfig.StoreType.LuckyShop then
pricecount = getPrice(self.storeId,id,pricecount)
elseif cfg.discount then
pricecount = pricecount * cfg.discount
end
self.player:PayReward(
cfg.price.type,
cfg.price.id,
pricecount * num,
BaseConfig.YuanbaoRecordType.Store,
"商店购买"
)
self:SetGoodsRecordsCount(id, num)
local data = self:GetMsgData()
self:_SendPlayerToClient(data)
--debug
lua_app.log_debug("Store:Buy", "success")
return true
end
StoreConfig.Config = {
{type = 1,cfg = "LuckyShopConfig",storeType = "LuckyShop",limitType = 4},
{type = 2,cfg = "MallConfig",storeType = "MallStore",limitType = 2},
}
StoreConfig读取storeid对应的商店配置名称,购买验证判定其实放在Store类更好
function Store:GoodsRecordsConfig(id)
local cfg = StoreConfig.Config[self.storeId].cfg
return server.configCenter[cfg][id]
end
--验证购买条件
function StorePlug:CheckBuy(storeId,id, count)
local store = self.storeList[storeId]
local cfg = store:GoodsRecordsConfig(id)
if not cfg then
server.sendErr(self.player, "error cfgid")
return false
end
-- 如果限购,检查数量 默认为1
if cfg.limit then
local limitcount = 1
if cfg.num then
limitcount = tonumber(cfg.num)
end
if store:GetGoodsRecordsCount(id) + count > limitcount then
server.sendErr(self.player, "overflow limitcount")
return false
end
end
-- 检查等级
if cfg.level then
if self.player.cache.level < cfg.level then
server.sendErr(self.player, "not enough level")
return false
end
end
-- 检查时间
if cfg.time then
if lua_app.now() < getTimeStamp(cfg.time[1]) or lua_app.now() > getTimeStamp(cfg.time[2]) then
server.sendErr(self.player, "error time")
return false
end
end
-- 检查钱
if not self.player:CheckReward(cfg.price.type, cfg.price.id, cfg.price.value) then
server.sendErr(self.player, "not enough money")
return false
end
-- 检查背包
if self.player.bag:GetBagEmptyCount() <= 0 then
server.sendErr(self.player, "bag full")
return false
end
return true
end
根据条件分为每日每周和后续添加的12小时重置购买次数,重置类型依然配置的StoreConfig中
-- TODO:HJ player实现接口后调用这里
function StorePlug:onDayTimer()
for _, store in pairs(self.storeList) do
store:onDayReset()
end
end
function Store:onDayReset()
self:_ResetgoodsRecords(StoreConfig.LimitType.DayLimit)
end
function Store:onHalfHour()
if StoreConfig.Config[self.storeId].limitType == StoreConfig.LimitType.HalfDayLimit then
if lua_util.isfresh(self.updatetime) then
self:_ResetgoodsRecords(StoreConfig.LimitType.HalfDayLimit)
end
end
end
function Store:onWeekReset()
self:_ResetgoodsRecords(StoreConfig.LimitType.WeekLimit)
end
function Store:_ResetgoodsRecords(limitType)
--商店购买数据刷新
for goodsid, data in pairs(self.goodsRecords) do
local cfg = self:GoodsRecordsConfig(goodsid)
if cfg.limit.type == limitType then
data.count = 0
end
end
self.uptime = lua_app.now()
local data = self:GetMsgData()
self:_SendPlayerToClient(data)
end
1.初始化推送全部商城数据
function StorePlug:onInitClient()
--初始化商店信息
for k,store in pairs(self.storeList) do
store:onInitClient()
end
--初始化玩家购买信息
local datas = {}
for _, store in pairs(self.storeList) do
local data = store:GetMsgData()
table.insert(datas, data)
end
server.sendReq(
self.player,
"sc_store_play_update",
{
storedatas = datas
}
)
end
2.购买推送商店数据
function Store:_SendPlayerToClient(data)
--玩家购买物品信息
local datas = {}
table.insert(datas, data)
server.sendReq(
self.player,
"sc_store_play_update",
{
storedatas = datas
}
)
end
3.协议数据结构
#store
.store_goods_data {
id 0 : integer
buyCount 1 : integer
}
.store_buy_data {
storeId 0 : integer
goods 1 : *store_goods_data
}
这其实不算商城系统的功能,不过有些商店可能有各种奇怪的要求,下面这个辛运商店实例:
每12小时更新一次商品,玩家数据重置已经做了,不过商店是随机生成配置的部分物品和折扣价
--刷新商店
function LuckyShop:RefreshGoods()
local cfg = StoreConfig.Config[self.storeId].cfg
local luckyShopConfig = server.configCenter[cfg]
self.data = {}
--获取随机id和折扣
luckyShopConfig = lua_util.randArray(luckyShopConfig,6)
for id, scfg in pairs(luckyShopConfig) do
self.data[scfg.id] = {ratio = getRatio(scfg.discount)}
end
self.updatetime = lua_app.now()
server.settingCenter:SetData(SettingConfig.SettingType.LuckyShop,self.data)
self:sendRecordToClient()
return true
end
我选择的方式是创建一张全局配置表,每次刷新商店id和折扣率,初始和更新数据也发送给客户端
总体来说商店系统还是比较好做的,只要以后的商店统一配置管理,增加商店添加StoreConfig数据就行了