123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376 |
- --活动时间服务
- local skynet = require "skynet"
- require "skynet.manager"
- local redisdriver = require "skynet.db.redis"
- local logger = require "logger"
- local common_fun = require "model.common_fun"
- local util = require "util"
- local asset = require "model.asset"
- local cjson = require "cjson"
- local stringify = require "stringify"
- local queue = require "skynet.queue"
- local trace = logger.trace
- --local trace = function(...) end
- local string_format = string.format
- local skynet_retpack = skynet.retpack
- local synchronized = queue()
- cjson.encode_sparse_array(true, 1)
- local STATE_OPEN = 0 -- 活动开启
- local STATE_CLOSE = 1 -- 活动结束
- local CMD = {}
- local activity = {}
- local THIS = {}
- local finishtime = { --记录已经开启活动,或者即将开启的活动
- --[[
- [activ_tyep] = {
- -- 活动信息
- }
- ]]
- }
- local recent_finishtime = { -- 开启/待开启/结束 (先筛选开启中 - 筛选待开启 - 筛选以结束)
- }
- local all_activity_time = {} -- 所有活动的数据 [sid] = {}
- local usercenter --玩家服务
- local redis --数据库
- local KEY_FORMAT = "activity:%s"
- local globaltime --开服时间
- local TEN_YEAR -- 开服十年后的时间节点
- local cache_acti = { -- 内存活动数据 配置表转发而来
- --[[
- [id] = {
- 活动信息
- }
- ]]
- }
- local IMM_SEND = false -- 立即推送活动数据
- local calculate = {}
- -- TODO: 活动时间类型 1
- --[[
- opentype = 1 永久活动 直接开启十年
- ]]
- calculate[1] = function(aconfig, t_type, act_info)
- act_info[1] = STATE_OPEN
- act_info[2] = globaltime
- act_info[3] = TEN_YEAR
- end
- -- TODO: 活动类型 2
- --[[
- opentype = 2 限时活动
- ]]
- calculate[2] = function(aconfig, t_type, act_info, now)
- local opentime = common_fun.split(aconfig.starttime)
- local endtime = common_fun.split(aconfig.endtime)
- if now >= opentime and now < endtime then
- act_info[1] = STATE_OPEN
- else
- act_info[1] = STATE_CLOSE
- end
- act_info[2] = opentime -- 活动开启时间
- act_info[3] = endtime -- 活动结束时间
- end
- function THIS.split_unknown(str)
- local ret = {}
- for t in string.gmatch(str, "(%d+)%/?") do
- table.insert(ret, 1, tonumber(t))
- end
- return ret
- end
- local function math_type6(tab)
- return tab[1]+ (tab[2] or 0)*MIN_SEC + (tab[3] or 0) * HOUR_SEC + ((tab[4] or 0)-1) *DAY_SEC
- end
- -- TODO: 活动类型 3
- --[[
- opentype = 3 开服活动
- ]]
- calculate[3] = function(aconfig, t_type, act_info, now)
- local list1 = THIS.split_unknown(aconfig.starttime) -- 活动开启配置
- local list2 = THIS.split_unknown(aconfig.endtime) -- 活动结束配置
- local opentime = globaltime + math_type6(list1)
- local endtime = globaltime + math_type6(list2)
- if now >= opentime and now < endtime then
- act_info[1] = STATE_OPEN
- else
- act_info[1] = STATE_CLOSE
- end
- act_info[2] = opentime -- 活动开启时间
- act_info[3] = endtime -- 活动结束时间
- end
- -- TODO: 计算活动开启时间, 及活动现在状态
- local function calculate_time(aconfig)
- local t_type = aconfig.opentype -- 活动开启类型
- -- globaltime -- 开服时间
- local now = os.time()
- local act_info = {
- [1] = STATE_CLOSE, -- 活动状态
- [2] = 0, -- 活动开启时间
- [3] = 0, -- 活动结束时间
- }
- calculate[t_type](aconfig, t_type, act_info, now)
- logger.trace(" id = %s, type = %s, opentype = %s, state = %s, open = %s, end = %s",
- aconfig.ID, aconfig.type, t_type, act_info[1], os.date("%Y-%m-%d %H:%M:%S",tonumber(act_info[2])),
- os.date("%Y-%m-%d %H:%M:%S",tonumber(act_info[3]))
- )
- return table.unpack(act_info)
- end
- -- TODO: 活动状态发生变化,推送活动数据
- function activity.send_active_info()
- --通知在线的玩家有活动的状态发生了变更
- skynet.send(usercenter, "lua", "command", "update", finishtime)--向服务器推送
- trace("限时活动时间new_finishtime:%s",stringify(finishtime))
- end
- -- TODO: 热更接口
- function CMD.hotfix(list)
- if list.ActivityConfig_proto then
- synchronized(function()
- logger.trace(" ========== 热更活动配置表")
- -- 读取配置,活动时间数据
- local temp = activity.load_conf()
- cache_acti = temp
- IMM_SEND = true
- end)
- end
- end
- -- TODO: 检查有活动状态, 并返回已经开启的活动 及 是否有活动状态变化
- function THIS.check_active_state()
- local open_act = {} -- 开启中得活动
- local finsi_act = {} -- 结束了得活动
- local recent_act = {} -- 待开启得活动
- local now = os.time()
- local nstate
- local change = false
- for sid, ainfo in pairs(cache_acti) do
- if ainfo.opentime <= now and ainfo.endtime > now then
- nstate = STATE_OPEN
- if open_act[ainfo.activity_type] then
- if ainfo.sid < open_act[ainfo.activity_type].sid then
- open_act[ainfo.activity_type] = ainfo
- change = true
- end
- else
- open_act[ainfo.activity_type] = ainfo
- end
- else
- nstate = STATE_CLOSE
- end
- if now < ainfo.opentime then -- 待开启活动
- if recent_act[ainfo.activity_type] then
- if recent_act[ainfo.activity_type].opentime > ainfo.opentime then -- 取时间小得
- recent_act[ainfo.activity_type] = ainfo
- end
- else
- recent_act[ainfo.activity_type] = ainfo
- end
- end
- if now >= ainfo.endtime then -- 已经结束得活动
- if finsi_act[ainfo.activity_type] then
- if finsi_act[ainfo.activity_type].endtime < ainfo.endtime then -- 取时间大得
- finsi_act[ainfo.activity_type] = ainfo
- end
- else
- finsi_act[ainfo.activity_type] = ainfo
- end
- end
- -- 检查状态是否变化
- if nstate ~= ainfo.state then
- logger.trace(" -- 活动状态改变 sid = %s, ainfo = %s", sid, stringify(ainfo))
- change = true
- ainfo.state = nstate
- end
- end
- return open_act, finsi_act, recent_act, change
- end
- --创建检查活动配置时间的协程
- function activity.detection()
- skynet.fork(function()
- local change, finsi_act, recent_act, recent_temp
- -- 处理 最近活动数据
- local dis_recent = function(tt, act)
- for sid, v in pairs(act) do
- if not tt[sid] then
- tt[sid] = v
- end
- end
- end
- while true do
- synchronized(function()
- finishtime, finsi_act, recent_act, change = THIS.check_active_state()
- -- 有活动发生了变化
- -- logger.trace(" ===============finishtime = %s", stringify(finishtime))
- recent_temp = {}
- dis_recent(recent_temp, finishtime)
- dis_recent(recent_temp, finsi_act)
- dis_recent(recent_temp, recent_act)
- recent_finishtime = recent_temp
- if change or IMM_SEND then
- activity.send_active_info()
- IMM_SEND = false
- end
- redis:set("activity:activity_time", cjson.encode(finishtime))
- end)
- skynet.sleep(100)
- end
- end)
- end
- --获得限时活动指定的时间
- function CMD.getassigntime(name)
- return synchronized(function()
- return finishtime[name]--state0是关闭1是开启
- end)
- end
- --玩家上线的时候获取一次所有限时活动的时间
- function CMD.getactivitytime()
- return synchronized(function()
- return finishtime
- end)
- end
- -- 获取对接活动数据
- function CMD.get_recent_activitytime()
- return synchronized(function()
- return recent_finishtime
- end)
- end
- -- 获取对接活动数据
- function CMD.get_recent_assigntime(name)
- return synchronized(function()
- return recent_finishtime[name]
- end)
- end
- function CMD.get_sid_info(sid)
- return all_activity_time[sid]
- end
- -- TODO: 准备-加载数据库数据
- function activity.prepare()
- local key = string_format(KEY_FORMAT, "global")
- local res = redis:hget(key, "starttime")
- if res then
- globaltime = util.today(tonumber(res)+HOUR_SEC) -- 防止冬夏令时导致的时间异常
- else
- res = util.today()
- globaltime = res
- redis:hmset(key, "starttime", res)
- end
- end
- function CMD.query()
- return globaltime
- end
- function CMD.open_day()
- return math.max(1, (util.today() - globaltime)/DAY_SEC + 1)
- end
- -----------------------------------------------------------------------
- -- TODO: 筛选本服得活动
- function activity.filtrate_activity()
- local ret = {}
- local act_conf = asset.ActivityConfig_proto
- for sid, info in pairs(act_conf) do
- ret[sid] = common_fun.scopy(info)
- end
- return ret
- end
- -- TODO: 加载活动配置数据,并生成时间节点 及活动状态
- function activity.load_conf()
- local act_conf = activity.filtrate_activity()
- local temp_act = {} -- 配置表转发活动数据结构, 临时存储
- for sid, aconfig in pairs(act_conf) do
- local astate, aopne_tm, aend_tm = calculate_time(aconfig)
- temp_act[sid] = {
- sid = sid, -- 活动sid
- state = astate, -- 活动状态
- switch = aconfig.switch, -- 临时关闭标记
- activity_type = aconfig.type, -- 活动类型
- name = aconfig.name, -- 活动名字
- opentime = aopne_tm,
- endtime = aend_tm,
- sort = aconfig.sort,
- icon = aconfig.icon -- 活动icon
- }
- all_activity_time[sid] = temp_act[sid]
- end
- return temp_act
- end
- function CMD.start()
- usercenter = usercenter or skynet.localname(".usercenter")
- local conf = assert(option.redis)
- redis = redisdriver.connect(conf)
- redis:select(1)--切换到数据库db1
- activity.prepare()
- TEN_YEAR = globaltime + DAY_SEC*365*10
- -- 读取配置,活动时间数据
- cache_acti = activity.load_conf()
- IMM_SEND = true
- activity.detection()--检查时间
- -- 冲关
- -- skynet.fork(function()
- -- skynet.sleep(300)
- -- CMD.hotfix()
- -- end)
- end
- skynet.info_func(function()
- return {
- open_activie = finishtime, -- 已经开启的活动关
- cache_acti = cache_acti, -- 所有活动情况
- }
- end)
- skynet.init(function()
- skynet.register(".activitytime")
- end)
- skynet.start(function()
- skynet.dispatch("lua", function(session, _, cmd, ...)
- local f = assert(CMD[cmd])
- if session == 0 then
- f(...)
- else
- skynet_retpack(f(...))
- end
- end)
- end)
|