Skip to content

Commit 822b0f3

Browse files
committed
refactor
1 parent b3cab52 commit 822b0f3

File tree

6 files changed

+361
-2
lines changed

6 files changed

+361
-2
lines changed

README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ This repository contains reverse engineered documentation about various Run8 V3
88

99
[/blender_scripts](/blender_scripts) - Import/Export scripts for Blender 3.x
1010

11-
[/ksy](/ksy) - Kaitai Structs
12-
1311
### Progress
1412

1513
- AISignalDatabase.r8

misc/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
other random bs
File renamed without changes.
File renamed without changes.
File renamed without changes.

misc/read_tkb.py

Lines changed: 360 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,360 @@
1+
from enum import Enum, Flag
2+
from typing import BinaryIO, Union
3+
4+
from binreader import BinaryReader
5+
6+
7+
class SerializeFlags(Flag):
8+
Normal = 0
9+
Dynamic = 1
10+
Nullable = 2
11+
12+
class EffectShaderType(Enum):
13+
Vertex = 0
14+
Hull = 1
15+
Domain = 2
16+
Geometry = 3
17+
Pixel = 4
18+
Compute = 5
19+
20+
class EffectCompilerFlags(Flag):
21+
Debug = 1
22+
SkipValidation = 2
23+
SkipOptimization = 4
24+
PackMatrixRowMajor = 8
25+
PackMatrixColumnMajor = 16
26+
PartialPrecision = 32
27+
AvoidFlowControl = 512
28+
PreferFlowControl = 1024
29+
EnableStrictness = 2048
30+
EnableBackwardsCompatibility = 4096
31+
IeeeStrictness = 8192
32+
OptimizationLevel0 = 16384
33+
OptimizationLevel1 = 0
34+
OptimizationLevel2 = 49152
35+
OptimizationLevel3 = 32768
36+
WarningsAreErrors = 262144
37+
Empty = 0
38+
39+
class FeatureLevel(Enum):
40+
Level_9_1 = 37120
41+
Level_9_2 = 37376
42+
Level_9_3 = 37632
43+
Level_10_0 = 40960
44+
Level_10_1 = 41216
45+
Level_11_0 = 45056
46+
47+
class EffectParameterClass(Enum):
48+
Scalar = 0
49+
Vector = 1
50+
MatrixRows = 2
51+
MatrixColumns = 3
52+
Object = 4
53+
Struct = 5
54+
InterfaceClass = 6
55+
InterfacePointer = 7
56+
57+
class EffectParameterType(Enum):
58+
Void = 0
59+
Bool = 1
60+
Int = 2
61+
Float = 3
62+
String = 4
63+
Texture = 5
64+
Texture1D = 6
65+
Texture2D = 7
66+
Texture3D = 8
67+
TextureCube = 9
68+
Sampler = 10
69+
Sampler1D = 11
70+
Sampler2D = 12
71+
Sampler3D = 13
72+
SamplerCube = 14
73+
Pixelshader = 15
74+
Vertexshader = 16
75+
Pixelfragment = 17
76+
Vertexfragment = 18
77+
UInt = 19
78+
UInt8 = 20
79+
Geometryshader = 21
80+
Rasterizer = 22
81+
Depthstencil = 23
82+
Blend = 24
83+
Buffer = 25
84+
ConstantBuffer = 26
85+
TextureBuffer = 27
86+
Texture1DArray = 28
87+
Texture2DArray = 29
88+
Rendertargetview = 30
89+
Depthstencilview = 31
90+
Texture2DMultisampled = 32
91+
Texture2DMultisampledArray = 33
92+
TextureCubeArray = 34
93+
Hullshader = 35
94+
Domainshader = 36
95+
InterfacePointer = 37
96+
Computeshader = 38
97+
Double = 39
98+
RWTexture1D = 40
99+
RWTexture1DArray = 41
100+
RWTexture2D = 42
101+
RWTexture2DArray = 43
102+
RWTexture3D = 44
103+
RWBuffer = 45
104+
ByteAddressBuffer = 46
105+
RWByteAddressBuffer = 47
106+
StructuredBuffer = 48
107+
RWStructuredBuffer = 49
108+
AppendStructuredBuffer = 50
109+
ConsumeStructuredBuffer = 51
110+
111+
class WrappedBinaryReader(BinaryReader):
112+
def __init__(self, buf: BinaryIO, endian: str = "<") -> None:
113+
super().__init__(buf, endian)
114+
115+
def is_serialize_null(self, flags: SerializeFlags = SerializeFlags.Nullable) -> bool:
116+
if (flags & SerializeFlags.Nullable) != SerializeFlags.Normal:
117+
# read a byte
118+
aByte = self.read_byte()
119+
120+
# 1 stores a reference, 2 gets this reference
121+
if aByte == 1:
122+
print("is_serialize_null: 1")
123+
elif aByte == 2:
124+
raise Exception("length 2 is not supported")
125+
126+
# if 0, string is null
127+
return aByte == 0
128+
129+
return False
130+
131+
def read_7bit_encoded_int(self) -> int:
132+
value = 0
133+
shift = 0
134+
while True:
135+
byte_value = ord(self.read(1))
136+
value |= (byte_value & 0x7F) << shift
137+
shift += 7
138+
if (byte_value & 0x80) == 0:
139+
break
140+
return value
141+
142+
def serialize_string(self, flags=SerializeFlags.Normal) -> Union[str, None]:
143+
if self.is_serialize_null(flags=flags):
144+
return None
145+
146+
# read the size
147+
size = self.read_7bit_encoded_int()
148+
# read the string
149+
return self.read(size).decode("utf-8")
150+
151+
def serialize_bytes(self, flags=SerializeFlags.Normal) -> bytes:
152+
if self.is_serialize_null(flags=flags):
153+
return None
154+
155+
# read the size
156+
size = self.read_7bit_encoded_int()
157+
# read the bytes
158+
return self.read(size)
159+
160+
def serialize_class_array(self, class_type: type) -> object:
161+
if self.is_serialize_null(flags=SerializeFlags.Normal):
162+
return None
163+
164+
# read the number of classes
165+
count = self.read_7bit_encoded_int()
166+
return [class_type(self) for i in range(count)]
167+
168+
class FourCC:
169+
@classmethod
170+
def calculate(self, code):
171+
"""
172+
Create a FourCC code from a four-character string.
173+
"""
174+
if len(code) != 4:
175+
raise ValueError("FourCC code must be a four-character string.")
176+
177+
fourcc = 0
178+
for i, char in enumerate(code):
179+
fourcc += ord(char) << (8 * i)
180+
181+
return fourcc
182+
183+
class Chunk:
184+
id: int
185+
index_end: int
186+
reader: WrappedBinaryReader
187+
188+
def __init__(self, id: str, reader: WrappedBinaryReader):
189+
self.id = FourCC.calculate(id)
190+
self.reader = reader
191+
192+
# read the magic from the file
193+
magic = reader.read_int32()
194+
if magic != self.id:
195+
raise ValueError("Invalid Chunk Magic.")
196+
197+
# read the chunk end index
198+
self.index_end = reader.read_int32()
199+
200+
class TKFX(Chunk):
201+
version: int
202+
203+
def __init__(self, reader: WrappedBinaryReader):
204+
super().__init__("TKFX", reader)
205+
self.version = reader.read_int32()
206+
207+
# hard coded version check
208+
if self.version != 257:
209+
raise ValueError("Invalid TKFX version.")
210+
211+
class SHDRShaderSignatureSemantic:
212+
name: str
213+
index: int
214+
register: int
215+
system_value_type: int
216+
component_type: int
217+
usage_mask: int
218+
read_write_mask: int
219+
stream: int
220+
221+
def __init__(self, reader: WrappedBinaryReader):
222+
self.name = reader.serialize_string()
223+
self.index = reader.read_byte()
224+
self.register = reader.read_byte()
225+
self.system_value_type = reader.read_byte()
226+
self.component_type = reader.read_byte()
227+
self.usage_mask = reader.read_byte()
228+
self.read_write_mask = reader.read_byte()
229+
self.stream = reader.read_byte()
230+
231+
def __repr__(self) -> str:
232+
return f"SHDRShaderSignatureSemantic(name={self.name}, index={self.index}, register={self.register}, system_value_type={self.system_value_type}, component_type={self.component_type}, usage_mask={self.usage_mask}, read_write_mask={self.read_write_mask}, stream={self.stream})"
233+
234+
class SHDRShaderSignature:
235+
semantics: list[SHDRShaderSignatureSemantic]
236+
bytecode: bytes
237+
hashcode: int
238+
239+
def __init__(self, reader: WrappedBinaryReader) -> None:
240+
self.semantics = reader.serialize_class_array(SHDRShaderSignatureSemantic)
241+
# read bytecode
242+
self.bytecode = reader.serialize_bytes(flags=SerializeFlags.Nullable)
243+
# read hashcode
244+
self.hashcode = reader.read_int32()
245+
246+
def __repr__(self) -> str:
247+
return f"SHDRShaderSignature(semantics={self.semantics}, bytecode={self.bytecode}, hashcode={self.hashcode})"
248+
249+
class Base:
250+
name: str
251+
parameter_class: EffectParameterClass
252+
parameter_type: EffectParameterType
253+
254+
def __init__(self, reader: WrappedBinaryReader) -> None:
255+
self.name = reader.serialize_string()
256+
self.parameter_class = EffectParameterClass(reader.read_byte())
257+
self.parameter_type = EffectParameterType(reader.read_byte())
258+
259+
def __repr__(self) -> str:
260+
return f"Base(name={self.name}, parameter_class={self.parameter_class}, parameter_type={self.parameter_type})"
261+
262+
class ValueTypeParameter(Base):
263+
offset: int
264+
count: int
265+
size: int
266+
row_count: int
267+
column_count: int
268+
default_value: bytes
269+
270+
def __init__(self, reader: WrappedBinaryReader) -> None:
271+
super().__init__(reader)
272+
self.offset = reader.read_7bit_encoded_int()
273+
self.count = reader.read_7bit_encoded_int()
274+
self.size = reader.read_7bit_encoded_int()
275+
self.row_count = reader.read_byte()
276+
self.column_count = reader.read_byte()
277+
self.default_value = reader.serialize_bytes(flags=SerializeFlags.Nullable)
278+
279+
def __repr__(self) -> str:
280+
return f"ValueTypeParameter(name={self.name}, class={self.parameter_class}, type={self.parameter_type}, offset={self.offset}, count={self.count}, size={self.size}, row_count={self.row_count}, column_count={self.column_count}, default_value={self.default_value})"
281+
282+
class ConstantBuffer:
283+
name: str
284+
size: int
285+
parameters: list[ValueTypeParameter]
286+
287+
def __init__(self, reader: WrappedBinaryReader) -> None:
288+
self.name = reader.serialize_string()
289+
self.size = reader.read_7bit_encoded_int()
290+
291+
# read an array of parameters
292+
self.parameters = reader.serialize_class_array(ValueTypeParameter)
293+
294+
def __repr__(self) -> str:
295+
return f"ConstantBuffer(name={self.name}, size={self.size}, parameters={self.parameters})"
296+
297+
class ResourceParameter(Base):
298+
slot: int
299+
count: int
300+
301+
def __init__(self, reader: WrappedBinaryReader) -> None:
302+
super().__init__(reader)
303+
self.slot = reader.read_byte()
304+
self.count = reader.read_byte()
305+
306+
def __repr__(self) -> str:
307+
return f"ResourceParameter(name={self.name}, class={self.parameter_class}, type={self.parameter_type}, slot={self.slot}, count={self.count})"
308+
309+
class SHDRShader:
310+
name: str
311+
shader_type: EffectShaderType
312+
compiler_flags: EffectCompilerFlags
313+
feature_level: FeatureLevel
314+
bytecode: bytes
315+
hashcode: int
316+
input_signature: SHDRShaderSignature
317+
output_signature: SHDRShaderSignature
318+
constant_buffers: list[ConstantBuffer]
319+
resource_parameters: list[ResourceParameter]
320+
321+
def __init__(self, reader: WrappedBinaryReader) -> None:
322+
self.name = reader.serialize_string(flags=SerializeFlags.Nullable)
323+
# read the shader type
324+
self.shader_type = EffectShaderType(reader.read_byte())
325+
# read compiler flags
326+
self.compiler_flags = EffectCompilerFlags(reader.read_int32())
327+
# read feature level
328+
self.feature_level = FeatureLevel(reader.read_int32())
329+
# read bytecode
330+
self.bytecode = reader.serialize_bytes()
331+
# read hashcode
332+
self.hashcode = reader.read_int32()
333+
# read input signature
334+
self.input_signature = SHDRShaderSignature(reader)
335+
# read output signature
336+
self.output_signature = SHDRShaderSignature(reader)
337+
# read constant buffers
338+
self.constant_buffers = reader.serialize_class_array(ConstantBuffer)
339+
# read resource parameters
340+
self.resource_parameters = reader.serialize_class_array(ResourceParameter)
341+
342+
def __repr__(self) -> str:
343+
return f"SHDRShader(name={self.name}, shader_type={self.shader_type}, compiler_flags={self.compiler_flags}, feature_level={self.feature_level}, bytecode={self.bytecode}, hashcode={self.hashcode}, input_signature={self.input_signature}, output_signature={self.output_signature}, constant_buffers={self.constant_buffers}, resource_parameters={self.resource_parameters})"
344+
345+
class SHDR(Chunk):
346+
def __init__(self, reader: WrappedBinaryReader):
347+
super().__init__("SHDR", reader)
348+
349+
# read an array of shaders
350+
num_shaders = self.reader.read_7bit_encoded_int()
351+
print("Shader Count: " + str(num_shaders))
352+
for i in range(num_shaders):
353+
shader = SHDRShader(self.reader)
354+
print(shader)
355+
356+
357+
with open("C:\\Run8Studios\\Run8 Train Simulator V3\\Content\\Shaders\\Avatar.tkb", "rb") as f:
358+
reader = WrappedBinaryReader(f)
359+
tkfx = TKFX(reader)
360+
shdr = SHDR(reader)

0 commit comments

Comments
 (0)