aoe2rec-py 0.1.14__pp311-pypy311_pp73-musllinux_1_2_i686.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.
aoe2rec_py/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ from .summary import RecSummary
2
+
3
+ __all__ = ["RecSummary"]
aoe2rec_py/summary.py ADDED
@@ -0,0 +1,250 @@
1
+ from collections import defaultdict
2
+ import collections
3
+ from dataclasses import dataclass
4
+ from datetime import datetime, timedelta
5
+ import json
6
+ from typing import BinaryIO
7
+
8
+ try:
9
+ from typing import override
10
+ except ImportError:
11
+
12
+ def override(f):
13
+ return f
14
+
15
+
16
+ from aoe2rec_py import aoe2rec_py
17
+
18
+
19
+ @dataclass
20
+ class Chat:
21
+ timestamp: timedelta
22
+ player: str
23
+ message: str
24
+
25
+ @override
26
+ def __str__(self):
27
+ return f"{self.timestamp} - {self.player}: {self.message}"
28
+
29
+
30
+ class RecSummary:
31
+ def __init__(self, handle: BinaryIO):
32
+ data = handle.read()
33
+ self._cache = aoe2rec_py.parse_rec(data)
34
+ self.players = {
35
+ player_id + 1: {"resigned": False, "elo": 0, "eapm": 0, **player}
36
+ for player_id, player in enumerate(
37
+ self._cache["zheader"]["game_settings"]["players"]
38
+ )
39
+ }
40
+ self.duration: float = 0
41
+ self.chats: list[Chat] = []
42
+
43
+ self._parse_operations()
44
+
45
+ def _parse_operations(self):
46
+ eapm_counter = collections.Counter()
47
+ for event in self._cache["operations"]:
48
+ if "Sync" in event:
49
+ self.duration += event["Sync"]["time_increment"]
50
+ if "Chat" in event:
51
+ chat = json.loads(event["Chat"]["text"])
52
+ self.chats.append(
53
+ Chat(
54
+ self.get_duration(),
55
+ self.players[chat["player"]]["name"],
56
+ chat["message"],
57
+ )
58
+ )
59
+ if "Action" in event:
60
+ actions = event["Action"]["action_data"]
61
+ for action_type, action_data in actions.items():
62
+ if "player_id" in action_data:
63
+ eapm_counter[action_data["player_id"]] += 1
64
+ if action_type == "Resign":
65
+ self.players[action_data["player_id"]]["resigned"] = True
66
+ if "PostGame" in event:
67
+ for block in event["PostGame"]["blocks"]:
68
+ if (
69
+ "Leaderboards" not in block
70
+ or block["Leaderboards"]["num_leaderboards"] < 1
71
+ ):
72
+ continue
73
+ for player in block["Leaderboards"]["leaderboards"][0]["players"]:
74
+ if (player["player_number"] + 1) in self.players:
75
+ self.players[player["player_number"] + 1]["elo"] = player[
76
+ "elo"
77
+ ]
78
+ total_minutes = self.get_duration().total_seconds() / 60
79
+ for player_id, action_count in eapm_counter.items():
80
+ self.players[player_id]["eapm"] = int(round(action_count / total_minutes))
81
+
82
+ def get_chat(self):
83
+ return self.chats
84
+
85
+ def get_postgame(self):
86
+ return None
87
+
88
+ def has_achievements(self):
89
+ return False
90
+
91
+ def get_header(self):
92
+ return self._cache["zheader"]
93
+
94
+ def get_start_time(self):
95
+ return self._cache["zheader"]["replay"]["world_time"]
96
+
97
+ def get_duration(self):
98
+ return timedelta(
99
+ milliseconds=self.duration + self._cache["zheader"]["replay"]["world_time"]
100
+ )
101
+
102
+ def get_restored(self):
103
+ return self.get_start_time() > 0, self.get_start_time()
104
+
105
+ def get_version(self):
106
+ header = self._cache["zheader"]
107
+ major = header["version_major"]
108
+ minor = header["version_minor"]
109
+ version = float(f"{major}.{minor}")
110
+ return (
111
+ "DE",
112
+ header["game"],
113
+ version,
114
+ self._cache["log_version"],
115
+ header["build"],
116
+ )
117
+
118
+ def get_owner(self):
119
+ return self._cache["zheader"]["replay"]["rec_player"]
120
+
121
+ def get_teams(self):
122
+ teams: defaultdict[int, list[int]] = defaultdict(list)
123
+ for player_id, player in self.players.items():
124
+ team_id: int = player["resolved_team_id"]
125
+ if team_id > 1:
126
+ teams[team_id].append(player_id)
127
+ elif team_id == 1:
128
+ teams[player_id + 8].append(player_id)
129
+ return set([frozenset(s) for s in teams.values()])
130
+
131
+ def get_diplomacy(self):
132
+ diplo_type = self._get_diplomacy_type()
133
+ if diplo_type == "FFA":
134
+ return {"type": diplo_type, "team_size": "FFA"}
135
+ team_sizes = [str(len(team)) for team in self.get_teams()]
136
+ return {"type": diplo_type, "team_size": "v".join(team_sizes)}
137
+
138
+ def get_players(self):
139
+ return [
140
+ {
141
+ "name": player["name"],
142
+ "number": player_id,
143
+ "civilization": player["civ_id"],
144
+ "color_id": player["color_id"],
145
+ "human": player["player_type"] == 2,
146
+ "winner": not player["resigned"],
147
+ "user_id": player["profile_id"],
148
+ "position": [
149
+ None,
150
+ None,
151
+ ], # TODO: Parse players objects and find starting TC
152
+ "rate_snapshot": player["elo"],
153
+ "prefer_random": player["prefer_random"],
154
+ "eapm": player["eapm"],
155
+ }
156
+ for player_id, player in self.players.items()
157
+ ]
158
+
159
+ def get_objects(self):
160
+ raise NotImplementedError()
161
+
162
+ def get_platform(self):
163
+ settings = self._cache["zheader"]["game_settings"]
164
+ guid = settings["guid"]
165
+ guid_str = f"{guid[0]:02x}{guid[1]:02x}{guid[2]:02x}{guid[3]:02x}-{guid[4]:02x}{guid[5]:02x}-{guid[6]:02x}{guid[7]:02x}-{guid[8]:02x}{guid[9]:02x}-{guid[10]:02x}{guid[11]:02x}{guid[12]:02x}{guid[13]:02x}{guid[14]:02x}{guid[15]:02x}"
166
+ return {
167
+ "platform_id": "de",
168
+ "platform_match_id": guid_str,
169
+ "rated": settings["ranked"],
170
+ "lobby_name": settings["lobby_name"],
171
+ "spec_delay": settings["spec_delay"],
172
+ "allow_specs": settings["allow_specs"],
173
+ "private": settings["lobby_visibility"] == 2,
174
+ }
175
+
176
+ def _get_diplomacy_type(self):
177
+ n_teams = len(self.get_teams())
178
+ n_players = len(self.players)
179
+ if n_teams == 2 and n_players > 2:
180
+ return "TG"
181
+ if n_players == 2:
182
+ return "1v1"
183
+ if n_teams == n_players or (n_teams == 1 and n_players > 2):
184
+ return "FFA"
185
+ return "Other"
186
+
187
+ def get_settings(self):
188
+ settings = self._cache["zheader"]["game_settings"]
189
+ # TODO: Add missing names from constants in aocref
190
+ return {
191
+ "type": (settings["game_type"], "<Missing>"),
192
+ "difficulty": (settings["difficulty"], "<Missing>"),
193
+ "population_limit": settings["population_limit"],
194
+ "speed": (settings["speed"], "<Missing>"),
195
+ "cheats": settings["cheats"],
196
+ "team_together": settings["team_positions"],
197
+ "all_technologies": settings["all_techs"],
198
+ "lock_speed": settings["lock_speed"],
199
+ "lock_teams": settings["lock_teams"],
200
+ "map_reveal_choice": (settings["reveal_map"], "<Missing>"),
201
+ "diplomacy_type": self._get_diplomacy_type(),
202
+ "starting_resouces": (settings["starting_resources_id"], "<Missing>"),
203
+ "starting_age": (settings["starting_age_id"], "<Missing>"),
204
+ "ending_age": (settings["ending_age_id"], "<Missing>"),
205
+ "victory_condition": (settings["victory_type_id"], "<Missing>"),
206
+ "treaty_length": settings["treaty_length"],
207
+ "multiqueue": True, # Always true for DE
208
+ "hidden_civs": settings["hidden_civs"],
209
+ }
210
+
211
+ def get_file_hash(self):
212
+ raise NotImplementedError()
213
+
214
+ def get_hash(self):
215
+ raise NotImplementedError()
216
+
217
+ def get_encoding(self):
218
+ raise NotImplementedError()
219
+
220
+ def get_language(self):
221
+ raise NotImplementedError()
222
+
223
+ def get_device(self):
224
+ raise NotImplementedError()
225
+
226
+ def get_map(self):
227
+ raise NotImplementedError()
228
+
229
+ def get_dataset(self):
230
+ raise NotImplementedError()
231
+
232
+ def get_completed(self):
233
+ raise NotImplementedError()
234
+
235
+ def get_mirror(self):
236
+ raise NotImplementedError()
237
+
238
+ def get_played(self):
239
+ return datetime.fromtimestamp(
240
+ self._cache["zheader"]["game_settings"]["timestamp"]
241
+ )
242
+
243
+
244
+ class NotImplementedError(Exception):
245
+ pass
246
+
247
+
248
+ def test():
249
+ with open("ClickBait_vs_Numerfolt_G1b.aoe2record", "rb") as f:
250
+ return RecSummary(f)
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 2.4
2
+ Name: aoe2rec-py
3
+ Version: 0.1.14
4
+ Classifier: Programming Language :: Rust
5
+ Classifier: Programming Language :: Python :: Implementation :: CPython
6
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
7
+ Requires-Dist: pip>=24.3.1
8
+ Requires-Python: >=3.9
9
+ Project-URL: Homepage, https://github.com/aoe2ct/aoe2rec
10
+ Project-URL: Repository, https://github.com/aoe2ct/aoe2rec/tree/main/crates/aoe2rec-py
@@ -0,0 +1,7 @@
1
+ aoe2rec_py-0.1.14.dist-info/METADATA,sha256=RF0S7Ys08cTRMRcnIw-DVnopR8lqFlj7ebUjzhS9KaI,431
2
+ aoe2rec_py-0.1.14.dist-info/WHEEL,sha256=Fu6Th1513hkS0xzotVqKvs6HLmJq411jN4voXwWEPh8,113
3
+ aoe2rec_py.libs/libgcc_s-27e5a392.so.1,sha256=x5sO63liVwXxrjGGP371wB0RyQe1KEnIynYm82T0G0M,449745
4
+ aoe2rec_py/__init__.py,sha256=yiy3pW1QnH4wdN-MOezsQ2f5OJUaxLgOCxhVwhyX-Cw,58
5
+ aoe2rec_py/aoe2rec_py.pypy311-pp73-x86-linux-gnu.so,sha256=zjS6VVOY42EfyTYdrLU--jthg7dYTcV03XVmly8fmXc,1198785
6
+ aoe2rec_py/summary.py,sha256=zx2k-7gJIU1WJXDRZFlMTQX_51cw7mFif5Szc_PpZ1E,8538
7
+ aoe2rec_py-0.1.14.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.10.2)
3
+ Root-Is-Purelib: false
4
+ Tag: pp311-pypy311_pp73-musllinux_1_2_i686
Binary file