File Coverage

blib/lib/Game/Tibia/Packet/Charlist.pm
Criterion Covered Total %
statement 65 67 97.0
branch 11 22 50.0
condition 4 9 44.4
subroutine 11 11 100.0
pod 2 2 100.0
total 93 111 83.7


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