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}