-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathreplcraftpy.py
More file actions
320 lines (286 loc) · 8.9 KB
/
replcraftpy.py
File metadata and controls
320 lines (286 loc) · 8.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
import websocket
import json
from base64 import b64decode
class ReplCraft:
def __init__(self, token):
self.token = token.replace('http://','')
self.config = json.loads(b64decode(token.split('.')[1]+'===='))
self.nonce = "0"
# Logs in :)
def login(self):
self.ws = websocket.create_connection('ws://' + self.config['host'] + '/gateway')
self._send(
{
"action":"authenticate",
"token": self.token,
"nonce": self.nonce
}
)
# Retrieves a block at the given structure-local coordinates.
def get_block(self, x, y, z):
return self._send(
{
"action":"get_block",
"x": x,
"y": y,
"z": z,
"nonce": self.nonce
}
)
# Retrieves the world coordinate location of the (0,0,0)
def location(self, x, y, z):
return self._send(
{
"action":"get_location",
"x": x,
"y": y,
"z": z,
"nonce": self.nonce
}
)
# Retrieves the inner size of the structure.
def get_size(self, x, y, z):
return self._send(
{
"action":"get_size",
"x": x,
"y": y,
"z": z,
"nonce": self.nonce
}
)
# Sets a block at the given structure-local coordinates. The block must be available
# in the specified source chest or the structure inventory. Any block replaced by this call
# is stored in the specified target chest or the structure inventory, or dropped in the
# world if there's no space.
#
# :source_x, source_y, source_z: The container the block to set is in.
# :target_x, target_y, target_z: The container the block replaced should go to.
def set_block(self, x, y, z, blockdata, source_x=None, source_y=None, source_z=None, target_x=None, target_y=None, target_z=None):
return self._send(
json.dumps({
"action":"set_block",
"x": x,
"y": y,
"z": z,
"blockData": blockdata,
"source_x": source_x,
"source_y": source_y,
"source_z": source_z,
"target_x": target_x,
"target_y": target_y,
"target_z": target_z,
"nonce": self.nonce
})
)
# Retrieves the text of a sign at the given coordinates.
def get_sign_text(self, x, y, z):
return self._send(
{
"action":"get_sign_text",
"x": x,
"y": y,
"z": z,
"nonce": self.nonce
}
)
# Sets the text of a sign at the given coordinates.
def set_sign_text(self, x, y, z, lines):
return self._send(
{
"action":"set_sign_text",
"x": x,
"y": y,
"z": z,
"lines": lines,
"nonce": self.nonce
}
)
# Begins watching a block for updates.
def watch(self, x, y, z):
return self._send(
{
"action":"watch",
"x": x,
"y": y,
"z": z,
"nonce": self.nonce
}
)
# Stops watching a block for updates.
def unwatch(self, x, y, z):
return self._send(
{
"action":"unwatch",
"x": x,
"y": y,
"z": z,
"nonce": self.nonce
}
)
# Begins watching all blocks in the structure for updates.
def watch_all(self):
return self._send(
{
"action":"watch_all",
"nonce": self.nonce
}
)
# Stops watching all blocks for updates.
def unwatch_all(self):
return self._send(
{
"action":"unwatch_all",
"nonce": self.nonce
}
)
# Begins polling all blocks in the structure for updates.
# Updates will be very slow!
def poll_all(self):
return self._send(
{
"action":"poll_all",
"nonce": self.nonce
}
)
# Stops polling all blocks in the structure.
def unpoll_all(self):
return self._send(
{
"action":"unpoll_all",
"nonce": self.nonce
}
)
# Begins polling a block for updates.
# Note that this catches all possible block updates, but only one block is polled per tick.
# The more blocks you poll, the slower each individual block will be checked.
# Additionally, if a block changes multiple times between polls, only the latest change
# will be reported.
def poll(self, x, y, z):
return self._send(
{
"action":"poll",
"x": x,
"y": y,
"z": z,
"nonce": self.nonce
}
)
# Stops watching a block for updates.
def unpoll(self, x, y, z):
return self._send(
{
"action":"unpoll",
"x": x,
"y": y,
"z": z,
"nonce": self.nonce
}
)
# Gets all entities inside the region.
def get_entities(self):
return self._send(
{
"action":"get_entities",
"nonce": self.nonce
}
)
# Gets all items from a container such as a chest or hopper.
def get_inventory(self, x, y, z):
return self._send(
{
"action":"get_inventory",
"x": x,
"y": y,
"z": z,
"nonce": self.nonce
}
)
# Moves an item between containers.
def move_item(self, index, source_x, source_y, source_z, target_x, target_y, target_z):
return self._send(
{
"action":"move_item",
"index": index,
"source_x": source_x,
"source_y": source_y,
"source_z": source_z,
"target_x": target_x,
"target_y": target_y,
"target_z": target_z,
"nonce": self.nonce
}
)
# Gets a block's redstone power level.
def get_power_level(self, x, y, z):
return self._send(
{
"action":"get_power_level",
"x": x,
"y": y,
"z": z,
"nonce": self.nonce
}
)
# Crafts an item, which is then stored into the given container.
def craft(self, x, y, z, recipe):
return self._send(
json.dumps({
"action":"craft",
"x": x,
"y": y,
"z": z,
"ingredients": recipe,
"nonce": self.nonce
})
)
# Listen for any server communication, use after watch & poll methods.
def listen(self):
return self._recv()
def disconnect(self):
self.ws.close()
# PRIVATE
def _recv(self):
return json.loads(self.ws.recv())
def _send(self, data):
self.ws.send(str(data))
self.nonce = str(int(self.nonce) + 1)
if 'nonce' in data:
return self._recv()
# Index of an item withing a container.
#
# :index: index of the slot the time is in within the container.
# :x, y, z: the coordinates of the container.
class ItemIndex:
def __init__(self, index, x, y, z):
self.index = index # The index of the chest slot the item is in.
self.x = x
self.y = y
self.z = z
def item(self):
return {
"index": self.index,
"x": self.x,
"y": self.y,
"z": self.z
}
# Recipe, matching it's vanilla definition
#
# :s1-s9: crafting table slots
class Recipe:
def __init__(self, s1=None, s2=None, s3=None, s4=None, s5=None, s6=None, s7=None, s8=None, s9=None):
self.s1 = s1
self.s2 = s2
self.s3 = s3
self.s4 = s4
self.s5 = s5
self.s6 = s6
self.s7 = s7
self.s8 = s8
self.s9 = s9
def table(self):
return [
self.s1, self.s2, self.s3,
self.s4, self.s5, self.s6,
self.s7, self.s8, self.s9
]