%% --------------------------------
%% desc  :聊天次数监控
%% time  :18/12/04
%% module:lib_chat_limit
%% author:hh
%% --------------------------------

%% 此聊天次数监控功能是对现有聊天监控的补充
%% 和现有的监控禁言功能不冲突
%% 细则:
% 1、国内服玩家在200级以下、V4以下，战力10W以下，发言时进行检查，匹配系统的关键词屏蔽库，如匹配到直接禁言72小时（仅限世界、私聊频道）
%    繁体服玩家同时满足150级以下、非VIP的限制私聊
% 2、玩家在150级以下、战力6W以下、V1以下、不允许发出大于等于50个字符的语句，仅自己可以看到（仅限世界频道）
% 3、被禁言的玩家无法收到其他人的消息（仅限私聊频道）
% 4、等级和对方相差30级，无法主动私聊对方，仅自己可以看到（仅限私聊频道，等级达到240级以上解除限制）
% 5、战力和对方相差30W以上，无法主动私聊对方，仅自己可以看到（仅限私聊频道，等级达到240级以上解除限制）
% 6、禁言、封号时前端会进行言论回收，回收时只回收其他玩家所看到的，不回收被禁言玩家本人的
% 7、每个角色的发言次数有限制，只有在完成一系列的隐藏任务后，才会增加（仅限世界、私聊频道）
% --245级及以上不检测，V2及以上不检测，战力60W及以上、男性角色不检测

% 隐藏任务
% 领取5分钟在线奖励（+3）
% 领取10分钟在线奖励（+6）
% 领取7天登录第一天奖励（+3）
% 领取冲级豪礼30级奖励（+1）
% 领取冲级豪礼65级奖励（+1）
% 领取冲级豪礼85级奖励（+1）
% 契兽达到1阶3星（+10）
% 日常必做达到1级（+3）
% 日常必做达到2级（+8）
% 日常必做达到3级（+15）
% 装备强化总等级达到10级（+1）
% 装备强化总等级达到20级（+3）
% 装备强化总等级达到30级（+5）

%% [{ModId, Id, Count}..]

-module(lib_chat_limit).

-include("server.hrl").
-include("chat.hrl").
-include("def_module.hrl").
-include("def_fun.hrl").
-include("figure.hrl").
-include("common.hrl").
-include("welfare.hrl").
-include("unite.hrl").
-include("predefine.hrl").
-include("errcode.hrl").
-include("game_vsn.hrl").

-export([
    login/1,
    incre_chat_count/2,
    get_role_shield/1,
    get_role_block/1,
    is_blocked/2
    ]).

-compile(export_all).



login(Id) ->
    SQL = io_lib:format(?SQL_CHAT_LIMIT_GET, [Id]),
    case db:get_row(SQL) of
        [ChatCount, ChatLimitsBin, SheildBin] ->
            #role_chat_limit{
             role_id = Id,
             chat_count = ChatCount,
             chat_limit = util:bitstring_to_term(ChatLimitsBin),
             role_shield = #role_shield{shield_roles = util:bitstring_to_term(SheildBin)}};
        _ ->
            #role_chat_limit{role_id = Id}
    end.

incre_lv_chat_count_limit(Player) ->
    #player_status{chat_limit_new = RoleChatLimit} = Player,
    #role_chat_limit{
        chat_count = ChatCount
    } = RoleChatLimit,
    NewRoleChatLimit = RoleChatLimit#role_chat_limit{chat_count = ChatCount+1},
    update(NewRoleChatLimit),
    Player#player_status{chat_limit_new = NewRoleChatLimit}.

update(RoleChatLimit = #role_chat_limit{}) ->
    #role_chat_limit{
        role_id = RoleId,
        chat_count = ChatCount,
        chat_limit = ChatLimits,
        role_shield = RoleShield
    } = RoleChatLimit,
    case RoleShield of
        #role_shield{shield_roles = SheildRoles} -> ok;
        _ ->
            SheildRoles = []
    end,
    SQL = io_lib:format(?SQL_CHAT_LIMIT_UPDATE,
     [RoleId, ChatCount, util:term_to_bitstring(ChatLimits), util:term_to_bitstring(SheildRoles)]),
    db:execute(SQL),
    ok;
update(Player = #player_status{}) ->
    #player_status{
        chat_limit_new = RoleChatLimit
    } = Player,
    #role_chat_limit{
        role_id = RoleId,
        chat_count = ChatCount,
        chat_limit = ChatLimits,
        role_shield = RoleShield
    } = RoleChatLimit,
    case RoleShield of
        #role_shield{shield_roles = SheildRoles} -> ok;
        _ ->
            SheildRoles = []
    end,
    SQL = io_lib:format(?SQL_CHAT_LIMIT_UPDATE,
     [RoleId, ChatCount, util:term_to_bitstring(ChatLimits), util:term_to_bitstring(SheildRoles)]),
    db:execute(SQL).



check_chat_role([], _Status, _, Sofar) ->
    if Sofar =:= [] -> true; true -> Sofar end;
check_chat_role([H|Rest], Status, Data, Sofar) ->
    case do_check_chat_role(H, Data, Status) of
        true ->
            check_chat_role(Rest, Status, Data, Sofar);
        Res = {true, chat_count_incre} ->
            check_chat_role(Rest, Status, Data, [Res|Sofar]);
        Res = {num_limit} ->
            check_chat_role(Rest, Status, Data, [Res|Sofar]);
        Res = {string_limit} ->
            check_chat_role(Rest, Status, Data, [Res|Sofar]);
        Res = {lv_power_diff_limit} ->
            check_chat_role(Rest, Status, Data, [Res|Sofar]);
        Res = {sensisitve_limit} ->
            check_chat_role(Rest, Status, Data, [Res|Sofar]);
        Res = {opp_talk_lim} ->
            check_chat_role(Rest, Status, Data, [Res|Sofar]);
        _ ->
            check_chat_role(Rest, Status, Data, Sofar)
    end.


do_check_chat_role(num_limit, _, Status) ->
    #player_status{
        figure = #figure{lv = RoleLv, vip = Vip, power = Power},
        chat_limit_new = RoleChatLimit
    } = Status,
    #role_chat_limit{chat_count = ChatCount, chat_limit = ChatNumLimits} = RoleChatLimit,
    LvLimit = lib_chat_limit:get_lv_chat_count(RoleLv),
    OtherChatCount = lib_chat_limit:calc_chat_count(ChatNumLimits),
    if LvLimit =:= nolimit ->
            true;
        Vip >= 2 ->
            true;
        Power >= 600000 ->
            true;
        ChatCount < LvLimit + OtherChatCount ->
            {true, chat_count_incre};
        true ->
            {num_limit}
    end;
do_check_chat_role(lv_diff_string_limit, [_ReceiveId, Content], Status) ->
    #player_status{
        figure = #figure{lv = RoleLv, power = Power, vip = Vip}
    } = Status,
    case lib_chat_limit:get_string_limit(RoleLv, Power, Vip, Content) of
        {string_limit, _} -> {string_limit};
        _                 -> true
    end;
do_check_chat_role(lv_power_diff_limit, [ReceiveId, _], Status) ->
    #player_status{
        figure = #figure{lv = RoleLv, power = Power}
    } = Status,
    #figure{lv = OppLv, power = OppPower} = lib_role:get_role_figure(ReceiveId),
    {ConfigLv, ConfigPower} = lib_chat_limit:get_private_diff_limit(),
    DiffLv = abs(RoleLv-OppLv),
    DiffPower = abs(Power-OppPower),
    if RoleLv < 240 -> %% 240及240级以上的不检测
            if
                DiffLv >= ConfigLv orelse DiffPower >= ConfigPower ->
                    {lv_power_diff_limit};
                true ->
                    true
            end;
        true ->
            true
    end;
do_check_chat_role({lv_power_diff_limit, ?VER_TW}, [_ReceiveId, _], Status) ->
    #player_status{
        figure = #figure{lv = RoleLv, vip = Vip}
    } = Status,
    if RoleLv < 150 andalso Vip == 0 ->
            {lv_power_diff_limit};
        true ->
            true
    end;
do_check_chat_role(sensisitve_limit, [_, ChatContent], Status) ->
    case lib_chat_limit:check_if_sensitive(Status, ChatContent) of
        false -> true;
        _A    -> {sensisitve_limit}
    end;
do_check_chat_role(opp_talk_lim, [ReceiveId, _ChatContent], _Status) ->
    case mod_chat_agent:lookup(ReceiveId) of
        [#ets_unite{talk_lim = 1, talk_lim_time = TalkLimTime}] ->
            case utime:unixtime() < TalkLimTime of
                true  -> {opp_talk_lim};
                false -> true
            end;
        _ ->
            true
    end;
do_check_chat_role(_, _, _) ->
    true.



get_lv_chat_count(Lv) ->
    if Lv < 60                     -> 0;
        60 =< Lv andalso Lv < 65   -> 1;
        65 =< Lv andalso Lv < 75   -> 2;
        75 =< Lv andalso Lv < 90   -> 3;
        90 =< Lv andalso Lv < 125  -> 4;
        125 =< Lv andalso Lv < 130 -> 5;
        130 =< Lv andalso Lv < 150 -> 6;
        150 =< Lv andalso Lv < 160 -> 7;
        160 =< Lv andalso Lv < 180 -> 8;
        180 =< Lv andalso Lv < 200 -> 10;
        200 =< Lv andalso Lv < 220 -> 15;
        220 =< Lv andalso Lv < 245 -> 20;
        true                       -> nolimit
    end.

get_string_limit(RoleLv, Power, Vip, ChatContent) ->
    if RoleLv =< ?DIFF_LV andalso Power =< ?DIFF_POWER andalso Vip =< ?DIFF_VIP ->
            NewChatContent = if
                is_integer(ChatContent) -> integer_to_list(ChatContent);
                is_atom(ChatContent)    -> atom_to_list(ChatContent);
                is_tuple(ChatContent)   -> tuple_to_list(ChatContent);
                is_float(ChatContent)   -> float_to_list(ChatContent);
                true                    -> ChatContent
            end,
            case util:check_length(NewChatContent, 30) of
                true ->
                    true;
                _ ->
                    {string_limit, 30}
            end;
        true ->
            true
    end.

get_private_diff_limit() ->
    {30, 300000}.

check_if_sensitive(Player, ChatContent) ->
    #player_status{figure = #figure{lv = RoleLv, vip = Vip, power = Power}} = Player,
    if RoleLv =< ?SEN_LV andalso Vip =< ?SEN_VIP andalso Power =< ?SEN_POWER ->
        mod_word:word_is_sensitive_banned(ChatContent);
        true ->
            false
    end.

%%incre_chat_count({online_gift, FetchID}, Player) ->
%%    #player_status{chat_limit_new = RoleChatLimit} = Player,
%%    #role_chat_limit{chat_limit = ChatLimit} = RoleChatLimit,
%%    #base_online_gift{limit = Limit}= data_online_gift:get_online_gift(FetchID),
%%    if Limit =:= 300 orelse Limit =:= 600 ->
%%        case lists:keyfind({?MOD_WELFARE, FetchID}, 1, ChatLimit) of
%%            {_, _ChatCount} ->
%%                Player;
%%            _ ->
%%                CountAdd = case Limit of
%%                    300 -> 3;
%%                    600 -> 6;
%%                    _ -> 0
%%                end,
%%                NewChatLimit = lists:keystore({?MOD_WELFARE, FetchID}, 1, ChatLimit, {{?MOD_WELFARE, FetchID}, CountAdd}),
%%                NewRoleChatLimit = RoleChatLimit#role_chat_limit{chat_limit = NewChatLimit},
%%                update(NewRoleChatLimit),
%%                Player#player_status{chat_limit_new = NewRoleChatLimit}
%%        end;
%%        true ->
%%            Player
%%    end;
incre_chat_count({login_day_reward, ?MOD_LOGIN_REWARD}, Player) ->
    #player_status{chat_limit_new = RoleChatLimit} = Player,
    #role_chat_limit{chat_limit = ChatLimit} = RoleChatLimit,
    case lists:keyfind({?MOD_LOGIN_REWARD}, 1, ChatLimit) of
        {_, _ChatCount} ->
            Player;
        _ ->
            CountAdd = 3,
            NewChatLimit = lists:keystore({?MOD_LOGIN_REWARD}, 1, ChatLimit, {{?MOD_LOGIN_REWARD}, CountAdd}),
            NewRoleChatLimit = RoleChatLimit#role_chat_limit{chat_limit = NewChatLimit},
            update(NewRoleChatLimit),
            Player#player_status{chat_limit_new = NewRoleChatLimit}
    end;
incre_chat_count({lv_reward, BagLv}, Player) ->
    #player_status{chat_limit_new = RoleChatLimit} = Player,
    #role_chat_limit{chat_limit = ChatLimit} = RoleChatLimit,
    if BagLv =:= 30 orelse BagLv =:= 65 orelse BagLv =:= 85 orelse BagLv =:= 105 ->
            case lists:keyfind({?MOD_WELFARE, BagLv}, 1, ChatLimit) of
                {_, _ChatCount} ->
                    Player;
                _ ->
                    CountAdd = case BagLv of
                        30 ->  1;
                        65 ->  1;
                        85 ->  1;
                        _  ->  0
                    end,
                    NewChatLimit = lists:keystore({?MOD_WELFARE, BagLv}, 1, ChatLimit, {{?MOD_WELFARE, BagLv}, CountAdd}),
                    NewRoleChatLimit = RoleChatLimit#role_chat_limit{chat_limit = NewChatLimit},
                    update(NewRoleChatLimit),
                    Player#player_status{chat_limit_new = NewRoleChatLimit}
            end;
        true ->
            Player
    end;
incre_chat_count({liveness_lv, NewLv}, Player) ->
    #player_status{chat_limit_new = RoleChatLimit} = Player,
    #role_chat_limit{chat_limit = ChatLimit} = RoleChatLimit,
    if NewLv =:= 1 orelse NewLv =:= 2 orelse NewLv =:= 3 ->
            case lists:keyfind({?MOD_ACTIVITY, NewLv}, 1, ChatLimit) of
                {_, _ChatCount} ->
                    Player;
                _ ->
                    CountAdd = case NewLv of
                        1 -> 3;
                        2 -> 8;
                        3 -> 15
                    end,
                    NewChatLimit = lists:keystore({?MOD_ACTIVITY, NewLv}, 1, ChatLimit, {{?MOD_ACTIVITY, NewLv}, CountAdd}),
                    NewRoleChatLimit = RoleChatLimit#role_chat_limit{chat_limit = NewChatLimit},
                    update(NewRoleChatLimit),
                    Player#player_status{chat_limit_new = NewRoleChatLimit}
            end;
        true ->
            Player
    end.

calc_chat_count(ChatLimit) ->
    lists:sum([CountAdd || {_, CountAdd} <- ChatLimit]).


%% 聊天屏蔽
%% 服务端只记录并提供玩家屏蔽的角色id列表
%% 真正屏蔽由前端实现
get_role_shield(Player) ->
    #player_status{id = MasterId, sid = Sid, chat_limit_new = #role_chat_limit{role_shield = RoleShield} = RoleChatLimit} = Player,
    case RoleShield of
        #role_shield{shield_roles = SheildRoles = [_|_], role_figure = RoleFigures} ->
            case filter_clusters_role_figure(MasterId, SheildRoles) of
                ClustersRoles = [_|_] ->
                    %% 更新本地的
                    {UpdateSign, NewFigures} = get_shield_figure(SheildRoles -- ClustersRoles, RoleFigures),
                    NewPlayer = case UpdateSign of
                        true ->
                            NewRoleShield = RoleShield#role_shield{role_figure = NewFigures},
                            NewRoleChatLimit = RoleChatLimit#role_chat_limit{role_shield = NewRoleShield},
                            Player#player_status{chat_limit_new = NewRoleChatLimit};
                        _ ->
                            Player
                    end,
                    %% 更新其他服的
                    MasterServId = config:get_server_id(),
                    [clusters_node:apply_cast(?MODULE, get_figure_in_center, [MasterId, MasterServId, RoleId, ?MODULE, update_sheild_figure]) || RoleId <- ClustersRoles],
                    {ok, NewPlayer};
                _ ->
                    %% 先查看需不需要更新figure数据
                    {UpdateSign, NewFigures} = get_shield_figure(SheildRoles, RoleFigures),
                    FigureData = [{FigureX, ServNum} || {_, FigureX, _, ServNum} <- NewFigures],
                    lib_server_send:send_to_sid(Sid, pt_110, 11065, [FigureData]),
                    case UpdateSign of
                        true ->
                            NewRoleShield = RoleShield#role_shield{role_figure = NewFigures},
                            NewRoleChatLimit = RoleChatLimit#role_chat_limit{role_shield = NewRoleShield},
                            {ok, Player#player_status{chat_limit_new = NewRoleChatLimit}};
                        _ ->
                            ok
                    end
            end;
        _ ->
            lib_server_send:send_to_sid(Sid, pt_110, 11065, [[]])
    end.

filter_clusters_role_figure(MasterId, RoleIds) ->
    lists:foldl(fun(RoleId, Acc) ->
        RoleServId = mod_player_create:get_serid_by_id(RoleId),
        MasterServId = mod_player_create:get_serid_by_id(MasterId),
        if RoleServId =/= MasterServId -> [RoleId|Acc];
            true -> Acc
        end
     end, [], RoleIds).

get_shield_figure(SheildRoles, Figures) ->
    Len1 = length(SheildRoles),
    Len2 = length(Figures),
    if Len1 =/= Len2 ->
            NewFigures = lists:foldl(fun(RoleId, TmpFigures) ->
                RoleFigure = lib_role:get_role_figure(RoleId),
                ServId = config:get_server_id(),
                ServNum = config:get_server_num(),
                lists:keystore(RoleFigure#figure.id, 1, TmpFigures, {RoleFigure#figure.id, RoleFigure, ServId, ServNum})
             end, Figures, SheildRoles),
            {true, NewFigures};
        true ->
            {false, Figures}
    end.

%% 跨服中心
get_figure_in_center(MasterId, MasterServId, RoleId, Mod, Fun) ->
    RoleServerId = mod_player_create:get_serid_by_id(RoleId),
    ServerId = clusters_center:find_now_server_id(RoleServerId),
    clusters_center:apply_cast(ServerId, ?MODULE, get_figure_in_des_server, [MasterId, MasterServId, RoleId, Mod, Fun]).

%% 目标服
get_figure_in_des_server(MasterId, MasterServId, RoleId, Mod, Fun) ->
    Figure = lib_role:get_role_figure(RoleId),
    ServNum = config:get_server_num(),
    ServerId = config:get_server_id(),
    if MasterServId == ServerId -> %% 同一服(之前合过服所以id判断时不一样)
            update_sheild_figure(MasterId, Figure, ServerId, ServNum);
        true ->
            clusters_node:apply_cast(?MODULE, get_figure_to_source_server, [MasterId, ServerId, ServNum, Figure, Mod, Fun])
    end.

%% 跨服中心
get_figure_to_source_server(MasterId, ServerId, ServNum, Figure, Mod, Fun) ->
    MasterServId = mod_player_create:get_serid_by_id(MasterId),
    MasterServId1 = clusters_center:find_now_server_id(MasterServId),
    clusters_center:apply_cast(MasterServId1, Mod, Fun, [MasterId, Figure, ServerId, ServNum]).

%% 源服
update_sheild_figure(MasterId, Figure, ServerId, ServNum) ->
    lib_player:apply_cast(MasterId, ?APPLY_CAST_SAVE, ?MODULE, role_update_sheild_figure, [Figure, ServerId, ServNum]).

role_update_sheild_figure(Player, Figure, ServerId, ServNum) ->
    #player_status{sid = Sid, chat_limit_new = #role_chat_limit{role_shield = RoleShield} = RoleChatLimit} = Player,
    #role_shield{shield_roles = SheildRoles, role_figure = RoleFigures} = RoleShield,
    NewRoleFigures = lists:keystore(Figure#figure.id, 1, RoleFigures, {Figure#figure.id, Figure, ServerId, ServNum}),
    NewRoleShield = RoleShield#role_shield{role_figure = NewRoleFigures},
    Len1 = length(SheildRoles), Len2 = length(NewRoleFigures),
    if Len1 =/= Len2 ->
            NewFigures = [{FigureX, ServNumX} || {_, FigureX, _ServerIdX, ServNumX} <- NewRoleFigures],
            lib_server_send:send_to_sid(Sid, pt_110, 11065, [NewFigures]),
            {ok, Player#player_status{chat_limit_new = RoleChatLimit#role_chat_limit{role_shield = NewRoleShield}}};
        true ->
            NewFigures = [{FigureX, ServNumX} || {_, FigureX, _ServerIdX, ServNumX} <- NewRoleFigures],
            lib_server_send:send_to_sid(Sid, pt_110, 11065, [NewFigures]),
            {ok, Player}
    end.


shield_role(Type, RoleId, #player_status{sid = Sid, id = RoleId}) ->
    lib_server_send:send_to_sid(Sid, pt_110, 11066, [?ERRCODE(err110_shield_self), Type, #figure{}, 0]);
shield_role(Type = ?CHAT_SHEILD, RoleId, Player) ->
    #player_status{id = MasterId, sid = Sid, chat_limit_new = RoleChatLimit} = Player,
    #role_chat_limit{role_shield = RoleShield0} = RoleChatLimit,
    RoleShield = case RoleShield0 of
        #role_shield{} ->
            RoleShield0;
        _ ->
            #role_shield{}
    end,
    case lists:member(RoleId, RoleShield#role_shield.shield_roles) of
        true ->
            lib_server_send:send_to_sid(Sid, pt_110, 11066, [?ERRCODE(err110_have_shield), Type, #figure{}, 0]);
        _ ->
            Len = length(RoleShield#role_shield.shield_roles),
            if Len >= ?SHEILD_NUM ->
                    lib_server_send:send_to_sid(Sid, pt_110, 11066, [?ERRCODE(err110_shield_num), Type, #figure{}, 0]);
                true ->
                    MasterServId = config:get_server_id(),
                    RoleServerId = mod_player_create:get_serid_by_id(RoleId),
                    if RoleServerId == MasterServId ->
                            role_update_sheild_figure_in_source(Player, RoleId, Type);
                        true ->
                            clusters_node:apply_cast(?MODULE, cluster_update_shield_role, [MasterId, MasterServId, RoleId, Type])
                    end
            end
    end;
shield_role(Type = ?CHAT_UNSHEILD, RoleId, Player) ->
    #player_status{id = MasterId, sid = Sid, chat_limit_new = RoleChatLimit} = Player,
    ServId = 0, ServNum = 0, Figure = #figure{id = RoleId}, %% 取消时缺省
    NewRoleChatLimit = update_sheild_figure_by_type(Type, MasterId, Figure, ServId, ServNum, RoleChatLimit),
    lib_relationship:del_from_block_list(MasterId, RoleId),
    NewPlayer = Player#player_status{chat_limit_new = NewRoleChatLimit},
    lib_server_send:send_to_sid(Sid, pt_110, 11066, [?SUCCESS, Type, #figure{id = RoleId}, 0]),
    {ok, NewPlayer};
shield_role(_, _, _) -> ok.


cluster_update_shield_role(MasterId, MasterServId, RoleId, Type) ->
    RoleServerId = mod_player_create:get_serid_by_id(RoleId),
    RoleServerId1 = clusters_center:find_now_server_id(RoleServerId),
    if RoleServerId1 == MasterServId -> %% 回原来服找即可
            clusters_center:apply_cast(RoleServerId1, ?MODULE, update_sheild_figure_in_source, [MasterId, RoleId, Type]);
        true -> %% 要去第三服找
            clusters_center:apply_cast(RoleServerId1, ?MODULE, get_shield_figure_in_des, [MasterServId, MasterId, RoleId, Type])
    end.

get_shield_figure_in_des(MasterServId, MasterId, RoleId, Type) ->
    Figure = lib_role:get_role_figure(RoleId),
    RoleServerId = config:get_server_id(),
    RoleServerNum = config:get_server_num(), %?ERR("~p ~p ~p ~p", [Figure, MasterServId, RoleServerId, RoleServerNum]),
    clusters_node:apply_cast(?MODULE, cluster_get_shield_figure_in_des, [MasterServId, MasterId, RoleId, Figure, RoleServerId, RoleServerNum, Type]).

cluster_get_shield_figure_in_des(MasterServId, MasterId, RoleId, Figure, ServId, ServNum, Type) ->
    clusters_center:apply_cast(MasterServId, ?MODULE, get_shield_figure_in_des1, [MasterId, RoleId, Figure, ServId, ServNum, Type]).

get_shield_figure_in_des1(MasterId, RoleId, Figure, ServId, ServNum, Type) ->
    lib_player:apply_cast(MasterId, ?APPLY_CAST_SAVE, ?MODULE, role_get_shield_figure_in_des, [RoleId, Figure, ServId, ServNum, Type]).

update_sheild_figure_in_source(MasterId, RoleId, Type) ->
    lib_player:apply_cast(MasterId, ?APPLY_CAST_SAVE, ?MODULE, role_update_sheild_figure_in_source, [RoleId, Type]).


role_get_shield_figure_in_des(Player, _RoleId, Figure, ServId, ServNum, Type) ->
    #player_status{id = MasterId, sid = Sid, chat_limit_new = RoleChatLimit} = Player,
    NewRoleChatLimit = update_sheild_figure_by_type(Type, MasterId, Figure, ServId, ServNum, RoleChatLimit),
    NewPlayer = Player#player_status{chat_limit_new = NewRoleChatLimit},
    {ok, Bin} = pt_110:write(11066, [?SUCCESS, Type, Figure, ServNum]),
    lib_server_send:send_to_sid(Sid, Bin),
    {ok, NewPlayer}.

role_update_sheild_figure_in_source(Player, RoleId, Type) ->
    #player_status{id = MasterId, sid = Sid, chat_limit_new = RoleChatLimit} = Player,
    Figure = lib_role:get_role_figure(RoleId),
    ServId = config:get_server_id(),
    ServNum = config:get_server_num(),
    BlockedServId = mod_player_create:get_real_serid_by_id(RoleId),
    NewRoleChatLimit = update_sheild_figure_by_type(Type, MasterId, Figure, ServId, ServNum, RoleChatLimit),
    %% 同服的才需要更新好友请求记录
    ServId == BlockedServId andalso lib_relationship:del_friend_ask_after_block(MasterId, RoleId),
    NewPlayer = Player#player_status{chat_limit_new = NewRoleChatLimit},
    {ok, Bin} = pt_110:write(11066, [?SUCCESS, Type, Figure, ServNum]),
    lib_server_send:send_to_sid(Sid, Bin),
    {ok, NewPlayer}.

update_sheild_figure_by_type(Type, MasterId, Figure, ServId, ServNum, RoleChatLimit) ->
    #role_chat_limit{role_shield = RoleShield0, chat_count = ChatCount, chat_limit = ChatLimit} = RoleChatLimit,
    RoleShield = case RoleShield0 of
        #role_shield{} -> RoleShield0;
        _ -> #role_shield{}
    end,
    if Type == ?CHAT_SHEILD ->
            NewRoleFigures = lists:keystore(Figure#figure.id, 1, RoleShield#role_shield.role_figure, {Figure#figure.id, Figure, ServId, ServNum}),
            NewShieldRoleIds = [Figure#figure.id|RoleShield#role_shield.shield_roles],
            db_update_role_shield(NewShieldRoleIds, ChatLimit, ChatCount, MasterId),
            NewRoleShield = RoleShield#role_shield{shield_roles = NewShieldRoleIds, role_figure = NewRoleFigures},
            RoleChatLimit#role_chat_limit{role_shield = NewRoleShield};
        Type == ?CHAT_UNSHEILD ->
            NewRoleFigures = lists:keydelete(Figure#figure.id, 1, RoleShield#role_shield.role_figure),
            NewShieldRoleIds = lists:delete(Figure#figure.id, RoleShield#role_shield.shield_roles),
            db_update_role_shield(NewShieldRoleIds, ChatLimit, ChatCount, MasterId),
            NewRoleShield = RoleShield#role_shield{shield_roles = NewShieldRoleIds, role_figure = NewRoleFigures},
            RoleChatLimit#role_chat_limit{role_shield = NewRoleShield};
        true ->
            RoleChatLimit
    end.

db_update_role_shield(SheildRoles, ChatLimit, ChatCount, MasterId) ->
    Sql = io_lib:format(?SQL_CHAT_LIMIT_UPDATE, [MasterId, ChatCount, util:term_to_bitstring(ChatLimit), util:term_to_bitstring(SheildRoles)]),
    db:execute(Sql),
    ok.

get_role_block(Player) ->
    #player_status{chat_limit_new = #role_chat_limit{role_shield = RoleShield}} = Player,
    case RoleShield of
        #role_shield{shield_roles = BlockList} -> BlockList;
        _     -> []
    end.

%% true 黑名单
%% false 不在黑名单
is_blocked(Player, ReceiveId) ->
    BlockList = get_role_block(Player),
    case lists:member(ReceiveId, BlockList) of
        true ->
            true;
        _ ->
            false
    end.


get_relalist_without_chatlimit(#role_chat_limit{
    role_shield = #role_shield{shield_roles = ShieldRoles = [_|_]}},
    RelaList = [_|_]) ->
        filter_chatlimit_do(RelaList, ShieldRoles);
get_relalist_without_chatlimit(_A, RelaList) ->
    RelaList.

filter_chatlimit_do(RelaList, SheildRoles) ->
    lists:foldl(fun(RelaInfo, TmpRelaList) ->
        if RelaInfo == {} -> TmpRelaList;
            true ->
                RoleId = erlang:element(1, RelaInfo),
                case lists:member(RoleId, SheildRoles) of
                    true ->
                        TmpRelaList;
                    _ ->
                        [RelaInfo|TmpRelaList]
                end
        end
    end, [], RelaList).
