tasd 1.0.0__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.
- tasd/__init__.py +4 -0
- tasd/constants.py +56 -0
- tasd/file.py +57 -0
- tasd/packet.py +304 -0
- tasd/packets/__init__.py +6 -0
- tasd/packets/extra.py +38 -0
- tasd/packets/general.py +406 -0
- tasd/packets/genesis.py +18 -0
- tasd/packets/input.py +106 -0
- tasd/packets/nes.py +38 -0
- tasd/packets/snes.py +50 -0
- tasd/utils.py +128 -0
- tasd-1.0.0.dist-info/METADATA +78 -0
- tasd-1.0.0.dist-info/RECORD +17 -0
- tasd-1.0.0.dist-info/WHEEL +5 -0
- tasd-1.0.0.dist-info/licenses/LICENSE +21 -0
- tasd-1.0.0.dist-info/top_level.txt +1 -0
tasd/__init__.py
ADDED
tasd/constants.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
class _MetaPacketType():
|
|
2
|
+
def __init_subclass__(self):
|
|
3
|
+
keys = [key for key in self.__dict__.keys() if type(self.__dict__[key]) == int]
|
|
4
|
+
self._key2name = dict()
|
|
5
|
+
for key in keys:
|
|
6
|
+
self._key2name[self.__dict__[key]] = key
|
|
7
|
+
|
|
8
|
+
class PacketType(_MetaPacketType):
|
|
9
|
+
# General Keys
|
|
10
|
+
CONSOLE_TYPE = 0x0001
|
|
11
|
+
CONSOLE_REGION = 0x0002
|
|
12
|
+
GAME_TITLE = 0x0003
|
|
13
|
+
ROM_NAME = 0x0004
|
|
14
|
+
ATTRIBUTION = 0x0005
|
|
15
|
+
CATEGORY = 0x0006
|
|
16
|
+
EMULATOR_NAME = 0x0007
|
|
17
|
+
EMULATOR_VERSION = 0x0008
|
|
18
|
+
EMULATOR_CORE = 0x0009
|
|
19
|
+
TAS_LAST_MODIFIED = 0x000A
|
|
20
|
+
DUMP_CREATED = 0x000B
|
|
21
|
+
DUMP_LAST_MODIFIED = 0x000C
|
|
22
|
+
TOTAL_FRAMES = 0x000D
|
|
23
|
+
RERECORDS = 0x000E
|
|
24
|
+
SOURCE_LINK = 0x000F
|
|
25
|
+
BLANK_FRAMES = 0x0010
|
|
26
|
+
VERIFIED = 0x0011
|
|
27
|
+
MEMORY_INIT = 0x0012
|
|
28
|
+
GAME_IDENTIFIER = 0x0013
|
|
29
|
+
MOVIE_LICENSE = 0x0014
|
|
30
|
+
MOVIE_FILE = 0x0015
|
|
31
|
+
PORT_CONTROLLER = 0x00F0
|
|
32
|
+
PORT_OVERREAD = 0x00F1
|
|
33
|
+
# NES Specific Keys
|
|
34
|
+
NES_LATCH_FILTER = 0x0101
|
|
35
|
+
NES_CLOCK_FILTER = 0x0102
|
|
36
|
+
NES_GAME_GENIE_CODE = 0x0104
|
|
37
|
+
# SNES Specific Keys
|
|
38
|
+
SNES_LATCH_FILTER = 0x0201
|
|
39
|
+
SNES_CLOCK_FILTER = 0x0202
|
|
40
|
+
SNES_GAME_GENIE_CODE = 0x0204
|
|
41
|
+
SNES_LATCH_TRAIN = 0x0205
|
|
42
|
+
# Genesis Specific Keys
|
|
43
|
+
GENESIS_GAME_GENIE_CODE = 0x0804
|
|
44
|
+
# Input Frame/Timing Keys
|
|
45
|
+
INPUT_CHUNK = 0xFE01
|
|
46
|
+
INPUT_MOMENT = 0xFE02
|
|
47
|
+
TRANSITION = 0xFE03
|
|
48
|
+
LAG_FRAME_CHUNK = 0xFE04
|
|
49
|
+
MOVIE_TRANSITION = 0xFE05
|
|
50
|
+
# Extraneous Keys
|
|
51
|
+
COMMENT = 0xFF01
|
|
52
|
+
EXPERIMENTAL = 0xFFFE
|
|
53
|
+
UNSPECIFIED = 0xFFFF
|
|
54
|
+
@classmethod
|
|
55
|
+
def lookup(cls, key):
|
|
56
|
+
return cls._key2name.get(key, f'UNKNOWN_PACKET_{key:04X}')
|
tasd/file.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import tasd.packets as packets
|
|
2
|
+
import tasd.constants as constants
|
|
3
|
+
import tasd.utils as utils
|
|
4
|
+
from tasd.packet import lookup_packet, _TASDPacket
|
|
5
|
+
from typing import List
|
|
6
|
+
|
|
7
|
+
class TASD():
|
|
8
|
+
MAGIC = b"TASD"
|
|
9
|
+
def __init__(self, version = 1, g_keylen = 2):
|
|
10
|
+
self.version = version
|
|
11
|
+
self.g_keylen = g_keylen
|
|
12
|
+
self.packets: List[_TASDPacket] = []
|
|
13
|
+
@classmethod
|
|
14
|
+
def from_bytes(cls, buffer: bytes, *, bypass_errors = False):
|
|
15
|
+
magic = utils.readBytes(buffer, 0, 4)
|
|
16
|
+
if magic != cls.MAGIC:
|
|
17
|
+
raise ValueError("Invalid TASD File, Missing Magic")
|
|
18
|
+
version = utils.readUint16(buffer, 4)
|
|
19
|
+
if version != 1 and not bypass_errors:
|
|
20
|
+
raise ValueError("Unsupported TASD File, Version Unsupported", version)
|
|
21
|
+
g_keylen = utils.readUint8(buffer, 6)
|
|
22
|
+
if g_keylen != 2:
|
|
23
|
+
raise ValueError("Unsupported TASD File, Unknown G_KEYLEN", g_keylen)
|
|
24
|
+
self = cls(version, g_keylen)
|
|
25
|
+
index = 7
|
|
26
|
+
while index < len(buffer):
|
|
27
|
+
key = utils.readUintN(buffer, index, self.g_keylen)
|
|
28
|
+
index += self.g_keylen
|
|
29
|
+
packet_cls = lookup_packet(key)
|
|
30
|
+
pexp = utils.readUint8(buffer, index)
|
|
31
|
+
index += 1
|
|
32
|
+
plen = utils.readUintN(buffer, index, pexp)
|
|
33
|
+
index += pexp
|
|
34
|
+
data = utils.readBytes(buffer, index, plen)
|
|
35
|
+
index += plen
|
|
36
|
+
packet = packet_cls.from_bytes(data)
|
|
37
|
+
self.packets.append(packet)
|
|
38
|
+
return self
|
|
39
|
+
def to_bytes(self):
|
|
40
|
+
header = bytearray(7)
|
|
41
|
+
header[0:4] = self.MAGIC
|
|
42
|
+
utils.writeUint16(self.version, header, 4)
|
|
43
|
+
utils.writeUint8(self.g_keylen, header, 6)
|
|
44
|
+
packets = [ header ]
|
|
45
|
+
for packet in self.packets:
|
|
46
|
+
plen = packet.size()
|
|
47
|
+
pexp = utils.minUint(plen)
|
|
48
|
+
size = self.g_keylen + 1 + pexp
|
|
49
|
+
buffer = bytearray(size)
|
|
50
|
+
utils.writeUintN(packet._key, buffer, 0, self.g_keylen)
|
|
51
|
+
utils.writeUint8(pexp, buffer, self.g_keylen)
|
|
52
|
+
utils.writeUintN(plen, buffer, self.g_keylen + 1, pexp)
|
|
53
|
+
payload = packet.to_bytes()
|
|
54
|
+
packets.append(buffer + payload)
|
|
55
|
+
return b"".join(packets)
|
|
56
|
+
def __repr__(self):
|
|
57
|
+
return f"TASD(version={self.version}, g_keylen={self.g_keylen})"
|
tasd/packet.py
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
from typing import NamedTuple, List, Any
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
from tasd.constants import PacketType
|
|
5
|
+
from tasd.utils import *
|
|
6
|
+
|
|
7
|
+
class _VariableType(Enum):
|
|
8
|
+
STRING_EOP = 0x00
|
|
9
|
+
STRING_PLEN = 0x01
|
|
10
|
+
STRING_PEXP = 0x02
|
|
11
|
+
BYTES_EOP = 0x10
|
|
12
|
+
BYTES_PLEN = 0x11
|
|
13
|
+
BYTES_PEXP = 0x12
|
|
14
|
+
INT_8 = 0x20
|
|
15
|
+
INT_16 = 0x21
|
|
16
|
+
INT_24 = 0x22
|
|
17
|
+
INT_32 = 0x23
|
|
18
|
+
INT_64 = 0x24
|
|
19
|
+
INT_N = 0x25
|
|
20
|
+
UINT_8 = 0x30
|
|
21
|
+
UINT_16 = 0x31
|
|
22
|
+
UINT_24 = 0x32
|
|
23
|
+
UINT_32 = 0x33
|
|
24
|
+
UINT_64 = 0x34
|
|
25
|
+
UINT_N = 0x35
|
|
26
|
+
BOOL = 0x40
|
|
27
|
+
LIST_UINT_64 = 0x50
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class _VariableDefinition(NamedTuple):
|
|
31
|
+
name: str
|
|
32
|
+
type: _VariableType
|
|
33
|
+
default: Any
|
|
34
|
+
|
|
35
|
+
class _EnumDefinition(NamedTuple):
|
|
36
|
+
name: str
|
|
37
|
+
enum: Enum
|
|
38
|
+
|
|
39
|
+
class _TASDPacket():
|
|
40
|
+
@classmethod
|
|
41
|
+
def from_bytes(cls, buffer: bytes):
|
|
42
|
+
self = cls()
|
|
43
|
+
index = 0
|
|
44
|
+
for variable in cls._variables:
|
|
45
|
+
match variable.type:
|
|
46
|
+
case _VariableType.STRING_EOP:
|
|
47
|
+
setattr(self, variable.name, readString(buffer, index, len(buffer) - index))
|
|
48
|
+
index = len(buffer)
|
|
49
|
+
case _VariableType.STRING_PLEN:
|
|
50
|
+
plen = readInt8(buffer, index)
|
|
51
|
+
index += 1
|
|
52
|
+
setattr(self, variable.name, readString(buffer, index, plen))
|
|
53
|
+
index += plen
|
|
54
|
+
case _VariableType.STRING_PEXP:
|
|
55
|
+
pexp = readInt8(buffer, index)
|
|
56
|
+
index += 1
|
|
57
|
+
plen = readIntN(buffer, index, pexp)
|
|
58
|
+
index += pexp
|
|
59
|
+
setattr(self, variable.name, readString(buffer, index, plen))
|
|
60
|
+
index += plen
|
|
61
|
+
case _VariableType.BYTES_EOP:
|
|
62
|
+
setattr(self, variable.name, readBytes(buffer, index, len(buffer)))
|
|
63
|
+
index = len(buffer)
|
|
64
|
+
case _VariableType.BYTES_PLEN:
|
|
65
|
+
plen = readInt8(buffer, index)
|
|
66
|
+
index += 1
|
|
67
|
+
setattr(self, variable.name, readBytes(buffer, index, plen))
|
|
68
|
+
index += plen
|
|
69
|
+
case _VariableType.BYTES_PEXP:
|
|
70
|
+
pexp = readInt8(buffer, index)
|
|
71
|
+
index += 1
|
|
72
|
+
plen = readIntN(buffer, index, pexp)
|
|
73
|
+
index += pexp
|
|
74
|
+
setattr(self, variable.name, readBytes(buffer, index, plen))
|
|
75
|
+
index += plen
|
|
76
|
+
case _VariableType.INT_8:
|
|
77
|
+
setattr(self, variable.name, readInt8(buffer, index))
|
|
78
|
+
index += 1
|
|
79
|
+
case _VariableType.INT_16:
|
|
80
|
+
setattr(self, variable.name, readInt16(buffer, index))
|
|
81
|
+
index += 2
|
|
82
|
+
case _VariableType.INT_24:
|
|
83
|
+
setattr(self, variable.name, readInt24(buffer, index))
|
|
84
|
+
index += 3
|
|
85
|
+
case _VariableType.INT_32:
|
|
86
|
+
setattr(self, variable.name, readInt32(buffer, index))
|
|
87
|
+
index += 4
|
|
88
|
+
case _VariableType.INT_64:
|
|
89
|
+
setattr(self, variable.name, readInt64(buffer, index))
|
|
90
|
+
index += 8
|
|
91
|
+
case _VariableType.INT_N:
|
|
92
|
+
pexp = readInt8(buffer, index)
|
|
93
|
+
index += 1
|
|
94
|
+
setattr(self, variable.name, readIntN(buffer, index, pexp))
|
|
95
|
+
index += pexp
|
|
96
|
+
case _VariableType.UINT_8:
|
|
97
|
+
setattr(self, variable.name, readUint8(buffer, index))
|
|
98
|
+
index += 1
|
|
99
|
+
case _VariableType.UINT_16:
|
|
100
|
+
setattr(self, variable.name, readUint16(buffer, index))
|
|
101
|
+
index += 2
|
|
102
|
+
case _VariableType.UINT_24:
|
|
103
|
+
setattr(self, variable.name, readUint24(buffer, index))
|
|
104
|
+
index += 3
|
|
105
|
+
case _VariableType.UINT_32:
|
|
106
|
+
setattr(self, variable.name, readUint32(buffer, index))
|
|
107
|
+
index += 4
|
|
108
|
+
case _VariableType.UINT_64:
|
|
109
|
+
setattr(self, variable.name, readUint64(buffer, index))
|
|
110
|
+
index += 8
|
|
111
|
+
case _VariableType.UINT_N:
|
|
112
|
+
pexp = readUint8(buffer, index)
|
|
113
|
+
index += 1
|
|
114
|
+
setattr(self, variable.name, readUintN(buffer, index, pexp))
|
|
115
|
+
index += pexp
|
|
116
|
+
case _VariableType.BOOL:
|
|
117
|
+
setattr(self, variable.name, readBoolean(buffer, index))
|
|
118
|
+
index += 1
|
|
119
|
+
case _VariableType.LIST_UINT_64:
|
|
120
|
+
l = list()
|
|
121
|
+
while index < len(buffer):
|
|
122
|
+
l.append(readUint64(buffer, index))
|
|
123
|
+
index += 8
|
|
124
|
+
setattr(self, variable.name, l)
|
|
125
|
+
case _:
|
|
126
|
+
raise ValueError("Unknown Variable Type", variable)
|
|
127
|
+
return self
|
|
128
|
+
def size(self):
|
|
129
|
+
size = 0
|
|
130
|
+
for variable in self._variables:
|
|
131
|
+
value = getattr(self, variable.name)
|
|
132
|
+
match variable.type:
|
|
133
|
+
case _VariableType.STRING_EOP:
|
|
134
|
+
size += sizeString(value)
|
|
135
|
+
case _VariableType.STRING_PLEN:
|
|
136
|
+
size += ( 1 + sizeString(value) )
|
|
137
|
+
case _VariableType.STRING_PEXP:
|
|
138
|
+
vsize = sizeString(value)
|
|
139
|
+
size += ( 1 + minUint(vsize) + vsize )
|
|
140
|
+
case _VariableType.BYTES_EOP:
|
|
141
|
+
size += len(value)
|
|
142
|
+
case _VariableType.BYTES_PLEN:
|
|
143
|
+
size += ( 1 + len(value) )
|
|
144
|
+
case _VariableType.BYTES_PEXP:
|
|
145
|
+
vsize = len(value)
|
|
146
|
+
size += ( 1 + minUint(vsize) + vsize )
|
|
147
|
+
case _VariableType.INT_8:
|
|
148
|
+
size += 1
|
|
149
|
+
case _VariableType.INT_16:
|
|
150
|
+
size += 2
|
|
151
|
+
case _VariableType.INT_24:
|
|
152
|
+
size += 3
|
|
153
|
+
case _VariableType.INT_32:
|
|
154
|
+
size += 4
|
|
155
|
+
case _VariableType.INT_64:
|
|
156
|
+
size += 8
|
|
157
|
+
case _VariableType.INT_N:
|
|
158
|
+
size += minInt(value)
|
|
159
|
+
case _VariableType.UINT_8:
|
|
160
|
+
size += 1
|
|
161
|
+
case _VariableType.UINT_16:
|
|
162
|
+
size += 2
|
|
163
|
+
case _VariableType.UINT_24:
|
|
164
|
+
size += 3
|
|
165
|
+
case _VariableType.UINT_32:
|
|
166
|
+
size += 4
|
|
167
|
+
case _VariableType.UINT_64:
|
|
168
|
+
size += 8
|
|
169
|
+
case _VariableType.UINT_N:
|
|
170
|
+
size += minUint(value)
|
|
171
|
+
case _VariableType.BOOL:
|
|
172
|
+
size += 1
|
|
173
|
+
case _VariableType.LIST_UINT_64:
|
|
174
|
+
size += ( 8 * len(value) )
|
|
175
|
+
case _:
|
|
176
|
+
raise ValueError("Unknown Variable Type", variable)
|
|
177
|
+
return size
|
|
178
|
+
def to_bytes(self):
|
|
179
|
+
buffer = bytearray(self.size())
|
|
180
|
+
index = 0
|
|
181
|
+
for variable in self._variables:
|
|
182
|
+
value = getattr(self, variable.name)
|
|
183
|
+
match variable.type:
|
|
184
|
+
case _VariableType.STRING_EOP:
|
|
185
|
+
writeString(value, buffer, index)
|
|
186
|
+
index += sizeString(value)
|
|
187
|
+
case _VariableType.STRING_PLEN:
|
|
188
|
+
plen = sizeString(value)
|
|
189
|
+
writeUint8(plen, buffer, index)
|
|
190
|
+
index += 1
|
|
191
|
+
writeString(value, buffer, index)
|
|
192
|
+
index += plen
|
|
193
|
+
case _VariableType.STRING_PEXP:
|
|
194
|
+
plen = sizeString(value)
|
|
195
|
+
pexp = minUint(plen)
|
|
196
|
+
writeUint8(pexp, buffer, index)
|
|
197
|
+
index += 1
|
|
198
|
+
writeUintN(plen, buffer, index, pexp)
|
|
199
|
+
index += pexp
|
|
200
|
+
writeString(value, buffer, index)
|
|
201
|
+
index += plen
|
|
202
|
+
case _VariableType.BYTES_EOP:
|
|
203
|
+
writeBytes(value, buffer, index)
|
|
204
|
+
index += len(value)
|
|
205
|
+
case _VariableType.BYTES_PLEN:
|
|
206
|
+
plen = len(value)
|
|
207
|
+
writeUint8(plen, buffer, index)
|
|
208
|
+
index += 1
|
|
209
|
+
writeBytes(value, buffer, index)
|
|
210
|
+
index += plen
|
|
211
|
+
case _VariableType.BYTES_PEXP:
|
|
212
|
+
plen = len(value)
|
|
213
|
+
pexp = minUint(plen)
|
|
214
|
+
writeUint8(pexp, buffer, index)
|
|
215
|
+
index += 1
|
|
216
|
+
writeUintN(plen, buffer, index, pexp)
|
|
217
|
+
index += pexp
|
|
218
|
+
writeBytes(value, buffer, index)
|
|
219
|
+
index += plen
|
|
220
|
+
case _VariableType.INT_8:
|
|
221
|
+
writeInt8(value, buffer, index)
|
|
222
|
+
index += 1
|
|
223
|
+
case _VariableType.INT_16:
|
|
224
|
+
writeInt16(value, buffer, index)
|
|
225
|
+
index += 2
|
|
226
|
+
case _VariableType.INT_24:
|
|
227
|
+
writeInt24(value, buffer, index)
|
|
228
|
+
index += 3
|
|
229
|
+
case _VariableType.INT_32:
|
|
230
|
+
writeInt32(value, buffer, index)
|
|
231
|
+
index += 4
|
|
232
|
+
case _VariableType.INT_64:
|
|
233
|
+
writeInt64(value, buffer, index)
|
|
234
|
+
index += 8
|
|
235
|
+
case _VariableType.INT_N:
|
|
236
|
+
pexp = minInt(value)
|
|
237
|
+
writeUint8(pexp, buffer, index)
|
|
238
|
+
index += 1
|
|
239
|
+
writeIntN(value, buffer, index, pexp)
|
|
240
|
+
index += pexp
|
|
241
|
+
case _VariableType.UINT_8:
|
|
242
|
+
writeUint8(value, buffer, index)
|
|
243
|
+
index += 1
|
|
244
|
+
case _VariableType.UINT_16:
|
|
245
|
+
writeUint16(value, buffer, index)
|
|
246
|
+
index += 2
|
|
247
|
+
case _VariableType.UINT_24:
|
|
248
|
+
writeUint24(value, buffer, index)
|
|
249
|
+
index += 3
|
|
250
|
+
case _VariableType.UINT_32:
|
|
251
|
+
writeUint32(value, buffer, index)
|
|
252
|
+
index += 4
|
|
253
|
+
case _VariableType.UINT_64:
|
|
254
|
+
writeUint64(value, buffer, index)
|
|
255
|
+
index += 8
|
|
256
|
+
case _VariableType.UINT_N:
|
|
257
|
+
pexp = minInt(value)
|
|
258
|
+
writeUint8(pexp, buffer, index)
|
|
259
|
+
index += 1
|
|
260
|
+
writeUintN(value, buffer, index, pexp)
|
|
261
|
+
index += pexp
|
|
262
|
+
case _VariableType.BOOL:
|
|
263
|
+
writeBoolean(value, buffer, index)
|
|
264
|
+
index += 1
|
|
265
|
+
case _VariableType.LIST_UINT_64:
|
|
266
|
+
for val in value:
|
|
267
|
+
writeUint64(val, buffer, index)
|
|
268
|
+
index += 8
|
|
269
|
+
case _:
|
|
270
|
+
raise ValueError("Unknown Variable Type", variable)
|
|
271
|
+
return buffer
|
|
272
|
+
def __repr__(self):
|
|
273
|
+
return f"{self._name}({', '.join(f'{var.name}={getattr(self, var.name)}' for var in self._variables)})"
|
|
274
|
+
|
|
275
|
+
_lookup_table = dict()
|
|
276
|
+
|
|
277
|
+
def _TASDPacketFactory(name: str, key: int, variables: List[_VariableDefinition] = [], enums: List[_EnumDefinition] = []):
|
|
278
|
+
class Packet(_TASDPacket):
|
|
279
|
+
_variables = variables
|
|
280
|
+
_key = key
|
|
281
|
+
_name = name
|
|
282
|
+
def __init__(self, **kwargs):
|
|
283
|
+
for variable in Packet._variables:
|
|
284
|
+
setattr(self, variable.name, kwargs.get(variable.name, variable.default))
|
|
285
|
+
|
|
286
|
+
for enum in enums:
|
|
287
|
+
setattr(Packet, enum.name, enum.enum)
|
|
288
|
+
|
|
289
|
+
_lookup_table[key] = Packet
|
|
290
|
+
|
|
291
|
+
Packet.__name__ = name
|
|
292
|
+
Packet.__qualname__ = name
|
|
293
|
+
return Packet
|
|
294
|
+
|
|
295
|
+
def _build_unknown_packet(key):
|
|
296
|
+
_UnknownPacket = _TASDPacketFactory(f"UnknownPacket_{key:04x}", key, [ _VariableDefinition("data", _VariableType.BYTES_EOP, b"") ])
|
|
297
|
+
return _UnknownPacket
|
|
298
|
+
|
|
299
|
+
def lookup_packet(key: int) -> _TASDPacket:
|
|
300
|
+
packet = _lookup_table.get(key, None)
|
|
301
|
+
if packet == None:
|
|
302
|
+
packet = _build_unknown_packet(key)
|
|
303
|
+
return packet
|
|
304
|
+
|
tasd/packets/__init__.py
ADDED
tasd/packets/extra.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from tasd.packet import _TASDPacketFactory as _TASD_PF, _VariableType as _VType, _VariableDefinition as _VDef, _EnumDefinition as _EDef
|
|
2
|
+
from tasd.constants import PacketType
|
|
3
|
+
|
|
4
|
+
'''
|
|
5
|
+
4.3.6.1. COMMENT Packet
|
|
6
|
+
'''
|
|
7
|
+
|
|
8
|
+
Comment = _TASD_PF(
|
|
9
|
+
"Comment",
|
|
10
|
+
PacketType.COMMENT,
|
|
11
|
+
[
|
|
12
|
+
_VDef("comment", _VType.STRING_EOP, "")
|
|
13
|
+
]
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
'''
|
|
17
|
+
4.3.6.2. EXPERIMENTAL Packet
|
|
18
|
+
'''
|
|
19
|
+
|
|
20
|
+
Experimental = _TASD_PF(
|
|
21
|
+
"Experimental",
|
|
22
|
+
PacketType.EXPERIMENTAL,
|
|
23
|
+
[
|
|
24
|
+
_VDef("experimental", _VType.BOOL, False)
|
|
25
|
+
]
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
'''
|
|
29
|
+
4.3.6.3. UNSPECIFIED Packet
|
|
30
|
+
'''
|
|
31
|
+
|
|
32
|
+
Unspecified = _TASD_PF(
|
|
33
|
+
"Unspecified",
|
|
34
|
+
PacketType.UNSPECIFIED,
|
|
35
|
+
[
|
|
36
|
+
_VDef("data", _VType.BYTES_EOP, b"")
|
|
37
|
+
]
|
|
38
|
+
)
|
tasd/packets/general.py
ADDED
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
from tasd.packet import _TASDPacketFactory as _TASD_PF, _VariableType as _VType, _VariableDefinition as _VDef, _EnumDefinition as _EDef
|
|
2
|
+
from tasd.constants import PacketType
|
|
3
|
+
|
|
4
|
+
'''
|
|
5
|
+
4.3.1.1. CONSOLE_TYPE Packet
|
|
6
|
+
'''
|
|
7
|
+
|
|
8
|
+
class CONSOLE_TYPE():
|
|
9
|
+
NES = 0x01
|
|
10
|
+
SNES = 0x02
|
|
11
|
+
N64 = 0x03
|
|
12
|
+
GC = 0x04
|
|
13
|
+
GB = 0x05
|
|
14
|
+
GBC = 0x06
|
|
15
|
+
GBA = 0x07
|
|
16
|
+
GENESIS = 0x08
|
|
17
|
+
A2600 = 0x09
|
|
18
|
+
CUSTOM = 0xFF
|
|
19
|
+
ConsoleType = _TASD_PF(
|
|
20
|
+
"ConsoleType",
|
|
21
|
+
PacketType.CONSOLE_TYPE,
|
|
22
|
+
[
|
|
23
|
+
_VDef("console", _VType.UINT_8, CONSOLE_TYPE.NES),
|
|
24
|
+
_VDef("name", _VType.STRING_EOP, "")
|
|
25
|
+
],
|
|
26
|
+
[
|
|
27
|
+
_EDef("CONSOLE_TYPE", CONSOLE_TYPE)
|
|
28
|
+
]
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
'''
|
|
32
|
+
4.3.1.2. CONSOLE_REGION Packet
|
|
33
|
+
'''
|
|
34
|
+
|
|
35
|
+
class CONSOLE_REGION():
|
|
36
|
+
NTSC = 0x01
|
|
37
|
+
PAL = 0x02
|
|
38
|
+
OTHER = 0xFF
|
|
39
|
+
ConsoleRegion = _TASD_PF(
|
|
40
|
+
"ConsoleRegion",
|
|
41
|
+
PacketType.CONSOLE_REGION,
|
|
42
|
+
[
|
|
43
|
+
_VDef("region", _VType.UINT_8, CONSOLE_REGION.NTSC)
|
|
44
|
+
],
|
|
45
|
+
[
|
|
46
|
+
_EDef("CONSOLE_REGION", CONSOLE_REGION)
|
|
47
|
+
]
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
'''
|
|
51
|
+
4.3.1.3. GAME_TITLE Packet
|
|
52
|
+
'''
|
|
53
|
+
|
|
54
|
+
GameTitle = _TASD_PF(
|
|
55
|
+
"GameTitle",
|
|
56
|
+
PacketType.GAME_TITLE,
|
|
57
|
+
[
|
|
58
|
+
_VDef("title", _VType.STRING_EOP, "")
|
|
59
|
+
]
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
'''
|
|
64
|
+
4.3.1.4. ROM_NAME Packet
|
|
65
|
+
'''
|
|
66
|
+
|
|
67
|
+
RomName = _TASD_PF(
|
|
68
|
+
"RomName",
|
|
69
|
+
PacketType.ROM_NAME,
|
|
70
|
+
[
|
|
71
|
+
_VDef("name", _VType.STRING_EOP, "")
|
|
72
|
+
]
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
'''
|
|
76
|
+
4.3.1.5. ATTRIBUTION Packet
|
|
77
|
+
'''
|
|
78
|
+
|
|
79
|
+
class ATTRIBUTION_TYPE():
|
|
80
|
+
AUTHOR = 0x01
|
|
81
|
+
VERIFIER = 0x02
|
|
82
|
+
TASD_FILE_CREATOR = 0x03
|
|
83
|
+
TASD_FILE_EDITOR = 0x04
|
|
84
|
+
OTHER = 0xFF
|
|
85
|
+
Attribution = _TASD_PF(
|
|
86
|
+
"Attribution",
|
|
87
|
+
PacketType.ATTRIBUTION,
|
|
88
|
+
[
|
|
89
|
+
_VDef("type", _VType.UINT_8, ATTRIBUTION_TYPE.AUTHOR),
|
|
90
|
+
_VDef("name", _VType.STRING_EOP, "")
|
|
91
|
+
],
|
|
92
|
+
[
|
|
93
|
+
_EDef("ATTRIBUTION_TYPE", ATTRIBUTION_TYPE)
|
|
94
|
+
]
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
'''
|
|
99
|
+
4.3.1.6. CATEGORY Packet
|
|
100
|
+
'''
|
|
101
|
+
|
|
102
|
+
Category = _TASD_PF(
|
|
103
|
+
"Category",
|
|
104
|
+
PacketType.CATEGORY,
|
|
105
|
+
[
|
|
106
|
+
_VDef("category", _VType.STRING_EOP, "")
|
|
107
|
+
]
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
'''
|
|
111
|
+
4.3.1.7. EMULATOR_NAME Packet
|
|
112
|
+
'''
|
|
113
|
+
|
|
114
|
+
EmulatorName = _TASD_PF(
|
|
115
|
+
"EmulatorName",
|
|
116
|
+
PacketType.EMULATOR_NAME,
|
|
117
|
+
[
|
|
118
|
+
_VDef("name", _VType.STRING_EOP, "")
|
|
119
|
+
]
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
'''
|
|
123
|
+
4.3.1.8. EMULATOR_VERSION Packet
|
|
124
|
+
'''
|
|
125
|
+
|
|
126
|
+
EmulatorVersion = _TASD_PF(
|
|
127
|
+
"EmulatorVersion",
|
|
128
|
+
PacketType.EMULATOR_VERSION,
|
|
129
|
+
[
|
|
130
|
+
_VDef("version", _VType.STRING_EOP, "")
|
|
131
|
+
]
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
'''
|
|
135
|
+
4.3.1.9. EMULATOR_CORE Packet
|
|
136
|
+
'''
|
|
137
|
+
|
|
138
|
+
EmulatorCore = _TASD_PF(
|
|
139
|
+
"EmulatorCore",
|
|
140
|
+
PacketType.EMULATOR_CORE,
|
|
141
|
+
[
|
|
142
|
+
_VDef("core", _VType.STRING_EOP, "")
|
|
143
|
+
]
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
'''
|
|
147
|
+
4.3.1.10. TAS_LAST_MODIFIED Packet
|
|
148
|
+
'''
|
|
149
|
+
|
|
150
|
+
TASLastModified = _TASD_PF(
|
|
151
|
+
"TASLastModified",
|
|
152
|
+
PacketType.TAS_LAST_MODIFIED,
|
|
153
|
+
[
|
|
154
|
+
_VDef("timestamp", _VType.INT_64, 0)
|
|
155
|
+
]
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
'''
|
|
159
|
+
4.3.1.11. DUMP_CREATED Packet
|
|
160
|
+
'''
|
|
161
|
+
|
|
162
|
+
DumpCreated = _TASD_PF(
|
|
163
|
+
"DumpCreated",
|
|
164
|
+
PacketType.DUMP_CREATED,
|
|
165
|
+
[
|
|
166
|
+
_VDef("timestamp", _VType.INT_64, 0)
|
|
167
|
+
]
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
'''
|
|
171
|
+
4.3.1.12. DUMP_LAST_MODIFIED Packet
|
|
172
|
+
'''
|
|
173
|
+
|
|
174
|
+
DumpLastModified = _TASD_PF(
|
|
175
|
+
"DumpLastModified",
|
|
176
|
+
PacketType.DUMP_LAST_MODIFIED,
|
|
177
|
+
[
|
|
178
|
+
_VDef("timestamp", _VType.INT_64, 0)
|
|
179
|
+
]
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
'''
|
|
183
|
+
4.3.1.13. TOTAL_FRAMES Packet
|
|
184
|
+
'''
|
|
185
|
+
|
|
186
|
+
TotalFrames = _TASD_PF(
|
|
187
|
+
"TotalFrames",
|
|
188
|
+
PacketType.TOTAL_FRAMES,
|
|
189
|
+
[
|
|
190
|
+
_VDef("frames", _VType.UINT_32, 0)
|
|
191
|
+
]
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
'''
|
|
195
|
+
4.3.1.14. RERECORDS Packet
|
|
196
|
+
'''
|
|
197
|
+
|
|
198
|
+
Rerecords = _TASD_PF(
|
|
199
|
+
"Rerecords",
|
|
200
|
+
PacketType.RERECORDS,
|
|
201
|
+
[
|
|
202
|
+
_VDef("rerecords", _VType.UINT_32, 0)
|
|
203
|
+
]
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
'''
|
|
207
|
+
4.3.1.15. SOURCE_LINK Packet
|
|
208
|
+
'''
|
|
209
|
+
|
|
210
|
+
SourceLink = _TASD_PF(
|
|
211
|
+
"SourceLink",
|
|
212
|
+
PacketType.SOURCE_LINK,
|
|
213
|
+
[
|
|
214
|
+
_VDef("link", _VType.STRING_EOP, "")
|
|
215
|
+
]
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
'''
|
|
219
|
+
4.3.1.16. BLANK_FRAMES Packet
|
|
220
|
+
'''
|
|
221
|
+
|
|
222
|
+
BlankFrames = _TASD_PF(
|
|
223
|
+
"BlankFrames",
|
|
224
|
+
PacketType.BLANK_FRAMES,
|
|
225
|
+
[
|
|
226
|
+
_VDef("frames", _VType.INT_16, 0)
|
|
227
|
+
]
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
'''
|
|
231
|
+
4.3.1.17. VERIFIED Packet
|
|
232
|
+
'''
|
|
233
|
+
|
|
234
|
+
Verified = _TASD_PF(
|
|
235
|
+
"Verified",
|
|
236
|
+
PacketType.VERIFIED,
|
|
237
|
+
[
|
|
238
|
+
_VDef("verified", _VType.BOOL, False)
|
|
239
|
+
]
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
'''
|
|
243
|
+
4.3.1.18. MEMORY_INIT Packet
|
|
244
|
+
'''
|
|
245
|
+
|
|
246
|
+
class MEMORY_INIT_TYPE():
|
|
247
|
+
NONE = 0x01
|
|
248
|
+
ALL_00 = 0x02
|
|
249
|
+
ALL_FF = 0x03
|
|
250
|
+
PATTERN_00000000FFFFFFFF = 0x04
|
|
251
|
+
RANDOM = 0x05
|
|
252
|
+
CUSTOM = 0xFF
|
|
253
|
+
class MEMORY_INIT_DEVICE():
|
|
254
|
+
NES_CPU_RAM = 0x0101
|
|
255
|
+
NES_CART_SRAM = 0x0102
|
|
256
|
+
SNES_CPU_RAM = 0x0201
|
|
257
|
+
SNES_CART_SRAM = 0x0202
|
|
258
|
+
GB_CPU_RAM = 0x0501
|
|
259
|
+
GB_CART_SRAM = 0x0502
|
|
260
|
+
GBC_CPU_RAM = 0x0601
|
|
261
|
+
GBC_CART_SRAM = 0x0602
|
|
262
|
+
GBA_CPU_RAM = 0x0701
|
|
263
|
+
GBA_CART_SRAM = 0x0702
|
|
264
|
+
GENESIS_CPU_RAM = 0x0801
|
|
265
|
+
GENESIS_CART_SRAM = 0x0802
|
|
266
|
+
A2600_CPU_RAM = 0x0901
|
|
267
|
+
A2600_CART_SRAM = 0x0902
|
|
268
|
+
CUSTOM = 0xFFFF
|
|
269
|
+
MemoryInit = _TASD_PF(
|
|
270
|
+
"MemoryInit",
|
|
271
|
+
PacketType.MEMORY_INIT,
|
|
272
|
+
[
|
|
273
|
+
_VDef("type", _VType.UINT_8, MEMORY_INIT_TYPE.NONE),
|
|
274
|
+
_VDef("device", _VType.UINT_16, MEMORY_INIT_DEVICE.NES_CPU_RAM),
|
|
275
|
+
_VDef("required", _VType.BOOL, False),
|
|
276
|
+
_VDef("name", _VType.STRING_PLEN, ""),
|
|
277
|
+
_VDef("data", _VType.BYTES_EOP, b"")
|
|
278
|
+
],
|
|
279
|
+
[
|
|
280
|
+
_EDef("MEMORY_INIT_TYPE", MEMORY_INIT_TYPE),
|
|
281
|
+
_EDef("MEMORY_INIT_DEVICE", MEMORY_INIT_DEVICE)
|
|
282
|
+
]
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
'''
|
|
286
|
+
4.3.1.19. GAME_IDENTIFIER Packet
|
|
287
|
+
'''
|
|
288
|
+
|
|
289
|
+
class GAME_IDENTIFIER_TYPE():
|
|
290
|
+
MD5 = 0x01
|
|
291
|
+
SHA1 = 0x02
|
|
292
|
+
SHA224 = 0x03
|
|
293
|
+
SHA256 = 0x04
|
|
294
|
+
SHA384 = 0x05
|
|
295
|
+
SHA512 = 0x06
|
|
296
|
+
SHA512_224 = 0x07
|
|
297
|
+
SHA512_256 = 0x08
|
|
298
|
+
SHA3_224 = 0x09
|
|
299
|
+
SHA3_256 = 0x0A
|
|
300
|
+
SHA3_384 = 0x0B
|
|
301
|
+
SHA3_512 = 0x0C
|
|
302
|
+
SHAKE_128 = 0x0D
|
|
303
|
+
SHAKE_256 = 0x0E
|
|
304
|
+
OTHER = 0xFF
|
|
305
|
+
class GAME_IDENTIFIER_BASE():
|
|
306
|
+
RAW_BINARY = 0x01
|
|
307
|
+
BASE16 = 0x02
|
|
308
|
+
BASE32 = 0x03
|
|
309
|
+
BASE64 = 0x04
|
|
310
|
+
OTHER = 0xFF
|
|
311
|
+
GameIdentifier = _TASD_PF(
|
|
312
|
+
"GameIdentifier",
|
|
313
|
+
PacketType.GAME_IDENTIFIER,
|
|
314
|
+
[
|
|
315
|
+
_VDef("type", _VType.UINT_8, GAME_IDENTIFIER_TYPE.MD5),
|
|
316
|
+
_VDef("encoding", _VType.UINT_8, GAME_IDENTIFIER_BASE.RAW_BINARY),
|
|
317
|
+
_VDef("name", _VType.STRING_PLEN, ""),
|
|
318
|
+
_VDef("identifier", _VType.BYTES_EOP, b"")
|
|
319
|
+
],
|
|
320
|
+
[
|
|
321
|
+
_EDef("GAME_IDENTIFIER_TYPE", GAME_IDENTIFIER_TYPE),
|
|
322
|
+
_EDef("GAME_IDENTIFIER_BASE", GAME_IDENTIFIER_BASE)
|
|
323
|
+
])
|
|
324
|
+
|
|
325
|
+
'''
|
|
326
|
+
4.3.1.20. MOVIE_LICENSE Packet
|
|
327
|
+
'''
|
|
328
|
+
|
|
329
|
+
MovieLicense = _TASD_PF(
|
|
330
|
+
"MovieLicense",
|
|
331
|
+
PacketType.MOVIE_LICENSE,
|
|
332
|
+
[
|
|
333
|
+
_VDef("link", _VType.STRING_EOP, "")
|
|
334
|
+
]
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
'''
|
|
338
|
+
4.3.1.21. MOVIE_FILE Packet
|
|
339
|
+
'''
|
|
340
|
+
|
|
341
|
+
MovieFile = _TASD_PF(
|
|
342
|
+
"MovieFile",
|
|
343
|
+
PacketType.MOVIE_FILE,
|
|
344
|
+
[
|
|
345
|
+
_VDef("name", _VType.STRING_PLEN, ""),
|
|
346
|
+
_VDef("data", _VType.BYTES_EOP, b"")
|
|
347
|
+
]
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
'''
|
|
351
|
+
4.3.1.22. PORT_CONTROLLER Packet
|
|
352
|
+
'''
|
|
353
|
+
|
|
354
|
+
class CONTROLLER_TYPE():
|
|
355
|
+
NES_STANDARD_CONTROLLER = 0x0101
|
|
356
|
+
NES_FOUR_SCORE = 0x0102
|
|
357
|
+
NES_ZAPPER = 0x0103
|
|
358
|
+
NES_POWER_PAD = 0x0104
|
|
359
|
+
FAMICOM_FAMILY_BASIC_KEYBOARD = 0x0105
|
|
360
|
+
SNES_STANDARD_CONTROLLER = 0x0201
|
|
361
|
+
SNES_SUPER_MULTITAP = 0x0202
|
|
362
|
+
SNES_MOUSE = 0x0203
|
|
363
|
+
SNES_SUPERSCOPE = 0x0204
|
|
364
|
+
N64_STANDARD_CONTROLLER = 0x0301
|
|
365
|
+
N64_STANDARD_CONTROLLER_WITH_RUMBLE_PAK = 0x0302
|
|
366
|
+
N64_STANDARD_CONTROLLER_WITH_CONTROLLER_PAK = 0x0303
|
|
367
|
+
N64_STANDARD_CONTROLLER_WITH_TRANSFER_PAK = 0x0304
|
|
368
|
+
N64_MOUSE = 0x0305
|
|
369
|
+
N64_VOICE_RECOGNITION_UNIT = 0x0306
|
|
370
|
+
N64_RANDNET_KEYBOARD = 0x0307
|
|
371
|
+
N64_DENSHA_DE_GO = 0x0308
|
|
372
|
+
GC_STANDARD_CONTROLLER = 0x0401
|
|
373
|
+
GC_KEYBOARD = 0x0402
|
|
374
|
+
GB_GAMEPAD = 0x0501
|
|
375
|
+
GBC_GAMEPAD = 0x0601
|
|
376
|
+
GBA_GAMEPAD = 0x0701
|
|
377
|
+
GENESIS_3BUTTON = 0x0801
|
|
378
|
+
GENESIS_6BUTTON = 0x0802
|
|
379
|
+
A2600_JOYSTICK = 0x0901
|
|
380
|
+
A2600_PADDLE = 0x0902
|
|
381
|
+
A2600_KEYBOARD_CONTROLLER = 0x0903
|
|
382
|
+
OTHER_UNSPECIFIED = 0xFFFF
|
|
383
|
+
PortController = _TASD_PF(
|
|
384
|
+
"PortController",
|
|
385
|
+
PacketType.PORT_CONTROLLER,
|
|
386
|
+
[
|
|
387
|
+
_VDef("port", _VType.UINT_8, 1),
|
|
388
|
+
_VDef("type", _VType.UINT_16, CONTROLLER_TYPE.NES_STANDARD_CONTROLLER)
|
|
389
|
+
],
|
|
390
|
+
[
|
|
391
|
+
_EDef("CONTROLLER_TYPE", CONTROLLER_TYPE)
|
|
392
|
+
]
|
|
393
|
+
)
|
|
394
|
+
|
|
395
|
+
'''
|
|
396
|
+
4.3.1.23. PORT_OVERREAD Packet
|
|
397
|
+
'''
|
|
398
|
+
|
|
399
|
+
PortOverread = _TASD_PF(
|
|
400
|
+
"PortOverread",
|
|
401
|
+
PacketType.PORT_OVERREAD,
|
|
402
|
+
[
|
|
403
|
+
_VDef("port", _VType.UINT_8, 1),
|
|
404
|
+
_VDef("high", _VType.BOOL, False)
|
|
405
|
+
]
|
|
406
|
+
)
|
tasd/packets/genesis.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from tasd.packet import _TASDPacketFactory as _TASD_PF, _VariableType as _VType, _VariableDefinition as _VDef, _EnumDefinition as _EDef
|
|
2
|
+
from tasd.constants import PacketType
|
|
3
|
+
|
|
4
|
+
'''
|
|
5
|
+
4.3.4.1. GENESIS_GAME_GENIE_CODE Packet
|
|
6
|
+
'''
|
|
7
|
+
|
|
8
|
+
GenesisGameGenieCode = _TASD_PF(
|
|
9
|
+
"GenesisGameGenieCode",
|
|
10
|
+
PacketType.GENESIS_GAME_GENIE_CODE,
|
|
11
|
+
[
|
|
12
|
+
_VDef("code", _VType.STRING_EOP, "")
|
|
13
|
+
]
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
GenesisGameGenieCode
|
|
18
|
+
]
|
tasd/packets/input.py
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
from tasd.packet import _TASDPacketFactory as _TASD_PF, _VariableType as _VType, _VariableDefinition as _VDef, _EnumDefinition as _EDef
|
|
2
|
+
from tasd.constants import PacketType
|
|
3
|
+
|
|
4
|
+
'''
|
|
5
|
+
4.3.5.1. INPUT_CHUNK Packet
|
|
6
|
+
'''
|
|
7
|
+
|
|
8
|
+
InputChunk = _TASD_PF(
|
|
9
|
+
"InputChunk",
|
|
10
|
+
PacketType.INPUT_CHUNK,
|
|
11
|
+
[
|
|
12
|
+
_VDef("port", _VType.UINT_8, 1),
|
|
13
|
+
_VDef("data", _VType.BYTES_EOP, b"")
|
|
14
|
+
]
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
'''
|
|
18
|
+
4.3.5.2. INPUT_MOMENT Packet
|
|
19
|
+
'''
|
|
20
|
+
|
|
21
|
+
class INPUT_MOMENT_INDEX_TYPE():
|
|
22
|
+
FRAME = 0x01
|
|
23
|
+
CYCLE_COUNT = 0x02
|
|
24
|
+
MILLISECONDS = 0x03
|
|
25
|
+
MICROSECONDS_X10 = 0x04
|
|
26
|
+
InputMoment = _TASD_PF(
|
|
27
|
+
"InputMoment",
|
|
28
|
+
PacketType.INPUT_MOMENT,
|
|
29
|
+
[
|
|
30
|
+
_VDef("port", _VType.UINT_8, 1),
|
|
31
|
+
_VDef("hold", _VType.BOOL, False),
|
|
32
|
+
_VDef("index_type", _VType.UINT_8, INPUT_MOMENT_INDEX_TYPE.FRAME),
|
|
33
|
+
_VDef("index", _VType.UINT_64, 0),
|
|
34
|
+
_VDef("inputs", _VType.BYTES_EOP, b"")
|
|
35
|
+
],
|
|
36
|
+
[
|
|
37
|
+
_EDef("INPUT_MOMENT_INDEX_TYPE", INPUT_MOMENT_INDEX_TYPE)
|
|
38
|
+
]
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
'''
|
|
42
|
+
4.3.5.3. TRANSITION Packet
|
|
43
|
+
'''
|
|
44
|
+
|
|
45
|
+
class TRANSITION_INDEX_TYPE():
|
|
46
|
+
FRAME = 0x01
|
|
47
|
+
CYCLE_COUNT = 0x02
|
|
48
|
+
MILLISECONDS = 0x03
|
|
49
|
+
MICROSECONDS = 0x04
|
|
50
|
+
NANOSECONDS = 0x05
|
|
51
|
+
INPUT_CHUNK_INDEX = 0x06
|
|
52
|
+
class TRANSITION_TYPE():
|
|
53
|
+
SOFT_RESET = 0x01
|
|
54
|
+
POWER_RESET = 0x02
|
|
55
|
+
RESTART_TASD_FILE = 0x03
|
|
56
|
+
PACKET_DERIVED = 0xFF
|
|
57
|
+
Transition = _TASD_PF(
|
|
58
|
+
"Transition",
|
|
59
|
+
PacketType.TRANSITION,
|
|
60
|
+
[
|
|
61
|
+
_VDef("port", _VType.UINT_8, 1),
|
|
62
|
+
_VDef("index_type", _VType.UINT_8, TRANSITION_INDEX_TYPE.FRAME),
|
|
63
|
+
_VDef("index", _VType.UINT_64, 0),
|
|
64
|
+
_VDef("type", _VType.UINT_8, TRANSITION_TYPE.SOFT_RESET),
|
|
65
|
+
_VDef("packet", _VType.BYTES_EOP, b"")
|
|
66
|
+
],
|
|
67
|
+
[
|
|
68
|
+
_EDef("TRANSITION_INDEX_TYPE", TRANSITION_INDEX_TYPE),
|
|
69
|
+
_EDef("TRANSITION_TYPE", TRANSITION_TYPE)
|
|
70
|
+
]
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
'''
|
|
74
|
+
4.3.5.4. LAG_FRAME_CHUNK Packet
|
|
75
|
+
'''
|
|
76
|
+
|
|
77
|
+
LagFrameChunk = _TASD_PF(
|
|
78
|
+
"LagFrameChunk",
|
|
79
|
+
PacketType.LAG_FRAME_CHUNK,
|
|
80
|
+
[
|
|
81
|
+
_VDef("frame", _VType.UINT_32, 0),
|
|
82
|
+
_VDef("count", _VType.UINT_32, 0)
|
|
83
|
+
]
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
'''
|
|
87
|
+
4.3.5.5. MOVIE_TRANSITION
|
|
88
|
+
'''
|
|
89
|
+
|
|
90
|
+
class MOVIE_TRANSITION_TYPE():
|
|
91
|
+
SOFT_RESET = 0x01
|
|
92
|
+
POWER_RESET = 0x02
|
|
93
|
+
RESTART_TASD_FILE = 0x03
|
|
94
|
+
PACKET_DERIVED = 0xFF
|
|
95
|
+
MovieTransition = _TASD_PF(
|
|
96
|
+
"MovieTransition",
|
|
97
|
+
PacketType.MOVIE_TRANSITION,
|
|
98
|
+
[
|
|
99
|
+
_VDef("frame", _VType.UINT_32, 0),
|
|
100
|
+
_VDef("type", _VType.UINT_8, MOVIE_TRANSITION_TYPE.SOFT_RESET),
|
|
101
|
+
_VDef("packet", _VType.BYTES_EOP, b"")
|
|
102
|
+
],
|
|
103
|
+
[
|
|
104
|
+
_EDef("MOVIE_TRANSITION_TYPE", MOVIE_TRANSITION_TYPE),
|
|
105
|
+
]
|
|
106
|
+
)
|
tasd/packets/nes.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from tasd.packet import _TASDPacketFactory as _TASD_PF, _VariableType as _VType, _VariableDefinition as _VDef, _EnumDefinition as _EDef
|
|
2
|
+
from tasd.constants import PacketType
|
|
3
|
+
|
|
4
|
+
'''
|
|
5
|
+
4.3.2.1. NES_LATCH_FILTER Packet
|
|
6
|
+
'''
|
|
7
|
+
|
|
8
|
+
NESLatchFilter = _TASD_PF(
|
|
9
|
+
"NESLatchFilter",
|
|
10
|
+
PacketType.NES_LATCH_FILTER,
|
|
11
|
+
[
|
|
12
|
+
_VDef("time", _VType.UINT_16, 0)
|
|
13
|
+
]
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
'''
|
|
17
|
+
4.3.2.2. NES_CLOCK_FILTER Packet
|
|
18
|
+
'''
|
|
19
|
+
|
|
20
|
+
NESClockFilter = _TASD_PF(
|
|
21
|
+
"NESClockFilter",
|
|
22
|
+
PacketType.NES_CLOCK_FILTER,
|
|
23
|
+
[
|
|
24
|
+
_VDef("time", _VType.UINT_8, 0)
|
|
25
|
+
]
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
'''
|
|
29
|
+
4.3.2.3. NES_GAME_GENIE_CODE Packet
|
|
30
|
+
'''
|
|
31
|
+
|
|
32
|
+
NESGameGenieCode = _TASD_PF(
|
|
33
|
+
"NESGameGenieCode",
|
|
34
|
+
PacketType.NES_GAME_GENIE_CODE,
|
|
35
|
+
[
|
|
36
|
+
_VDef("code", _VType.STRING_EOP, "")
|
|
37
|
+
]
|
|
38
|
+
)
|
tasd/packets/snes.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from tasd.packet import _TASDPacketFactory as _TASD_PF, _VariableType as _VType, _VariableDefinition as _VDef, _EnumDefinition as _EDef
|
|
2
|
+
from tasd.constants import PacketType
|
|
3
|
+
|
|
4
|
+
'''
|
|
5
|
+
4.3.3.1. SNES_LATCH_FILTER Packet
|
|
6
|
+
'''
|
|
7
|
+
|
|
8
|
+
SNESLatchFilter = _TASD_PF(
|
|
9
|
+
"SNESLatchFilter",
|
|
10
|
+
PacketType.SNES_LATCH_FILTER,
|
|
11
|
+
[
|
|
12
|
+
_VDef("time", _VType.UINT_16, 0)
|
|
13
|
+
]
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
'''
|
|
17
|
+
4.3.3.2. SNES_CLOCK_FILTER Packet
|
|
18
|
+
'''
|
|
19
|
+
|
|
20
|
+
SNESClockFilter = _TASD_PF(
|
|
21
|
+
"SNESClockFilter",
|
|
22
|
+
PacketType.SNES_CLOCK_FILTER,
|
|
23
|
+
[
|
|
24
|
+
_VDef("time", _VType.UINT_8, 0)
|
|
25
|
+
]
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
'''
|
|
29
|
+
4.3.3.3. SNES_GAME_GENIE_CODE Packet
|
|
30
|
+
'''
|
|
31
|
+
|
|
32
|
+
SNESGameGenieCode = _TASD_PF(
|
|
33
|
+
"SNESGameGenieCode",
|
|
34
|
+
PacketType.SNES_GAME_GENIE_CODE,
|
|
35
|
+
[
|
|
36
|
+
_VDef("code", _VType.STRING_EOP, "")
|
|
37
|
+
]
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
'''
|
|
41
|
+
4.3.3.4. SNES_LATCH_TRAIN Packet
|
|
42
|
+
'''
|
|
43
|
+
|
|
44
|
+
SNESLatchTrain = _TASD_PF(
|
|
45
|
+
"SNESLatchTrain",
|
|
46
|
+
PacketType.SNES_LATCH_TRAIN,
|
|
47
|
+
[
|
|
48
|
+
_VDef("trains", _VType.LIST_UINT_64, None)
|
|
49
|
+
]
|
|
50
|
+
)
|
tasd/utils.py
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
def readString(buffer: bytearray, index: int, length: int) -> str:
|
|
2
|
+
return buffer[index:index+length].decode("utf8")
|
|
3
|
+
def writeString(string: str, buffer: bytearray, index: int) -> None:
|
|
4
|
+
rawstring = string.encode("utf8")
|
|
5
|
+
buffer[index:index+len(rawstring)] = rawstring
|
|
6
|
+
def sizeString(string: str) -> int:
|
|
7
|
+
return len(string.encode("utf8"))
|
|
8
|
+
|
|
9
|
+
def readBytes(buffer: bytearray, index: int, length: int) -> bytes:
|
|
10
|
+
return buffer[index:index+length]
|
|
11
|
+
def writeBytes(value: bytes, buffer: bytearray, index: int) -> None:
|
|
12
|
+
buffer[index:index+len(value)] = value
|
|
13
|
+
|
|
14
|
+
def readUint8(buffer: bytearray, index: int) -> int:
|
|
15
|
+
return int.from_bytes(buffer[index:index+1], byteorder="big", signed=False)
|
|
16
|
+
def readUint16(buffer: bytearray, index: int) -> int:
|
|
17
|
+
return int.from_bytes(buffer[index:index+2], byteorder="big", signed=False)
|
|
18
|
+
def readUint24(buffer: bytearray, index: int) -> int:
|
|
19
|
+
return int.from_bytes(buffer[index:index+3], byteorder="big", signed=False)
|
|
20
|
+
def readUint32(buffer: bytearray, index: int) -> int:
|
|
21
|
+
return int.from_bytes(buffer[index:index+4], byteorder="big", signed=False)
|
|
22
|
+
def readUint64(buffer: bytearray, index: int) -> int:
|
|
23
|
+
return int.from_bytes(buffer[index:index+8], byteorder="big", signed=False)
|
|
24
|
+
def readUintN(buffer: bytearray, index: int, size: int) -> int:
|
|
25
|
+
if size == 1:
|
|
26
|
+
return readUint8(buffer, index)
|
|
27
|
+
if size == 2:
|
|
28
|
+
return readUint16(buffer, index)
|
|
29
|
+
if size == 3:
|
|
30
|
+
return readUint24(buffer, index)
|
|
31
|
+
if size == 4:
|
|
32
|
+
return readUint32(buffer, index)
|
|
33
|
+
raise ValueError("Unsuported UintN size", size)
|
|
34
|
+
|
|
35
|
+
def writeUint8(value: int, buffer: bytearray, index: int) -> None:
|
|
36
|
+
buffer[index:index+1] = (value & (2 ** 8 - 1)).to_bytes(1, byteorder="big", signed=False)
|
|
37
|
+
def writeUint16(value: int, buffer: bytearray, index: int) -> None:
|
|
38
|
+
buffer[index:index+2] = (value & (2 ** 16 - 1)).to_bytes(2, byteorder="big", signed=False)
|
|
39
|
+
def writeUint24(value: int, buffer: bytearray, index: int) -> None:
|
|
40
|
+
buffer[index:index+3] = (value & (2 ** 24 - 1)).to_bytes(3, byteorder="big", signed=False)
|
|
41
|
+
def writeUint32(value: int, buffer: bytearray, index: int) -> None:
|
|
42
|
+
buffer[index:index+4] = (value & (2 ** 32 - 1)).to_bytes(4, byteorder="big", signed=False)
|
|
43
|
+
def writeUint64(value: int, buffer: bytearray, index: int) -> None:
|
|
44
|
+
buffer[index:index+8] = (value & (2 ** 64 - 1)).to_bytes(8, byteorder="big", signed=False)
|
|
45
|
+
def writeUintN(value: int, buffer: bytearray, index: int, size: int) -> None:
|
|
46
|
+
if size == 1:
|
|
47
|
+
return writeUint8(value, buffer, index)
|
|
48
|
+
if size == 2:
|
|
49
|
+
return writeUint16(value, buffer, index)
|
|
50
|
+
if size == 3:
|
|
51
|
+
return writeUint24(value, buffer, index)
|
|
52
|
+
if size == 4:
|
|
53
|
+
return writeUint32(value, buffer, index)
|
|
54
|
+
raise ValueError("Unsuported UintN size", size)
|
|
55
|
+
|
|
56
|
+
def minUint(value: int) -> int:
|
|
57
|
+
if value < 256:
|
|
58
|
+
return 1
|
|
59
|
+
if value < 65536:
|
|
60
|
+
return 2
|
|
61
|
+
if value < 16777216:
|
|
62
|
+
return 3
|
|
63
|
+
if value < 4294967296:
|
|
64
|
+
return 4
|
|
65
|
+
raise ValueError("Unsupported UInt size", value);
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def readInt8(buffer: bytearray, index: int) -> int:
|
|
69
|
+
return int.from_bytes(buffer[index:index+1], byteorder="big", signed=True)
|
|
70
|
+
def readInt16(buffer: bytearray, index: int) -> int:
|
|
71
|
+
return int.from_bytes(buffer[index:index+2], byteorder="big", signed=True)
|
|
72
|
+
def readInt24(buffer: bytearray, index: int) -> int:
|
|
73
|
+
return int.from_bytes(buffer[index:index+3], byteorder="big", signed=True)
|
|
74
|
+
def readInt32(buffer: bytearray, index: int) -> int:
|
|
75
|
+
return int.from_bytes(buffer[index:index+4], byteorder="big", signed=True)
|
|
76
|
+
def readInt64(buffer: bytearray, index: int) -> int:
|
|
77
|
+
return int.from_bytes(buffer[index:index+8], byteorder="big", signed=True)
|
|
78
|
+
def readIntN(buffer: bytearray, index: int, n: int) -> int:
|
|
79
|
+
if n == 1:
|
|
80
|
+
return readInt8(buffer, index)
|
|
81
|
+
if n == 2:
|
|
82
|
+
return readInt16(buffer, index)
|
|
83
|
+
if n == 3:
|
|
84
|
+
return readInt24(buffer, index)
|
|
85
|
+
if n == 4:
|
|
86
|
+
return readInt32(buffer, index)
|
|
87
|
+
raise ValueError("Unsuported IntN size", n)
|
|
88
|
+
|
|
89
|
+
def writeInt8(value: int, buffer: bytearray, index: int) -> None:
|
|
90
|
+
buffer[index:index+1] = (value & (2 ** 8 - 1)).to_bytes(1, byteorder="big", signed=True)
|
|
91
|
+
def writeInt16(value: int, buffer: bytearray, index: int) -> None:
|
|
92
|
+
buffer[index:index+2] = (value & (2 ** 16 - 1)).to_bytes(2, byteorder="big", signed=True)
|
|
93
|
+
def writeInt24(value: int, buffer: bytearray, index: int) -> None:
|
|
94
|
+
buffer[index:index+3] = (value & (2 ** 24 - 1)).to_bytes(3, byteorder="big", signed=True)
|
|
95
|
+
def writeInt32(value: int, buffer: bytearray, index: int) -> None:
|
|
96
|
+
buffer[index:index+4] = (value & (2 ** 32 - 1)).to_bytes(4, byteorder="big", signed=True)
|
|
97
|
+
def writeInt64(value: int, buffer: bytearray, index: int) -> None:
|
|
98
|
+
buffer[index:index+8] = (value & (2 ** 64 - 1)).to_bytes(8, byteorder="big", signed=True)
|
|
99
|
+
def writeIntN(value: int, buffer: bytearray, index: int, size: int) -> None:
|
|
100
|
+
if size == 1:
|
|
101
|
+
return writeInt8(value, buffer, index)
|
|
102
|
+
if size == 2:
|
|
103
|
+
return writeInt16(value, buffer, index)
|
|
104
|
+
if size == 3:
|
|
105
|
+
return writeInt24(value, buffer, index)
|
|
106
|
+
if size == 4:
|
|
107
|
+
return writeInt32(value, buffer, index)
|
|
108
|
+
raise ValueError("Unsuported IntN size", size)
|
|
109
|
+
|
|
110
|
+
def minInt(value: int) -> int:
|
|
111
|
+
if -0x80 <= value <= 0x7f:
|
|
112
|
+
return 1
|
|
113
|
+
if -0x8000 <= value <= 0x7fff:
|
|
114
|
+
return 2
|
|
115
|
+
if -0x800000 <= value <= 0x7fffff:
|
|
116
|
+
return 3
|
|
117
|
+
if -0x80000000 <= value <= 0x7fffffff:
|
|
118
|
+
return 4
|
|
119
|
+
raise ValueError("Unsupported Int size", value);
|
|
120
|
+
|
|
121
|
+
def readBoolean(buffer: bytearray, index: int) -> bool:
|
|
122
|
+
if buffer[index] == 1:
|
|
123
|
+
return True
|
|
124
|
+
if buffer[index] == 0:
|
|
125
|
+
return False
|
|
126
|
+
raise ValueError("Invalid Boolean value")
|
|
127
|
+
def writeBoolean(bool: bool, buffer: bytearray, index: int) -> None:
|
|
128
|
+
buffer[index] = (1 if bool else 0)
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tasd
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: TASD file serializer and deserializer
|
|
5
|
+
Author-email: TheMas3212 <mas3212@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/themas3212/tasd-py
|
|
8
|
+
Project-URL: Issues, https://github.com/themas3212/tasd-py/issues
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# TASD
|
|
18
|
+
|
|
19
|
+
This is a python library for the serialization and deserialization of tasd files using the [tasd file specfication](https://tasd.io/)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
Install tasd with pip
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install tasd
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Usage/Examples
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
Read a file in a print all the packets in it
|
|
34
|
+
```py
|
|
35
|
+
from tasd import TASD
|
|
36
|
+
|
|
37
|
+
with open("example.tasd", "rb") as f:
|
|
38
|
+
file = TASD.from_bytes(f.read())
|
|
39
|
+
|
|
40
|
+
print(file)
|
|
41
|
+
for packet in file. packets:
|
|
42
|
+
print(packet)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Create a tasd file from scratch and add packets to it
|
|
46
|
+
```py
|
|
47
|
+
from tasd import TASD, packets
|
|
48
|
+
|
|
49
|
+
file = TASD()
|
|
50
|
+
file.packets.append(packets.extra.Comment(comment="This is a comment"))
|
|
51
|
+
file.packets.append(packets.general.Attribution(type=packets.general.Attribution.ATTRIBUTION_TYPE.TASD_FILE_CREATOR, name="Me"))
|
|
52
|
+
|
|
53
|
+
for packet in file. packets:
|
|
54
|
+
print(packet)
|
|
55
|
+
|
|
56
|
+
print(file.to_bytes())
|
|
57
|
+
```
|
|
58
|
+
## Brief API Reference
|
|
59
|
+
|
|
60
|
+
Not an exhaustive list
|
|
61
|
+
|
|
62
|
+
`tasd.TASD`
|
|
63
|
+
|
|
64
|
+
Class holding properties of the tasd file itself: Version and KeyLength
|
|
65
|
+
|
|
66
|
+
`tasd.constants.PACKET_TYPES`
|
|
67
|
+
|
|
68
|
+
Enumlike class containing the different packet type indentifiers
|
|
69
|
+
|
|
70
|
+
`tasd.packets`
|
|
71
|
+
|
|
72
|
+
Submodule containing all the different packet classes
|
|
73
|
+
|
|
74
|
+
For details about the different packet types i suggest reading the specification document to determine what packets you need to consider for your use case
|
|
75
|
+
## Appendix
|
|
76
|
+
|
|
77
|
+
Any additional information goes here
|
|
78
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
tasd/__init__.py,sha256=1yGBy9LKlZOfg7qB2BXhSRECm4ag1eOELMnMKUT5Yns,86
|
|
2
|
+
tasd/constants.py,sha256=A60Y_e_PqF6oCX2VlINZqbRm0ooqGF4azpMuohaHbW0,2149
|
|
3
|
+
tasd/file.py,sha256=CiRx1Vi-vqIzofRcGrWXXIKhz80AqBRgXlsepSw_vcw,2315
|
|
4
|
+
tasd/packet.py,sha256=SFdHIHCb4gKL4eOzNBZwsfJi5O-QLPbgYCDCW3E0iPQ,12204
|
|
5
|
+
tasd/utils.py,sha256=m3dFok1VswQ1Ba5t_nYPLG90Y90KegkLFIvNN4LMJyk,5842
|
|
6
|
+
tasd/packets/__init__.py,sha256=aznvDufzsVEIfHAV__FA3W1bnE4wrQWzsMc5wbMQbqs,157
|
|
7
|
+
tasd/packets/extra.py,sha256=upxQ7_V69nAbNhdCMuO1QFR_QR8ZRywj8YEglkwu0p4,676
|
|
8
|
+
tasd/packets/general.py,sha256=Ib2UZbYAa7aP27X_iyAmBTMJwf7MzUdWYWs0GCE327k,8858
|
|
9
|
+
tasd/packets/genesis.py,sha256=CHqKBRmZjma6Q-VD8S635jBbRZwk2vsNCLV8NVjurRo,424
|
|
10
|
+
tasd/packets/input.py,sha256=OkPQvSC3hbNSVHYYMt1Ss5FI3SLz67j1Z1hHhI5IdsE,2620
|
|
11
|
+
tasd/packets/nes.py,sha256=X4JuKT9TkDvd6PL3PDHCujPKh7V_JAb51NkMVQCg2_s,729
|
|
12
|
+
tasd/packets/snes.py,sha256=GpJmbp-wlSEWC5E__9a0r_9lJ6hrJctzPysZlPNkbNQ,932
|
|
13
|
+
tasd-1.0.0.dist-info/licenses/LICENSE,sha256=g3ow4YGepg8H1fLp2CiNhGHkMFiBvfX1P-JH3oKmA3g,1067
|
|
14
|
+
tasd-1.0.0.dist-info/METADATA,sha256=PEaPbWhxNgP0XlMRhqornw7fjp2-v2iwuwPwUpyoTJI,1841
|
|
15
|
+
tasd-1.0.0.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
|
|
16
|
+
tasd-1.0.0.dist-info/top_level.txt,sha256=Ys1rtVCDs2s_wERGa-Z-umkR87S0XWHo9UzpemZxDsg,5
|
|
17
|
+
tasd-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 TheMas3212
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
tasd
|