Fix: 1.16.5 is erroneously marked as unsupported
[pyCraft.git] / start.py
blob353a1581183179e501fe397de8d10a904e348d26
1 #!/usr/bin/env python
3 import getpass
4 import sys
5 import re
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
14 def get_options():
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",
32 action="store_true",
33 help="print sent and received packets to standard error")
35 parser.add_option("-v", "--dump-unknown-packets", dest="dump_unknown",
36 action="store_true",
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)
55 if match is None:
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)
60 return options
63 def main():
64 options = get_options()
66 if options.offline:
67 print("Connecting in offline mode...")
68 connection = Connection(
69 options.address, options.port, username=options.username)
70 else:
71 auth_token = authentication.AuthenticationToken()
72 try:
73 auth_token.authenticate(options.username, options.password)
74 except YggdrasilError as e:
75 print(e)
76 sys.exit()
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)
89 else:
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):
101 print('Connected.')
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)
113 connection.connect()
115 while True:
116 try:
117 text = input()
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)
123 else:
124 packet = serverbound.play.ChatPacket()
125 packet.message = text
126 connection.write_packet(packet)
127 except KeyboardInterrupt:
128 print("Bye!")
129 sys.exit()
132 if __name__ == "__main__":
133 main()