tdengine 0.1.2

game server for Rust
Documentation
-- user.lua
-- Created by wugd
-- 玩家基类

USER_TDCLS = tdcls(DBASE_TDCLS, RID_TDCLS, AGENT_TDCLS, HEARTBEAT_TDCLS, ATTRIB_TDCLS)
USER_TDCLS.name = "USER_TDCLS"

function USER_TDCLS:create(value)
    assert(type(value) == "table", "user::create para not corret")
    self:replace_dbase(value)
    self:set("ob_type", OB_TYPE_USER)
    self:freeze_dbase()

    self:set_temp("container", clone_object(CONTAINER_TDCLS, {rid = get_ob_rid(self)}))

end

function USER_TDCLS:destruct()
    if self:query_temp("entered_world") then
        self:leave_world()

        -- 移除此 raiser
        remove_responder_from_raiser(self:get_ob_id())
        remove_audience_from_raiser(self:get_ob_id())

        -- 保存玩家相关数据
        USER_D.hiberate(self)
    end

    local account_ob = find_object_by_rid(self:query("account_rid"))
    if is_object(account_ob) then
        destruct_object(account_ob)
    end

    destruct_object(self:get_container())
    destruct_object(self:get_ddz_dbase())

    self:delete_logout_timer()
end

-- 生成对象的唯一ID
function USER_TDCLS:get_ob_id()
    return (string.format("USER_TDCLS:%s:%s", save_string(self:query("rid")),
                         save_string(self:query("account_rid"))))
end

function USER_TDCLS:delete_logout_timer()
    if is_valid_timer(self.logout_timer) then
        delete_timer(self.logout_timer)
        self.logout_timer = nil
    end
end

-- 定义公共接口,按照字母顺序排序
-- 将连接对象转接到 user 对象上
function USER_TDCLS:accept_relay(agent, is_reconnect)
    
    -- 将连接转换到 user 对象上
    agent:relay_comm(self)
    
    -- if is_reconnect then
    --     self:send_message(MSG_RECONNECT_INFO, {ret = 0})
    -- end
    self:enter_world()
    self:delete_logout_timer()
end

function USER_TDCLS:logout_callback()
    USER_D.user_logout(self)
end

-- 连接断开时不立即析构对像,供断线重连
function USER_TDCLS:connection_lost(at_once)
    self:set("last_logout_time", os.time())
    if self:query_temp("login_act_time") ~= nil then
        self:add_attrib("all_login_time", os.time() - self:query_temp("login_act_time"))
        self:delete_temp("login_act_time")
    end

    if at_once then
        USER_D.user_logout(self)
    else
        self:close_agent()
        if not is_valid_timer(self.logout_timer) then
            self.logout_timer = set_timer(30, self.logout_callback, self)--30000
        end
    end

    REDIS_D.run_publish(REDIS_USER_CONNECTION_LOST, get_ob_rid(self))
end

-- 玩家进入世界
function USER_TDCLS:enter_world()
    --设置心跳时间
    self:set_heartbeat_interval(30000)
    -- 发送开始游戏的消息
    self:set_temp("entered_world", true)
    raise_issue(EVENT_USER_LOGIN, self)
    trace("玩家(%o  %s/%s)进入游戏世界。\n", self:query("name"), get_ob_rid(self), self:query("account_rid"))
   
    local data = {
        user = self:query(), 
        item_list = self:get_dump_item(),
        equip_list = self:get_dump_equip(),
        ddz_info = self:get_ddz_dbase():query(),
    }
   
    self:send_message(MSG_ENTER_GAME, data)
    
    self:set_temp("login_act_time", os.time())

    local value = {rid=get_ob_rid(self), online=1}
    USER_D.publish_user_attr_update(value)

    -- 日志记录玩家登录
    LOG_D.to_log(LOG_TYPE_LOGIN_RECORD, get_ob_rid(self), tostring(self:query("account_rid")), "", "")

    REDIS_D.run_publish(REDIS_USER_ENTER_WORLD, encode_json({rid = get_ob_rid(self), server_id = tonumber(SERVER_ID)}))
end

-- 取得对象类
function USER_TDCLS:get_ob_class()
    return "USER_TDCLS"
end

-- 玩家离开世界
function USER_TDCLS:leave_world()
    self:delete_hearbeat()
    raise_issue(EVENT_USER_LOGOUT, self)
    trace("玩家(%s/%s)离开游戏世界。\n", get_ob_rid(self), self:query("account_rid"))
    self:delete_temp("entered_world")

    local value = {rid=get_ob_rid(self), online=0}
    USER_D.publish_user_attr_update(value)

    LOG_D.to_log(LOG_TYPE_LOGOUT_RECORD, get_ob_rid(self), tostring(self:query("account_rid")), "", "")
end

-- 取得保存数据库的信息
function USER_TDCLS:save_to_mapping()
      -- 玩家数据发生变化的字段
    local change_list = self:get_change_list()
    local data = {}

    for key,_ in pairs(change_list) do
        if USER_D.is_in_user_fields(key) then
            data[key] = self:query(key)
        end
    end
    return data
end

-- 取得数据库的保存路径
function USER_TDCLS:get_save_oper()
    return "user", { rid = get_ob_rid(self) }
end

function USER_TDCLS:set_change_to_db(callback, arg)
    local dbase = self:save_to_mapping()
    arg.sql_count = arg.sql_count + 1
    if is_empty_table(dbase) then
        if callback then callback(arg, 0, {}) end
    else
        local table_name, condition = self:get_save_oper()
        local sql = SQL_D.update_sql(table_name, dbase, condition)
        DB_D.execute_db(table_name, sql, callback, arg)
        self:freeze_dbase()
    end
    self:save_sub_content(callback, arg)
end

function USER_TDCLS:save_sub_content(callback, arg)
    -- 取得玩家容器中的所有物件的保存信息
    for pos, ob in pairs(self:get_container():get_carry()) do
        assert(is_object(ob))
        if is_object(ob) then
            -- 取得该物件需要保存的 dbase
            local dbase, is_part = ob:save_to_mapping()
            if dbase then

                -- 取得该物件的保存操作相关信息
                local table_name, primary, oper = ob:get_save_oper()
                local sql
                if oper == "insert" then
                    sql = SQL_D.insert_sql(table_name, dbase)
                elseif oper == "update" then
                    sql = SQL_D.update_sql(table_name, dbase, {rid = primary})
                else
                    assert(false, "unknow op")
                end
                arg.sql_count = arg.sql_count + 1
                DB_D.execute_db(table_name, sql, callback, arg)
            end
        end
    end

    self:save_obj_content(self:get_ddz_dbase(), callback, arg)
end

function USER_TDCLS:save_obj_content(ob, callback, arg)
    if is_object(ob) then
        ob:set_change_to_db(callback, arg)
    end
end

-- 弹出提示文字
function USER_TDCLS:notify_message_info(message, is_important)
    self:send_message(MSG_MESSAGE_TIP, {msg_type = MSG_TYPE_MESSAGE, msg_info = message})
end

-- 弹出提示框
function USER_TDCLS:notify_dialog_ok(message, is_important)
    self:send_message(MSG_MESSAGE_TIP, {msg_type = MSG_TYPE_DIALOG, msg_info = message})
end

-- 弹出提示框
function USER_TDCLS:notify_scroll(message, is_important)
    self:send_message(MSG_MESSAGE_TIP, {msg_type = MSG_TYPE_SCROLL, msg_info = message})
end

function USER_TDCLS:is_user()
    return true
end

-- 通知字段变更
function USER_TDCLS:notify_fields_updated(field_names)
    self:notify_property_updated(get_ob_rid(self), field_names)
end

-- 通知物件加载
function USER_TDCLS:notify_property_loaded(rid)
    local ob = find_object_by_rid(rid)
    local appearance = APPEARANCE_D.get_appearance(ob, "SELF")
    self:send_message(MSG_PROPERTY_LOADED, get_ob_rid(self), { appearance })
end

-- 通知物件删除
function USER_TDCLS:notify_property_delete(rids)
    if is_string(rids) then
        rids = { rids }
    end
 
    self:send_message(MSG_PROPERTY_DELETE, rids )
end

-- 通知玩家物件字段变更
function USER_TDCLS:notify_property_updated(rid, field_names)
    if is_string(field_names) then
        field_names = { field_names }
    end

    local ob = find_object_by_rid(rid)
    if not ob then
        return
    end

    local info = APPEARANCE_D.build_object_info(ob, field_names)
    self:send_message(MSG_OBJECT_UPDATED, rid, info)
end

-- 保存所有记录
function USER_TDCLS:save_all()
    USER_D.hiberate(self)
end

function USER_TDCLS:get_attr_desc(fields)
    local result = {rid=get_ob_rid(self)}
    for _,v in ipairs(fields) do
        result[v] = self:query(v)
    end
    return result
end

function USER_TDCLS:query_log_channel()
    return self:query_temp("LOG_CHANNEL")
end

function USER_TDCLS:set_log_channel(channel)
    self:set_temp("LOG_CHANNEL", channel)
end

function USER_TDCLS:get_container()
    return self:query_temp("container")
end

function USER_TDCLS:set_ddz_dbase( ddz_info )
    self:set_temp("ddz_info", clone_object(DDZ_INFO_TDCLS, get_ob_rid(self), ddz_info))
end

function USER_TDCLS:get_ddz_dbase()
    return self:query_temp("ddz_info")
end

function USER_TDCLS:get_dump_item()    
    local result = {}
    for _, data in pairs(self:get_item_dbase()) do
        table.insert(result, data:query())
    end
    return result
end

function USER_TDCLS:get_item_dbase()
    return self:get_container():get_page_carry(PAGE_ITEM)
end

function USER_TDCLS:get_dump_equip()
    local result = {}
    for _, data in pairs(self:get_equip_dbase()) do
        table.insert(result, data:query())
    end
    return result
end

function USER_TDCLS:get_equip_dbase()
    return self:get_container():get_page_carry(PAGE_EQUIP)
end