70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/wrapper/management/html/requests.js:
--------------------------------------------------------------------------------
1 | // Hooray, I just hit 111 commits on Wrapper.py's development branch.
2 | // Why am I saying this here? Because easter eggs.
3 | requests = {}
4 | requests.action = function(action, arguments){
5 | args = ""
6 | for(i in arguments){
7 | console.log(i)
8 | args += "&" + i + "=" + encodeURIComponent(arguments[i])
9 | if(i == undefined) continue
10 | }
11 | // console.log("GET Regular Request: /action/"+action+"?"+args)
12 | var xml = new XMLHttpRequest()
13 | xml.open("GET", "/action/"+action+"?"+args, false)
14 | xml.send()
15 | return JSON.parse(xml.responseText)
16 | }
17 | requests.admin = function(action, arguments){
18 | args = "key=" + localStorage.sessionKey
19 | for(i in arguments){
20 | if(i == undefined) continue
21 | args += "&" + i + "=" + encodeURIComponent(arguments[i])
22 | }
23 | // console.log("GET Admin Request: /action/"+action+"?"+args)
24 | var xml = new XMLHttpRequest()
25 | xml.open("GET", "/action/"+action+"?"+args, false)
26 | try{xml.send()}catch(err){return false}
27 | var response = JSON.parse(xml.responseText)
28 | if (response["status"] == "error")
29 | return false
30 | return response["payload"]
31 | }
32 | requests.adminThreaded = function(action, arguments, callBack){
33 | args = "key=" + localStorage.sessionKey
34 | for(i in arguments){
35 | if(i == undefined) continue
36 | args += "&" + i + "=" + encodeURIComponent(arguments[i])
37 | }
38 | try{
39 | var xml = new XMLHttpRequest()
40 | xml.open("GET", "/action/"+action+"?"+args, true)
41 | }catch(err){return false}
42 | try{xml.send()}catch(err){return false}
43 | xml.onreadystatechange = function(){
44 | if(xml.readyState == 4){
45 | try{
46 | var response = JSON.parse(xml.responseText)
47 | }catch(err){
48 | callBack(false)
49 | return
50 | }
51 | callBack(response["payload"])
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/wrapper/proxy/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Copyright (C) 2016, 2017 - BenBaptist and Wrapper.py developer(s).
4 | # https://github.com/benbaptist/minecraft-wrapper
5 | # This program is distributed under the terms of the GNU
6 | # General Public License, version 3 or later.
7 |
--------------------------------------------------------------------------------
/wrapper/proxy/constants.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Copyright (C) 2016, 2017 - BenBaptist and Wrapper.py developer(s).
4 | # https://github.com/benbaptist/minecraft-wrapper
5 | # This program is distributed under the terms of the GNU
6 | # General Public License, version 3 or later.
7 |
8 | # Mincraft version constants
9 | # use these constants decide how a packet should be parsed.
10 |
11 | # Still in development at versions 201-210(6/14/16)
12 |
13 |
14 | PROTOCOL_MAX = 4000
15 |
16 | PROTOCOL_1_11 = 314
17 |
18 | PROTOCOL_1_10 = 205
19 |
20 | # post- 1.9.3 "pre" releases (1.9.3 pre-2 -)
21 | PROTOCOL_1_9_4 = 110
22 |
23 | # PAGE: http://wiki.vg/index.php?title=Protocol&oldid=7817
24 | # post- 1.9 "pre" releases (1.9.2 - 1.9.3 pre-1)
25 | PROTOCOL_1_9_3PRE3 = 109
26 |
27 | # PAGE: http://wiki.vg/index.php?title=Protocol&oldid=7617
28 | # post- 1.9 "pre" releases (1.9.1 pre-3 through 1.9.1)
29 | PROTOCOL_1_9_1PRE = 108
30 | # first stable 1.9 release
31 | PROTOCOL_1_9REL1 = 107
32 |
33 | # Between 49-106, the protocol is incredibly unstable.
34 | # Packet numbers changed almost weekly. using a version in this range
35 | # will raise as UnsupportedMinecraftProtocol Exception
36 |
37 | # start of 1.9 snapshots
38 | PROTOCOL_1_9START = 48
39 |
40 | # PAGE: http://wiki.vg/index.php?title=Protocol&oldid=7368
41 | # 1.8.9
42 | PROTOCOL_1_8END = 47
43 | # 1.8 snapshots start- #
44 | PROTOCOL_1_8START = 6
45 |
46 | # PAGE: http://wiki.vg/index.php?title=Protocol&oldid=6003
47 | # 1.7.6 - 1.7.10
48 | PROTOCOL_1_7_9 = 5
49 |
50 | # PAGE: http://wiki.vg/index.php?title=Protocol&oldid=5486
51 | # 1.7.1-pre to 1.7.5
52 | PROTOCOL_1_7 = 4
53 |
54 | """Minecraft version 1.6.4 and older used a protocol versioning
55 | scheme separate from the current one. Accordingly, an old protocol
56 | version number may ambiguously refer to an one of those old versions
57 | and from the list above. Do not run a 1.6.4 server with proxy mode."""
58 |
59 | # parser constants
60 | PKT = 0
61 | PARSER = 1
62 |
63 | # Data constants
64 | # ------------------------------------------------
65 |
66 | STRING = 0
67 | JSON = 1
68 | UBYTE = 2
69 | BYTE = 3
70 | INT = 4
71 | SHORT = 5
72 | USHORT = 6
73 | LONG = 7
74 | DOUBLE = 8
75 | FLOAT = 9
76 | BOOL = 10
77 | VARINT = 11
78 | BYTEARRAY = 12
79 | BYTEARRAY_SHORT = 13
80 | POSITION = 14
81 |
82 | # gets full slot info, including NBT data.
83 | SLOT = 15
84 |
85 | # This fellow is a bit of a hack that allows getting the
86 | # basic slot data where the NBT part may be buggy or
87 | # you are not sure you are correctly parsing the NBT
88 | # data (like in older pre-1.8 minecrafts).
89 | SLOT_NO_NBT = 18
90 |
91 | UUID = 16
92 |
93 | # this is the old pre-1.9 metadata parsing.
94 | METADATA = 17
95 | # It is radically different in 1.9+ now (through 11.2 atm)
96 | METADATA_1_9 = 19
97 |
98 |
99 | # Both of these just read or send the rest of the packet in its raw bytes form.
100 | REST = 90
101 | RAW = 90
102 |
103 | # allows the insertion of padding into argument lists.
104 | # Any field with this designation is just silently skipped.
105 | NULL = 100
106 |
--------------------------------------------------------------------------------
/wrapper/proxy/mcpackets_cb.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Copyright (C) 2016, 2017 - BenBaptist and Wrapper.py developer(s).
4 | # https://github.com/benbaptist/minecraft-wrapper
5 | # This program is distributed under the terms of the GNU
6 | # General Public License, version 3 or later.
7 |
8 | from core.exceptions import UnsupportedMinecraftProtocol
9 |
10 | from proxy.constants import *
11 |
12 | """
13 | Ways to reference packets by names and not hard-coded numbers.
14 |
15 | This attempts to follow the wiki as much as possible.
16 |
17 | the ServerBound and ClientBound classes take an integer protocol argument
18 | to determine the packet values.
19 |
20 | Protocol constants are named as follows:
21 | first two digits are major version, third digit in minor version.
22 | example: PROTOCOL_1_8_9 means - version 1.8.9.
23 | Explanatory text (pre, start, etc) may be last.
24 |
25 | set something False/unimplemented using 0xEE
26 |
27 | """
28 |
29 |
30 | class Packets(object):
31 | def __init__(self, protocol):
32 |
33 | if PROTOCOL_1_8END < protocol < PROTOCOL_1_9REL1:
34 | raise UnsupportedMinecraftProtocol
35 |
36 | # Login, Status, and Ping packets
37 | # -------------------------------
38 | self.LOGIN_DISCONNECT = 0x00
39 | self.LOGIN_ENCR_REQUEST = 0x01
40 | self.LOGIN_SUCCESS = 0x02
41 | self.LOGIN_SET_COMPRESSION = 0X03
42 |
43 | # the json data represented as a string
44 | self.PING_JSON_RESPONSE = 0x00
45 | # PONG sent in response to Client PING
46 | self.PING_PONG = 0x01
47 |
48 | # play mode packets
49 | # -------------------------------
50 | # Base set 1.7 - 1.8.9 - The packet numbers were the same,
51 | # although parsing differed amongst versions
52 | self.KEEP_ALIVE = [0x00, [INT]]
53 | self.JOIN_GAME = [0x01, [INT, UBYTE, BYTE, UBYTE, UBYTE, STRING]]
54 | self.CHAT_MESSAGE = [0x02, [STRING, NULL]]
55 | self.TIME_UPDATE = 0x03
56 | self.ENTITY_EQUIPMENT = 0x04 # TODO - never parsed by wrapper
57 | self.SPAWN_POSITION = 0x05
58 | self.UPDATE_HEALTH = 0x06 # TODO - never parsed by wrapper
59 | self.RESPAWN = 0x07
60 | self.PLAYER_POSLOOK = 0x08
61 | self.HELD_ITEM_CHANGE = 0x09 # TODO - never parsed by wrapper
62 | self.USE_BED = 0x0a
63 | self.ANIMATION = 0x0b
64 | self.SPAWN_PLAYER = 0x0c
65 | self.COLLECT_ITEM = 0x0d # TODO - never parsed by wrapper
66 | self.SPAWN_OBJECT = 0x0e
67 | self.SPAWN_MOB = 0x0f
68 | self.SPAWN_PAINTING = 0x10 # TODO - never parsed by wrapper
69 | self.SPAWN_EXPERIENCE_ORB = 0x11 # TODO - never parsed by wrapper
70 | self.ENTITY_VELOCITY = 0x12 # TODO - never parsed by wrapper before
71 | self.DESTROY_ENTITIES = 0x13
72 | self.ENTITY = 0x14
73 | self.ENTITY_RELATIVE_MOVE = 0x15
74 | self.ENTITY_LOOK = 0x16 # TODO - never parsed by wrapper before
75 | self.ENTITY_LOOK_AND_RELATIVE_MOVE = 0x17 # TODO - never parsed by wrapper
76 | self.ENTITY_TELEPORT = 0x18
77 | self.ENTITY_HEAD_LOOK = 0x19
78 | self.ENTITY_STATUS = 0x1a
79 | self.ATTACH_ENTITY = 0x1b
80 | # [VARINT, METADATA] This one and NBT things are broke in 1.7
81 | self.ENTITY_METADATA = [0x1c, [VARINT, RAW]]
82 | self.ENTITY_EFFECT = 0x1d
83 | self.REMOVE_ENTITY_EFFECT = 0x1e
84 | self.SET_EXPERIENCE = 0x1f
85 | self.ENTITY_PROPERTIES = 0x20
86 | self.CHUNK_DATA = 0x21
87 | self.MULTI_BLOCK_CHANGE = 0x22 # TODO - never parsed by wrapper before
88 | self.BLOCK_CHANGE = 0x23
89 | self.BLOCK_ACTION = 0x24 # TODO - never parsed by wrapper before
90 | self.BLOCK_BREAK_ANIMATION = 0x25 # TODO - never parsed by wrapper before
91 | self.MAP_CHUNK_BULK = 0x26
92 | self.EXPLOSION = 0x27 # TODO - never parsed by wrapper before
93 | self.EFFECT = 0x28 # TODO - never parsed by wrapper before
94 | self.SOUND_EFFECT = 0x29
95 | self.PARTICLE = 0x2a
96 | self.CHANGE_GAME_STATE = 0x2b
97 | self.SPAWN_GLOBAL_ENTITY = 0x2c # TODO - never parsed by wrapper before
98 | self.OPEN_WINDOW = 0x2d
99 | self.CLOSE_WINDOW = 0x2e # TODO - never parsed by wrapper before
100 | self.SET_SLOT = 0x2f
101 | self.WINDOW_ITEMS = 0x30
102 | self.WINDOW_PROPERTY = 0x31 # TODO - never parsed by wrapper before
103 | self.CONFIRM_TRANSACTION = 0x32 # TODO - never parsed by wrapper before
104 | self.UPDATE_SIGN = 0x33 # TODO - never parsed by wrapper before
105 | self.MAP = 0x34 # TODO - never parsed by wrapper before
106 | self.UPDATE_BLOCK_ENTITY = 0x35 # TODO - never parsed by wrapper before
107 | self.OPEN_SIGN_EDITOR = 0x36 # TODO - never parsed by wrapper before
108 | self.STATISTICS = 0x37 # TODO - never parsed by wrapper before
109 | self.PLAYER_LIST_ITEM = 0x38
110 | self.PLAYER_ABILITIES = 0x39
111 | self.TAB_COMPLETE = 0x3a # TODO - never parsed by wrapper before
112 | self.SCOREBOARD_OBJECTIVE = 0x3b # TODO - never parsed by wrapper before
113 | self.UPDATE_SCORE = 0x3c # TODO - never parsed by wrapper before
114 | self.DISPLAY_SCOREBOARD = 0x3d # TODO - never parsed by wrapper before
115 | self.TEAMS = 0x3e # TODO - never parsed by wrapper before
116 | self.PLUGIN_MESSAGE = 0x3F
117 | self.DISCONNECT = 0x40
118 | self.SERVER_DIFFICULTY = 0x41 # TODO - never parsed by wrapper before
119 | self.COMBAT_EVENT = 0x42 # TODO - never parsed by wrapper before
120 | self.CAMERA = 0x43 # TODO - never parsed by wrapper before
121 | self.WORLD_BORDER = 0x44 # TODO - never parsed by wrapper before
122 | self.TITLE = 0x45 # TODO - never parsed by wrapper before
123 | self.BROKEN_SET_COMPRESSION_REMOVED1_9 = 0x46
124 | self.PLAYER_LIST_HEADER_AND_FOOTER = 0x47 # TODO - never parsed by wrapper before
125 | self.RESOURCE_PACK_SEND = 0x48
126 | self.UPDATE_ENTITY_NBT = 0x49 # TODO - never parsed by wrapper before
127 |
128 | # NEW to 1.9
129 | self.PACKET_THAT_EXISTS_IN_OTHER_PROTOCOLS_BUT_NOT_THIS_ONE = 0xee
130 | # ALL VERSIONS handle chunk unloading DIFFERENTLY - CAVEAT EMPTOR!
131 | self.UNLOAD_CHUNK = 0xee
132 | self.NAMED_SOUND_EFFECT = 0xee
133 | self.BOSS_BAR = 0xee
134 | self.SET_COOLDOWN = 0xee
135 | self.VEHICLE_MOVE = 0xee
136 | self.SET_PASSENGERS = 0xee
137 |
138 | # 1.8 changes
139 | if protocol >= PROTOCOL_1_8START:
140 | # Parsing changes
141 | self.KEEP_ALIVE[PARSER] = [VARINT]
142 | self.CHAT_MESSAGE[PARSER] = [JSON, BYTE]
143 | self.ENTITY_METADATA[PARSER] = [VARINT, METADATA]
144 |
145 | # 1.9 changes
146 | if protocol >= PROTOCOL_1_9REL1:
147 | self.SPAWN_OBJECT = 0x00
148 | self.SPAWN_EXPERIENCE_ORB = 0x01
149 | self.SPAWN_GLOBAL_ENTITY = 0x02
150 | self.SPAWN_MOB = 0x03
151 | self.SPAWN_PAINTING = 0x04
152 | self.SPAWN_PLAYER = 0x05
153 | self.ANIMATION = 0x06
154 | self.STATISTICS = 0x07
155 | self.BLOCK_BREAK_ANIMATION = 0x08
156 | self.UPDATE_BLOCK_ENTITY = 0x09
157 | self.BLOCK_ACTION = 0x0a
158 | self.BLOCK_CHANGE = 0x0b
159 | self.BOSS_BAR = 0x0c # TODO NEW
160 | self.SERVER_DIFFICULTY = 0x0d
161 | self.TAB_COMPLETE = 0x0e
162 | self.CHAT_MESSAGE[PKT] = 0x0f
163 | self.MULTI_BLOCK_CHANGE = 0x10
164 | self.CONFIRM_TRANSACTION = 0x11
165 | self.CLOSE_WINDOW = 0x12
166 | self.OPEN_WINDOW = 0x13
167 | self.WINDOW_ITEMS = 0x14
168 | self.WINDOW_PROPERTY = 0x15
169 | self.SET_SLOT = 0x16
170 | self.SET_COOLDOWN = 0x17 # TODO NEW
171 | self.PLUGIN_MESSAGE = 0x18
172 | self.NAMED_SOUND_EFFECT = 0x19 # TODO NEW
173 | self.DISCONNECT = 0x1a
174 | self.ENTITY_STATUS = 0x1b
175 | self.EXPLOSION = 0x1c
176 | # ALL VERSIONS handle chunk unloading DIFFERENTLY - CAVEAT EMPTOR!
177 | self.UNLOAD_CHUNK = 0x1d # TODO NEW
178 | self.CHANGE_GAME_STATE = 0x1e
179 | self.KEEP_ALIVE[PKT] = 0x1f
180 | self.CHUNK_DATA = 0x20
181 | self.EFFECT = 0x21
182 | self.PARTICLE = 0x22
183 | self.JOIN_GAME[PKT] = 0x23
184 | self.MAP = 0x24
185 | self.ENTITY_RELATIVE_MOVE = 0x25
186 | self.ENTITY_LOOK_AND_RELATIVE_MOVE = 0x26
187 | self.ENTITY_LOOK = 0x27
188 | self.ENTITY = 0x28
189 | self.VEHICLE_MOVE = 0x29 # TODO NEW
190 | self.OPEN_SIGN_EDITOR = 0x2a
191 | self.PLAYER_ABILITIES = 0x2b
192 | self.COMBAT_EVENT = 0x2c
193 | self.PLAYER_LIST_ITEM = 0x2d
194 | self.PLAYER_POSLOOK = 0x2e
195 | self.USE_BED = 0x2f
196 | self.DESTROY_ENTITIES = 0x30
197 | self.REMOVE_ENTITY_EFFECT = 0x31
198 | self.RESOURCE_PACK_SEND = 0x32
199 | self.RESPAWN = 0x33
200 | self.ENTITY_HEAD_LOOK = 0x34
201 | self.WORLD_BORDER = 0x35
202 | self.CAMERA = 0x36
203 | self.HELD_ITEM_CHANGE = 0x37
204 | self.DISPLAY_SCOREBOARD = 0x38
205 | self.ENTITY_METADATA = [0x39, [VARINT, METADATA_1_9]]
206 | self.ATTACH_ENTITY = 0x3a
207 | self.ENTITY_VELOCITY = 0x3b
208 | self.ENTITY_EQUIPMENT = 0x3c
209 | self.SET_EXPERIENCE = 0x3d
210 | self.UPDATE_HEALTH = 0x3e
211 | self.SCOREBOARD_OBJECTIVE = 0x3f
212 | self.SET_PASSENGERS = 0x40 # TODO NEW
213 | self.TEAMS = 0x41
214 | self.UPDATE_SCORE = 0x42
215 | self.SPAWN_POSITION = 0x43
216 | self.TIME_UPDATE = 0x44
217 | self.TITLE = 0x45 # did not change
218 | self.UPDATE_SIGN = 0x46
219 | self.SOUND_EFFECT = 0x47
220 | self.PLAYER_LIST_HEADER_AND_FOOTER = 0x48
221 | self.COLLECT_ITEM = 0x49
222 | self.ENTITY_TELEPORT = 0x4a
223 | self.ENTITY_PROPERTIES = 0x4b
224 | self.ENTITY_EFFECT = 0x4c
225 |
226 | # removed
227 | self.UPDATE_ENTITY_NBT = 0xee
228 | self.MAP_CHUNK_BULK = 0xee
229 | self.BROKEN_SET_COMPRESSION_REMOVED1_9 = 0xee
230 |
231 | # parsing changes
232 | self.JOIN_GAME[PARSER] = [INT, UBYTE, INT, UBYTE, UBYTE, STRING]
233 |
234 | # 1.9.4 - 1.11 changes
235 | # http://wiki.vg/index.php?title=Protocol&oldid=7819#Entity_Properties
236 | # still good packet numbers through protocol 315
237 | if protocol > PROTOCOL_1_9_4:
238 | self.UPDATE_SIGN = 0xee
239 | self.SOUND_EFFECT = 0x46
240 | self.PLAYER_LIST_HEADER_AND_FOOTER = 0x47
241 | self.COLLECT_ITEM = 0x48
242 | self.ENTITY_TELEPORT = 0x49
243 | self.ENTITY_PROPERTIES = 0x4a
244 | self.ENTITY_EFFECT = 0x4b
245 |
--------------------------------------------------------------------------------
/wrapper/proxy/mcpackets_sb.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Copyright (C) 2016, 2017 - BenBaptist and Wrapper.py developer(s).
4 | # https://github.com/benbaptist/minecraft-wrapper
5 | # This program is distributed under the terms of the GNU
6 | # General Public License, version 3 or later.
7 |
8 | from core.exceptions import UnsupportedMinecraftProtocol
9 |
10 | from proxy.constants import *
11 |
12 | """
13 | Ways to reference packets by names and not hard-coded numbers.
14 |
15 | This attempts to follow the wiki as much as possible.
16 |
17 | the ServerBound and ClientBound classes take an integer protocol argument
18 | to determine the packet values.
19 |
20 | Protocol constants are named as follows:
21 | first two digits are major version, third digit in minor version.
22 | example: PROTOCOL_1_8_9 means - version 1.8.9.
23 | Explanatory text (pre, start, etc) may be last.
24 |
25 | set something False/unimplemented using 0xEE
26 |
27 | """
28 |
29 |
30 | class Packets(object):
31 | def __init__(self, protocol):
32 |
33 | if PROTOCOL_1_8END < protocol < PROTOCOL_1_9REL1:
34 | raise UnsupportedMinecraftProtocol
35 |
36 | # Login, Status, and Ping packets
37 | # -------------------------------
38 | # set server to STATUS(1) or LOGIN(2) mode.
39 | self.HANDSHAKE = 0x00
40 | # Server sends server json list data in response packet
41 | self.REQUEST = 0x00
42 | # server responds with a PONG
43 | self.STATUS_PING = 0x01
44 | # contains the "name" of user. Sent after handshake for LOGIN
45 | self.LOGIN_START = 0x00
46 | # client response to ENCR_REQUEST
47 | self.LOGIN_ENCR_RESPONSE = 0x01
48 |
49 | # Play packets
50 | # -------------------------------
51 | # 1.7 - 1.7.10 PLAY packets
52 | self.KEEP_ALIVE = [0x00, [INT]]
53 | self.CHAT_MESSAGE = 0x01
54 | self.USE_ENTITY = 0x02
55 | self.PLAYER = 0x03
56 | self.PLAYER_POSITION = 0x04
57 | self.PLAYER_LOOK = 0x05
58 | self.PLAYER_POSLOOK = 0x06
59 | self.PLAYER_DIGGING = 0x07
60 | self.PLAYER_BLOCK_PLACEMENT = 0x08
61 | self.HELD_ITEM_CHANGE = 0x09
62 | self.ANIMATION = 0x0a # TODO NEW
63 | self.ENTITY_ACTION = 0x0b # TODO NEW
64 | self.STEER_VEHICLE = 0x0c # TODO NEW
65 | self.CLOSE_WINDOW = 0x0b # TODO NEW
66 | self.CLICK_WINDOW = 0x0e
67 | self.CONFIRM_TRANSACTION = 0x0f # TODO NEW
68 | self.CREATIVE_INVENTORY_ACTION = 0x10 # TODO NEW
69 | self.ENCHANT_ITEM = 0x11 # TODO NEW
70 | self.PLAYER_UPDATE_SIGN = 0x12
71 | self.PLAYER_ABILITIES = 0x13
72 | self.TAB_COMPLETE = 0x14 # TODO NEW
73 | self.CLIENT_SETTINGS = 0x15
74 | self.CLIENT_STATUS = 0x16
75 | self.PLUGIN_MESSAGE = 0x17
76 |
77 | # new packets unimplemented in 1.7
78 | self.SPECTATE = 0xee
79 | self.RESOURCE_PACK_STATUS = 0xee
80 | self.TELEPORT_CONFIRM = 0xee
81 | self.USE_ITEM = 0xee
82 | self.VEHICLE_MOVE = 0xee
83 | self.STEER_BOAT = 0xee
84 |
85 | # Parsing changes
86 | if protocol >= PROTOCOL_1_8START:
87 | self.KEEP_ALIVE[PARSER] = [VARINT]
88 |
89 | if PROTOCOL_1_9START > protocol >= PROTOCOL_1_8START:
90 | self.SPECTATE = 0x18
91 | self.RESOURCE_PACK_STATUS = 0x19
92 |
93 | # 1.9
94 | if protocol >= PROTOCOL_1_9REL1:
95 | self.TELEPORT_CONFIRM = 0x00
96 | self.TAB_COMPLETE = 0x01 # TODO NEW
97 | self.CHAT_MESSAGE = 0x02
98 | self.CLIENT_STATUS = 0x03
99 | self.CLIENT_SETTINGS = 0x04
100 | self.CONFIRM_TRANSACTION = 0x05 # TODO NEW
101 | self.ENCHANT_ITEM = 0x06 # TODO NEW
102 | self.CLICK_WINDOW = 0x07
103 | self.CLOSE_WINDOW = 0x08 # TODO NEW
104 | self.PLUGIN_MESSAGE = 0x09
105 | self.USE_ENTITY = 0x0a
106 | self.KEEP_ALIVE[PKT] = 0x0b
107 | self.PLAYER_POSITION = 0x0c
108 | self.PLAYER_POSLOOK = 0x0d
109 | self.PLAYER_LOOK = 0x0e
110 | self.PLAYER = 0x0f
111 | self.VEHICLE_MOVE = 0x10 # TODO NEW
112 | self.STEER_BOAT = 0x11 # TODO NEW
113 | self.PLAYER_ABILITIES = 0x12
114 | self.PLAYER_DIGGING = 0x13
115 | self.ENTITY_ACTION = 0x14 # TODO NEW
116 | self.STEER_VEHICLE = 0x15 # TODO NEW
117 | self.RESOURCE_PACK_STATUS = 0x16 # TODO NEW
118 | self.HELD_ITEM_CHANGE = 0x17
119 | self.CREATIVE_INVENTORY_ACTION = 0x18 # TODO NEW
120 | self.PLAYER_UPDATE_SIGN = 0x19
121 | self.ANIMATION = 0x1a # TODO NEW
122 | self.SPECTATE = 0x1b
123 | self.PLAYER_BLOCK_PLACEMENT = 0x1c
124 | self.USE_ITEM = 0x1d
125 |
--------------------------------------------------------------------------------
/wrapper/proxy/serverconnection.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Copyright (C) 2016, 2017 - BenBaptist and Wrapper.py developer(s).
4 | # https://github.com/benbaptist/minecraft-wrapper
5 | # This program is distributed under the terms of the GNU
6 | # General Public License, version 3 or later.
7 |
8 | # standard
9 | import socket
10 | import threading
11 | import time
12 | import traceback
13 |
14 | # local
15 | from proxy.packet import Packet
16 | from proxy.parse_cb import ParseCB
17 | from proxy import mcpackets_sb
18 | from proxy import mcpackets_cb
19 |
20 | from proxy.constants import *
21 |
22 |
23 | # noinspection PyMethodMayBeStatic
24 | class ServerConnection(object):
25 | def __init__(self, client, ip=None, port=None):
26 | """
27 | This class ServerConnection is a "fake" client connecting
28 | to the server. It receives "CLIENT BOUND" packets from
29 | server, parses them, and forards them on to the client.
30 |
31 | ServerConnection receives the parent client as it's argument.
32 | It's wrapper and proxy instances are passed from the Client.
33 | Therefore, a server instance does not really validly exist
34 | unless it has a valid parent client.
35 |
36 | Client, by contrast, can exist and run in the absence
37 | of a server.
38 | """
39 |
40 | # TODO server needs to be a true child of clientconnection process.
41 | # It should not close its own instance, etc
42 |
43 | # basic __init__ items from passed arguments
44 | self.client = client
45 | self.wrapper = client.wrapper
46 | self.proxy = client.proxy
47 | self.log = client.wrapper.log
48 | self.ip = ip
49 | self.port = port
50 |
51 | # server setup and operating paramenters
52 | self.abort = False
53 | self.state = self.proxy.HANDSHAKE
54 | self.packet = None
55 | self.parse_cb = None
56 | self.buildmode = False
57 |
58 | # dictionary of parser packet constants and associated parsing methods
59 | self.parsers = {}
60 |
61 | self.infos_debug = "(player=%s, IP=%s, Port=%s)" % (
62 | self.client.username, self.ip, self.port)
63 | self.version = -1
64 |
65 | # self parsers get updated here
66 | self._refresh_server_version()
67 |
68 | # temporary assignment. The actual socket is assigned later.
69 | self.server_socket = socket.socket()
70 |
71 | self.infos_debug = "(player=%s, IP=%s, Port=%s)" % (
72 | self.client.username, self.ip, self.port)
73 |
74 | def _refresh_server_version(self):
75 | """Get serverversion for mcpackets use"""
76 |
77 | self.version = self.wrapper.javaserver.protocolVersion
78 | self.pktSB = mcpackets_sb.Packets(self.version)
79 | self.pktCB = mcpackets_cb.Packets(self.version)
80 | self.parse_cb = ParseCB(self, self.packet)
81 | self._define_parsers()
82 |
83 | if self.version > PROTOCOL_1_7:
84 | # used by ban code to enable wrapper group help for ban items.
85 | self.wrapper.api.registerPermission("mc1.7.6", value=True)
86 |
87 | def send(self, packetid, xpr, payload):
88 | """ Not supported. A wrapper of packet.send(), which is
89 | further a wrapper for packet.sendpkt(); both wrappers
90 | exist for older code compatability purposes only for
91 | 0.7.x version plugins that might use it."""
92 |
93 | self.log.debug("deprecated server.send() called. Use "
94 | "server.packet.sendpkt() for best performance.")
95 | self.packet.send(packetid, xpr, payload)
96 | pass
97 |
98 | def connect(self):
99 | """ This simply establishes the tcp socket connection and
100 | starts the flush loop, NOTHING MORE. """
101 | self.state = self.proxy.LOGIN
102 | # Connect to this wrapper's javaserver (core/mcserver.py)
103 | if self.ip is None:
104 | self.server_socket.connect(("localhost",
105 | self.wrapper.javaserver.server_port))
106 |
107 | # Connect to some other server (or an offline wrapper)
108 | else:
109 | self.server_socket.connect((self.ip, self.port))
110 |
111 | # start packet handler
112 | self.packet = Packet(self.server_socket, self)
113 | self.packet.version = self.client.clientversion
114 |
115 | # define parsers
116 | self.parse_cb = ParseCB(self, self.packet)
117 | self._define_parsers()
118 |
119 | t = threading.Thread(target=self.flush_loop, args=())
120 | t.daemon = True
121 | t.start()
122 |
123 | def close_server(self, reason="Disconnected", lobby_return=False):
124 | """
125 | :lobby_return: determines whether the client should be
126 | aborted too.
127 | :return:
128 | """
129 |
130 | # todo remove this and fix reason code
131 | # print(reason)
132 |
133 | if lobby_return:
134 | # stop parsing PLAY packets to prevent further "disconnects"
135 | self.state = self.proxy.LOBBY
136 | self.log.debug("Disconnecting proxy server socket connection."
137 | " %s", self.infos_debug)
138 |
139 | # end 'handle' cleanly
140 | self.abort = True
141 | time.sleep(0.1)
142 | # noinspection PyBroadException
143 | try:
144 | self.server_socket.shutdown(2)
145 | self.log.debug("Sucessfully closed server socket for"
146 | " %s", self.infos_debug)
147 |
148 | # todo - we need to discover our expected exception
149 | except:
150 | self.log.debug("Server socket for %s already "
151 | "closed", self.infos_debug)
152 | pass
153 |
154 | if not lobby_return:
155 | self.client.abort = True
156 |
157 | # allow packet to be GC'ed
158 | self.packet = None
159 |
160 | def flush_loop(self):
161 | while not self.abort:
162 | try:
163 | self.packet.flush()
164 | except socket.error:
165 | self.log.debug("Socket_error- server socket was closed"
166 | " %s", self.infos_debug)
167 | break
168 | time.sleep(0.01)
169 | self.log.debug("server connection flush_loop thread ended."
170 | " %s", self.infos_debug)
171 |
172 | def handle(self):
173 | while not self.abort:
174 | # get packet
175 | try:
176 | pkid, original = self.packet.grabpacket()
177 | except EOFError as eof:
178 | # This error is often erroneous, see
179 | # https://github.com/suresttexas00/minecraft-wrapper/issues/30
180 | self.log.debug("%s server Packet EOF"
181 | " (%s)", self.infos_debug, eof)
182 | return self._break_handle()
183 |
184 | # Bad file descriptor occurs anytime a socket is closed.
185 | except socket.error:
186 | self.log.debug("%s Failed to grab packet [SERVER]"
187 | " socket error", self.infos_debug)
188 | return self._break_handle()
189 | except Exception as e:
190 | # anything that gets here is a bona-fide error we
191 | # need to become aware of
192 | self.log.debug("%s Failed to grab packet [SERVER]"
193 | " (%s):", self.infos_debug, e)
194 | return self._break_handle()
195 |
196 | # parse it
197 | if self.parse(pkid) and self.client.state in (
198 | self.proxy.PLAY, self.proxy.LOBBY):
199 | try:
200 | self.client.packet.send_raw(original)
201 | if self.proxy.trace:
202 | self._do_trace(pkid, self.state)
203 |
204 | except Exception as e:
205 | self.log.debug("[SERVER %s] Could not send packet"
206 | " (%s): (%s): \n%s",
207 | self.infos_debug, pkid, e, traceback)
208 | return self._break_handle()
209 |
210 | def _do_trace(self, pkid, state):
211 | name = str(self.parsers[state][pkid]).split(" ")[0]
212 | if pkid not in self.proxy.ignoredCB:
213 | self.log.warn("<=CB %s (%s)", hex(pkid), name)
214 |
215 | def _break_handle(self):
216 | if self.state == self.proxy.LOBBY:
217 | self.log.info("%s is without a server now.", self.client.username)
218 | # self.close_server("%s server connection closing..." %
219 | # self.client.username, lobby_return=True)
220 | else:
221 | self.close_server("%s server connection"
222 | " closing..." % self.client.username)
223 | return
224 |
225 | def _parse_keep_alive(self):
226 | data = self.packet.readpkt(
227 | self.pktSB.KEEP_ALIVE[PARSER])
228 | self.packet.sendpkt(
229 | self.pktSB.KEEP_ALIVE[PKT],
230 | self.pktSB.KEEP_ALIVE[PARSER],
231 | data)
232 | return False
233 |
234 | def _transmit_upstream(self):
235 | """ transmit wrapper channel status info to the server's
236 | direction to help sync hub/lobby wrappers """
237 |
238 | channel = "WRAPPER|SYNC"
239 |
240 | # received SYNC from the client (this is a child wrapper)
241 | received = self.proxy.shared["received"]
242 |
243 | # if true, this is a multiworld (child wrapper instance)
244 | sent = self.proxy.shared["sent"]
245 | state = self.state
246 |
247 | if self.version < PROTOCOL_1_8START:
248 | self.packet.sendpkt(
249 | self.pktCB.PLUGIN_MESSAGE,
250 | [STRING, SHORT, BOOL, BOOL, BYTE],
251 | [channel, 3, received, sent, state])
252 | else:
253 | self.packet.sendpkt(
254 | self.pktCB.PLUGIN_MESSAGE,
255 | [STRING, BOOL, BOOL, BYTE],
256 | [channel, received, sent, state])
257 |
258 | # PARSERS SECTION
259 | # -----------------------------
260 |
261 | # Login parsers
262 | # -----------------------
263 | def _parse_login_disconnect(self):
264 | message = self.packet.readpkt([STRING])
265 | self.log.info("Disconnected from server: %s", message)
266 | self.close_server(message)
267 | return False
268 |
269 | def _parse_login_encr_request(self):
270 | self.close_server("Server is in online mode. Please turn it off "
271 | "in server.properties and allow wrapper to "
272 | "handle the authetication.")
273 | return False
274 |
275 | # Login Success - UUID & Username are sent in this packet as strings
276 | def _parse_login_success(self):
277 | self.state = self.proxy.PLAY
278 | # todo - we may not need to assign this to a variable.
279 | # (we supplied uuid/name anyway!)
280 | # noinspection PyUnusedLocal
281 | data = self.packet.readpkt([STRING, STRING])
282 | return False
283 |
284 | def _parse_login_set_compression(self):
285 | data = self.packet.readpkt([VARINT])
286 | # ("varint:threshold")
287 | if data[0] != -1:
288 | self.packet.compression = True
289 | self.packet.compressThreshold = data[0]
290 | else:
291 | self.packet.compression = False
292 | self.packet.compressThreshold = -1
293 | time.sleep(10)
294 | return # False
295 |
296 | # Lobby parsers
297 | # -----------------------
298 | def _parse_lobby_disconnect(self):
299 | message = self.packet.readpkt([JSON])
300 | self.log.info("%s went back to Hub", self.client.username)
301 | self.close_server(message, lobby_return=True)
302 |
303 | def parse(self, pkid):
304 | try:
305 | return self.parsers[self.state][pkid]()
306 | except KeyError:
307 | self.parsers[self.state][pkid] = self._parse_built
308 | if self.buildmode:
309 | # some code here to document un-parsed packets?
310 | pass
311 | return True
312 |
313 | # Do nothing parser
314 | def _parse_built(self):
315 | return True
316 |
317 | def _define_parsers(self):
318 | # the packets we parse and the methods that parse them.
319 | self.parsers = {
320 | self.proxy.HANDSHAKE: {}, # maps identically to OFFLINE ( '0' )
321 | self.proxy.LOGIN: {
322 | self.pktCB.LOGIN_DISCONNECT:
323 | self._parse_login_disconnect,
324 | self.pktCB.LOGIN_ENCR_REQUEST:
325 | self._parse_login_encr_request,
326 | self.pktCB.LOGIN_SUCCESS:
327 | self._parse_login_success,
328 | self.pktCB.LOGIN_SET_COMPRESSION:
329 | self._parse_login_set_compression
330 | },
331 | self.proxy.PLAY: {
332 | self.pktCB.COMBAT_EVENT:
333 | self.parse_cb.parse_play_combat_event,
334 | self.pktCB.KEEP_ALIVE[PKT]:
335 | self._parse_keep_alive,
336 | self.pktCB.CHAT_MESSAGE[PKT]:
337 | self.parse_cb.parse_play_chat_message,
338 | self.pktCB.JOIN_GAME[PKT]:
339 | self.parse_cb.parse_play_join_game,
340 | self.pktCB.TIME_UPDATE:
341 | self.parse_cb.parse_play_time_update,
342 | self.pktCB.SPAWN_POSITION:
343 | self.parse_cb.parse_play_spawn_position,
344 | self.pktCB.RESPAWN:
345 | self.parse_cb.parse_play_respawn,
346 | self.pktCB.PLAYER_POSLOOK:
347 | self.parse_cb.parse_play_player_poslook,
348 | self.pktCB.USE_BED:
349 | self.parse_cb.parse_play_use_bed,
350 | self.pktCB.SPAWN_PLAYER:
351 | self.parse_cb.parse_play_spawn_player,
352 | self.pktCB.SPAWN_OBJECT:
353 | self.parse_cb.parse_play_spawn_object,
354 | self.pktCB.SPAWN_MOB:
355 | self.parse_cb.parse_play_spawn_mob,
356 | self.pktCB.ENTITY_RELATIVE_MOVE:
357 | self.parse_cb.parse_play_entity_relative_move,
358 | self.pktCB.ENTITY_TELEPORT:
359 | self.parse_cb.parse_play_entity_teleport,
360 | self.pktCB.ATTACH_ENTITY:
361 | self.parse_cb.parse_play_attach_entity,
362 | self.pktCB.DESTROY_ENTITIES:
363 | self.parse_cb.parse_play_destroy_entities,
364 | self.pktCB.MAP_CHUNK_BULK:
365 | self.parse_cb.parse_play_map_chunk_bulk,
366 | self.pktCB.CHANGE_GAME_STATE:
367 | self.parse_cb.parse_play_change_game_state,
368 | self.pktCB.OPEN_WINDOW:
369 | self.parse_cb.parse_play_open_window,
370 | self.pktCB.SET_SLOT:
371 | self.parse_cb.parse_play_set_slot,
372 | self.pktCB.WINDOW_ITEMS:
373 | self.parse_cb.parse_play_window_items,
374 | self.pktCB.ENTITY_PROPERTIES:
375 | self.parse_cb.parse_play_entity_properties,
376 | self.pktCB.PLAYER_LIST_ITEM:
377 | self.parse_cb.parse_play_player_list_item,
378 | self.pktCB.DISCONNECT:
379 | self.parse_cb.parse_play_disconnect,
380 | self.pktCB.ENTITY_METADATA[PKT]:
381 | self.parse_cb.parse_entity_metadata,
382 | },
383 | self.proxy.LOBBY: {
384 | self.pktCB.DISCONNECT:
385 | self._parse_lobby_disconnect,
386 | self.pktCB.KEEP_ALIVE[PKT]:
387 | self._parse_keep_alive
388 | }
389 | }
390 |
--------------------------------------------------------------------------------
/wrapper/test.py:
--------------------------------------------------------------------------------
1 | import api
2 |
3 | from api.base import API
4 |
5 | #from api.base import API
6 | api = API(wrapper, "Web", internal=True)
7 | world = api.minecraft.getWorld()
--------------------------------------------------------------------------------
/wrapper/utils/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Copyright (C) 2016, 2017 - BenBaptist and Wrapper.py developer(s).
4 | # https://github.com/benbaptist/minecraft-wrapper
5 | # This program is distributed under the terms of the GNU
6 | # General Public License, version 3 or later.
7 |
--------------------------------------------------------------------------------
/wrapper/utils/encryption.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Copyright (C) 2016, 2017 - BenBaptist and Wrapper.py developer(s).
4 | # https://github.com/benbaptist/minecraft-wrapper
5 | # This program is distributed under the terms of the GNU
6 | # General Public License, version 3 or later.
7 |
8 |
9 | from Crypto.PublicKey import RSA
10 | from Crypto import Random
11 | from Crypto.Cipher import AES
12 |
13 | # Py3-2
14 | import sys
15 | PY3 = sys.version_info > (3,)
16 |
17 |
18 | def decode_public_key(thebytes):
19 | """Decodes a public RSA key in ASN.1 format as defined by x.509"""
20 | return RSA.importKey(thebytes)
21 |
22 |
23 | def encode_public_key(key):
24 | """Encodes a public RSA key in ASN.1 format as defined by x.509"""
25 | return key.publickey().exportKey(format="DER")
26 |
27 |
28 | def generate_key_pair():
29 | """Generates a 1024 bit RSA key pair"""
30 | return RSA.generate(1024)
31 |
32 |
33 | def generate_random_bytes(length):
34 | return Random.get_random_bytes(length)
35 |
36 |
37 | def generate_server_id():
38 | """Generates 20 random hex characters"""
39 | if PY3:
40 | return "".join("%02x" % c for c in generate_random_bytes(10))
41 | else:
42 | return "".join("%02x" % ord(c) for c in generate_random_bytes(10))
43 |
44 |
45 | def generate_challenge_token():
46 | """Generates 4 random bytes"""
47 | return generate_random_bytes(4)
48 |
49 |
50 | def decrypt_shared_secret(encrypted_key, private_key):
51 | """Decrypts the PKCS#1 padded shared secret using the private RSA key"""
52 | return _pkcs1_unpad(private_key.decrypt(encrypted_key))
53 |
54 |
55 | # noinspection PyPep8Naming
56 | def AES128CFB8(shared_secret):
57 | """Creates a AES128 stream cipher using cfb8 mode"""
58 | return AES.new(shared_secret, AES.MODE_CFB, shared_secret)
59 |
60 |
61 | def _pkcs1_unpad(thebytes):
62 | null_byte = '\x00'
63 | if PY3:
64 | null_byte = 0x00
65 | pos = thebytes.find(null_byte)
66 | if pos > 0:
67 | return thebytes[pos + 1:]
68 |
--------------------------------------------------------------------------------
/wrapper/utils/entities.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Copyright (C) 2016, 2017 - BenBaptist and Wrapper.py developer(s).
4 | # https://github.com/benbaptist/minecraft-wrapper
5 | # This program is distributed under the terms of the GNU
6 | # General Public License, version 3 or later.
7 | PRE1_11_RENAMES = {
8 | # Mob Entities
9 | "chest_minecart": "MinecartChest",
10 | "commandblock_minecart": "MinecartCommandBlock",
11 | "egg": "ThrownEgg",
12 | "ender_pearl": "ThrownEnderpearl",
13 | "falling_block": "FallingSand",
14 | "fireworks_rocket": "FireworksRocketEntity",
15 | "furnace_minecart": "MinecartFurnace",
16 | "hopper_minecart": "MinecartHopper",
17 | "horse": "EntityHorse",
18 | "magma_cube": "LavaSlime",
19 | "minecart": "MinecartRideable",
20 | "mooshroom": "MushroomCow",
21 | "ocelot": "Ozelot",
22 | "potion": "ThrownPotion",
23 | "spawner_minecart": "MinecartSpawner",
24 | "tnt": "PrimedTnt",
25 | "tnt_minecart": "MinecartTNT",
26 | "wither": "WitherBoss",
27 | "xp_bottle": "ThrownExpBottle",
28 | "xp_orb": "XPOrb",
29 | "zombie_pigman": "PigZombie",
30 | # Block Entities
31 | "brewing_stand": "Cauldron",
32 | "command_block": "Control",
33 | "daylight_detector": "DLDetector",
34 | "dispenser": "Trap",
35 | "enchanting_table": "EnchantTable",
36 | "end_portal": "AirPortal",
37 | "jukebox": "RecordPlayer",
38 | "noteblock": "Music",
39 | "structure_block": "Structure",
40 | }
41 |
42 |
43 | ENTITIES = {
44 | 1: {
45 | "name": "item"
46 | },
47 | 2: {
48 | "name": "xp_orb"
49 | },
50 | 3: {
51 | "name": "area_effect_cloud"
52 | },
53 | 4: {
54 | "name": "elder_guardian"
55 | },
56 | 5: {
57 | "name": "wither_skeleton"
58 | },
59 | 6: {
60 | "name": "stray"
61 | },
62 | 7: {
63 | "name": "egg"
64 | },
65 | 8: {
66 | "name": "leash_knot"
67 | },
68 | 9: {
69 | "name": "painting"
70 | },
71 | 10: {
72 | "name": "arrow"
73 | },
74 | 11: {
75 | "name": "snowball"
76 | },
77 | 12: {
78 | "name": "fireball"
79 | },
80 | 13: {
81 | "name": "small_fireball"
82 | },
83 | 14: {
84 | "name": "ender_pearl"
85 | },
86 | 15: {
87 | "name": "eye_of_ender_signal"
88 | },
89 | 16: {
90 | "name": "potion"
91 | },
92 | 17: {
93 | "name": "xp_bottle"
94 | },
95 | 18: {
96 | "name": "item_frame"
97 | },
98 | 19: {
99 | "name": "wither_skull"
100 | },
101 | 20: {
102 | "name": "tnt"
103 | },
104 | 21: {
105 | "name": "falling_block"
106 | },
107 | 22: {
108 | "name": "fireworks_rocket"
109 | },
110 | 23: {
111 | "name": "husk"
112 | },
113 | 24: {
114 | "name": "spectral_arrow"
115 | },
116 | 25: {
117 | "name": "shulker_bullet"
118 | },
119 | 26: {
120 | "name": "dragon_fireball"
121 | },
122 | 27: {
123 | "name": "zombie_villager"
124 | },
125 | 28: {
126 | "name": "skeleton_horse"
127 | },
128 | 29: {
129 | "name": "zombie_horse"
130 | },
131 | 30: {
132 | "name": "armor_stand"
133 | },
134 | 31: {
135 | "name": "donkey"
136 | },
137 | 32: {
138 | "name": "mule"
139 | },
140 | 33: {
141 | "name": "evocation_fangs"
142 | },
143 | 34: {
144 | "name": "evocation_illager"
145 | },
146 | 35: {
147 | "name": "vex"
148 | },
149 | 36: {
150 | "name": "vindication_illager"
151 | },
152 | 40: {
153 | "name": "commandblock_minecart"
154 | },
155 | 41: {
156 | "name": "boat"
157 | },
158 | 42: {
159 | "name": "minecart"
160 | },
161 | 43: {
162 | "name": "chest_minecart"
163 | },
164 | 44: {
165 | "name": "furnace_minecart"
166 | },
167 | 45: {
168 | "name": "tnt_minecart"
169 | },
170 | 46: {
171 | "name": "hopper_minecart"
172 | },
173 | 47: {
174 | "name": "spawner_minecart"
175 | },
176 | 50: {
177 | "name": "creeper"
178 | },
179 | 51: {
180 | "name": "skeleton"
181 | },
182 | 52: {
183 | "name": "spider"
184 | },
185 | 53: {
186 | "name": "giant"
187 | },
188 | 54: {
189 | "name": "zombie"
190 | },
191 | 55: {
192 | "name": "slime"
193 | },
194 | 56: {
195 | "name": "ghast"
196 | },
197 | 57: {
198 | "name": "zombie_pigman"
199 | },
200 | 58: {
201 | "name": "enderman"
202 | },
203 | 59: {
204 | "name": "cave_spider"
205 | },
206 | 60: {
207 | "name": "silverfish"
208 | },
209 | 61: {
210 | "name": "blaze"
211 | },
212 | 62: {
213 | "name": "magma_cube"
214 | },
215 | 63: {
216 | "name": "ender_dragon"
217 | },
218 | 64: {
219 | "name": "wither"
220 | },
221 | 65: {
222 | "name": "bat"
223 | },
224 | 66: {
225 | "name": "witch"
226 | },
227 | 67: {
228 | "name": "endermite"
229 | },
230 | 68: {
231 | "name": "guardian"
232 | },
233 | 69: {
234 | "name": "shulker"
235 | },
236 | 90: {
237 | "name": "pig"
238 | },
239 | 91: {
240 | "name": "sheep"
241 | },
242 | 92: {
243 | "name": "cow"
244 | },
245 | 93: {
246 | "name": "chicken"
247 | },
248 | 94: {
249 | "name": "squid"
250 | },
251 | 95: {
252 | "name": "wolf"
253 | },
254 | 96: {
255 | "name": "mooshroom"
256 | },
257 | 97: {
258 | "name": "snowman"
259 | },
260 | 98: {
261 | "name": "ocelot"
262 | },
263 | 99: {
264 | "name": "villager_golem"
265 | },
266 | 100: {
267 | "name": "horse"
268 | },
269 | 101: {
270 | "name": "rabbit"
271 | },
272 | 102: {
273 | "name": "polar_bear"
274 | },
275 | 103: {
276 | "name": "llama"
277 | },
278 | 104: {
279 | "name": "llama_spit"
280 | },
281 | 120: {
282 | "name": "villager"
283 | },
284 | 200: {
285 | "name": "ender_crystal"
286 | }
287 | }
288 |
--------------------------------------------------------------------------------
/wrapper/utils/log.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Copyright (C) 2016, 2017 - BenBaptist and Wrapper.py developer(s).
4 | # https://github.com/benbaptist/minecraft-wrapper
5 | # This program is distributed under the terms of the GNU
6 | # General Public License, version 3 or later.
7 |
8 | import json
9 | import os
10 | import logging
11 | from logging.config import dictConfig
12 |
13 | # noinspection PyProtectedMember
14 | from api.helpers import mkdir_p, _use_style
15 |
16 | DEFAULT = {
17 | "wrapperversion": 1.2,
18 | "version": 1,
19 | "disable_existing_loggers": False,
20 | "formatters": {
21 | "standard": {
22 | "()": "utils.log.ColorFormatter",
23 | "format": "[%(asctime)s] [%(name)s/%(levelname)s]: %(message)s",
24 | "datefmt": "%H:%M:%S"
25 | },
26 | "file": {
27 | "format": "[%(asctime)s] [%(name)s/%(levelname)s]: %(message)s",
28 | "datefmt": "%Y-%m-%d %H:%M:%S"
29 | }
30 | },
31 | "handlers": {
32 | "console": {
33 | "class": "logging.StreamHandler",
34 | "level": "INFO",
35 | "formatter": "standard",
36 | "filters": [],
37 | "stream": "ext://sys.stdout"
38 | },
39 | "wrapper_file_handler": {
40 | "class": "utils.log.WrapperHandler",
41 | "level": "INFO",
42 | "formatter": "file",
43 | "filters": [],
44 | "filename": "logs/wrapper/wrapper.log",
45 | "maxBytes": 10485760,
46 | "backupCount": 20,
47 | "encoding": "utf8"
48 | },
49 | "error_file_handler": {
50 | "class": "utils.log.WrapperHandler",
51 | "level": "ERROR",
52 | "formatter": "file",
53 | "filters": [],
54 | "filename": "logs/wrapper/wrapper.errors.log",
55 | "maxBytes": 10485760,
56 | "backupCount": 20,
57 | "encoding": "utf8"
58 | }
59 | },
60 | "root": {
61 | "level": "NOTSET",
62 | "handlers": ["console", "wrapper_file_handler", "error_file_handler"]
63 | }
64 | }
65 |
66 |
67 | def configure_logger(betterconsole=False):
68 | loadconfig(betterconsole=betterconsole)
69 | logging.getLogger()
70 |
71 |
72 | def loadconfig(betterconsole=False, configfile="logging.json"):
73 | dictConfig(DEFAULT) # Load default config
74 | try:
75 | if os.path.isfile(configfile):
76 | with open(configfile, "r") as f:
77 | conf = json.load(f)
78 |
79 | # Use newer logging configuration, if the one on disk is too old
80 | if "wrapperversion" not in conf or \
81 | (conf["wrapperversion"] < DEFAULT["wrapperversion"]):
82 | with open(configfile, "w") as f:
83 | f.write(json.dumps(DEFAULT, indent=4,
84 | separators=(',', ': ')))
85 | logging.warning("Logging configuration updated (%s) -- creat"
86 | "ing new logging configuration", configfile)
87 | else:
88 | if betterconsole:
89 | readcurrent = conf["formatters"]["standard"]["format"]
90 | conf["formatters"]["standard"]["format"] = (
91 | # go up one line to print - '^[1A' (in hex ASCII)
92 | "\x1b\x5b\x31\x41%s\r\n" % readcurrent)
93 | dictConfig(conf)
94 | logging.info("Logging configuration file (%s) located and "
95 | "loaded, logging configuration set!", configfile)
96 | else:
97 | with open(configfile, "w") as f:
98 | f.write(json.dumps(DEFAULT, indent=4, separators=(',', ': ')))
99 | logging.warning("Unable to locate %s -- Creating default logging "
100 | "configuration", configfile)
101 | except Exception as e:
102 | logging.exception("Unable to load or create %s! (%s)", configfile, e)
103 |
104 |
105 | class ColorFormatter(logging.Formatter):
106 | """This custom formatter will format console color/option
107 | (bold, italic, etc) and output based on logging level."""
108 | def __init__(self, *args, **kwargs):
109 | super(ColorFormatter, self).__init__(*args, **kwargs)
110 |
111 | # noinspection PyUnusedLocal
112 | def format(self, record):
113 | args = record.args
114 | msg = record.msg
115 |
116 | # Only style on *nix since windows doesn't support ANSI
117 | if os.name in ("posix", "mac"):
118 | if record.levelno == logging.INFO:
119 | info_style = _use_style(foreground="green")
120 | msg = info_style(msg)
121 | elif record.levelno == logging.DEBUG:
122 | debug_style = _use_style(foreground="cyan")
123 | msg = debug_style(msg)
124 | elif record.levelno == logging.WARNING:
125 | warn_style = _use_style(foreground="yellow", options=("bold",))
126 | msg = warn_style(msg)
127 | elif record.levelno == logging.ERROR:
128 | error_style = _use_style(foreground="red", options=("bold",))
129 | msg = error_style(msg)
130 | elif record.levelno == logging.CRITICAL:
131 | crit_style = _use_style(foreground="black", background="red",
132 | options=("bold",))
133 | msg = crit_style(msg)
134 |
135 | record.msg = msg
136 |
137 | return super(ColorFormatter, self).format(record)
138 |
139 |
140 | # noinspection PyPep8Naming,PyUnresolvedReferences
141 | class WrapperHandler(logging.handlers.RotatingFileHandler):
142 | def __init__(self, filename, mode='a', maxBytes=0,
143 | backupCount=0, encoding=None, delay=0):
144 | mkdir_p(os.path.dirname(filename))
145 | super(WrapperHandler, self).__init__(filename, mode, maxBytes,
146 | backupCount, encoding, delay)
147 |
--------------------------------------------------------------------------------
/wrapper/utils/readkey.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Copyright (C) 2017 - SurestTexas00.
4 | # This program is distributed under the terms of the GNU
5 | # General Public License, version 3 or later.
6 | #
7 | # However, this file is based heavily on this gist:
8 | # http://code.activestate.com/recipes/134892/
9 | # and is therefore also attributed to DannyYoo and company.
10 | #
11 | # Some elements (like the ESCAPE_SEQUENCES construct) are
12 | # attibuted to Miguel Ángel García (@magmax9) and his
13 | # readchar package.
14 |
15 |
16 | import sys
17 |
18 | WINDOWS = True
19 | try:
20 | import msvcrt
21 | except ImportError:
22 | WINDOWS = False
23 | import tty
24 | import termios
25 |
26 | # Linux keyboard constants
27 | ESC = '\x1b'
28 | TAB = '\x09'
29 | LF = '\x0d'
30 | CR = '\x0a'
31 | ENTER = '\x0d'
32 | BACKSPACE = '\x7f'
33 | CTRL_A = '\x01'
34 | CTRL_B = '\x02'
35 | CTRL_C = '\x03'
36 | CTRL_D = '\x04'
37 | CTRL_E = '\x05'
38 | CTRL_F = '\x06'
39 | CTRL_Z = '\x1a'
40 | ALT_TAB = '\x1b\x09'
41 | ALT_A = '\x1b\x61'
42 | CTRL_ALT_A = '\x1b\x01'
43 | UP = '\x1b\x5b\x41'
44 | DOWN = '\x1b\x5b\x42'
45 | LEFT = '\x1b\x5b\x44'
46 | RIGHT = '\x1b\x5b\x43'
47 | CTRL_ALT_DEL = '\x1b\x5b\x33\x5e'
48 | F1 = '\x1b\x4f\x50'
49 | F2 = '\x1b\x4f\x51'
50 | F3 = '\x1b\x4f\x52'
51 | F4 = '\x1b\x4f\x53'
52 | F5 = '\x1b\x5b\x31\x35\x7e'
53 | F1_1 = '\x1b\x5b\x5b\x41'
54 | F2_1 = '\x1b\x5b\x5b\x42'
55 | F3_1 = '\x1b\x5b\x5b\x43'
56 | F4_1 = '\x1b\x5b\x5b\x44'
57 | F5_1 = '\x1b\x5b\x5b\x45'
58 | F6 = '\x1b\x5b\x31\x37\x7e'
59 | F7 = '\x1b\x5b\x31\x38\x7e'
60 | F8 = '\x1b\x5b\x31\x39\x7e'
61 | F9 = '\x1b\x5b\x32\x30\x7e'
62 | F10 = '\x1b\x5b\x32\x31\x7e'
63 | F11_1 = '\x1b\x5b\x32\x33\x7e'
64 | F11 = '\x1b\x5b\x32\x33\x7e\x1b'
65 | F12_1 = '\x1b\x5b\x32\x34\x7e'
66 | F12 = '\x1b\x5b\x32\x34\x7e\x08'
67 | PAGE_UP = '\x1b\x5b\x35\x7e'
68 | PAGE_DOWN = '\x1b\x5b\x36\x7e'
69 | HOME_1 = '\x1b\x5b\x31\x7e'
70 | END_1 = '\x1b\x5b\x34\x7e'
71 | INSERT = '\x1b\x5b\x32\x7e'
72 | DELETE = '\x1b\x5b\x33\x7e'
73 | HOME = '\x1b\x5b\x48'
74 | END = '\x1b\x5b\x46'
75 | # Windows
76 | BACKSPACE_WIN = '\x08'
77 | CTRL_X_WIN = '\x18'
78 | CTRL_ALT_A_WIN = '\x00\x1e'
79 | UP_WIN = '\xe0\x48'
80 | DOWN_WIN = '\xe0\x50'
81 | LEFT_WIN = '\xe0\x4b'
82 | RIGHT_WIN = '\xe0\x4d'
83 | F1_WIN = '\x00\x3b'
84 | F2_WIN = '\x00\x3c'
85 | F3_WIN = '\x00\x3d'
86 | F4_WIN = '\x00\x3e'
87 | F5_WIN = '\x00\x3f'
88 | F6_WIN = '\x00\x40'
89 | F7_WIN = '\x00\x41'
90 | F8_WIN = '\x00\x42'
91 | F9_WIN = '\x00\x43'
92 | F10_WIN = '\x00\x44'
93 | F11_WIN = '\xe0\x85'
94 | F12_WIN = '\xe0\x86'
95 | PAGE_UP_WIN = '\xe0\x49'
96 | PAGE_DOWN_WIN = '\xe0\x51'
97 | INSERT_WIN = '\xe0\x52'
98 | DELETE_WIN = '\xe0\x53'
99 | HOME_WIN = '\xe0\x47'
100 | END_WIN = '\xe0\x4f'
101 | PAGE_UP_WIN_NUMLOCK = '\x00\x49'
102 | PAGE_DOWN_WIN_NUMLOCK = '\x00\x51'
103 | HOME_WIN_NUMLOCK = '\x00\x47'
104 | END_WIN_NUMLOCK = '\x00\x4f'
105 | UP_WIN_NUMLOCK = '\x00\x48'
106 | DOWN_WIN_NUMLOCK = '\x00\x50'
107 | LEFT_WIN_NUMLOCK = '\x00\x4b'
108 | RIGHT_WIN_NUMLOCK = '\x00\x4d'
109 | INSERT_WIN_NUMLOCK = '\x00\x52'
110 | DELETE_WIN_NUMLOCK = '\x00\x53'
111 |
112 | NAMES = {
113 | ESC: 'esc',
114 | TAB: 'tab',
115 | LF: 'lf',
116 | CR: 'cr',
117 | ENTER: 'enter',
118 | BACKSPACE: 'backspace',
119 | CTRL_A: 'ctrl-a',
120 | CTRL_B: 'ctrl-b',
121 | CTRL_C: 'ctrl-c',
122 | CTRL_D: 'ctrl-d',
123 | CTRL_E: 'ctrl-e',
124 | CTRL_F: 'ctrl-f',
125 | CTRL_Z: 'ctrl-z',
126 | ALT_TAB: 'alt-tab',
127 | ALT_A: 'alt-a',
128 | CTRL_ALT_A: 'ctrl-alt-a',
129 | UP: 'up',
130 | DOWN: 'down',
131 | LEFT: 'left',
132 | RIGHT: 'right',
133 | CTRL_ALT_DEL: 'ctrl-alt-del',
134 | F1: 'f1',
135 | F2: 'f2',
136 | F3: 'f3',
137 | F4: 'f4',
138 | F5: 'f5',
139 | F1_1: 'f1',
140 | F2_1: 'f2',
141 | F3_1: 'f3',
142 | F4_1: 'f4',
143 | F5_1: 'f5',
144 | F6: 'f6',
145 | F7: 'f7',
146 | F8: 'f8',
147 | F9: 'f9',
148 | F10: 'f10',
149 | F11: 'f11',
150 | F12: 'f12',
151 | F11_1: 'f11',
152 | F12_1: 'f12',
153 | PAGE_UP: 'page-up',
154 | PAGE_DOWN: 'page-down',
155 | HOME_1: 'home',
156 | END_1: 'end',
157 | INSERT: 'insert',
158 | DELETE: 'delete',
159 | HOME: 'home',
160 | END: 'end',
161 | BACKSPACE_WIN: 'backspace',
162 | CTRL_X_WIN: 'ctrl-x',
163 | CTRL_ALT_A_WIN: 'ctrl-alt-a',
164 | UP_WIN: 'up',
165 | DOWN_WIN: 'down',
166 | LEFT_WIN: 'left',
167 | RIGHT_WIN: 'right',
168 | F1_WIN: 'f1',
169 | F2_WIN: 'f2',
170 | F3_WIN: 'f3',
171 | F4_WIN: 'f4',
172 | F5_WIN: 'f5',
173 | F6_WIN: 'f6',
174 | F7_WIN: 'f7',
175 | F8_WIN: 'f8',
176 | F9_WIN: 'f9',
177 | F10_WIN: 'f10',
178 | F11_WIN: 'f11',
179 | F12_WIN: 'f12',
180 | PAGE_UP_WIN: 'page-up',
181 | PAGE_DOWN_WIN: 'page-down',
182 | INSERT_WIN: 'insert',
183 | DELETE_WIN: 'delete',
184 | HOME_WIN: 'home',
185 | END_WIN: 'end',
186 | PAGE_UP_WIN_NUMLOCK: 'page-up',
187 | PAGE_DOWN_WIN_NUMLOCK: 'page-down',
188 | HOME_WIN_NUMLOCK: 'home',
189 | END_WIN_NUMLOCK: 'end',
190 | UP_WIN_NUMLOCK: 'up',
191 | DOWN_WIN_NUMLOCK: 'down',
192 | LEFT_WIN_NUMLOCK: 'left',
193 | RIGHT_WIN_NUMLOCK: 'right',
194 | INSERT_WIN_NUMLOCK: 'insert',
195 | DELETE_WIN_NUMLOCK: 'delete',
196 | }
197 |
198 | ESCAPE_SEQUENCES = (
199 | ESC,
200 | ESC + '\x5b',
201 | ESC + '\x5b' + '\x5b',
202 | ESC + '\x5b' + '\x31',
203 | ESC + '\x5b' + '\x32',
204 | ESC + '\x5b' + '\x33',
205 | ESC + '\x5b' + '\x34',
206 | ESC + '\x5b' + '\x35',
207 | ESC + '\x5b' + '\x36',
208 |
209 | ESC + '\x5b' + '\x31' + '\x33',
210 | ESC + '\x5b' + '\x31' + '\x34',
211 | ESC + '\x5b' + '\x31' + '\x35',
212 | ESC + '\x5b' + '\x31' + '\x36',
213 | ESC + '\x5b' + '\x31' + '\x37',
214 | ESC + '\x5b' + '\x31' + '\x38',
215 | ESC + '\x5b' + '\x31' + '\x39',
216 |
217 | ESC + '\x5b' + '\x32' + '\x30',
218 | ESC + '\x5b' + '\x32' + '\x31',
219 | ESC + '\x5b' + '\x32' + '\x32',
220 | ESC + '\x5b' + '\x32' + '\x33',
221 | ESC + '\x5b' + '\x32' + '\x34',
222 | ESC + '\x5b' + '\x32' + '\x33' + '\x7e',
223 | ESC + '\x5b' + '\x32' + '\x34' + '\x7e',
224 | ESC + '\x4f',
225 |
226 | ESC + ESC,
227 | ESC + ESC + '\x5b',
228 | ESC + ESC + '\x5b' + '\x32',
229 | ESC + ESC + '\x5b' + '\x33',
230 |
231 | # Windows sequences
232 | '\x00',
233 | '\xe0',
234 | )
235 |
236 |
237 | class _Getch(object):
238 | """Gets a single character from standard input. Does not echo to the
239 | screen."""
240 | def __init__(self):
241 | try:
242 | self.getch = _GetchWindows()
243 | except ImportError:
244 | self.getch = _GetchUnix()
245 |
246 | def __call__(self): return self.getch()
247 |
248 |
249 | class _GetchUnix(object):
250 | def __init__(self):
251 | pass
252 |
253 | def __call__(self):
254 | fd = sys.stdin.fileno()
255 | old_settings = termios.tcgetattr(fd)
256 | try:
257 | tty.setraw(sys.stdin.fileno())
258 | ch = sys.stdin.read(1)
259 | finally:
260 | termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
261 | return ch
262 |
263 |
264 | class _GetchWindows(object):
265 | def __init__(self):
266 | if not WINDOWS:
267 | # purposely cause import error for try-except
268 | # noinspection PyUnresolvedReferences
269 | import msvcrt
270 |
271 | def __call__(self):
272 | # noinspection PyUnresolvedReferences
273 | return msvcrt.getch().decode('latin-1')
274 |
275 |
276 | def getcharacter():
277 | g = _Getch()
278 | charbuffer = ""
279 | while True:
280 | # noinspection PyArgumentEqualDefault
281 | char1 = g.__call__()
282 | if (charbuffer + char1) not in ESCAPE_SEQUENCES:
283 | charbuffer += char1
284 | break
285 |
286 | if (charbuffer + char1) == charbuffer:
287 | break
288 |
289 | charbuffer += char1
290 | return charbuffer
291 |
292 |
293 | def convertchar(charbuffer):
294 | if charbuffer in NAMES:
295 | return NAMES[charbuffer]
296 | return None
297 |
298 |
299 | def _test():
300 | running = True
301 | while running:
302 | charbuffer = getcharacter()
303 | name = convertchar(charbuffer)
304 | if name == "up":
305 | print("UP key...")
306 | it = "\\x".join("{:02x}".format(ord(c)) for c in charbuffer)
307 | if name:
308 | print(name)
309 | else:
310 | print("\\x%s" % it)
311 | if name == "ctrl-c":
312 | break
313 |
314 |
315 | if __name__ == "__main__":
316 | _test()
317 |
--------------------------------------------------------------------------------