minecraft-perl/lib/POE/Component/Minecraft.pm

153 lines
3.8 KiB
Perl

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 POE::Component::SSLify; # i don't need to use this, BUT I do need to see it in the requirements
use HTTP::Request;
use Data::Dumper;
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 %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 = (%opts, @_); # we're given a hash if so
} elsif (@_ == 1) { # exactly one, must be a hashref
%opts = (%opts, %{$_[0]});
}
my $self = bless \%opts, $class;
$self->{_session} = POE::Session->create(
object_states => [
$self => {
_start => "_poe_start",
login => "_poe_login",
login_response => "_poe_login_response",
connect => "_poe_connect",
},
],
);
$self->{_http} = POE::Component::Client::HTTP->spawn(
Agent => 'Minecraft Bot 2387', # defaults to something long
Alias => $self->{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]->{alias});
}
sub _poe_login {
my $self = $_[OBJECT];
print "Doing login\n";
my $to = $self->{alias}.'UA';
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];
$res = $res->[0];
$req = $req->[0];
print "Got back login : ",$res->is_success(),"\n";
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($self->{alias}, "login");
} else {
print Dumper $self;
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;