-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlogger.py
More file actions
152 lines (110 loc) · 4.14 KB
/
Copy pathlogger.py
File metadata and controls
152 lines (110 loc) · 4.14 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
import inspect
import json
import math
from datetime import datetime
from typing import NotRequired, TypedDict
class SpriteInfo(TypedDict):
type: str
pos: NotRequired[list[float]]
vel: NotRequired[list[float]]
rad: NotRequired[float]
rot: NotRequired[float]
class GroupInfo(TypedDict):
count: int
sprites: list[SpriteInfo]
__all__ = ["log_state", "log_event"]
_FPS = 60
_MAX_SECONDS = 16
_SPRITE_SAMPLE_LIMIT = 10 # Maximum number of sprites to log per group
_frame_count = 0
_state_log_initialized = False
_event_log_initialized = False
_start_time = datetime.now()
def log_state() -> None:
global _frame_count, _state_log_initialized
# Stop logging after `_MAX_SECONDS` seconds
if _frame_count > _FPS * _MAX_SECONDS:
return
# Take a snapshot approx. once per second
_frame_count += 1
if _frame_count % _FPS != 0:
return
now = datetime.now()
frame = inspect.currentframe()
if frame is None:
return
frame_back = frame.f_back
if frame_back is None:
return
local_vars = frame_back.f_locals.copy()
screen_size: list[int] = []
game_state: dict[str, object] = {}
sprite_info: SpriteInfo
for key, value in local_vars.items():
if "pygame" in str(type(value)) and hasattr(value, "get_size"):
screen_size = list(value.get_size())
if hasattr(value, "__class__") and "Group" in value.__class__.__name__:
sprites_data: list[SpriteInfo] = []
for i, sprite in enumerate(value):
if i >= _SPRITE_SAMPLE_LIMIT:
break
sprite_info = {"type": sprite.__class__.__name__}
if hasattr(sprite, "position"):
sprite_info["pos"] = [
round(sprite.position.x, 2),
round(sprite.position.y, 2),
]
if hasattr(sprite, "velocity"):
sprite_info["vel"] = [
round(sprite.velocity.x, 2),
round(sprite.velocity.y, 2),
]
if hasattr(sprite, "radius"):
sprite_info["rad"] = sprite.radius
if hasattr(sprite, "rotation"):
sprite_info["rot"] = round(sprite.rotation, 2)
sprites_data.append(sprite_info)
group_info: GroupInfo = {"count": len(value), "sprites": sprites_data}
game_state[key] = group_info
if len(game_state) == 0 and hasattr(value, "position"):
sprite_info = {"type": value.__class__.__name__}
sprite_info["pos"] = [
round(value.position.x, 2),
round(value.position.y, 2),
]
if hasattr(value, "velocity"):
sprite_info["vel"] = [
round(value.velocity.x, 2),
round(value.velocity.y, 2),
]
if hasattr(value, "radius"):
sprite_info["rad"] = value.radius
if hasattr(value, "rotation"):
sprite_info["rot"] = round(value.rotation, 2)
game_state[key] = sprite_info
entry: dict[str, object] = {
"timestamp": now.strftime("%H:%M:%S.%f")[:-3],
"elapsed_s": math.floor((now - _start_time).total_seconds()),
"frame": _frame_count,
"screen_size": screen_size,
**game_state,
}
# New log file on each run
mode = "w" if not _state_log_initialized else "a"
with open("game_state.jsonl", mode) as f:
f.write(json.dumps(entry) + "\n")
_state_log_initialized = True
def log_event(event_type: str, **details: object) -> None:
global _event_log_initialized
now = datetime.now()
event: dict[str, object] = {
"timestamp": now.strftime("%H:%M:%S.%f")[:-3],
"elapsed_s": math.floor((now - _start_time).total_seconds()),
"frame": _frame_count,
"type": event_type,
**details,
}
mode = "w" if not _event_log_initialized else "a"
with open("game_events.jsonl", mode) as f:
f.write(json.dumps(event) + "\n")
_event_log_initialized = True