@ -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) -> | |||
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). | |||
%% -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. |