Skip to main content

roblox_studio_utils/paths/
mod.rs

1use std::{
2    path::{Path, PathBuf},
3    sync::Arc,
4};
5
6use crate::RobloxStudioResult;
7use crate::task::RobloxStudioTask;
8
9#[cfg(target_os = "linux")]
10mod linux;
11#[cfg(target_os = "macos")]
12mod macos;
13#[cfg(target_os = "windows")]
14mod windows;
15
16/**
17    References to discovered, validated paths to the current
18    Roblox Studio executable, content, and plugins directories.
19
20    Can be cheaply cloned and shared between threads.
21*/
22#[derive(Debug, Clone)]
23pub struct RobloxStudioPaths {
24    inner: Arc<RobloxStudioPathsInner>,
25}
26
27impl RobloxStudioPaths {
28    /**
29        Tries to locate the current Roblox Studio installation and directories.
30
31        # Errors
32
33        - If Roblox Studio is not installed.
34    */
35    pub fn new() -> RobloxStudioResult<Self> {
36        RobloxStudioPathsInner::new().map(Self::from)
37    }
38
39    /**
40        Returns the path to the Roblox Studio executable.
41    */
42    #[must_use]
43    pub fn exe(&self) -> &Path {
44        self.inner.exe.as_path()
45    }
46
47    /**
48        Returns the path to the Roblox Studio launcher executable,
49        if one is available.
50    */
51    #[must_use]
52    pub fn launcher(&self) -> Option<&Path> {
53        self.inner.launcher.as_deref()
54    }
55
56    /**
57        Returns the preferred executable path for the given task.
58    */
59    #[must_use]
60    pub(crate) fn exe_for_task(&self, task: Option<RobloxStudioTask>) -> &Path {
61        if cfg!(target_os = "windows")
62            && task.is_some_and(RobloxStudioTask::needs_launcher)
63            && self.inner.launcher.is_some()
64        {
65            self.inner
66                .launcher
67                .as_deref()
68                .expect("launcher path should exist")
69        } else {
70            self.exe()
71        }
72    }
73
74    /**
75        Returns the path to the Roblox Studio content directory.
76
77        This directory contains Roblox bundled assets, in sub-directories such as:
78
79        - `fonts` - bundled font files, typically in OpenType or TrueType format
80        - `sounds` - bundled basic sounds, such as the character reset sound
81        - `textures` - bundled texture files, typically used for `CoreGui`
82    */
83    #[must_use]
84    pub fn content(&self) -> &Path {
85        self.inner.content.as_path()
86    }
87
88    /**
89        Returns the path to the Roblox Studio **user plugins** directory.
90
91        For the path to built-in plugins, see [`RobloxStudioPaths::built_in_plugins`].
92
93        # Warning
94
95        This directory may or may not exist as it is created on demand,
96        either when a user opens it through the Roblox Studio settings,
97        or when they install their first plugin.
98    */
99    #[must_use]
100    pub fn user_plugins(&self) -> &Path {
101        self.inner.plugins_user.as_path()
102    }
103
104    /**
105        Returns the path to the Roblox Studio **built-in plugins** directory.
106
107        These plugins are bundled with Roblox Studio itself, and the directory is guaranteed
108        to exist unlike the user plugins directory ([`RobloxStudioPaths::user_plugins`]).
109    */
110    #[must_use]
111    pub fn built_in_plugins(&self) -> &Path {
112        self.inner.plugins_builtin.as_path()
113    }
114}
115
116// Private inner struct to make RobloxStudioPaths cheaper to clone
117#[derive(Debug, Clone)]
118struct RobloxStudioPathsInner {
119    exe: PathBuf,
120    launcher: Option<PathBuf>,
121    content: PathBuf,
122    plugins_user: PathBuf,
123    plugins_builtin: PathBuf,
124}
125
126impl From<RobloxStudioPathsInner> for RobloxStudioPaths {
127    fn from(inner: RobloxStudioPathsInner) -> Self {
128        Self {
129            inner: Arc::new(inner),
130        }
131    }
132}