konnektoren_bevy/assets/
challenge_asset.rs1use bevy::{
2 asset::{io::Reader, AssetLoader, LoadContext},
3 prelude::*,
4 reflect::TypePath,
5};
6
7#[cfg(feature = "assets")]
8use konnektoren_core::challenges::challenge_type::ChallengeType;
9#[cfg(feature = "assets")]
10use serde_yaml;
11#[cfg(feature = "assets")]
12use thiserror::Error;
13
14#[derive(Asset, TypePath, Debug, Clone)]
16pub struct ChallengeAsset {
17 #[cfg(feature = "assets")]
18 pub challenge_type: ChallengeType,
19 #[cfg(not(feature = "assets"))]
20 pub challenge_type: String, pub file_path: String,
22}
23
24#[cfg(feature = "assets")]
25impl ChallengeAsset {
26 pub fn id(&self) -> &str {
28 self.challenge_type.id()
29 }
30
31 pub fn name(&self) -> &str {
33 self.challenge_type.name()
34 }
35}
36
37#[cfg(not(feature = "assets"))]
38impl ChallengeAsset {
39 pub fn id(&self) -> &str {
41 &self.challenge_type
42 }
43
44 pub fn name(&self) -> &str {
46 &self.challenge_type
47 }
48}
49
50#[derive(Default)]
52pub struct ChallengeAssetLoader;
53
54#[non_exhaustive]
56#[derive(Debug, Error)]
57#[cfg(feature = "assets")]
58pub enum ChallengeAssetLoaderError {
59 #[error("Could not load challenge asset: {0}")]
61 Io(#[from] std::io::Error),
62
63 #[error("Could not parse YAML challenge: {0}")]
65 YamlError(#[from] serde_yaml::Error),
66}
67
68#[cfg(not(feature = "assets"))]
69#[derive(Debug)]
70pub enum ChallengeAssetLoaderError {
71 Io(std::io::Error),
72 YamlError(String),
73}
74
75#[cfg(not(feature = "assets"))]
76impl std::fmt::Display for ChallengeAssetLoaderError {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 match self {
79 ChallengeAssetLoaderError::Io(e) => write!(f, "IO Error: {}", e),
80 ChallengeAssetLoaderError::YamlError(e) => write!(f, "YAML Error: {}", e),
81 }
82 }
83}
84
85#[cfg(not(feature = "assets"))]
86impl std::error::Error for ChallengeAssetLoaderError {}
87
88#[cfg(feature = "assets")]
89impl AssetLoader for ChallengeAssetLoader {
90 type Asset = ChallengeAsset;
91 type Settings = ();
92 type Error = ChallengeAssetLoaderError;
93
94 async fn load(
95 &self,
96 reader: &mut dyn Reader,
97 _settings: &(),
98 load_context: &mut LoadContext<'_>,
99 ) -> Result<Self::Asset, Self::Error> {
100 let mut bytes = Vec::new();
101 reader.read_to_end(&mut bytes).await?;
102
103 let challenge_type = serde_yaml::from_slice::<ChallengeType>(&bytes)?;
104 let file_path = load_context.path().to_string_lossy().to_string();
105
106 info!(
107 "Loaded challenge '{}' ({}) from {}",
108 challenge_type.name(),
109 challenge_type.id(),
110 file_path
111 );
112
113 Ok(ChallengeAsset {
114 challenge_type,
115 file_path,
116 })
117 }
118
119 fn extensions(&self) -> &[&str] {
120 &["yml", "yaml"]
121 }
122}
123
124#[cfg(not(feature = "assets"))]
125impl AssetLoader for ChallengeAssetLoader {
126 type Asset = ChallengeAsset;
127 type Settings = ();
128 type Error = ChallengeAssetLoaderError;
129
130 async fn load(
131 &self,
132 reader: &mut dyn Reader,
133 _settings: &(),
134 load_context: &mut LoadContext<'_>,
135 ) -> Result<Self::Asset, Self::Error> {
136 let mut bytes = Vec::new();
137 reader
138 .read_to_end(&mut bytes)
139 .await
140 .map_err(ChallengeAssetLoaderError::Io)?;
141
142 let file_path = load_context.path().to_string_lossy().to_string();
143 let challenge_type = "unknown".to_string(); Ok(ChallengeAsset {
146 challenge_type,
147 file_path,
148 })
149 }
150
151 fn extensions(&self) -> &[&str] {
152 &["yml", "yaml"]
153 }
154}