File Coverage

blib/lib/Game/Tibia/Packet/Charlist.pm
Criterion Covered Total %
statement 66 68 97.0
branch 11 24 45.8
condition 6 15 40.0
subroutine 11 11 100.0
pod 2 2 100.0
total 96 120 80.0


line stmt bran cond sub pod time code
1 2     2   96225 use strict;
  2         5  
  2         62  
2 2     2   14 use warnings;
  2         6  
  2         54  
3 2     2   30 use v5.16.0;
  2         7  
4             package Game::Tibia::Packet::Charlist;
5              
6             # ABSTRACT: Character list packet support for the MMORPG Tibia
7             our $VERSION = '0.006'; # VERSION
8              
9 2     2   14 use Carp;
  2         5  
  2         134  
10 2     2   603 use Game::Tibia::Packet;
  2         7  
  2         71  
11              
12 2     2   15 use constant DLG_MOTD => 0x14;
  2         5  
  2         109  
13 2     2   14 use constant DLG_INFO => 0x15;
  2         5  
  2         96  
14 2     2   14 use constant DLG_ERROR => 0x0a;
  2         5  
  2         98  
15 2     2   14 use constant DLG_CHARLIST => 0x64;
  2         5  
  2         1294  
16              
17             =pod
18              
19             =encoding utf8
20              
21             =head1 NAME
22              
23             Game::Tibia::Packet::Charlist - Character list packet support for the MMORPG Tibia
24              
25              
26             =head1 SYNOPSIS
27              
28             use Game::Tibia::Packet::Charlist;
29              
30             my $p = Game::Tibia::Packet::Charlist->new(
31             packet => $packet,
32             xtea => $xtea,
33             version => 830
34             );
35              
36             $p->{premium_days} = 0xff;
37             $sock->send($p->finalize);
38              
39              
40             =head1 DESCRIPTION
41              
42             Decodes Tibia Login packets into hashes and vice versa.
43              
44             =cut
45              
46             =head1 METHODS AND ARGUMENTS
47              
48             =over 4
49              
50             =item new([packet => $packet, version => $version, xtea => $xtea])
51              
52             Constructs a new Game::Tibia::Packet::Charlist instance of version C<$version>. When C and C are specified, the supplied packet is decrypted and is then retrievable with the C subroutine.
53              
54             =cut
55              
56             sub new {
57 3     3 1 638 my $class = shift;
58            
59 3         14 my $self = {
60             packet => undef,
61             xtea => undef,
62              
63             @_
64             };
65              
66 3 50 33     28 croak " 761 <= protocol version < 980 isn't satisfied" if !defined $self->{version} || ! (761 <= $self->{version} && $self->{version} < 980);
      33        
67 3 50 66     17 croak "Packet was specified without XTEA key" if defined $self->{packet} && !defined $self->{xtea};
68 3 50       19 $self->{versions}{client} = Game::Tibia::Packet::version $self->{version} unless ref $self->{version};
69              
70 3 100       10 if (defined $self->{packet}) {
71             my $packet = Game::Tibia::Packet->new(
72             packet => $self->{packet},
73             xtea => $self->{xtea},
74             version => $self->{version},
75 2         11 );
76              
77 2         6 my $payload = $packet->payload;
78 2         8 (my $type, $payload) = unpack 'Ca*', $payload;
79 2 50       7 if ($type eq DLG_MOTD) {
    0          
    0          
80 2         8 ($self->{motd}, $payload) = unpack '(S/a)< a*', $payload;
81             } elsif ($type eq DLG_INFO) {
82 0         0 ($self->{info}, $payload) = unpack '(S/a)< a*', $payload;
83             } elsif ($type eq DLG_ERROR) {
84 0         0 ($self->{error}, $payload) = unpack '(S/a)< a*', $payload;
85             }
86 2         6 ($type, $payload) = unpack 'Ca*', $payload;
87 2 50       6 if ($type eq DLG_CHARLIST) {
88 2         5 (my $count, $payload) = unpack 'Ca*', $payload;
89 2         5 $self->{characters} = undef;
90 2         3 my @chars;
91 2         5 while ($count--) {
92 4         6 my $char;
93 4         18 ($char->{name}, $char->{world}{name}, $char->{world}{ip}, $char->{world}{port}, $payload)
94             = unpack '(S/a S/a a4 S)< a*', $payload;
95 4         15 $char->{world}{ip} = join '.', unpack('C4', $char->{world}{ip});
96 4         10 push @chars, $char;
97             }
98 2         5 $self->{characters} = \@chars;
99             }
100 2         10 $self->{premium_days} = unpack 'S<', $payload;
101             }
102              
103 3         6 bless $self, $class;
104 3         8 return $self;
105             }
106              
107             =item finalize([$xtea]])
108              
109             Finalizes the packet. encrypts with XTEA and prepends header
110              
111             =cut
112              
113              
114             sub finalize {
115 2     2 1 8 my $self = shift;
116 2   33     10 my $xtea = shift // $self->{xtea};
117              
118 2         6 my $packet = Game::Tibia::Packet->new(version => $self->{version});
119 2 50       8 $packet->payload .= pack '(C S/a)<', DLG_MOTD, $self->{motd} if defined $self->{motd};
120 2 50       6 $packet->payload .= pack '(C S/a)<', DLG_INFO, $self->{info} if defined $self->{info};
121 2 50       5 $packet->payload .= pack '(C S/a)<', DLG_ERROR, $self->{error} if defined $self->{error};
122 2 50 33     6 if (defined $self->{characters} && @{$self->{characters}} > 0) {
  2         7  
123 2         4 $packet->payload .= pack 'C C', DLG_CHARLIST, scalar @{$self->{characters}};
  2         5  
124 2         3 foreach my $char (@{$self->{characters}}) {
  2         5  
125             $packet->payload .= pack '(S/a S/a a4 S)<',
126             $char->{name}, $char->{world}{name},
127 4         8 pack("C4", split('\.', $char->{world}{ip})), $char->{world}{port};
128             }
129             }
130 2         6 $packet->payload .= pack('S<', $self->{premium_days}); # pacc days
131 2         7 return $packet->finalize($xtea);
132             }
133              
134              
135             1;
136             __END__