py2hackCraft2 0.0.1__tar.gz → 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: py2hackCraft2
3
- Version: 0.0.1
3
+ Version: 1.0.0
4
4
  Summary: These are APIs that connect to the hackCraft2 server from Python to manipulate pets.
5
5
  Home-page: http://example.com/HelloWorld/
6
6
  Author: Masafumi Terazono
@@ -0,0 +1,11 @@
1
+ setup:
2
+ <command>
3
+ pip install setuptools wheel twine
4
+
5
+ build:
6
+ <command>
7
+ python3 setup.py sdist bdist_wheel
8
+
9
+ deploy:
10
+ <command>
11
+ twine upload --repository-url https://upload.pypi.org/legacy/ dist/* -u "__token__"
@@ -0,0 +1,409 @@
1
+ import websocket
2
+ import threading
3
+ import time
4
+ import json
5
+ from dataclasses import dataclass
6
+ from typing import Callable, Any
7
+
8
+ def str_to_bool(s):
9
+ """
10
+ 文字列をブール値に変換する。
11
+
12
+ Args:
13
+ s (str): "true" または "false"(大文字小文字は無視)
14
+
15
+ Returns:
16
+ bool: 変換されたブール値。"true"ならTrue、"false"ならFalse
17
+ """
18
+ if s.lower() == 'true':
19
+ return True
20
+ elif s.lower() == 'false':
21
+ return False
22
+ else:
23
+ raise ValueError(f"Cannot covert {s} to a boolean.") # 有効な文字列でない場合はエラー
24
+
25
+
26
+ class WebSocketClient:
27
+ def __init__(self, url):
28
+ self.url = url
29
+ self.ws = websocket.WebSocketApp(url,
30
+ on_message=self.on_message,
31
+ on_error=self.on_error,
32
+ on_close=self.on_close)
33
+ self.ws.on_open = self.on_open
34
+ self.thread = threading.Thread(target=self.ws.run_forever)
35
+ self.thread.daemon = True
36
+ self.lock = threading.Lock()
37
+ self.connected = False
38
+ self.response_event = threading.Event() # イベントオブジェクトを追加
39
+ self.last_message = None # 最後に受信したメッセージを保持
40
+ self.callbacks = {} # コールバック関数を保持
41
+
42
+ def setCallback(self, eventName, callbackFunc):
43
+ self.callbacks[eventName] = callbackFunc
44
+
45
+ def on_message(self, ws, message):
46
+ print("on_message '%s'" % message)
47
+ try:
48
+ jsonMessage = json.loads(message)
49
+ type = jsonMessage['type']
50
+ data = jsonMessage['data']
51
+ if(type == 'result'):
52
+ self.result = data
53
+ elif(type == 'error'):
54
+ self.error = data
55
+ elif(type == 'connected'):
56
+ self.connected = True
57
+ self.entityUUID = data
58
+ elif(type == 'event'):
59
+ jsonEvent = json.loads(data)
60
+ eventName = jsonEvent['name']
61
+ print("on event %s '%s'" %(eventName, jsonEvent['data']))
62
+ if eventName in self.callbacks:
63
+ self.callbacks[eventName](jsonEvent['data'])
64
+ self.response_event.set() # イベントをセットして、メッセージの受信を通知
65
+ except json.JSONDecodeError:
66
+ print("JSONDecodeError '%s'" % message)
67
+
68
+ def on_error(self, ws, error):
69
+ print("on_error '%s'" % error)
70
+
71
+ def on_close(self, ws, close_status_code, close_msg):
72
+ print("### closed ###")
73
+ self.connected = False
74
+
75
+ def on_open(self, ws):
76
+ print("Opened connection")
77
+ self.connected = True
78
+
79
+ def run_forever(self):
80
+ self.thread.start()
81
+
82
+ def wait_for_connection(self):
83
+ while not self.connected:
84
+ time.sleep(0.1) # Wait for connection to be established
85
+
86
+ def send(self, message):
87
+ self.wait_for_connection()
88
+ with self.lock:
89
+ self.response_event.clear() # イベントをクリアして新しいレスポンスの準備をする
90
+ self.ws.send(message)
91
+ self.response_event.wait() # サーバーからのレスポンスを待つ
92
+ return self.last_message # 最後に受信したメッセージを返す
93
+
94
+ def close(self):
95
+ self.ws.close()
96
+ self.thread.join()
97
+
98
+ def sendCall(self, name, args=None):
99
+ data = {"name": name}
100
+ if args is not None:
101
+ data['args'] = args
102
+ message = {
103
+ "type": "call",
104
+ "data": data
105
+ }
106
+ self.send(json.dumps(message))
107
+
108
+
109
+ @dataclass
110
+ class Location:
111
+ x: int
112
+ y: int
113
+ z: int
114
+ world: str = "world"
115
+
116
+
117
+ @dataclass
118
+ class ChatMessage:
119
+ """
120
+ チャットメッセージを表すデータクラス。
121
+
122
+ Attributes:
123
+ player (str): プレイヤー名または識別子。
124
+ uuid (str): プレイヤーの一意の識別子(UUID)。
125
+ message (str): プレイヤーがチャットで送信したメッセージの内容。
126
+ """
127
+ player: str
128
+ uuid: str
129
+ message: str
130
+
131
+ @dataclass
132
+ class RedstonePower:
133
+ """
134
+ レッドストーン信号を表すデータクラス。
135
+
136
+ Attributes:
137
+ oldCurrent (int): 前のレッドストーン信号の強さ
138
+ newCurrent (int): 最新のレッドストーン信号の強さ
139
+ """
140
+ oldCurrent: int
141
+ newCurrent: int
142
+
143
+ @dataclass
144
+ class Block:
145
+ """
146
+ ブロックを表すデータクラス。
147
+
148
+ Attributes:
149
+ name (str): ブロックの種類。
150
+ data (int): ブロックのデータ値。
151
+ isLiquid (bool): 液体ブロックかどうか。
152
+ isAir (bool): 空気ブロックかどうか。
153
+ isBurnable (bool): 燃えるブロックかどうか。
154
+ isFuel (bool): 燃料ブロックかどうか。
155
+ isOccluding (bool): 透過しないブロックかどうか。
156
+ isSolid (bool): 壁のあるブロックかどうか。
157
+ isPassable (bool): 通過可能なブロックかどうか。
158
+ x (int): ブロックのX座標。
159
+ y (int): ブロックのY座標。
160
+ z (int): ブロックのZ座標。
161
+ """
162
+ name: str
163
+ data: int
164
+ isLiquid: bool
165
+ isAir: bool
166
+ isBurnable: bool
167
+ isFuel: bool
168
+ isOccluding: bool
169
+ isSolid: bool
170
+ isPassable: bool
171
+ x: int
172
+ y: int
173
+ z: int
174
+
175
+ class Entity:
176
+ """
177
+ エンティティを表すクラス。
178
+ """
179
+ def __init__(self, url: str, player: str, entity: str):
180
+ self.client = None # 初期化時にはWebSocketClientはNone
181
+ self.url = url
182
+ self.player = player
183
+ self.entity = entity
184
+
185
+ def connect(self):
186
+ """
187
+ 設定されているプレイヤーのエンティティに接続する。
188
+ """
189
+ print("Connecting to %s %s %s" %( self.url, self.player, self.entity))
190
+ if not self.client:
191
+ self.client = WebSocketClient(self.url) # 遅延初期化
192
+ self.client.run_forever()
193
+ self.client.send(json.dumps({
194
+ "type": "connect2",
195
+ "data": {
196
+ "player": self.player,
197
+ "entity": self.entity,
198
+ }
199
+ }))
200
+
201
+ def disconnect(self):
202
+ """
203
+ 接続しているエンティティから切断する。
204
+ """
205
+ if self.client:
206
+ self.client.close()
207
+ self.client = None
208
+ self.player = None
209
+ self.entity = None
210
+
211
+ def setOnPlayerChat(self, callbackFunc: Callable[['Entity', 'ChatMessage'], Any]):
212
+ """
213
+ チャットを受信したときに呼び出されるコールバック関数を設定する。
214
+ """
215
+ def callbackWrapper(data):
216
+ print("callbackWrapper '%s'" % data)
217
+ chatMessage = ChatMessage(**data)
218
+ callbackFunc(self, chatMessage)
219
+ self.client.setCallback('onPlayerChat', callbackWrapper)
220
+
221
+ def setOnRedstoneChange(self, callbackFunc: Callable[['Entity', 'RedstonePower'], Any]):
222
+ """
223
+ レッドストーンを受信したときに呼び出されるコールバック関数を設定する。
224
+ """
225
+ def callbackWrapper(data):
226
+ print("callbackWrapper '%s'" % data)
227
+ power = RedstonePower(**data)
228
+ callbackFunc(self, power)
229
+ self.client.setCallback('onEntityRedstone', callbackWrapper)
230
+
231
+ def forward(self):
232
+ """
233
+ エンティティを前方に移動させる。
234
+ """
235
+ self.client.sendCall("forward")
236
+
237
+ def back(self):
238
+ """
239
+ エンティティを後方に移動させる。
240
+ """
241
+ self.client.sendCall("back")
242
+
243
+ def up(self):
244
+ """
245
+ エンティティを上方に移動させる。
246
+ """
247
+ self.client.sendCall("up")
248
+
249
+ def down(self):
250
+ """
251
+ エンティティを下方に移動させる。
252
+ """
253
+ self.client.sendCall("down")
254
+
255
+ def turnLeft(self):
256
+ """
257
+ エンティティを左に回転させる。
258
+ """
259
+ self.client.sendCall("turnLeft")
260
+
261
+ def turnRight(self):
262
+ """
263
+ エンティティを右に回転させる。
264
+ """
265
+ self.client.sendCall("turnRight")
266
+
267
+ def place(self):
268
+ """
269
+ エンティティの前方にブロックを設置する。
270
+ """
271
+ self.client.sendCall("placeFront")
272
+
273
+ def placeUp(self):
274
+ """
275
+ エンティティの真上にブロックを設置する。
276
+ """
277
+ self.client.sendCall("placeUp")
278
+
279
+ def placeDown(self):
280
+ """
281
+ エンティティの真下にブロックを設置する。
282
+ """
283
+ self.client.sendCall("placeDown")
284
+
285
+ def useItem(self):
286
+ """
287
+ エンティティの前方にアイテムを使う
288
+ """
289
+ self.client.sendCall("useItemFront")
290
+
291
+ def useItemUp(self):
292
+ """
293
+ エンティティの真上にアイテムを使う
294
+ """
295
+ self.client.sendCall("useItemUp")
296
+
297
+ def useItemDown(self):
298
+ """
299
+ エンティティの真下にアイテムを使う
300
+ """
301
+ self.client.sendCall("useItemDown")
302
+
303
+ def dig(self):
304
+ """
305
+ エンティティの前方のブロックを壊す。
306
+ """
307
+ self.client.sendCall("digFront")
308
+
309
+ def digUp(self):
310
+ """
311
+ エンティティの真上のブロックを壊す。
312
+ """
313
+ self.client.sendCall("digUp")
314
+
315
+ def digDown(self):
316
+ """
317
+ エンティティの真下のブロックを壊す。
318
+ """
319
+ self.client.sendCall("digDown")
320
+
321
+ def setItem(self, slot: int, block: str):
322
+ """
323
+ エンティティのインベントリにアイテムを設定する。
324
+
325
+ Args:
326
+ slot (int): 設定するアイテムのスロット番号。
327
+ block (str): 設定するブロックの種類。
328
+ """
329
+ self.client.sendCall("setItem", [slot, block])
330
+
331
+ def holdItem(self, slot: int):
332
+ """
333
+ 指定されたスロットからアイテムをエンティティの手に持たせる。
334
+
335
+ Args:
336
+ slot (int): アイテムを持たせたいスロットの番号。
337
+ """
338
+ self.client.sendCall("grabItem", [slot])
339
+
340
+ def say(self, message: str):
341
+ """
342
+ エンティティに指定されたメッセージをチャットとして送信させる。
343
+
344
+ Args:
345
+ message (str): エンティティがチャットで送信するメッセージの内容。
346
+ """
347
+ self.client.sendCall("sendChat", [message])
348
+
349
+ def inspect(self, x: int, y: int, z: int) -> Block :
350
+ """
351
+ 指定された座標のブロックを調べる。
352
+
353
+ Args:
354
+ x (int): 相対的なX座標。
355
+ y (int): 相対的なY座標。
356
+ z (int): 相対的なZ座標。
357
+ Returns:
358
+ Block: 調べたブロックの情報。
359
+ """
360
+ self.client.sendCall("inspect", [x, y, z])
361
+ block = Block(** json.loads(self.client.result))
362
+ return block
363
+
364
+ def getLocation(self) -> Location :
365
+ """
366
+ エンティティの現在位置を調べる。
367
+ Returns:
368
+ Location: 調べた位置情報。
369
+ """
370
+ self.client.sendCall("getPosition")
371
+ location = Location(** json.loads(self.client.result))
372
+ return location
373
+
374
+ def teleport(self, x: int, y: int, z: int) :
375
+ """
376
+ 指定された座標に移動する。
377
+ Args:
378
+ x (int): 絶対的なX座標。
379
+ y (int): 絶対的なY座標。
380
+ z (int): 絶対的なZ座標。
381
+ """
382
+ self.client.sendCall("teleport", [x, y, z])
383
+
384
+ def isBlocked(self) -> str :
385
+ """
386
+ エンティティの前方にブロックがあるかどうか調べる。
387
+ Returns:
388
+ bool: 調べた結果。
389
+ """
390
+ self.client.sendCall("isBlockedFront")
391
+ return str_to_bool(self.client.result)
392
+
393
+ def isBlockedUp(self) -> str :
394
+ """
395
+ エンティティの真上にブロックがあるかどうか調べる。
396
+ Returns:
397
+ bool: 調べた結果。
398
+ """
399
+ self.client.sendCall("isBlockedUp")
400
+ return str_to_bool(self.client.result)
401
+
402
+ def isBlockedDown(self) -> bool :
403
+ """
404
+ エンティティの真下にブロックがあるかどうか調べる。
405
+ Returns:
406
+ bool: 調べた結果。
407
+ """
408
+ self.client.sendCall("isBlockedDown")
409
+ return str_to_bool(self.client.result)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: py2hackCraft2
3
- Version: 0.0.1
3
+ Version: 1.0.0
4
4
  Summary: These are APIs that connect to the hackCraft2 server from Python to manipulate pets.
5
5
  Home-page: http://example.com/HelloWorld/
6
6
  Author: Masafumi Terazono
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="py2hackCraft2",
5
- version="0.0.1",
5
+ version="1.0.0",
6
6
  packages=find_packages(),
7
7
  install_requires=[
8
8
  "websocket-client" # websocketライブラリの追加
@@ -1,21 +0,0 @@
1
- if __name__ == "__main__":
2
- client = WebSocketClient("ws://localhost:25570/ws")
3
- client.run_forever()
4
- time.sleep(1) # Give time for connection to establish
5
- client.send(json.dumps({
6
- "type": "connect2",
7
- "data": {
8
- "player": "masafumi_t",
9
- "entity": "test",
10
- }
11
- }))
12
- time.sleep(1) # Keep application open to receive message
13
- client.send(json.dumps({
14
- "type": "call",
15
- "data": {
16
- "name": "forward"
17
- }
18
- }))
19
-
20
-
21
- client.close()
@@ -1,136 +0,0 @@
1
- import websocket
2
- import threading
3
- import time
4
- import json
5
-
6
- class WebSocketClient:
7
- def __init__(self, url):
8
- self.url = url
9
- self.ws = websocket.WebSocketApp(url,
10
- on_message=self.on_message,
11
- on_error=self.on_error,
12
- on_close=self.on_close)
13
- self.ws.on_open = self.on_open
14
- self.thread = threading.Thread(target=self.ws.run_forever)
15
- self.thread.daemon = True
16
- self.lock = threading.Lock()
17
- self.connected = False
18
- self.response_event = threading.Event() # イベントオブジェクトを追加
19
- self.last_message = None # 最後に受信したメッセージを保持
20
-
21
- def on_message(self, ws, message):
22
- print("Received '%s'" % message)
23
- self.last_message = message # 最後に受信したメッセージを更新
24
- self.response_event.set() # イベントをセットして、メッセージの受信を通知
25
-
26
- def on_error(self, ws, error):
27
- print("Error '%s'" % error)
28
-
29
- def on_close(self, ws, close_status_code, close_msg):
30
- print("### closed ###")
31
- self.connected = False
32
-
33
- def on_open(self, ws):
34
- print("Opened connection")
35
- self.connected = True
36
-
37
- def run_forever(self):
38
- self.thread.start()
39
-
40
- def wait_for_connection(self):
41
- while not self.connected:
42
- time.sleep(0.1) # Wait for connection to be established
43
-
44
- def send(self, message):
45
- self.wait_for_connection()
46
- with self.lock:
47
- self.response_event.clear() # イベントをクリアして新しいレスポンスの準備をする
48
- self.ws.send(message)
49
- self.response_event.wait() # サーバーからのレスポンスを待つ
50
- return self.last_message # 最後に受信したメッセージを返す
51
-
52
- def close(self):
53
- self.ws.close()
54
- self.thread.join()
55
-
56
-
57
- class Entity:
58
- def __init__(self, url, player, entity):
59
- self.client = None # 初期化時にはWebSocketClientはNone
60
- self.url = url
61
- self.player = player
62
- self.entity = entity
63
-
64
- def connect(self):
65
- print("Connecting to %s %s %s" %( self.url, self.player, self.entity))
66
- if not self.client:
67
- self.client = WebSocketClient(self.url) # 遅延初期化
68
- self.client.run_forever()
69
- self.client.send(json.dumps({
70
- "type": "connect2",
71
- "data": {
72
- "player": self.player,
73
- "entity": self.entity,
74
- }
75
- }))
76
-
77
- def disconnect(self):
78
- if self.client:
79
- self.client.close()
80
- self.client = None
81
- self.player = None
82
- self.entity = None
83
-
84
- def forward(self):
85
- message = {
86
- "type": "call",
87
- "data": {
88
- "name": "forward"
89
- }
90
- }
91
- self.client.send(json.dumps(message))
92
-
93
- def back(self):
94
- message = {
95
- "type": "call",
96
- "data": {
97
- "name": "back"
98
- }
99
- }
100
- self.client.send(json.dumps(message))
101
-
102
- def up(self):
103
- message = {
104
- "type": "call",
105
- "data": {
106
- "name": "up"
107
- }
108
- }
109
- self.client.send(json.dumps(message))
110
-
111
- def down(self):
112
- message = {
113
- "type": "call",
114
- "data": {
115
- "name": "down"
116
- }
117
- }
118
- self.client.send(json.dumps(message))
119
-
120
- def turnLeft(self):
121
- message = {
122
- "type": "call",
123
- "data": {
124
- "name": "turnLeft"
125
- }
126
- }
127
- self.client.send(json.dumps(message))
128
-
129
- def turnRight(self):
130
- message = {
131
- "type": "call",
132
- "data": {
133
- "name": "turnRight"
134
- }
135
- }
136
- self.client.send(json.dumps(message))
File without changes