physis/resource/resolver.rs
1// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4use crate::ByteBuffer;
5
6use super::Resource;
7
8/// Allows chaining multiple Resources together.
9///
10/// # Example
11///
12/// ```
13/// # use physis::resource::{ResourceResolver, SqPackResource, UnpackedResource};
14/// # use physis::common::Platform;
15/// let sqpack_source = SqPackResource::from_existing(Platform::Win32, "SquareEnix/Final Fantasy XIV - A Realm Reborn/game");
16/// let file_source = UnpackedResource::from_existing("unpacked/");
17/// let mut resolver = ResourceResolver::new();
18/// resolver.add_source(Box::new(file_source)); // first has most priority
19/// resolver.add_source(Box::new(sqpack_source)); // this is the fallback
20/// ```
21pub struct ResourceResolver {
22 resolvers: Vec<Box<dyn Resource + Send + Sync>>,
23}
24
25impl ResourceResolver {
26 pub fn new() -> Self {
27 Self {
28 resolvers: Vec::new(),
29 }
30 }
31
32 pub fn add_source(&mut self, source: Box<dyn Resource + Send + Sync>) {
33 self.resolvers.push(source);
34 }
35}
36
37impl Resource for ResourceResolver {
38 fn read(&mut self, path: &str) -> Option<ByteBuffer> {
39 for resolver in &mut self.resolvers {
40 if let Some(bytes) = resolver.read(path) {
41 return Some(bytes);
42 }
43 }
44
45 return None;
46 }
47
48 fn exists(&mut self, path: &str) -> bool {
49 for resolver in &mut self.resolvers {
50 if resolver.exists(path) {
51 return true;
52 }
53 }
54
55 return false;
56 }
57}