catgirl_engine_client/
lib.rs

1//! Client side component of the game engine
2#![warn(missing_docs)]
3#![doc(
4    html_favicon_url = "https://engine.catgirl.land/resources/assets/vanilla/texture/logo/logo.svg",
5    html_logo_url = "https://engine.catgirl.land/resources/assets/vanilla/texture/logo/logo.svg",
6    html_playground_url = "https://play.rust-lang.org"
7)]
8
9#[macro_use]
10extern crate tracing;
11
12/// Handles the client side game logic
13pub mod game;
14
15/// Handles the client window
16mod window;
17
18/// Handles the rendering code
19mod render;
20
21/// Module for storing and using build data
22pub mod build;
23
24use std::{env, fs, path::PathBuf};
25
26/// Retrieve the engine's icon as raw bytes
27///
28/// # Panics
29///
30/// May panic if the bytes to load cannot be unwrapped
31fn get_icon_bytes() -> Option<Vec<u8>> {
32    let resource_path: PathBuf = PathBuf::from("resources");
33    let logo_path: PathBuf = resource_path
34        .join("assets")
35        .join("vanilla")
36        .join("texture")
37        .join("logo")
38        .join("logo-1024x1024.png");
39    let bytes: Result<Vec<u8>, String> = utils::resources::get_resource_bytes(&logo_path);
40
41    if bytes.is_err() {
42        warn!("{}", bytes.err().unwrap());
43        return None;
44    }
45
46    Some(bytes.unwrap())
47}
48
49/// Retrieve the engine's icon
50///
51/// This does not work on Wayland, use the .desktop shortcut
52///
53/// # Panics
54///
55/// This may fail to load the file from the byte array as an image
56#[must_use]
57#[cfg(not(target_family = "wasm"))]
58fn get_icon() -> Option<winit::window::Icon> {
59    let image_bytes_option: Option<Vec<u8>> = get_icon_bytes();
60    image_bytes_option.as_ref()?;
61
62    let image_bytes: Vec<u8> = image_bytes_option.unwrap();
63    let image: image::ImageBuffer<image::Rgba<u8>, Vec<u8>> = image::load_from_memory(&image_bytes)
64        .expect("Could not get asset from memory...")
65        .into_rgba8();
66    let (width, height) = image.dimensions();
67
68    Some(winit::window::Icon::from_rgba(image.into_raw(), width, height).unwrap())
69}
70
71/// Install Linux desktop files
72///
73/// # Panics
74///
75/// May panic if cannot unwrap executable path
76///
77/// # Errors
78///
79/// May error if home directory cannot be found
80pub fn install_desktop_files() -> Result<(), String> {
81    let resource_path: PathBuf = PathBuf::from("resources");
82    let desktop_file_path: PathBuf = resource_path
83        .join("linux")
84        .join("install")
85        .join("game-engine.desktop");
86    let desktop_file_contents_results: Result<String, String> =
87        utils::resources::get_resource_string(&desktop_file_path);
88    let icon_bytes_option: Option<Vec<u8>> = get_icon_bytes();
89
90    if desktop_file_contents_results.is_err() {
91        warn!("{}", desktop_file_contents_results.err().unwrap());
92
93        return Err("Could not find desktop file to install...".to_string());
94    }
95
96    // Get path of executable
97    let executable_path: String =
98        if let Some(app_image_path) = utils::environment::get_environment_var("APPIMAGE") {
99            app_image_path
100        } else {
101            env::current_exe()
102                .expect("Could not get own path when installing desktop file...")
103                .to_str()
104                .unwrap()
105                .to_string()
106        };
107
108    let desktop_file_contents: String = desktop_file_contents_results
109        .unwrap()
110        .replace("${engine_path}", executable_path.as_str());
111
112    if let Some(home) = utils::environment::get_environment_var("HOME") {
113        // User Application Directories
114        let applications_directory: String = format!("{home}/.local/share/applications");
115        let icons_directory: String = format!("{home}/.local/share/icons");
116
117        // Install Paths
118        let desktop_path: PathBuf =
119            PathBuf::from(&applications_directory).join("land.catgirl.engine.desktop");
120        let icon_path: PathBuf = PathBuf::from(&icons_directory).join("land.catgirl.engine.png");
121
122        // Create folders if they don't exist
123        let _ = fs::create_dir_all(&applications_directory);
124        let _ = fs::create_dir_all(&icons_directory);
125
126        // Remove old files if any
127        let _ = fs::remove_file(&desktop_path);
128        let _ = fs::remove_file(&icon_path);
129
130        let _ = fs::write(desktop_path, desktop_file_contents);
131
132        if let Some(icon_bytes) = icon_bytes_option {
133            let _ = fs::write(icon_path, icon_bytes);
134        }
135
136        return Ok(());
137    }
138
139    Err("Failed to find home directory".to_string())
140}
141
142/// Install Linux desktop files
143///
144/// # Panics
145///
146/// May panic if cannot unwrap executable path
147///
148/// # Errors
149///
150/// May error if home directory cannot be found
151pub fn uninstall_desktop_files() -> Result<(), String> {
152    if let Some(home) = utils::environment::get_environment_var("HOME") {
153        // User Application Directories
154        let applications_directory: String = format!("{home}/.local/share/applications");
155        let icons_directory: String = format!("{home}/.local/share/icons");
156
157        // Install Paths
158        let desktop_path: PathBuf =
159            PathBuf::from(&applications_directory).join("land.catgirl.engine.desktop");
160        let icon_path: PathBuf = PathBuf::from(&icons_directory).join("land.catgirl.engine.png");
161
162        // Remove old files if any
163        let _ = fs::remove_file(desktop_path);
164        let _ = fs::remove_file(icon_path);
165
166        return Ok(());
167    }
168
169    Err("Failed to find home directory".to_string())
170}