-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconverter.py
More file actions
111 lines (93 loc) · 4.03 KB
/
Copy pathconverter.py
File metadata and controls
111 lines (93 loc) · 4.03 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
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# This script converts a N demo file into libTAS inputs
# Usage: python converter.py
import sys
def decode_demo_number(num, debug=False):
"""
Decode one demo number into 7 frames of inputs.
Returns list of sets: [{'left','jump'}, {}, {'right'}, ...]
"""
frames = [set() for _ in range(7)]
# Each input has weight per frame (powers of 16).
# All the "hold" cases are not actually jumps, they seem to be
# meaningless. Dropping them.
mapping = {
'left': [1, 16, 256, 4096, 65536, 1048576, 16777216],
'right': [2, 32, 512, 8192, 131072, 2097152, 33554432],
'jump': [12, 192, 3072, 49152, 786432, 12582912, 201326592], # jump
# 'jump_hold_prev': [4, 68, 1092, 17476, 279620, 4473924, 71582788], # hold from prev 7 frames (as jump)
# 'jump_hold': [4, 64, 1024, 16384, 262144, 4194304, 67108864], # hold (theoretical values)
# 'jump_and_hold': [76, 1216, 19456, 311296, 4980736, 79691776, 0], # jump+hold
# 'jump_and_hold2': [0, 1100, 17600, 281600, 4505600, 72089600, 0], # jump+hold+hold
# 'jump_and_hold3': [0, 0, 17484, 279744, 4475904, 71614464, 0], # etc
# 'jump_and_hold4': [0, 0, 0, 279628, 4474048, 71584768, 0],
# 'jump_and_hold5': [0, 0, 0, 0, 4473932, 71582912, 0],
# 'jump_and_hold6': [0, 0, 0, 0, 0, 71582796, 0],
}
if debug:
print("num %s" % num)
for i in range(7):
for key, weights in mapping.items():
if num & weights[i]:
if key in ['jump_hold_prev', 'jump_hold',
'jump_and_hold', 'jump_and_hold2', 'jump_and_hold3',
'jump_and_hold4', 'jump_and_hold5', 'jump_and_hold6']:
new_key = 'jump' # they're all just jumps
else:
new_key = key
if new_key not in frames[i]: # avoid duplicates
frames[i].add(new_key)
if debug:
print("Add key %s to frame %s" % (key, i))
return frames
def convert_chunks(demo_numbers, advertised_nb_frames, debug=False):
"""
demo_numbers: list of integers (each encodes 7 frames)
output_path: path to save libtas input file
"""
# Xlib KeySym mapping
keysym_map = {
'left': 'ff51', # XK_Left
'right': 'ff53', # XK_Right
'jump': 'ffe1', # XK_Shift_L
}
res = ""
nb_frames = 0
for num in demo_numbers:
frames = decode_demo_number(num, debug)
for frame in frames:
if frame:
pressed = ":".join(keysym_map[key] for key in frame)
res += f"|K{pressed}|\n"
nb_frames += 1
# Avoid adding additional frames at the end
elif nb_frames < advertised_nb_frames:
res += "|\n"
nb_frames += 1
return res, nb_frames
def extract_chunks(demo_str):
"""
Extract only the chunk part from a demo string.
Flexible: works whether the demo has multiple '#' sections
or is just a single '#chunks#' block.
"""
parts = demo_str.split('#')
if len(parts) < 2:
raise ValueError("Invalid demo format: missing '#' separators")
# The last '#' section should contain the chunks
chunk_section = parts[-2] if parts[-1] == '' else parts[-1]
if ':' not in chunk_section:
raise ValueError("Invalid chunk section: missing ':' separator")
number_of_frames, chunks_str = chunk_section.split(':', 1)
number_of_frames = int(number_of_frames)
chunks = [int(x) for x in chunks_str.split('|') if x.strip()]
return chunks, number_of_frames
def convert_demo_to_libtas(demo_str):
demo_numbers, advertised_nb_frames = extract_chunks(demo_str)
return convert_chunks(demo_numbers, advertised_nb_frames)
if __name__ == "__main__":
demo_str = sys.stdin.read().strip()
demo_numbers, nb_frames = extract_chunks(demo_str)
libtas_input, nb_frames = convert_chunks(demo_numbers, nb_frames, debug=False)
print(libtas_input, end="")