local skynet = require "skynet" local util = require "util" local logger = require "logger" local packstring = skynet.packstring local unpack = skynet.unpack local intmax = math.maxinteger local clamp = util.clamp local table_insert = table.insert local traceback = debug.traceback local spawn = function(readonly) -- 首先,定义角色默认的数据结构 local datasource = { -- TODO: 在下面定义 Number 和 String 类型的字段 uid = nil, -- 角色ID sid = nil, -- 服务器ID account = nil, -- 帐号唯一标识(渠道分配) appid = nil, -- App唯一标识 channel = nil, -- 渠道唯一标识 platform = nil, -- 操作系统(pc,ios,android等) tourist = nil, -- 游客标识:1:非游客账号 2: 游客账号 -- CDPK3-005 海外SDK reported = nil, -- 玩家角色数据上报 --PK3-1366 数据统计 createtime = nil, -- 创号时间 lastlogin = nil, -- 最后登录时间 lastlogout = nil, -- 最后下线时间 forbidden = 0, -- 封号标志0是正常,非0解封号时间 silent = 0, -- 禁言标志0是正常,非0解禁言时间 fb = nil, -- 玩家绑定faceboik帐号使用的云帐号 facebook = nil, -- 玩家绑定facebook账号 google = nil, -- 玩家绑定google账号 ios = nil, -- 玩家绑定ios账号 nickname = nil, -- 角色名 rename_time = 0, -- 改变名字的时间 level = 1, -- 队伍等级 exp = 0, -- 队伍经验 avater = 0, -- avater vip = 0, -- vip等级 updiamond = 0, -- vip经验 money = 0, -- 充值金额 daily_refresh = 0, -- 每日刷新时间 weekly_refresh = 0, -- 每周刷新时间 ban_rank = 0, -- 禁用排行 power = 0, -- 战斗力 -- TODO: 在下面定义二进制类型的字段 (BLOB) role = nil, -- 角色数据 currency = nil, -- 货币 adventure = nil, -- 冒险 building = nil, -- 建筑 mail = nil, -- 邮件 hero = nil, -- 英雄 embattle = nil, -- 阵容 debris = nil, -- 碎片 skill_card = nil, -- 技能卡牌 equip = nil, -- 装备 talent = nil, -- 天赋 sign_in = nil, -- 签到 stats = nil, -- 任务数据统计 quest = nil, -- 任务 manual = nil, -- 战令 draw = nil, -- 抽奖 grocery = nil, -- 杂货店 time_box = nil, -- 宝箱 activitytimemod = nil, -- 活动时间 } -- 定义角色数据的只读元表 local mt = { __index = datasource, __newindex = function(t, k, v) assert(false, "attempt to update a read-only table") end } -- 定义 setter 的基础函数 local tracker = {} local function setter(k, v) tracker[k] = v datasource[k] = v end local function n_setter(k, v, low, up) v = clamp(v, low, up or intmax) tracker[k] = v datasource[k] = v end -- TODO: 在下面定义字段的 setter local self = { readonly=readonly } function self.set_exp(value, up) n_setter('exp', value, 0, up) end function self.set_avater(value, up) n_setter('avater', value, 0, up) end function self.set_forbidden(value, up) n_setter('forbidden', value, 0, up) end function self.set_silent(value, up) n_setter('silent', value, 0, up) end function self.set_lastlogin(value, up) n_setter('lastlogin', value, 0, up) end function self.set_lastlogout(value, up) n_setter('lastlogout', value, 0, up) end function self.set_level(value, up) n_setter('level', value, 1, up) end function self.set_rename_time(value, up) n_setter('rename_time', value, 1, up) end function self.set_nickname(value) setter('nickname', value) end function self.set_vip(value, up) n_setter('vip', value, 0, up) end function self.set_updiamond(value, up) n_setter('updiamond', value, 0, up) end--累计充值钻石 function self.set_money(value, up) n_setter('money', value, 0, up) end--累计充值的金额 function self.set_daily_refresh(value, up) n_setter('daily_refresh', value, 0, up) end function self.set_weekly_refresh(value, up) n_setter('weekly_refresh', value, 0, up) end function self.set_ban_rank(value, up) n_setter('ban_rank', value, 0, up) end function self.set_power(value, up) n_setter('power', value, 0, up) end function self.set_currency(value) setter('currency', value) end function self.set_role(value) setter('role', value) end function self.set_adventure(value) setter('adventure', value) end function self.set_building(value) setter('building', value) end function self.set_mail(value) setter('mail', value) end function self.set_hero(value) setter('hero', value) end function self.set_embattle(value) setter('embattle', value) end function self.set_debris(value) setter('debris', value) end function self.set_skill_card(value) setter('skill_card', value) end function self.set_equip(value) setter('equip', value) end function self.set_talent(value) setter('talent', value) end function self.set_sign_in(value) setter('sign_in', value) end function self.set_stats(value) setter('stats', value) end function self.set_quest(value) setter('quest', value) end function self.set_manual(value) setter('manual', value) end function self.set_draw(value) setter('draw', value) end function self.set_grocery(value) setter('grocery', value) end function self.set_time_box(value) setter('time_box', value) end --------------------------------- setter end --------------------------------- local function loadfrom(metadata) assert(metadata) local dest = datasource for i=1, #metadata, 2 do local k = metadata[i] local v = metadata[i+1] if k == "nickname" then dest[k] = v else dest[k] = tonumber(v) or v end end dest.uid = tostring(dest.uid) return self end local function pack(k) if next(tracker) then local pkg = { k } for field, value in pairs(tracker) do table_insert(pkg, field) table_insert(pkg, value) end tracker = {} -- Must do it return pkg end end local function packall(k) tracker = datasource return pack(k) end -- TODO: 备份抛弃的数据 local backups_discard = { presence = 'presence', } local function backups_all() local ret = {} for k, v in pairs(datasource) do if not backups_discard[k] then if type(v) == 'number' or k == 'uid' or k == 'channel' or k == 'nickname' or k == 'account' or k == 'appid' or k == 'platform' then ret[k] = v else ret[k] = unpack(v) end end end return ret end local listener = {} local function dispatch(signame, ...) local sigslot = listener[signame] or {} for i, v in ipairs(sigslot) do local ok,info = xpcall(v, traceback, self, ...) if not ok then logger.trace("dispatch errno %s, errno info %s", signame, info) end end end local function monitor(signame, f) listener[signame] = listener[signame] or {} table_insert(listener[signame], f) end local specific = {} local function getspecific(k) return specific[k] end local function register_specific(k, alloc) assert(not specific[k], k) local d = nil local v = datasource[k] if v then d = unpack(v) elseif alloc then d = alloc() end local f = rawget(self, 'set_'..k) local function get() return d end local function save() assert(f, string.format("attempt to call a nil value(field 'set_%s')", k)) f(packstring(d)) end specific[k] = { get=get, save=save, runtime={} } return d end -- Ok, let's go on self.loadfrom = loadfrom self.pack = pack self.packall = packall self.dispatch = dispatch self.monitor = monitor self.getspecific = getspecific self.register_specific = register_specific self.backups_all = backups_all self.__index = self return setmetatable(self, mt) end return spawn