- 论坛徽章:
- 1
|
主要逻辑处理:也就是 GameClient.pm
- package GameClient;
- our ($VERSION) = q$Revision: 78 $ =~ /(\d+)/;
- use strict;
- use warnings;
- use JzCrypt;
- use JzCompress;
- use Data::HexDump;
- use Data::Dumper;
- use POE;
- use Time::HiRes qw(usleep);
- our @ddClassCode = qw(格斗家 魔法师 剑士 枪手);
- our @ddGenderCode = qw(男 女);
- our @ddNpcTypeCode = qw(怪物 NPC 门 守卫 移动守卫 工会NPC 工会守卫 工会特殊 工会门);
- our @ddSystemMsgTypeCode = qw(特殊 一般 错误 NPC 通知 断线);
- our @ddChatTypeCode = qw(普通聊天 悄悄话 喊叫 军团聊天 好友聊天 好友邀请 好友分手);
- our $ddItemInfo = {};
- our $Debug = 1;
- use constant SM_BASE => 0x8000;
- use constant SM_LOGIN_REQ => SM_BASE + 0;
- use constant SM_LOGIN_ACK => SM_BASE + 1;
- use constant SM_GAME_REQ => SM_BASE + 12;
- use constant SM_GAME_ACK => SM_BASE + 13;
- use constant SM_CONNECTINFO_ACK => SM_BASE + 100;
- use constant SM_GAMESERVER_CONNECT_REQ => SM_BASE + 502; # 81F6
- use constant SM_GAMESERVER_CONNECT_ACK => SM_BASE + 503; # 81F7
- use constant CI_ACCOUNT_LOGIN_REQ => 0x0C;
- use constant CI_ACCOUNT_LOGIN_ACK => 0x0D;
- use constant CI_DISCONNECT_REQ => 0xEB;
- use constant CI_DISCONNECT_ACK => 0xEB; # 注意这里响应和请求是同一个编码
- use constant CI_PUBLIC_KEY_REQ => 0xD5;
- use constant CI_PUBLIC_KEY_ACK => 0xD6;
- use constant CI_CRYPT_PACKET => 0xF9;
- use constant ZS_COMPRESS_PACKET => 0xC1;
- use constant ZS_USER_INFO => 1;
- use constant ZS_CHAR_INFO => 2;
- use constant ZS_NPC_INFO => 3;
- use constant ZS_SYSTEM_MSG => 5;
- use constant ZS_WEATHER_CHANGE => 7;
- use constant ZS_FIELD_ITEM_INFO => 58;
- use constant ZS_USER_STATUS_UPDATE => 79;
- use constant ZS_GAME_START_REQ => 14;
- use constant ZS_GAME_START_ACK => 15;
- use constant ZS_MOVE_FIRST_ACK => 91;
- use constant ZS_MOVE_REQ => 92;
- use constant ZS_MOVE_ACK => 93;
- use constant ZS_MOVE_END_ACK => 95;
- use constant ZS_SET_EXP => 76;
- use constant ZS_SET_SP => 102;
- use constant ZS_SET_HP => 107;
- use constant ZS_RUN_FIRST_REQ => 96;
- use constant ZS_RUN_FIRST_ACK => 97;
- use constant ZS_RUN_REQ => 98;
- use constant ZS_RUN_ACK => 99;
- use constant ZS_CHAT_RESULT => 31;
- use constant ZS_ATTACK_REQ => 111;
- use constant ZS_ATTACK_ACK => 112;
- use constant ZS_DEAD_ACK => 113;
- use constant ZS_ITEM_USE_REQ => 55;
- use constant ZS_ITEM_USE_ACK => 56;
- use constant ZS_USE_POSTION_NOTICE => 119;
- use constant MAC => '00.13.CE.1B.0C.11';
- our %gSMPacketID = (
- SM_LOGIN_ACK() => [ '登录响应', \&LoginAck ],
- SM_CONNECTINFO_ACK() => [ '连接信息', \&ConnectInfoAck ],
- SM_GAMESERVER_CONNECT_ACK() => [ '连接游戏应答', \&GameServerConnectAck ],
- );
- our %gCIPacketID = (
- CI_PUBLIC_KEY_REQ() => [ '请求公钥', undef ],
- CI_PUBLIC_KEY_ACK() => [ '公钥响应', \&PublicKeyAck ],
- CI_ACCOUNT_LOGIN_ACK() => [ '帐户登录结果', \&CIAccountLoginAck ],
- CI_DISCONNECT_ACK() => [ '断开角色服务器响应', \&CIServerDisconnectAck ],
- ZS_GAME_START_ACK() => [ '进入游戏响应', \&GameStartAck ],
- ZS_MOVE_FIRST_ACK() => [ ' NPC 或玩家开始移动信息', \&MoveAck ],
- ZS_MOVE_ACK() => [ ' NPC 或玩家移动信息', \&MoveAck ],
- ZS_MOVE_END_ACK() => [ ' NPC 或玩家终止移动信息', \&MoveAck ],
- ZS_SYSTEM_MSG() => [ '系统消息', \&SystemMsg ],
- ZS_WEATHER_CHANGE() => [ '天气变化', \&WeatherChange ],
- ZS_USER_STATUS_UPDATE() => [ '玩家状态变化信息', \&UserStatusUpdate ],
- ZS_USER_INFO() => [ '玩家信息通知', \&UserInfo ],
- ZS_CHAR_INFO() => [ '人物信息通知', \&CharInfo ],
- ZS_NPC_INFO() => [ ' NPC 信息通知信息', \&NpcInfo ],
- ZS_ATTACK_ACK() => [ '攻击响应', \&AttackAck ],
- ZS_DEAD_ACK() => [ '死亡通知', \&DeadAck ],
-
- ZS_SET_HP() => [ '生命变化通知', \&SetHP ],
- ZS_SET_EXP() => [ '经验值变化通知', \&SetExp ],
- ZS_SET_SP() => [ '体力变化通知', \&SetSP ],
- ZS_FIELD_ITEM_INFO() => [ '地图物品信息通知', \&FieldItemInfo ],
- ZS_ITEM_USE_ACK() => [ '使用物品响应', \&ItemUseAck ],
- ZS_USE_POSTION_NOTICE() => [ '服用药物通知', \&UsePotionNotice ],
- ZS_RUN_FIRST_ACK() => [ '开始跑动响应', \&RunAck ],
- ZS_RUN_ACK() => [ '跑动响应', \&RunAck ],
- ZS_CHAT_RESULT() => [ '聊天消息', \&ChatResult ],
- );
- our $Kernel;
- sub new {
- my $class = shift;
- $class = ref $class || $class;
- my $session = shift;
- my $itemDB = shift;
- if ( ref $session ne 'POE::Session' ){
- return undef;
- }
- *Kernel = \$main::poe_kernel;
- return bless {
- session => $session,
- heap => $session->get_heap(),
- state => '游戏启动',
- main_state => '游戏启动',
- online => 0,
- send_req => 1,
- }, $class;
- }
- sub SMPacketType {
- my $self = shift;
- my $data = shift;
- (my $id, $data) = unpack( 'Sa*', $data );
- if ( exists $gSMPacketID{$id} ){
- return ($gSMPacketID{$id}->[0], $id, $data);
- }
- else{
- return (undef,$id,$data);
- }
- }
- sub SMParse {
- my $self = shift;
- my ($id, $data) = @_;
- if ( exists $gSMPacketID{$id}
- and ref $gSMPacketID{$id}->[1] eq 'CODE' ){
- $gSMPacketID{$id}->[1]->( $self, $data );
- }
- }
- sub CIPacketType {
- my $self = shift;
- my $data = shift;
- (my $id, $data) = unpack( 'Ca*', $data );
- if ( $id == CI_CRYPT_PACKET ){
- $self->logmsg( '接收到加密报文,自动解密……' ) if not $self->{online};
- my $len = length($data);
- my $out = ' ' x $len;
- $JzDecryptionFast->Call( $len, $data, $out );
- (my $seq, $data) = unpack( 'i a*', $out );
- $self->logmsg( "报文已解密。包序号:[$seq]。" ) if not $self->{online};
- ($id, $data) = unpack( 'Ca*', $data );
- if ( $id == ZS_COMPRESS_PACKET ){
- $self->logmsg( '接收到压缩报文,自动解压……' ) if not $self->{online};
- $out = UnCompress( $data );
- if ( not defined $out ){
- $self->logmsg( '解压失败。' );
- return (undef, $id, $data);
- }
- $self->logmsg( sprintf "报文已解压。长度: [%d]。", length($out) ) if not $self->{online};
- ($id, $data) = unpack( 'Ca*', $out );
- }
- }
- if ( exists $gCIPacketID{$id} ){
- return ($gCIPacketID{$id}->[0], $id, $data);
- }
- else{
- return (undef,$id,$data);
- }
- }
- sub CIParse {
- my $self = shift;
- my ($id, $data) = @_;
- if ( exists $gCIPacketID{$id}
- and ref $gCIPacketID{$id}->[1] eq 'CODE' ){
- $gCIPacketID{$id}->[1]->( $self, $data );
- }
- }
- sub Login {
- my $self = shift;
- return if @_ < 2;
- my ($id, $passwd) = @_;
- return if $id eq '';
- return if $passwd eq '';
- $self->{sm_wheel}->put( pack( 'ss/a*', SM_LOGIN_REQ,
- pack( 's/a*', $id )
- . pack( 's/a*', $passwd )
- . pack( 's/a*', MAC ) ) );
- $self->{userInfo}->{name} = $id;
- $self->{userInfo}->{passwd} = $passwd;
- $self->{main_state} = '连线 Session Manager Server';
- $self->{state} = '正在登录';
- $self->logmsg( "已发送登录请求。" );
- }
- sub LoginAck {
- my $self = shift;
- my $data = shift;
- my $retcode = unpack( 's/a*', $data );
- if ( $retcode eq '' ){
- $self->logmsg( "登录失败,错误代码不明,重试一下。" );
- return $self->Login( $self->{userInfo}{name}, $self->{userInfo}{passwd} );
- }
- $retcode = ord( $retcode );
- if ( $retcode != 0 ){
- my %errmsg = (
- 1 => '用户名不存在',
- 2 => '用户名不存在',
- 3 => '重复的连接',
- 4 => '帐户已过期',
- 5 => '数据库操作失败',
- 6 => '帐户无效',
- 7 => '密码错误',
- );
- # XXX: 退出或重试。
- $self->exitmsg( "登录失败,错误代码:[$retcode] 错误信息:[$errmsg{$retcode}]。" );
- }
- $self->{state} = '登录成功';
- $self->logmsg( "登录成功。" );
- $self->SMStartGame(0,1);
- }
- sub SMStartGame {
- my $self = shift;
- my ($serverNo, $flag) = @_;
- $self->{sm_wheel}->put( pack( 'ss/a*', SM_GAME_REQ, pack( 'ic', $serverNo, $flag ) ) );
- $self->{state} = '开始游戏';
- $self->logmsg( "已发送开始游戏请求。" );
- }
- sub ConnectInfoAck {
- my $self = shift;
- my $data = shift;
- ($data) = unpack( 's/a*', $data );
- (my ($strUserID, $count), $data) = unpack( 's/a*ca*', $data );
- $self->dbgmsg( "用户名: [$strUserID] 服务器个数: [$count]" );
- my @serverInfo = unpack( 's/a*s' x $count, $data );
- for( my $i=0; $i<@serverInfo; $i+=2 ){
- my ($IP, $Port) = @serverInfo[$i, $i+1];
- $self->dbgmsg( "IP: [$IP] Port: [$Port]" );
- }
- my ($IP, $Port) = @serverInfo;
- $self->{state} = '正在连接';
- $self->{main_state} = '连线 CharInfoServer';
- $self->logmsg( '正在连接 CharInfoServer ……' );
- $self->{heap}->{socket} = POE::Wheel::SocketFactory->new(
- RemoteAddress => $IP,
- RemotePort => $Port,
- SuccessEvent => 'charinfo_connected',
- FailureEvent => 'sock_error',
- );
- }
- sub GetPublicKey {
- my $self = shift;
- my $type = shift;
- if ( not grep { $type == $_ } (0,1,2) ){
- $self->exitmsg( "类型错误。参数给出的类型是 [$type], 但可选值是 [0,1,2]" );
- }
- $self->{wheel}->put( pack( 'ss/a*s', 0x55aa,
- pack( 'CC', CI_PUBLIC_KEY_REQ, $type ),
- 0xaa55 ) );
- $self->{public_key_type} = $type;
- $self->{state} = '请求公钥';
- $self->logmsg( '正在请求加密公钥……' );
- }
- sub PublicKeyAck {
- my $self = shift;
- my $data = shift;
- my ($key, $type) = unpack( 'a8c', $data );
- $self->dbgmsg( '公钥: ' . unpack( 'H*', $key ) );
- if ( $type != $self->{public_key_type} ){
- $self->exitmsg( sprintf( "公钥类型不对。期望值: [%x] 实际得到: [%x]", $self->{public_key_type}, $type ) );
- }
- $self->{public_key} = $key;
- $self->{state} = '得到公钥';
- $JzSetPublicKey->Call( $key );
- $self->logmsg( '已经获得加密公钥。' );
- if ( $self->{main_state} eq '连线 CharInfoServer' ){
- $self->CIAccountLogin();
- }
- elsif ( $self->{main_state} eq '连线 ZoneServer' ){
- $self->GameStart(1,0);
- }
- else{
- $self->exitmsg( '程序状态出错。' );
- }
- }
- sub SendCryptPack {
- my $self = shift;
- my ($wheel, $data) = @_;
- $data = pack( 'ia*', $self->{send_req}++, $data );
- my $len = length($data);
- my $crypt_data = ' ' x $len;
- $JzEncryptionFast->Call( $len, $data, $crypt_data );
- my $packet = pack( 'ss/a*s', 0x55aa,
- pack( 'Ca*', CI_CRYPT_PACKET, $crypt_data ),
- 0xaa55 );
- $wheel->put( $packet );
- }
- sub CIAccountLogin {
- my $self = shift;
- my $data = pack( 'cc/a*sa4', CI_ACCOUNT_LOGIN_REQ, $self->{userInfo}->{name}, 1, '' );
- $self->SendCryptPack( $self->{wheel}, $data );
- $self->{state} = '登录游戏';
- $self->logmsg( '已发送登录游戏请求。' );
- }
- sub CIAccountLoginAck {
- my $self = shift;
- my $data = shift;
- ( my ($result, $retcode), $data ) = unpack( 'c c a*', $data );
- if ( $result != 1 ){
- my %errmsg = (
- 1 => 'ID 错误',
- 2 => '未知错误',
- );
- # XXX: 退出或重试。
- $self->exitmsg( "登录游戏失败!错误代码: [$retcode] 错误信息: [$errmsg{$retcode}]" );
- }
- my @packFormat = (
- { charID => 'c' },
- { name => 'c/A*' },
- { STR => 's' },
- { CON => 's' },
- { DEX => 's' },
- { VOL => 's' },
- { WIS => 's' },
- { skin => 'i' },
- { hair => 'i' },
- { gender => 'c' },
- { face => 'a10' },
- { class => 'c' },
- { level => 's' },
- { HP => 's' },
- { PP => 's' },
- { SP => 's' },
- { MaxHP => 's' },
- { MaxPP => 's' },
- { MaxSP => 's' },
- { skillStr => 'a60' },
- { wearItemStr => 'a28' },
- { serverIP => 'c/A*' },
- { serverPort => 's' },
- );
- my %charInfo;
- my $format = join '', map{ (values %$_)[0] } @packFormat;
- @charInfo{ map{ (keys %$_)[0] } @packFormat } = unpack( $format, $data );
- $charInfo{face} = unpack( 'H*', $charInfo{face} );
- while( ( my $item = substr( $charInfo{wearItemStr}, 0, 2, '' ) ) ne '' ){
- push @{$charInfo{wearItems}}, [ unpack( 's', $item ) ];
- }
- delete $charInfo{wearItemStr};
- while( ( my $skill = substr( $charInfo{skillStr}, 0, 3, '' ) ) ne '' ){
- push @{$charInfo{skills}}, [ unpack( 'sc', $skill ) ];
- }
- delete $charInfo{skillStr};
- $charInfo{className} = $ddClassCode[$charInfo{class}];
- $charInfo{genderName} = $ddGenderCode[$charInfo{gender}];
- $self->{state} = '登录成功';
- # 在这里打印出友好的信息。
- $self->logmsg( "登录成功。角色信息:\n" . '='x79 . "\n"
- . "角色: [$charInfo{name}] 性别: [$charInfo{genderName}] 职业: [$charInfo{className}] 级别: [$charInfo{level}]\n"
- . "力量: [$charInfo{STR}] 体质: [$charInfo{CON}] 敏捷: [$charInfo{DEX}] 智慧: [$charInfo{VOL}] 智力: [$charInfo{WIS}]\n"
- . "生命: [$charInfo{HP}/$charInfo{MaxHP}] 精神: [$charInfo{PP}/$charInfo{MaxPP}] 体力: [$charInfo{SP}/$charInfo{MaxSP}]"
- . "\n" . '='x79 );
- $self->{zs_ip} = $charInfo{serverIP};
- $self->{zs_port} = $charInfo{serverPort};
- delete $charInfo{serverIP};
- delete $charInfo{serverPort};
- $self->{userInfo}->{chars}->{$charInfo{charID}} = \%charInfo;
- $self->CIServerDisconnect();
- }
- sub CIServerDisconnect {
- my $self = shift;
- my $data = pack( 'C', CI_DISCONNECT_REQ );
- $self->SendCryptPack( $self->{wheel}, $data );
- $self->{state} = '断开连接';
- $self->logmsg( '已发送断开角色服务器请求。' );
- }
- sub CIServerDisconnectAck {
- my $self = shift;
- $self->{state} = '断开连接';
- $self->logmsg( '断开角色服务器' );
- delete $self->{wheel};
- delete $self->{heap}->{wheel};
- delete $self->{heap}->{socket};
- $self->{main_state} = '连线 ZoneServer';
- $self->{state} = '进入游戏';
- $self->logmsg( "正在连接 ZoneServer ……" );
- $self->{heap}->{socket} = POE::Wheel::SocketFactory->new(
- RemoteAddress => $self->{zs_ip},
- RemotePort => $self->{zs_port},
- SuccessEvent => 'zoneserver_connected',
- FailureEvent => 'sock_error',
- );
- }
- sub GameStart {
- my $self = shift;
- my ($serverID, $charID) = @_;
- $self->{charID} = $charID;
- $self->{charInfo} = $self->{userInfo}->{chars}->{$self->{charID}};
- my $data = pack( 'C c/a* s c/a*', ZS_GAME_START_REQ, $self->{userInfo}{chars}{$charID}{name}, $serverID, $self->{userInfo}{name} );
- $self->SendCryptPack( $self->{wheel}, $data );
- $self->{state} = '进入游戏';
- $self->logmsg( '已发送进入游戏请求。' );
- }
- sub GameStartAck {
- my $self = shift;
- my $data = shift;
- my $result = substr( $data, 0, 1, '' );
- if ( $result ne "\x01" ){
- my $retcode = substr( $data, 0, 1 );
- $self->exitmsg( sprintf "进入游戏失败。错误代码是:[0x%02X:%d]", ord($retcode), ord($retcode) );
- }
- # 已经成功进入游戏,可以断开 Session Manager Server 连接。
- delete $self->{sm_wheel};
- delete $self->{heap}->{sm_wheel};
- delete $self->{heap}->{sm_socket};
- $self->logmsg( '断开 Session Manager Server。' );
- my ($zone, $uid, $posX, $posY, $dir, $gameHour, $gameMin) = unpack( 's i s s c c c', $data );
- $self->{charInfo}->{uid} = $uid;
- $self->{charInfo}->{x} = $posX;
- $self->{charInfo}->{y} = $posY;
- $self->{charInfo}->{dir} = $dir;
- $self->{gameHour} = $gameHour;
- $self->{gameMin} = $gameMin;
- $self->{main_state} = '在线';
- $self->{state} = '普通在线';
- $self->{online} = 1;
- $self->logmsg( "已进入游戏。" );
- $self->logmsg( "位置:[$posX, $posY]; 面向:[$dir]; 游戏时间:[$gameHour 点 $gameMin 分]" );
- # 现在人物已经站在地图上了。
- # 先吃药,补满生命值。
- $self->TakeMedicineIfPossible();
- # XXX: 接下来开始打怪。
- $self->{curTask} = '打怪';
- $self->{charInfo}{attackRange} = 3;
- # 启动打怪线程
- $self->{attack_session} = POE::Session->create(
- inline_states => {
- _start => \&attack_start,
- attack_loop => \&attack_loop,
- add_attack_obj => \&add_attack_obj,
- del_attack_obj => \&del_attack_obj,
- _stop => \&attack_stop,
- },
- args => [ $self ],
- );
- }
- sub MoveAck {
- my $self = shift;
- my $data = shift;
- my $result = substr( $data, 0, 1, '' );
- if ( $result ne "\x01" ){
- return;
- }
- my ($uid, $x, $y) = unpack( 'iss', $data );
- if ( $uid == $self->{charInfo}{uid} ){
- $self->{charInfo}{x} = $x;
- $self->{charInfo}{y} = $y;
- if ( $self->{curTask} eq '打怪' ){
- if( $self->foundMonsterToAttack(0) ){
- $self->{state} = '普通在线';
- delete $self->{move_points};
- return;
- }
- }
- usleep(1000 * 300);
- $self->ContinueMove();
- }
- # XXX: 根据 UID 来判断是怪物还是玩家,不科学。
- return if $uid < 20000;
- $self->{npcinfo}{$uid}{x} = $x;
- $self->{npcinfo}{$uid}{y} = $y;
- }
- sub NpcInfo {
- my $self = shift;
- my $data = shift;
- (my ($mode, $nid), $data) = unpack( 'c s a*', $data );
- if ( $mode == 2 ){
- $self->logmsg( "$nid 嗖~地一声消失了……" );
- delete $self->{npcinfo}{$nid};
- return;
- }
- my ($pid, $name, $x, $y, $state, $type, $MaxHP, $HP, $speed, $color, $rest)
- = unpack( 's c/A* s s c c s s x8 s c a*', $data );
- my $questSay;
- if ( $type == 8 ){
- $questSay = unpack( 'x4 s', $rest );
- }
- else{
- $questSay = unpack( 's', $rest );
- }
- my $typeName = $ddNpcTypeCode[$type];
- $self->logmsg( "发现了一个$typeName,名称 [$name] HP [$HP] 位置 [$x,$y]" );
- $self->{npcinfo}{$nid} = {
- name => $name,
- x => $x,
- y => $y,
- };
- my $total = keys %{$self->{npcinfo}};
- $self->dbgmsg( "有 $total 个怪物信息。" );
- }
- sub SystemMsg {
- my $self = shift;
- my $data = shift;
- my ($type, $msg) = unpack( 'c c/A*', $data );
- my $typeName = $ddSystemMsgTypeCode[ $type ];
- $self->logmsg( "接收到$typeName消息: [$msg]" );
- }
- sub WeatherChange {
- my $self = shift;
- my $data = shift;
- my ($type, $value) = unpack( 'cc', $data );
- if ( $type == 1 ){
- $self->logmsg( "$value 点了。" );
- }
- elsif ( $type == 2 ){
- if ( $value ){
- $self->logmsg( '下雨了。' );
- }
- else{
- $self->logmsg( '雨停了。' );
- }
- }
- }
- sub UserStatusUpdate {
- my $self = shift;
- my $data = shift;
- my @packFormat = (
- { PA => 's' },
- { STR => 's' },
- { CON => 's' },
- { DEX => 's' },
- { VOL => 's' },
- { WIS => 's' },
- { HP => 's' },
- { PP => 's' },
- { SP => 's' },
- { MaxHP => 's' },
- { MaxPP => 's' },
- { MaxSP => 's' },
- { Damage => 's' },
- { Defense => 's' },
- { skillPoint=> 's' },
- { skillClass=> 'c' },
- { skillStr => 'a15' },
- );
- my %charInfo;
- my $format = join '', map{ (values %$_)[0] } @packFormat;
- @charInfo{ map{ (keys %$_)[0] } @packFormat } = unpack( $format, $data );
- while( ( my $skill = substr( $charInfo{skillStr}, 0, 3, '' ) ) ne '' ){
- push @{$charInfo{skills}}, [ unpack( 'sc', $skill ) ];
- }
- delete $charInfo{skillStr};
- my @keys = qw(PA STR CON DEX VOL WIS HP PP SP MaxHP MaxPP MaxSP Damage Defense skillPoint);
- foreach my $key (@keys){
- $self->{charInfo}->{$key} = $charInfo{$key};
- }
- # TODO: 需要继续单独处理一下 SkillClass and skillStr
- }
- sub UserInfo {
- my $self = shift;
- my $data = shift;
- (my ($mode, $uid), $data) = unpack( 'C I a*', $data );
- if ( $mode == 2 ){
- $self->logmsg( "$uid 嗖~地一声消失了。" );
- return;
- }
- my @packFormat = (
- { name => 'c/A*' },
- { x => 's' },
- { y => 's' },
- { skin => 'i' },
- { hair => 'i' },
- { gender => 'c' },
- { face => 'a10' },
- { equipItem => 'a20' },
- { HP => 's' },
- { MaxHP => 's' },
- { dir => 'c' },
- { abnormal => 'i' },
- { cityRank => 's' },
- { guildIndex => 'i' },
- { guildName => 'c/A*' },
- { version => 's' },
- { class => 'c' },
- { killState => 'c' },
- { loveName => 'c/A*' },
- { ebodyItem => 'a8' },
- );
- my %userInfo;
- my $format = join '', map{ (values %$_)[0] } @packFormat;
- @userInfo{ map{ (keys %$_)[0] } @packFormat } = unpack( $format, $data );
- $self->logmsg( "接收到人物 $userInfo{name} 的概要信息。" );
- if ( $uid == $self->{charInfo}->{uid} ){
- my @keys = qw(name x y equipItem HP MaxHP dir cityRank guildIndex guildName class loveName ebodyItem);
- foreach my $key (@keys){
- $self->{charInfo}->{$key} = $userInfo{$key};
- }
- }
- else {
- $self->{npcinfo}{$uid} = {
- name => $userInfo{name},
- x => $userInfo{x},
- y => $userInfo{y},
- };
- }
- }
- sub CharInfo {
- my $self = shift;
- my $data = shift;
- my @packFormat = (
- { name => 'c/A*' },
- { STR => 'S' },
- { CON => 'S' },
- { DEX => 'S' },
- { VOL => 'S' },
- { WIS => 'S' },
- { abilitySum=> 'S' },
- { skin => 'I' },
- { hair => 'I' },
- { gender => 'c' },
- { face => 'a10' },
- { Exp => 'I' },
- { XP => 'I' },
- { skillPoint=> 'S' },
- { PA => 'S' },
- { MaxHP => 'S' },
- { HP => 'S' },
- { MaxPP => 'S' },
- { PP => 'S' },
- { MaxSP => 'S' },
- { SP => 'S' },
- { DN => 'I' },
- { cityRank => 'S' },
- { level => 'S' },
- { class => 'C' },
- { skillStr => 'a60' },
- { havePsi => 'C' },
- );
- my %charInfo;
- my $format = join '', map{ (values %$_)[0] } @packFormat;
- (@charInfo{ map{ (keys %$_)[0] } @packFormat }, $data) = unpack( $format . 'a*', $data );
- while( ( my $skill = substr( $charInfo{skillStr}, 0, 3, '' ) ) ne '' ){
- push @{$charInfo{skills}}, [ unpack( 'sc', $skill ) ];
- }
- delete $charInfo{skillStr};
- for( my $i=0; $i<$charInfo{havePsi}; $i++ ){
- my $userPsiStr = substr( $data, 0, 3, '' );
- push @{$charInfo{userPsi}}, [ unpack( 'SC', $userPsiStr ) ];
- }
- # 继续处理剩下的字段
- @packFormat = (
- { itemStr => sprintf( 'a%d', 39 * 22 ) },
- { expNext => 'I' },
- { abnormal => 'I' },
- { changeClassStr => 'a8' },
- { _pad => 'a12' },
- { guildIndex=> 'i' },
- { guildName => 'c/A*' },
- { version => 'S' },
- );
- $format = join '', map{ (values %$_)[0] } @packFormat;
- @charInfo{ map{ (keys %$_)[0] } @packFormat } = unpack( $format, $data );
- while( ( my $item = substr( $charInfo{itemStr}, 0, 22, '' ) ) ne '' ){
- my ($level, $sid, $duration, $bullNum, $count, $magicStr, $IQ)
- = unpack( 'sssssa11c', $item );
- push @{$charInfo{items}}, {
- sid => $sid,
- level => $level,
- duration => $duration,
- bullNum => $bullNum,
- count => $count,
- magicStr => $magicStr,
- IQ => $IQ
- };
- }
- delete $charInfo{itemStr};
-
- $charInfo{_pad} = unpack( 'H*', $charInfo{_pad} );
- foreach my $key (keys %charInfo){
- $self->{charInfo}->{$key} = $charInfo{$key};
- }
- $self->{charInfo}->{repairHP} = [];
- $self->{charInfo}->{repairPP} = [];
- $self->{charInfo}->{repairSP} = [];
- # 检查有没有药
- foreach my $slot (0..$#{$self->{charInfo}->{items}}){
- my $sid = $self->{charInfo}->{items}->[$slot]->{sid};
- my $count = $self->{charInfo}->{items}->[$slot]->{count};
- next if ( $sid == -1 );
- if ( not exists $ddItemInfo->{$sid} ){
- $self->logmsg( "严重错误:物品 $sid 不存在。" );
- next;
- }
- # 跳过不是药品的物品
- next if ( $ddItemInfo->{$sid}->{byWear} != 101 );
- if ( $count <= 0 ){
- $self->logmsg( "严重错误:物品 $ddItemInfo->{$sid}($sid) 的个数为 $count" );
- next;
- }
- # 可以恢复生命值的,将它的 slot 和可恢复值记录在这个数组里。
- if ( $ddItemInfo->{$sid}->{sRepairHP} > 0 ){
- push @{$self->{charInfo}->{repairHP}}, {
- slot => $slot,
- value => $ddItemInfo->{$sid}->{sRepairHP},
- };
- }
- # 可以恢复精神值的,将它的 slot 和可恢复值记录在这个数组里。
- if ( $ddItemInfo->{$sid}->{sRepairPP} > 0 ){
- push @{$self->{charInfo}->{repairPP}}, {
- slot => $slot,
- value => $ddItemInfo->{$sid}->{sRepairPP},
- };
- }
- # 可以恢复体力值的,将它的 slot 和可恢复值记录在这个数组里。
- if ( $ddItemInfo->{$sid}->{sRepairSP} > 0 ){
- push @{$self->{charInfo}->{repairSP}}, {
- slot => $slot,
- value => $ddItemInfo->{$sid}->{sRepairSP},
- };
- }
- }
- $self->logmsg( "接收到人物 $charInfo{name} 的详细信息。" );
- }
- sub foundMonsterToAttack {
- my $self = shift;
- my $allowMove = shift;
- my $count = 0;
- my $nearest;
- foreach my $nid (keys %{$self->{npcinfo}}) {
- next if $nid < 20000 || $nid > 29999;
- my $x = $self->{npcinfo}{$nid}{x};
- my $y = $self->{npcinfo}{$nid}{y};
- if ( abs($x-$self->{charInfo}{x}) < $self->{charInfo}{attackRange}
- and abs($y-$self->{charInfo}{y}) < $self->{charInfo}{attackRange} ){
- $self->Attack( $nid );
- $count ++;
- }
- elsif( not defined $nearest ){
- $nearest = $self->{npcinfo}{$nid};
- }
- else{
- my $interval1 = abs($nearest->{x} - $self->{charInfo}{x})
- +abs($nearest->{y} - $self->{charInfo}{y});
- my $interval2 = abs($self->{npcinfo}{$nid}{x} - $self->{charInfo}{x})
- +abs($self->{npcinfo}{$nid}{y} - $self->{charInfo}{y});
- if ( $interval2 < $interval1 ){
- $nearest = $self->{npcinfo}{$nid};
- }
- }
- }
- if ( $count == 0 and $allowMove and $nearest ){
- $self->GoTo( $nearest->{x}, $nearest->{y} );
- }
- return $count;
- }
- sub Attack {
- my $self = shift;
- my $uid = shift;
- $Kernel->post( $self->{attack_session}, 'add_attack_obj', $uid );
- }
- sub GoTo {
- my $self = shift;
- my ($dst_x, $dst_y) = @_;
- return if $self->{state} eq '正在移动';
- $self->{state} = '正在移动';
- $self->{move_points} = [];
- my $x = $self->{charInfo}{x};
- my $y = $self->{charInfo}{y};
- my $dx = $dst_x - $x;
- my $dy = $dst_y - $y;
- my $ix = 1;
- my $iy = 1;
- if ( $dx < 0 ){
- $dx = -$dx;
- $ix = -1;
- }
- if ( $dy < 0 ){
- $dy = -$dy;
- $iy = -1;
- }
- if ( $dx > $dy ){
- my $e = -$dx;
- for( my $i=0; $i<=$dx; $i++ ){
- push @{$self->{move_points}}, [$x,$y];
- $x += $ix;
- $e += 2*$dy;
- if ( $e >= 0 ){
- $y += $iy; $e-=2*$dx;
- }
- else{
- $i++;
- $x += $ix;
- $e += 2*$dy;
- }
- }
- }
- else{
- my $e = -$dy;
- for( my $i=0; $i<=$dy; $i++ ){
- push @{$self->{move_points}}, [$x,$y];
- $y += $iy;
- $e += 2*$dx;
- if ( $e >= 0 ){
- $x += $ix; $e-=2*$dy;
- }
- else{
- $i++;
- $y += $iy;
- $e += 2*$dy;
- }
- }
- }
- shift @{$self->{move_points}};
- $self->ContinueMove();
- }
- sub ContinueMove {
- my $self = shift;
- return if $self->{state} ne '正在移动';
- return if not defined $self->{move_points};
- if ( @{$self->{move_points}} < 1 ){
- delete $self->{move_points};
- $self->{state} = '普通在线';
- $self->logmsg( "跑动结束" );
- return;
- }
- my $x = $self->{charInfo}{x};
- my $y = $self->{charInfo}{y};
- my $point = shift @{$self->{move_points}};
- my ($x1, $y1) = @$point;
- if ( $self->{charInfo}{SP} < 10 ){
- $self->logmsg( "走动 cur: $x,$y next: $x1,$y1" );
- my $data = pack( 'cssc', ZS_MOVE_REQ, $x1, $y1, 1 );
- $self->SendCryptPack( $self->{wheel}, $data );
- $self->TakeMedicineIfPossible();
- return;
- }
- my ($x2, $y2) = ($x1, $y1);
- if ( @{$self->{move_points}} > 0 ){
- $point = shift @{$self->{move_points}};
- ($x2, $y2) = @$point;
- }
- $self->logmsg( "跑动 cur: $x,$y next1: $x1,$y1 next2: $x2,$y2" );
- my $data = pack( 'cssssc', ZS_RUN_REQ, $x1, $y1, $x2, $y2, 1 );
- $self->SendCryptPack( $self->{wheel}, $data );
- }
- sub RunAck {
- my $self = shift;
- my $data = shift;
- my $result = ord( substr( $data, 0, 1, '' ) );
- if ( $result != 1 ){
- $self->{state} = '普通在线';
- $self->dbgmsg( "没跑成功。" );
- delete $self->{move_points};
- return;
- }
- my ($uid, $x1, $y1, $x2, $y2) = unpack( 'Issss', $data );
- if ( $x2 != -1 and $y2 != -1 ){
- $self->{npcinfo}{$uid}{x} = $x2;
- $self->{npcinfo}{$uid}{y} = $y2;
- $self->logmsg( "$uid 经由 $x1, $y1 跑到 $x2, $y2" );
- }
- else{
- $self->{npcinfo}{$uid}{x} = $x1;
- $self->{npcinfo}{$uid}{y} = $y1;
- $self->logmsg( "$uid 跑到 $x1, $y1" );
- }
- if ( $uid == $self->{charInfo}{uid} ){
- $self->{charInfo}{x} = $x2 != -1 ? $x2 : $x1;
- $self->{charInfo}{y} = $y2 != -1 ? $y2 : $y1;
- if ( $self->{curTask} eq '打怪' ){
- if( $self->foundMonsterToAttack(0) ){
- $self->{state} = '普通在线';
- delete $self->{move_points};
- return;
- }
- }
- usleep(1000 * 300);
- $self->ContinueMove();
- }
- }
- sub ChatResult {
- my $self = shift;
- my $data = shift;
- my $result = ord( substr( $data, 0, 1, '' ) );
- if ( $result != 1 ){
- my $errCode = ord( substr( $data, 0, 1, '' ) );
- $self->dbgmsg( "接收到聊天结果响应报文,但是包含有错误代码。" );
- return;
- }
- my ($type, $uid, $name, $msg) = unpack( 'C I c/A* c/A*', $data );
- $self->logmsg( "接收到来自于 $name 的消息: [$msg]" );
- if ( $name eq 'wxh' ){
- if ( $msg =~ /goto (-?\d+) (-?\d+)/ ){
- my ($x, $y) = ($self->{charInfo}{x}+$1, $self->{charInfo}{y}+$2);
- $self->dbgmsg( "管理员指令:立即跑步前往 => $x,$y" );
- $self->{curTask} = '管理员任务';
- $self->{state} = '普通在线';
- $self->GoTo( $x, $y );
- }
- elsif ( $msg eq 'dg' ){
- $self->dbgmsg( "管理员指令:开始打怪。" );
- $self->{curTask} = '打怪';
- }
- }
- }
- sub SendAttackReq {
- my $self = shift;
- my $uid = shift;
- my $data = pack( 'cs', ZS_ATTACK_REQ, $uid );
- $self->SendCryptPack( $self->{wheel}, $data );
- }
- sub AttackAck {
- my $self = shift;
- my $data = shift;
- my $result = ord( substr( $data, 0, 1, '' ) );
- if ( $result == 0 ){
- my %errMsg = (
- 0 => '攻击延时太短',
- 1 => '距离太远够不着打',
- );
- my $errcode = ord( $data );
- if ( exists( $errMsg{$errcode} ) ){
- $self->logmsg( "因为$errMsg{$errcode},所以没打着" );
- }
- else{
- $self->logmsg( "因为 $errcode,没打着" );
- }
- return;
- }
- if ( $result == 2 ){
- my ($src, $dst) = unpack( 'ii', $data );
- if ( $src == $self->{charInfo}{uid} ){
- $self->logmsg( "你想打 $dst,结果它灵巧地躲开了" );
- $Kernel->post( $self->{attack_session}, 'touch_attack_obj', $dst );
- }
- elsif ( $dst == $self->{charInfo}{uid} ){
- $self->logmsg( "$src 想打你,结果你灵巧地躲开了" );
- $self->Attack( $src );
- }
- else{
- # 别人打架的就不用报告了。
- }
- return;
- }
- if ( $result != 1 && $result != 3 ){
- $self->logmsg( "接收到攻击响应报文,但不知道是什么类型。请联系开发人员,谢谢合作!" );
- $self->pkgDump( $data, '未知攻击' );
- return;
- }
- my ($src, $dst, $HP, $MaxHP) = unpack( 'iiss', $data );
- if ( $src == $self->{charInfo}{uid} ){
- $self->logmsg( "你打中了 $dst, 它的 HP: [$HP/$MaxHP]" );
- $Kernel->post( $self->{attack_session}, 'touch_attack_obj', $dst );
- }
- elsif ( $dst == $self->{charInfo}{uid} ) {
- $self->logmsg( "$src 打中了你, 你的 HP: [$HP/$MaxHP]" );
- $self->{charInfo}{HP} = $HP;
- $self->{charInfo}{MaxHP} = $MaxHP;
- $self->Attack( $src ); # 还击
- }
- else{
- # 别人打架
- }
- return;
- }
- sub DeadAck {
- my $self = shift;
- my $data = shift;
- my ($uid, $x, $y) = unpack( 'sss', $data );
- $self->logmsg( "$uid 在 $x,$y 倒下了。" );
- $self->logmsg( "删除攻击对象。" );
- $Kernel->post( $self->{attack_session}, 'del_attack_obj', $uid );
- delete $self->{npcinfo}{$uid};
- }
- sub SetHP {
- my $self = shift;
- my $data = shift;
- my $hp = unpack( 's', $data );
- $hp -= $self->{charInfo}{HP};
- $self->{charInfo}{HP} += $hp;
- if ( $hp < 0 ){
- $hp = -$hp;
- $self->logmsg( "生命值减少了 $hp,目前是 $self->{charInfo}{HP}/$self->{charInfo}{MaxHP}" );
- $self->TakeMedicineIfPossible(); # 如果能吃得下药,就吃药。
- }
- elsif ( $hp > 0 ){
- $self->logmsg( "生命值增加了 $hp,目前是 $self->{charInfo}{HP}/$self->{charInfo}{MaxHP}" );
- }
- }
- sub SetExp {
- my $self = shift;
- my $data = shift;
- my ($type, $rest) = unpack( 'ca*', $data );
- if ( $type == 0 ){
- $self->dbgmsg( "接收到 SET_EXP 报文,但是类型标记为错误。" );
- return;
- }
- if ( $type != 1 and $type != 2 ){
- $self->dbgmsg( "接收到 SET_EXP 报文,但是类型无法识别。" );
- return;
- }
- (my $exp, $rest) = unpack( 'Ia*', $rest );
- if ( not defined $self->{charInfo}{Exp} ){
- $self->dbgmsg( "warning! exp not defined" );
- }
- $exp -= $self->{charInfo}{Exp};
- $self->{charInfo}{Exp} += $exp;
- if ($type == 1){
- $self->logmsg( "获得 $exp 点经验值,距离升级还需要", $self->{charInfo}{expNext} - $self->{charInfo}{Exp}, "点经验值。" );
- }
- else{
- my ($expNext, $level, $skillPoint, $PA) = unpack( 'Isss', $rest );
- $self->{charInfo}{expNext} = $expNext;
- $self->{charInfo}{level} = $level;
- $self->{charInfo}{skillPoint} = $skillPoint;
- $self->{charInfo}{PA} = $PA;
- $self->logmsg( "升级了。" );
- }
- }
- sub SetSP {
- my $self = shift;
- my $data = shift;
- my $sp = unpack( 's', $data );
- $sp -= $self->{charInfo}{SP};
- $self->{charInfo}{SP} += $sp;
- if ( $sp < 0 ){
- $sp = -$sp;
- $self->logmsg( "体力减少了 $sp,目前是 $self->{charInfo}{SP}/$self->{charInfo}{MaxSP}" );
- $self->TakeMedicineIfPossible(); # 如果能吃得下药,就吃药。
- }
- elsif ( $sp > 0 ){
- $self->logmsg( "体力增加了 $sp,目前是 $self->{charInfo}{SP}/$self->{charInfo}{MaxSP}" );
- }
- }
- sub TakeMedicineIfPossible {
- my $self = shift;
- # 先考虑生命值
- foreach my $item ( sort {$a->{value} <=> $b->{value}} @{$self->{charInfo}->{repairHP}} ){
- if ( $item->{value} <= $self->{charInfo}->{MaxHP} - $self->{charInfo}->{HP} ){
- $self->ItemUse( $item->{slot} );
- return;
- }
- }
- # 再考虑精神值
- foreach my $item ( sort {$a->{value} <=> $b->{value}} @{$self->{charInfo}->{repairPP}} ){
- if ( $item->{value} <= $self->{charInfo}->{MaxPP} - $self->{charInfo}->{PP} ){
- $self->ItemUse( $item->{slot} );
- return;
- }
- }
- # 接下来考虑体力值
- foreach my $item ( sort {$a->{value} <=> $b->{value}} @{$self->{charInfo}->{repairSP}} ){
- if ( $item->{value} <= $self->{charInfo}->{MaxSP} - $self->{charInfo}->{SP} ){
- $self->ItemUse( $item->{slot} );
- return;
- }
- }
- }
- sub ItemUse {
- my $self = shift;
- my $slot = shift;
- return if ( $self->{charInfo}->{items}->[$slot]->{count} <= 0 );
- $self->logmsg( "服用药品", $ddItemInfo->{$self->{charInfo}->{items}->[$slot]->{sid}}->{strName} );
- my $data = pack( 'ccc', ZS_ITEM_USE_REQ, 1, $slot );
- $self->SendCryptPack( $self->{wheel}, $data );
- }
- sub ItemUseAck {
- my $self = shift;
- my $data = shift;
- my $result = ord( substr( $data, 0, 1, '' ) );
- if ( $result != 1 ){
- $self->logmsg( "物品使用失败。" );
- return;
- }
- my ($mode, $SP, $HP, $PP, undef, $slot, $level, $sid, $duration, $bullNum, $count, $magicStr, $IQ)
- = unpack( 'c s s s s c sssssa11c', $data );
- if ( $mode == 1 ){
- $self->logmsg( "物品使用结果: 体力恢复到 $SP。" );
- }
- elsif ( $mode == 2 ){
- $self->logmsg( "物品使用结果: 精神恢复到 $PP。" );
- }
- elsif ( $mode == 4 ){
- $self->logmsg( "物品使用结果: 生命恢复到 $HP。" );
- }
- elsif ( $mode == 7 ){
- $self->logmsg( "物品使用结果: 体力恢复到 $SP, 精神恢复到 $PP, 生命恢复到 $HP。" );
- }
- else{
- $self->logmsg( "汗~我究竟吃了什么药?似乎吃错药了。" );
- }
- $self->{charInfo}->{items}->[$slot] = {
- level => $level,
- sid => $sid,
- duration => $duration,
- bullNum => $bullNum,
- count => $count,
- magicStr => $magicStr,
- IQ => $IQ,
- };
- }
- sub UsePotionNotice {
- my $self = shift;
- my $data = shift;
- my ($uid, $type) = unpack( 'Ic', $data );
- my $name = $self->getUserName( $uid );
- my %potionName = (
- 1 => '生命恢复剂',
- 2 => '精神恢复剂',
- 3 => '体力恢复剂',
- 4 => '全面恢复剂',
- 9 => '毒药',
- );
- my $potionName = $potionName{$type} || '不知什么药丸。';
- $self->logmsg( "$name 吃下了 $potionName" );
- }
- sub FieldItemInfo {
- my $self = shift;
- my $data = shift;
- my ($loopCount, $mode, $x, $y, $sid, $count, $IQ, $uid) = unpack( 'sCsssICa*', $data );
- my $name = $sid;
- if ( exists $ddItemInfo->{$sid} ){
- $name = $ddItemInfo->{$sid}->{strName};
- }
- if ( $mode == 1 ){
- $self->logmsg( "在 $x, $y 发现 $count 个 $name。" );
- }
- elsif ( $mode == 2 ){
- $self->logmsg( "$x, $y 处的 $count 个 $name 消失了。" );
- }
- elsif ( $mode == 3 ){
- $uid = unpack( 'I', $uid );
- $self->logmsg( "$x, $y 处的 $count 个 $name 被 " . $self->getUserName($uid) . " 捡走了。" );
- }
- else{
- $self->dbgmsg( "接受到错误的 FIELD_ITEM_INFO 报文。Mode = [$mode]" );
- }
- }
- sub attack_start {
- my ($kernel, $heap, $gameClient ) = @_[KERNEL, HEAP, ARG0];
- $heap->{game_client} = $gameClient;
- $heap->{timer} = 0;
- $kernel->yield( 'attack_loop' );
- }
- sub attack_loop {
- my ($kernel, $heap ) = @_[KERNEL, HEAP];
- foreach my $uid ( @{$heap->{attack_list}} ){
- if ( !defined $heap->{attack_sent}{$uid} ||
- $heap->{timer} - $heap->{attack_sent}{$uid} > 10 ){
- $heap->{game_client}->logmsg( "攻击 $uid");
- $heap->{game_client}->SendAttackReq( $uid );
- $heap->{attack_sent}{$uid} = $heap->{timer};
- }
- }
- $heap->{timer} ++;
- $heap->{game_client}->foundMonsterToAttack(1);
- # 不论有无怪物,线程都要空转。
- usleep(1000 * 200);
- $kernel->yield( 'attack_loop' );
- }
- sub add_attack_obj {
- my ($kernel, $heap, $uid) = @_[KERNEL, HEAP, ARG0];
- my ($index) = grep { $heap->{attack_list}->[$_] == $uid } (0..$#{$heap->{attack_list}});
- return if defined $index;
- $heap->{game_client}->logmsg( "打 $uid" );
- push @{$heap->{attack_list}}, $uid;
- }
- sub del_attack_obj {
- my ($heap, $uid) = @_[HEAP, ARG0];
- $heap->{game_client}->logmsg( "查找攻击对象 $uid。" );
- my ($index) = grep { $heap->{attack_list}->[$_] == $uid } (0..$#{$heap->{attack_list}});
- return if not defined $index;
- $heap->{game_client}->logmsg( "找到了,位置在 $index。" );
- splice @{$heap->{attack_list}}, $index, 1;
- }
- sub touch_attack_obj {
- my ($heap, $uid) = @_[HEAP, ARG0];
- delete $heap->{attack_sent}{$uid};
- }
- sub attack_stop {
- my $heap = $_[HEAP];
- $heap->{game_client}->{state} = '普通在线';
- delete $_[HEAP]->{game_client}->{attack_session};
- }
- sub getUserName {
- my $self = shift;
- my $uid = shift;
- if ( $uid == $self->{charInfo}{uid} ){
- return $self->{charInfo}{name};
- }
- elsif ( exists $self->{npcinfo}{$uid} ){
- return $self->{npcinfo}{$uid}{name};
- }
- else{
- return $uid;
- }
- }
- sub logmsg {
- my $self = shift;
- return if @_ == 0;
- printf "%s %s: %s\n", &getTimeStr(), $self->{state}, join ' ', @_;
- }
- sub exitmsg {
- my $self = shift;
- return if @_ == 0;
- printf "%s %s: %s\n", &getTimeStr(), $self->{state}, join ' ', @_;
- die "\n";
- }
- sub dbgmsg {
- my $self = shift;
- return if @_ == 0;
- return if $Debug != 1;
- printf "%s %s: %s\n", &getTimeStr(), $self->{state}, join ' ', @_;
- }
- sub pkgDump {
- my $self = shift;
- my $data = shift;
- my $title = shift || '';
- return if not defined $data;
- return if $Debug != 1;
- if ( $title ){
- $title = sprintf( "%-9s ", $title );
- $title .= '=' x 67;
- }
- else{
- $title = '=' x 77;
- }
- print $title, "\n";
- print HexDump( $data );
- print '=' x 77, "\n";
- }
- sub todo {
- my $self = shift;
- my ($id, $data) = @_;
- open FH, ">>todo.txt";
- select FH;
- $self->logmsg( sprintf( "接收到未知 [0x%02X:%d] 报文。", $id, $id ) );
- $self->pkgDump( $data, 'From ZS:' ) if ( defined $data and $data ne '' );
- select STDOUT;
- close FH;
- }
- sub getTimeStr(;$) {
- my $arg1 = shift;
- my @ret;
- if ( $arg1 ){
- @ret = localtime($arg1);
- } else {
- @ret = localtime;
- }
- $ret[4] += 1;
- $ret[5] += 1900;
- return sprintf( "%02d-%02d %02d:%02d:%02d", @ret[4, 3, 2, 1, 0] );
- }
- 1;
复制代码
[ 本帖最后由 flw 于 2007-3-13 18:31 编辑 ] |
|