Update.
Moved hooks to DESTROY.
But Receive object currently created new, and only then deleted old one. Easy to make it another way. In this patch checks for hasHook are disabled, so handlers from deal.pm need to be removed from Receive to work correctly.
Code: Select all
Index: ext/deal/deal.pl
===================================================================
--- ext/deal/deal.pl (revision 0)
+++ ext/deal/deal.pl (revision 0)
@@ -0,0 +1,336 @@
+package deal;
+use strict;
+return 1;
+use Carp::Assert;
+
+use I18N qw/bytesToString/;
+use Log qw/message error/;
+use Misc qw/itemName/;
+use Translation qw/T TF/;
+use Utils qw/formatNumber/;
+
+use Globals qw/$net $messageSender $char $playersList @playersID %timeout %items_lut %itemChange/;
+
+our %currentDeal;
+our %incomingDeal;
+our %outgoingDeal;
+
+Plugins::register 'deal', 'OpenKore deal extension', \&unload;
+
+my $hooks = Plugins::addHooks (
+ ['packet_handle/deal_request', \&deal_request],
+ ['packet_handle/deal_begin', \&deal_begin],
+ ['packet_handle/deal_add_other', \&deal_add_other],
+ ['packet_handle/deal_add_you', \&deal_add_you],
+ ['packet_handle/deal_finalize', \&deal_finalize],
+ ['packet_handle/deal_cancelled', \&deal_cancelled],
+ ['packet_handle/deal_complete', \&deal_complete],
+ ['packet_handle/deal_undo', \&deal_undo],
+);
+
+my $commands = Commands::register (
+ ['deal', '', \&cmdDeal],
+ ['dl', '', \&cmdDealList],
+);
+
+sub unload {
+ Plugins::delHooks ($hooks);
+ Commands::unregister ($commands);
+}
+
+# misc
+
+##
+# void deal(Actor::Player player)
+# Requires: defined($player)
+# Ensures: exists $outgoingDeal{ID}
+#
+# Sends $player a deal request.
+sub deal {
+ my $player = $_[0];
+ assert(defined $player) if DEBUG;
+ assert(UNIVERSAL::isa($player, 'Actor::Player')) if DEBUG;
+
+ $outgoingDeal{ID} = $player->{ID};
+ $messageSender->sendDeal($player->{ID});
+}
+
+##
+# dealAddItem($item, $amount)
+#
+# Adds $amount of $item to the current deal.
+sub dealAddItem {
+ my ($item, $amount) = @_;
+
+ $messageSender->sendDealAddItem($item->{index}, $amount);
+ $currentDeal{lastItemAmount} = $amount;
+}
+
+# commands
+
+sub cmdDeal {
+ 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 (undef, $args) = @_;
+ my @arg = split / /, $args;
+
+ if (%currentDeal && $arg[0] =~ /\d+/) {
+ error T("Error in function 'deal' (Deal a Player)\n" .
+ "You are already in a deal\n");
+ } elsif (%incomingDeal && $arg[0] =~ /\d+/) {
+ error T("Error in function 'deal' (Deal a Player)\n" .
+ "You must first cancel the incoming deal\n");
+ } elsif ($arg[0] =~ /\d+/ && !$playersID[$arg[0]]) {
+ error TF("Error in function 'deal' (Deal a Player)\n" .
+ "Player %s does not exist\n", $arg[0]);
+ } elsif ($arg[0] =~ /\d+/) {
+ my $ID = $playersID[$arg[0]];
+ my $player = Actor::get($ID);
+ message TF("Attempting to deal %s\n", $player);
+ deal($player);
+
+ } elsif ($arg[0] eq "no" && !%incomingDeal && !%outgoingDeal && !%currentDeal) {
+ error T("Error in function 'deal' (Deal a Player)\n" .
+ "There is no incoming/current deal to cancel\n");
+ } elsif ($arg[0] eq "no" && (%incomingDeal || %outgoingDeal)) {
+ $messageSender->sendDealReply(4);
+ } elsif ($arg[0] eq "no" && %currentDeal) {
+ $messageSender->sendCurrentDealCancel();
+
+ } elsif ($arg[0] eq "" && !%incomingDeal && !%currentDeal) {
+ error T("Error in function 'deal' (Deal a Player)\n" .
+ "There is no deal to accept\n");
+ } elsif ($arg[0] eq "" && $currentDeal{'you_finalize'} && !$currentDeal{'other_finalize'}) {
+ error TF("Error in function 'deal' (Deal a Player)\n" .
+ "Cannot make the trade - %s has not finalized\n", $currentDeal{'name'});
+ } elsif ($arg[0] eq "" && $currentDeal{'final'}) {
+ error T("Error in function 'deal' (Deal a Player)\n" .
+ "You already accepted the final deal\n");
+ } elsif ($arg[0] eq "" && %incomingDeal) {
+ $messageSender->sendDealReply(3);
+ } elsif ($arg[0] eq "" && $currentDeal{'you_finalize'} && $currentDeal{'other_finalize'}) {
+ $messageSender->sendDealTrade();
+ $currentDeal{'final'} = 1;
+ message T("You accepted the final Deal\n"), "deal";
+ } elsif ($arg[0] eq "" && %currentDeal) {
+ $messageSender->sendDealAddItem(0, $currentDeal{'you_zeny'});
+ $messageSender->sendDealFinalize();
+
+ } elsif ($arg[0] eq "add" && !%currentDeal) {
+ error T("Error in function 'deal_add' (Add Item to Deal)\n" .
+ "No deal in progress\n");
+ } elsif ($arg[0] eq "add" && $currentDeal{'you_finalize'}) {
+ error T("Error in function 'deal_add' (Add Item to Deal)\n" .
+ "Can't add any Items - You already finalized the deal\n");
+ } elsif ($arg[0] eq "add" && $arg[1] =~ /\d+/ && !$char->inventory->get($arg[1])) {
+ error TF("Error in function 'deal_add' (Add Item to Deal)\n" .
+ "Inventory Item %s does not exist.\n", $arg[1]);
+ } elsif ($arg[0] eq "add" && $arg[2] && $arg[2] !~ /\d+/) {
+ error T("Error in function 'deal_add' (Add Item to Deal)\n" .
+ "Amount must either be a number, or not specified.\n");
+ } elsif ($arg[0] eq "add" && $arg[1] =~ /\d+/) {
+ if ($currentDeal{you_items} < 10) {
+ my $item = $char->inventory->get($arg[1]);
+ my $amount = $item->{amount};
+ if (!$arg[2] || $arg[2] > $amount) {
+ $arg[2] = $amount;
+ }
+ dealAddItem($item, $arg[2]);
+ } else {
+ error T("You can't add any more items to the deal\n"), "deal";
+ }
+ } elsif ($arg[0] eq "add" && $arg[1] eq "z") {
+ if (!$arg[2] && !($arg[2] eq "0") || $arg[2] > $char->{'zeny'}) {
+ $arg[2] = $char->{'zeny'};
+ }
+ $currentDeal{'you_zeny'} = $arg[2];
+ message TF("You put forward %sz to Deal\n", formatNumber($arg[2])), "deal";
+
+ } else {
+ error T("Syntax Error in function 'deal' (Deal a player)\n" .
+ "Usage: deal [<Player # | no | add>] [<item #>] [<amount>]\n");
+ }
+}
+
+sub cmdDealList {
+ if (!%currentDeal) {
+ error T("There is no deal list - You are not in a deal\n");
+
+ } else {
+ message T("-----------Current Deal-----------\n"), "list";
+ my $other_string = $currentDeal{'name'};
+ my $you_string = "You";
+ if ($currentDeal{'other_finalize'}) {
+ $other_string .= " - Finalized";
+ }
+ if ($currentDeal{'you_finalize'}) {
+ $you_string .= " - Finalized";
+ }
+
+ message(swrite(
+ "@<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
+ [$you_string, $other_string]),
+ "list");
+
+ my @currentDealYou;
+ my @currentDealOther;
+ foreach (keys %{$currentDeal{'you'}}) {
+ push @currentDealYou, $_;
+ }
+ foreach (keys %{$currentDeal{'other'}}) {
+ push @currentDealOther, $_;
+ }
+
+ my ($lastindex, $display, $display2);
+ $lastindex = @currentDealOther;
+ $lastindex = @currentDealYou if (@currentDealYou > $lastindex);
+ for (my $i = 0; $i < $lastindex; $i++) {
+ if ($i < @currentDealYou) {
+ $display = ($items_lut{$currentDealYou[$i]} ne "")
+ ? $items_lut{$currentDealYou[$i]}
+ : "Unknown ".$currentDealYou[$i];
+ $display .= " x $currentDeal{'you'}{$currentDealYou[$i]}{'amount'}";
+ } else {
+ $display = "";
+ }
+ if ($i < @currentDealOther) {
+ $display2 = ($items_lut{$currentDealOther[$i]} ne "")
+ ? $items_lut{$currentDealOther[$i]}
+ : "Unknown ".$currentDealOther[$i];
+ $display2 .= " x $currentDeal{'other'}{$currentDealOther[$i]}{'amount'}";
+ } else {
+ $display2 = "";
+ }
+
+ message(swrite(
+ "@<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
+ [$display, $display2]),
+ "list");
+ }
+ $you_string = ($currentDeal{'you_zeny'} ne "") ? $currentDeal{'you_zeny'} : 0;
+ $other_string = ($currentDeal{'other_zeny'} ne "") ? $currentDeal{'other_zeny'} : 0;
+
+ message TF("zeny: %-25s zeny: %-14s",
+ formatNumber($you_string), formatNumber($other_string)), "list";
+ message("----------------------------------\n", "list");
+ }
+}
+
+# receive handlers (from kRO ST)
+
+sub deal_add_other {
+ my ($self, $args) = @_;
+
+ if ($args->{nameID} > 0) {
+ my $item = $currentDeal{other}{ $args->{nameID} } ||= {};
+ $item->{amount} += $args->{amount};
+ $item->{nameID} = $args->{nameID};
+ $item->{identified} = $args->{identified};
+ $item->{broken} = $args->{broken};
+ $item->{upgrade} = $args->{upgrade};
+ $item->{cards} = $args->{cards};
+ $item->{name} = itemName($item);
+ message TF("%s added Item to Deal: %s x %s\n", $currentDeal{name}, $item->{name}, $args->{amount}), "deal";
+ } elsif ($args->{amount} > 0) {
+ $currentDeal{other_zeny} += $args->{amount};
+ my $amount = formatNumber($args->{amount});
+ message TF("%s added %s z to Deal\n", $currentDeal{name}, $amount), "deal";
+ }
+}
+
+sub deal_add_you {
+ my ($self, $args) = @_;
+
+ if ($args->{fail} == 1) {
+ error T("That person is overweight; you cannot trade.\n"), "deal";
+ return;
+ } elsif ($args->{fail} == 2) {
+ error T("This item cannot be traded.\n"), "deal";
+ return;
+ } elsif ($args->{fail}) {
+ error TF("You cannot trade (fail code %s).\n", $args->{fail}), "deal";
+ return;
+ }
+
+ return unless $args->{index} > 0;
+
+ my $item = $char->inventory->getByServerIndex($args->{index});
+ $currentDeal{you}{$item->{nameID}}{amount} += $currentDeal{lastItemAmount};
+ $item->{amount} -= $currentDeal{lastItemAmount};
+ message TF("You added Item to Deal: %s x %s\n", $item->{name}, $currentDeal{lastItemAmount}), "deal";
+ $itemChange{$item->{name}} -= $currentDeal{lastItemAmount};
+ $currentDeal{you_items}++;
+ $args->{item} = $item;
+ $char->inventory->remove($item) if ($item->{amount} <= 0);
+}
+
+sub deal_begin {
+ my ($self, $args) = @_;
+
+ if ($args->{type} == 0) {
+ error T("That person is too far from you to trade.\n");
+ } elsif ($args->{type} == 2) {
+ error T("That person is in another deal.\n");
+ } elsif ($args->{type} == 3) {
+ if (%incomingDeal) {
+ $currentDeal{name} = $incomingDeal{name};
+ undef %incomingDeal;
+ } else {
+ my $ID = $outgoingDeal{ID};
+ my $player;
+ $player = $playersList->getByID($ID) if (defined $ID);
+ $currentDeal{ID} = $ID;
+ if ($player) {
+ $currentDeal{name} = $player->{name};
+ } else {
+ $currentDeal{name} = 'Unknown #' . unpack("V", $ID);
+ }
+ undef %outgoingDeal;
+ }
+ message TF("Engaged Deal with %s\n", $currentDeal{name}), "deal";
+ } else {
+ error TF("Deal request failed (unknown error %s).\n", $args->{type});
+ }
+}
+
+sub deal_cancelled {
+ undef %incomingDeal;
+ undef %outgoingDeal;
+ undef %currentDeal;
+ message T("Deal Cancelled\n"), "deal";
+}
+
+sub deal_complete {
+ undef %outgoingDeal;
+ undef %incomingDeal;
+ undef %currentDeal;
+ message T("Deal Complete\n"), "deal";
+}
+
+sub deal_finalize {
+ my ($self, $args) = @_;
+ if ($args->{type} == 1) {
+ $currentDeal{other_finalize} = 1;
+ message TF("%s finalized the Deal\n", $currentDeal{name}), "deal";
+
+ } else {
+ $currentDeal{you_finalize} = 1;
+ # FIXME: shouldn't we do this when we actually complete the deal?
+ $char->{zeny} -= $currentDeal{you_zeny};
+ message T("You finalized the Deal\n"), "deal";
+ }
+}
+
+sub deal_request {
+ my ($self, $args) = @_;
+ my $level = $args->{level} || 'Unknown';
+ my $user = bytesToString($args->{user});
+
+ $incomingDeal{name} = $user;
+ $timeout{ai_dealAutoCancel}{time} = time;
+ message TF("%s (level %s) Requests a Deal\n", $user, $level), "deal";
+ message T("Type 'deal' to start dealing, or 'deal no' to deny the deal.\n"), "deal";
+}
Index: Commands.pm
===================================================================
--- Commands.pm (revision 7095)
+++ Commands.pm (working copy)
@@ -79,9 +79,9 @@
conf => \&cmdConf,
connect => \&cmdConnect,
damage => \&cmdDamage,
- deal => \&cmdDeal,
+ #deal => \&cmdDeal,
debug => \&cmdDebug,
- dl => \&cmdDealList,
+ #dl => \&cmdDealList,
doridori => \&cmdDoriDori,
drop => \&cmdDrop,
dump => \&cmdDump,
@@ -1245,6 +1245,7 @@
}
}
+=pod
sub cmdDeal {
if (!$net || $net->getState() != Network::IN_GAME) {
error TF("You must be logged in the game to use this command (%s)\n", shift);
@@ -1395,6 +1396,7 @@
message("----------------------------------\n", "list");
}
}
+=cut
sub cmdDebug {
my (undef, $args) = @_;
Index: Network/Receive.pm
===================================================================
--- Network/Receive.pm (revision 7095)
+++ Network/Receive.pm (working copy)
@@ -87,11 +87,43 @@
TF("An error occured while loading the server message parser for server type '%s':\n%s",
$type, $@)
);
- } else {
- return $class->new();
}
+
+ my $self = $class->new;
+
+ # hook all handlers from packet_list
+
+ my @handlers = grep { $self->can ($_) } keys %{{map { $_->[0] => 1 } values %{$self->{packet_list}}}};
+ # && !Plugins::hasHook ("packet_handle/$_")
+
+ if (@handlers) {
+ debug TF("Adding hooks for packet handlers in %s: %s\n", $class, join ', ', @handlers), 'network_compatibility';
+
+ Scalar::Util::weaken (my $weakSelf = $self);
+
+ my $handler = sub {
+ my (undef, $args, $callback) = @_;
+
+ $weakSelf->$callback ($args);
+ $args->{return} = 1;
+ };
+
+ $self->{recvpacketHandleHooks} = Plugins::addHooks (map { ["packet_handle/$_", $handler, $_] } @handlers);
+ }
+
+ return $self;
}
+sub DESTROY {
+ my ($self) = @_;
+
+ if ($self->{recvpacketHandleHooks}) {
+ debug T("Removing hooks for packet handlers in Network::Receive\n"), 'network_compatibility';
+
+ Plugins::delHooks ($self->{recvpacketHandleHooks});
+ }
+}
+
# $packetParser->reconstruct($args)
#
# Reconstructs a raw packet from $args using $self->{packet_list}.
@@ -138,6 +170,18 @@
}
}
+ Plugins::callHook("packet_pre/$handler->[0]", \%args);
+ Misc::checkValidity("Packet: " . $handler->[0] . " (pre)");
+ unless ($args{return}) {
+ if (Plugins::hasHook("packet_handle/$handler->[0]", \%args)) {
+ Plugins::callHook("packet_handle/$handler->[0]", \%args);
+ Misc::checkValidity("Packet: " . $handler->[0]);
+ } else {
+ warning "Packet Parser: Unhandled Packet: $switch Handler: $handler->[0]\n";
+ debug ("Unpacked: " . join(', ', @{\%args}{@{$handler->[2]}}) . "\n"), "packetParser", 2;
+ }
+ }
+=pod
my $callback = $self->can($handler->[0]);
if ($callback) {
Plugins::callHook("packet_pre/$handler->[0]", \%args);
@@ -148,6 +192,7 @@
warning "Packet Parser: Unhandled Packet: $switch Handler: $handler->[0]\n";
debug ("Unpacked: " . join(', ', @{\%args}{@{$handler->[2]}}) . "\n"), "packetParser", 2;
}
+=cut
Plugins::callHook("packet/$handler->[0]", \%args);
return \%args;