Add tank catalog with USDZ models and tank selection
Introduce TankDefinition/TankCatalog loaded from Tanks.json, bundle the Drachengas USDZ tank models, add tank selection and preview views, and update the AR experience, editor and project views to use the catalog. Includes tests for catalog loading and model selection. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
58
GasTankAR/Services/TankCatalogLoader.swift
Normal file
58
GasTankAR/Services/TankCatalogLoader.swift
Normal file
@ -0,0 +1,58 @@
|
||||
//
|
||||
// TankCatalogLoader.swift
|
||||
// GasTankAR
|
||||
//
|
||||
// Created by Dennis Nemec on 14.09.26.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Rohdaten des Tank-Katalogs, wie sie in `Tanks.json` abgelegt sind: die
|
||||
/// verfügbaren Varianten sowie die separat gepflegten Anzeigenamen-Mappings
|
||||
/// (jeweils `rawValue` → Anzeigename).
|
||||
nonisolated struct TankCatalogFile: Decodable {
|
||||
let sizeDisplayNames: [String: String]
|
||||
let colorDisplayNames: [String: String]
|
||||
let tanks: [TankDefinition]
|
||||
}
|
||||
|
||||
/// Lädt den Tank-Katalog aus einer JSON-Quelle. Über das Protokoll lässt sich
|
||||
/// die Quelle für Tests austauschen (z. B. In-Memory-Daten).
|
||||
nonisolated protocol TankCatalogLoading {
|
||||
func load() throws -> TankCatalogFile
|
||||
}
|
||||
|
||||
nonisolated enum TankCatalogLoaderError: Error, Equatable {
|
||||
/// Die JSON-Ressource wurde im Bundle nicht gefunden.
|
||||
case resourceNotFound(name: String, extension: String)
|
||||
}
|
||||
|
||||
/// Lädt den Katalog aus einer JSON-Datei im App-Bundle.
|
||||
nonisolated struct BundleTankCatalogLoader: TankCatalogLoading {
|
||||
let bundle: Bundle
|
||||
let resourceName: String
|
||||
let resourceExtension: String
|
||||
|
||||
init(bundle: Bundle = .main, resourceName: String = "Tanks", resourceExtension: String = "json") {
|
||||
self.bundle = bundle
|
||||
self.resourceName = resourceName
|
||||
self.resourceExtension = resourceExtension
|
||||
}
|
||||
|
||||
func load() throws -> TankCatalogFile {
|
||||
guard let url = bundle.url(forResource: resourceName, withExtension: resourceExtension) else {
|
||||
throw TankCatalogLoaderError.resourceNotFound(name: resourceName, extension: resourceExtension)
|
||||
}
|
||||
let data = try Data(contentsOf: url)
|
||||
return try JSONDecoder().decode(TankCatalogFile.self, from: data)
|
||||
}
|
||||
}
|
||||
|
||||
/// Lädt den Katalog aus bereits vorliegenden JSON-Daten (nützlich für Tests).
|
||||
nonisolated struct DataTankCatalogLoader: TankCatalogLoading {
|
||||
let data: Data
|
||||
|
||||
func load() throws -> TankCatalogFile {
|
||||
try JSONDecoder().decode(TankCatalogFile.self, from: data)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user