mirror of
https://github.com/SK8-ENGINE/skate-3-rust-engine.git
synced 2026-10-26 19:47:44 +00:00
Resolve scoring and HUD font records by native VLT identity
This commit is contained in:
1 parent
a05c8c06b3
commit
cfafc213c0
3 files changed
+75
-7
No files matched your search
@@ -10,6 +10,16 @@ use skate_core::{
|
||||
const SCORABLE: &str = "Hash_6918469984A8C596";
|
||||
const TUNING: &str = "Hash_349215E2E817703C";
|
||||
|
||||
fn scorable_keys(data: &Collections) -> std::collections::BTreeSet<String> {
|
||||
// Setup's name dictionary may resolve the class as `scoring_trick`.
|
||||
// Presence checks must use the same native identities as Collections::field.
|
||||
data.entries()
|
||||
.iter()
|
||||
.filter(|row| crate::attrib_hash::numeric_name(&row.class_name) == SCORABLE)
|
||||
.map(|row| crate::attrib_hash::numeric_name(&row.key))
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Definition {
|
||||
pub metadata: Scorable,
|
||||
@@ -53,14 +63,11 @@ impl ScoringData {
|
||||
}
|
||||
pub fn load(data: &Collections) -> Result<Self, String> {
|
||||
let mut definitions = Vec::new();
|
||||
let available = scorable_keys(data);
|
||||
for (id, &(identifier, class, score_type)) in IDENTIFIERS.iter().enumerate() {
|
||||
// The executable enum includes unused entries without VLT records.
|
||||
// Only actual records are eligible for recognition.
|
||||
if !data.entries().iter().any(|r| {
|
||||
r.class_name == SCORABLE
|
||||
&& (r.key == identifier
|
||||
|| r.key == crate::attrib_hash::numeric_name(identifier))
|
||||
}) {
|
||||
if !available.contains(&crate::attrib_hash::numeric_name(identifier)) {
|
||||
continue;
|
||||
}
|
||||
let words = |name| data.words::<1>(SCORABLE, identifier, name).map(|v| v[0]);
|
||||
@@ -132,6 +139,29 @@ impl ScoringData {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod identity_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn scoring_presence_accepts_readable_and_numeric_vault_names() {
|
||||
let key = IDENTIFIERS[0].0;
|
||||
let numeric_key = crate::attrib_hash::numeric_name(key);
|
||||
for class in ["scoring_trick", SCORABLE, "0x6918469984a8c596"] {
|
||||
for name in [key, numeric_key.as_str()] {
|
||||
let data: Collections = serde_json::from_value(serde_json::json!({
|
||||
"version": 1,
|
||||
"collections": [{"class": class, "key": name, "parent": "",
|
||||
"source": "fixture", "sha256": "", "fields": {}},
|
||||
{"class": "unrelated", "key": "other", "parent": "",
|
||||
"source": "fixture", "sha256": "", "fields": {}}]
|
||||
})).unwrap();
|
||||
assert_eq!(scorable_keys(&data), [numeric_key.clone()].into());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CollectorTuning {
|
||||
scalars: std::collections::BTreeMap<u16, f32>,
|
||||
|
||||
@@ -24,11 +24,12 @@ def font_mapping(collections: Path, cache: AssetCache) -> dict:
|
||||
data = json.loads(collections.read_text(encoding='utf-8'))
|
||||
result = {}
|
||||
for row in data['collections']:
|
||||
if row['class'] != 'Hash_FECFBCAF356518C4':
|
||||
class_id = int(row['class'][5:], 16) if row['class'].startswith('Hash_') else hash64(row['class'])
|
||||
if class_id != 0xFECFBCAF356518C4:
|
||||
continue
|
||||
def field(name):
|
||||
return row['fields'].get(name, row['fields'].get(f'Hash_{hash64(name):016X}'))
|
||||
apt_name = row['fields']['Hash_340832CCFD9FDEB4']['data']
|
||||
apt_name = field('AptName')['data']
|
||||
filename = field('FileName')['data']
|
||||
matches = [r for r in cache.manifest['bundles']
|
||||
if 'font' in r and Path(r['name']).name == filename]
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
from prepare_hud import font_mapping
|
||||
from asset_pipeline.vlt import hash64
|
||||
|
||||
|
||||
class Cache:
|
||||
manifest = {'bundles': [{'name': 'fonts/original', 'font': {'family': 'Original family'}}]}
|
||||
|
||||
def add_font_alias(self, name, target, provenance):
|
||||
self.alias = (name, target)
|
||||
|
||||
|
||||
class FontIdentityTests(unittest.TestCase):
|
||||
def test_readable_and_numeric_exports_resolve_the_same_original_font(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
path = Path(directory) / 'collections.json'
|
||||
for named_class in (True, False):
|
||||
for named_fields in (True, False):
|
||||
fields = {'AptName': {'data': 'Original APT name'}, 'FileName': {'data': 'original'}}
|
||||
fields.update({key: {'data': '3F800000'} for key in ('ScaleX', 'ScaleY', 'OffsetX', 'OffsetY')})
|
||||
if not named_fields:
|
||||
fields = {f'Hash_{hash64(key):016X}': value for key, value in fields.items()}
|
||||
path.write_text(json.dumps({'collections': [{
|
||||
'class': 'fe_fonts' if named_class else 'Hash_FECFBCAF356518C4',
|
||||
'key': 'original', 'sha256': '', 'fields': fields}]}))
|
||||
cache = Cache()
|
||||
result = font_mapping(path, cache)
|
||||
self.assertEqual(cache.alias, ('Original APT name', 'Original family'))
|
||||
self.assertEqual(result['Original APT name']['native_layout']['ScaleX'], 1.0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user