6 from optparse
import OptionParser
8 from minecraft
import authentication
9 from minecraft
.exceptions
import YggdrasilError
10 from minecraft
.networking
.connection
import Connection
11 from minecraft
.networking
.packets
import Packet
, clientbound
, serverbound
15 parser
= OptionParser()
17 parser
.add_option("-u", "--username", dest
="username", default
=None,
18 help="username to log in with")
20 parser
.add_option("-p", "--password", dest
="password", default
=None,
21 help="password to log in with")
23 parser
.add_option("-s", "--server", dest
="server", default
=None,
24 help="server host or host:port "
25 "(enclose IPv6 addresses in square brackets)")
27 parser
.add_option("-o", "--offline", dest
="offline", action
="store_true",
28 help="connect to a server in offline mode "
29 "(no password required)")
31 parser
.add_option("-d", "--dump-packets", dest
="dump_packets",
33 help="print sent and received packets to standard error")
35 parser
.add_option("-v", "--dump-unknown-packets", dest
="dump_unknown",
37 help="include unknown packets in --dump-packets output")
39 (options
, args
) = parser
.parse_args()
41 if not options
.username
:
42 options
.username
= input("Enter your username: ")
44 if not options
.password
and not options
.offline
:
45 options
.password
= getpass
.getpass("Enter your password (leave "
46 "blank for offline mode): ")
47 options
.offline
= options
.offline
or (options
.password
== "")
49 if not options
.server
:
50 options
.server
= input("Enter server host or host:port "
51 "(enclose IPv6 addresses in square brackets): ")
52 # Try to split out port and address
53 match
= re
.match(r
"((?P<host>[^\[\]:]+)|\[(?P<addr>[^\[\]]+)\])"
54 r
"(:(?P<port>\d+))?$", options
.server
)
56 raise ValueError("Invalid server address: '%s'." % options
.server
)
57 options
.address
= match
.group("host") or match
.group("addr")
58 options
.port
= int(match
.group("port") or 25565)
64 options
= get_options()
67 print("Connecting in offline mode...")
68 connection
= Connection(
69 options
.address
, options
.port
, username
=options
.username
)
71 auth_token
= authentication
.AuthenticationToken()
73 auth_token
.authenticate(options
.username
, options
.password
)
74 except YggdrasilError
as e
:
77 print("Logged in as %s..." % auth_token
.username
)
78 connection
= Connection(
79 options
.address
, options
.port
, auth_token
=auth_token
)
81 if options
.dump_packets
:
82 def print_incoming(packet
):
83 if type(packet
) is Packet
:
84 # This is a direct instance of the base Packet type, meaning
85 # that it is a packet of unknown type, so we do not print it
86 # unless explicitly requested by the user.
87 if options
.dump_unknown
:
88 print('--> [unknown packet] %s' % packet
, file=sys
.stderr
)
90 print('--> %s' % packet
, file=sys
.stderr
)
92 def print_outgoing(packet
):
93 print('<-- %s' % packet
, file=sys
.stderr
)
95 connection
.register_packet_listener(
96 print_incoming
, Packet
, early
=True)
97 connection
.register_packet_listener(
98 print_outgoing
, Packet
, outgoing
=True)
100 def handle_join_game(join_game_packet
):
103 connection
.register_packet_listener(
104 handle_join_game
, clientbound
.play
.JoinGamePacket
)
106 def print_chat(chat_packet
):
107 print("Message (%s): %s" % (
108 chat_packet
.field_string('position'), chat_packet
.json_data
))
110 connection
.register_packet_listener(
111 print_chat
, clientbound
.play
.ChatMessagePacket
)
118 if text
== "/respawn":
119 print("respawning...")
120 packet
= serverbound
.play
.ClientStatusPacket()
121 packet
.action_id
= serverbound
.play
.ClientStatusPacket
.RESPAWN
122 connection
.write_packet(packet
)
124 packet
= serverbound
.play
.ChatPacket()
125 packet
.message
= text
126 connection
.write_packet(packet
)
127 except KeyboardInterrupt:
132 if __name__
== "__main__":