@ -0,0 +1,484 @@ | |||||
%%%------------------------------------------------ | |||||
%%% File : common.hrl | |||||
%%% Author : csj | |||||
%%% Created : 2010-09-15 | |||||
%%% Description: 公共定义 | |||||
%%%------------------------------------------------ | |||||
-define(ALL_SERVER_PLAYERS, 100000). | |||||
%%-define(SLICEWIDTH, 25). | |||||
%%-define(SLICEHEIGHT, 15). | |||||
-define(SLICEWIDTH, 15). | |||||
-define(SLICEHEIGHT, 9). | |||||
-define(SOLUT_X, 30). %% 默认手机分表率X | |||||
-define(SOLUT_Y, 20). %% 默认手机分表率Y | |||||
%%数据库模块选择 (db_mysql 或 db_mongo) | |||||
-define(DB_MODULE, db_mysql). | |||||
%%数据库模块(日志数据库) | |||||
-define(DB_LOG_MODULE, db_mysql_admin). | |||||
-define(DB_SERVER, mysql_dispatcher). | |||||
%%数据库模块(日志数据库) | |||||
-define(DB_SERVER_ADMIN, mysql_admin_dispatcher). | |||||
-define(DB_LOG_DELAY, 1). %延迟写日志(批量写,已做优化) | |||||
-define(DB_LOG_NORMAL, 0).%普通方式写数据库 (立即写) | |||||
%%mongo主数据库链接池 | |||||
-define(MASTER_POOLID, master_mongo). | |||||
%%mongo从数据库链接池 | |||||
-define(SLAVE_POOLID, slave_mongo). | |||||
%%Mysql数据库连接 | |||||
-define(DB_POOL, mysql_conn). | |||||
%%消息头长度 | |||||
-define(HEADER_LENGTH, 4). %%消息头长度 2Byte 长度 + 2Byte 消息编号 | |||||
%% 心跳包时间间隔 | |||||
-define(HEART_TIMEOUT, 5 * 60 * 1000). %%心跳包超时时间 | |||||
%% 最大心跳包检测失败次数 | |||||
-define(HEART_TIMEOUT_TIME, 2). %%心跳包超时次数 | |||||
-define(TCP_TIMEOUT, 1000). % 解析协议超时时间 | |||||
%% 每个场景的工作进程数 | |||||
-define(SCENE_WORKER_NUMBER, 5). | |||||
%% 代理进程数 | |||||
-define(SCENE_AGENT_NUMBER, 30). | |||||
%% 每个场景的最多容纳人数 | |||||
-define(SCENE_PLAYER_MAX_NUMBER, 50). | |||||
%% 最大分场景数 | |||||
-define(SCENE_MAX_NUMBER, 70). | |||||
-define(GRID_CANGO, 1). % 可走格子 | |||||
-define(GRID_SHADE, 2). % 阴影格子 | |||||
-define(GRID_BLOCK, 3). % 障碍格子 | |||||
-define(ETS_SCENE_MAP_INFO, ets_map_info). %地图信息表 | |||||
%%安全校验 | |||||
-define(TICKET, "SDFSDESF123DFSDF"). | |||||
%%tcp_server监听参数 | |||||
-define(TCP_OPTIONS, [binary, {packet, 0}, {active, false}, {reuseaddr, true}, {nodelay, false}, {delay_send, true}, {send_timeout, 5000}, {keepalive, true}, {exit_on_close, true}]). | |||||
-define(RECV_TIMEOUT, 5000). | |||||
%%出师等级限制 | |||||
-define(FINISHED_MASTER_LV, 35). | |||||
%%徒弟未汇报时间 | |||||
-define(UNREPORT_DAYS, 3). | |||||
%%师傅未登陆时间 | |||||
-define(UNLOGIN_DAYS, 3). | |||||
%%人物和宠物死亡后的最低血量 | |||||
-define(LIMIT_HP, 10). | |||||
%%自然对数的底 | |||||
-define(E, 2.718281828459). | |||||
%% --------------------------------- | |||||
%% Logging mechanism | |||||
%% Print in standard output | |||||
-define(PRINT(Format, Args), | |||||
io:format(Format, Args)). | |||||
-define(TEST_MSG(Format, Args), | |||||
logger:test_msg(?MODULE, ?LINE, Format, Args)). | |||||
-define(DEBUG(Format, Args), | |||||
logger:debug_msg(?MODULE, ?LINE, Format, Args)). | |||||
-define(INFO_MSG(Format, Args), | |||||
logger:info_msg(?MODULE, ?LINE, Format, Args)). | |||||
-define(WARNING_MSG(Format, Args), | |||||
logger:warning_msg(?MODULE, ?LINE, Format, Args)). | |||||
-define(ERROR_MSG(Format, Args), | |||||
logger:error_msg(?MODULE, ?LINE, Format, Args)). | |||||
-define(CRITICAL_MSG(Format, Args), | |||||
logger:critical_msg(?MODULE, ?LINE, Format, Args)). | |||||
%% log event manager name | |||||
-define(LOGMODULE, logger_mgr). | |||||
-define(INIT_SCENE_ID, 101). %%新手村 | |||||
-define(INIT_SCENE_XY, {10, 10}). %%新建帐号位置 | |||||
%性别 | |||||
-define(GENDER_ANY, 0). | |||||
-define(GENDER_MALE, 1). | |||||
-define(GENDER_FEMALE, 2). | |||||
%%玩家状态 | |||||
-define(PLAYER_NORMAL_STATE, 0). %%正常 | |||||
-define(PLAYER_BATTLE_STATE, 1). %%战斗 | |||||
%职业 | |||||
-define(CAREER_F, 1). %战士 | |||||
-define(CAREER_M, 2). %法师 | |||||
-define(CAREER_D, 3). %射手 | |||||
-define(CAREER_ANY, 4). %各职业通用 | |||||
-define(CAREER_PET, 5). %宠物 | |||||
-define(CAREER_MOUNT, 6). %战骑 | |||||
%% 性别 | |||||
-define(SEX_ANY, 0). % 男女通用 | |||||
-define(SEX_MALE, 1). % 男 | |||||
-define(SEX_FEMALE, 2). % 女 | |||||
%VIP类型定义 | |||||
-define(VIP_NOT, 0). %不是VIP | |||||
-define(VIP_EXPERIENCE, 1). %VIP钟点卡(试用装) | |||||
-define(VIP_DAY, 11). %VIP日卡 | |||||
-define(VIP_WEEK, 12). %VIP周卡 | |||||
-define(VIP_MONTH, 13). %VIP月卡 | |||||
-define(VIP_HALF_YEAR, 21). %VIP半年卡 | |||||
-define(VIP_YEAR, 22). %VIP年卡 | |||||
-define(VIP_FOREVER, 99). %VIP终身卡 | |||||
-define(ELEMENT_PLAYER, 1). %% 玩家 | |||||
-define(ELEMENT_MONSTER, 2). %% 怪物 | |||||
-define(ELEMENT_ALL, 3). %% 玩家,怪物 | |||||
-define(ELEMENT_PET, 4). %% 宠物 | |||||
-define(EXP_DUNGEON, 399). | |||||
%% 攻击目标类型 | |||||
-define(DEST_SINGLE, 0). % 单体攻击 | |||||
-define(DEST_ATTACK, 1). % 自身为中心 | |||||
-define(DEST_DEFEND, 2). % 目标为中心 | |||||
-define(DEST_GROUND, 3). % 地面为中心 | |||||
%%打开发送消息客户端进程数量 | |||||
-define(SEND_MSG, 1). | |||||
%%player.switch开关位定义(32位) | |||||
-define(SW_PET_BIT, 16#00000001). %宠物 | |||||
-define(SW_MOUNT_BIT, 16#00000002). %座骑 | |||||
-define(SW_GUILD_BIT, 16#00000004). %帮派 | |||||
-define(SW_RELATION_BIT, 16#00000000). %关系 16#00000008 | |||||
-define(SW_SKILL_BIT, 16#00000010). %技能 | |||||
-define(SW_CAMP_BIT, 16#00000020). %阵营 | |||||
-define(SW_MER_BIT, 16#00000040). %经脉 | |||||
-define(SW_BIT7, 16#00000080). | |||||
-define(SW_BIT8, 16#00000100). | |||||
-define(SW_BIT9, 16#00000200). | |||||
-define(SW_BIT10, 16#00000400). | |||||
-define(SW_BIT11, 16#00000800). | |||||
-define(SW_BIT12, 16#00001000). | |||||
-define(SW_BIT13, 16#00002000). | |||||
-define(SW_BIT14, 16#00004000). | |||||
-define(SW_BIT15, 16#00008000). | |||||
-define(SW_BIT16, 16#00010000). | |||||
-define(SW_BIT17, 16#00020000). | |||||
-define(SW_BIT18, 16#00040000). | |||||
-define(SW_BIT19, 16#00080000). | |||||
-define(SW_BIT20, 16#00100000). | |||||
-define(SW_BIT21, 16#00200000). | |||||
-define(SW_BIT22, 16#00400000). | |||||
-define(SW_BIT23, 16#00800000). | |||||
-define(SW_BIT24, 16#01000000). | |||||
-define(SW_BIT25, 16#02000000). | |||||
-define(SW_BIT26, 16#04000000). | |||||
-define(SW_BIT27, 16#08000000). | |||||
-define(SW_BIT28, 16#10000000). | |||||
-define(SW_BIT29, 16#20000000). | |||||
-define(SW_BIT30, 16#40000000). | |||||
-define(SW_BIT31, 16#80000000). | |||||
%% 联盟进程的工作进程数 | |||||
-define(MON_LIMIT_NUM, 100000000). %% 怪物数量限制数 | |||||
-define(DIFF_SECONDS_1970_1900, 2208988800). | |||||
-define(DIFF_SECONDS_0000_1900, 62167219200). | |||||
-define(ONE_DAY_SECONDS, 86400). %%一天的时间(秒) | |||||
-define(ONE_DAY_MILLISECONDS, 86400000). %%一天时间(毫秒) | |||||
-define(COMMON_ATTR_SPEED, 1200). %默认攻速 | |||||
-define(COMMON_MOVE_SPEED, 7). %默认移动速度 | |||||
-define(COMMON_MOVE_PATROL, 3). %默认巡逻速度 | |||||
-define(COMMON_MOVE_SURROUND, 3). %默认漫游速度 | |||||
-define(DEFAULT_NAME, "匿名"). | |||||
%%ETS | |||||
-define(ETS_SERVER, ets_server). | |||||
-define(ETS_GET_SERVER, ets_get_server). | |||||
-define(ETS_GET_SCENE, ets_get_scene). | |||||
-define(ETS_SYSTEM_INFO, ets_system_info). %% 系统配置信息 | |||||
-define(ETS_MONITOR_PID, ets_monitor_pid). %% 记录监控的PID | |||||
-define(ETS_STAT_SOCKET, ets_stat_socket). %% Socket送出数据统计(协议号,次数) | |||||
-define(ETS_STAT_DB, ets_stat_db). %% 数据库访问统计(表名,操作,次数) | |||||
-define(ETS_SYS_ANNONUCE, sys_announce). | |||||
%% -define(ETS_BASE_MON, ets_base_mon). %% 基础_怪物信息 | |||||
%% -define(ETS_MONGROUP, ets_mongroup). %% 基础_怪物信息 | |||||
-define(ETS_NPC, temp_npc). %% 基础_NPC/怪物信息 | |||||
-define(ETS_TEMP_SCENE, temp_scene). %% 基础_场景信息 | |||||
-define(ETS_SCENE, ets_scene). %% 本节点场景实例 | |||||
-define(ETS_NPC_LAYOUT, npc_layout). %% 实例-场景NPC布局 | |||||
-define(ETS_TEMP_MON_LAYOUT, temp_mon_layout). %% 基础_场景怪物布局 | |||||
-define(SECNE_MON, scene_mon). %% 场景中怪物保存,可以用作ETS,可以用这dict key | |||||
-define(SECNE_DROP, scene_drop). %% 场景中怪物怪物掉落 | |||||
-define(MON_STATE_TIMER_KEY, mon_state_timer_key). %% 怪物状态的TimerKey | |||||
-define(DUNGEON_MON_STATE_TIMER_KEY, dungeon_mon_state_timer_key). %% 怪物状态的TimerKey | |||||
-define(ETS_TEMP_GUILD_LEVEL, temp_guild_level). %%帮派等级配置 | |||||
-define(MON_STATE_SPEED_7, 143). %% 怪物状态管理 143 毫秒一轮询,每一秒7步 | |||||
-define(MON_STATE_SPEED_BIAS_7, 202). %% 怪物状态管理 202 毫秒一轮询,每一秒7步(斜线) | |||||
-define(MON_STATE_SPEED_3, 333). %% 怪物状态管理 333 毫秒一轮询,每一秒3步 | |||||
-define(MON_STATE_SPEED_BIAS_3, 470). %% 怪物状态管理 470 毫秒一轮询,每一秒3步(斜线) | |||||
-define(BUFF_TIMER_TIME, 200). %buff技能计时器刷新时间 | |||||
-define(SKILL_TIMER_KEY, skill_timer_key). %% 技能状态的TimerKey | |||||
-define(MON_STATE_1_GUARD, 1). | |||||
-define(MON_STATE_2_TRYATT, 2). | |||||
-define(MON_STATE_3_MOVE, 3). | |||||
-define(MON_STATE_4_FIGHT, 4). | |||||
-define(MON_STATE_5_RETURN, 5). | |||||
-define(MON_STATE_6_DEAD, 6). | |||||
-define(MON_STATE_7_CHANT, 7). | |||||
-define(PLAYER_STATE_TIMER_KEY, player_state_timer_key). %% 玩家状态的TimerKey | |||||
-define(PLAYER_STATE_LOOP_TIME, 500). %% 玩家状态管理 500 毫秒先 | |||||
-define(MON_SKILL_TIMER_LIST, mon_skill_timer_list). %% 怪物技能状态的列表 | |||||
-define(MON_SKILL_TIMER_LOOP_TIME, 250). %% 怪物技能管理 250 毫秒先 | |||||
-define(ETS_ONLINE, ets_online). %% 本节点在线玩家 | |||||
-define(ETS_ONLINE_SCENE, ets_online_scene). %% 本节点场景中玩家 | |||||
%% -define(ETS_BASE_SCENE_POSES, ets_base_scene_poses). %% 基本_场景坐标表 | |||||
-define(ETS_BASE_SCENE_MON, ets_base_scene_mon). %% 基础_场景怪物信息 | |||||
-define(ETS_BASE_SCENE_NPC, ets_base_scene_npc). %% 基础_场景NPC信息 | |||||
-define(ETS_SCENE_MON, ets_mon). %% 本节点场景中怪物 | |||||
-define(ETS_SCENE_NPC, ets_npc). %% 本节点场景中NPC | |||||
-define(ETS_DUNGEON_DAILY, dungeon_daily). %% 玩家每日副本记录 | |||||
-define(ETS_DUNGEON_FINISH, dungeon_finish). %% 玩家已经完成的副本记录 | |||||
-define(ETS_DUNGEON_MASTER, dungeon_master). %% 玩家已经完成的副本记录 | |||||
-define(ETS_OPERA, opera). %% 玩家已经完成的副本记录 | |||||
-define(ETS_SCENE_GIFT, scene_gift). %% 玩家已经领取过的场景礼包 | |||||
-define(ETS_BLACKLIST, ets_blacklist). %% 黑名单记录表 | |||||
-define(ETS_GOODS_ONLINE, ets_goods_online). %% 在线物品表 | |||||
-define(ETS_GOODS_EQUIP, ets_goods_equip). %% 装备物品类型表 | |||||
-define(ETS_GUILD, ets_guild). %% 联盟 | |||||
-define(ETS_GUILD_MEMBER, ets_guild_member). %% 联盟成员 | |||||
-define(ETS_GUILD_APPLY, ets_guild_apply). %% 联盟申请 | |||||
-define(ETS_GUILD_INVITE, ets_guild_invite). %% 联盟邀请 | |||||
-define(ETS_MOUNT, ets_mount). %%座骑ETS表名 | |||||
-define(ETS_ACTIVITY, ets_activity). %%活跃度 | |||||
-define(ETS_CONTACT, ets_contact). | |||||
-define(ETS_RELATION, ets_relation). %%关系ETS表名 | |||||
-define(ETS_RELATION_AGENT, ets_relation_agent). %%玩家关系代理进程ets | |||||
-define(ETS_TEAM, ets_team). %%队伍表ETS | |||||
-define(ETS_TEAM_MEMBER, ets_team_member). %%队伍成员表ETS | |||||
-define(ETS_TEMP_SHOP, ets_temp_shop). %% 商城模版表 | |||||
-define(ETS_SHOP_LOG, ets_shop_log). %% 商城购买物品记录 | |||||
-define(ETS_NPC_SHOP_LOG, ets_npc_shop_log). %% npc商店购买物品记录 | |||||
-define(ETS_RAND_SHOP, rand_shop). %% 随机商城记录 | |||||
-define(ETS_TPL_TASK, tpl_task). %%角色任务模板 | |||||
%-define(ETS_TASK_DAILY_FINISH, ets_task_daily_finish). %%日常任务完成进度 | |||||
-define(ETS_TASK_PROCESS, task_process). %% 角色任务记录 | |||||
-define(ETS_TASK_FINISH, task_finish). %% 角色任务历史记录 | |||||
-define(ETS_TASK_QUERY_CACHE, ets_task_query_cache). %% 当前所有可接任务 | |||||
-define(ETS_TASK_DETAIL, ets_task_datil). %%任务模板子表 | |||||
-define(ETS_TASK_MASTER, task_master).%玩家师门令,刷新列表 | |||||
-define(ETS_HEAVEN, heaven).%天道令数据 | |||||
-define(ETS_TASK_HEAVEN, task_heaven).%玩家天道数据记录表 | |||||
-define(ETS_TASK_DAILY, task_daily).%日常任务统计表 | |||||
-define(ETS_MOUNT_LEVEL_STAR, ets_mount_lv_star).%%坐骑星阶外观绑定表 | |||||
%新手引导 | |||||
-define(ETS_LEADER, ets_newbie_leader).%玩家新手引导记录表 | |||||
-define(ONE_DAY_MSECONDS, (24 * 60 * 60 * 1000)). % 一天的毫秒数 | |||||
-define(ONE_HOUR_SECONDS, (60 * 60)). % 一小时的秒数 | |||||
-define(ONE_HOUR_MSECONDS, (60 * 60 * 1000)). % 一小时的毫秒数 | |||||
-define(ONE_MINUTE_SECONDS, 60). % 一分钟的秒数 | |||||
-define(ONE_MINUTE_MSECONDS, (60 * 1000)). % 一分钟的毫秒数 | |||||
-define(START_NOW, {-1, 0, 0}). %% {-1, 0, 0}:表示从当前时间开始 | |||||
-define(START_TOMORROW, {-2, 0, 0}). %% {-2, 0, 0}:表示从每日零点开始 | |||||
%% 通知客户端刷新 | |||||
-define(REFRESH_ROLE_ATTRI, 1). %刷新人物属性 | |||||
-define(REFRESH_BAG, 2). %刷新背包 | |||||
-define(REFRESH_P_EQUIP, 3). %武将装备 | |||||
-define(REFRESH_MONEY, 4). %刷新三种货币 | |||||
-define(REFRESH_GOODS_INFO, 5). %刷新物品信息 | |||||
-define(REFRESH_R_EQUIP, 6). %玩家装备 | |||||
-define(REFRESH_ROLE_POWER, 7). %刷新人物体力条 | |||||
-define(REFRESH_ROLE_HP, 8). %刷新人物血条 | |||||
-define(REFRESH_PAR_ATTRI, 9). %刷新武将属性 | |||||
-define(REFRESH_PAR_HP, 10). %刷新武将血条 | |||||
-define(REFRESH_STORE, 11). %刷新仓库 | |||||
-define(REFRESH_TREA, 12). %刷新淘宝仓库 | |||||
-define(REFRESH_DAN, 13). % 刷新丹药仓库 | |||||
%% 角色战斗力的调节参数 | |||||
%-define(ROLE_BATTLE_CAPACITY_CONTROLLED_PARA, -242). | |||||
-define(HURT_CALL_BACK, 0). %玩家受到伤害后 触发反伤技能 | |||||
-define(HURT_NOT_CALL_BACK, 1). %玩家受到伤害后不触发反伤技能 | |||||
%% 体力的增减 | |||||
-define(PLAYER_POWER_LIMIT, 200). % 玩家体力值上限(固定值) | |||||
-define(ADD_POWER_PER_30_MIN, 5). % (自动回复)体力增加 | |||||
-define(POWER_INCREASE, 40). % (购买)体力增加 | |||||
-define(POWER_DECREASE, 20). % (关卡)体力消耗 | |||||
-define(POWER_BUFF, 50). % (体力buff)12、18点系统赠予50点体力buff | |||||
-define(COST_BUY_POWER, 20). % 购买体力固定花费的元宝 | |||||
%% 背包、仓库默认格子数 | |||||
-define(DEFAUL_BAG_CELL, 36 * 2). | |||||
-define(DEFAULT_STORE_CELL, 24). | |||||
%% VIP等级 | |||||
-define(VIP_LV_0, 0). % 0级,表示不是vip | |||||
-define(VIP_LV_1, 1). % 体验vip | |||||
-define(VIP_LV_2, 2). % 日vip | |||||
-define(VIP_LV_3, 3). % 周vip | |||||
-define(VIP_LV_4, 4). % 月vip | |||||
-define(VIP_LV_5, 5). % 半年vip | |||||
-define(VIP_LV_6, 6). % 至尊vip | |||||
-define(VIP_TITLE_CHG_MAX_TIMES, 3). % vip称号最多只能修改3次 | |||||
-define(VIP_TITLE_MAX_LENGTH, 18). % vip称号上限6个汉字 | |||||
-define(VIP_INFINATE_TIME, 2000000000). % 至尊VIP有效时间(无限) | |||||
-define(BOOKING_GIFT, 181000005). %预定礼包 | |||||
% 定时更新称号(单位:秒)为18分钟 | |||||
-define(UPDATE_TITLE_TIMER, 18 * 60 * 1000). | |||||
%% 游戏中流通的货币 | |||||
-define(MONEY_T_GOLD, 1). %% 元宝 | |||||
-define(MONEY_T_BGOLD, 2). %% 绑定元宝 | |||||
-define(MONEY_T_COIN, 3). %% 铜钱 | |||||
-define(MONEY_T_BCOIN, 4). %% 绑定铜钱 | |||||
-define(MONEY_T_COUPON, 5). %% 礼券 | |||||
-define(MONEY_T_HONOR, 6). %% 积分/礼券 | |||||
-define(MONEY_T_EXCHANGE, 7). %% 兑换 | |||||
%% 物品、装备相关宏 | |||||
-define(LOCATION_BAG, 0). % 背包位置 | |||||
-define(LOCATION_PLAYER, 1). % 玩家身上 | |||||
-define(LOCATION_PET, 2). % 宠物 | |||||
-define(LOCATION_TREA, 4). % 淘宝仓库 5页300格 | |||||
-define(LOCATION_WINGS, 5). % 衣柜 | |||||
-define(LOCATION_HOLY_PLATFORM, 6). % 圣坛 | |||||
-define(LOCATION_MAIL, 11). % 虚拟位置:邮件(用于标记邮件中的附件) | |||||
-define(LOCATION_MARKET, 12). % 虚拟位置:市场(用于标记市场中挂售的物品) | |||||
-define(LOCATION_PARTNER_TRANSFORM, 20). % 武将装备转档仓库 | |||||
-define(TenMinute, 10 * 60 * 1000). | |||||
%% 返回结果: | |||||
-define(RESULT_OK, 1). %% 成功 | |||||
-define(RESULT_FAIL, 0). %% 失败 | |||||
-define(DELAY_CALL, 5000). | |||||
%% -define(ETS_TEMP_GOODS, temp_goods). %% 物品类型表 | |||||
-define(ETS_COMPOSE_RULE, ets_compose_rule). %% 宝石合成规则表 | |||||
-define(ETS_GOODS_INLAY, ets_goods_inlay). %% 宝石镶嵌规则表 | |||||
-define(ETS_MARKET_GOODS_ONLINE, ets_market_goods_online). %% 市场的上架物品信息表 | |||||
-define(ETS_MARKET_GOODS_ATTR, ets_market_goods_attr). %% 市场的上架物品的附加属性信息表 | |||||
-define(ETS_GOODS_DROP, ets_goods_drop). %% 物品掉落表 | |||||
-define(ETS_DROP_TYPE, ets_drop_type). %% 物品掉落类型 | |||||
-define(ETS_DROP_NUM, ets_drop_num). %% 物品掉落上限值 | |||||
-define(ETS_DROP_CONTENT, ets_drop_content). %% 物品掉落包中物品 | |||||
-define(ETS_MARKET_SELLING, ets_mk_selling). %% 市场上架物品表 | |||||
-define(ETS_MARKET_REQUEST, ets_mk_request). %% 市场求购物品表 | |||||
-define(GLOBAL_MARK_PROCESS, g_market_process). %% 市场/拍卖行 | |||||
-define(ETS_PET_INFO, ets_pet_info). %% 宠物 | |||||
-define(ETS_GOODS_BUFF, ets_goods_buff). | |||||
-define(ETS_ZIP_PROTO, ets_zip_proto). | |||||
% 32位有符号数的最大值 | |||||
-define(MAX_S32, 2147483647). | |||||
% 16位有符号数的最大值 | |||||
-define(MAX_S16, 32767). | |||||
% 8位有符号数的最大值 | |||||
-define(MAX_S8, 127). | |||||
% 8位无符号数的最大值 | |||||
-define(MAX_U8, 255). | |||||
%% 宠物 | |||||
-define(PET_REST, 0). % 宠物休息 | |||||
-define(PET_FIGHTING, 1). % 出战 | |||||
-define(PET_NOT_EXIST, 2). % 不存在 | |||||
%% 换装 | |||||
-define(DEFAULT_T_WEAPON, 0). % 武器 | |||||
-define(DEFAULT_T_ARMOR, 0). % 盔甲 | |||||
-define(DEFAULT_T_FASHION, 0). % 时装 | |||||
-define(DEFAULT_T_WINGS, 0). % 翅膀 | |||||
-define(DEFAULT_T_WEAPONACCESSORIES, 0). % 武饰 | |||||
-define(DEFAULT_T_MOUNT, 0). % 战骑 | |||||
%%经脉 | |||||
-define(ETS_MERIDIAN, player_meridian).%经脉模板表 | |||||
-define(ETS_TPL_BONES, base_bones).%筋骨模板表 | |||||
%%副本物件 | |||||
-define(CONDITION_NULL, 1). | |||||
-define(CONDITION_END, 2). | |||||
-define(CONDITION_MON_DEAD, 3). | |||||
-define(CONDITION_NULLEND, 4). | |||||
%% 互动通知右边圆圈图标类型 | |||||
-define(NOTICE_ICON_TYPE_FRIEND, 1). %% 好友 | |||||
-define(NOTICE_ICON_TYPE_GUILD, 2). %% 帮派 | |||||
-define(NOTICE_ICON_TYPE_MAIL, 3). %% 邮件 | |||||
-define(NOTICE_ICON_TYPE_GIFT, 4). %% 礼物 | |||||
-define(NOTICE_ICON_TYPE_FIGHT, 5). %% 打架 | |||||
-define(NOTICE_ICON_TYPE_FLOWER, 6). %% 送花 | |||||
%%定义需要做协议压缩的协议号 | |||||
-define(ZIP_PROTO, [12002, 12003, 12007, 12010, 12012, 12013, 12015, 13000, 13001, 13002, 13003, 13007, 14001, 14002 | |||||
, 14003, 14005, 15000, 15002, 15004, 15015, 15021, 15026, 19002, 19011, 20001, 21000, 25001, 30006 | |||||
, 30601, 30701, 35002, 40001, 40005, 44000, 45001, 45006, 45008, 50001]). | |||||
-define(ZONE_POS, [{0, 0}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}]). | |||||
-record(scene_map_info, { | |||||
map_id, | |||||
grid_row, | |||||
grid_col, | |||||
grid_type | |||||
}). | |||||
-define(PLAYER_EXIT_UNORMAL, 0). %玩家正常退出标识 | |||||
-define(ALL_CAMP_TYPE, [1, 2, 3]). %所有阵营的类别 | |||||
%%充值处理状态 | |||||
-define(HANDLE_CHARGE_ORDER, 1). % 已处理充值订单 | |||||
-define(UNHANDLE_CHARGE_ORDER, 0). % 未处理充值订单 | |||||
%%充值订单状态 | |||||
-define(CHARGE_ORDER_STATUS_SUCCESSFUL, 1). | |||||
-define(CHARGE_ORDER_STATUS_FAILED, 0). | |||||
%%充值渠道 | |||||
-define(CHARGE_CHANEL_GM, 50). %GM指令渠道 | |||||
-define(CHARGE_CHANEL_4399_SHOU_YOU_BI, 1). %4399手游币 | |||||
-define(CHARGE_CHANEL_SHEN_ZHOU_XING, 2). %移动神州行 | |||||
-define(CHARGE_CHANEL_LIAN_TONG, 3). %联通 | |||||
-define(CHARGE_CHANEL_ALIPAY, 4). %支付宝 |
@ -0,0 +1,232 @@ | |||||
%%%------------------------------------------------ | |||||
%%% File : record.erl | |||||
%%% Author : csj | |||||
%%% Created : 2010-09-15 | |||||
%%% Description: record | |||||
%%%------------------------------------------------ | |||||
-include("table_to_record.hrl"). | |||||
%%战斗属性 战斗相关属性的率一般为 万分比值*10000, | |||||
%% 发给客户端显示使用 万分比值*10000/100,显示为等级 | |||||
-record(battle_attr, { | |||||
x = 0, %% X 坐标 | |||||
y = 0, %% Y 坐标 | |||||
direct_x = 0, %% 朝向x坐标 | |||||
direct_y = 0, %% 朝向y坐标 | |||||
career = 1, %% 职业(参考common.hrl定义) | |||||
skill_cd_all = 0, %% 对所有技能的CD, 冷冻到期时间(毫秒) | |||||
buff_timer_start = false, %% buff计时器是否开启 true.开启 false.关闭 | |||||
skill_cd_list = [], %% 技能使用CD,格式[{SkillId, CdTime},...], CdTime为冷冻到期时间(毫秒) | |||||
link_skill_buff = [], %% 能触发后续技能的buff列表 | |||||
delay_skill_buff = [], %% 延迟触发buff | |||||
timer_buff = [], %% 时间触发类buff | |||||
hurted_buff = [], %% 被击触发类buff | |||||
skill_buff = [], %% 技能特殊状态Buff/单次有效,过期还原/需发到客户端[{BufId, 过期时间},...] 毫秒, | |||||
buff1 = [], %% 技能加战斗属性BUF列表/单次有效,过期还原 [{BufId, 过期时间},...] 毫秒 | |||||
buff2 = [], %% 技能加血力法量BUF列表/周期性, 过期保留 [{BufId, CD到期时间, 剩余次数},...] 毫秒 | |||||
sing_expire = 0, %% 吟唱到期时间(毫秒), 目前只对怪有效, 0为不在吟唱时间内 | |||||
use_combopoint = 0, %% 是否使用了combopoint增加属性攻击值(0未用, 其他为使用的点数) | |||||
combopoint_max = 0, %% 最大连击点数 | |||||
combopoint = 0, %% 连击点数(技能消耗/获得的属性,可额外增加伤害率或防御率) | |||||
hit_point = 0, %% 生命 | |||||
hit_point_max = 0, %% 生命上限 | |||||
magic = 0, %% 法力值 | |||||
magic_max = 0, %% 法力值上限 | |||||
anger = 0, %% 怒气值 | |||||
anger_max = 0, %% 怒气值上限 | |||||
attack = 0, %% 普通攻击力 | |||||
attack_ratio = 0, %% 普通攻击力增加伤害率(Buff附加值, 初始为0) | |||||
defense = 0, %% 普通防御力 | |||||
defense_ratio = 0, %% 普通防御力增加防御率(Buff附加值, 初始为0) | |||||
abs_damage = 0, %% 绝对伤害值 | |||||
fattack = 0, %% 仙攻值 | |||||
fattack_ratio = 0, %% 仙攻值增加伤害率(Buff附加值, 初始为0) | |||||
mattack = 0, %% 魔攻值 | |||||
mattack_ratio = 0, %% 魔攻值增加伤害率(Buff附加值, 初始为0) | |||||
dattack = 0, %% 妖攻值 | |||||
dattack_ratio = 0, %% 妖攻值增加伤害率(Buff附加值, 初始为0) | |||||
fdefense = 0, %% 仙防值 | |||||
fdefense_ratio = 0, %% 仙防值增加防御率(Buff附加值, 初始为0) | |||||
mdefense = 0, %% 魔防值 | |||||
mdefense_ratio = 0, %% 魔防值增加防御率(Buff附加值, 初始为0) | |||||
ddefense = 0, %% 妖防值 | |||||
ddefense_ratio = 0, %% 妖防值增加防御率(Buff附加值, 初始为0) | |||||
speed = 0, %% 移动速度 | |||||
attack_speed = 0, %% 攻击速度 | |||||
hit_ratio = 1, %% 命中等级(万分比) | |||||
dodge_ratio = 1, %% 闪避等级(万分比) | |||||
crit_ratio = 1, %% 暴击等级(万分比) | |||||
tough_ratio = 1, %% 坚韧等级(万分比) | |||||
frozen_resis_ratio = 0, %% 冰冻抗性率(帮派技能引入) | |||||
weak_resis_ratio = 0, %% 虚弱抗性率(帮派技能引入) | |||||
flaw_resis_ratio = 0, %% 破绽抗性率(帮派技能引入) | |||||
poison_resis_ratio = 0, %% 中毒抗性率(帮派技能引入) | |||||
avoid_attack_ratio = 0, %% 受到普攻免伤害率(Buff附加值, 初始为0) | |||||
avoid_fattack_ratio = 0, %% 受到仙攻免伤率(Buff附加值, 初始为0) | |||||
avoid_mattack_ratio = 0, %% 受到魔攻免伤率(Buff附加值, 初始为0) | |||||
avoid_dattack_ratio = 0, %% 受到妖攻免伤率(Buff附加值, 初始为0) | |||||
avoid_crit_attack_ratio = 0, %% 受到普攻暴击免伤害率(Buff附加值, 初始为0) | |||||
avoid_crit_fattack_ratio = 0, %% 受到仙攻暴击免伤率(Buff附加值, 初始为0) | |||||
avoid_crit_mattack_ratio = 0, %% 受到魔攻暴击免伤率(Buff附加值, 初始为0) | |||||
avoid_crit_dattack_ratio = 0, %% 受到妖攻暴击免伤率(Buff附加值, 初始为0) | |||||
ignore_defense = 0, %% 攻方忽略防方普防值(武魂引入) | |||||
ignore_fdefense = 0, %% 攻方忽略防方仙防值(武魂引入) | |||||
ignore_mdefense = 0, %% 攻方忽略防方魔防值(武魂引入) | |||||
ignore_ddefense = 0, %% 攻方忽略防方妖防值(武魂引入) | |||||
status_stop = 0, %% 石化状态 | |||||
status_silent = 0, %% 沉默状态[能普攻,不能技能] | |||||
status_unstoptable = 0, %% 免役控制 | |||||
status_unattrackable = 0, %% 不能发起攻击[普通或者技能都不可以] | |||||
change_appearance = 0, %% 外观变换 | |||||
energy = {}, %% 能量球, | |||||
passive_skill_attr = [], %% 职业被动分流, | |||||
hurt_call_back = 0, %% 受击反弹伤害百分比 | |||||
passive_hurt_rate = 0, %% 反伤百分比增加比率(被动技能) | |||||
control_radio = 0, %% 技能产生控制的几率 | |||||
walk_path = [], %% 行走路径,格式[DestX,DestY,Len,<<WalkPath>>] | |||||
move_destination = {0, 0}, %% 移动的目的点 | |||||
ai_init_id = 0, %% 初始的AI,用于重置 | |||||
clock_time = 143, %% 初始的时钟(一秒钟走7步,1000/7) | |||||
demage_buff_list = [], %% 伤害buff列表 | |||||
remove_buff_list = [], %% 移除buff列表 | |||||
attr_freeze_probability = 0, %% 受到冰冻的概率 | |||||
hp_cover_callback = 0, %% 回复效果 | |||||
is_rush_success = 0, %% 标记玩家是否冲锋成功 0.默认状态 1.冲锋成功 2.冲锋失败 | |||||
fight_pos = {1, 1}, %% 攻击对方时,站在对方的方位参数 1,0/1,1/1,-1/0,1/0,-1/-1,0/-1,1/-1,-1 | |||||
return_steps = 0, %% 在返回时,记录返回的步数(主要用于怪物返回的瞬移) | |||||
move_speed_queue = {{0, []}, {0, []}},%%移动速度buff效果队列 | |||||
damage_reduction = {0, 0, 0, ""}, %%当前吸收伤害盾吸收数值 | |||||
damage_reduction_queue = [], %%伤害吸收队列 | |||||
invincible = 0, %%无敌状态 | |||||
reduce_dot_damage = 0, %%忽略dot千分比伤害 | |||||
abs_crit_ratio = 1, %%暴击率真实值 | |||||
real_defense = 0 %%实际的物理防御力 | |||||
}). | |||||
%%用户的其他附加信息(对应player.other) | |||||
-record(player_other, { | |||||
skill_list = [], % 技能列表[{SkillId, Level}, ...] | |||||
skill_point = {0, 0}, % 技能点 | |||||
socket = undefined, % 当前用户的socket | |||||
pid = undefined, % 用户进程Pid | |||||
pid_goods = undefined, % 物品模块进程Pid | |||||
pid_send = [], % 消息发送进程Pid(可多个) | |||||
pid_battle = undefined, % 战斗进程Pid | |||||
pid_scene = undefined, % 当前场景Pid | |||||
pid_dungeon = undefined, % 当前副本进程 | |||||
pid_task = undefined, % 当前任务Pid | |||||
pid_mount = undefined, % 当前座骑Pid | |||||
node = undefined, % 进程所在节点 | |||||
blacklist = false, % 是否受黑名单监控 | |||||
pk_mode = 0, % 0-不强制pk模式 1-强制和平模式 2-强制自由pk模式 3-强制帮会pk模式 | |||||
goods_ets_id = 0, % 物品ets表ID | |||||
equip_current = [], % 影响玩家外观装备 | |||||
role_suit = [], % 套装列表 | |||||
weapon_strenLv = 0, % 武器强化等级 | |||||
armor_strenLv = 0, % 盔甲强化等级 | |||||
fashion_strenLv = 0, % 时装强化等级 | |||||
wapon_accstrenLv = 0, % 武饰强化等级 | |||||
wing_strenLv = 0, % 翅膀强化等级 | |||||
mount_fashion = 0, % 坐骑外观 | |||||
team_id = 0, % 队伍ID, 0为无队伍 | |||||
team_leader = 0, % 是否队长1是,其他不是 | |||||
pet_facade = 0, % 宠物外观 | |||||
pet_status = 0, % 0宠物休息, 1出战, 2不存在 | |||||
pet_quality_lv = 0, % 宠物品阶 | |||||
pet_name = <<"">>, % 宠物名字 | |||||
step_check_tasks = [], % 玩家移动时候是否需要检查任务的任务列表 | |||||
hardware_info = {} %玩家硬件信息 | |||||
}). | |||||
%%任务进度(用于在杀怪,采集等动作时保存对应的未完成任务与已完成任务) | |||||
-record(task_process_info, { | |||||
task_unfinsh = [], %%未完成的任务 | |||||
task_fin = [] %%已完成任务 | |||||
}). | |||||
%%怪物掉落 | |||||
-record(mon_drop_goods, { | |||||
drop_id = 0, %% 掉落物实例ID | |||||
uid = 0, %% 玩家ID | |||||
mon_id = 0, %% 掉落产生ID | |||||
goods_id = 0, %% 物品ID | |||||
goods_num = 0, %% 掉落数量 | |||||
x = 0, %% 掉落的X左边 | |||||
y = 0, %% 掉落的Y坐标 | |||||
expire_time = 0 %% 掉落失效时间 | |||||
}). | |||||
%% 购买npc商店日志 | |||||
-record(ets_npc_shop_log, { | |||||
key, | |||||
buy_num, %% | |||||
buy_time %% | |||||
}). | |||||
%% 购买商城日志 | |||||
-record(ets_shop_log, { | |||||
key, | |||||
buy_num, %% | |||||
buy_time %% | |||||
}). | |||||
%% 购买商城日志 | |||||
-record(ets_special_shop_log, { | |||||
key, | |||||
buy_num, %% | |||||
buy_time %% | |||||
}). | |||||
%% 队伍信息 | |||||
-record(team, { | |||||
tid = 0, %%队伍ID | |||||
leader_id = 0, %%队长ID | |||||
leader_nick = <<>>, %%队长名字 | |||||
leader_level = 0, %%队长的等级 | |||||
direct_join = 0, %%直接加入队伍 | |||||
invite_allow = 0, %%成员可发邀请 | |||||
max_num = 0, %%最大队员数 | |||||
member_ids = [] %%成员ID列表 | |||||
}). | |||||
%% 成员信息 | |||||
-record(team_member, { | |||||
uid = 0, %%角色ID | |||||
tid = 0, %%队伍ID | |||||
level = 0, %%队长的等级 | |||||
nick = <<>>, %%名字 | |||||
force = 0, %%战斗力 | |||||
camp = 0, %%阵营 | |||||
career = 0, %%职业 | |||||
gender = 0 %%性别 | |||||
}). | |||||
-record(energy, { | |||||
attack = <<"{}">>, %%攻击时回复的能量系数k | |||||
injured, %%被攻击时回复的能量系数k | |||||
crit, %%暴击回复的能量系数k | |||||
battle_recover, %%战斗时回复每秒的能量系数 k | |||||
normal_recover, %%离开战斗时每秒回复的能量系数 k | |||||
last_reflesh_time, %%最近一次计算能量球的时间 | |||||
energy_val, %%玩家当前的能量值 | |||||
max_energy, %%玩家能量值上限 , | |||||
freeze_second = 0, %%能量值暂停衰减的时间 | |||||
attack_callback_rate = 1, %%攻击回复能量值比 | |||||
injured_rate = 1000, %%受击回复能量比例 | |||||
recover_percent = 0 %%回复能量百分比 | |||||
}). | |||||
-record(ets_scene_slice, { | |||||
id = 0, | |||||
obj = [] | |||||
}). | |||||
-record(hardware_info, { | |||||
os = 0,%%手机操作系统,如:0.未知 1.android 2.iphone | |||||
os_version = <<"">>,%%操作系统版本号,如:2.3.4 | |||||
device = <<"">>,%%设备名称,如:三星GT-S5830 | |||||
device_type = 0,%%设备类型,如:0.未知 1.android 2.iPhone 3.iPad | |||||
screen = <<"">>,%%屏幕分辨率,如:480*800 | |||||
mno = 0,%%移动网络运营商(mobile network operators),0.未知 1.中国移动 2.中国电信 3.中国联通 | |||||
nm = 0 %%联网方式(Networking mode),如:0.未知 1.3G 2.WIFI 3.2G | |||||
}). |
@ -1,4 +1,50 @@ | |||||
-module(misc). | |||||
-module(misc1). | |||||
%% | |||||
%% API Functions | |||||
%% | |||||
%% get the pid of a registered name | |||||
whereis_name({local, Atom}) -> | |||||
erlang:whereis(Atom); | |||||
whereis_name({global, Atom}) -> | |||||
global:whereis_name(Atom). | |||||
register(local, Name, Pid) -> | |||||
erlang:register(Name, Pid); | |||||
register(global, Name, Pid) -> | |||||
%% case global:whereis_name(Name) of | |||||
%% Pid0 when is_pid(Pid0) -> | |||||
%% exit(Pid0,normal); | |||||
%% undefined -> | |||||
%% global:re_register_name(Name, Pid) | |||||
%% end. | |||||
global:re_register_name(Name, Pid); | |||||
register(unique, Name, Pid) -> | |||||
global:register_name(Name, Pid). | |||||
unregister({local, Atom}) -> | |||||
erlang:unregister(Atom); | |||||
unregister({global, Atom}) -> | |||||
global:unregister(Atom). | |||||
is_process_alive(Pid) -> | |||||
try | |||||
if is_pid(Pid) -> | |||||
%%现在都是单节点,无需访问节点来判断 | |||||
%% case rpc:call(node(Pid), erlang, is_process_alive, [Pid]) of | |||||
%% {badrpc, _Reason} -> false; | |||||
%% Res -> Res | |||||
%% end; | |||||
erlang:is_process_alive(Pid); | |||||
true -> false | |||||
end | |||||
catch | |||||
_:_ -> false | |||||
end. | |||||
get_child_count(Atom) -> | get_child_count(Atom) -> | ||||
case whereis_name({local, Atom}) of | case whereis_name({local, Atom}) of |
@ -1,714 +0,0 @@ | |||||
-module(misc). | |||||
%% | |||||
%% Include files | |||||
%% | |||||
-include("common.hrl"). | |||||
-include("cache.hrl"). | |||||
-include("item.hrl"). | |||||
-include_lib("kernel/include/file.hrl"). | |||||
%% | |||||
%% Exported Functions | |||||
%% | |||||
-export([ | |||||
whereis_name/1, | |||||
register/3, | |||||
unregister/2, | |||||
is_process_alive/1, | |||||
create_process_name/2, | |||||
to_atom/1, | |||||
% t/1, | |||||
% t/2, | |||||
% tr/1, | |||||
% tun/1, | |||||
% tan/1, | |||||
% t_clear/0, | |||||
dump_process_info/1 | |||||
, u/1 | |||||
, hot/0 | |||||
, hot_beam/1 %% 直接加载更新变动beam文件,运营服使用 | |||||
, ets_mem/0 | |||||
, tcp_links/0 | |||||
, top_back/0 | |||||
, top/0 | |||||
, request/1 | |||||
, u_one/1 | |||||
, stop/0 | |||||
, del_ref/1 | |||||
]). | |||||
-export([ | |||||
role_cmd/3 | |||||
, gm/2 | |||||
, check_mem/0 | |||||
, check_mem/1 | |||||
, online_num/0 | |||||
, is_cross/0 | |||||
]). | |||||
-export([ | |||||
decompile/1 | |||||
, pstack/1 | |||||
, etop/0 | |||||
, etop_mem/0 | |||||
, etop_stop/0 | |||||
, gc_all/0 | |||||
, fprof/3 | |||||
, eprof_all/1 | |||||
, eprof/2 | |||||
, scheduler_usage/0 | |||||
, scheduler_usage/1 | |||||
, scheduler_stat/0 | |||||
, scheduler_stat/1 | |||||
, trace/1 | |||||
, trace/2 | |||||
, trace_stop/0 | |||||
, proc_mem_all/1 | |||||
, proc_mem/1 | |||||
, crash_dump/0 | |||||
, process_infos/0 | |||||
]). | |||||
-export([check_item/0, ints2str/2]). | |||||
%% | |||||
%% API Functions | |||||
%% | |||||
%% @doc 删除ref | |||||
del_ref(Ref) when is_reference(Ref) -> | |||||
erlang:cancel_timer(Ref); | |||||
del_ref(_) -> | |||||
ok. | |||||
%% @doc 节点所有进程信息 | |||||
process_infos() -> | |||||
filelib:ensure_dir("./logs/"), | |||||
File = "./logs/processes_infos.log", | |||||
{ok, Fd} = file:open(File, [write, raw, binary, append]), | |||||
Fun = fun(Pi) -> | |||||
Info = io_lib:format("=>~p \n\n", [Pi]), | |||||
case filelib:is_file(File) of | |||||
true -> file:write(Fd, Info); | |||||
false -> | |||||
file:close(Fd), | |||||
{ok, NewFd} = file:open(File, [write, raw, binary, append]), | |||||
file:write(NewFd, Info) | |||||
end, | |||||
timer:sleep(20) | |||||
end, | |||||
[Fun(erlang:process_info(P)) || P <- erlang:processes()]. | |||||
%% @doc erlang_dump | |||||
crash_dump() -> | |||||
Date = erlang:list_to_binary(rfc1123_local_date()), | |||||
Header = binary:list_to_bin([<<"=erl_crash_dump:0.2\n">>, Date, <<"\nSystem version: ">>]), | |||||
Ets = ets_info(), | |||||
Report = binary:list_to_bin([Header, erlang:list_to_binary(erlang:system_info(system_version)), | |||||
erlang:system_info(info), erlang:system_info(procs), Ets, erlang:system_info(dist), | |||||
<<"=loaded_modules\n">>, binary:replace(erlang:system_info(loaded), | |||||
<<"\n">>, <<"\n=mod:">>, [global])]), | |||||
file:write_file("erl_crash.dump", Report). | |||||
ets_info() -> | |||||
binary:list_to_bin([ets_table_info(T) || T <- ets:all()]). | |||||
ets_table_info(Table) -> | |||||
Info = ets:info(Table), | |||||
Owner = erlang:list_to_binary(erlang:pid_to_list(proplists:get_value(owner, Info))), | |||||
TableN = erlang:list_to_binary(erlang:atom_to_list(proplists:get_value(name, Info))), | |||||
Name = erlang:list_to_binary(erlang:atom_to_list(proplists:get_value(name, Info))), | |||||
Objects = erlang:list_to_binary(erlang:integer_to_list(proplists:get_value(size, Info))), | |||||
binary:list_to_bin([<<"=ets:">>, Owner, <<"\nTable: ">>, TableN, <<"\nName: ">>, Name, | |||||
<<"\nObjects: ">>, Objects, <<"\n">>]). | |||||
rfc1123_local_date() -> | |||||
rfc1123_local_date(os:timestamp()). | |||||
rfc1123_local_date({A, B, C}) -> | |||||
rfc1123_local_date(calendar:now_to_local_time({A, B, C})); | |||||
rfc1123_local_date({{YYYY, MM, DD}, {Hour, Min, Sec}}) -> | |||||
DayNumber = calendar:day_of_the_week({YYYY, MM, DD}), | |||||
lists:flatten( | |||||
io_lib:format("~s, ~2.2.0w ~3.s ~4.4.0w ~2.2.0w:~2.2.0w:~2.2.0w GMT", | |||||
[httpd_util:day(DayNumber), DD, httpd_util:month(MM), YYYY, Hour, Min, Sec])); | |||||
rfc1123_local_date(Epoch) when erlang:is_integer(Epoch) -> | |||||
rfc1123_local_date(calendar:gregorian_seconds_to_datetime(Epoch + 62167219200)). | |||||
%% @doc etop 无法应对10w+ 进程节点, 下面代码就没问题了;找到可疑proc后通过pstack、message_queu_len 排查原因 | |||||
proc_mem_all(SizeLimitKb) -> | |||||
Procs = [{undefined, Pid} || Pid <- erlang:processes()], | |||||
proc_mem(Procs, SizeLimitKb). | |||||
proc_mem(SizeLimitKb) -> | |||||
Procs = [{Name, Pid} || {_, Name, Pid, _} <- release_handler_1:get_supervised_procs(), erlang:is_process_alive(Pid)], | |||||
proc_mem(Procs, SizeLimitKb). | |||||
proc_mem(Procs, SizeLimitKb) -> | |||||
SizeLimit = SizeLimitKb * 1024, | |||||
{R, Total} = lists:foldl(fun({Name, Pid}, {Acc, TotalSize}) -> | |||||
case erlang:process_info(Pid, total_heap_size) of | |||||
{_, Size0} -> | |||||
Size = Size0 * 8, | |||||
case Size > SizeLimit of | |||||
true -> {[{Name, Pid, Size} | Acc], TotalSize + Size}; | |||||
false -> {Acc, TotalSize} | |||||
end; | |||||
_ -> {Acc, TotalSize} | |||||
end | |||||
end, {[], 0}, Procs), | |||||
R1 = lists:keysort(3, R), | |||||
{Total, lists:reverse(R1)}. | |||||
%trace Mod 所有方法的调用 | |||||
trace(Mod) -> | |||||
dbg:tracer(), | |||||
dbg:tpl(Mod, '_', []), | |||||
dbg:p(all, c). | |||||
%trace Node上指定 Mod 所有方法的调用, 结果将输出到本地shell | |||||
trace(Node, Mod) -> | |||||
dbg:tracer(), | |||||
dbg:n(Node), | |||||
dbg:tpl(Mod, '_', []), | |||||
dbg:p(all, c). | |||||
%停止trace | |||||
trace_stop() -> | |||||
dbg:stop_clear(). | |||||
% 统计下1s内调度进程数量(含义:第一个数字执行进程数量,第二个数字迁移进程数量) | |||||
scheduler_stat() -> | |||||
scheduler_stat(1000). | |||||
scheduler_stat(RunMs) -> | |||||
erlang:system_flag(scheduling_statistics, enable), | |||||
Ts0 = erlang:system_info(total_scheduling_statistics), | |||||
timer:sleep(RunMs), | |||||
Ts1 = erlang:system_info(total_scheduling_statistics), | |||||
erlang:system_flag(scheduling_statistics, disable), | |||||
lists:map(fun({{Key, In0, Out0}, {Key, In1, Out1}}) -> | |||||
{Key, In1 - In0, Out1 - Out0} end, lists:zip(Ts0, Ts1)). | |||||
% 统计下1s每个调度器CPU的实际利用率(因为有spin wait、调度工作, 可能usage 比top显示低很多) | |||||
scheduler_usage() -> | |||||
scheduler_usage(1000). | |||||
scheduler_usage(RunMs) -> | |||||
erlang:system_flag(scheduler_wall_time, true), | |||||
Ts0 = lists:sort(erlang:statistics(scheduler_wall_time)), | |||||
timer:sleep(RunMs), | |||||
Ts1 = lists:sort(erlang:statistics(scheduler_wall_time)), | |||||
erlang:system_flag(scheduler_wall_time, false), | |||||
Cores = lists:map(fun({{I, A0, T0}, {I, A1, T1}}) -> | |||||
{I, (A1 - A0) / (T1 - T0)} end, lists:zip(Ts0, Ts1)), | |||||
{A, T} = lists:foldl(fun({{_, A0, T0}, {_, A1, T1}}, {Ai, Ti}) -> | |||||
{Ai + (A1 - A0), Ti + (T1 - T0)} end, {0, 0}, lists:zip(Ts0, Ts1)), | |||||
Total = A / T, | |||||
io:format("~p~n", [[{total, Total} | Cores]]). | |||||
% 对整个节点内所有进程执行eprof, eprof 对线上业务有一定影响,慎用! | |||||
% 建议TimeoutSec<10s,且进程数< 1000,否则可能导致节点crash | |||||
% 结果: | |||||
% 输出每个方法实际执行时间(不会累计方法内其他mod调用执行时间) | |||||
% 只能得到mod - Fun 执行次数 执行耗时 | |||||
eprof_all(TimeoutSec) -> | |||||
eprof(processes() -- [whereis(eprof)], TimeoutSec). | |||||
eprof(Pids, TimeoutSec) -> | |||||
eprof:start(), | |||||
eprof:start_profiling(Pids), | |||||
timer:sleep(TimeoutSec), | |||||
eprof:stop_profiling(), | |||||
eprof:analyze(total), | |||||
eprof:stop(). | |||||
% @doc 对MFA 执行分析,会严重减缓运行,建议只对小量业务执行 | |||||
% 结果: | |||||
% fprof 结果比较详细,能够输出热点调用路径 | |||||
fprof(M, F, A) -> | |||||
fprof:start(), | |||||
fprof:apply(M, F, A), | |||||
fprof:profile(), | |||||
fprof:analyse([{dest, "fprof.analysis"}, {sort, own}]), | |||||
fprof:stop(). | |||||
% @doc 对所有process做gc | |||||
gc_all() -> | |||||
[erlang:garbage_collect(Pid) || Pid <- processes()]. | |||||
% @doc 进程CPU占用排名 | |||||
etop() -> | |||||
spawn(fun() -> etop:start([{output, text}, {interval, 10}, {lines, 20}, {sort, runtime}]) end). | |||||
% @doc 进程Mem占用排名 | |||||
etop_mem() -> | |||||
spawn(fun() -> etop:start([{output, text}, {interval, 10}, {lines, 20}, {sort, memory}]) end). | |||||
% @doc 停止etop | |||||
etop_stop() -> | |||||
etop:stop(). | |||||
%% @doc 类似于jstack,发现大量进程挂起,进程数过高,运行慢,hang住等问题用到 | |||||
pstack(Reg) when is_atom(Reg) -> | |||||
case whereis(Reg) of | |||||
undefined -> undefined; | |||||
Pid -> pstack(Pid) | |||||
end; | |||||
pstack(Pid) -> | |||||
io:format("~s~n", [element(2, process_info(Pid, backtrace))]). | |||||
%% @doc 检测占用总内存大运600M的全部强制GC | |||||
check_mem() -> | |||||
Total = erlang:memory(total), | |||||
case Total > 600000000 of | |||||
true -> | |||||
spawn(fun() -> [erlang:garbage_collect(Pid) || Pid <- processes()] end); | |||||
_ -> | |||||
ok | |||||
end. | |||||
% check_mem(1000000000). | |||||
%% 检查溢出的内存,强制gc, 并写入日志分析 | |||||
check_mem(MemLim) -> | |||||
lists:foreach( | |||||
fun(P) -> | |||||
case is_pid(P) andalso erlang:is_process_alive(P) of | |||||
true -> | |||||
{memory, Mem} = erlang:process_info(P, memory), | |||||
case Mem > MemLim of | |||||
true -> | |||||
erlang:garbage_collect(P); | |||||
false -> | |||||
[] | |||||
end; | |||||
false -> | |||||
[] | |||||
end | |||||
end, erlang:processes()). | |||||
%% @doc 发送GM命令 | |||||
gm(RoleId, Content) -> | |||||
role_cmd(RoleId, 11600, [Content]). | |||||
%% @doc 发送玩家协议 | |||||
role_cmd(RoleId, Cmd, Data) -> | |||||
svr_role:apply(async, RoleId, {lib_role, async_cmd, [Cmd, Data]}). | |||||
%% @doc 关闭应用 | |||||
stop() -> | |||||
case is_cross() of | |||||
true -> | |||||
cross_stop(); | |||||
_ -> | |||||
common_stop() | |||||
end. | |||||
%% @doc 游戏服关闭 | |||||
common_stop() -> | |||||
AllRoles = ets:tab2list(?ETS_ONLINE), | |||||
[Pid ! {'stop', server_stop} || #role{pid = Pid} <- AllRoles],%玩家下线 | |||||
cowboy:stop_listener(http), | |||||
catch svr_cache_mgr:do_save(), | |||||
catch svr_chat:save_chat(), | |||||
catch svr_rank:hand_save(), | |||||
catch svr_log:hand_save(), | |||||
case catch check_item() of | |||||
{'EXIT', Res} -> | |||||
?INF("error:~p", [Res]); | |||||
_ -> | |||||
ok | |||||
end, | |||||
?INF("server_stop"), | |||||
init:stop(). | |||||
%% @doc 检测物品消失 | |||||
check_item() -> | |||||
List = ets:tab2list(?ETS_CACHE_ITEM_ROLE), | |||||
check_item(List). | |||||
check_item([{RoleId, Ids = [_ | _]} | T]) -> | |||||
SelectSql = io_lib:format(<<"select id from player_item where role_id=~p;">>, [RoleId]), | |||||
IdVals = db:execute(SelectSql), | |||||
case filter_item_ids(IdVals, Ids, []) of | |||||
[_ | IdStrs] -> | |||||
Sql = io_lib:format(<<"delete from player_item where id in (~s);">>, [IdStrs]), | |||||
db:execute(Sql); | |||||
_ -> | |||||
ok | |||||
end, | |||||
save_eq(Ids), | |||||
check_item(T); | |||||
check_item([_ | T]) -> | |||||
check_item(T); | |||||
check_item([]) -> | |||||
ok. | |||||
%% @doc 保存玩家装备信息 | |||||
save_eq(Ids) -> | |||||
case find_eq_item(Ids, []) of | |||||
[_ | SqlVals] -> | |||||
Sql = io_lib:format(?SQL_ITEM_BATCH_REPLACE, [SqlVals]), | |||||
db:execute(Sql); | |||||
_ -> | |||||
ok | |||||
end. | |||||
find_eq_item([Id | T], L) -> | |||||
L1 = | |||||
case svr_cache_item:find_item(Id) of | |||||
Item = #item{slot = Slot} -> | |||||
case Slot > 0 orelse lib_awake_equip:is_awake(Item) of | |||||
true -> | |||||
"," ++ lib_item_dict:make_batch_insert_sql_one(Item) ++ L; | |||||
_ -> | |||||
L | |||||
end; | |||||
_ -> | |||||
L | |||||
end, | |||||
find_eq_item(T, L1); | |||||
find_eq_item([], L) -> | |||||
L. | |||||
%% @doc 筛选物品 | |||||
filter_item_ids([[Id] | T], Ids, L) -> | |||||
L1 = | |||||
case lists:member(Id, Ids) of | |||||
false -> | |||||
IdStr = integer_to_list(Id), | |||||
"," ++ IdStr ++ L; | |||||
_ -> | |||||
L | |||||
end, | |||||
filter_item_ids(T, Ids, L1); | |||||
filter_item_ids([], _, L) -> | |||||
L. | |||||
ints2str([Id | T], L) -> | |||||
IdStr = integer_to_list(Id), | |||||
case T of | |||||
[] -> | |||||
ints2str(T, IdStr ++ L); | |||||
_ -> | |||||
ints2str(T, "," ++ IdStr ++ L) | |||||
end; | |||||
ints2str([], L) -> | |||||
L. | |||||
%% @doc 中央服关闭 | |||||
cross_stop() -> | |||||
catch svr_kfboss_awake_mgr:stop(), | |||||
catch svr_kfnode:stop(), | |||||
init:stop(). | |||||
%% @doc 是否是中央服 | |||||
is_cross() -> | |||||
case config:get_platform() of | |||||
"cross" -> | |||||
true; | |||||
_ -> | |||||
false | |||||
end. | |||||
%% @doc 寻找PID | |||||
whereis_name({local, Atom}) -> | |||||
erlang:whereis(Atom); | |||||
whereis_name({global, Atom}) -> | |||||
global:whereis_name(Atom). | |||||
register(local, Name, Pid) -> | |||||
erlang:register(Name, Pid); | |||||
register(global, Name, Pid) -> | |||||
global:re_register_name(Name, Pid). | |||||
unregister(local, Name) -> | |||||
erlang:unregister(Name); | |||||
unregister(global, Name) -> | |||||
global:unregister_name(Name). | |||||
is_process_alive(Pid) -> | |||||
try | |||||
case Pid of | |||||
_ when is_pid(Pid) -> | |||||
Node = node(), | |||||
Result = case node(Pid) of | |||||
Node -> erlang:is_process_alive(Pid); | |||||
Node1 -> rpc:call(Node1, erlang, is_process_alive, [Pid]) | |||||
end, | |||||
case Result of | |||||
{badrpc, _Reason} -> false; | |||||
Res -> Res | |||||
end; | |||||
_ -> false | |||||
end | |||||
catch | |||||
_:_ -> false | |||||
end. | |||||
create_process_name(Prefix, List) -> | |||||
to_atom(lists:concat(lists:flatten([Prefix] ++ lists:map(fun(T) -> ['_', T] end, List)))). | |||||
to_atom(Msg) when is_atom(Msg) -> | |||||
Msg; | |||||
to_atom(Msg) when is_binary(Msg) -> | |||||
list_to_atom2(binary_to_list(Msg)); | |||||
to_atom(Msg) when is_list(Msg) -> | |||||
list_to_atom2(Msg); | |||||
to_atom(_) -> | |||||
throw(other_value). %%list_to_atom(""). | |||||
list_to_atom2(List) when is_list(List) -> | |||||
case catch (list_to_existing_atom(List)) of | |||||
{'EXIT', _} -> erlang:list_to_atom(List); | |||||
Atom when is_atom(Atom) -> Atom | |||||
end. | |||||
%%------------------------------------------------ | |||||
%% Admin API | |||||
%%------------------------------------------------ | |||||
%% @spec hot/0 -> ok | |||||
%% @doc 编译源码并热更 TODO:会加载修改时间在六分钟之内的模块 | |||||
%% @doc 开发环境这里需要编译,线上环境直接加载更新的beam文件 | |||||
hot() -> | |||||
HotTime = svr_handle_mgr:hot_time() - 360, | |||||
Now = ?NOW, | |||||
case max(0, Now - HotTime) of | |||||
TimeLimit when TimeLimit > 0 -> | |||||
hot_beam(TimeLimit), | |||||
% 热更后需要刷新的活动 | |||||
svr_activity_fl:reflash(), | |||||
ok; | |||||
_ -> | |||||
ok | |||||
end. | |||||
hot_beam(TimeLimit) when TimeLimit > 0 -> | |||||
Now = ?NOW, | |||||
FilePaths = all_ebin_file(), | |||||
io:format("-----------------------------------------------~n"), | |||||
io:format("hots ~p ~p~n", [node(), config:server_ids()]), | |||||
io:format("~n"), | |||||
lists:foreach(fun(FilePath) -> | |||||
case file:read_file_info(FilePath) of | |||||
{ok, #file_info{mtime = Mtime}} -> | |||||
Time = util:datetime_to_seconds(Mtime), | |||||
case Now - Time =< TimeLimit of | |||||
true -> | |||||
Module = filename:basename(FilePath, ".beam"), | |||||
u(list_to_atom(Module)); | |||||
_ -> | |||||
ok | |||||
end; | |||||
_ -> | |||||
ok | |||||
end | |||||
end, FilePaths), | |||||
io:format("~n"), | |||||
io:format("-----------------------------------------------~n"); | |||||
hot_beam(_) -> | |||||
ok. | |||||
%% @doc 获取代码所有 | |||||
all_ebin_file() -> | |||||
LogicNames = filelib:wildcard("../ebin/*.beam"), | |||||
DepsNames = filelib:wildcard("../deps/*/ebin/*.beam"), | |||||
DepsNames ++ LogicNames. | |||||
%% @doc 热更 | |||||
u(M) when not is_list(M) -> | |||||
u([M], []); | |||||
u(List) -> | |||||
u(List, []). | |||||
u([], List) -> | |||||
List; | |||||
u([Module | T], List) -> | |||||
Ret = u_one(Module), | |||||
u(T, [{Ret, Module} | List]). | |||||
u_one(Module) -> | |||||
case c:nl(Module) of | |||||
abcast -> | |||||
?PRINT("~w:load ~20w ok", [calendar:local_time(), Module]), | |||||
ok; | |||||
_ -> | |||||
?PRINT("~w:load ~20w fail", [calendar:local_time(), Module]), | |||||
error | |||||
end. | |||||
%% @spec top() -> ok | |||||
%% @doc 查看系统当前的综合信息 | |||||
top() -> | |||||
Release = erlang:system_info(otp_release), | |||||
SchedNum = erlang:system_info(schedulers), | |||||
ProcCount = erlang:system_info(process_count), | |||||
ProcLimit = erlang:system_info(process_limit), | |||||
ProcMemUsed = erlang:memory(processes_used), | |||||
EtsMemAlc = erlang:memory(ets), | |||||
MemTot = erlang:memory(total), | |||||
RoleNum = ets:info(?ETS_ONLINE, size), | |||||
%PetNum = all_pets(), | |||||
io:format( | |||||
"++++++++++++++++++++++++++++++++++++++++++~n" | |||||
" ServerId: ~p~n" | |||||
" Node: ~p~n" | |||||
" Erlang Ver: ~p~n" | |||||
" Free Threads: ~p~n" | |||||
" Process Used Memory: ~pMb~n" | |||||
" Ets Used Memory: ~pMb~n" | |||||
" Erlang VM Used Memory: ~pMb~n" | |||||
" Process Limit: ~p~n" | |||||
" Process Used: ~p~n" | |||||
" Online Players: ~p~n" | |||||
"++++++++++++++++++++++++++++++++++++++++++~n" | |||||
, [config:server_ids(), node(), Release, SchedNum, ProcMemUsed / 1024 / 1024, EtsMemAlc / 1024 / 1024, MemTot / 1024 / 1024, ProcLimit, ProcCount, RoleNum]), | |||||
ok. | |||||
%% @doc 运维要用 | |||||
top_back() -> | |||||
Release = erlang:system_info(otp_release), | |||||
SchedNum = erlang:system_info(schedulers), | |||||
ProcCount = erlang:system_info(process_count), | |||||
ProcLimit = erlang:system_info(process_limit), | |||||
ProcMemUsed = erlang:memory(processes_used), | |||||
EtsMemAlc = erlang:memory(ets), | |||||
MemTot = erlang:memory(total), | |||||
RoleNum = ets:info(?ETS_ONLINE, size), | |||||
Str = io_lib:format( | |||||
" Erlang 版本: ~p~n" | |||||
" 可使用的调度线程: ~p~n" | |||||
" 所有进程使用的内存: ~pMb~n" | |||||
" 所有ets使用的内存: ~pMb~n" | |||||
" Erlang系统占用内存: ~pMb~n" | |||||
" 可创建进程数量上限: ~p~n" | |||||
" 当前进程数: ~p~n" | |||||
" 在线角色数: ~p~n" | |||||
, [Release, SchedNum, ProcMemUsed / 1024 / 1024, EtsMemAlc / 1024 / 1024, MemTot / 1024 / 1024, ProcLimit, ProcCount, RoleNum]), | |||||
binary_to_list(list_to_binary(Str)). | |||||
%% @spec ets_mem() -> term() | |||||
%% @doc 查看内存占用最多的30张ets表 | |||||
ets_mem() -> | |||||
L = ets:all(), | |||||
Mems = lists:map(fun(Tab) -> | |||||
Info = ets:info(Tab), | |||||
case lists:keyfind(memory, 1, Info) of | |||||
{memory, Mem} -> {Tab, Mem}; | |||||
_ -> {Tab, 0} | |||||
end | |||||
end, L), | |||||
L1 = lists:sublist(lists:reverse(lists:keysort(2, Mems)), 30), | |||||
?PRINT("~n--------------------------------------------------~n" | |||||
"~-30w ~w~n--------------------------------------------------~n" | |||||
, [table, used_memory]), | |||||
lists:foreach(fun({Tab, Mem}) -> | |||||
?PRINT("~-30w ~wKb~n", [Tab, Mem / 1024]) | |||||
end, L1). | |||||
%% @spec tcp_links() -> Info | |||||
%% @doc 统计tcp链接 | |||||
tcp_links() -> | |||||
L = erlang:ports(), | |||||
F = fun(P) -> | |||||
Pinfo = erlang:port_info(P), | |||||
case lists:keyfind(name, 1, Pinfo) of | |||||
{name, "tcp_inet"} -> true; | |||||
_ -> false | |||||
end | |||||
end, | |||||
L1 = lists:filter(F, L), | |||||
?PRINT("~n当前socket数量(包括链接数据库的socket): ~w~n", [length(L1)]). | |||||
% %% @doc 根据账户名trace | |||||
% tan(AcountName) -> | |||||
% Bin = unicode:characters_to_binary(AcountName), | |||||
% [t(UserID)||#ets_user{account_name = Name, id = UserID} <- ets:tab2list(?ETS_ONLINE), Name =:= Bin]. | |||||
% %% @doc 根据角色名trace | |||||
% tun(UserName) -> | |||||
% Bin = unicode:characters_to_binary(UserName), | |||||
% [t(UserID) ||#ets_user{name = Name, id = UserID} <- ets:tab2list(?ETS_ONLINE), Name =:= Bin]. | |||||
% %% @doc 根据角色ID trace 方法 | |||||
% t(UserID, MFN) -> | |||||
% t(UserID), | |||||
% t(MFN). | |||||
% t({M, F, Num}) -> | |||||
% dbg:tpl(M, F, Num, []); | |||||
% t(UserID) -> | |||||
% dbg:tracer(), | |||||
% Pid = misc:whereis_name({global, player_process_name(UserID)}), | |||||
% dbg:p(Pid, c). | |||||
% tr({M, F, Num}) -> | |||||
% dbg:tpl(M, F, Num, [{'_', [], [{return_trace}]}]). | |||||
% %% @doc 停止 trace | |||||
% t_clear() -> | |||||
% dbg:stop_clear(). | |||||
%% @doc 备份进程信息 | |||||
dump_process_info(Pid) -> | |||||
{{Year, Month, Day}, {Hour, Minutes, Second}} = util:local_time(), | |||||
{ok, FileHandle} = file:open(util:fbin("~s-~w-~w-~w-~w-~w-~w", [<<"../logs/pid_info.dump">>, Year, Month, Day, Hour, Minutes, Second]), write), | |||||
case erlang:process_info(Pid) of | |||||
Info when is_list(Info) -> | |||||
lists:foreach(fun({messages, Messages}) -> | |||||
case Messages =:= [] of | |||||
true -> | |||||
io:format(FileHandle, "~w~n", [{messages, Messages}]); | |||||
_ -> | |||||
io:format(FileHandle, "{messages,~n", []), | |||||
lists:foreach(fun(M) -> | |||||
io:format(FileHandle, " ~w~n", [M]) | |||||
end, Messages), | |||||
io:format(FileHandle, "}~n", []) | |||||
end; | |||||
({dictionary, Dics}) -> | |||||
case Dics =:= [] of | |||||
true -> | |||||
io:format(FileHandle, "~w~n", [{dictionary, Dics}]); | |||||
_ -> | |||||
io:format(FileHandle, "{dictionary,~n", []), | |||||
lists:foreach(fun(M) -> | |||||
io:format(FileHandle, " ~w~n", [M]) | |||||
end, Dics), | |||||
io:format(FileHandle, "}~n", []) | |||||
end; | |||||
(E) -> | |||||
io:format(FileHandle, "~w~n", [E]) | |||||
end, Info); | |||||
_ -> ?PRINT("not find pid info") | |||||
end, | |||||
file:close(FileHandle). | |||||
request(Url) -> | |||||
{ok, RequestId} = httpc:request(get, {Url, []}, [], [{sync, false}]), | |||||
receive | |||||
{http, {RequestId, {{_Version, 200, _ReasonPhrase}, _Headers, Body}}} -> | |||||
Body; | |||||
E -> | |||||
E | |||||
after 500 -> | |||||
timeout | |||||
end. |
@ -1,124 +0,0 @@ | |||||
%%-------------------------------------- | |||||
%% @Module : auto_id | |||||
%% @Author : smxx | |||||
%% @Created : 2013.03.01 | |||||
%% @Description: 设置数据表的自增ID初值 | |||||
%%-------------------------------------- | |||||
-module(auto_id). | |||||
-compile([export_all]). | |||||
-include("auto_id.hrl"). | |||||
%%设置自增ID初值(服务节点才需要处理. 其他不管) | |||||
set_auto_increment(server) -> | |||||
ServerNum = config:get_server_num(), | |||||
io:format("~n--------------------------------------------------~n"), | |||||
io:format("Start checking tables Auto Increment...~n"), | |||||
io:format("Current Server Num: ~p~n", [ServerNum]), | |||||
io:format("--------------------------------------------------~n"), | |||||
F = fun(TableName) -> | |||||
case get_auto_increment_width(TableName) of | |||||
no_match -> | |||||
io:format("Table: ~p found NO AUTO_INCREMENT fields, check your configuration!~n", [TableName]); | |||||
Width -> %%字段宽度 | |||||
case Width of | |||||
20 -> | |||||
Start = ServerNum * ?SPACE20 + 1, | |||||
End = (ServerNum + 1) * ?SPACE20; | |||||
11 -> | |||||
Start = ServerNum * ?SPACE11 + 1, | |||||
End = (ServerNum + 1) * ?SPACE11 | |||||
end, | |||||
CurrentOffset = get_auto_increment_offset(TableName), | |||||
if | |||||
%% CurrentOffset >= Start andalso CurrentOffset < End -> %%已经设置好了 | |||||
%% io:format("Table: ~p \tAUTO_INCREMENT OFFSET ->\tOK~n", [TableName]), | |||||
%% io:format("\t\tCurrent: ~p, Start: ~p, End:~p~n~n", [CurrentOffset, Start, End]); | |||||
%% CurrentOffset >= End -> | |||||
%% io:format("Table: ~p \tAUTO_INCREMENT OFFSET -> OUT OF RANGE~n", [TableName]), | |||||
%% io:format("\t\tCurrent: ~p, Start: ~p, End:~p~n~n", [CurrentOffset, Start, End]); | |||||
CurrentOffset > ?SPACE20 -> %% 已经设置过了偏移量 | |||||
io:format("Table: ~p \t AUTO_INCREMENT OFFSET ->\tOK~n", [TableName]), | |||||
io:format("\t\tCurrent: ~p, Start: ~p, End:~p~n~n", [CurrentOffset, Start, End]); | |||||
true -> | |||||
io:format("Table: ~p \tAUTO_INCREMENT OFFSET -> NOT SET~n", [TableName]), | |||||
io:format("\t\tCurrent: ~p, Start: ~p, End:~p~n", [CurrentOffset, Start, End]), | |||||
io:format("\t\tSetting to: ~p", [Start]), | |||||
case set_auto_increment_offset(TableName, Start) of | |||||
true -> io:format(" -> OK~n~n"); | |||||
_ -> io:format(" -> Failed~n~n") | |||||
end | |||||
end | |||||
end | |||||
end, | |||||
lists:foreach(F, ?AUTO_ID_TABLES), | |||||
io:format("~nTables Auto Increment Done~n"), | |||||
io:format("--------------------------------------------------~n"); | |||||
set_auto_increment(_) -> | |||||
skip. | |||||
%%Auto_Increment字段在第11位 | |||||
get_auto_increment_offset(TableName) -> | |||||
Sql = lists:concat(["show table status where name='", TableName, "'"]), | |||||
case lists:nth(11, db_esql:get_row(Sql)) of | |||||
Offset when is_integer(Offset) -> | |||||
Offset; | |||||
_Error -> | |||||
io:format("ERROR when getting Auto_Increment for table ~p~n", [TableName]), | |||||
error | |||||
end. | |||||
%%获取数据表的AUTO_INCREMENT字段的宽度 | |||||
get_auto_increment_width(TableName) -> | |||||
Sql = lists:concat(["show create table ", TableName]), | |||||
case db_esql:get_row(Sql) of | |||||
{db_error, _} -> | |||||
error; | |||||
[_, A | _] -> | |||||
CreateTableList = re:split(A, "[\n]", [{return, binary}]), | |||||
search_auto_increment(CreateTableList) | |||||
end. | |||||
%%设置AUTO_INCREMENT的值 | |||||
set_auto_increment_offset(TableName, Offset) -> | |||||
Sql = io_lib:format("alter table ~s auto_increment=~s;", [atom_to_list(TableName), integer_to_list(Offset)]), | |||||
case db_esql:execute_sql(Sql) of | |||||
{db_error, _} -> | |||||
false; | |||||
_Result -> | |||||
%io:format("Result: ~p~n", [Result]) | |||||
true | |||||
end. | |||||
%%搜索有没有含AUTO_INCRMENT字段的行 | |||||
%%如果没有,返回no_match | |||||
%%如果有: 搜索AUTO_INCREMENT行中"int(xx)"并返回xx的值, 没有返回no_match | |||||
search_auto_increment([]) -> | |||||
no_match; | |||||
search_auto_increment([L | T]) -> | |||||
Line = binary_to_list(L), | |||||
case re:run(Line, "AUTO_INCREMENT", [caseless]) of %%匹配AUTO_INCREMENT行 | |||||
{match, _} -> %%有 | |||||
search_int_width(Line); | |||||
_Other -> | |||||
search_auto_increment(T) | |||||
end. | |||||
%%搜索"int(xx)"并返回xx的值, 没有返回no_match | |||||
search_int_width(Line) -> | |||||
case re:run(Line, "int", [caseless]) of | |||||
{match, [{Idx1, L1} | _]} -> %%匹配上,Idx1, L1是"int"起始坏置及长度 | |||||
Idx = min(Idx1 + L1 + 1, length(Line)), | |||||
case lists:sublist(Line, Idx, 4) of %%取"(xx)"这一段, 最多取4字符 | |||||
[40, A, B, 41] -> %%40为"(", 41为")",长度为两数字 | |||||
list_to_integer([A, B]); | |||||
[40, A, 41] -> %%长度为1数字 | |||||
list_to_integer([A]); | |||||
_Other -> | |||||
no_match | |||||
end; | |||||
_Other -> | |||||
no_match | |||||
end. | |||||
@ -1,132 +0,0 @@ | |||||
%% Author: Richard Jones | |||||
%% Modified: bisonwu | |||||
%% Description: Takes a serialized php object and turns it into an erlang data structure | |||||
-module(php_parser). | |||||
%% | |||||
%% Include files | |||||
%% | |||||
%% | |||||
%% Exported Functions | |||||
%% | |||||
-export([unserialize/1]). | |||||
-export([serialize_map/1, serialize_map/2]). | |||||
%% | |||||
%% API Functions | |||||
%% | |||||
%% @spec serialize_map/1 | |||||
%% @doc serialize for key-value list | |||||
serialize_map(KeyValueList) when is_list(KeyValueList) -> | |||||
serialize_map(KeyValueList, {"i", "d"}). | |||||
%% @spec serialize_map/2 | |||||
%% @doc serialize for key-value list | |||||
%% result eg:"a:2:{i:7;d:1277086515;i:8;d:1277086522;}" | |||||
serialize_map(KeyValueList, {KeyType, ValType}) when is_list(KeyValueList) -> | |||||
%% eg:[{7,1277086515},{8,1277086522}] | |||||
Len = length(KeyValueList), | |||||
Items = lists:foldr(fun(X, Items) -> | |||||
{Key, Val} = X, | |||||
lists:concat([KeyType, ":", Key, ";", ValType, ":", Val, ";", Items]) | |||||
end, "", KeyValueList), | |||||
lists:concat(["a:", Len, ":{", Items, "}"]). | |||||
%% @spec unserialize/1 | |||||
%% Usage: {Result, Leftover} = php_parser:unserialize(…) | |||||
unserialize(S) when is_binary(S) -> unserialize(binary_to_list(S)); | |||||
unserialize(S) when is_list(S) -> takeval(S, 1). | |||||
% Internal stuff | |||||
takeval(Str, Num) -> | |||||
{Parsed, Remains} = takeval(Str, Num, []), | |||||
{lists:reverse(Parsed), Remains}. | |||||
takeval([$} | Leftover], 0, Acc) -> {Acc, Leftover}; | |||||
takeval(Str, 0, Acc) -> {Acc, Str}; | |||||
takeval([], 0, Acc) -> Acc; | |||||
takeval(Str, Num, Acc) -> | |||||
{Val, Rest} = phpval(Str), | |||||
%Lots of tracing if you enable this: | |||||
%io:format("\nState\n Str: ~s\n Num: ~w\n Acc:~w\n", [Str,Num,Acc]), | |||||
%io:format("-Val: ~w\n-Rest: ~s\n\n",[Val, Rest]), | |||||
takeval(Rest, Num - 1, [Val | Acc]). | |||||
% | |||||
% Parse induvidual php values. | |||||
% a "phpval" here is T:val; where T is the type code for int, object, array etc.. | |||||
% | |||||
% Simple ones: | |||||
phpval([]) -> []; | |||||
phpval([$} | Rest]) -> phpval(Rest); % skip } | |||||
phpval([$N, $; | Rest]) -> {null, Rest}; % null | |||||
phpval([$b, $:, $1, $; | Rest]) -> {true, Rest}; % true | |||||
phpval([$b, $:, $0, $; | Rest]) -> {false, Rest}; % false | |||||
% r seems to be a recursive reference to something, represented as an int. | |||||
phpval([$r, $: | Rest]) -> | |||||
{RefNum, [$; | Rest1]} = string:to_integer(Rest), | |||||
{{php_ref, RefNum}, Rest1}; | |||||
% int | |||||
phpval([$i, $: | Rest]) -> | |||||
{Num, [$; | Rest1]} = string:to_integer(Rest), | |||||
{Num, Rest1}; | |||||
% double / float | |||||
% NB: php floats can be ints, and string:to_float doesn’t like that. | |||||
phpval(_X = [$d, $: | Rest]) -> | |||||
{Num, [$; | Rest1]} = case string:to_float(Rest) of | |||||
{error, no_float} -> string:to_integer(Rest); | |||||
{N, R} -> {N, R} | |||||
end, | |||||
{Num, Rest1}; | |||||
% string | |||||
phpval([$s, $: | Rest]) -> | |||||
{Len, [$: | Rest1]} = string:to_integer(Rest), | |||||
S = list_to_binary(string:sub_string(Rest1, 2, Len + 1)), | |||||
{S, lists:nthtail(Len + 3, Rest1)}; | |||||
% array | |||||
phpval([$a, $: | Rest]) -> | |||||
{NumEntries, [$:, ${ | Rest1]} = string:to_integer(Rest), | |||||
{Array, Rest2} = takeval(Rest1, NumEntries * 2), | |||||
{arraytidy(Array), Rest2}; | |||||
% object O:4:\"User\":53:{ | |||||
phpval([$O, $: | Rest]) -> | |||||
{ClassnameLen, [$: | Rest1]} = string:to_integer(Rest), | |||||
% Rest1: "classname":NumEnt:{.. | |||||
Classname = string:sub_string(Rest1, 2, ClassnameLen + 1), | |||||
Rest1b = lists:nthtail(ClassnameLen + 3, Rest1), | |||||
{NumEntries, [$:, ${ | Rest2]} = string:to_integer(Rest1b), | |||||
{Classvals, Rest3} = takeval(Rest2, NumEntries * 2), | |||||
{{class, Classname, arraytidy(Classvals)}, Rest3}. | |||||
%% | |||||
%% Helpers: | |||||
%% | |||||
% convert [ k1,v1,k2,v2,k3,v3 ] into [ {k1,v2}, {k2,v2}, {k3,v3} ] | |||||
arraytidy(L) -> | |||||
lists:reverse(lists:foldl(fun arraytidy/2, [], L)). | |||||
arraytidy(El, [{key___partial, K} | L]) -> [{atomize(K), El} | L]; | |||||
arraytidy(El, L) -> [{key___partial, El} | L]. | |||||
%% Make properties or keys into atoms | |||||
atomize(K) when is_binary(K) -> | |||||
atomize(binary_to_list(K)); | |||||
atomize(K) when is_list(K) -> | |||||
list_to_atom(string:to_lower(K)); | |||||
atomize(K) -> K. |
@ -1,9 +1,2 @@ | |||||
%%%--------------------------------------------- | |||||
%%% @Module : robot_pet | |||||
%%% @Author : smxx | |||||
%%% @Created : 2013.03.xx | |||||
%%% @Description: 宠物客户端测试程序 | |||||
%%%--------------------------------------------- | |||||
-module(robot_pet). | -module(robot_pet). | ||||
%% -include("robot.hrl"). | |||||
%% -compile(export_all). | |||||
@ -1,247 +0,0 @@ | |||||
%% @author Administrator | |||||
%% @doc @todo Add description to task_data_checker. | |||||
-module(task_data_checker). | |||||
%% ==================================================================== | |||||
%% API functions | |||||
%% ==================================================================== | |||||
-export([]). | |||||
-compile(export_all). | |||||
-include("common.hrl"). | |||||
-include("table_to_record.hrl"). | |||||
-include("task.hrl"). | |||||
-define(CONFIG_FILE, "../config/gateway.config"). | |||||
-define(TMP_TABLE_PATH, "./tmptable/"). | |||||
-define(SRC_TABLE_PATH, "../src/table/"). | |||||
-define(BEAM_PATH, "./"). | |||||
-define(IOFILE(Str, Args), (fun() -> | |||||
Command = io_lib:format(Str, Args), | |||||
file:write_file("../logs/data/task_data.log", Command, [append]) | |||||
end)()). | |||||
-define(IOFILE(Str), (fun() -> | |||||
file:write_file("../logs/data/task_data.log", Str, [append]) | |||||
end)()). | |||||
%% ==================================================================== | |||||
%% Internal functions | |||||
%% ==================================================================== | |||||
start() -> | |||||
case table_to_erlang:get_db_config(?CONFIG_FILE) of | |||||
[Host, Port, User, Password, DB, Encode, _Conns] -> | |||||
table_to_erlang:start_erlydb(Host, Port, User, Password, DB), | |||||
mysql:start_link(?DB_SERVER, Host, Port, User, Password, DB, fun(_, _, _, _) -> ok end, Encode), | |||||
mysql:connect(?DB_SERVER, Host, Port, User, Password, DB, Encode, true), | |||||
start_check(), | |||||
ok; | |||||
_ -> mysql_config_fail | |||||
end, | |||||
halt(), | |||||
ok. | |||||
start_check() -> | |||||
?IOFILE("\n[信息]******************任务数据有效性检测开始********************** \n"), | |||||
?IOFILE("[信息]***************日期:~p 时间:~p******************* ~n", [date(), time()]), | |||||
F = fun(Task) -> | |||||
D = list_to_tuple([tpl_task | Task]), | |||||
TaskInfo = D#tpl_task{ | |||||
goods_list = util:bitstring_to_term(D#tpl_task.goods_list), | |||||
target_property = util:bitstring_to_term(D#tpl_task.target_property), | |||||
guild_goods_list = util:bitstring_to_term(D#tpl_task.guild_goods_list) | |||||
}, | |||||
check_interface(TaskInfo) | |||||
end, | |||||
Lists = db_esql:get_all("select * from temp_task;"), | |||||
lists:foreach(F, Lists), | |||||
?IOFILE("[信息]***************任务数据有效性检测结束******************* \n \n"). | |||||
check_interface(TaskInfo) -> | |||||
check_start_npc_scene(TaskInfo#tpl_task.start_npc, TaskInfo#tpl_task.start_scene, TaskInfo#tpl_task.tid), | |||||
check_end_npc_scene(TaskInfo#tpl_task.end_npc, TaskInfo#tpl_task.end_scene, TaskInfo#tpl_task.tid), | |||||
check_next_task(TaskInfo#tpl_task.next_tid, TaskInfo#tpl_task.tid), | |||||
check_pid_task(TaskInfo#tpl_task.pre_tid, TaskInfo#tpl_task.tid), | |||||
check_goods_list(TaskInfo#tpl_task.goods_list, TaskInfo#tpl_task.tid, "goods_list"), | |||||
check_goods_list(TaskInfo#tpl_task.goods_list, TaskInfo#tpl_task.tid, "guild_goods_list"), | |||||
check_target_pro(TaskInfo#tpl_task.target_type, TaskInfo#tpl_task.target_property, TaskInfo#tpl_task.pre_tid). | |||||
check_npc(NpcId, Type, Tid) -> | |||||
Sql = io_lib:format("select count(*) from temp_npc where nid = ~p;", [NpcId]), | |||||
case db_esql:get_all(Sql) of | |||||
[[0]] -> | |||||
?IOFILE("[错误]任务 task id -> ~p 中, ~p npc数据 npc id -> ~p 无效 ~n", [Tid, Type, NpcId]); | |||||
_ -> | |||||
skip | |||||
end. | |||||
check_scene(SceneId, Type, Tid) -> | |||||
Sql = io_lib:format("select count(*) from temp_scene where sid = ~p;", [SceneId]), | |||||
case db_esql:get_all(Sql) of | |||||
[[0]] -> | |||||
?IOFILE("[错误]任务 task id -> ~p 中, ~p场景数据 id -> ~p 无效 ~n", [Tid, Type, SceneId]); | |||||
_ -> | |||||
skip | |||||
end. | |||||
check_start_npc_scene(NpcId, SceneId, Tid) -> | |||||
if NpcId =:= 0 -> | |||||
skip; | |||||
true -> | |||||
check_npc(NpcId, "开始", Tid), | |||||
check_scene(SceneId, "开始", Tid), | |||||
Sql = io_lib:format("select count(*) from temp_npc_layout where scene_id = ~p and npcid = ~p;", [SceneId, NpcId]), | |||||
case db_esql:get_all(Sql) of | |||||
[[0]] -> | |||||
?IOFILE("[警告]任务 task id -> ~p 中,任务开始场景id -> ~p 与 任务开始npc id -> ~p 不匹配(可能是跨地图任务,同事们自己留意下)~n", [Tid, SceneId, NpcId]); | |||||
_ -> skip | |||||
end | |||||
end. | |||||
check_end_npc_scene(NpcId, SceneId, Tid) -> | |||||
if NpcId =:= 0 -> | |||||
skip; | |||||
true -> | |||||
check_npc(NpcId, "结束", Tid), | |||||
check_scene(SceneId, "结束", Tid), | |||||
Sql = io_lib:format("select count(*) from temp_npc_layout where scene_id = ~p and npcid = ~p;", [SceneId, NpcId]), | |||||
case db_esql:get_all(Sql) of | |||||
[[0]] -> | |||||
?IOFILE("[错误]任务 task id -> ~p 中,任务结束场景id -> ~p 与 任务结束npc id -> ~p 不匹配 ~n", [Tid, SceneId, NpcId]); | |||||
_ -> skip | |||||
end | |||||
end. | |||||
check_next_task(NextTid, Tid) -> | |||||
if NextTid =:= -1 -> | |||||
skip; | |||||
true -> | |||||
case NextTid =< Tid of | |||||
true -> | |||||
?IOFILE("[错误]任务 task id -> ~p 中,后置任务 id -> ~p 必须比本任务id大 ~n", [Tid, NextTid]); | |||||
false -> | |||||
Sql = io_lib:format("select count(*) from temp_task where tid = ~p;", [NextTid]), | |||||
case db_esql:get_all(Sql) of | |||||
[[0]] -> | |||||
?IOFILE("[错误]任务 task id -> ~p 中,后置任务 id -> ~p 无效~n", [Tid, NextTid]); | |||||
_ -> skip | |||||
end | |||||
end | |||||
end. | |||||
check_pid_task(PerTid, Tid) -> | |||||
if PerTid =:= -1 -> | |||||
skip; | |||||
true -> | |||||
case PerTid >= Tid of | |||||
true -> | |||||
?IOFILE("[错误]任务 task id -> ~p 中, 前置任务 id -> ~p 必须比本任务id小 ~n", [Tid, PerTid]); | |||||
false -> | |||||
Sql = io_lib:format("select count(*) from temp_task where tid = ~p;", [PerTid]), | |||||
case db_esql:get_all(Sql) of | |||||
[[0]] -> | |||||
?IOFILE("[错误]任务 task id -> ~p 中,前置任务 id -> ~p 无效 ~n", [Tid, PerTid]); | |||||
_ -> skip | |||||
end | |||||
end | |||||
end. | |||||
check_goods_list(GoodsList, Tid, Type) -> | |||||
F = fun({_, _, Gid, _}) -> | |||||
Sql = io_lib:format("select count(*) from temp_goods where gtid = ~p;", [Gid]), | |||||
case db_esql:get_all(Sql) of | |||||
[[0]] -> | |||||
?IOFILE("[错误]任务 task id -> ~p 中,任务奖励物品 id -> ~p 无效 ,具体见字段: ~p ~n", [Tid, Gid, Type]); | |||||
_ -> skip | |||||
end | |||||
end, | |||||
lists:foreach(F, GoodsList). | |||||
check_target_pro(?NPC_TALK_EVENT, TaskPro, Tid) -> | |||||
case TaskPro of | |||||
[{NpcId}] -> | |||||
Sql = io_lib:format("select count(*) from temp_npc where nid = ~p;", [NpcId]), | |||||
case db_esql:get_all(Sql) of | |||||
[[0]] -> | |||||
?IOFILE("[错误]对话任务 task id -> ~p 中,目标npc -> ~p 无效,具体见字段 target_property ~n", [Tid, NpcId]); | |||||
_ -> skip | |||||
end; | |||||
_ -> | |||||
?IOFILE("[错误]任务 task id -> ~p 中,字段 target_property 格式有误 ~n", [Tid]) | |||||
end; | |||||
check_target_pro(?KILL_EVENT, TaskPro, Tid) -> | |||||
case TaskPro of | |||||
[{MonId, _, 0}] -> | |||||
Sql = io_lib:format("select count(*) from temp_npc where nid = ~p;", [MonId]), | |||||
case db_esql:get_all(Sql) of | |||||
[[0]] -> | |||||
?IOFILE("[错误]杀怪任务 task id -> ~p 中,怪物数据 monster id -> ~p 无效,具体见字段 target_property ~n", [Tid, MonId]); | |||||
_ -> skip | |||||
end; | |||||
_ -> | |||||
?IOFILE("[错误]任务 task id -> ~p 中,字段 target_property 格式有误 ~n", [Tid]) | |||||
end; | |||||
check_target_pro(?COLLECT_EVENT, TaskPro, Tid) -> | |||||
case TaskPro of | |||||
[{ItemId, _, 0}] -> | |||||
Sql = io_lib:format("select count(*) from temp_npc where nid = ~p;", [ItemId]), | |||||
case db_esql:get_all(Sql) of | |||||
[[0]] -> | |||||
?IOFILE("[错误]采集任务 task id -> ~p 中, 采集物数据 item id -> ~p 无效,具体见字段 target_property ~n", [Tid, ItemId]); | |||||
_ -> | |||||
skip | |||||
end; | |||||
_ -> | |||||
?IOFILE("[错误]任务 task id -> ~p 中,字段 target_property 格式有误 ~n", [Tid]) | |||||
end; | |||||
check_target_pro(?NPC_GOODS_EVENT, TaskPro, Tid) -> | |||||
case TaskPro of | |||||
[{NpcId, ItemId, _, 0}] -> | |||||
do_check_npc_shop_item(ItemId, Tid), | |||||
do_check_npc_shop_npc(NpcId, Tid), | |||||
do_check_npc_shop_data(NpcId, ItemId, Tid); | |||||
_ -> | |||||
?IOFILE("[错误]任务 task id -> ~p 中,字段 target_property 格式有误 ~n", [Tid]) | |||||
end; | |||||
check_target_pro(ERR1, Err2, Err3) -> | |||||
io:format("[ERROR]param of check_target_pro err ~p ~n", [{ERR1, Err2, Err3}]). | |||||
do_check_npc_shop_item(ItemId, Tid) -> | |||||
Sql = io_lib:format("select count(*) from temp_goods where gtid = ~p;", [ItemId]), | |||||
case db_esql:get_all(Sql) of | |||||
[[0]] -> | |||||
?IOFILE("[错误]npc购物任务 task id -> ~p 中, 商品数据 item id -> ~p 无效,具体见字段 target_property ~n", [Tid, ItemId]); | |||||
_ -> | |||||
skip | |||||
end. | |||||
do_check_npc_shop_npc(NpcId, Tid) -> | |||||
Sql = io_lib:format("select count(*) from temp_npc where nid = ~p;", [NpcId]), | |||||
case db_esql:get_all(Sql) of | |||||
[[0]] -> | |||||
?IOFILE("[错误]npc购物任务 task id -> ~p 中, npc数据 npc id -> ~p 无效,具体见字段 target_property ~n", [Tid, NpcId]); | |||||
_ -> | |||||
skip | |||||
end. | |||||
do_check_npc_shop_data(NpcId, ItemId, Tid) -> | |||||
Sql = io_lib:format("select shop_goods from temp_npc_shop where shop_id = ~p;", [NpcId]), | |||||
case db_esql:get_all(Sql) of | |||||
[] -> | |||||
?IOFILE("[错误]npc购物任务 task id -> ~p 中, npc数据 npc id -> ~p 没有商品,具体见 temp_npc_shop表 ~n", [Tid, NpcId]); | |||||
Data -> | |||||
ResultList = lists:map(fun(ShopGoos) -> | |||||
do_check_npc_shop_npc_item(ItemId, ShopGoos) | |||||
end, Data), | |||||
case lists:member(true, ResultList) of | |||||
true -> skip; | |||||
false -> | |||||
?IOFILE("[错误]npc购物任务 task id -> ~p 中, npc数据 npc id -> ~p 没有商品 item id -> ~p,具体见 temp_npc_shop表 ~n", [Tid, NpcId, ItemId]) | |||||
end | |||||
end. | |||||
do_check_npc_shop_npc_item(ItemId, ShopGoos) -> | |||||
NewShopGoods = util:bitstring_to_term(ShopGoos), | |||||
case lists:keyfind(ItemId, 1, NewShopGoods) of | |||||
false -> false; | |||||
_ -> true | |||||
end. |