Skip to content

Commit 6e16b1f

Browse files
Merge pull request #128 from denniske/2025-08-uptimes
parse uptimes from chat and return in model
2 parents 83c6f6e + 078e216 commit 6e16b1f

5 files changed

Lines changed: 105 additions & 6 deletions

File tree

mgz/common/chat.py

Lines changed: 73 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,66 @@
33
import logging
44
from enum import Enum
55

6+
from mgz.fast import Age
7+
68
LOGGER = logging.getLogger(__name__)
9+
FEUDAL_AGE_MARKERS = [
10+
'봉건 시대',
11+
'Edad Feudal',
12+
'封建时代',
13+
'Feudalzeit',
14+
'Feodal Çağ',
15+
'封建時代',
16+
'Edad Feudal',
17+
'領主の時代',
18+
'Zaman Feudal',
19+
'Età feudale',
20+
'Feudal Age',
21+
'Thời phong kiến',
22+
'सामंतवादी युग',
23+
'Era Feudalna',
24+
'Idade Feudal',
25+
'Âge féodal',
26+
'Феодальная эпоха',
27+
]
28+
CASTLE_AGE_MARKERS = [
29+
'성주 시대',
30+
'Ed. Castillos',
31+
'城堡时代',
32+
'Ritterzeit',
33+
'Kale Çağı',
34+
'城堡時代',
35+
'Edad de los Castillos',
36+
'城主の時代',
37+
'Zaman Kastil',
38+
'Età dei castelli',
39+
'Castle Age',
40+
'Thời lâu đài',
41+
'परिवर्तन युग',
42+
'Era Zamków',
43+
'Idade dos Castelos',
44+
'Âge des châteaux',
45+
'Замковая эпоха',
46+
]
47+
IMPERIAL_AGE_MARKERS = [
48+
'왕정 시대',
49+
'Edad Imperial',
50+
'帝王时代',
51+
'Imperialzeit',
52+
'İmparatorluk Çağı',
53+
'帝王時代',
54+
'Edad Imperial',
55+
'帝王の時代',
56+
'Zaman Empayar',
57+
'Età imperiale',
58+
'Imperial Age',
59+
'Thời đế quốc',
60+
'साम्राज्यवादी युग',
61+
'Era Imperiów',
62+
'Idade Imperial',
63+
'Âge impérial',
64+
'Имперская эпоха',
65+
]
766
AGE_MARKERS = [
867
'advanced to the',
968
'a progressé vers',
@@ -26,6 +85,9 @@
2685
'ha raggiunto',
2786
'avanzó a Ed',
2887
'đã nâng cấp',
88+
'युग में उन्नत है।', # hi
89+
'telah mara ke', # ms
90+
'geçti', # tr
2991
]
3092
SAVE_MARKERS = [
3193
'Continuar con la partida en vez de guardar y salir',
@@ -84,10 +146,6 @@ def parse_chat(line, encoding, timestamp, players, diplomacy_type=None, originat
84146
if line.find(save_marker) > 0:
85147
data['type'] = Chat.SAVE
86148
return data
87-
for age_marker in AGE_MARKERS:
88-
if line.find(age_marker) > 0:
89-
data['type'] = Chat.AGE
90-
return data
91149
if line.find('Voobly: Ratings provided') > 0:
92150
_parse_ladder(data, line)
93151
elif line.find('Voobly') == 3:
@@ -102,6 +160,17 @@ def parse_chat(line, encoding, timestamp, players, diplomacy_type=None, originat
102160
_parse_json(data, line, diplomacy_type)
103161
else:
104162
_parse_chat(data, line, players, diplomacy_type)
163+
164+
for age_marker in AGE_MARKERS:
165+
if line.find(age_marker) > 0:
166+
data['type'] = Chat.AGE
167+
if any(marker in line for marker in FEUDAL_AGE_MARKERS):
168+
data['age'] = Age.FEUDAL_AGE
169+
if any(marker in line for marker in CASTLE_AGE_MARKERS):
170+
data['age'] = Age.CASTLE_AGE
171+
if any(marker in line for marker in IMPERIAL_AGE_MARKERS):
172+
data['age'] = Age.IMPERIAL_AGE
173+
105174
if not _validate(data, players):
106175
data['type'] = Chat.DISCARD
107176
return data

mgz/fast/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import io
33
import struct
44

5-
from mgz.fast.enums import Operation, Action, Postgame
5+
from mgz.fast.enums import Operation, Action, Postgame, Age
66
from mgz.fast.actions import parse_action_71094
77
from mgz.util import check_flags, unpack
88

mgz/fast/enums.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,10 @@ class Postgame(Enum):
8787
"""Postgame types."""
8888
WORLD_TIME = 1
8989
LEADERBOARDS = 2
90+
91+
class Age(Enum):
92+
"""Age types."""
93+
DARK_AGE = 1
94+
FEUDAL_AGE = 2
95+
CASTLE_AGE = 3
96+
IMPERIAL_AGE = 4

mgz/model/__init__.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ def parse_match(handle):
233233
resigned = []
234234
actions = []
235235
viewlocks = []
236+
uptimes = []
236237
eapm = collections.Counter()
237238
last_viewlock = None
238239
while True:
@@ -257,6 +258,14 @@ def parse_match(handle):
257258
players[chat['player_number']]
258259
))
259260
inputs.add_chat(chats[-1])
261+
if chat['type'] == ChatEnum.AGE:
262+
uptimes.append(
263+
Uptime(
264+
timedelta(milliseconds=chat['timestamp'] + data['map']['restore_time']),
265+
chat['age'],
266+
players.get(chat['player_number']),
267+
)
268+
)
260269
elif op_type is fast.Operation.ACTION:
261270
action_type, action_data = op_data
262271
action = Action(timedelta(milliseconds=timestamp), action_type, action_data)
@@ -363,7 +372,8 @@ def parse_match(handle):
363372
data['de']['visibility_id'] == 2 if data['version'] is Version.DE else None,
364373
get_hash(data),
365374
actions,
366-
inputs.inputs
375+
inputs.inputs,
376+
uptimes
367377
)
368378

369379

mgz/model/definitions.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from dataclasses import dataclass
44
from datetime import timedelta, datetime
55
from mgz.fast import Action as ActionEnum
6+
from mgz.fast import Age as AgeEnum
67
from mgz.util import Version
78

89

@@ -141,6 +142,17 @@ class Chat:
141142
def __repr__(self):
142143
return f'[{self.timestamp}] {self.player}: {self.message}'
143144

145+
@dataclass
146+
class Uptime:
147+
"""Represents an advanced to age event."""
148+
149+
timestamp: timedelta
150+
age: AgeEnum
151+
player: Player
152+
153+
def __repr__(self):
154+
return f'[{self.timestamp}] {self.player} -> {self.age}'
155+
144156

145157
@dataclass
146158
class Match:
@@ -192,3 +204,4 @@ class Match:
192204
hash: str
193205
actions: list
194206
inputs: list
207+
uptimes: list

0 commit comments

Comments
 (0)