mirror of
https://github.com/SK8-ENGINE/skate-3-rust-engine.git
synced 2026-10-26 19:47:44 +00:00
Handle retail park streams and spline headers across all disc maps
This commit is contained in:
1 parent
ae107e2876
commit
a7090f9ef3
4 files changed
+34
-5
No files matched your search
@@ -102,8 +102,15 @@ pub(crate) fn primitives(map: Option<&SkateMap>) -> Result<Vec<Primitive>,String
|
||||
let [a,b,c,d] = coefficients;
|
||||
let end = std::array::from_fn(|j| (a[j]+b[j])+(c[j]+d[j]));
|
||||
let length: f32 = (0..3).map(|j| (end[j]-d[j]).powi(2)).sum();
|
||||
if !length.is_finite() || length <= 0.000001 {
|
||||
return Err(format!("Spline segment {i} has a degenerate contact chord"));
|
||||
if !length.is_finite() {
|
||||
return Err(format!("Spline segment {i} has a non-finite contact chord"));
|
||||
}
|
||||
if length <= 0.000001 {
|
||||
// Retail Downtown contains duplicate knots and sub-millimetre
|
||||
// chords. They cannot provide a usable contact direction. Keep
|
||||
// their cubic records and links in build(), but omit them from
|
||||
// this adapter's independent contact-primitive array.
|
||||
continue;
|
||||
}
|
||||
result.push(Primitive { start:d,end,owner:((word(r) as u64)<<32)|word(r+4) as u64 });
|
||||
}
|
||||
|
||||
@@ -46,3 +46,19 @@ game process and closes the current session so physics and render resources
|
||||
are recreated. A fresh launch defaults to University. Development checkouts
|
||||
with `assets/private/game.json` retain their existing local assets and default
|
||||
test world; `--assets DIRECTORY` also selects a prepared asset set explicitly.
|
||||
|
||||
## Conversion checks
|
||||
|
||||
The direct converter was checked against an extracted Xbox 360 disc containing
|
||||
the three main districts, Skate School, and six separately stored parks:
|
||||
Black Box, Downtown Skate Park, Industrial Skate Park, Maloof, Mega Park and
|
||||
Start Park. All ten outputs passed the runtime's asset, spline and collision
|
||||
load checks. This does not establish visual or gameplay parity, and the
|
||||
original ISO extraction step still needs checking with an ISO.
|
||||
|
||||
Two retail spline details needed corrections. Downtown contains duplicate
|
||||
knots and sub-millimetre chords. The native cubic records remain intact;
|
||||
only unusable contact primitives are omitted. Skate School's first spline
|
||||
header word is `0001 0002`, meaning two rails, not 65,538. TU3 function
|
||||
`82C1EEF0` reads the count with `lhz +2` (also at `82C1EFBC`). The reader now
|
||||
uses that halfword and retains the other halfword in the map metadata.
|
||||
@@ -98,7 +98,9 @@ def convert_map(archive,work,maps,stage,game_exe,log,report):
|
||||
manifest_path=prepare(stream_directory=stream,output_root=district_work/'intermediate',
|
||||
utt_root=TOOLS/'vendor/utt',district_name=district,map_name=label,
|
||||
package_name='Skate 3 owned disc',cache_format='skate3-rust-map-v1',
|
||||
texture_stream_names=('Tex',),excluded_normal_texture_ids=EXCLUDED_NORMAL_TEXTURE_IDS)
|
||||
# Smaller parks keep their textures in Pres rather than a Tex stream.
|
||||
texture_stream_names=('Tex',) if any(stream.glob('cTex_*.xsf')) else (),
|
||||
excluded_normal_texture_ids=EXCLUDED_NORMAL_TEXTURE_IDS)
|
||||
collision=district_work/'collision.rwcmset'
|
||||
build_archive(manifest_path,collision)
|
||||
final=maps/(label+'.skate')
|
||||
|
||||
+6
-2
@@ -168,8 +168,11 @@ def decode_grind_splines(data: bytes) -> list[dict[str, object]]:
|
||||
):
|
||||
raise ValueError("RX2 spline section extends beyond the file")
|
||||
|
||||
rail_count, segment_count, rail_table, segment_table = (
|
||||
struct.unpack_from(">4I", data, section_offset)
|
||||
# TU3 GrindData::Add (82C1EEF0) reads lhz +2, including its loop
|
||||
# bound at 82C1EFBC. The first halfword is not part of the count:
|
||||
# Skate School has header 0001 0002, two rails, table end 0x50.
|
||||
header_halfword, rail_count, segment_count, rail_table, segment_table = (
|
||||
struct.unpack_from(">HH3I", data, section_offset)
|
||||
)
|
||||
expected_segment_table = (
|
||||
SPLINE_HEADER_SIZE + rail_count * SPLINE_RAIL_SIZE
|
||||
@@ -271,6 +274,7 @@ def decode_grind_splines(data: bytes) -> list[dict[str, object]]:
|
||||
{
|
||||
"section_index": record_index,
|
||||
"section_offset": section_offset,
|
||||
"section_header_halfword": header_halfword,
|
||||
"rail_index": rail_index,
|
||||
"spline_id": f"0x{spline_id:016X}",
|
||||
"type_signature": f"0x{type_signature:016X}",
|
||||
|
||||
Reference in new issue
Block a user