Skip to content

Commit 3503e6c

Browse files
committed
2026-05-06T0954Z
1 parent 5e580cd commit 3503e6c

7 files changed

Lines changed: 63 additions & 72 deletions

File tree

Source/assets/serialisers/csg/csgphs8.py

Lines changed: 31 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import io
66

77

8-
# 40-byte magic header that prefixes a CSGPHS V6/V7 Mesh struct.
8+
# 40-byte magic header that prefixes a CSGPHS3, 6, or 7 mesh struct.
99
_CSGPHS_MESH_MAGIC = (
1010
b"\x10\0\0\0" + b"\0" * 16 +
1111
b"\x10\0\0\0" + b"\0" * 12 +
@@ -25,6 +25,28 @@ class Edgebreaker:
2525
vertices: list[bytes]
2626
triangles: list[tuple[int, int, int]]
2727

28+
29+
def read_bit(clers_bytes: bytes, total_bits: int):
30+
for byte_idx in range(total_bits // 8):
31+
word = clers_bytes[byte_idx]
32+
for bit_idx in range(8):
33+
34+
shift = 7 - bit_idx
35+
yield (word >> shift) & 0b1
36+
37+
38+
def get_next_edge(c: int) -> int:
39+
if c % 3 == 2:
40+
return c - 2
41+
return c + 1
42+
43+
44+
def get_prev_edge(c: int) -> int:
45+
if c % 3 == 0:
46+
return c + 2
47+
return c - 1
48+
49+
2850
# ---------------------------------------------------------------------------
2951
# Edgebreaker decoder ported from clv2's Mesh Lab plugin (CSGPHS8 module).
3052
# Decodes the CLERS bitstream + global vertex array into per-hull
@@ -48,39 +70,9 @@ def _edgebreaker_decode(
4870
here for python; convert at emit time.
4971
'''
5072
hulls = []
51-
bit_pos = 0
52-
total_words = (total_bits + 31) // 32
53-
54-
def read_bit() -> int:
55-
nonlocal bit_pos
56-
if bit_pos >= total_bits:
57-
raise ValueError("Edgebreaker: read past end")
58-
word_idx = bit_pos // 0x20
59-
bit_in_word = bit_pos % 0x20
60-
61-
bits_in_word = 32
62-
if word_idx == total_words - 1:
63-
bits_in_word = total_bits % 0x20
64-
if bits_in_word == 0:
65-
bits_in_word = 0x20
66-
67-
shift = bits_in_word - bit_in_word - 1
68-
word = struct.unpack_from("<I", clers_bytes, word_idx * 4)[0]
69-
bit_pos += 1
70-
return (word >> shift) & 1
71-
73+
bitreader = read_bit(clers_bytes, total_bits)
7274
global_vert_offset = 0
7375

74-
def get_next_edge(c):
75-
if c % 3 == 2:
76-
return c - 2
77-
return c + 1
78-
79-
def get_prev_edge(c):
80-
if c % 3 == 0:
81-
return c + 2
82-
return c - 1
83-
8476
state = State()
8577

8678
def zip_boundary(cursor_edge: int) -> int:
@@ -172,16 +164,16 @@ def decode_recursive(cursor_edge, depth) -> bool:
172164
idx[tri_base_edge + 2] = idx[get_next_edge(cursor_edge)]
173165
cursor_edge = tri_base_edge + 1
174166

175-
b1 = read_bit()
167+
b1 = next(bitreader)
176168
if b1 == 0: # C
177169
state.vertex_counter += 1
178170
idx[tri_base_edge] = state.vertex_counter
179171
next_edge = get_next_edge(cursor_edge)
180172
adj[next_edge] = -1
181173
continue
182174

183-
b2 = read_bit()
184-
b3 = read_bit()
175+
b2 = next(bitreader)
176+
b3 = next(bitreader)
185177
op = (
186178
(b1 * 4) +
187179
(b2 * 2) +
@@ -234,11 +226,11 @@ def decode_recursive(cursor_edge, depth) -> bool:
234226
hull_verts = []
235227
hull_tris = []
236228
max_local_idx = 0
237-
for t in range(state.current_tri_idx + 1):
229+
for t in range(state.current_tri_idx):
238230
base = 3 * t
239-
i0 = state.index[base + 1]
240-
i1 = state.index[base + 2]
241-
i2 = state.index[base + 3]
231+
i0 = state.index[base + 0]
232+
i1 = state.index[base + 1]
233+
i2 = state.index[base + 2]
242234
if i0 == i1:
243235
continue
244236
if i0 == i2:

Source/assets/serialisers/csg/util.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77

88

99
OBFUSCATION_NOISE_CYCLE_XOR = bytes([
10-
0x56, 0x2e, 0x6e, 0x58, 0x31, 0x20, 0x30, 0x04,
11-
0x34, 0x69, 0x0c, 0x77, 0x0c, 0x01, 0x5e, 0x00,
12-
0x1a, 0x60, 0x37, 0x69, 0x1d, 0x52, 0x2b, 0x07,
13-
0x4f, 0x24, 0x59, 0x65, 0x53, 0x04, 0x7a,
10+
0x56, 0x2E, 0x6E, 0x58, 0x31, 0x20, 0x30, 0x04,
11+
0x34, 0x69, 0x0C, 0x77, 0x0C, 0x01, 0x5E, 0x00,
12+
0x1A, 0x60, 0x37, 0x69, 0x1D, 0x52, 0x2B, 0x07,
13+
0x4F, 0x24, 0x59, 0x65, 0x53, 0x04, 0x7A,
1414
])
1515

1616
INT_SIZE = 4
@@ -70,10 +70,10 @@ def create_hash(vertices: bytes, indices: bytes, salt: bytes = b'\0'*16) -> byte
7070
def recalculate_hash(data: bytes) -> bytes:
7171
data_xor = xor_encrypt(data)
7272

73-
hash_base = 0x0a
73+
hash_base = 0x0A
7474
hash_size = 0x20
7575

76-
hash_salt_base = hash_base+0x10
76+
hash_salt_base = hash_base + 0x10
7777
hash_salt_size = 0x10
7878
hash_salt = data_xor[
7979
hash_salt_base:

Source/assets/serialisers/mesh/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def parse(original_data: bytes) -> bytes | None:
2727
elif mesh_version == "4.01":
2828
return b''.join([
2929
b'version 4.00',
30-
original_data[0xc:],
30+
original_data[0xC:],
3131
])
3232
'''
3333

Source/assets/serialisers/rbxl/fonts.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,20 @@
66
b'rbxasset://fonts/families/Fondamento.json\x90\x01\x00': 0x19,
77
b'rbxasset://fonts/families/Merriweather.json\x90\x01\x00': 0x21,
88
b'rbxasset://fonts/families/SourceSansPro.json\x90\x01\x01': 0x06,
9-
b'rbxasset://fonts/families/Ubuntu.json\x90\x01\x00': 0x2d,
10-
b'rbxasset://fonts/families/JosefinSans.json\x90\x01\x00': 0x1d,
11-
b'rbxasset://fonts/families/JosefinSans.json\xbc\x02\x00': 0x1d,
9+
b'rbxasset://fonts/families/Ubuntu.json\x90\x01\x00': 0x2D,
10+
b'rbxasset://fonts/families/JosefinSans.json\x90\x01\x00': 0x1D,
11+
b'rbxasset://fonts/families/JosefinSans.json\xbc\x02\x00': 0x1D,
1212
b'rbxasset://fonts/families/PatrickHand.json\x90\x01\x00': 0x25,
1313
b'rbxasset://fonts/families/Bangers.json\x90\x01\x00': 0x16,
14-
b'rbxasset://fonts/families/Inconsolata.json\x90\x01\x00': 0x0a,
15-
b'rbxasset://fonts/families/FredokaOne.json\x90\x01\x00': 0x1a,
16-
b'rbxasset://fonts/families/FredokaOne.json\xf4\x01\x00': 0x1a,
14+
b'rbxasset://fonts/families/Inconsolata.json\x90\x01\x00': 0x0A,
15+
b'rbxasset://fonts/families/FredokaOne.json\x90\x01\x00': 0x1A,
16+
b'rbxasset://fonts/families/FredokaOne.json\xf4\x01\x00': 0x1A,
1717
b'rbxasset://fonts/families/SourceSansPro.json\xbc\x02\x00': 0x04,
1818
b'rbxasset://fonts/families/GothamSSm.json\x90\x01\x00': 0x11,
1919
b'rbxasset://fonts/families/SourceSansPro.json\x2c\x01\x00': 0x05,
20-
b'rbxasset://fonts/families/GrenzeGotisch.json\x90\x01\x00': 0x1b,
20+
b'rbxasset://fonts/families/GrenzeGotisch.json\x90\x01\x00': 0x1B,
2121
b'rbxasset://fonts/families/Arial.json\xbc\x02\x00': 0x02,
22-
b'rbxasset://fonts/families/TitilliumWeb.json\x90\x01\x00': 0x2c,
22+
b'rbxasset://fonts/families/TitilliumWeb.json\x90\x01\x00': 0x2C,
2323
b'rbxasset://fonts/families/Guru.json\x90\x01\x00': 0x08,
2424
b'rbxasset://fonts/families/Michroma.json\x90\x01\x00': 0x22,
2525
b'rbxasset://fonts/families/RobotoCondensed.json\x90\x01\x00': 0x28,
@@ -29,29 +29,29 @@
2929
b'rbxasset://fonts/families/AccanthisADFStd.json\x90\x01\x00': 0x07,
3030
b'rbxasset://fonts/families/LegacyArial.json\x90\x01\x00': 0x00,
3131
b'rbxasset://fonts/families/RobotoMono.json\x90\x01\x00': 0x29,
32-
b'rbxasset://fonts/families/PressStart2P.json\x90\x01\x00': 0x0d,
32+
b'rbxasset://fonts/families/PressStart2P.json\x90\x01\x00': 0x0D,
3333
b'rbxasset://fonts/families/SourceSansPro.json\x90\x01\x00': 0x03,
34-
b'rbxasset://fonts/families/Sarpanch.json\x90\x01\x00': 0x2a,
34+
b'rbxasset://fonts/families/Sarpanch.json\x90\x01\x00': 0x2A,
3535
b'rbxasset://fonts/families/DenkOne.json\x90\x01\x00': 0x18,
36-
b'rbxasset://fonts/families/IndieFlower.json\x90\x01\x00': 0x1c,
36+
b'rbxasset://fonts/families/IndieFlower.json\x90\x01\x00': 0x1C,
3737
b'rbxasset://fonts/families/SourceSansPro.json\x58\x02\x00': 0x10,
38-
b'rbxasset://fonts/families/RomanAntique.json\x90\x01\x00': 0x0f,
38+
b'rbxasset://fonts/families/RomanAntique.json\x90\x01\x00': 0x0F,
3939
b'rbxasset://fonts/families/AmaticSC.json\x90\x01\x00': 0x15,
40-
b'rbxasset://fonts/families/Kalam.json\x90\x01\x00': 0x1f,
40+
b'rbxasset://fonts/families/Kalam.json\x90\x01\x00': 0x1F,
4141
b'rbxasset://fonts/families/PermanentMarker.json\x90\x01\x00': 0x26,
4242
b'rbxasset://fonts/families/Roboto.json\x90\x01\x00': 0x27,
4343
b'rbxasset://fonts/families/LuckiestGuy.json\x90\x01\x00': 0x20,
4444
b'rbxasset://fonts/families/Arial.json\x90\x01\x00': 0x01,
4545
b'rbxasset://fonts/families/Nunito.json\x90\x01\x00': 0x23,
46-
b'rbxasset://fonts/families/HighwayGothic.json\x90\x01\x00': 0x0b,
46+
b'rbxasset://fonts/families/HighwayGothic.json\x90\x01\x00': 0x0B,
4747
b'rbxasset://fonts/families/Oswald.json\x90\x01\x00': 0x24,
48-
b'rbxasset://fonts/families/SpecialElite.json\x90\x01\x00': 0x2b,
49-
b'rbxasset://fonts/families/SpecialElite.json\xf4\x01\x00': 0x2b,
48+
b'rbxasset://fonts/families/SpecialElite.json\x90\x01\x00': 0x2B,
49+
b'rbxasset://fonts/families/SpecialElite.json\xf4\x01\x00': 0x2B,
5050
b'rbxasset://fonts/families/GothamSSm.json\x84\x03\x00': 0x14,
5151
b'rbxasset://fonts/families/GothamSSm.json\xf4\x01\x00': 0x12,
52-
b'rbxasset://fonts/families/Balthazar.json\x90\x01\x00': 0x0e,
53-
b'rbxasset://fonts/families/Zekton.json\x90\x01\x00': 0x0c,
54-
b'rbxasset://fonts/families/Jura.json\x90\x01\x00': 0x1e,
52+
b'rbxasset://fonts/families/Balthazar.json\x90\x01\x00': 0x0E,
53+
b'rbxasset://fonts/families/Zekton.json\x90\x01\x00': 0x0C,
54+
b'rbxasset://fonts/families/Jura.json\x90\x01\x00': 0x1E,
5555
}
5656

5757

Source/tester/test_serialise.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ def test_csgmdl2_hash(self) -> None:
2323
data_xor = xor_encrypt(data)
2424
self.assertEqual(
2525
first=create_hash(
26-
data_xor[0x32:0x32+0x3a*0x54],
27-
data_xor[0x0000133E:0x0000133E + 4*0x6c],
28-
data_xor[0x1a:0x2a]
26+
data_xor[0x32:0x32+0x3A*0x54],
27+
data_xor[0x0000133E:0x0000133E + 4*0x6C],
28+
data_xor[0x1A:0x2A]
2929
),
30-
second=data_xor[0xa:0x2a],
30+
second=data_xor[0xA:0x2A],
3131
)
3232
self.assertEqual(
3333
first=recalculate_hash(data),

Source/web_server/endpoints/save_place.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
from web_server._logic import web_server_handler, server_path
1414

1515

16-
1716
def decompress_gzip(data, file_handle) -> None:
1817
"""
1918
Decompress a gzip compressed string into a file handle.
@@ -35,7 +34,7 @@ def decompress_gzip(data, file_handle) -> None:
3534
crc, length = struct.unpack("<II", do.unused_data[:8])
3635
if crc != zlib.crc32(decompressed):
3736
raise gzip.BadGzipFile("CRC check failed")
38-
if length != (len(decompressed) & 0xffffffff):
37+
if length != (len(decompressed) & 0xFFFFFFFF):
3938
raise gzip.BadGzipFile("Incorrect length of data produced")
4039
file_handle.write(decompressed)
4140
data = do.unused_data[8:].lstrip(b"\x00")

0 commit comments

Comments
 (0)