Skip to content

Commit 73bb6a7

Browse files
committed
Implement basic functionality of mcchat2.py.
0 parents  commit 73bb6a7

File tree

8 files changed

+2884
-0
lines changed

8 files changed

+2884
-0
lines changed

en_US.lang

Lines changed: 2678 additions & 0 deletions
Large diffs are not rendered by default.

json_chat.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
from __future__ import print_function
2+
3+
from itertools import *
4+
import os.path
5+
import json
6+
import sys
7+
import re
8+
9+
class DecodeError(Exception):
10+
pass
11+
12+
def load_language(file):
13+
language = dict()
14+
for line in file:
15+
try: name, value = line.split('=', 1)
16+
except ValueError: continue
17+
language[name] = value.strip()
18+
return language
19+
20+
with open(os.path.join(os.path.dirname(__file__), './en_US.lang')) as file:
21+
language = load_language(file)
22+
23+
def decode_string(data):
24+
try:
25+
return decode_struct(json.loads(data))
26+
except DecodeError as e:
27+
print(e, file=sys.stderr)
28+
return data
29+
30+
def decode_struct(data):
31+
if type(data) is str or type(data) is unicode:
32+
return data
33+
elif type(data) is list:
34+
return ''.join(decode_struct(part) for part in data)
35+
elif type(data) is dict:
36+
if 'text' in data:
37+
result = decode_struct(data['text'])
38+
elif 'translate' in data and ('using' in data or 'with' in data):
39+
using = data.get('using') or data.get('with')
40+
using = [decode_struct(item) for item in using]
41+
result = translate(data['translate'], using)
42+
else:
43+
raise DecodeError
44+
if 'extra' in data:
45+
result += decode_struct(data['extra'])
46+
return result
47+
else:
48+
raise DecodeError
49+
50+
def translate(id, params):
51+
if id not in language: raise DecodeError
52+
53+
ord_params = params[:]
54+
def repl(match):
55+
if match.group() == '%%':
56+
return '%'
57+
elif match.group('index'):
58+
index = int(match.group('index')) - 1
59+
if index >= len(params): raise DecodeError(
60+
'Index %s in "%s" out of bounds for %s.'
61+
% (match.group(), language[id], params))
62+
param = params[index]
63+
elif match.group('rest') != '%':
64+
if not ord_params: raise DecodeError(
65+
'Too few arguments for "%s" in %s.'
66+
% (language[id], params))
67+
param = ord_params.pop(0)
68+
return ('%' + match.group('rest')) % param
69+
70+
return re.sub(
71+
r'%((?P<index>\d+)\$)?(?P<rest>(\.\d+)?[a-zA-Z%])',
72+
repl, language[id])

json_chat.pyc

2.92 KB
Binary file not shown.

lib/mcstatus

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit 2a29e1397574d91d2cf488e1fa91e84c3ff0fb98

lib/pyCraft

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit 79ee31c44e7467339ac6406d66c82788a8bed148

mcchat2.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
#!/usr/bin/env python2.7
2+
3+
from __future__ import print_function
4+
5+
import sys
6+
import time
7+
import argparse
8+
import getpass
9+
from threading import Thread, Condition
10+
import thread
11+
12+
import minecraft.authentication as authentication
13+
import minecraft.networking.connection as connection
14+
import minecraft.networking.packets as packets
15+
16+
import mcstatus
17+
import json_chat
18+
19+
KEEPALIVE_TIMEOUT_S = 20
20+
21+
def main():
22+
parser = argparse.ArgumentParser()
23+
parser.add_argument('addr', metavar='HOST[:PORT]')
24+
parser.add_argument('uname', metavar='USERNAME')
25+
parser.add_argument('pword', metavar='PASSWORD', nargs='?')
26+
parser.add_argument('--offline', dest='offline', action='store_true')
27+
28+
args = parser.parse_args()
29+
host, port = (
30+
(args.addr.rsplit(':', 1)[0], int(args.addr.rsplit(':', 1)[1]))
31+
if ':' in args.addr else (args.addr, None))
32+
offline = args.offline
33+
if args.pword is None and not offline:
34+
pword = getpass.getpass(
35+
'Enter password for %s, or leave blank for offline mode: '
36+
% args.uname)
37+
if not pword: offline = True
38+
else:
39+
pword = args.pword
40+
41+
connect(args.uname, pword, host, port, offline=offline)
42+
43+
def connect(uname, pword, host, port=None, offline=False):
44+
port = 25565 if port is None else port
45+
46+
if offline:
47+
auth = authentication.AuthenticationToken('-', '-', '-')
48+
auth.profile.id_ = '-'
49+
auth.profile.name = uname
50+
else:
51+
auth = authentication.AuthenticationToken()
52+
auth.authenticate(uname, pword)
53+
54+
conn = connection.Connection(host, port, auth)
55+
keepalive_cond = Condition()
56+
57+
conn.register_packet_listener(h_join_game,
58+
packets.JoinGamePacket)
59+
conn.register_packet_listener(h_chat_message,
60+
packets.ChatMessagePacket)
61+
conn.register_packet_listener(lambda p: h_keepalive(keepalive_cond, p),
62+
packets.KeepAlivePacket)
63+
conn.register_packet_listener(h_disconnect,
64+
packets.DisconnectPacket, packets.DisconnectPacketPlayState)
65+
66+
stdin = Thread(name='stdin', target=stdin_thread, args=(
67+
conn,))
68+
stdin.daemon = True
69+
70+
timeout = Thread(name='timeout', target=timeout_thread, args=(
71+
keepalive_cond,))
72+
timeout.daemon = True
73+
74+
conn.connect()
75+
stdin.start()
76+
timeout.start()
77+
main_thread(conn)
78+
79+
def h_join_game(packet):
80+
print('Connected to server.')
81+
82+
def h_chat_message(packet):
83+
print(json_chat.decode_string(packet.json_data))
84+
85+
def h_keepalive(keepalive_cond, packet):
86+
keepalive_cond.acquire()
87+
keepalive_cond.value = True
88+
keepalive_cond.notify_all()
89+
keepalive_cond.release()
90+
91+
def h_disconnect(packet):
92+
msg = json_chat.decode_string(packet.json_data)
93+
print('Disconnected from server: %s' % msg)
94+
thread.interrupt_main()
95+
96+
def main_thread(conn):
97+
try:
98+
while conn.networking_thread.is_alive():
99+
conn.networking_thread.join(0.1)
100+
print('Disconnected from server.')
101+
except KeyboardInterrupt as e:
102+
pass
103+
104+
def timeout_thread(keepalive_cond):
105+
while True:
106+
start = time.clock()
107+
keepalive_cond.acquire()
108+
keepalive_cond.value = False
109+
keepalive_cond.wait(KEEPALIVE_TIMEOUT_S)
110+
keepalive_cond.release()
111+
if not keepalive_cond.value: break
112+
113+
print('Disconnected from server: timed out.')
114+
thread.interrupt_main()
115+
116+
def stdin_thread(conn):
117+
def send_chat(conn, text):
118+
packet = packets.ChatPacket()
119+
packet.message = text
120+
conn.write_packet(packet)
121+
while True:
122+
text = raw_input().decode('utf8')
123+
while len(text) > 100:
124+
send_chat(text[:97] + '...')
125+
text = '...' + text[97:]
126+
if text:
127+
send_chat(conn, text)
128+
129+
if __name__ == '__main__':
130+
main()

mcstatus

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
lib/mcstatus/mcstatus/

minecraft

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
lib/pyCraft/minecraft/

0 commit comments

Comments
 (0)