mc5-api-client 1.0.16__py3-none-any.whl → 1.0.17__py3-none-any.whl

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.
@@ -0,0 +1,439 @@
1
+ #!/usr/bin/env python3
2
+ # ────────────[ CHIZOBA ]────────────────────────────
3
+ # | Email : chizoba2026@hotmail.com
4
+ # | File : squad_battle.py
5
+ # | License | MIT License © 2026 Chizoba
6
+ # | Brief | Squad battle and clan battle APIs
7
+ # ────────────────★─────────────────────────────────
8
+
9
+ import json
10
+ from typing import Optional, Dict, Any, List
11
+ from .telemetry import report_error, report_usage
12
+ from .debug import debug_function, debug_print
13
+
14
+ class SquadBattleMixin:
15
+ """Mixin class for squad battle and clan battle functionality."""
16
+
17
+ @debug_function
18
+ def create_squad_battle_room(self, room_name: Optional[str] = None, capacity: int = 2) -> Dict[str, Any]:
19
+ """
20
+ Create a squad battle room.
21
+
22
+ Args:
23
+ room_name: Optional room name (generated if not provided)
24
+ capacity: Room capacity (default: 2 for squad battles)
25
+
26
+ Returns:
27
+ Room creation response with room_id, lobby_host, lobby_port
28
+ """
29
+ try:
30
+ import uuid
31
+
32
+ if not room_name:
33
+ room_name = str(uuid.uuid4())
34
+
35
+ url = f"{self.BASE_URLS['anubisfinder']}/rooms/1875:55979:6.0.0a:windows:windows/quick_join"
36
+
37
+ data = {
38
+ "access_token": self._token_data["access_token"],
39
+ "server_type": "mp_server",
40
+ "filters": '["_name=clan_owners&creator_datacenter=None"]',
41
+ "create_command": json.dumps({
42
+ "_name": "clan_owners",
43
+ "capacity": capacity,
44
+ "server_type": "mp_server"
45
+ }),
46
+ "name": room_name,
47
+ "http_room": "false"
48
+ }
49
+
50
+ debug_print(f"Creating squad battle room: {room_name}", "info")
51
+ result = self._make_request("POST", url, data=data)
52
+
53
+ if result:
54
+ debug_print(f"✅ Squad battle room created: {result.get('room_id')}", "success")
55
+ report_usage("create_squad_battle_room", True, 0, {
56
+ "room_id": result.get('room_id'),
57
+ "capacity": capacity
58
+ })
59
+
60
+ return result
61
+
62
+ except Exception as e:
63
+ debug_print(f"❌ Failed to create squad battle room: {e}", "error")
64
+ report_error(e, "create_squad_battle_room", {
65
+ "room_name": room_name,
66
+ "capacity": capacity
67
+ })
68
+ raise
69
+
70
+ @debug_function
71
+ def send_squad_battle_notification(self,
72
+ room_id: str,
73
+ lobby_host: str,
74
+ lobby_port: int,
75
+ message: str = "Squad battle starting!") -> Dict[str, Any]:
76
+ """
77
+ Send squad battle notification via multicast message.
78
+
79
+ Args:
80
+ room_id: Room ID from battle creation
81
+ lobby_host: Lobby host from battle creation
82
+ lobby_port: Lobby port from battle creation
83
+ message: Notification message
84
+
85
+ Returns:
86
+ Notification send result
87
+ """
88
+ try:
89
+ url = f"{self.BASE_URLS['hermes']}/messages/inbox/multicast"
90
+
91
+ # Create payload for squad battle notification
92
+ payload_data = {
93
+ "aps": {
94
+ "alert": {
95
+ "action-loc-key": "BL",
96
+ "loc-key": "M"
97
+ },
98
+ "sound": "pn_squad_invite.wav"
99
+ },
100
+ "h": lobby_host,
101
+ "m": str(lobby_port),
102
+ "p": 36843, # Default port
103
+ "r": room_id,
104
+ "ts": int(__import__('time').time()),
105
+ "type": "sb" # Squad battle
106
+ }
107
+
108
+ data = {
109
+ "access_token": self._token_data["access_token"],
110
+ "payload": json.dumps(payload_data),
111
+ "credentials": "[]",
112
+ "alert_kairos": "true"
113
+ }
114
+
115
+ debug_print(f"Sending squad battle notification to room: {room_id}", "info")
116
+ result = self._make_request("POST", url, data=data)
117
+
118
+ if result:
119
+ debug_print("✅ Squad battle notification sent", "success")
120
+ report_usage("send_squad_battle_notification", True, 0, {
121
+ "room_id": room_id,
122
+ "lobby_host": lobby_host
123
+ })
124
+
125
+ return result
126
+
127
+ except Exception as e:
128
+ debug_print(f"❌ Failed to send squad battle notification: {e}", "error")
129
+ report_error(e, "send_squad_battle_notification", {
130
+ "room_id": room_id,
131
+ "lobby_host": lobby_host
132
+ })
133
+ raise
134
+
135
+ @debug_function
136
+ def get_squad_wall_messages(self,
137
+ squad_id: str,
138
+ limit: int = 20,
139
+ sort_type: str = "chronological",
140
+ include_fields: str = "actor,creation,id,text") -> List[Dict[str, Any]]:
141
+ """
142
+ Get squad wall messages including battle results.
143
+
144
+ Args:
145
+ squad_id: Squad/group ID
146
+ limit: Number of messages to retrieve (default: 20)
147
+ sort_type: Sort order (chronological, etc.)
148
+ include_fields: Fields to include in response
149
+
150
+ Returns:
151
+ List of wall messages with battle information
152
+ """
153
+ try:
154
+ url = f"{self.BASE_URLS['osiris']}/groups/{squad_id}/wall"
155
+
156
+ params = {
157
+ "access_token": self._token_data["access_token"],
158
+ "sort_type": sort_type,
159
+ "limit": str(limit),
160
+ "include_fields": include_fields
161
+ }
162
+
163
+ debug_print(f"Getting squad wall messages for: {squad_id}", "info")
164
+ result = self._make_request("GET", url, params=params)
165
+
166
+ if result:
167
+ battle_messages = []
168
+ for message in result:
169
+ # Parse battle messages
170
+ if message.get("text"):
171
+ try:
172
+ text_data = json.loads(message["text"])
173
+ if text_data.get("msg_type") == 2: # Battle result
174
+ battle_info = {
175
+ "id": message.get("id"),
176
+ "creation": message.get("creation"),
177
+ "actor": message.get("actor"),
178
+ "battle_data": text_data
179
+ }
180
+ battle_messages.append(battle_info)
181
+ except json.JSONDecodeError:
182
+ # Skip non-JSON messages
183
+ continue
184
+
185
+ debug_print(f"✅ Found {len(battle_messages)} battle messages", "success")
186
+ report_usage("get_squad_wall_messages", True, 0, {
187
+ "squad_id": squad_id,
188
+ "battle_messages_count": len(battle_messages)
189
+ })
190
+
191
+ return battle_messages
192
+
193
+ return []
194
+
195
+ except Exception as e:
196
+ debug_print(f"❌ Failed to get squad wall messages: {e}", "error")
197
+ report_error(e, "get_squad_wall_messages", {
198
+ "squad_id": squad_id,
199
+ "limit": limit
200
+ })
201
+ raise
202
+
203
+ @debug_function
204
+ def post_squad_battle_result(self,
205
+ squad_id: str,
206
+ squad_score: int,
207
+ enemy_squad_id: str,
208
+ enemy_squad_name: str,
209
+ enemy_squad_logo: str = "31",
210
+ enemy_squad_logo_color1: str = "16428544",
211
+ enemy_squad_logo_color2: str = "16428544",
212
+ enemy_squad_score: int = 0) -> Dict[str, Any]:
213
+ """
214
+ Post squad battle result to squad wall.
215
+
216
+ Args:
217
+ squad_id: Your squad ID
218
+ squad_score: Your squad's score
219
+ enemy_squad_id: Enemy squad ID
220
+ enemy_squad_name: Enemy squad name
221
+ enemy_squad_logo: Enemy squad logo ID
222
+ enemy_squad_logo_color1: Enemy squad logo color 1
223
+ enemy_squad_logo_color2: Enemy squad logo color 2
224
+ enemy_squad_score: Enemy squad's score
225
+
226
+ Returns:
227
+ Post result
228
+ """
229
+ try:
230
+ url = f"{self.BASE_URLS['osiris']}/groups/{squad_id}/wall"
231
+
232
+ # Create battle result message
233
+ battle_data = {
234
+ "msg_type": 2, # Battle result message type
235
+ "squad_score": squad_score,
236
+ "enemy_squad_id": enemy_squad_id,
237
+ "enemy_squad_name": enemy_squad_name,
238
+ "enemy_squad_logo": enemy_squad_logo,
239
+ "enemy_squad_logo_color1": enemy_squad_logo_color1,
240
+ "enemy_squad_logo_color2": enemy_squad_logo_color2,
241
+ "enemy_squad_score": enemy_squad_score
242
+ }
243
+
244
+ data = {
245
+ "access_token": self._token_data["access_token"],
246
+ "text": json.dumps(battle_data)
247
+ }
248
+
249
+ debug_print(f"Posting battle result: {squad_score} vs {enemy_squad_score}", "info")
250
+ result = self._make_request("POST", url, data=data)
251
+
252
+ if result:
253
+ debug_print("✅ Battle result posted to squad wall", "success")
254
+ report_usage("post_squad_battle_result", True, 0, {
255
+ "squad_id": squad_id,
256
+ "squad_score": squad_score,
257
+ "enemy_squad_score": enemy_squad_score
258
+ })
259
+
260
+ return result
261
+
262
+ except Exception as e:
263
+ debug_print(f"❌ Failed to post battle result: {e}", "error")
264
+ report_error(e, "post_squad_battle_result", {
265
+ "squad_id": squad_id,
266
+ "squad_score": squad_score,
267
+ "enemy_squad_id": enemy_squad_id
268
+ })
269
+ raise
270
+
271
+ @debug_function
272
+ def get_squad_battle_history(self, squad_id: str, limit: int = 50) -> List[Dict[str, Any]]:
273
+ """
274
+ Get complete squad battle history from wall messages.
275
+
276
+ Args:
277
+ squad_id: Squad ID
278
+ limit: Number of messages to analyze
279
+
280
+ Returns:
281
+ List of battle results with detailed information
282
+ """
283
+ try:
284
+ # Get wall messages
285
+ messages = self.get_squad_wall_messages(squad_id, limit=limit)
286
+
287
+ battle_history = []
288
+ for message in messages:
289
+ battle_data = message.get("battle_data", {})
290
+
291
+ # Extract battle information
292
+ battle_info = {
293
+ "message_id": message.get("id"),
294
+ "creation_time": message.get("creation"),
295
+ "posted_by": message.get("actor", {}).get("name", "Unknown"),
296
+ "squad_score": battle_data.get("squad_score", 0),
297
+ "enemy_squad_id": battle_data.get("enemy_squad_id"),
298
+ "enemy_squad_name": battle_data.get("enemy_squad_name"),
299
+ "enemy_squad_logo": battle_data.get("enemy_squad_logo"),
300
+ "enemy_squad_logo_color1": battle_data.get("enemy_squad_logo_color1"),
301
+ "enemy_squad_logo_color2": battle_data.get("enemy_squad_logo_color2"),
302
+ "enemy_squad_score": battle_data.get("enemy_squad_score", 0),
303
+ "result": "Victory" if battle_data.get("squad_score", 0) > battle_data.get("enemy_squad_score", 0) else "Defeat"
304
+ }
305
+
306
+ battle_history.append(battle_info)
307
+
308
+ debug_print(f"✅ Retrieved {len(battle_history)} battle results", "success")
309
+ return battle_history
310
+
311
+ except Exception as e:
312
+ debug_print(f"❌ Failed to get battle history: {e}", "error")
313
+ report_error(e, "get_squad_battle_history", {"squad_id": squad_id})
314
+ raise
315
+
316
+ @debug_function
317
+ def analyze_squad_performance(self, squad_id: str, limit: int = 100) -> Dict[str, Any]:
318
+ """
319
+ Analyze squad battle performance statistics.
320
+
321
+ Args:
322
+ squad_id: Squad ID
323
+ limit: Number of battles to analyze
324
+
325
+ Returns:
326
+ Performance statistics
327
+ """
328
+ try:
329
+ battles = self.get_squad_battle_history(squad_id, limit=limit)
330
+
331
+ if not battles:
332
+ return {"error": "No battle history found"}
333
+
334
+ # Calculate statistics
335
+ total_battles = len(battles)
336
+ victories = sum(1 for battle in battles if battle["result"] == "Victory")
337
+ defeats = total_battles - victories
338
+
339
+ total_score = sum(battle["squad_score"] for battle in battles)
340
+ total_enemy_score = sum(battle["enemy_squad_score"] for battle in battles)
341
+
342
+ avg_score = total_score / total_battles if total_battles > 0 else 0
343
+ avg_enemy_score = total_enemy_score / total_battles if total_battles > 0 else 0
344
+
345
+ win_rate = (victories / total_battles * 100) if total_battles > 0 else 0
346
+
347
+ # Find most common enemies
348
+ enemy_frequency = {}
349
+ for battle in battles:
350
+ enemy = battle["enemy_squad_name"]
351
+ enemy_frequency[enemy] = enemy_frequency.get(enemy, 0) + 1
352
+
353
+ top_enemies = sorted(enemy_frequency.items(), key=lambda x: x[1], reverse=True)[:5]
354
+
355
+ stats = {
356
+ "squad_id": squad_id,
357
+ "total_battles": total_battles,
358
+ "victories": victories,
359
+ "defeats": defeats,
360
+ "win_rate": round(win_rate, 2),
361
+ "total_score": total_score,
362
+ "total_enemy_score": total_enemy_score,
363
+ "average_score": round(avg_score, 2),
364
+ "average_enemy_score": round(avg_enemy_score, 2),
365
+ "score_difference": total_score - total_enemy_score,
366
+ "top_enemies": [{"name": name, "battles": count} for name, count in top_enemies],
367
+ "recent_performance": battles[:10] # Last 10 battles
368
+ }
369
+
370
+ debug_print(f"✅ Squad performance analyzed: {win_rate:.1f}% win rate", "success")
371
+ return stats
372
+
373
+ except Exception as e:
374
+ debug_print(f"❌ Failed to analyze squad performance: {e}", "error")
375
+ report_error(e, "analyze_squad_performance", {"squad_id": squad_id})
376
+ raise
377
+
378
+ @debug_function
379
+ def post_squad_wall_message(self,
380
+ squad_id: str,
381
+ message: str,
382
+ player_killsig: str = "default_killsig_42",
383
+ player_killsig_color: int = -974646126,
384
+ language: str = "en",
385
+ activity_type: str = "user_post") -> Dict[str, Any]:
386
+ """
387
+ Post a simple message to squad wall.
388
+
389
+ Args:
390
+ squad_id: Squad/group ID
391
+ message: Message text to post
392
+ player_killsig: Player kill signature ID
393
+ player_killsig_color: Kill signature color
394
+ language: Message language (default: "en")
395
+ activity_type: Activity type (default: "user_post")
396
+
397
+ Returns:
398
+ Post result with message ID
399
+ """
400
+ try:
401
+ url = f"{self.BASE_URLS['osiris']}/groups/{squad_id}/wall"
402
+
403
+ # Create message payload
404
+ message_data = {
405
+ "msg_body": message,
406
+ "msg_type": 0, # Simple message type
407
+ "playerKillSign": player_killsig,
408
+ "playerKillSignColor": player_killsig_color
409
+ }
410
+
411
+ data = {
412
+ "access_token": self._token_data["access_token"],
413
+ "text": json.dumps(message_data),
414
+ "language": language,
415
+ "activity_type": activity_type,
416
+ "alert_kairos": "false"
417
+ }
418
+
419
+ debug_print(f"Posting message to squad wall: {message[:30]}...", "info")
420
+ result = self._make_request("POST", url, data=data)
421
+
422
+ if result:
423
+ message_id = result.get('id')
424
+ debug_print(f"✅ Message posted successfully! ID: {message_id}", "success")
425
+ report_usage("post_squad_wall_message", True, 0, {
426
+ "squad_id": squad_id,
427
+ "message_id": message_id,
428
+ "message_length": len(message)
429
+ })
430
+
431
+ return result
432
+
433
+ except Exception as e:
434
+ debug_print(f"❌ Failed to post wall message: {e}", "error")
435
+ report_error(e, "post_squad_wall_message", {
436
+ "squad_id": squad_id,
437
+ "message": message[:50]
438
+ })
439
+ raise
@@ -0,0 +1,223 @@
1
+ #!/usr/bin/env python3
2
+ # ────────────[ CHIZOBA ]────────────────────────────
3
+ # | Email : chizoba2026@hotmail.com
4
+ # | File : squad_battle_quick.py
5
+ # | License | MIT License © 2026 Chizoba
6
+ # | Brief | Quick functions for squad battle operations
7
+ # ────────────────★─────────────────────────────────
8
+
9
+ from typing import Optional, Dict, Any, List
10
+ from .simple_client import SimpleMC5Client
11
+ from .telemetry import report_usage
12
+ from .debug import debug_function, debug_print
13
+
14
+ @debug_function
15
+ def quick_create_squad_battle_room(username: str, password: str, capacity: int = 2) -> Optional[Dict[str, Any]]:
16
+ """
17
+ Quick function to create a squad battle room.
18
+
19
+ Args:
20
+ username: MC5 username
21
+ password: MC5 password
22
+ capacity: Room capacity (default: 2)
23
+
24
+ Returns:
25
+ Room creation response or None if failed
26
+ """
27
+ try:
28
+ with SimpleMC5Client(username, password) as client:
29
+ if client.connect():
30
+ result = client.client.create_squad_battle_room(capacity=capacity)
31
+ debug_print(f"✅ Squad battle room created: {result.get('room_id')}", "success")
32
+ return result
33
+ return None
34
+ except Exception as e:
35
+ debug_print(f"❌ Failed to create squad battle room: {e}", "error")
36
+ return None
37
+
38
+ @debug_function
39
+ def quick_post_squad_battle_result(username: str, password: str,
40
+ squad_id: str,
41
+ squad_score: int,
42
+ enemy_squad_id: str,
43
+ enemy_squad_name: str,
44
+ enemy_squad_score: int = 0) -> bool:
45
+ """
46
+ Quick function to post squad battle result.
47
+
48
+ Args:
49
+ username: MC5 username
50
+ password: MC5 password
51
+ squad_id: Your squad ID
52
+ squad_score: Your squad's score
53
+ enemy_squad_id: Enemy squad ID
54
+ enemy_squad_name: Enemy squad name
55
+ enemy_squad_score: Enemy squad's score
56
+
57
+ Returns:
58
+ True if successful, False otherwise
59
+ """
60
+ try:
61
+ with SimpleMC5Client(username, password) as client:
62
+ if client.connect():
63
+ result = client.client.post_squad_battle_result(
64
+ squad_id=squad_id,
65
+ squad_score=squad_score,
66
+ enemy_squad_id=enemy_squad_id,
67
+ enemy_squad_name=enemy_squad_name,
68
+ enemy_squad_score=enemy_squad_score
69
+ )
70
+ debug_print(f"✅ Battle result posted: {squad_score} vs {enemy_squad_score}", "success")
71
+ return bool(result)
72
+ return False
73
+ except Exception as e:
74
+ debug_print(f"❌ Failed to post battle result: {e}", "error")
75
+ return False
76
+
77
+ @debug_function
78
+ def quick_get_squad_battle_history(username: str, password: str, squad_id: str, limit: int = 50) -> Optional[List[Dict[str, Any]]]:
79
+ """
80
+ Quick function to get squad battle history.
81
+
82
+ Args:
83
+ username: MC5 username
84
+ password: MC5 password
85
+ squad_id: Squad ID
86
+ limit: Number of battles to retrieve
87
+
88
+ Returns:
89
+ List of battle results or None if failed
90
+ """
91
+ try:
92
+ with SimpleMC5Client(username, password) as client:
93
+ if client.connect():
94
+ battles = client.client.get_squad_battle_history(squad_id, limit=limit)
95
+ debug_print(f"✅ Retrieved {len(battles)} battle results", "success")
96
+ return battles
97
+ return None
98
+ except Exception as e:
99
+ debug_print(f"❌ Failed to get battle history: {e}", "error")
100
+ return None
101
+
102
+ @debug_function
103
+ def quick_analyze_squad_performance(username: str, password: str, squad_id: str, limit: int = 100) -> Optional[Dict[str, Any]]:
104
+ """
105
+ Quick function to analyze squad performance.
106
+
107
+ Args:
108
+ username: MC5 username
109
+ password: MC5 password
110
+ squad_id: Squad ID
111
+ limit: Number of battles to analyze
112
+
113
+ Returns:
114
+ Performance statistics or None if failed
115
+ """
116
+ try:
117
+ with SimpleMC5Client(username, password) as client:
118
+ if client.connect():
119
+ stats = client.client.analyze_squad_performance(squad_id, limit=limit)
120
+ debug_print(f"✅ Squad performance analyzed: {stats.get('win_rate', 0)}% win rate", "success")
121
+ return stats
122
+ return None
123
+ except Exception as e:
124
+ debug_print(f"❌ Failed to analyze squad performance: {e}", "error")
125
+ return None
126
+
127
+ @debug_function
128
+ def quick_get_squad_wall_messages(username: str, password: str, squad_id: str, limit: int = 20) -> Optional[List[Dict[str, Any]]]:
129
+ """
130
+ Quick function to get squad wall messages.
131
+
132
+ Args:
133
+ username: MC5 username
134
+ password: MC5 password
135
+ squad_id: Squad ID
136
+ limit: Number of messages to retrieve
137
+
138
+ Returns:
139
+ List of wall messages or None if failed
140
+ """
141
+ try:
142
+ with SimpleMC5Client(username, password) as client:
143
+ if client.connect():
144
+ messages = client.client.get_squad_wall_messages(squad_id, limit=limit)
145
+ debug_print(f"✅ Retrieved {len(messages)} wall messages", "success")
146
+ return messages
147
+ return None
148
+ except Exception as e:
149
+ debug_print(f"❌ Failed to get wall messages: {e}", "error")
150
+ return None
151
+
152
+ @debug_function
153
+ def quick_post_squad_wall_message(username: str, password: str,
154
+ squad_id: str,
155
+ message: str,
156
+ player_killsig: str = "default_killsig_42",
157
+ player_killsig_color: int = -974646126) -> Optional[str]:
158
+ """
159
+ Quick function to post a message to squad wall.
160
+
161
+ Args:
162
+ username: MC5 username
163
+ password: MC5 password
164
+ squad_id: Squad ID
165
+ message: Message text to post
166
+ player_killsig: Player kill signature ID
167
+ player_killsig_color: Kill signature color
168
+
169
+ Returns:
170
+ Message ID if successful, None otherwise
171
+ """
172
+ try:
173
+ with SimpleMC5Client(username, password) as client:
174
+ if client.connect():
175
+ result = client.client.post_squad_wall_message(
176
+ squad_id=squad_id,
177
+ message=message,
178
+ player_killsig=player_killsig,
179
+ player_killsig_color=player_killsig_color
180
+ )
181
+
182
+ if result:
183
+ message_id = result.get('id')
184
+ debug_print(f"✅ Message posted! ID: {message_id}", "success")
185
+ return message_id
186
+ return None
187
+ return None
188
+ except Exception as e:
189
+ debug_print(f"❌ Failed to post wall message: {e}", "error")
190
+ return None
191
+
192
+ @debug_function
193
+ def quick_send_squad_battle_notification(username: str, password: str,
194
+ room_id: str,
195
+ lobby_host: str,
196
+ lobby_port: int) -> bool:
197
+ """
198
+ Quick function to send squad battle notification.
199
+
200
+ Args:
201
+ username: MC5 username
202
+ password: MC5 password
203
+ room_id: Room ID from battle creation
204
+ lobby_host: Lobby host from battle creation
205
+ lobby_port: Lobby port from battle creation
206
+
207
+ Returns:
208
+ True if successful, False otherwise
209
+ """
210
+ try:
211
+ with SimpleMC5Client(username, password) as client:
212
+ if client.connect():
213
+ result = client.client.send_squad_battle_notification(
214
+ room_id=room_id,
215
+ lobby_host=lobby_host,
216
+ lobby_port=lobby_port
217
+ )
218
+ debug_print("✅ Squad battle notification sent", "success")
219
+ return bool(result)
220
+ return False
221
+ except Exception as e:
222
+ debug_print(f"❌ Failed to send notification: {e}", "error")
223
+ return False