From ae979274f828e2d8cc679641071edd14b2771811 Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Wed, 3 Jan 2018 18:52:35 +0700 Subject: [PATCH 1/3] Added support for Refine UI * Added command `refineui select [item_index]` * Added command `refineui refine [item_index] [material_id] [catalyst_toggle]` * References: * https://github.com/rathena/rathena/pull/2494 * https://github.com/cydh/rathena/pull/9 * Tested using rAthena's PACKETVER 20161207 --- src/Commands.pm | 108 ++++++++++++++++++ src/Globals.pm | 7 +- src/Network/Receive.pm | 56 +++++++++ src/Network/Receive/ServerType0.pm | 2 + .../Receive/kRO/RagexeRE_2016_12_07e.pm | 14 +++ src/Network/Send.pm | 41 ++++++- src/Network/Send/ServerType0.pm | 3 + src/Network/Send/kRO/RagexeRE_2016_12_07e.pm | 5 +- src/functions.pl | 1 + 9 files changed, 232 insertions(+), 5 deletions(-) diff --git a/src/Commands.pm b/src/Commands.pm index bd8784c15c..b418a678de 100644 --- a/src/Commands.pm +++ b/src/Commands.pm @@ -239,6 +239,7 @@ sub initHandlers { southeast => \&cmdManualMove, southwest => \&cmdManualMove, captcha => \&cmdAnswerCaptcha, + refineui => \&cmdRefienUI, # Skill Exchange Item cm => \&cmdExchangeItem, @@ -6747,4 +6748,111 @@ sub cmdExchangeItem { "Combination: %s , , \n", $switch, $switch, $switch); } +## +# refineui select [item_index] +# refineui refine [item_index] [material_id] [catalyst_toggle] +# @author [Cydh] +## +sub cmdRefienUI { + if (!$net || $net->getState() != Network::IN_GAME) { + error TF("You must be logged in the game to use this command '%s'\n", shift); + return; + } + my ($cmd, $args_string) = @_; + if (!defined $refineUI) { + error T("Cannot use RefineUI yet.\n"); + return; + } + my @args = parseArgs($args_string, 4); + + # refineui close + # End Refine UI state + if ($args[0] eq "cancel" || $args[0] eq "end" || $args[0] eq "no") { + message T("Closing Refine UI.\n"), "info"; + undef $refineUI; + $messageSender->sendRefineUIClose(); + return; + + # refineui select [item_index] + # Do refine + } elsif ($args[0] eq "select") { + #my ($invIndex) = $args =~ /^(\d+)/; + my $invIndex = $args[1]; + + # Check item + my $item = $char->inventory->get($invIndex); + if (!defined $item) { + warning TF("Item in index '%d' is not exists.\n", $invIndex); + return; + } elsif ($item->{equipped} != 0) { + warning TF("Cannot select equipped %s (%d) item!\n", $item->{name}, $invIndex); + return; + } + $refineUI->{invIndex} = $invIndex; + message TF("Request info for selected item to refine: %s (%d)\n", $item->{name}, $invIndex); + $messageSender->sendRefineUISelect( $item->{ID}); + return; + + # refineui refine [item_index] [material_id] [catalyst_toggle] + # Do refine + } elsif ($args[0] eq "refine") { + #my ($invIndex, $matInvIndex, $catalyst) = $args =~ /^(\d+) (\d+) (\d+|yes|no)/; + my $invIndex = $args[1]; + my $matNameID = $args[2]; + my $catalyst = $args[3]; + + # Check item + my $item = $char->inventory->get($invIndex); + if (!defined $item) { + warning TF("Item in index '%d' is not exists.\n", $invIndex); + return; + } elsif ($item->{equipped} != 0) { + warning TF("Cannot select equipped %s (%d) item!\n", $item->{name}, $invIndex); + return; + } + + # Check material + my $material = $char->inventory->getByNameID($matNameID); + if (!defined $material) { + warning TF("You don't have enough '%s' (%d) as refine material.\n", itemNameSimple($matNameID), $matNameID); + return; + } + # Check if the selected item is valid material + my $valid = 0; + foreach my $mat (@{$refineUI->{materials}}) { + if ($mat->{nameid} == $matNameID) { + $valid = 1; + } + } + if ($valid != 1) { + warning TF("'%s' (%d) is not valid refine material for '%s'.\n", itemNameSimple($matNameID), $matNameID, $item->{name}); + return; + } + + # Check catalyst toggle + my $useCatalyst = 0; + #my $Blacksmith_Blessing = 6635; # 6635,Blacksmith_Blessing,Blacksmith Blessing + my $blessName = itemNameSimple($Blacksmith_Blessing); + if ($refineUI->{bless} > 0 && ($catalyst == 1 || $catalyst eq "yes")) { + my $catalystItem = $char->inventory->getByNameID($Blacksmith_Blessing); + if (!$catalystItem || $catalystItem->{amount} < $refineUI->{bless}) { + warning TF("You don't have %s for RefineUI. Needed: %d!\n", $blessName, $refineUI->{bless}); + return; + } + $useCatalyst = 1; + } + + my $matStr = $material->{name}; + if ($useCatalyst) { + $matStr .= " and ".$refineUI->{bless}."x ".$blessName; + } + message TF("Refining item: %s with material %s.\n", $item->{name}, $matStr); + $messageSender->sendRefineUIRefine($item->{ID}, $matNameID, $useCatalyst); + return; + } else { + error T("Invalid usage!\n"); + return; + } +} + 1; diff --git a/src/Globals.pm b/src/Globals.pm index a9f23a8ae6..b021ddbb46 100644 --- a/src/Globals.pm +++ b/src/Globals.pm @@ -26,9 +26,9 @@ use Modules 'register'; # Do not use any other Kore modules here. It will create circular dependancies. our %EXPORT_TAGS = ( - config => [qw(%arrowcraft_items %avoid @chatResponses %cities_lut %config %consoleColors %directions_lut %equipTypes_lut %equipSlot_rlut %equipSlot_lut %haircolors @headgears_lut @msgTable %items_control %items_lut %itemSlotCount_lut %itemsDesc_lut %itemTypes_lut %jobs_lut %maps_lut %masterServers %monsters_lut %npcs_lut %packetDescriptions %portals_lut @portals_lut_missed %responses %sex_lut %shop %skillsDesc_lut %lookHandle %skillsArea %skillsEncore %spells_lut %emotions_lut %timeout $char %mon_control %priority %routeWeights %pickupitems %rpackets %itemSlots_lut %statusHandle %statusName %effectName %hatEffectHandle %hatEffectName %portals_los %stateHandle %ailmentHandle %mapTypeHandle %mapPropertyTypeHandle %mapPropertyInfoHandle %elements_lut %mapAlias_lut %quests_lut)], + config => [qw(%arrowcraft_items %avoid @chatResponses %cities_lut %config %consoleColors %directions_lut %equipTypes_lut %equipSlot_rlut %equipSlot_lut %haircolors @headgears_lut @msgTable %items_control %items_lut %itemSlotCount_lut %itemsDesc_lut %itemTypes_lut %jobs_lut %maps_lut %masterServers %monsters_lut %npcs_lut %packetDescriptions %portals_lut @portals_lut_missed %responses %sex_lut %shop %skillsDesc_lut %lookHandle %skillsArea %skillsEncore %spells_lut %emotions_lut %timeout $char %mon_control %priority %routeWeights %pickupitems %rpackets %itemSlots_lut %statusHandle %statusName %effectName %hatEffectHandle %hatEffectName %portals_los %stateHandle %ailmentHandle %mapTypeHandle %mapPropertyTypeHandle %mapPropertyInfoHandle %elements_lut %mapAlias_lut %quests_lut $Blacksmith_Blessing)], ai => [qw(@ai_seq @ai_seq_args %ai_v %targetTimeout)], - state => [qw($accountID $cardMergeIndex @cardMergeItemsID $charID @chars @chars_old @friendsID %friends %incomingFriend $field %homunculus $itemsList @itemsID %items $monstersList @monstersID %monsters @npcsID %npcs $npcsList @playersID %players @portalsID @portalsID_old %portals %portals_old $portalsList $storeList $currentChatRoom @currentChatRoomUsers @chatRoomsID %createdChatRoom %chatRooms @skillsID $storageTitle @arrowCraftID %guild %incomingGuild @spellsID %spells @unknownPlayers @unknownNPCs $useArrowCraft %currentDeal %incomingDeal %outgoingDeal @identifyID @partyUsersID %incomingParty @petsID %pets $venderItemList $venderID $venderCID @venderListsID @buyerItemList @selfBuyerItemList $buyerID $buyingStoreID @buyerListsID @articles $articles %venderLists %buyerLists %monsters_old @monstersID_old %npcs_old %items_old %players_old @playersID_old @servers $sessionID $sessionID2 $accountSex $accountSex2 $map_ip $map_port $KoreStartTime $secureLoginKey $initSync $lastConfChangeTime $petsList $playersList $portalsList @playerNameCacheIDs %playerNameCache %pet $pvp @cashList $slavesList @slavesID %slaves %cashShop $skillExchangeItem)], + state => [qw($accountID $cardMergeIndex @cardMergeItemsID $charID @chars @chars_old @friendsID %friends %incomingFriend $field %homunculus $itemsList @itemsID %items $monstersList @monstersID %monsters @npcsID %npcs $npcsList @playersID %players @portalsID @portalsID_old %portals %portals_old $portalsList $storeList $currentChatRoom @currentChatRoomUsers @chatRoomsID %createdChatRoom %chatRooms @skillsID $storageTitle @arrowCraftID %guild %incomingGuild @spellsID %spells @unknownPlayers @unknownNPCs $useArrowCraft %currentDeal %incomingDeal %outgoingDeal @identifyID @partyUsersID %incomingParty @petsID %pets $venderItemList $venderID $venderCID @venderListsID @buyerItemList @selfBuyerItemList $buyerID $buyingStoreID @buyerListsID @articles $articles %venderLists %buyerLists %monsters_old @monstersID_old %npcs_old %items_old %players_old @playersID_old @servers $sessionID $sessionID2 $accountSex $accountSex2 $map_ip $map_port $KoreStartTime $secureLoginKey $initSync $lastConfChangeTime $petsList $playersList $portalsList @playerNameCacheIDs %playerNameCache %pet $pvp @cashList $slavesList @slavesID %slaves %cashShop $skillExchangeItem $refineUI)], network => [qw($remote_socket $net $messageSender $charServer $conState $conState_tries $encryptVal $ipc $bus $masterServer $lastSwitch $packetParser $clientPacketHandler $bytesSent $incomingMessages $outgoingClientMessages $enc_val1 $enc_val2 $captcha_state)], interface => [qw($interface)], misc => [qw($quit $reconnectCount @lastpm %lastpm @privMsgUsers %timeout_ex $shopstarted $dmgpsec $totalelasped $elasped $totaldmg %overallAuth %responseVars %talk $startTime_EXP $startingzeny @monsters_Killed $bExpSwitch $jExpSwitch $totalBaseExp $totalJobExp $shopEarned %itemChange $XKore_dontRedirect $monkilltime $monstarttime $startedattack $firstLoginMap $sentWelcomeMessage $versionSearch $monsterBaseExp $monsterJobExp %descriptions %flags %damageTaken $logAppend @sellList $userSeed $taskManager $repairList $mailList $rodexList $rodexWrite $auctionList $questList $achievementList $hotkeyList $devotionList $cookingList %charSvrSet @deadTime)], @@ -471,6 +471,7 @@ our %playerNameCache; our %pet; our @cashList; our $skillExchangeItem; +our $refineUI; # Network our $remote_socket; # Unused, but required for outdated plugins @@ -560,7 +561,7 @@ our $cookingList; our %charSvrSet; our $questList; our $achievementList; - +our $Blacksmith_Blessing = 6635; our $captcha_state = 0; our %quests_lut; diff --git a/src/Network/Receive.pm b/src/Network/Receive.pm index 5a0f23066b..b5c3222daa 100644 --- a/src/Network/Receive.pm +++ b/src/Network/Receive.pm @@ -4165,4 +4165,60 @@ sub skill_exchange_item { $skillExchangeItem = $args->{type} + 1; } +# Allowed to RefineUI by server +# '0AA0' => ['refineui_opened', '' ,[qw()]], +# @author [Cydh] +sub refineui_opened { + my ($self, $args) = @_; + message TF("RefineUI is opened. Type 'i' to check equipment and its index. To continue: refineui select [ItemIdx]\n"), "info"; + $refineUI->{open} = 1; +} + +# Received refine info for selected item +# '0AA2' => ['refineui_info', 'v v C a*' ,[qw(index bless materials)]], +# @param args Packet data +# @author [Cydh] +sub refineui_info { + my ($self, $args) = @_; + + if ($args->{len} > 7) { + $refineUI->{itemIndex} = $args->{index}; + $refineUI->{bless} = $args->{bless}; + + my $item = $char->inventory->[$refineUI->{invIndex}]; + my $bless = $char->inventory->getByNameID($Blacksmith_Blessing); + + message T("========= RefineUI Info =========\n"), "info"; + message TF("Target Equip:\n". + "- Index: %d\n". + "- Name: %s\n", + $refineUI->{invIndex}, $item ? itemName($item) : "Unknown."), + "info"; + + message TF("%s:\n". + "- Needed: %d\n". + "- Owned: %d\n", + #itemNameSimple($Blacksmith_Blessing) + "Blacksmith Blessing", $refineUI->{bless}, $bless ? $bless->{amount} : 0), + "info"; + + @{$refineUI->{materials}} = map { my %r; @r{qw(nameid chance zeny)} = unpack 'v C V', $_; \%r} unpack '(a7)*', $args->{materials}; + + my $msg = center(T(" Possible Materials "), 53, '-') ."\n" . + T("Mat_ID % Zeny Material \n"); + foreach my $mat (@{$refineUI->{materials}}) { + my $myMat = $char->inventory->getByNameID($mat->{nameid}); + my $myMatCount = sprintf("%d ea %s", $myMat ? $myMat->{amount} : 0, itemNameSimple($mat->{nameid})); + $msg .= swrite( + "@>>>>>>>> @>>>>> @>>>>>>>>>>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<", + [$mat->{nameid}, $mat->{chance}, $mat->{zeny}, $myMatCount]); + } + $msg .= ('-'x53) . "\n"; + message $msg, "info"; + message TF("Continue: refineui refine %d [Mat_ID] [catalyst_toggle] to continue.\n", $refineUI->{invIndex}), "info"; + } else { + error T("Equip cannot be refined, try different equipment. Type 'i' to check equipment and its index.\n"); + } +} + 1; diff --git a/src/Network/Receive/ServerType0.pm b/src/Network/Receive/ServerType0.pm index 0f34420c82..89b095c030 100644 --- a/src/Network/Receive/ServerType0.pm +++ b/src/Network/Receive/ServerType0.pm @@ -600,6 +600,8 @@ sub new { '09E7' => ['unread_rodex', 'C', [qw(show)]], # 3 '0A05' => ['rodex_add_item', 'C a2 v2 C4 a8 a25 v a5', [qw(fail ID amount nameID type identified broken upgrade cards options weight unknow)]], # 53 '0A7D' => ['rodex_mail_list', 'v C3', [qw(len type amount isEnd)]], # -1 + '0AA0' => ['refineui_opened', '' ,[qw()]], + '0AA2' => ['refineui_info', 'v v C a*' ,[qw(len index bless materials)]], }; # Item RECORD Struct's diff --git a/src/Network/Receive/kRO/RagexeRE_2016_12_07e.pm b/src/Network/Receive/kRO/RagexeRE_2016_12_07e.pm index 3cd416813c..c032a47968 100644 --- a/src/Network/Receive/kRO/RagexeRE_2016_12_07e.pm +++ b/src/Network/Receive/kRO/RagexeRE_2016_12_07e.pm @@ -16,6 +16,20 @@ package Network::Receive::kRO::RagexeRE_2016_12_07e; use strict; use base qw(Network::Receive::kRO::RagexeRE_2016_07_06c); +sub new { + my ($class) = @_; + my $self = $class->SUPER::new(@_); + + my %packets = ( + '0AA0' => ['refineui_opened', '' ,[qw()]], + '0AA2' => ['refineui_info', 'v v C a*' ,[qw(len index bless materials)]], + ); + + foreach my $switch (keys %packets) { $self->{packet_list}{$switch} = $packets{$switch}; } + + return $self; +} + 1; =pod diff --git a/src/Network/Send.pm b/src/Network/Send.pm index f92622da22..5fad15e007 100644 --- a/src/Network/Send.pm +++ b/src/Network/Send.pm @@ -31,7 +31,7 @@ use Carp::Assert; use Digest::MD5; use Math::BigInt; -use Globals qw(%config $encryptVal $bytesSent $conState %packetDescriptions $enc_val1 $enc_val2 $char $masterServer $syncSync $accountID %timeout %talk %masterServers $skillExchangeItem); +use Globals qw(%config $encryptVal $bytesSent $conState %packetDescriptions $enc_val1 $enc_val2 $char $masterServer $syncSync $accountID %timeout %talk %masterServers $skillExchangeItem $refineUI); use I18N qw(bytesToString stringToBytes); use Utils qw(existsInList getHex getTickCount getCoordString makeCoordsDir); use Misc; @@ -1195,4 +1195,43 @@ sub reconstruct_item_list_window_selected { $args->{itemInfo} = pack '(a4)*', map { pack 'v2', @{$_}{qw(itemIndex amount)} } @{$args->{items}}; } +# Select equip for refining +# '0AA1' => ['refineui_select', 'a2' ,[qw(index)]], +# @param itemIndex OpenKore's Inventory Item Index +# @author [Cydh] +sub sendRefineUISelect { + my ($self, $itemIndex) = @_; + $self->sendToServer($self->reconstruct({ + switch => 'refineui_select', + index => $itemIndex, + })); + debug "Checking item for RefineUI\n", "sendPacket"; +} + +# Continue to refine equip +# '0AA3' => ['refineui_refine', 'a2 v C' ,[qw(index catalyst bless)]], +# @param itemIndex OpenKore's Inventory Item Index +# @param materialNameIDMaterial's NameID +# @param useCatalyst Catalyst (Blacksmith Blessing) toggle. 0 = Not using, 1 = Use catalyst +# @author [Cydh] +sub sendRefineUIRefine { + my ($self, $itemIndex, $materialNameID, $useCatalyst) = @_; + $self->sendToServer($self->reconstruct({ + switch => 'refineui_refine', + index => $itemIndex, + catalyst => $materialNameID, + bless => $useCatalyst, + })); + debug "Refining using RefineUI\n", "sendPacket"; +} + +# Cancel RefineUI usage +# '0AA4' => ['refineui_close', '' ,[qw()]], +# @author [Cydh] +sub sendRefineUIClose { + my $self = shift; + $self->sendToServer($self->reconstruct({switch => 'refineui_close'})); + debug "Closing RefineUI\n", "sendPacket"; +} + 1; diff --git a/src/Network/Send/ServerType0.pm b/src/Network/Send/ServerType0.pm index 8b7a0dff4f..d6eaaa9757 100644 --- a/src/Network/Send/ServerType0.pm +++ b/src/Network/Send/ServerType0.pm @@ -160,6 +160,9 @@ sub new { '0A08' => ['rodex_open_write_mail', 'Z24', [qw(name)]], # 26 -- RodexOpenWriteMail '0A13' => ['rodex_checkname', 'Z24', [qw(name)]], # 26 -- RodexCheckName '0A6E' => ['rodex_send_mail', 'v Z24 Z24 V2 v v V a* a*', [qw(len receiver sender zeny1 zeny2 title_len body_len char_id title body)]], # -1 -- RodexSendMail + '0AA1' => ['refineui_select', 'a2' ,[qw(index)]], + '0AA3' => ['refineui_refine', 'a2 v C' ,[qw(index catalyst bless)]], + '0AA4' => ['refineui_close', '' ,[qw()]], ); $self->{packet_list}{$_} = $packets{$_} for keys %packets; diff --git a/src/Network/Send/kRO/RagexeRE_2016_12_07e.pm b/src/Network/Send/kRO/RagexeRE_2016_12_07e.pm index a94f9b17ba..3a78c4ce89 100644 --- a/src/Network/Send/kRO/RagexeRE_2016_12_07e.pm +++ b/src/Network/Send/kRO/RagexeRE_2016_12_07e.pm @@ -41,7 +41,10 @@ sub new { '0875' => ['storage_item_add', 'a2 V', [qw(ID amount)]], '091D' => ['storage_item_remove', 'a2 V', [qw(ID amount)]], '095D' => ['storage_password'], - '035F' => ['sync', 'V', [qw(time)]], + '035F' => ['sync', 'V', [qw(time)]], + '0AA1' => ['refineui_select', 'a2' ,[qw(index)]], + '0AA3' => ['refineui_refine', 'a2 v C' ,[qw(index catalyst bless)]], + '0AA4' => ['refineui_close', '' ,[qw()]], ); $self->{packet_list}{$_} = $packets{$_} for keys %packets; diff --git a/src/functions.pl b/src/functions.pl index 0a48a33dcb..570d19961d 100644 --- a/src/functions.pl +++ b/src/functions.pl @@ -667,6 +667,7 @@ sub initMapChangeVars { undef $rodexList; undef $rodexWrite; undef $skillExchangeItem; + undef $refineUI; $captcha_state = 0; $itemsList->clear(); From fee6c77432619b6b1d195f87095e4ea1040171dd Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Wed, 3 Jan 2018 18:57:40 +0700 Subject: [PATCH 2/3] Typo fixes --- src/Commands.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Commands.pm b/src/Commands.pm index b418a678de..9adaeda87f 100644 --- a/src/Commands.pm +++ b/src/Commands.pm @@ -239,7 +239,7 @@ sub initHandlers { southeast => \&cmdManualMove, southwest => \&cmdManualMove, captcha => \&cmdAnswerCaptcha, - refineui => \&cmdRefienUI, + refineui => \&cmdRefineUI, # Skill Exchange Item cm => \&cmdExchangeItem, @@ -6753,7 +6753,7 @@ sub cmdExchangeItem { # refineui refine [item_index] [material_id] [catalyst_toggle] # @author [Cydh] ## -sub cmdRefienUI { +sub cmdRefineUI { if (!$net || $net->getState() != Network::IN_GAME) { error TF("You must be logged in the game to use this command '%s'\n", shift); return; From 37697fe82429e7c4f4c2a33c19c8fe0dcc20a855 Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Wed, 3 Jan 2018 19:14:22 +0700 Subject: [PATCH 3/3] Added packet list for Sakexe_0 --- src/Network/Receive/kRO/Sakexe_0.pm | 2 ++ src/Network/Send/kRO/Sakexe_0.pm | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/Network/Receive/kRO/Sakexe_0.pm b/src/Network/Receive/kRO/Sakexe_0.pm index 82e32aa76c..ebb4922d9b 100644 --- a/src/Network/Receive/kRO/Sakexe_0.pm +++ b/src/Network/Receive/kRO/Sakexe_0.pm @@ -388,6 +388,8 @@ sub new { '09E7' => ['unread_rodex', 'C', [qw(show)]], # 3 '0A05' => ['rodex_add_item', 'C a2 v2 C4 a8 a25 v a5', [qw(fail ID amount nameID type identified broken upgrade cards options weight unknow)]], # 53 '0A7D' => ['rodex_mail_list', 'v C3', [qw(len type amount isEnd)]], # -1 + '0AA0' => ['refineui_opened', '' ,[qw()]], + '0AA2' => ['refineui_info', 'v v C a*' ,[qw(len index bless materials)]], }; # Item RECORD Struct's diff --git a/src/Network/Send/kRO/Sakexe_0.pm b/src/Network/Send/kRO/Sakexe_0.pm index 78babe425d..dec3277e14 100644 --- a/src/Network/Send/kRO/Sakexe_0.pm +++ b/src/Network/Send/kRO/Sakexe_0.pm @@ -94,6 +94,9 @@ sub new { '0848' => ['cash_shop_buy_items', 's s V V s', [qw(len count item_id item_amount tab_code)]], #item_id, item_amount and tab_code could be repeated in order to buy multiple itens at once '084A' => ['cash_shop_close'],#2 '08B8' => ['send_pin_password','a4 Z*', [qw(accountID pin)]], + '0AA1' => ['refineui_select', 'a2' ,[qw(index)]], + '0AA3' => ['refineui_refine', 'a2 v C' ,[qw(index catalyst bless)]], + '0AA4' => ['refineui_close', '' ,[qw()]], ); $self->{packet_list}{$_} = $packets{$_} for keys %packets;