diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..df154d9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.build +*~ diff --git a/dist.ini b/dist.ini index c039a4e..26c9bf4 100644 --- a/dist.ini +++ b/dist.ini @@ -6,4 +6,25 @@ copyright_year = 2011 version = 0.001 -[@Basic] +[GatherDir] +[PruneCruft] +[ManifestSkip] +[MetaYAML] +[MetaJSON] +[License] +[Readme] +[ExtraTests] +[PodCoverageTests] +[PodSyntaxTests] +[ExecDir] +[ShareDir] +[MakeMaker] +;[=inc::HailoMakeMaker / HailoMakeMaker] +;[=inc::BuildUpskirt ] +[ReadmeFromPod] +[Manifest] +[TestRelease] +[ConfirmRelease] +[UploadToCPAN] +[PkgVersion] +[@Git] diff --git a/lib/POE/Component/Minecraft.pm b/lib/POE/Component/Minecraft.pm index 55a220c..274c51d 100644 --- a/lib/POE/Component/Minecraft.pm +++ b/lib/POE/Component/Minecraft.pm @@ -2,4 +2,141 @@ use strict; use warnings; package POE::Component::Minecraft; +# ABSTRACT: Implements login and hooks for interacting with Minecraft + +use POE; +use POE::Component::Client::TCP; +use POE::Component::Client::HTTP; +use HTTP::Request; + +our $client_version = 12; # current launcher version as of October 23rd 2011, package variable to allow monkey patching to new required versions + +sub new { + my $class = shift; + my $self = bless { }, $class; + + my %opts = (username => undef, + password => undef, + server => "minecraft.net", + port => 25565, + alias => "Minecraft", + + _session => undef, + _http => undef, + _tcp => undef, + ); + + if (@_ > 1) { # do we have more than one argument left? + %opts = @_; # we're given a hash if so + } elsif (@_ == 1) { # exactly one, must be a hashref + %opts = %$_[0]; + } + $alias = "resolver" unless $alias; + + $self->{_session} = POE::Session->create( + object_states => [ + $self => { + _start => "_poe_start", + login => "_poe_login", + login_response => "_poe_login_response", + }, + ], + ); + + $self->{_http} = POE::Component::Client::HTTP->spawn( + Agent => 'Minecraft Bot 2387', # defaults to something long + Alias => 'ua', # defaults to 'weeble' + From => 'simcop2387@simcop2387.info', # defaults to undef (no header) + Timeout => 60, # defaults to 180 seconds + FollowRedirects => 2, # defaults to 0 (off) + ); + + return $self; +} + +sub _poe_start { + my $self = $_[OBJECT]; + $_[KERNEL]->alias_set("$_[OBJECT]"); +} + +sub _poe_login { + my $self = $_[OBJECT]; + + my $to = $self->{_http}->ID(); + my $req = HTTP::Request->new(POST => 'https://login.minecraft.net/'); + + $req->content_type('application/x-www-form-urlencoded'); + $req->content('user='.$self->{username}.'&password='.$self->{password}.'&version='.$client_version); + + $poe_kernel->post($to, 'request', 'login_response', $req); +} + +sub _poe_login_response { + my $self = $_[OBJECT]; + my ($req, $res) = @_[ARG0, ARG1]; + + if ($res->is_success) + { + print $res->content, "\n"; + @{$self}{qw/game_version download_ticket username_case session_id/} = split /:/, $res->content; + + $poe_kernel->post($_[SESSION], "connect"); + } + else + { + # i should have some way of giving this back to the user of the module, probably through the callback + + # $cb->(LOGIN_FAILED, $res->status_line) + print $res->status_line, "\n"; + } +} + +sub _poe_connect { + my $self = $_[OBJECT]; + + die "Not going to actually connect!" +} + +# strict object methods, these are directly called by the user of the module + +sub login { + my $self = shift; + my $cb = shift; + + $self->{_login_cb} = $cb; # save login callback + + if (defined($self->{username}) && defined($self->{password}) && + defined($self->{server}) && defined($self->{port})) { + $poe_kernel->call($_[SESSION], login); + } else { + die "No Server or credentials"; + } +} + +# ACCESORS + +sub credentials { + my ($self, $username, $password) = @_; + $self->{username} = $username if (defined($username)); + $self->{password} = $password if (defined($password)); + + return [$self->{username}, $self->{password}]; # send them back so that this is an accessor also +} + +sub server { + my ($self, $server) = @_; + + $self->{server} = $server if (defined $server); + + return $self->{server}; +} + +sub port { + my ($self, $port) = @_; + + $self->{port} = $port if defined($port); + + return $self->{port}; +} + 1; diff --git a/test.pl b/test.pl new file mode 100644 index 0000000..0b40881 --- /dev/null +++ b/test.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl + +use lib 'lib'; +use POE qw/Component::Minecraft/; + +my $username = $ARGV[0]; +my $password = $ARGV[1]; + +my $mc = POE::Component::Minecraft->new({ + username => $username, + password => $password, + server => "mythmaster", +}); + + POE::Session->create( + inline_states => { + _start => sub { + $mc->login(sub {print "woo!\n"}) + }, + }, + ); + +POE::Kernel->run(); \ No newline at end of file