├── .github └── workflows │ └── release.yaml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE.md ├── README.md ├── USAGE.md ├── images ├── image.png └── tree.png ├── src ├── cli_utils.rs ├── commands │ ├── build.rs │ ├── init.rs │ ├── mod.rs │ ├── update.rs │ └── watch.rs ├── main.rs ├── toml_conf.rs ├── utils.rs └── zip_utils.rs └── static ├── .gitignore ├── conf.lua ├── globals.d.luau ├── main.luau └── vscode_settings.json /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | tags: 5 | - v* 6 | env: 7 | BIN_NAME: kaledis 8 | jobs: 9 | build: 10 | strategy: 11 | matrix: 12 | include: 13 | - os: ubuntu-latest 14 | host: linux 15 | arch: x86_64 16 | target: x86_64-unknown-linux-gnu 17 | 18 | - os: windows-latest 19 | host: windows 20 | arch: x86_64 21 | target: x86_64-pc-windows-msvc 22 | 23 | - os: macos-13 24 | host: macos 25 | arch: x86_64 26 | target: x86_64-apple-darwin 27 | 28 | - os: macos-latest 29 | host: macos 30 | arch: aarch64 31 | target: aarch64-apple-darwin 32 | runs-on: ${{ matrix.os }} 33 | name: Build for ${{ matrix.host }}-${{ matrix.arch }} 34 | steps: 35 | - uses: actions/checkout@v4 36 | - uses: dtolnay/rust-toolchain@stable 37 | - name: Set env 38 | shell: bash 39 | run: | 40 | ARCHIVE_NAME=${{ env.BIN_NAME }}-$(echo ${{ github.ref_name }} | cut -c 2-)-${{ matrix.host }}-${{ matrix.arch }} 41 | 42 | echo "ARCHIVE_NAME=$ARCHIVE_NAME" >> $GITHUB_ENV 43 | 44 | - name: Install OS dependencies 45 | if: ${{ matrix.host == 'linux' }} 46 | run: | 47 | sudo apt-get update 48 | sudo apt-get install libdbus-1-dev pkg-config 49 | 50 | - name: Build 51 | run: cargo build --bins --all-features --release --target ${{ matrix.target }} --locked 52 | 53 | - name: Archive 54 | shell: bash 55 | run: | 56 | if [ ${{ matrix.host }} = "windows" ]; then 57 | mv target/${{ matrix.target }}/release/${{ env.BIN_NAME }}.exe ${{ env.BIN_NAME }}.exe 58 | 7z a ${{ env.ARCHIVE_NAME }}.zip ${{ env.BIN_NAME }}.exe 59 | tar -czf ${{ env.ARCHIVE_NAME }}.tar.gz ${{ env.BIN_NAME }}.exe 60 | else 61 | mv target/${{ matrix.target }}/release/${{ env.BIN_NAME }} ${{ env.BIN_NAME }} 62 | zip -r ${{ env.ARCHIVE_NAME }}.zip ${{ env.BIN_NAME }} 63 | tar -czf ${{ env.ARCHIVE_NAME }}.tar.gz ${{ env.BIN_NAME }} 64 | fi 65 | 66 | - name: Upload zip artifact 67 | uses: actions/upload-artifact@v4 68 | with: 69 | name: ${{ env.ARCHIVE_NAME }}.zip 70 | path: ${{ env.ARCHIVE_NAME }}.zip 71 | 72 | - name: Upload tar.gz artifact 73 | uses: actions/upload-artifact@v4 74 | with: 75 | name: ${{ env.ARCHIVE_NAME }}.tar.gz 76 | path: ${{ env.ARCHIVE_NAME }}.tar.gz 77 | 78 | publish: 79 | name: Publish to crates.io 80 | runs-on: ubuntu-latest 81 | needs: [ build ] 82 | steps: 83 | - uses: actions/checkout@v4 84 | - uses: dtolnay/rust-toolchain@stable 85 | - name: Publish 86 | run: cargo publish --token ${{ secrets.CRATES_IO_TOKEN }} --allow-dirty 87 | 88 | create_release: 89 | name: Create Release 90 | runs-on: ubuntu-latest 91 | permissions: 92 | contents: write 93 | pull-requests: read 94 | needs: [ build, publish ] 95 | steps: 96 | - uses: actions/checkout@v4 97 | with: 98 | fetch-depth: 0 99 | - uses: actions/download-artifact@v4 100 | with: 101 | path: artifacts 102 | merge-multiple: true 103 | 104 | - name: Create Release 105 | id: create_release 106 | uses: softprops/action-gh-release@v1 107 | with: 108 | token: ${{ secrets.GITHUB_TOKEN }} 109 | tag_name: ${{ github.ref_name }} 110 | name: ${{ github.ref_name }} 111 | draft: true 112 | prerelease: ${{ endsWith(github.ref_name, 'rc') }} 113 | files: artifacts/* -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | love 3 | ./.vscode/**/* 4 | .vscode 5 | 6 | playground 7 | 8 | 9 | # Added by cargo 10 | 11 | dal_custom/target 12 | 13 | # this is a folder that i normally use to test 14 | project/**/* 15 | project/.gitignore 16 | ./project -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kaledis" 3 | version = "1.3.4" 4 | edition = "2021" 5 | authors = ["lettuce-magician", "orpos"] 6 | documentation = "https://github.com/orpos/kaledis" 7 | repository = "https://github.com/orpos/kaledis" 8 | license-file = "LICENSE.md" 9 | description="A new way to LÖVE. Kaledis is a tool for allowing Luau to be used with Love2D via transpiling, alongside providing easier & simpler management of Love2D projects." 10 | 11 | [dependencies] 12 | clap = { version = "4.5.21", features = ["derive"] } 13 | clap-serde-derive = "0.2.1" 14 | colored = "3.0.0" 15 | inquire = "0.7.5" 16 | serde = { version = "1.0.219", features = ["derive"] } 17 | tokio = { version = "1.44.2", features = ["full"] } 18 | toml = "0.8.20" 19 | url = { version = "2.5.3", features = ["serde"] } 20 | glob = "0.3.1" 21 | zip = "2.6.1" 22 | anyhow = "1.0.93" 23 | async-watcher = "0.3.0" 24 | reqwest = { version = "0.12.15", features = ["json", "rustls-tls"] } 25 | semver = "1.0.23" 26 | console = { version = "0.15.11", features = ["windows-console-colors"] } 27 | tokio-tar = "0.3.1" 28 | async-compression = { version = "0.4.18", features = ["gzip", "tokio"] } 29 | futures = "0.3.31" 30 | strum_macros = "0.27.1" 31 | strum = { version = "0.27.1", features = ["strum_macros"] } 32 | indexmap = "2.9.0" 33 | kaledis_dalbit = { version = "0.1.2" } 34 | ignore = "0.4.23" 35 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024-present orpos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | # Kaledis 5 | 6 |
7 | 8 | Kaledis is a tool for allowing Luau to be used with Love2D via transpiling, alongside providing easier & simpler management of Love2D projects. 9 | 10 | It has many resources to make your life much easier when using Love2D: 11 | * Transpiles Luau into compatible Love2D code, allowing type annotations, libraries and other features to be implemented. 12 | * Automatically manages and provides Love2D installations. (WIP) 13 | * Simple commands and CLI, you'll get the hang of it in no time. 14 | * Easily create & ship your project to the current OS you build the project in. 15 | * A more friendly frontend configuration framework, using a TOML file instead of a *conf.lua* 16 | * If you need to make it dynamic, we allow you to still use a *conf.lua* file. 17 | 18 | ## Installation 19 | *Note: The only available builds are for Windows. MacOS and Linux builds have not been tested.* 20 | 21 | ### From Cargo 22 | ```bash 23 | cargo install kaledis 24 | ``` 25 | 26 | ### From Releases 27 | Go to the Releases page and download the zip corresponding to your system. 28 | 29 | ### From Source 30 | Clone the repo, then use `cargo build` to build the project from scratch *Probably all platforms.* 31 | 32 | ## Usage 33 | You can check the usage [here](USAGE.md) 34 | 35 | ## Credits 36 | - [Dalbit](https://github.com/CavefulGames/dalbit) for the awesome transpiling system. 37 | 38 | ## FAQ 39 | ### Why the name 'Kaledis'? 40 | The name came from the word 'Kalendis', in latin means "moons" or "more than 1 moon". By the fact that Luau and Love2D are "incompatible" and the package solves that problem, it was given this name. 41 | 42 | ### Who I contact for source code related stuff? 43 | If you need anything regarding the code, you can contact lettuce-magician and he will forward the topic to ordep (that actually edits the code). 44 | 45 | ### Why are the type definition files so ugly and are lacking some features? 46 | Luau LSP's typedefs file parsing is kinda weird, and sometimes it crashes or memory leaks. Leaving the only option to weird workarounds. 47 | Currently we're waiting for the [environments](https://github.com/JohnnyMorganz/luau-lsp/pull/84) feature to release so we can finally have proper type definitions for the Love2D environment. -------------------------------------------------------------------------------- /USAGE.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | by default [PATH] is the directory kaledis is executed on. 4 | 5 | ## `init` 6 | Initializes a new Love2D project. 7 | ```sh 8 | kaledis init [PATH] 9 | ``` 10 | 11 | It initiates the project with this files: 12 | ``` 13 | ├───.vscode 14 | ├───assets 15 | ├───love 16 | └───modules 17 | ``` 18 | 19 | ## `build` 20 | Transpiles the project and builds a .love file inside the '.build' directory. 21 | ```sh 22 | kaledis build [PATH] -o 23 | ``` 24 | it will generate a folder looking like this: 25 | ![project structure](images/tree.png) 26 | 27 | ## `compile` 28 | Compiles the project into a executable inside the 'dist' folder. 29 | ```sh 30 | kaledis compile [PATH] -o 31 | ``` 32 | The -o flag joins all files in a single one. 33 | 34 | ## `dev` 35 | Watches for changes in your project, builds and executes love automatically/manual 36 | ```sh 37 | kaledis dev [PATH] 38 | ``` 39 | 40 | ## `update` 41 | Tries to update to the latest release using github releases. 42 | ```sh 43 | kaledis update 44 | ``` -------------------------------------------------------------------------------- /images/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orpos/kaledis/22d4eb0e5a7dec2d088f9e725934b88a967a8dfa/images/image.png -------------------------------------------------------------------------------- /images/tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orpos/kaledis/22d4eb0e5a7dec2d088f9e725934b88a967a8dfa/images/tree.png -------------------------------------------------------------------------------- /src/cli_utils.rs: -------------------------------------------------------------------------------- 1 | use std::{ io::Write, sync::{ Arc, Weak }, time::Duration }; 2 | 3 | use console::{ style, Term }; 4 | use tokio::{ sync::RwLock, time::sleep }; 5 | 6 | pub struct LoadingStatusBar { 7 | status: Arc>, 8 | } 9 | 10 | async fn loading_animation(text: Weak>) { 11 | let mut term = Term::stdout(); 12 | let mut frame_index = 0; 13 | let frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]; 14 | loop { 15 | // As we have a Weak reference when the variable holding LoadingStatusBar dies 16 | // it will be deleted and as such the upgrade will return None 17 | // So we stop showing the animation 18 | if let Some(text) = text.upgrade() { 19 | let data = &*text.read().await; 20 | term.write( 21 | format!("{} {}\r", style(frames[frame_index]).dim().blue(), data).as_bytes() 22 | ).unwrap(); 23 | frame_index += 1; 24 | frame_index %= frames.len(); 25 | sleep(Duration::from_millis(100)).await; 26 | continue; 27 | } 28 | break; 29 | } 30 | } 31 | 32 | impl LoadingStatusBar { 33 | pub fn new(text: String) -> LoadingStatusBar { 34 | Self { 35 | status: Arc::new(RwLock::new(text)), 36 | } 37 | } 38 | pub async fn start_animation(&self) { 39 | let status = Arc::downgrade(&self.status); 40 | tokio::spawn(async move { 41 | loading_animation(status).await; 42 | }); 43 | } 44 | pub async fn change_status(&self, data: String) { 45 | // Clear the line before because there maybe some chars from the previous text 46 | let _ = Term::stdout().clear_line(); 47 | 48 | *self.status.write().await = data; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/commands/build.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | use std::path::PathBuf; 3 | use std::sync::{ Arc, Mutex }; 4 | 5 | use anyhow::Context; 6 | use ignore::WalkBuilder; 7 | use indexmap::IndexSet; 8 | use strum::IntoEnumIterator; 9 | use tokio::io::{ AsyncReadExt, AsyncWriteExt }; 10 | use tokio::fs::{ self, create_dir, remove_dir_all, File }; 11 | 12 | use kaledis_dalbit::{ manifest::Manifest, transpile }; 13 | 14 | use crate::cli_utils::LoadingStatusBar; 15 | use crate::{ toml_conf::{ Config, Modules }, utils::relative }; 16 | use colored::Colorize; 17 | use crate::{ allow, zip_utils::* }; 18 | 19 | pub enum ModelConf { 20 | Exclude(Vec), 21 | Include(Vec), 22 | } 23 | 24 | impl From<&Config> for ModelConf { 25 | fn from(config: &Config) -> Self { 26 | if config.modules.len() < 1 && config.exclude_modules.len() > 0 { 27 | Self::Exclude(config.exclude_modules.clone()) 28 | } else if config.modules.len() > 0 { 29 | if config.exclude_modules.len() > 0 { 30 | eprintln!( 31 | "{}", 32 | "Both modules and exclude modules used, the exclude modules will be ignored".red() 33 | ); 34 | } 35 | Self::Include(config.modules.clone()) 36 | } else { 37 | Self::Exclude(vec![]) 38 | } 39 | } 40 | } 41 | 42 | struct Builder { 43 | transpiler_manifest: Manifest, 44 | strategy: Strategy, 45 | zip: Option, 46 | local: PathBuf, 47 | build_path: PathBuf, 48 | bar: LoadingStatusBar, 49 | used_modules: Option>>>, 50 | } 51 | 52 | impl Builder { 53 | pub async fn new( 54 | local: &PathBuf, 55 | collect_used_modules: bool, 56 | run: Strategy, 57 | one_file: bool 58 | ) -> anyhow::Result { 59 | let config = get_transpiler(one_file).await.context("Failed to build manifest")?; 60 | let bar = LoadingStatusBar::new("Building project...".into()); 61 | bar.start_animation().await; 62 | Ok(Self { 63 | transpiler_manifest: config, 64 | zip: if let Strategy::BuildDev = run { 65 | None 66 | } else { 67 | Some(Zipper::new()) 68 | }, 69 | strategy: run, 70 | bar, 71 | build_path: local.join(".build"), 72 | local: local.clone(), 73 | used_modules: if collect_used_modules { 74 | Some(Arc::new(Mutex::new(IndexSet::new()))) 75 | } else { 76 | None 77 | }, 78 | }) 79 | } 80 | 81 | pub fn generate_conf_modules( 82 | &self, 83 | imported_modules: Vec, 84 | model_conf: ModelConf 85 | ) -> String { 86 | let mut modules_string = "".to_string(); 87 | for module in imported_modules { 88 | let enabled = match model_conf { 89 | ModelConf::Include(ref models) | ModelConf::Exclude(ref models) => { 90 | let found_model = models 91 | .iter() 92 | .find(|x| **x == module) 93 | .is_some(); 94 | if let ModelConf::Exclude(_) = model_conf { 95 | !found_model 96 | } else { 97 | found_model 98 | } 99 | } 100 | }; 101 | modules_string += &format!( 102 | "t.modules.{}={}\n", 103 | &module.to_string().to_lowercase(), 104 | enabled 105 | ); 106 | } 107 | modules_string 108 | } 109 | pub async fn clean_build_folder(&self) -> anyhow::Result<()> { 110 | if self.build_path.exists() { 111 | // This clean function only happens when a new build is requested 112 | // and in dev i considered it unnecessary to persist 113 | if let Strategy::BuildDev = self.strategy { 114 | self.bar.change_status("Cleaning build folder.".to_string()).await; 115 | } else { 116 | println!("Previous build folder found. Deleting it..."); 117 | } 118 | remove_dir_all(&self.build_path).await?; 119 | } 120 | create_dir(&self.build_path).await?; 121 | Ok(()) 122 | } 123 | pub async fn process_file(&self, input: PathBuf, output: PathBuf) -> anyhow::Result<()> { 124 | let mut additional_rules = vec![ 125 | kaledis_dalbit::modifiers::Modifier::DarkluaRule( 126 | Box::new(kaledis_dalbit::modifiers::ModifyRelativePath { 127 | project_root: self.local.clone(), 128 | }) 129 | ) 130 | ]; 131 | if let Some(modules) = &self.used_modules { 132 | additional_rules.push( 133 | kaledis_dalbit::modifiers::Modifier::DarkluaRule( 134 | Box::new(kaledis_dalbit::modifiers::GetLoveModules { 135 | modules: Arc::clone(modules), 136 | }) 137 | ) 138 | ); 139 | } 140 | let mut new_manifest = self.transpiler_manifest.clone(); 141 | new_manifest.input = input; 142 | new_manifest.output = output; 143 | new_manifest.minify = if self.strategy == Strategy::BuildDev { true } else { false }; 144 | transpile::process(new_manifest, Some(&mut additional_rules)).await?; 145 | return Ok(()); 146 | } 147 | pub async fn add_luau_file(&mut self, input: &PathBuf) -> anyhow::Result<()> { 148 | let zip_path = input.strip_prefix(&self.local)?; 149 | 150 | let out_path = self.local.join(".build").join(zip_path); 151 | self.process_file(input.clone(), out_path).await?; 152 | 153 | if let Some(zip) = &mut self.zip { 154 | zip.copy_zip_f_from_path( 155 | &self.local.join(".build").join(zip_path).with_extension("lua"), 156 | zip_path.with_extension("lua") 157 | ).await?; 158 | } 159 | 160 | Ok(()) 161 | } 162 | pub async fn add_luau_files(&mut self) -> anyhow::Result> { 163 | self.bar.change_status(format!("{} {} {}", "Adding", "lua".green(), "files...")).await; 164 | if self.local.join("main.luau").exists() && self.transpiler_manifest.bundle { 165 | if let Err(dat) = self.add_luau_file(&self.local.join("main.luau")).await { 166 | eprintln!("{:?}", dat); 167 | panic!("{} Failed to process {} file", "[!]".red(), "main.luau"); 168 | } 169 | } else { 170 | for path in glob 171 | ::glob(&(self.local.to_string_lossy().to_string() + "/**/*.luau"))? 172 | .filter_map(Result::ok) 173 | .filter( 174 | |path| 175 | !path 176 | .file_name() 177 | .map(|x| x.to_string_lossy().to_string()) 178 | .unwrap_or("".to_string()) 179 | .ends_with(".d.luau") 180 | ) { 181 | if let Err(dat) = self.add_luau_file(&path).await { 182 | eprintln!("{:?}", dat); 183 | eprintln!("{} Failed to process {} file", "[!]".red(), path.display()); 184 | } 185 | } 186 | } 187 | if let Some(zip) = &mut self.zip { 188 | for path in glob 189 | ::glob(&(self.local.to_string_lossy().to_string() + "/**/__polyfill__.lua")) 190 | .unwrap() 191 | .filter_map(Result::ok) { 192 | if 193 | path 194 | .file_name() 195 | .map(|x| x.to_string_lossy().to_string()) 196 | .unwrap_or("".to_string()) 197 | .ends_with(".d.luau") 198 | { 199 | continue; 200 | } 201 | let out_path = path.strip_prefix(&self.local.join(".build")).unwrap(); 202 | zip.copy_zip_f_from_path( 203 | &self.local.join(".build").join(out_path).with_extension("lua"), 204 | out_path.with_extension("lua") 205 | ).await.unwrap(); 206 | } 207 | } 208 | if let Some(modules) = &self.used_modules { 209 | let inside = modules.lock().unwrap(); 210 | Ok( 211 | inside 212 | .iter() 213 | .map(|x| Modules::from_str(&uppercase_first(&x))) 214 | .filter_map(Result::ok) 215 | .collect() 216 | ) 217 | } else { 218 | Ok(vec![]) 219 | } 220 | } 221 | pub async fn add_assets(&mut self) { 222 | self.bar.change_status("Adding asset files...".into()).await; 223 | // TODO use override builder 224 | for path in WalkBuilder::new(&self.local) 225 | .build() 226 | .filter_map(Result::ok) 227 | .filter(|pth| { 228 | let pth = pth.path(); 229 | let ext = pth 230 | .extension() 231 | .map(|x| x.to_str().unwrap()) 232 | .unwrap_or(""); 233 | !( 234 | pth.starts_with(self.local.join("dist")) || 235 | allow!(ext, "lua", "luau", "toml") || 236 | pth.is_dir() 237 | ) 238 | }) { 239 | let path = path.path(); 240 | if let Some(zip) = &mut self.zip { 241 | zip.add_zip_f_from_path(&path, &self.local).await.unwrap(); 242 | } else { 243 | let final_ = self.local 244 | .join(".build") 245 | .join(path.strip_prefix(self.local.clone()).unwrap()); 246 | if !final_.parent().unwrap().exists() { 247 | fs::create_dir_all(final_.parent().unwrap()).await.unwrap(); 248 | } 249 | fs::hard_link(&path, final_).await.unwrap(); 250 | } 251 | } 252 | } 253 | #[inline] 254 | pub fn finish_zip(mut self) -> Option> { 255 | self.zip.take().map(|x| x.finish()) 256 | } 257 | } 258 | 259 | pub async fn get_transpiler(one_file: bool) -> anyhow::Result { 260 | let mut manifest = Manifest { 261 | minify: true, 262 | file_extension: Some("lua".to_string()), 263 | target_version: kaledis_dalbit::TargetVersion::Lua51, 264 | bundle: one_file, 265 | ..Default::default() 266 | }; 267 | 268 | macro_rules! add_modifiers { 269 | ($modifier:expr) => { 270 | manifest.modifiers.insert($modifier.to_string(), true); 271 | }; 272 | ($modifier:expr, $($modi:expr),+) => { 273 | add_modifiers!($modifier); 274 | add_modifiers!($($modi), +); 275 | }; 276 | } 277 | add_modifiers!( 278 | // "rename_variables", 279 | "remove_empty_do", 280 | "remove_spaces", 281 | "remove_unused_while", 282 | "remove_unused_variable", 283 | "remove_unused_if_branch" 284 | ); 285 | // Thanks to new dalbit version this was made much easier 286 | manifest.polyfill.cache().await?; 287 | return Ok(manifest); 288 | } 289 | 290 | fn uppercase_first(s: &str) -> String { 291 | let mut c = s.chars(); 292 | match c.next() { 293 | None => String::new(), 294 | Some(f) => f.to_uppercase().chain(c).collect(), 295 | } 296 | } 297 | 298 | fn format_option(value: Option) -> String { 299 | value.map(|x| x.to_string()).unwrap_or("nil".to_string()) 300 | } 301 | 302 | #[derive(PartialEq, Eq, Clone)] 303 | pub enum Strategy { 304 | /// Makes the executable 305 | BuildAndCompile, 306 | /// Just creates the love file 307 | Build, 308 | /// Just compiles the lua files 309 | BuildDev, 310 | } 311 | 312 | pub async fn build(path: Option, run: Strategy, one_file: bool) -> anyhow::Result<()> { 313 | let local = relative(path); 314 | 315 | if !local.join("kaledis.toml").exists() { 316 | println!("{}", "No Project found!".red()); 317 | return Ok(()); 318 | } 319 | let configs = Config::from_toml_file(local.join("kaledis.toml"))?; 320 | 321 | if configs.project.name.len() < 1 { 322 | eprintln!("{}", "Cannot distribute a game without a name".red()); 323 | return Ok(()); 324 | } 325 | 326 | let mut builder = Builder::new( 327 | &local, 328 | configs.project.detect_modules.unwrap_or(false), 329 | run.clone(), 330 | one_file 331 | ).await?; 332 | builder.clean_build_folder().await?; 333 | let imported_modules = builder.add_luau_files().await?; 334 | 335 | builder.add_assets().await; 336 | 337 | let model_conf: ModelConf = (&configs).into(); 338 | 339 | builder.bar.change_status("Adding config file...".into()).await; 340 | if !(local.join("conf.luau").exists() || local.join("conf.lua").exists()) { 341 | let modules = builder.generate_conf_modules( 342 | if let Strategy::BuildDev = run { 343 | Modules::iter().collect() 344 | } else { 345 | if configs.project.detect_modules.unwrap_or(false) { 346 | println!("Detected Modules: {:?}", imported_modules); 347 | imported_modules 348 | } else { 349 | Modules::iter().collect() 350 | } 351 | }, 352 | model_conf 353 | ); 354 | let conf_file = format!( 355 | r#" 356 | function love.conf(t) 357 | t.identity = {} 358 | t.appendidentity = {} 359 | t.version = {:?} 360 | t.console = {} 361 | t.accelerometerjoystick = {} 362 | t.externalstorage = {} 363 | t.gammacorrect = {} 364 | 365 | t.audio.mic = {} 366 | t.audio.mixwithsystem = {} 367 | 368 | t.window.title = {:?} 369 | t.window.icon = {} 370 | t.window.width = {} 371 | t.window.height = {} 372 | t.window.borderless = {} 373 | t.window.resizable = {} 374 | t.window.minwidth = {} 375 | t.window.minheight = {} 376 | t.window.fullscreen = {} 377 | t.window.fullscreentype = {} 378 | t.window.vsync = {} 379 | t.window.msaa = {} 380 | t.window.depth = {} 381 | t.window.stencil = {} 382 | t.window.display = {} 383 | t.window.highdpi = {} 384 | t.window.usedpiscale = {} 385 | t.window.x = {} 386 | t.window.y = {} 387 | {} 388 | end 389 | "#, 390 | format_option( 391 | configs.project.identity.as_ref().map(|x| x.to_string_lossy().to_string()) 392 | ), 393 | "false", 394 | configs.project.version, 395 | configs.project.console, 396 | configs.project.accelerometer_joystick, 397 | configs.project.external_storage, 398 | configs.project.gamma_correct, 399 | configs.audio.mic, 400 | configs.audio.mix_with_system, 401 | configs.window.title, 402 | format_option(configs.window.icon.as_ref().map(|x| x.to_string_lossy().to_string())), 403 | configs.window.width, 404 | configs.window.height, 405 | configs.window.borderless, 406 | configs.window.resizable, 407 | configs.window.minwidth, 408 | configs.window.minheight, 409 | configs.window.fullscreen, 410 | match configs.window.fullscreentype { 411 | crate::toml_conf::FullscreenType::Desktop => "\"desktop\"", 412 | crate::toml_conf::FullscreenType::Exclusive => "\"exclusive\"", 413 | }, 414 | configs.window.vsync, 415 | configs.window.msaa, 416 | format_option(configs.window.depth), 417 | format_option(configs.window.stencil), 418 | configs.window.display, 419 | configs.window.highdpi, 420 | configs.window.usedpiscale, 421 | format_option(configs.window.x), 422 | format_option(configs.window.y), 423 | modules 424 | ); 425 | if let Strategy::BuildDev = run { 426 | let mut result = fs::File::create(builder.build_path.join("conf.lua")).await?; 427 | result.write(conf_file.as_bytes()).await?; 428 | } else { 429 | if let Some(zip) = &mut builder.zip { 430 | zip.add_zip_f_from_buf("conf.lua", conf_file.as_bytes()).await?; 431 | } 432 | } 433 | } else { 434 | println!("{}", "Custom config file found! Overwriting configs...".yellow()); 435 | } 436 | 437 | match run { 438 | Strategy::BuildDev => {} 439 | Strategy::BuildAndCompile => { 440 | let build_path = builder.build_path.clone(); 441 | builder.clean_build_folder().await?; 442 | let fin = builder.finish_zip().unwrap(); 443 | let love_executable = configs.project.love_path.join("love.exe"); 444 | 445 | 446 | let dist_folder = local.join("dist"); 447 | 448 | if !dist_folder.exists() { 449 | create_dir(&dist_folder).await?; 450 | } 451 | 452 | let new_exe = dist_folder.join(configs.project.name).with_extension("exe"); 453 | 454 | { 455 | // Here we store the contents only when writing 456 | let mut contents = File::open(love_executable).await?; 457 | let mut buffer = Vec::new(); 458 | 459 | contents.read_to_end(&mut buffer).await?; 460 | 461 | let mut f = File::create(&new_exe).await?; 462 | f.write(&buffer).await?; 463 | f.write(&fin).await?; 464 | } 465 | 466 | println!("Saving executable in : {}", new_exe.display().to_string()); 467 | 468 | let l_path = configs.project.love_path; 469 | 470 | macro_rules! import_love_file { 471 | ($name:expr) => { 472 | { 473 | let path = l_path.join($name); 474 | if path.exists() { 475 | std::fs::copy(&path, dist_folder.join($name))?; 476 | } else { 477 | println!("{}{:?}", "Missing dll: ".red(), path); 478 | } 479 | } 480 | }; 481 | ($name:expr, $($na:expr),+) => { 482 | import_love_file!($name); 483 | import_love_file!($($na), +) 484 | }; 485 | } 486 | import_love_file!( 487 | "license.txt", 488 | "love.dll", 489 | "lua51.dll", 490 | "mpg123.dll", 491 | "msvcp120.dll", 492 | "msvcr120.dll", 493 | "OpenAL32.dll", 494 | "SDL2.dll" 495 | ); 496 | remove_dir_all(&build_path).await?; 497 | } 498 | Strategy::Build => { 499 | let build_path = builder.build_path.clone(); 500 | let fin = builder.finish_zip().unwrap(); 501 | 502 | let mut file = File::create(build_path.join("final.love")).await?; 503 | file.write(&fin).await?; 504 | } 505 | } 506 | 507 | println!("{} {}", "[+]".green(), "Love project builded sucessfully"); 508 | 509 | Ok(()) 510 | } 511 | -------------------------------------------------------------------------------- /src/commands/init.rs: -------------------------------------------------------------------------------- 1 | use std::{ env, fs, io::Write, path::PathBuf }; 2 | 3 | use colored::Colorize; 4 | use inquire::{ MultiSelect, Text }; 5 | use strum::IntoEnumIterator; 6 | 7 | use crate::{ toml_conf::{ self, Modules, Project }, utils::relative }; 8 | 9 | pub fn init(path: Option) { 10 | let local = relative(path); 11 | 12 | println!( 13 | "{} {}{}", 14 | "Initializing project in ".blue(), 15 | local.as_os_str().to_string_lossy().bright_white(), 16 | ".".blue() 17 | ); 18 | 19 | let project_name = Text::new("What is the name of the project? ") 20 | .with_placeholder("my-game") 21 | .prompt() 22 | .unwrap(); 23 | 24 | // TODO: give user the option to auto install 25 | let mut path_ = env 26 | ::var_os("PATH") 27 | .map(|path_| { 28 | for path in env::split_paths(&path_) { 29 | if path.join("love.exe").exists() { 30 | return Some(path); 31 | } 32 | } 33 | return None; 34 | }) 35 | .flatten(); 36 | path_ = path_ 37 | .map(|x| Some(x)) 38 | .unwrap_or_else(|| { 39 | if cfg!(windows) { 40 | if let Ok(dir) = env::var("ProgramFiles") { 41 | let love_path = PathBuf::from(dir).join("LOVE"); 42 | if love_path.exists() { 43 | return Some(love_path); 44 | } 45 | } 46 | } 47 | return None; 48 | }); 49 | 50 | let location = path_.unwrap_or_else(|| { 51 | println!("{} {}", "[!]".red(), "Love not found."); 52 | Text::new("Where is the Love2D executable located?") 53 | .with_placeholder(r"C:\Program Files\LOVE") 54 | .prompt() 55 | .unwrap() 56 | .into() 57 | }); 58 | 59 | let modules = MultiSelect::new("Select what modules you will use:", Modules::iter().collect()) 60 | .with_all_selected_by_default() 61 | .prompt() 62 | .unwrap(); 63 | 64 | let config = toml_conf::Config { 65 | modules, 66 | project: Project { 67 | name: project_name, 68 | love_path: location.clone(), 69 | ..Default::default() 70 | }, 71 | ..Default::default() 72 | }; 73 | let conf = toml::to_string(&config).unwrap(); 74 | 75 | if !local.exists() { 76 | fs::create_dir(&local).unwrap(); 77 | } 78 | 79 | macro_rules! create { 80 | (dir $nome:expr) => { 81 | fs::create_dir(local.join($nome)).unwrap() 82 | }; 83 | (dir $nome:expr, $($nome_2:expr),+) => { 84 | create!(dir $nome); 85 | create!(dir $($nome_2), +); 86 | }; 87 | (file $nome:expr, $content:expr) => { 88 | { 89 | let mut file = fs::File::create(local.join($nome)).unwrap(); 90 | file.write($content).unwrap(); 91 | file 92 | } 93 | }; 94 | (file_absolute $nome:expr, $content:expr) => { 95 | { 96 | let mut file = fs::File::create($nome).unwrap(); 97 | file.write($content).unwrap(); 98 | file 99 | } 100 | }; 101 | } 102 | create!(dir "modules", "assets", ".vscode"); 103 | create!(file "kaledis.toml", conf.as_bytes()); 104 | create!(file "globals.d.luau", include_bytes!("../../static/globals.d.luau")); 105 | create!(file "main.luau", include_bytes!("../../static/main.luau")); 106 | create!(file_absolute local.join(".vscode").join("settings.json"), include_bytes!("../../static/vscode_settings.json")); 107 | create!(file ".gitignore", include_bytes!("../../static/.gitignore")); 108 | } 109 | -------------------------------------------------------------------------------- /src/commands/mod.rs: -------------------------------------------------------------------------------- 1 | mod init; 2 | mod build; 3 | mod watch; 4 | mod update; 5 | 6 | use std::{ env::{current_exe, temp_dir}, path::PathBuf, thread, time::Duration }; 7 | 8 | use clap::{ Parser, Subcommand }; 9 | use tokio::{ fs::{ copy, remove_file }, process::Command }; 10 | 11 | #[derive(Subcommand, Debug)] 12 | pub enum Commands { 13 | #[clap(about = "Initializes a new Love2D project.")] Init { 14 | path: Option, 15 | }, 16 | #[clap( 17 | about = "Transpiles everything, and builds a '.love' file inside a '.build' directory." 18 | )] Build { 19 | path: Option, 20 | #[arg(short, long, help="A config that joins all files in a single one.")] 21 | one_file: bool 22 | }, 23 | #[clap( 24 | about = "Compiles the entire project to a executable, inside a 'dist' folder." 25 | )] Compile { 26 | path: Option, 27 | #[arg(short, long, help="A config that joins all files in a single one.")] 28 | one_file: bool 29 | }, 30 | #[clap( 31 | about = "Watches for changes in the project and builds and executes love automatically." 32 | )] Dev { 33 | path: Option, 34 | }, 35 | #[clap( 36 | about = "Updates kaledis based of github releases. This will also be used internally to handle files. If you want just to update just call it without passing anything" 37 | )] Update { 38 | step: Option, 39 | is_established: Option, 40 | #[arg(short, long, help="A config that joins all files in a single one.")] 41 | allow_breaking: bool 42 | }, 43 | } 44 | 45 | #[derive(Parser, Debug)] 46 | #[clap(version)] 47 | pub struct CLI { 48 | #[command(subcommand)] 49 | pub cli: Commands, 50 | // TODO: make subcommands shortcuts to flags 51 | } 52 | 53 | pub async fn handle_commands(command: Commands) { 54 | if temp_dir().join("new.exe").exists() { 55 | let _ = remove_file(temp_dir().join("new.exe")).await; 56 | } 57 | match command { 58 | Commands::Init { path } => { 59 | init::init(path); 60 | } 61 | Commands::Build { path, one_file } => { 62 | build::build(path, build::Strategy::Build, one_file).await.unwrap(); 63 | } 64 | Commands::Dev { path } => { 65 | watch::watch(path).await; 66 | } 67 | Commands::Compile { path, one_file } => { 68 | build::build(path, build::Strategy::BuildAndCompile, one_file).await.unwrap(); 69 | } 70 | Commands::Update { step, is_established, allow_breaking } => { 71 | // Artificial delay to wait for the previous instance to die 72 | if let Some(_) = is_established { 73 | println!("Removing temporary file"); 74 | thread::sleep(Duration::from_millis(1100)); 75 | let _ = remove_file(step.unwrap()).await; 76 | return; 77 | } 78 | if let Some(target) = step { 79 | println!("Removing old version"); 80 | thread::sleep(Duration::from_millis(700)); 81 | remove_file(&target).await.unwrap(); 82 | copy(current_exe().unwrap(), &target).await.unwrap(); 83 | Command::new(target) 84 | .args(vec!["update", ¤t_exe().unwrap().display().to_string(), "true"]) 85 | .spawn() 86 | .unwrap(); 87 | return; 88 | } 89 | update::update(allow_breaking).await; 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/commands/update.rs: -------------------------------------------------------------------------------- 1 | use std::env::temp_dir; 2 | use std::io::Write; 3 | 4 | use anyhow::Context; 5 | use futures::StreamExt; 6 | use reqwest::header::ACCEPT; 7 | use semver::Version; 8 | use serde::Deserialize; 9 | use tokio::process::Command; 10 | 11 | use tokio::io::AsyncReadExt; 12 | 13 | #[derive(Debug, Deserialize)] 14 | struct Asset { 15 | name: String, 16 | url: url::Url, 17 | } 18 | 19 | #[derive(Debug, Deserialize)] 20 | struct Release { 21 | tag_name: String, 22 | assets: Vec, 23 | } 24 | 25 | fn get_repo() -> (String, String) { 26 | let mut parts = env!("CARGO_PKG_REPOSITORY").split('/').skip(3); 27 | (parts.next().unwrap().to_string(), parts.next().unwrap().to_string()) 28 | } 29 | 30 | fn get_version() -> Version { 31 | Version::parse(env!("CARGO_PKG_VERSION").trim_start_matches("v")).unwrap() 32 | } 33 | 34 | pub async fn get_latest_remote_version(reqwest: &reqwest::Client) -> anyhow::Result { 35 | let (owner, repo) = get_repo(); 36 | let releases = reqwest 37 | .get(format!("https://api.github.com/repos/{owner}/{repo}/releases")) 38 | .send().await 39 | .context("Failed to send request to GitHub API") 40 | .unwrap() 41 | .json::>().await 42 | .unwrap(); 43 | 44 | releases 45 | .into_iter() 46 | .map(|release| Version::parse(&release.tag_name.trim_start_matches("v"))) 47 | .filter_map(Result::ok) 48 | .max() 49 | .context("Failed to find first version.") 50 | } 51 | 52 | pub async fn get_update(reqwest: &reqwest::Client, allow_breaking: bool) -> anyhow::Result { 53 | let latest = get_latest_remote_version(reqwest).await?; 54 | if latest > get_version() { 55 | if latest.major > get_version().major && !allow_breaking { 56 | eprintln!("Major update detected. Add --allow-breaking flag to update"); 57 | return Ok(false); 58 | } 59 | println!("New update found! Updating..."); 60 | 61 | let release = reqwest 62 | .get(format!("https://api.github.com/repos/orpos/kaledis/releases/tags/v{}", latest)) 63 | .send().await 64 | .unwrap() 65 | .json::().await 66 | .unwrap(); 67 | 68 | let asset = release.assets 69 | .into_iter() 70 | .find(|asset| { 71 | asset.name.ends_with( 72 | &format!("-{}-{}.tar.gz", std::env::consts::OS, std::env::consts::ARCH) 73 | ) 74 | }) 75 | .context("Failed to find a version for current platform")?; 76 | let bytes = reqwest 77 | .get(asset.url) 78 | .header(ACCEPT, "application/octet-stream") 79 | .send().await 80 | .unwrap() 81 | .bytes().await 82 | .unwrap(); 83 | 84 | let mut decoder = async_compression::tokio::bufread::GzipDecoder::new(bytes.as_ref()); 85 | let mut archive = tokio_tar::Archive::new(&mut decoder); 86 | 87 | let mut entry = archive 88 | .entries() 89 | .context("Failed to read archive")? 90 | .next().await 91 | .context("Archive has no files.")? 92 | .context("Failed to get first file")?; 93 | 94 | let mut buffer = Vec::new(); 95 | 96 | entry.read_to_end(&mut buffer).await.context("Failed to read the bytes.")?; 97 | 98 | let exe = temp_dir().with_file_name("new.exe"); 99 | 100 | { 101 | let mut new_exe = std::fs::File::create(&exe).unwrap(); 102 | new_exe.write(&buffer).unwrap(); 103 | } 104 | Command::new(&exe).args(vec!["update", &temp_dir().display().to_string()]).spawn().unwrap(); 105 | std::process::exit(0); 106 | } else { 107 | println!("No update found."); 108 | return Ok(false); 109 | } 110 | } 111 | 112 | pub async fn update(allow_breaking: bool) { 113 | let reqwest = { 114 | let mut headers = reqwest::header::HeaderMap::new(); 115 | 116 | headers.insert( 117 | reqwest::header::ACCEPT, 118 | "application/json".parse().context("failed to create accept header").unwrap() 119 | ); 120 | 121 | reqwest::Client 122 | ::builder() 123 | .user_agent(concat!("kaledis", "/", "updater")) 124 | .default_headers(headers) 125 | .build() 126 | .unwrap() 127 | }; 128 | get_update(&reqwest, allow_breaking).await.unwrap(); 129 | } 130 | -------------------------------------------------------------------------------- /src/commands/watch.rs: -------------------------------------------------------------------------------- 1 | use std::{ path::PathBuf, sync::{ Arc, RwLock }, time::Duration }; 2 | 3 | use anyhow::Context; 4 | use async_watcher::AsyncDebouncer; 5 | use colored::Colorize; 6 | use console::Term; 7 | use tokio::{ process::{ Child, Command }, sync::broadcast::{ channel, Sender } }; 8 | 9 | use crate::{ commands::build, toml_conf::Config, utils::relative }; 10 | 11 | #[derive(Clone)] 12 | struct WatchDaemon<'a> { 13 | path: &'a PathBuf, 14 | base_path: Option, 15 | love_path: PathBuf, 16 | love_executable: PathBuf, 17 | } 18 | 19 | impl<'a> WatchDaemon<'a> { 20 | pub fn new(path: &'a PathBuf, love_path: PathBuf, base_path: Option) -> Self { 21 | Self { 22 | path, 23 | love_executable: love_path.join("love.exe"), 24 | love_path, 25 | base_path, 26 | } 27 | } 28 | pub async fn build(&self) -> anyhow::Result<()> { 29 | build 30 | ::build(self.base_path.clone(), build::Strategy::BuildDev, false).await 31 | .context("Building")?; 32 | Ok(()) 33 | } 34 | pub async fn run(&self) -> anyhow::Result { 35 | if !self.path.join(".build").exists() { 36 | anyhow::bail!("No bundle found."); // maybe we forgot to build it 37 | } 38 | Ok( 39 | Command::new(&self.love_executable) 40 | .current_dir(&self.love_path) 41 | .arg(self.path.join(".build")) 42 | .spawn() 43 | .context("Spawning the process")? 44 | ) 45 | } 46 | } 47 | 48 | async fn spawn_file_reader(watching: Arc>, local: &PathBuf, sender: Sender) { 49 | let local = local.clone(); 50 | tokio::spawn(async move { 51 | let (mut c, mut r) = AsyncDebouncer::new_with_channel( 52 | Duration::from_secs(1), 53 | Some(Duration::from_secs(1)) 54 | ).await.unwrap(); 55 | 56 | c.watcher().watch(&local, async_watcher::notify::RecursiveMode::Recursive).unwrap(); 57 | while let Some(Ok(data)) = r.recv().await { 58 | { 59 | if !*watching.read().unwrap() { 60 | continue; 61 | } 62 | } 63 | if 64 | data 65 | .iter() 66 | .filter(|x| { !x.path.starts_with(local.join(".build")) }) 67 | .collect::>() 68 | .len() < 1 69 | { 70 | continue; 71 | } 72 | sender.send(Message::BuildProject).unwrap(); 73 | } 74 | }); 75 | } 76 | 77 | #[derive(Clone, PartialEq, Eq, Debug)] 78 | enum Message { 79 | CloseLove, 80 | BuildProject, 81 | CloseDev, 82 | } 83 | 84 | async fn spawn_keyboard_handler(watching: Arc>, sender: Sender) { 85 | tokio::task::spawn_blocking(move || { 86 | let term = Term::stdout(); 87 | loop { 88 | let key = term.read_key().unwrap_or(console::Key::Unknown); 89 | match key { 90 | console::Key::Char('a') | console::Key::Char('A') => { 91 | let mut auto_save = watching.write().unwrap(); 92 | if !*auto_save { 93 | println!("{} {}", "[+]".blue(), "Auto Save enabled"); 94 | } else { 95 | println!("{} {}", "[-]".blue(), "Auto Save disabled"); 96 | } 97 | *auto_save = !*auto_save; 98 | } 99 | console::Key::Char('L') | console::Key::Char('l') => { 100 | sender.send(Message::BuildProject).unwrap(); 101 | } 102 | console::Key::Char('Q') | console::Key::Char('q') => { 103 | sender.send(Message::CloseDev).unwrap(); 104 | break; 105 | } 106 | console::Key::Escape => { 107 | print!("[-] Closing...\r"); 108 | sender.send(Message::CloseLove).unwrap(); 109 | } 110 | _ => {} 111 | } 112 | } 113 | }); 114 | } 115 | 116 | pub async fn watch(base_path: Option) { 117 | let local = relative(base_path.clone()); 118 | println!("Watching..."); 119 | println!("Press [L] if you want to build manually"); 120 | println!("Press [A] if you want to toggle between auto build and manual mode."); 121 | println!("Press [Q] if you want to close the dev server."); 122 | println!("Press [Esc] if you want to close Love."); 123 | 124 | if !local.join("kaledis.toml").exists() { 125 | eprintln!("{}", "No project found!".red()); 126 | return; 127 | } 128 | 129 | let configs = Config::from_toml_file(local.join("kaledis.toml")).unwrap(); 130 | let love_path = configs.project.love_path; 131 | 132 | let daemon = WatchDaemon::new(&local, love_path, base_path); 133 | 134 | let watching = Arc::new(RwLock::new(false)); 135 | let (sender, mut receiver) = channel::(2); 136 | 137 | spawn_keyboard_handler(Arc::clone(&watching), sender.clone()).await; 138 | spawn_file_reader(watching, &local, sender.clone()).await; 139 | 140 | let mut child: Option = None; 141 | while let Ok(message) = receiver.recv().await { 142 | if let Some(mut child) = child.take() { 143 | if let Err(err) = child.kill().await { 144 | eprintln!("{}\n{}", err, "Failed to kill love2d process.".red()); 145 | } else if let Message::CloseLove = message { 146 | println!("{} Closed love.", "[+]".blue()); 147 | }; 148 | } 149 | if let Message::CloseDev = message { 150 | break; 151 | } 152 | if let Message::BuildProject = message { 153 | child = daemon.build().await.and(daemon.run().await).ok(); 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod toml_conf; 2 | mod commands; 3 | mod utils; 4 | mod zip_utils; 5 | mod cli_utils; 6 | 7 | use std::{ process::ExitCode, thread }; 8 | 9 | use colored::Colorize; 10 | use commands::{ handle_commands, CLI }; 11 | 12 | use clap::Parser; 13 | use tokio::runtime; 14 | 15 | const STACK_SIZE: usize = 4 * 1024 * 1024 * 1024; 16 | 17 | fn print_banner() { 18 | println!( 19 | "{}", 20 | "░ ░░░░ ░░░ ░░░ ░░░░░░░░ ░░ ░░░ ░░░ ░░".purple() 21 | ); 22 | println!( 23 | "{}", 24 | "▒ ▒▒▒ ▒▒▒ ▒▒▒▒ ▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒▒".purple() 25 | ); 26 | println!("{}", "▓ ▓▓▓▓▓ ▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓".cyan()); 27 | println!("{}", "█ ███ ███ ██ ████████ ████████ ████ █████ ███████████ █".cyan()); 28 | println!("{}", "█ ████ ██ ████ ██ ██ ██ ███ ███ ██".cyan()); 29 | println!(""); 30 | } 31 | 32 | fn run() -> ExitCode { 33 | print_banner(); 34 | let args = CLI::parse(); 35 | let rt = runtime::Builder::new_multi_thread().enable_io().enable_time().build().unwrap(); 36 | rt.block_on(handle_commands(args.cli)); 37 | ExitCode::SUCCESS 38 | } 39 | 40 | fn main() -> ExitCode { 41 | let child = thread::Builder::new().stack_size(STACK_SIZE).spawn(run).unwrap(); 42 | return child.join().unwrap_or(ExitCode::FAILURE) 43 | } 44 | -------------------------------------------------------------------------------- /src/toml_conf.rs: -------------------------------------------------------------------------------- 1 | use std::{ fmt::Display, fs::read_to_string, path::{ Path, PathBuf } }; 2 | 3 | use clap_serde_derive::{ clap::{ self }, serde::Serialize, ClapSerde }; 4 | use serde::Deserialize; 5 | 6 | use strum::IntoEnumIterator; 7 | use strum_macros::{ EnumIter, EnumString }; 8 | 9 | #[derive(ClapSerde, Serialize, Deserialize)] 10 | #[derive(Debug)] 11 | pub struct Audio { 12 | /// Request and use microphone capabilities in Android 13 | #[default(false)] 14 | #[arg(short, long, help = "Request and use microphone capabilities in Android")] 15 | pub mic: bool, 16 | /// Keep background music playing when opening LOVE (boolean, iOS and Android only) 17 | #[default(true)] 18 | #[arg( 19 | short, 20 | long, 21 | help = "Keep background music playing when opening LOVE (boolean, iOS and Android only) " 22 | )] 23 | pub mix_with_system: bool, 24 | } 25 | 26 | #[derive(Debug, Deserialize, Serialize, Clone, clap_serde_derive::clap::ValueEnum)] 27 | pub enum FullscreenType { 28 | Desktop, 29 | Exclusive, 30 | } 31 | impl Display for FullscreenType { 32 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 33 | write!(f, "{self:?}") 34 | } 35 | } 36 | 37 | #[derive(ClapSerde, Serialize, Deserialize)] 38 | #[derive(Debug)] 39 | pub struct Window { 40 | /// The window title 41 | #[default("Untitled".to_string())] 42 | #[arg(short, long, help = "The window title")] 43 | pub title: String, 44 | /// Filepath to an image to use as the window's icon 45 | #[arg(short, long, help = "Filepath to an image to use as the window's icon.")] 46 | pub icon: Option, 47 | /// The window width 48 | #[default(800)] 49 | #[arg(short, long, help = "The window width.")] 50 | pub width: u32, 51 | /// The window height 52 | #[default(600)] 53 | #[arg(short, long, help = "The window height.")] 54 | pub height: u32, 55 | /// Remove all border visuals from the window 56 | #[default(false)] 57 | #[arg(short, long, help = "Remove all border visuals from the window.")] 58 | pub borderless: bool, 59 | /// Let the window be user-resizable (boolean) 60 | #[default(false)] 61 | #[arg(short, long, help = "Let the window be user-resizable.")] 62 | pub resizable: bool, 63 | /// Minimum window width if the window is resizable 64 | #[default(1)] 65 | #[arg(short, long, help = "Minimum window width if the window is resizable.")] 66 | pub minwidth: u32, 67 | /// Minimum window height if the window is resizable 68 | #[default(1)] 69 | #[arg(short, long, help = "Minimum window height if the window is resizable")] 70 | pub minheight: u32, 71 | /// Enable fullscreen 72 | #[default(false)] 73 | #[arg(short, long, help = "Enable fullscreen")] 74 | pub fullscreen: bool, 75 | // Choose between "desktop" fullscreen or "exclusive" fullscreen mode 76 | #[arg( 77 | short, 78 | long, 79 | help = "Choose between \"desktop\" fullscreen or \"exclusive\" fullscreen mode" 80 | )] 81 | #[default(FullscreenType::Desktop)] 82 | pub fullscreentype: FullscreenType, 83 | /// Vertical sync mode 84 | #[default(1)] 85 | #[arg(short, long, help = "Vertical sync mode")] 86 | pub vsync: u32, 87 | /// The number of samples to use with multi-sampled antialiasing 88 | #[default(0)] 89 | #[arg(short, long, help = "The number of samples to use with multi-sampled antialiasing")] 90 | pub msaa: u32, 91 | /// The number of bits per sample in the depth buffer 92 | #[arg(short, long, help = "The number of bits per sample in the depth buffer")] 93 | pub depth: Option, 94 | /// The number of bits per sample in the stencil buffer 95 | #[arg(short, long, help = "The number of bits per sample in the stencil buffer")] 96 | pub stencil: Option, 97 | /// Index of the monitor to show the window in 98 | #[default(1)] 99 | #[arg(short, long, help = "Index of the monitor to show the window in")] 100 | pub display: u8, 101 | /// Enable high-dpi mode for the window on a Retina display (boolean) 102 | #[default(false)] 103 | #[arg(short, long, help = "Enable high-dpi mode for the window on a Retina display (boolean)")] 104 | pub highdpi: bool, 105 | /// Enable automatic DPI scaling when highdpi is set to true as well (boolean) 106 | #[default(true)] 107 | #[arg( 108 | short, 109 | long, 110 | help = "Enable automatic DPI scaling when highdpi is set to true as well (boolean)" 111 | )] 112 | pub usedpiscale: bool, 113 | /// The x-coordinate of the window's position in the specified display 114 | #[arg(short, long, help = "The x-coordinate of the window's position in the specified display")] 115 | pub x: Option, 116 | /// The y-coordinate of the window's position in the specified display 117 | #[arg(short, long, help = "The y-coordinate of the window's position in the specified display")] 118 | pub y: Option, 119 | } 120 | 121 | #[derive( 122 | EnumString, 123 | EnumIter, 124 | Debug, 125 | Deserialize, 126 | Serialize, 127 | Clone, 128 | clap_serde_derive::clap::ValueEnum, 129 | PartialEq, 130 | Eq 131 | )] 132 | pub enum Modules { 133 | /// Enable the audio module 134 | Audio, 135 | /// Enable the data module 136 | Data, 137 | /// Enable the event module 138 | Event, 139 | /// Enable the font module 140 | Font, 141 | /// Enable the graphics module 142 | Graphics, 143 | /// Enable the image module 144 | Image, 145 | /// Enable the joystick module 146 | Joystick, 147 | /// Enable the keyboard module 148 | Keyboard, 149 | /// Enable the math module 150 | Math, 151 | /// Enable the mouse module 152 | Mouse, 153 | /// Enable the physics module 154 | Physics, 155 | /// Enable the sound module 156 | Sound, 157 | /// Enable the system module 158 | System, 159 | /// Enable the thread module 160 | Thread, 161 | /// Enable the timer module, Disabling it will result 0 delta time in love.update 162 | Timer, 163 | /// Enable the touch module 164 | Touch, 165 | /// Enable the video module 166 | Video, 167 | /// Enable the window module 168 | Window, 169 | } 170 | 171 | impl Display for Modules { 172 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 173 | write!(f, "{self:?}") 174 | } 175 | } 176 | 177 | #[derive(ClapSerde, Serialize, Deserialize)] 178 | #[derive(Debug)] 179 | pub struct Project { 180 | #[arg(short, long, help = "Enable detection algorithm.")] 181 | pub detect_modules : Option, 182 | 183 | #[arg(short, long, help = "Save location.")] 184 | pub identity: Option, 185 | 186 | /// Name of the project 187 | #[arg(short, long, help = "Name of the project")] 188 | pub name: String, 189 | 190 | /// Where the Love2D executable is located 191 | #[arg(short, long, help = "Where the Love2D executable is located")] 192 | pub love_path: PathBuf, 193 | 194 | /// What version of Love2D to use 195 | #[default("11.5".to_string())] 196 | #[arg(short, long, help = "What version of Love2D to use")] 197 | pub version: String, 198 | 199 | /// Allows a custom configuration file to be used, that will later be merged with the TOML whenever building the project 200 | #[arg( 201 | short, 202 | long, 203 | help = "Allows a custom configuration file to be used, that will later be merged with the TOML whenever building the project" 204 | )] 205 | pub custom_conf: Option, 206 | 207 | /// Whenever to attach a console (Windows only) 208 | #[default(true)] 209 | #[arg(short, long, help = "Whenever to attach a console when running the game")] 210 | pub console: bool, 211 | 212 | /// Enable the accelerometer on iOS and Android by exposing it as a Joystick (boolean) 213 | #[default(true)] 214 | #[arg( 215 | short, 216 | help = "Enable the accelerometer on iOS and Android by exposing it as a Joystick " 217 | )] 218 | pub accelerometer_joystick: bool, 219 | 220 | /// If it's true, allows saving files (and read from the save directory) in external storage on Android 221 | #[default(false)] 222 | #[arg( 223 | short, 224 | long, 225 | help = "If it's true, allows saving files (and read from the save directory) in external storage on Android" 226 | )] 227 | pub external_storage: bool, 228 | 229 | /// Enable gamma-correct rendering, when supported by the system (boolean) 230 | #[default(false)] 231 | #[arg( 232 | short, 233 | long, 234 | help = "Enable gamma-correct rendering, when supported by the system (boolean)" 235 | )] 236 | pub gamma_correct: bool, 237 | 238 | #[default(vec![])] 239 | #[arg(short, long, help = "Define what dependencies the project uses")] 240 | pub dependencies: Vec, 241 | } 242 | 243 | #[derive(ClapSerde, Serialize, Deserialize)] 244 | #[derive(Debug)] 245 | pub struct Config { 246 | #[clap_serde] 247 | #[command(flatten)] 248 | pub project: Project, 249 | 250 | #[clap_serde] 251 | #[command(flatten)] 252 | pub window: Window, 253 | 254 | #[clap_serde] 255 | #[command(flatten)] 256 | pub audio: Audio, 257 | 258 | #[default(Modules::iter().collect())] 259 | pub modules: Vec, 260 | 261 | #[default(vec![])] 262 | pub exclude_modules: Vec, 263 | } 264 | 265 | impl Config { 266 | pub fn from_toml_file>(path: P) -> anyhow::Result { 267 | let data = read_to_string(path)?; 268 | Ok(toml::from_str(&data)?) 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /src/utils.rs: -------------------------------------------------------------------------------- 1 | use std::{ env, path::PathBuf }; 2 | 3 | pub fn relative(path: Option) -> PathBuf { 4 | let ma = env::current_dir().unwrap(); 5 | path.map(|x| ma.join(x)).unwrap_or(ma) 6 | } 7 | 8 | #[macro_export] 9 | macro_rules! allow { 10 | ($target:expr, $equal:expr) => { 11 | { 12 | $target == $equal 13 | } 14 | }; 15 | ($target:expr, $equal:expr, $($eq:expr),+) => { 16 | { 17 | allow!($target, $equal) || 18 | allow!($target, $($eq),+) 19 | } 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /src/zip_utils.rs: -------------------------------------------------------------------------------- 1 | use std::{ io::{ Cursor, Write }, path::{ Path, PathBuf } }; 2 | 3 | use tokio::{ fs::File, io::AsyncReadExt }; 4 | use zip::{ result::ZipResult, write::SimpleFileOptions, ZipWriter }; 5 | 6 | pub struct Zipper { 7 | inner: ZipWriter>>, 8 | } 9 | 10 | impl Zipper { 11 | pub fn new() -> Zipper { 12 | Self { 13 | inner: ZipWriter::new(Cursor::new(Vec::new())), 14 | } 15 | } 16 | pub fn finish(self) -> Vec { 17 | let data = self.inner.finish().unwrap(); 18 | data.into_inner() 19 | } 20 | pub async fn add_zip_f_from_buf(&mut self, name: &str, buffer: &[u8]) -> ZipResult<()> { 21 | let zip = &mut self.inner; 22 | zip.start_file( 23 | name, 24 | SimpleFileOptions::default().compression_method(zip::CompressionMethod::Stored) 25 | )?; 26 | zip.write(buffer)?; 27 | Ok(()) 28 | } 29 | 30 | pub async fn add_zip_f_from_path( 31 | &mut self, 32 | name: &Path, 33 | prefix: &PathBuf 34 | ) -> anyhow::Result<()> { 35 | self.copy_zip_f_from_path(name, name.strip_prefix(prefix)?.to_path_buf()).await 36 | } 37 | pub async fn copy_zip_f_from_path( 38 | &mut self, 39 | name: &Path, 40 | output: PathBuf 41 | ) -> anyhow::Result<()> { 42 | let zip = &mut self.inner; 43 | zip.start_file_from_path( 44 | output, 45 | SimpleFileOptions::default().compression_method(zip::CompressionMethod::Stored) 46 | )?; 47 | let mut file = File::open(name).await?; 48 | let mut buffer = Vec::new(); 49 | file.read_to_end(&mut buffer).await?; 50 | zip.write(&buffer)?; 51 | Ok(()) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /static/.gitignore: -------------------------------------------------------------------------------- 1 | .build 2 | dist -------------------------------------------------------------------------------- /static/conf.lua: -------------------------------------------------------------------------------- 1 | function love.conf(t) 2 | t.identity = nil -- The name of the save directory (string) 3 | t.appendidentity = false -- Search files in source directory before save directory (boolean) 4 | t.version = "11.4" -- The LÖVE version this game was made for (string) 5 | t.console = false -- Attach a console (boolean, Windows only) 6 | t.accelerometerjoystick = true -- Enable the accelerometer on iOS and Android by exposing it as a Joystick (boolean) 7 | t.externalstorage = false -- True to save files (and read from the save directory) in external storage on Android (boolean) 8 | t.gammacorrect = false -- Enable gamma-correct rendering, when supported by the system (boolean) 9 | 10 | t.audio.mic = false -- Request and use microphone capabilities in Android (boolean) 11 | t.audio.mixwithsystem = true -- Keep background music playing when opening LOVE (boolean, iOS and Android only) 12 | 13 | t.window.title = "Untitled" -- The window title (string) 14 | t.window.icon = nil -- Filepath to an image to use as the window's icon (string) 15 | t.window.width = 800 -- The window width (number) 16 | t.window.height = 600 -- The window height (number) 17 | t.window.borderless = false -- Remove all border visuals from the window (boolean) 18 | t.window.resizable = false -- Let the window be user-resizable (boolean) 19 | t.window.minwidth = 1 -- Minimum window width if the window is resizable (number) 20 | t.window.minheight = 1 -- Minimum window height if the window is resizable (number) 21 | t.window.fullscreen = false -- Enable fullscreen (boolean) 22 | t.window.fullscreentype = "desktop" -- Choose between "desktop" fullscreen or "exclusive" fullscreen mode (string) 23 | t.window.vsync = 1 -- Vertical sync mode (number) 24 | t.window.msaa = 0 -- The number of samples to use with multi-sampled antialiasing (number) 25 | t.window.depth = nil -- The number of bits per sample in the depth buffer 26 | t.window.stencil = nil -- The number of bits per sample in the stencil buffer 27 | t.window.display = 1 -- Index of the monitor to show the window in (number) 28 | t.window.highdpi = false -- Enable high-dpi mode for the window on a Retina display (boolean) 29 | t.window.usedpiscale = true -- Enable automatic DPI scaling when highdpi is set to true as well (boolean) 30 | t.window.x = nil -- The x-coordinate of the window's position in the specified display (number) 31 | t.window.y = nil -- The y-coordinate of the window's position in the specified display (number) 32 | 33 | t.modules.audio = true -- Enable the audio module (boolean) 34 | t.modules.data = true -- Enable the data module (boolean) 35 | t.modules.event = true -- Enable the event module (boolean) 36 | t.modules.font = true -- Enable the font module (boolean) 37 | t.modules.graphics = true -- Enable the graphics module (boolean) 38 | t.modules.image = true -- Enable the image module (boolean) 39 | t.modules.joystick = true -- Enable the joystick module (boolean) 40 | t.modules.keyboard = true -- Enable the keyboard module (boolean) 41 | t.modules.math = true -- Enable the math module (boolean) 42 | t.modules.mouse = true -- Enable the mouse module (boolean) 43 | t.modules.physics = true -- Enable the physics module (boolean) 44 | t.modules.sound = true -- Enable the sound module (boolean) 45 | t.modules.system = true -- Enable the system module (boolean) 46 | t.modules.thread = true -- Enable the thread module (boolean) 47 | t.modules.timer = true -- Enable the timer module (boolean), Disabling it will result 0 delta time in love.update 48 | t.modules.touch = true -- Enable the touch module (boolean) 49 | t.modules.video = true -- Enable the video module (boolean) 50 | t.modules.window = true -- Enable the window module (boolean) 51 | end -------------------------------------------------------------------------------- /static/globals.d.luau: -------------------------------------------------------------------------------- 1 | -- this file relies on only thoughts and prayers to work thanks to innefficient parsing & memory leaks from lsp 🙏 2 | -- modify this at your risk 3 | -- jit types coming soon (if luau-lsp fixes the typedef files parsing or i find a hack to make it work) 4 | 5 | declare ffi: any 6 | declare jit: any 7 | 8 | type userdata = typeof(newproxy()) 9 | type Variant = any 10 | type DistanceModel = 'none'|'inverse'|'inverseclamped'|'linear'|'linearclamped'|'exponent'|'exponentclamped' 11 | type EffectType = 'chorus'|'compressor'|'distortion'|'echo'|'equalizer'|'flanger'|'reverb'|'ringmodulator' 12 | type EffectWaveform = 'sawtooth'|'sine'|'square'|'triangle' 13 | type FilterType = 'lowpass'|'highpass'|'bandpass' 14 | type SourceType = 'static'|'stream'|'queue' 15 | type TimeUnit = 'seconds'|'samples' 16 | type CompressedDataFormat = 'lz4'|'zlib'|'gzip'|'deflate' 17 | type ContainerType = 'data'|'string' 18 | type EncodeFormat = 'base64'|'hex' 19 | type HashFunction = 'md5'|'sha1'|'sha224'|'sha256'|'sha384'|'sha512' 20 | type Event = 'focus'|'joystickpressed'|'joystickreleased'|'keypressed'|'keyreleased'|'mousepressed'|'mousereleased'|'quit'|'resize'|'visible'|'mousefocus'|'threaderror'|'joystickadded'|'joystickremoved'|'joystickaxis'|'joystickhat'|'gamepadpressed'|'gamepadreleased'|'gamepadaxis'|'textinput'|'mousemoved'|'lowmemory'|'textedited'|'wheelmoved'|'touchpressed'|'touchreleased'|'touchmoved'|'directorydropped'|'filedropped'|'jp'|'jr'|'kp'|'kr'|'mp'|'mr'|'q'|'f' 21 | type BufferMode = 'none'|'line'|'full' 22 | type FileDecoder = 'file'|'base64' 23 | type FileMode = 'r'|'w'|'a'|'c' 24 | type FileType = 'file'|'directory'|'symlink'|'other' 25 | type HintingMode = 'normal'|'light'|'mono'|'none' 26 | type AlignMode = 'center'|'left'|'right'|'justify' 27 | type ArcType = 'pie'|'open'|'closed' 28 | type AreaSpreadDistribution = 'uniform'|'normal'|'ellipse'|'borderellipse'|'borderrectangle'|'none' 29 | type BlendAlphaMode = 'alphamultiply'|'premultiplied' 30 | type BlendMode = 'alpha'|'replace'|'screen'|'add'|'subtract'|'multiply'|'lighten'|'darken'|'additive'|'subtractive'|'multiplicative'|'premultiplied' 31 | type CompareMode = 'equal'|'notequal'|'less'|'lequal'|'gequal'|'greater'|'never'|'always' 32 | type CullMode = 'back'|'front'|'none' 33 | type DrawMode = 'fill'|'line' 34 | type FilterMode = 'linear'|'nearest' 35 | type GraphicsFeature = 'clampzero'|'lighten'|'multicanvasformats'|'glsl3'|'instancing'|'fullnpot'|'pixelshaderhighp'|'shaderderivatives' 36 | type GraphicsLimit = 'pointsize'|'texturesize'|'multicanvas'|'canvasmsaa'|'texturelayers'|'volumetexturesize'|'cubetexturesize'|'anisotropy' 37 | type IndexDataType = 'uint16'|'uint32' 38 | type LineJoin = 'miter'|'none'|'bevel' 39 | type LineStyle = 'rough'|'smooth' 40 | type MeshDrawMode = 'fan'|'strip'|'triangles'|'points' 41 | type MipmapMode = 'none'|'auto'|'manual' 42 | type ParticleInsertMode = 'top'|'bottom'|'random' 43 | type SpriteBatchUsage = 'dynamic'|'static'|'stream' 44 | type StackType = 'transform'|'all' 45 | type StencilAction = 'replace'|'increment'|'decrement'|'incrementwrap'|'decrementwrap'|'invert' 46 | type TextureType = '2d'|'array'|'cube'|'volume' 47 | type VertexAttributeStep = 'pervertex'|'perinstance' 48 | type VertexWinding = 'cw'|'ccw' 49 | type WrapMode = 'clamp'|'repeat'|'mirroredrepeat'|'clampzero' 50 | type CompressedImageFormat = 'DXT1'|'DXT3'|'DXT5'|'BC4'|'BC4s'|'BC5'|'BC5s'|'BC6h'|'BC6hs'|'BC7'|'ETC1'|'ETC2rgb'|'ETC2rgba'|'ETC2rgba1'|'EACr'|'EACrs'|'EACrg'|'EACrgs'|'PVR1rgb2'|'PVR1rgb4'|'PVR1rgba2'|'PVR1rgba4'|'ASTC4x4'|'ASTC5x4'|'ASTC5x5'|'ASTC6x5'|'ASTC6x6'|'ASTC8x5'|'ASTC8x6'|'ASTC8x8'|'ASTC10x5'|'ASTC10x6'|'ASTC10x8'|'ASTC10x10'|'ASTC12x10'|'ASTC12x12' 51 | type ImageFormat = 'tga'|'png'|'jpg'|'bmp' 52 | type PixelFormat = 'unknown'|'normal'|'hdr'|'r8'|'rg8'|'rgba8'|'srgba8'|'r16'|'rg16'|'rgba16'|'r16f'|'rg16f'|'rgba16f'|'r32f'|'rg32f'|'rgba32f'|'la8'|'rgba4'|'rgb5a1'|'rgb565'|'rgb10a2'|'rg11b10f'|'stencil8'|'depth16'|'depth24'|'depth32f'|'depth24stencil8'|'depth32fstencil8'|'DXT1'|'DXT3'|'DXT5'|'BC4'|'BC4s'|'BC5'|'BC5s'|'BC6h'|'BC6hs'|'BC7'|'ETC1'|'ETC2rgb'|'ETC2rgba'|'ETC2rgba1'|'EACr'|'EACrs'|'EACrg'|'EACrgs'|'PVR1rgb2'|'PVR1rgb4'|'PVR1rgba2'|'PVR1rgba4'|'ASTC4x4'|'ASTC5x4'|'ASTC5x5'|'ASTC6x5'|'ASTC6x6'|'ASTC8x5'|'ASTC8x6'|'ASTC8x8'|'ASTC10x5'|'ASTC10x6'|'ASTC10x8'|'ASTC10x10'|'ASTC12x10'|'ASTC12x12' 53 | type GamepadAxis = 'leftx'|'lefty'|'rightx'|'righty'|'triggerleft'|'triggerright' 54 | type GamepadButton = 'a'|'b'|'x'|'y'|'back'|'guide'|'start'|'leftstick'|'rightstick'|'leftshoulder'|'rightshoulder'|'dpup'|'dpdown'|'dpleft'|'dpright' 55 | type JoystickHat = 'c'|'d'|'l'|'ld'|'lu'|'r'|'rd'|'ru'|'u' 56 | type JoystickInputType = 'axis'|'button'|'hat' 57 | type KeyConstant = 'a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'i'|'j'|'k'|'l'|'m'|'n'|'o'|'p'|'q'|'r'|'s'|'t'|'u'|'v'|'w'|'x'|'y'|'z'|'0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'|'space'|'!'|'\"'|'#'|'$'|'&'|'\''|'('|')'|'*'|'+'|','|'-'|'.'|'/'|':'|';'|'<'|'='|'>'|'?'|'@'|'['|'\\'|']'|'^'|'_'|'`'|'kp0'|'kp1'|'kp2'|'kp3'|'kp4'|'kp5'|'kp6'|'kp7'|'kp8'|'kp9'|'kp.'|'kp/'|'kp*'|'kp-'|'kp+'|'kpenter'|'kp='|'up'|'down'|'right'|'left'|'home'|'end'|'pageup'|'pagedown'|'insert'|'backspace'|'tab'|'clear'|'return'|'delete'|'f1'|'f2'|'f3'|'f4'|'f5'|'f6'|'f7'|'f8'|'f9'|'f10'|'f11'|'f12'|'f13'|'f14'|'f15'|'numlock'|'capslock'|'scrollock'|'rshift'|'lshift'|'rctrl'|'lctrl'|'ralt'|'lalt'|'rmeta'|'lmeta'|'lsuper'|'rsuper'|'mode'|'compose'|'pause'|'escape'|'help'|'print'|'sysreq'|'break'|'menu'|'power'|'euro'|'undo'|'www'|'mail'|'calculator'|'appsearch'|'apphome'|'appback'|'appforward'|'apprefresh'|'appbookmarks' 58 | type Scancode = 'a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'i'|'j'|'k'|'l'|'m'|'n'|'o'|'p'|'q'|'r'|'s'|'t'|'u'|'v'|'w'|'x'|'y'|'z'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'|'0'|'return'|'escape'|'backspace'|'tab'|'space'|'-'|'='|'['|']'|'\\'|'nonus#'|';'|'\''|'`'|','|'.'|'/'|'capslock'|'f1'|'f2'|'f3'|'f4'|'f5'|'f6'|'f7'|'f8'|'f9'|'f10'|'f11'|'f12'|'f13'|'f14'|'f15'|'f16'|'f17'|'f18'|'f19'|'f20'|'f21'|'f22'|'f23'|'f24'|'lctrl'|'lshift'|'lalt'|'lgui'|'rctrl'|'rshift'|'ralt'|'rgui'|'printscreen'|'scrolllock'|'pause'|'insert'|'home'|'numlock'|'pageup'|'delete'|'end'|'pagedown'|'right'|'left'|'down'|'up'|'nonusbackslash'|'application'|'execute'|'help'|'menu'|'select'|'stop'|'again'|'undo'|'cut'|'copy'|'paste'|'find'|'kp/'|'kp*'|'kp-'|'kp+'|'kp='|'kpenter'|'kp1'|'kp2'|'kp3'|'kp4'|'kp5'|'kp6'|'kp7'|'kp8'|'kp9'|'kp0'|'kp.'|'international1'|'international2'|'international3'|'international4'|'international5'|'international6'|'international7'|'international8'|'international9'|'lang1'|'lang2'|'lang3'|'lang4'|'lang5'|'mute'|'volumeup'|'volumedown'|'audionext'|'audioprev'|'audiostop'|'audioplay'|'audiomute'|'mediaselect'|'www'|'mail'|'calculator'|'computer'|'acsearch'|'achome'|'acback'|'acforward'|'acstop'|'acrefresh'|'acbookmarks'|'power'|'brightnessdown'|'brightnessup'|'displayswitch'|'kbdillumtoggle'|'kbdillumdown'|'kbdillumup'|'eject'|'sleep'|'alterase'|'sysreq'|'cancel'|'clear'|'prior'|'return2'|'separator'|'out'|'oper'|'clearagain'|'crsel'|'exsel'|'kp00'|'kp000'|'thsousandsseparator'|'decimalseparator'|'currencyunit'|'currencysubunit'|'app1'|'app2'|'unknown' 59 | type MatrixLayout = 'row'|'column' 60 | type CursorType = 'image'|'arrow'|'ibeam'|'wait'|'waitarrow'|'crosshair'|'sizenwse'|'sizenesw'|'sizewe'|'sizens'|'sizeall'|'no'|'hand' 61 | type BodyType = 'static'|'dynamic'|'kinematic' 62 | type JointType = 'distance'|'friction'|'gear'|'mouse'|'prismatic'|'pulley'|'revolute'|'rope'|'weld' 63 | type ShapeType = 'circle'|'polygon'|'edge'|'chain' 64 | type PowerState = 'unknown'|'battery'|'nobattery'|'charging'|'charged' 65 | type DisplayOrientation = 'unknown'|'landscape'|'landscapeflipped'|'portrait'|'portraitflipped' 66 | type FullscreenType = 'desktop'|'exclusive'|'normal' 67 | type MessageBoxType = 'info'|'warning'|'error' 68 | 69 | declare class Object 70 | function release(self): (boolean) 71 | function type(self): (string) 72 | function typeOf(self,name:string): (boolean) 73 | end 74 | 75 | declare class Data extends Object 76 | function clone(self): (Data) 77 | function getFFIPointer(self): (unknown) 78 | function getPointer(self): (unknown) 79 | function getSize(self): (number) 80 | function getString(self): (string) 81 | end 82 | 83 | declare class RecordingDevice extends Object 84 | function getBitDepth(self): (number) 85 | function getChannelCount(self): (number) 86 | function getData(self): (SoundData) 87 | function getName(self): (string) 88 | function getSampleCount(self): (number) 89 | function getSampleRate(self): (number) 90 | function isRecording(self): (boolean) 91 | function start(self,samplecount:number,samplerate:number,bitdepth:number,channels:number): (boolean) 92 | function stop(self): (SoundData) 93 | end 94 | 95 | declare class Source extends Object 96 | function clone(self): (Source) 97 | function getActiveEffects(self): ({string}) 98 | function getAirAbsorption(self): (number) 99 | function getAttenuationDistances(self): (number,number) 100 | function getChannelCount(self): (number) 101 | function getCone(self): (number,number,number) 102 | function getDirection(self): (number,number,number) 103 | function getDuration(self,unit:TimeUnit): (number) 104 | function getEffect(self,name:string,filtersettings:{[any]: any}): ({volume:number,highgain:number,lowgain:number,}) 105 | function getFilter(self): ({type:FilterType,volume:number,highgain:number,lowgain:number,}) 106 | function getFreeBufferCount(self): (number) 107 | function getPitch(self): (number) 108 | function getPosition(self): (number,number,number) 109 | function getRolloff(self): (number) 110 | function getType(self): (SourceType) 111 | function getVelocity(self): (number,number,number) 112 | function getVolume(self): (number) 113 | function getVolumeLimits(self): (number,number) 114 | function isLooping(self): (boolean) 115 | function isPlaying(self): (boolean) 116 | function isRelative(self): (boolean) 117 | function pause(self): () 118 | function play(self): (boolean) 119 | function queue(self,sounddata:SoundData): (boolean) 120 | function seek(self,offset:number,unit:TimeUnit): () 121 | function setAirAbsorption(self,amount:number): () 122 | function setAttenuationDistances(self,ref:number,max:number): () 123 | function setCone(self,innerAngle:number,outerAngle:number,outerVolume:number): () 124 | function setDirection(self,x:number,y:number,z:number): () 125 | function setEffect(self,name:string,enable:boolean): (boolean) 126 | function setEffect(self,name:string,filtersettings:{type:FilterType,volume:number,highgain:number,lowgain:number,}): (boolean) 127 | function setFilter(self,settings:{type:FilterType,volume:number,highgain:number,lowgain:number,}): (boolean) 128 | function setFilter(self): () 129 | function setLooping(self,loop:boolean): () 130 | function setPitch(self,pitch:number): () 131 | function setPosition(self,x:number,y:number,z:number): () 132 | function setRelative(self,enable:boolean): () 133 | function setRolloff(self,rolloff:number): () 134 | function setVelocity(self,x:number,y:number,z:number): () 135 | function setVolume(self,volume:number): () 136 | function setVolumeLimits(self,min:number,max:number): () 137 | function stop(self): () 138 | function tell(self,unit:TimeUnit): (number) 139 | end 140 | 141 | declare class ByteData extends Object 142 | end 143 | 144 | declare class CompressedData extends Data 145 | function getFormat(self): (CompressedDataFormat) 146 | end 147 | 148 | declare class File extends Object 149 | function close(self): (boolean) 150 | function flush(self): (boolean,string) 151 | function getBuffer(self): (BufferMode,number) 152 | function getFilename(self): (string) 153 | function getMode(self): (FileMode) 154 | function getSize(self): (number) 155 | function isEOF(self): (boolean) 156 | function isOpen(self): (boolean) 157 | function lines(self): ((...any)->(...any)) 158 | function open(self,mode:FileMode): (boolean,string) 159 | function read(self,bytes:number): (string,number) 160 | function read(self,container:ContainerType,bytes:number): (FileData|string,number) 161 | function seek(self,pos:number): (boolean) 162 | function setBuffer(self,mode:BufferMode,size:number): (boolean,string) 163 | function tell(self): (number) 164 | function write(self,data:string,size:number): (boolean,string) 165 | function write(self,data:Data,size:number): (boolean,string) 166 | end 167 | 168 | declare class DroppedFile extends File 169 | end 170 | 171 | declare class FileData extends Data 172 | function getExtension(self): (string) 173 | function getFilename(self): (string) 174 | end 175 | 176 | declare class GlyphData extends Data 177 | function getAdvance(self): (number) 178 | function getBearing(self): (number,number) 179 | function getBoundingBox(self): (number,number,number,number) 180 | function getDimensions(self): (number,number) 181 | function getFormat(self): (PixelFormat) 182 | function getGlyph(self): (number) 183 | function getGlyphString(self): (string) 184 | function getHeight(self): (number) 185 | function getWidth(self): (number) 186 | end 187 | 188 | declare class Rasterizer extends Object 189 | function getAdvance(self): (number) 190 | function getAscent(self): (number) 191 | function getDescent(self): (number) 192 | function getGlyphCount(self): (number) 193 | function getGlyphData(self,glyph:string): (GlyphData) 194 | function getGlyphData(self,glyphNumber:number): (GlyphData) 195 | function getHeight(self): (number) 196 | function getLineHeight(self): (number) 197 | function hasGlyphs(self,glyph1:string|number,glyph2:string|number,...:string|number): (boolean) 198 | end 199 | 200 | declare class Drawable extends Object 201 | end 202 | 203 | declare class Texture extends Drawable 204 | function getDPIScale(self): (number) 205 | function getDepth(self): (number) 206 | function getDepthSampleMode(self): (CompareMode) 207 | function getDimensions(self): (number,number) 208 | function getFilter(self): (FilterMode,FilterMode,number) 209 | function getFormat(self): (PixelFormat) 210 | function getHeight(self): (number) 211 | function getLayerCount(self): (number) 212 | function getMipmapCount(self): (number) 213 | function getMipmapFilter(self): (FilterMode,number) 214 | function getPixelDimensions(self): (number,number) 215 | function getPixelHeight(self): (number) 216 | function getPixelWidth(self): (number) 217 | function getTextureType(self): (TextureType) 218 | function getWidth(self): (number) 219 | function getWrap(self): (WrapMode,WrapMode,WrapMode) 220 | function isReadable(self): (boolean) 221 | function setDepthSampleMode(self,compare:CompareMode): () 222 | function setFilter(self,min:FilterMode,mag:FilterMode,anisotropy:number): () 223 | function setMipmapFilter(self,filtermode:FilterMode,sharpness:number): () 224 | function setMipmapFilter(self): () 225 | function setWrap(self,horiz:WrapMode,vert:WrapMode,depth:WrapMode): () 226 | end 227 | 228 | declare class Canvas extends Texture 229 | function generateMipmaps(self): () 230 | function getMSAA(self): (number) 231 | function getMipmapMode(self): (MipmapMode) 232 | function newImageData(self): (ImageData) 233 | function newImageData(self,slice:number,mipmap:number,x:number,y:number,width:number,height:number): (ImageData) 234 | function renderTo(self,func:(...any)->(...any),...:any): () 235 | end 236 | 237 | declare class Font extends Object 238 | function getAscent(self): (number) 239 | function getBaseline(self): (number) 240 | function getDPIScale(self): (number) 241 | function getDescent(self): (number) 242 | function getFilter(self): (FilterMode,FilterMode,number) 243 | function getHeight(self): (number) 244 | function getKerning(self,leftchar:string,rightchar:string): (number) 245 | function getKerning(self,leftglyph:number,rightglyph:number): (number) 246 | function getLineHeight(self): (number) 247 | function getWidth(self,text:string): (number) 248 | function getWrap(self,text:string,wraplimit:number): (number,{string}) 249 | function hasGlyphs(self,text:string): (boolean) 250 | function hasGlyphs(self,character1:string,character2:string): (boolean) 251 | function hasGlyphs(self,codepoint1:number,codepoint2:number): (boolean) 252 | function setFallbacks(self,fallbackfont1:Font,...:Font): () 253 | function setFilter(self,min:FilterMode,mag:FilterMode,anisotropy:number): () 254 | function setLineHeight(self,height:number): () 255 | end 256 | 257 | declare class Image extends Texture 258 | function isCompressed(self): (boolean) 259 | function isFormatLinear(self): (boolean) 260 | function replacePixels(self,data:ImageData,slice:number,mipmap:number,x:number,y:number,reloadmipmaps:boolean): () 261 | end 262 | 263 | declare class Mesh extends Drawable 264 | function attachAttribute(self,name:string,mesh:Mesh): () 265 | function attachAttribute(self,name:string,mesh:Mesh,step:VertexAttributeStep,attachname:string): () 266 | function detachAttribute(self,name:string): (boolean) 267 | function flush(self): () 268 | function getDrawMode(self): (MeshDrawMode) 269 | function getDrawRange(self): (number,number) 270 | function getTexture(self): (Texture) 271 | function getVertex(self,index:number): (number,number) 272 | function getVertex(self,index:number): (number,number,number,number,number,number,number,number) 273 | function getVertexAttribute(self,vertexindex:number,attributeindex:number): (number,number,number) 274 | function getVertexCount(self): (number) 275 | function getVertexFormat(self): ({attribute:{[any]: any},}) 276 | function getVertexMap(self): ({number}) 277 | function isAttributeEnabled(self,name:string): (boolean) 278 | function setAttributeEnabled(self,name:string,enable:boolean): () 279 | function setDrawMode(self,mode:MeshDrawMode): () 280 | function setDrawRange(self,start:number,count:number): () 281 | function setDrawRange(self): () 282 | function setTexture(self,texture:Texture): () 283 | function setTexture(self): () 284 | function setVertex(self,index:number,attributecomponent:number,...:number): () 285 | function setVertex(self,index:number,vertex:{attributecomponent:number,}): () 286 | function setVertex(self,index:number,x:number,y:number,u:number,v:number,r:number,g:number,b:number,a:number): () 287 | function setVertex(self,index:number,vertex:{number?}): () 288 | function setVertexAttribute(self,vertexindex:number,attributeindex:number,value1:number,value2:number,...:number): () 289 | function setVertexMap(self,map:{[any]: any}): () 290 | function setVertexMap(self,vi1:number,vi2:number,vi3:number): () 291 | function setVertexMap(self,data:Data,datatype:IndexDataType): () 292 | function setVertices(self,vertices:{attributecomponent:number,},startvertex:number,count:number): () 293 | function setVertices(self,data:Data,startvertex:number): () 294 | function setVertices(self,vertices:{number?}): () 295 | end 296 | 297 | declare class ParticleSystem extends Drawable 298 | function clone(self): (ParticleSystem) 299 | function emit(self,numparticles:number): () 300 | function getBufferSize(self): (number) 301 | function getColors(self): (number,number,number,number,number,number,number,number,number,number,number,number) 302 | function getCount(self): (number) 303 | function getDirection(self): (number) 304 | function getEmissionArea(self): (AreaSpreadDistribution,number,number,number,boolean) 305 | function getEmissionRate(self): (number) 306 | function getEmitterLifetime(self): (number) 307 | function getInsertMode(self): (ParticleInsertMode) 308 | function getLinearAcceleration(self): (number,number,number,number) 309 | function getLinearDamping(self): (number,number) 310 | function getOffset(self): (number,number) 311 | function getParticleLifetime(self): (number,number) 312 | function getPosition(self): (number,number) 313 | function getQuads(self): ({Quad}) 314 | function getRadialAcceleration(self): (number,number) 315 | function getRotation(self): (number,number) 316 | function getSizeVariation(self): (number) 317 | function getSizes(self): (number,number,number) 318 | function getSpeed(self): (number,number) 319 | function getSpin(self): (number,number,number) 320 | function getSpinVariation(self): (number) 321 | function getSpread(self): (number) 322 | function getTangentialAcceleration(self): (number,number) 323 | function getTexture(self): (Texture) 324 | function hasRelativeRotation(self): (boolean) 325 | function isActive(self): (boolean) 326 | function isPaused(self): (boolean) 327 | function isStopped(self): (boolean) 328 | function moveTo(self,x:number,y:number): () 329 | function pause(self): () 330 | function reset(self): () 331 | function setBufferSize(self,size:number): () 332 | function setColors(self,r1:number,g1:number,b1:number,a1:number,...:number): () 333 | function setColors(self,rgba1:{number},...:{number}): () 334 | function setDirection(self,direction:number): () 335 | function setEmissionArea(self,distribution:AreaSpreadDistribution,dx:number,dy:number,angle:number,directionRelativeToCenter:boolean): () 336 | function setEmissionRate(self,rate:number): () 337 | function setEmitterLifetime(self,life:number): () 338 | function setInsertMode(self,mode:ParticleInsertMode): () 339 | function setLinearAcceleration(self,xmin:number,ymin:number,xmax:number,ymax:number): () 340 | function setLinearDamping(self,min:number,max:number): () 341 | function setOffset(self,x:number,y:number): () 342 | function setParticleLifetime(self,min:number,max:number): () 343 | function setPosition(self,x:number,y:number): () 344 | function setQuads(self,quad1:Quad,...:Quad): () 345 | function setQuads(self,quads:{Quad}): () 346 | function setRadialAcceleration(self,min:number,max:number): () 347 | function setRelativeRotation(self,enable:boolean): () 348 | function setRotation(self,min:number,max:number): () 349 | function setSizeVariation(self,variation:number): () 350 | function setSizes(self,size1:number,size2:number,size8:number): () 351 | function setSpeed(self,min:number,max:number): () 352 | function setSpin(self,min:number,max:number): () 353 | function setSpinVariation(self,variation:number): () 354 | function setSpread(self,spread:number): () 355 | function setTangentialAcceleration(self,min:number,max:number): () 356 | function setTexture(self,texture:Texture): () 357 | function start(self): () 358 | function stop(self): () 359 | function update(self,dt:number): () 360 | end 361 | 362 | declare class Quad extends Object 363 | function getTextureDimensions(self): (number,number) 364 | function getViewport(self): (number,number,number,number) 365 | function setViewport(self,x:number,y:number,w:number,h:number,sw:number,sh:number): () 366 | end 367 | 368 | declare class Shader extends Object 369 | function getWarnings(self): (string) 370 | function hasUniform(self,name:string): (boolean) 371 | function send(self,name:string,number:number,...:number): () 372 | function send(self,name:string,vector:{[any]: any},...:{[any]: any}): () 373 | function send(self,name:string,matrix:{[any]: any},...:{[any]: any}): () 374 | function send(self,name:string,texture:Texture): () 375 | function send(self,name:string,boolean:boolean,...:boolean): () 376 | function send(self,name:string,matrixlayout:MatrixLayout,matrix:{[any]: any},...:{[any]: any}): () 377 | function send(self,name:string,data:Data,offset:number,size:number): () 378 | function send(self,name:string,data:Data,matrixlayout:MatrixLayout,offset:number,size:number): () 379 | function send(self,name:string,matrixlayout:MatrixLayout,data:Data,offset:number,size:number): () 380 | function sendColor(self,name:string,color:{number},...:{number}): () 381 | end 382 | 383 | declare class SpriteBatch extends Drawable 384 | function add(self,x:number,y:number,r:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number): (number) 385 | function add(self,quad:Quad,x:number,y:number,r:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number): (number) 386 | function addLayer(self,layerindex:number,x:number,y:number,r:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number): (number) 387 | function addLayer(self,layerindex:number,quad:Quad,x:number,y:number,r:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number): (number) 388 | function addLayer(self,layerindex:number,transform:Transform): (number) 389 | function addLayer(self,layerindex:number,quad:Quad,transform:Transform): (number) 390 | function attachAttribute(self,name:string,mesh:Mesh): () 391 | function clear(self): () 392 | function flush(self): () 393 | function getBufferSize(self): (number) 394 | function getColor(self): (number,number,number,number) 395 | function getCount(self): (number) 396 | function getTexture(self): (Texture) 397 | function set(self,spriteindex:number,x:number,y:number,r:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number): () 398 | function set(self,spriteindex:number,quad:Quad,x:number,y:number,r:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number): () 399 | function setColor(self,r:number,g:number,b:number,a:number): () 400 | function setColor(self): () 401 | function setDrawRange(self,start:number,count:number): () 402 | function setDrawRange(self): () 403 | function setLayer(self,spriteindex:number,layerindex:number,x:number,y:number,r:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number): () 404 | function setLayer(self,spriteindex:number,layerindex:number,quad:Quad,x:number,y:number,r:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number): () 405 | function setLayer(self,spriteindex:number,layerindex:number,transform:Transform): () 406 | function setLayer(self,spriteindex:number,layerindex:number,quad:Quad,transform:Transform): () 407 | function setTexture(self,texture:Texture): () 408 | end 409 | 410 | declare class Text extends Drawable 411 | function add(self,textstring:string,x:number,y:number,angle:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number): (number) 412 | function add(self,coloredtext:{color1:{[any]: any},string1:string,color2:{[any]: any},string2:string,},x:number,y:number,angle:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number): (number) 413 | function addf(self,textstring:string,wraplimit:number,align:AlignMode,x:number,y:number,angle:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number): (number) 414 | function addf(self,coloredtext:{color1:{[any]: any},string1:string,color2:{[any]: any},string2:string,},wraplimit:number,align:AlignMode,x:number,y:number,angle:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number): (number) 415 | function clear(self): () 416 | function getDimensions(self): (number,number) 417 | function getDimensions(self,index:number): (number,number) 418 | function getFont(self): (Font) 419 | function getHeight(self): (number) 420 | function getHeight(self,index:number): (number) 421 | function getWidth(self): (number) 422 | function getWidth(self,index:number): (number) 423 | function set(self,textstring:string): () 424 | function set(self,coloredtext:{color1:{[any]: any},string1:string,color2:{[any]: any},string2:string,}): () 425 | function setFont(self,font:Font): () 426 | function setf(self,textstring:string,wraplimit:number,align:AlignMode): () 427 | function setf(self,coloredtext:{color1:{[any]: any},string1:string,color2:{[any]: any},string2:string,},wraplimit:number,align:AlignMode): () 428 | end 429 | 430 | declare class Video extends Drawable 431 | function getDimensions(self): (number,number) 432 | function getFilter(self): (FilterMode,FilterMode,number) 433 | function getHeight(self): (number) 434 | function getSource(self): (Source) 435 | function getStream(self): (VideoStream) 436 | function getWidth(self): (number) 437 | function isPlaying(self): (boolean) 438 | function pause(self): () 439 | function play(self): () 440 | function rewind(self): () 441 | function seek(self,offset:number): () 442 | function setFilter(self,min:FilterMode,mag:FilterMode,anisotropy:number): () 443 | function setSource(self,source:Source): () 444 | function tell(self): (number) 445 | end 446 | 447 | declare class CompressedImageData extends Data 448 | function getDimensions(self): (number,number) 449 | function getDimensions(self,level:number): (number,number) 450 | function getFormat(self): (CompressedImageFormat) 451 | function getHeight(self): (number) 452 | function getHeight(self,level:number): (number) 453 | function getMipmapCount(self): (number) 454 | function getWidth(self): (number) 455 | function getWidth(self,level:number): (number) 456 | end 457 | 458 | declare class ImageData extends Data 459 | function encode(self,format:ImageFormat,filename:string): (FileData) 460 | function encode(self,outFile:string): () 461 | function encode(self,outFile:string,format:ImageFormat): () 462 | function getDimensions(self): (number,number) 463 | function getHeight(self): (number) 464 | function getPixel(self,x:number,y:number): (number,number,number,number) 465 | function getWidth(self): (number) 466 | function mapPixel(self,pixelFunction:(...any)->(...any),x:number,y:number,width:number,height:number): () 467 | function paste(self,source:ImageData,dx:number,dy:number,sx:number,sy:number,sw:number,sh:number): () 468 | function setPixel(self,x:number,y:number,r:number,g:number,b:number,a:number): () 469 | function setPixel(self,x:number,y:number,color:{number}): () 470 | function getFormat(self): (PixelFormat) 471 | end 472 | 473 | declare class Joystick extends Object 474 | function getAxes(self): (number,number,number) 475 | function getAxis(self,axis:number): (number) 476 | function getAxisCount(self): (number) 477 | function getButtonCount(self): (number) 478 | function getDeviceInfo(self): (number,number,number) 479 | function getGUID(self): (string) 480 | function getGamepadAxis(self,axis:GamepadAxis): (number) 481 | function getGamepadMapping(self,axis:GamepadAxis): (JoystickInputType,number,JoystickHat) 482 | function getGamepadMapping(self,button:GamepadButton): (JoystickInputType,number,JoystickHat) 483 | function getGamepadMappingString(self): (string) 484 | function getHat(self,hat:number): (JoystickHat) 485 | function getHatCount(self): (number) 486 | function getID(self): (number,number) 487 | function getName(self): (string) 488 | function getVibration(self): (number,number) 489 | function isConnected(self): (boolean) 490 | function isDown(self,buttonN:number): (boolean) 491 | function isGamepad(self): (boolean) 492 | function isGamepadDown(self,buttonN:GamepadButton): (boolean) 493 | function isVibrationSupported(self): (boolean) 494 | function setVibration(self,left:number,right:number): (boolean) 495 | function setVibration(self): (boolean) 496 | function setVibration(self,left:number,right:number,duration:number): (boolean) 497 | end 498 | 499 | declare class BezierCurve extends Object 500 | function evaluate(self,t:number): (number,number) 501 | function getControlPoint(self,i:number): (number,number) 502 | function getControlPointCount(self): (number) 503 | function getDegree(self): (number) 504 | function getDerivative(self): (BezierCurve) 505 | function getSegment(self,startpoint:number,endpoint:number): (BezierCurve) 506 | function insertControlPoint(self,x:number,y:number,i:number): () 507 | function removeControlPoint(self,index:number): () 508 | function render(self,depth:number): ({number}) 509 | function renderSegment(self,startpoint:number,endpoint:number,depth:number): ({number}) 510 | function rotate(self,angle:number,ox:number,oy:number): () 511 | function scale(self,s:number,ox:number,oy:number): () 512 | function setControlPoint(self,i:number,x:number,y:number): () 513 | function translate(self,dx:number,dy:number): () 514 | end 515 | 516 | declare class RandomGenerator extends Object 517 | function getSeed(self): (number,number) 518 | function getState(self): (string) 519 | function random(self): (number) 520 | function random(self,max:number): (number) 521 | function random(self,min:number,max:number): (number) 522 | function randomNormal(self,stddev:number,mean:number): (number) 523 | function setSeed(self,seed:number): () 524 | function setSeed(self,low:number,high:number): () 525 | function setState(self,state:string): () 526 | end 527 | 528 | declare class Transform extends Object 529 | function apply(self,other:Transform): (Transform) 530 | function clone(self): (Transform) 531 | function getMatrix(self): (number,number,number,number,number,number,number,number,number,number,number,number,number,number,number,number) 532 | function inverse(self): (Transform) 533 | function inverseTransformPoint(self,localX:number,localY:number): (number,number) 534 | function isAffine2DTransform(self): (boolean) 535 | function reset(self): (Transform) 536 | function rotate(self,angle:number): (Transform) 537 | function scale(self,sx:number,sy:number): (Transform) 538 | function setMatrix(self,e1_1:number,e1_2:number,e1_3:number,e1_4:number,e2_1:number,e2_2:number,e2_3:number,e2_4:number,e3_1:number,e3_2:number,e3_3:number,e3_4:number,e4_1:number,e4_2:number,e4_3:number,e4_4:number): (Transform) 539 | function setMatrix(self,layout:MatrixLayout,e1_1:number,e1_2:number,e1_3:number,e1_4:number,e2_1:number,e2_2:number,e2_3:number,e2_4:number,e3_1:number,e3_2:number,e3_3:number,e3_4:number,e4_1:number,e4_2:number,e4_3:number,e4_4:number): (Transform) 540 | function setMatrix(self,layout:MatrixLayout,matrix:{number}): (Transform) 541 | function setMatrix(self,layout:MatrixLayout,matrix:{[any]: any}): (Transform) 542 | function setTransformation(self,x:number,y:number,angle:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number): (Transform) 543 | function shear(self,kx:number,ky:number): (Transform) 544 | function transformPoint(self,globalX:number,globalY:number): (number,number) 545 | function translate(self,dx:number,dy:number): (Transform) 546 | end 547 | 548 | declare class Cursor extends Object 549 | function getType(self): (CursorType) 550 | end 551 | 552 | declare class Body extends Object 553 | function applyAngularImpulse(self,impulse:number): () 554 | function applyForce(self,fx:number,fy:number): () 555 | function applyForce(self,fx:number,fy:number,x:number,y:number): () 556 | function applyLinearImpulse(self,ix:number,iy:number): () 557 | function applyLinearImpulse(self,ix:number,iy:number,x:number,y:number): () 558 | function applyTorque(self,torque:number): () 559 | function destroy(self): () 560 | function getAngle(self): (number) 561 | function getAngularDamping(self): (number) 562 | function getAngularVelocity(self): (number) 563 | function getContacts(self): ({Contact}) 564 | function getFixtures(self): ({Fixture}) 565 | function getGravityScale(self): (number) 566 | function getInertia(self): (number) 567 | function getJoints(self): ({Joint}) 568 | function getLinearDamping(self): (number) 569 | function getLinearVelocity(self): (number,number) 570 | function getLinearVelocityFromLocalPoint(self,x:number,y:number): (number,number) 571 | function getLinearVelocityFromWorldPoint(self,x:number,y:number): (number,number) 572 | function getLocalCenter(self): (number,number) 573 | function getLocalPoint(self,worldX:number,worldY:number): (number,number) 574 | function getLocalPoints(self,x1:number,y1:number,x2:number,y2:number,...:number): (number,number,number,number,number) 575 | function getLocalVector(self,worldX:number,worldY:number): (number,number) 576 | function getMass(self): (number) 577 | function getMassData(self): (number,number,number,number) 578 | function getPosition(self): (number,number) 579 | function getTransform(self): (number,number,number) 580 | function getType(self): (BodyType) 581 | function getUserData(self): (any) 582 | function getWorld(self): (World) 583 | function getWorldCenter(self): (number,number) 584 | function getWorldPoint(self,localX:number,localY:number): (number,number) 585 | function getWorldPoints(self,x1:number,y1:number,x2:number,y2:number): (number,number,number,number) 586 | function getWorldVector(self,localX:number,localY:number): (number,number) 587 | function getX(self): (number) 588 | function getY(self): (number) 589 | function isActive(self): (boolean) 590 | function isAwake(self): (boolean) 591 | function isBullet(self): (boolean) 592 | function isDestroyed(self): (boolean) 593 | function isFixedRotation(self): (boolean) 594 | function isSleepingAllowed(self): (boolean) 595 | function isTouching(self,otherbody:Body): (boolean) 596 | function resetMassData(self): () 597 | function setActive(self,active:boolean): () 598 | function setAngle(self,angle:number): () 599 | function setAngularDamping(self,damping:number): () 600 | function setAngularVelocity(self,w:number): () 601 | function setAwake(self,awake:boolean): () 602 | function setBullet(self,status:boolean): () 603 | function setFixedRotation(self,isFixed:boolean): () 604 | function setGravityScale(self,scale:number): () 605 | function setInertia(self,inertia:number): () 606 | function setLinearDamping(self,ld:number): () 607 | function setLinearVelocity(self,x:number,y:number): () 608 | function setMass(self,mass:number): () 609 | function setMassData(self,x:number,y:number,mass:number,inertia:number): () 610 | function setPosition(self,x:number,y:number): () 611 | function setSleepingAllowed(self,allowed:boolean): () 612 | function setTransform(self,x:number,y:number,angle:number): () 613 | function setType(self,type:BodyType): () 614 | function setUserData(self,value:any): () 615 | function setX(self,x:number): () 616 | function setY(self,y:number): () 617 | end 618 | 619 | declare class Shape extends Object 620 | function computeAABB(self,tx:number,ty:number,tr:number,childIndex:number): (number,number,number,number) 621 | function computeMass(self,density:number): (number,number,number,number) 622 | function getChildCount(self): (number) 623 | function getRadius(self): (number) 624 | function getType(self): (ShapeType) 625 | function rayCast(self,x1:number,y1:number,x2:number,y2:number,maxFraction:number,tx:number,ty:number,tr:number,childIndex:number): (number,number,number) 626 | function testPoint(self,tx:number,ty:number,tr:number,x:number,y:number): (boolean) 627 | end 628 | 629 | declare class ChainShape extends Shape 630 | function getChildEdge(self,index:number): (EdgeShape) 631 | function getNextVertex(self): (number,number) 632 | function getPoint(self,index:number): (number,number) 633 | function getPoints(self): (number,number,number,number) 634 | function getPreviousVertex(self): (number,number) 635 | function getVertexCount(self): (number) 636 | function setNextVertex(self,x:number,y:number): () 637 | function setPreviousVertex(self,x:number,y:number): () 638 | end 639 | 640 | declare class CircleShape extends Shape 641 | function getPoint(self): (number,number) 642 | function getRadius(self): (number) 643 | function setPoint(self,x:number,y:number): () 644 | function setRadius(self,radius:number): () 645 | end 646 | 647 | declare class Contact extends Object 648 | function getChildren(self): (number,number) 649 | function getFixtures(self): (Fixture,Fixture) 650 | function getFriction(self): (number) 651 | function getNormal(self): (number,number) 652 | function getPositions(self): (number,number,number,number) 653 | function getRestitution(self): (number) 654 | function isEnabled(self): (boolean) 655 | function isTouching(self): (boolean) 656 | function resetFriction(self): () 657 | function resetRestitution(self): () 658 | function setEnabled(self,enabled:boolean): () 659 | function setFriction(self,friction:number): () 660 | function setRestitution(self,restitution:number): () 661 | end 662 | 663 | declare class Joint extends Object 664 | function destroy(self): () 665 | function getAnchors(self): (number,number,number,number) 666 | function getBodies(self): (Body,Body) 667 | function getCollideConnected(self): (boolean) 668 | function getReactionForce(self,x:number): (number,number) 669 | function getReactionTorque(self,invdt:number): (number) 670 | function getType(self): (JointType) 671 | function getUserData(self): (any) 672 | function isDestroyed(self): (boolean) 673 | function setUserData(self,value:any): () 674 | end 675 | 676 | declare class DistanceJoint extends Joint 677 | function getDampingRatio(self): (number) 678 | function getFrequency(self): (number) 679 | function getLength(self): (number) 680 | function setDampingRatio(self,ratio:number): () 681 | function setFrequency(self,Hz:number): () 682 | function setLength(self,l:number): () 683 | end 684 | 685 | declare class EdgeShape extends Shape 686 | function getNextVertex(self): (number,number) 687 | function getPoints(self): (number,number,number,number) 688 | function getPreviousVertex(self): (number,number) 689 | function setNextVertex(self,x:number,y:number): () 690 | function setPreviousVertex(self,x:number,y:number): () 691 | end 692 | 693 | declare class Fixture extends Object 694 | function destroy(self): () 695 | function getBody(self): (Body) 696 | function getBoundingBox(self,index:number): (number,number,number,number) 697 | function getCategory(self): (number) 698 | function getDensity(self): (number) 699 | function getFilterData(self): (number,number,number) 700 | function getFriction(self): (number) 701 | function getGroupIndex(self): (number) 702 | function getMask(self): (number) 703 | function getMassData(self): (number,number,number,number) 704 | function getRestitution(self): (number) 705 | function getShape(self): (Shape) 706 | function getUserData(self): (any) 707 | function isDestroyed(self): (boolean) 708 | function isSensor(self): (boolean) 709 | function rayCast(self,x1:number,y1:number,x2:number,y2:number,maxFraction:number,childIndex:number): (number,number,number) 710 | function setCategory(self,...:number): () 711 | function setDensity(self,density:number): () 712 | function setFilterData(self,categories:number,mask:number,group:number): () 713 | function setFriction(self,friction:number): () 714 | function setGroupIndex(self,group:number): () 715 | function setMask(self,...:number): () 716 | function setRestitution(self,restitution:number): () 717 | function setSensor(self,sensor:boolean): () 718 | function setUserData(self,value:any): () 719 | function testPoint(self,x:number,y:number): (boolean) 720 | end 721 | 722 | declare class FrictionJoint extends Joint 723 | function getMaxForce(self): (number) 724 | function getMaxTorque(self): (number) 725 | function setMaxForce(self,maxForce:number): () 726 | function setMaxTorque(self,torque:number): () 727 | end 728 | 729 | declare class GearJoint extends Joint 730 | function getJoints(self): (Joint,Joint) 731 | function getRatio(self): (number) 732 | function setRatio(self,ratio:number): () 733 | end 734 | 735 | declare class MotorJoint extends Joint 736 | function getAngularOffset(self): (number) 737 | function getLinearOffset(self): (number,number) 738 | function setAngularOffset(self,angleoffset:number): () 739 | function setLinearOffset(self,x:number,y:number): () 740 | end 741 | 742 | declare class MouseJoint extends Joint 743 | function getDampingRatio(self): (number) 744 | function getFrequency(self): (number) 745 | function getMaxForce(self): (number) 746 | function getTarget(self): (number,number) 747 | function setDampingRatio(self,ratio:number): () 748 | function setFrequency(self,freq:number): () 749 | function setMaxForce(self,f:number): () 750 | function setTarget(self,x:number,y:number): () 751 | end 752 | 753 | declare class PolygonShape extends Shape 754 | function getPoints(self): (number,number,number,number) 755 | end 756 | 757 | declare class PrismaticJoint extends Joint 758 | function areLimitsEnabled(self): (boolean) 759 | function getAxis(self): (number,number) 760 | function getJointSpeed(self): (number) 761 | function getJointTranslation(self): (number) 762 | function getLimits(self): (number,number) 763 | function getLowerLimit(self): (number) 764 | function getMaxMotorForce(self): (number) 765 | function getMotorForce(self,invdt:number): (number) 766 | function getMotorSpeed(self): (number) 767 | function getReferenceAngle(self): (number) 768 | function getUpperLimit(self): (number) 769 | function isMotorEnabled(self): (boolean) 770 | function setLimits(self,lower:number,upper:number): () 771 | function setLimitsEnabled(self): (boolean) 772 | function setLowerLimit(self,lower:number): () 773 | function setMaxMotorForce(self,f:number): () 774 | function setMotorEnabled(self,enable:boolean): () 775 | function setMotorSpeed(self,s:number): () 776 | function setUpperLimit(self,upper:number): () 777 | end 778 | 779 | declare class PulleyJoint extends Joint 780 | function getConstant(self): (number) 781 | function getGroundAnchors(self): (number,number,number,number) 782 | function getLengthA(self): (number) 783 | function getLengthB(self): (number) 784 | function getMaxLengths(self): (number,number) 785 | function getRatio(self): (number) 786 | function setConstant(self,length:number): () 787 | function setMaxLengths(self,max1:number,max2:number): () 788 | function setRatio(self,ratio:number): () 789 | end 790 | 791 | declare class RevoluteJoint extends Joint 792 | function areLimitsEnabled(self): (boolean) 793 | function getJointAngle(self): (number) 794 | function getJointSpeed(self): (number) 795 | function getLimits(self): (number,number) 796 | function getLowerLimit(self): (number) 797 | function getMaxMotorTorque(self): (number) 798 | function getMotorSpeed(self): (number) 799 | function getMotorTorque(self): (number) 800 | function getReferenceAngle(self): (number) 801 | function getUpperLimit(self): (number) 802 | function hasLimitsEnabled(self): (boolean) 803 | function isMotorEnabled(self): (boolean) 804 | function setLimits(self,lower:number,upper:number): () 805 | function setLimitsEnabled(self,enable:boolean): () 806 | function setLowerLimit(self,lower:number): () 807 | function setMaxMotorTorque(self,f:number): () 808 | function setMotorEnabled(self,enable:boolean): () 809 | function setMotorSpeed(self,s:number): () 810 | function setUpperLimit(self,upper:number): () 811 | end 812 | 813 | declare class RopeJoint extends Joint 814 | function getMaxLength(self): (number) 815 | function setMaxLength(self,maxLength:number): () 816 | end 817 | 818 | declare class WeldJoint extends Joint 819 | function getDampingRatio(self): (number) 820 | function getFrequency(self): (number) 821 | function getReferenceAngle(self): (number) 822 | function setDampingRatio(self,ratio:number): () 823 | function setFrequency(self,freq:number): () 824 | end 825 | 826 | declare class WheelJoint extends Joint 827 | function getAxis(self): (number,number) 828 | function getJointSpeed(self): (number) 829 | function getJointTranslation(self): (number) 830 | function getMaxMotorTorque(self): (number) 831 | function getMotorSpeed(self): (number) 832 | function getMotorTorque(self,invdt:number): (number) 833 | function getSpringDampingRatio(self): (number) 834 | function getSpringFrequency(self): (number) 835 | function isMotorEnabled(self): (boolean) 836 | function setMaxMotorTorque(self,maxTorque:number): () 837 | function setMotorEnabled(self,enable:boolean): () 838 | function setMotorSpeed(self,speed:number): () 839 | function setSpringDampingRatio(self,ratio:number): () 840 | function setSpringFrequency(self,freq:number): () 841 | end 842 | 843 | declare class World extends Object 844 | function destroy(self): () 845 | function getBodies(self): ({Body}) 846 | function getBodyCount(self): (number) 847 | function getCallbacks(self): ((...any)->(...any),(...any)->(...any),(...any)->(...any),(...any)->(...any)) 848 | function getContactCount(self): (number) 849 | function getContactFilter(self): ((...any)->(...any)) 850 | function getContacts(self): ({Contact}) 851 | function getGravity(self): (number,number) 852 | function getJointCount(self): (number) 853 | function getJoints(self): ({Joint}) 854 | function isDestroyed(self): (boolean) 855 | function isLocked(self): (boolean) 856 | function isSleepingAllowed(self): (boolean) 857 | function queryBoundingBox(self,topLeftX:number,topLeftY:number,bottomRightX:number,bottomRightY:number,callback:(...any)->(...any)): () 858 | function rayCast(self,x1:number,y1:number,x2:number,y2:number,callback:(...any)->(...any)): () 859 | function setCallbacks(self,beginContact:(...any)->(...any),endContact:(...any)->(...any),preSolve:(...any)->(...any),postSolve:(...any)->(...any)): () 860 | function setContactFilter(self,filter:(...any)->(...any)): () 861 | function setGravity(self,x:number,y:number): () 862 | function setSleepingAllowed(self,allow:boolean): () 863 | function translateOrigin(self,x:number,y:number): () 864 | function update(self,dt:number,velocityiterations:number,positioniterations:number): () 865 | end 866 | 867 | declare class SoundData extends Data 868 | function getBitDepth(self): (number) 869 | function getChannelCount(self): (number) 870 | function getDuration(self): (number) 871 | function getSample(self,i:number): (number) 872 | function getSample(self,i:number,channel:number): (number) 873 | function getSampleCount(self): (number) 874 | function getSampleRate(self): (number) 875 | function setSample(self,i:number,sample:number): () 876 | function setSample(self,i:number,channel:number,sample:number): () 877 | end 878 | 879 | declare class Decoder extends Object 880 | function clone(self): (Decoder) 881 | function decode(self): (SoundData) 882 | function getBitDepth(self): (number) 883 | function getChannelCount(self): (number) 884 | function getDuration(self): (number) 885 | function getSampleRate(self): (number) 886 | function seek(self,offset:number): () 887 | end 888 | 889 | 890 | 891 | declare class Channel extends Object 892 | function clear(self): () 893 | function demand(self): (Variant) 894 | function demand(self,timeout:number): (Variant) 895 | function getCount(self): (number) 896 | function hasRead(self,id:number): (boolean) 897 | function peek(self): (Variant) 898 | function performAtomic(self,func:(...any)->(...any),...:any): (any,any) 899 | function pop(self): (Variant) 900 | function push(self,value:Variant): (number) 901 | function supply(self,value:Variant): (boolean) 902 | function supply(self,value:Variant,timeout:number): (boolean) 903 | end 904 | 905 | declare class Thread extends Object 906 | function getError(self): (string) 907 | function isRunning(self): (boolean) 908 | function start(self): () 909 | function start(self,...:Variant): () 910 | function wait(self): () 911 | end 912 | 913 | declare class VideoStream extends Object 914 | function getFilename(self): (string) 915 | function isPlaying(self): (boolean) 916 | function pause(self): () 917 | function play(self): () 918 | function rewind(self): () 919 | function seek(self,offset:number): () 920 | function tell(self): (number) 921 | end 922 | 923 | type getModeReturn = { 924 | fullscreen:boolean, 925 | display:number, 926 | minwidth:number, 927 | minheight:number, 928 | highdpi:boolean, 929 | refreshrate:number, 930 | x:number, 931 | y:number, 932 | srgb:boolean, 933 | fullscreentype:'desktop'|'exclusive'|'normal', 934 | vsync:boolean, 935 | msaa:number, 936 | resizable:boolean, 937 | borderless:boolean, 938 | centered:boolean, 939 | } 940 | 941 | declare love: { 942 | getVersion: () -> (number,number,number,string), 943 | hasDeprecationOutput: () -> (boolean), 944 | isVersionCompatible: (version:string) -> (boolean), 945 | isVersionCompatible: (major:number,minor:number,revision:number) -> (boolean), 946 | setDeprecationOutput: (enable:boolean) -> (), 947 | conf: (t:{identity:string?,appendidentity:boolean?,version:string?,console:boolean?,accelerometerjoystick:boolean?,externalstorage:boolean?,gammacorrect:boolean?,audio:{mic:boolean?,mixwithsystem:boolean?,},window:{title:string?,icon:string?,width:number?,height:number?,borderless:boolean?,resizable:boolean?,minwidth:number?,minheight:number?,fullscreen:boolean?,fullscreentype:string?,usedpiscale:boolean?,vsync:number?,depth:number?,stencil:number?,msaa:number?,display:number?,highdpi:boolean?,x:number?,y:number?,},modules:{audio:boolean?,event:boolean?,graphics:boolean?,image:boolean?,joystick:boolean?,keyboard:boolean?,math:boolean?,mouse:boolean?,physics:boolean?,sound:boolean?,system:boolean?,timer:boolean?,touch:boolean?,video:boolean?,window:boolean?,thread:boolean?,},}) -> (), 948 | directorydropped: (path:string) -> (), 949 | displayrotated: (index:number,orientation:DisplayOrientation) -> (), 950 | draw: () -> (), 951 | errorhandler: (msg:string) -> ((...any)->(...any)), 952 | filedropped: (file:DroppedFile) -> (), 953 | focus: (focus:boolean) -> (), 954 | gamepadaxis: (joystick:Joystick,axis:GamepadAxis,value:number) -> (), 955 | gamepadpressed: (joystick:Joystick,button:GamepadButton) -> (), 956 | gamepadreleased: (joystick:Joystick,button:GamepadButton) -> (), 957 | joystickadded: (joystick:Joystick) -> (), 958 | joystickaxis: (joystick:Joystick,axis:number,value:number) -> (), 959 | joystickhat: (joystick:Joystick,hat:number,direction:JoystickHat) -> (), 960 | joystickpressed: (joystick:Joystick,button:number) -> (), 961 | joystickreleased: (joystick:Joystick,button:number) -> (), 962 | joystickremoved: (joystick:Joystick) -> (), 963 | keypressed: (key:KeyConstant,scancode:Scancode,isrepeat:boolean) -> (), 964 | keypressed: (key:KeyConstant,isrepeat:boolean) -> (), 965 | keyreleased: (key:KeyConstant,scancode:Scancode) -> (), 966 | load: (arg:{[any]: any},unfilteredArg:{[any]: any}) -> (), 967 | lowmemory: () -> (), 968 | mousefocus: (focus:boolean) -> (), 969 | mousemoved: (x:number,y:number,dx:number,dy:number,istouch:boolean) -> (), 970 | mousepressed: (x:number,y:number,button:number,istouch:boolean,presses:number) -> (), 971 | mousereleased: (x:number,y:number,button:number,istouch:boolean,presses:number) -> (), 972 | quit: () -> (boolean), 973 | resize: (w:number,h:number) -> (), 974 | run: () -> ((...any)->(...any)), 975 | textedited: (text:string,start:number,length:number) -> (), 976 | textinput: (text:string) -> (), 977 | threaderror: (thread:Thread,errorstr:string) -> (), 978 | touchmoved: (id:unknown,x:number,y:number,dx:number,dy:number,pressure:number) -> (), 979 | touchpressed: (id:unknown,x:number,y:number,dx:number,dy:number,pressure:number) -> (), 980 | touchreleased: (id:unknown,x:number,y:number,dx:number,dy:number,pressure:number) -> (), 981 | update: (dt:number) -> (), 982 | visible: (visible:boolean) -> (), 983 | wheelmoved: (x:number,y:number) -> (), 984 | } & { 985 | audio: { 986 | getActiveEffects: (() -> ({string})), 987 | getActiveSourceCount: (() -> (number)), 988 | getDistanceModel: (() -> (DistanceModel)), 989 | getDopplerScale: (() -> (number)), 990 | getEffect: ((name:string) -> ({[any]: any})), 991 | getMaxSceneEffects: (() -> (number)), 992 | getMaxSourceEffects: (() -> (number)), 993 | getOrientation: (() -> (number,number,number,number,number,number)), 994 | getPosition: (() -> (number,number,number)), 995 | getRecordingDevices: (() -> ({RecordingDevice})), 996 | getVelocity: (() -> (number,number,number)), 997 | getVolume: (() -> (number)), 998 | isEffectsSupported: (() -> (boolean)), 999 | newQueueableSource: ((samplerate:number,bitdepth:number,channels:number,buffercount:number) -> (Source)), 1000 | newSource: ((filename:string,type:SourceType) -> (Source))&((file:File,type:SourceType) -> (Source))&((decoder:Decoder,type:SourceType) -> (Source))&((data:FileData,type:SourceType) -> (Source))&((data:SoundData) -> (Source)), 1001 | pause: (() -> ({Source}))&((source:Source,...Source) -> ())&((sources:{Source}) -> ()), 1002 | play: ((source:Source) -> ())&((sources:{Source}) -> ())&((source1:Source,source2:Source,...Source) -> ()), 1003 | setDistanceModel: ((model:DistanceModel) -> ()), 1004 | setDopplerScale: ((scale:number) -> ()), 1005 | setEffect: ((name:string,settings:{type:EffectType,volume:number}?) -> (boolean))&((name:string,enabled:boolean) -> (boolean)), 1006 | setMixWithSystem: ((mix:boolean) -> (boolean)), 1007 | setOrientation: ((fx:number, fy:number, fz:number, ux:number, uy:number, uz:number) -> ()), 1008 | setPosition: ((x:number,y:number,z:number) -> ()), 1009 | setVelocity: ((x:number,y:number,z:number) -> ()), 1010 | setVolume: ((volume:number) -> ()), 1011 | stop: (() -> ())&((source:Source) -> ())&((source1:Source,source2:Source,...Source) -> ())&((sources:{Source}) -> ()), 1012 | }, 1013 | } & { 1014 | data: { 1015 | compress: ((container:ContainerType,format:CompressedDataFormat,rawstring:string,level:number) -> (CompressedData|string))&((container:ContainerType,format:CompressedDataFormat,data:Data,level:number) -> (CompressedData|string)), 1016 | decode: ((container:ContainerType,format:EncodeFormat,sourceString:string) -> (ByteData|string))&((container:ContainerType,format:EncodeFormat,sourceData:Data) -> (ByteData|string)), 1017 | decompress: ((container:ContainerType,compressedData:CompressedData) -> (Data|string))&((container:ContainerType,format:CompressedDataFormat,compressedString:string) -> (Data|string))&((container:ContainerType,format:CompressedDataFormat,data:Data) -> (Data|string)), 1018 | encode: ((container:ContainerType,format:EncodeFormat,sourceString:string,linelength:number) -> (ByteData|string))&((container:ContainerType,format:EncodeFormat,sourceData:Data,linelength:number) -> (ByteData|string)), 1019 | getPackedSize: ((format:string) -> (number)), 1020 | hash: ((hashFunction:HashFunction,string:string) -> (string))&((hashFunction:HashFunction,data:Data) -> (string)), 1021 | newByteData: ((datastring:string) -> (ByteData))&((Data:Data,offset:number,size:number) -> (ByteData))&((size:number) -> (ByteData)), 1022 | newDataView: ((data:Data,offset:number,size:number) -> (Data)), 1023 | pack: ((container:ContainerType,format:string,v1:number|boolean|string,...number|boolean|string) -> (Data|string)), 1024 | unpack: ((format:string,datastring:string,pos:number) -> (number|boolean|string,...number|boolean|string))&((format:string,data:Data,pos:number) -> (number|boolean|string,...number|boolean|string)), 1025 | }, 1026 | } & { 1027 | event: { 1028 | clear: (() -> ()), 1029 | poll: (() -> ((...any)->(...any))), 1030 | pump: (() -> ()), 1031 | push: ((n:Event,a:Variant,b:Variant,c:Variant,d:Variant,e:Variant,f:Variant,...Variant) -> ()), 1032 | quit: ((exitstatus:number) -> ())&(('restart'|nil) -> ()), 1033 | wait: (() -> (Event,Variant,Variant,Variant,Variant,Variant,Variant,...Variant)), 1034 | }, 1035 | filesystem: { 1036 | append: ((name:string,data:string,size:number) -> (boolean,string))&((name:string,data:Data,size:number) -> (boolean,string)), 1037 | areSymlinksEnabled: (() -> (boolean)), 1038 | createDirectory: ((name:string) -> (boolean)), 1039 | getAppdataDirectory: (() -> (string)), 1040 | getCRequirePath: (() -> (string)), 1041 | getDirectoryItems: ((dir:string) -> ({string}))&((dir:string,callback:(...any)->(...any)) -> ({[any]: any})), 1042 | getIdentity: (() -> (string)), 1043 | getInfo: ((path:string,filtertype:FileType) -> ({type:FileType,size:number,modtime:number,}))&((path:string,info:{[any]: any}) -> ({type:FileType,size:number,modtime:number,}))&((path:string,filtertype:FileType,info:{[any]: any}) -> ({type:FileType,size:number,modtime:number,})), 1044 | getRealDirectory: ((filepath:string) -> (string)), 1045 | getRequirePath: (() -> (string)), 1046 | getSaveDirectory: (() -> (string)), 1047 | getSource: (() -> (string)), 1048 | getSourceBaseDirectory: (() -> (string)), 1049 | getUserDirectory: (() -> (string)), 1050 | getWorkingDirectory: (() -> (string)), 1051 | init: ((appname:string) -> ()), 1052 | isFused: (() -> (boolean)), 1053 | lines: ((name:string) -> ((...any)->(...any))), 1054 | load: ((name:string) -> ((...any)->(...any),string)), 1055 | mount: ((archive:string,mountpoint:string,appendToPath:boolean) -> (boolean))&((filedata:FileData,mountpoint:string,appendToPath:boolean) -> (boolean))&((data:Data,archivename:string,mountpoint:string,appendToPath:boolean) -> (boolean)), 1056 | newFile: ((filename:string) -> (File))&((filename:string,mode:FileMode) -> (File,string)), 1057 | newFileData: ((contents:string,name:string) -> (FileData))&((originaldata:Data,name:string) -> (FileData))&((filepath:string) -> (FileData,string)), 1058 | read: ((name:string,size:number) -> (string,number,nil,string))&((container:ContainerType,name:string,size:number) -> (FileData|string,number,nil,string)), 1059 | remove: ((name:string) -> (boolean)), 1060 | setCRequirePath: ((paths:string) -> ()), 1061 | setIdentity: ((name:string) -> ())&((name:string) -> ()), 1062 | setRequirePath: ((paths:string) -> ()), 1063 | setSource: ((path:string) -> ()), 1064 | setSymlinksEnabled: ((enable:boolean) -> ()), 1065 | unmount: ((archive:string) -> (boolean)), 1066 | write: ((name:string,data:string,size:number) -> (boolean,string))&((name:string,data:Data,size:number) -> (boolean,string)), 1067 | }, 1068 | } & { 1069 | font: { 1070 | newBMFontRasterizer: ((imageData:ImageData,glyphs:string,dpiscale:number) -> (Rasterizer))&((fileName:string,glyphs:string,dpiscale:number) -> (Rasterizer)), 1071 | newGlyphData: ((rasterizer:Rasterizer,glyph:number) -> ()), 1072 | newImageRasterizer: ((imageData:ImageData,glyphs:string,extraSpacing:number,dpiscale:number) -> (Rasterizer)), 1073 | newRasterizer: ((filename:string) -> (Rasterizer))&((data:FileData) -> (Rasterizer))&((size:number,hinting:HintingMode,dpiscale:number) -> (Rasterizer))&((fileName:string,size:number,hinting:HintingMode,dpiscale:number) -> (Rasterizer))&((fileData:FileData,size:number,hinting:HintingMode,dpiscale:number) -> (Rasterizer))&((imageData:ImageData,glyphs:string,dpiscale:number) -> (Rasterizer))&((fileName:string,glyphs:string,dpiscale:number) -> (Rasterizer)), 1074 | newTrueTypeRasterizer: ((size:number,hinting:HintingMode,dpiscale:number) -> (Rasterizer))&((fileName:string,size:number,hinting:HintingMode,dpiscale:number) -> (Rasterizer))&((fileData:FileData,size:number,hinting:HintingMode,dpiscale:number) -> (Rasterizer)), 1075 | }, 1076 | } & { 1077 | graphics: { 1078 | applyTransform: ((transform:Transform) -> ()), 1079 | arc: ((drawmode:DrawMode,x:number,y:number,radius:number,angle1:number,angle2:number,segments:number) -> ())&((drawmode:DrawMode,arctype:ArcType,x:number,y:number,radius:number,angle1:number,angle2:number,segments:number) -> ()), 1080 | captureScreenshot: ((filename:string) -> ())&((callback:(...any)->(...any)) -> ())&((channel:Channel) -> ()), 1081 | circle: ((mode:DrawMode,x:number,y:number,radius:number) -> ())&((mode:DrawMode,x:number,y:number,radius:number,segments:number) -> ()), 1082 | clear: (() -> ())&((r:number,g:number,b:number,a:number,clearstencil:boolean,cleardepth:boolean) -> ())&((color:{number},cleardepth:boolean) -> ())&((clearcolor:boolean,clearstencil:boolean,cleardepth:boolean) -> ()), 1083 | discard: ((discardcolor:boolean,discardstencil:boolean) -> ())&((discardcolors:{boolean},discardstencil:boolean) -> ()), 1084 | draw: ((drawable:Drawable,x:number,y:number,r:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number) -> ())&((texture:Texture,quad:Quad,x:number,y:number,r:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number) -> ())&((drawable:Drawable,transform:Transform) -> ())&((texture:Texture,quad:Quad,transform:Transform) -> ()), 1085 | drawInstanced: ((mesh:Mesh,instancecount:number,x:number,y:number,r:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number) -> ())&((mesh:Mesh,instancecount:number,transform:Transform) -> ()), 1086 | drawLayer: ((texture:Texture,layerindex:number,x:number,y:number,r:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number) -> ())&((texture:Texture,layerindex:number,quad:Quad,x:number,y:number,r:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number) -> ())&((texture:Texture,layerindex:number,transform:Transform) -> ())&((texture:Texture,layerindex:number,quad:Quad,transform:Transform) -> ()), 1087 | ellipse: ((mode:DrawMode,x:number,y:number,radiusx:number,radiusy:number) -> ())&((mode:DrawMode,x:number,y:number,radiusx:number,radiusy:number,segments:number) -> ()), 1088 | flushBatch: (() -> ()), 1089 | getBackgroundColor: (() -> (number,number,number,number)), 1090 | getBlendMode: (() -> (BlendMode,BlendAlphaMode)), 1091 | getCanvas: (() -> (Canvas)), 1092 | getCanvasFormats: (() -> ({[PixelFormat]:boolean}))&((readable:boolean) -> ({[PixelFormat]:boolean})), 1093 | getColor: (() -> (number,number,number,number)), 1094 | getColorMask: (() -> (boolean,boolean,boolean,boolean)), 1095 | getDPIScale: (() -> (number)), 1096 | getDefaultFilter: (() -> (FilterMode,FilterMode,number)), 1097 | getDepthMode: (() -> (CompareMode,boolean)), 1098 | getDimensions: (() -> (number,number)), 1099 | getFont: (() -> (Font)), 1100 | getFrontFaceWinding: (() -> (VertexWinding)), 1101 | getHeight: (() -> (number)), 1102 | getImageFormats: (() -> ({[PixelFormat]:boolean})), 1103 | getLineJoin: (() -> (LineJoin)), 1104 | getLineStyle: (() -> (LineStyle)), 1105 | getLineWidth: (() -> (number)), 1106 | getMeshCullMode: (() -> (CullMode)), 1107 | getPixelDimensions: (() -> (number,number)), 1108 | getPixelHeight: (() -> (number)), 1109 | getPixelWidth: (() -> (number)), 1110 | getPointSize: (() -> (number)), 1111 | getRendererInfo: (() -> (string,string,string,string)), 1112 | getScissor: (() -> (number,number,number,number)), 1113 | getShader: (() -> (Shader)), 1114 | getStackDepth: (() -> (number)), 1115 | getStats: (() -> ({drawcalls:number,canvasswitches:number,texturememory:number,images:number,canvases:number,fonts:number,shaderswitches:number,drawcallsbatched:number,}))&((stats:{[any]: any}) -> ({drawcalls:number,canvasswitches:number,texturememory:number,images:number,canvases:number,fonts:number,shaderswitches:number,drawcallsbatched:number,})), 1116 | getStencilTest: (() -> (CompareMode,number)), 1117 | getSupported: (() -> ({[GraphicsFeature]:boolean})), 1118 | getSystemLimits: (() -> ({[GraphicsLimit]:number})), 1119 | getTextureTypes: (() -> ({[TextureType]:boolean})), 1120 | getWidth: (() -> (number)), 1121 | intersectScissor: ((x:number,y:number,width:number,height:number) -> ()), 1122 | inverseTransformPoint: ((screenX:number,screenY:number) -> (number,number)), 1123 | isActive: (() -> (boolean)), 1124 | isGammaCorrect: (() -> (boolean)), 1125 | isWireframe: (() -> (boolean)), 1126 | line: ((x1:number,y1:number,x2:number,y2:number,...number) -> ())&((points:{number}) -> ()), 1127 | newArrayImage: ((slices:{[any]: any},settings:{mipmaps:boolean?,linear:boolean?,dpiscale:number?,}) -> (Image)), 1128 | newCanvas: (() -> (Canvas))&((width:number,height:number) -> (Canvas))&((width:number,height:number,settings:{type:TextureType?,format:PixelFormat?,readable:boolean,msaa:number?,dpiscale:number?,mipmaps:MipmapMode?,}) -> (Canvas))&((width:number,height:number,layers:number,settings:{type:TextureType?,format:PixelFormat?,readable:boolean,msaa:number?,dpiscale:number?,mipmaps:MipmapMode?,}) -> (Canvas)), 1129 | newCubeImage: ((filename:string,settings:{mipmaps:boolean?,linear:boolean?,}) -> (Image))&((faces:{[any]: any},settings:{mipmaps:boolean?,linear:boolean?,}) -> (Image)), 1130 | newFont: ((filename:string) -> (Font))&((filename:string,size:number,hinting:HintingMode,dpiscale:number) -> (Font))&((filename:string,imagefilename:string) -> (Font))&((size:number,hinting:HintingMode,dpiscale:number) -> (Font)), 1131 | newImage: ((filename:string,settings:{dpiscale:number?,linear:boolean?,mipmaps:boolean?,}) -> (Image))&((fileData:FileData,settings:{dpiscale:number?,linear:boolean?,mipmaps:boolean?,}) -> (Image))&((imageData:ImageData,settings:{dpiscale:number?,linear:boolean?,mipmaps:boolean?,}) -> (Image))&((compressedImageData:CompressedImageData,settings:{dpiscale:number?,linear:boolean?,mipmaps:boolean?,}) -> (Image)), 1132 | newImageFont: ((filename:string,glyphs:string) -> (Font))&((imageData:ImageData,glyphs:string) -> (Font))&((filename:string,glyphs:string,extraspacing:number) -> (Font)), 1133 | newMesh: ((vertices:{number},mode:MeshDrawMode,usage:SpriteBatchUsage) -> (Mesh))&((vertexcount:number,mode:MeshDrawMode,usage:SpriteBatchUsage) -> (Mesh))&((vertexformat:{attribute:{[any]: any}},vertices:{attributecomponent:number},mode:MeshDrawMode,usage:SpriteBatchUsage) -> (Mesh))&((vertexformat:{attribute:{[any]: any}},vertexcount:number,mode:MeshDrawMode,usage:SpriteBatchUsage) -> (Mesh))&((vertexcount:number,texture:Texture,mode:MeshDrawMode) -> (Mesh)), 1134 | newParticleSystem: ((image:Image,buffer:number) -> (ParticleSystem))&((texture:Texture,buffer:number) -> (ParticleSystem)), 1135 | newQuad: ((x:number,y:number,width:number,height:number,sw:number,sh:number) -> (Quad))&((x:number,y:number,width:number,height:number,texture:Texture) -> (Quad)), 1136 | newShader: ((code:string) -> (Shader))&((pixelcode:string,vertexcode:string) -> (Shader)), 1137 | newSpriteBatch: ((image:Image,maxsprites:number) -> (SpriteBatch))&((image:Image,maxsprites:number,usage:SpriteBatchUsage) -> (SpriteBatch))&((texture:Texture,maxsprites:number,usage:SpriteBatchUsage) -> (SpriteBatch)), 1138 | newText: ((font:Font,textstring:string) -> (Text))&((font:Font,coloredtext:{color1:{[any]: any},string1:string,color2:{[any]: any},string2:string}) -> (Text)), 1139 | newVideo: ((filename:string) -> (Video))&((videostream:VideoStream) -> (Video))&((filename:string,settings:{audio:boolean?,dpiscale:number?,}) -> (Video))&((filename:string,loadaudio:boolean) -> (Video))&((videostream:VideoStream,loadaudio:boolean) -> (Video)), 1140 | newVolumeImage: ((layers:{[any]: any},settings:{mipmaps:boolean?,linear:boolean?,}) -> (Image)), 1141 | origin: (() -> ()), 1142 | points: ((x:number,y:number,...number) -> ())&((points:{number}) -> ())&((points:{point:{[any]: any}}) -> ()), 1143 | polygon: ((mode:DrawMode,...number) -> ())&((mode:DrawMode,vertices:{number}) -> ()), 1144 | pop: (() -> ()), 1145 | present: (() -> ()), 1146 | print: ((text:string,x:number,y:number,r:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number) -> ())&((coloredtext:{color1:{[any]: any},string1:string,color2:{[any]: any},string2:string},x:number,y:number,angle:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number) -> ())&((text:string,transform:Transform) -> ())&((coloredtext:{color1:{[any]: any},string1:string,color2:{[any]: any},string2:string},transform:Transform) -> ())&((text:string,font:Font,transform:Transform) -> ())&((coloredtext:{color1:{[any]: any},string1:string,color2:{[any]: any},string2:string},font:Font,transform:Transform) -> ()), 1147 | printf: ((text:string,x:number,y:number,limit:number,align:AlignMode,r:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number) -> ())&((text:string,font:Font,x:number,y:number,limit:number,align:AlignMode,r:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number) -> ())&((text:string,transform:Transform,limit:number,align:AlignMode) -> ())&((text:string,font:Font,transform:Transform,limit:number,align:AlignMode) -> ())&((coloredtext:{color1:{[any]: any},string1:string,color2:{[any]: any},string2:string},x:number,y:number,limit:number,align:AlignMode,angle:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number) -> ())&((coloredtext:{color1:{[any]: any},string1:string,color2:{[any]: any},string2:string},font:Font,x:number,y:number,limit:number,align:AlignMode,angle:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number) -> ())&((coloredtext:{color1:{[any]: any},string1:string,color2:{[any]: any},string2:string},transform:Transform,limit:number,align:AlignMode) -> ())&((coloredtext:{color1:{[any]: any},string1:string,color2:{[any]: any},string2:string},font:Font,transform:Transform,limit:number,align:AlignMode) -> ()), 1148 | push: (() -> ())&((stack:StackType) -> ()), 1149 | rectangle: ((mode:DrawMode,x:number,y:number,width:number,height:number) -> ())&((mode:DrawMode,x:number,y:number,width:number,height:number,rx:number,ry:number,segments:number) -> ()), 1150 | replaceTransform: ((transform:Transform) -> ()), 1151 | reset: (() -> ()), 1152 | rotate: ((angle:number) -> ()), 1153 | scale: ((sx:number,sy:number) -> ()), 1154 | setBackgroundColor: ((red:number,green:number,blue:number,alpha:number) -> ())&((rgba:{number}) -> ()), 1155 | setBlendMode: ((mode:BlendMode) -> ())&((mode:BlendMode,alphamode:BlendAlphaMode) -> ()), 1156 | setCanvas: ((canvas:Canvas,mipmap:number) -> ())&(() -> ())&((canvas1:Canvas,canvas2:Canvas,...Canvas) -> ())&((canvas:Canvas,slice:number,mipmap:number) -> ())&((setup:{number}) -> ()), 1157 | setColor: ((red:number,green:number,blue:number,alpha:number) -> ())&((rgba:{number}) -> ()), 1158 | setColorMask: ((red:boolean,green:boolean,blue:boolean,alpha:boolean) -> ())&(() -> ()), 1159 | setDefaultFilter: ((min:FilterMode,mag:FilterMode,anisotropy:number) -> ()), 1160 | setDepthMode: ((comparemode:CompareMode,write:boolean) -> ())&(() -> ()), 1161 | setFont: ((font:Font) -> ()), 1162 | setFrontFaceWinding: ((winding:VertexWinding) -> ()), 1163 | setLineJoin: ((join:LineJoin) -> ()), 1164 | setLineStyle: ((style:LineStyle) -> ()), 1165 | setLineWidth: ((width:number) -> ()), 1166 | setMeshCullMode: ((mode:CullMode) -> ()), 1167 | setNewFont: ((size:number) -> (Font))&((filename:string,size:number) -> (Font))&((file:File,size:number) -> (Font))&((data:Data,size:number) -> (Font))&((rasterizer:Rasterizer) -> (Font)), 1168 | setPointSize: ((size:number) -> ()), 1169 | setScissor: ((x:number,y:number,width:number,height:number) -> ())&(() -> ()), 1170 | setShader: ((shader:Shader) -> ())&(() -> ()), 1171 | setStencilTest: ((comparemode:CompareMode,comparevalue:number) -> ())&(() -> ()), 1172 | setWireframe: ((enable:boolean) -> ()), 1173 | shear: ((kx:number,ky:number) -> ()), 1174 | stencil: ((stencilfunction:(...any)->(...any),action:StencilAction,value:number,keepvalues:boolean) -> ()), 1175 | transformPoint: ((globalX:number,globalY:number) -> (number,number)), 1176 | translate: ((dx:number,dy:number) -> ()), 1177 | validateShader: ((gles:boolean,code:string) -> (boolean,string))&((gles:boolean,pixelcode:string,vertexcode:string) -> (boolean,string)), 1178 | }, 1179 | } & { 1180 | image: { 1181 | isCompressed: ((filename:string) -> (boolean))&((fileData:FileData) -> (boolean)), 1182 | newCompressedData: ((filename:string) -> (CompressedImageData))&((fileData:FileData) -> (CompressedImageData)), 1183 | newImageData: ((width:number,height:number) -> (ImageData))&((width:number,height:number,format:PixelFormat,data:string) -> (ImageData))&((width:number,height:number,data:string) -> (ImageData))&((filename:string) -> (ImageData))&((filedata:FileData) -> (ImageData)), 1184 | }, 1185 | } & { 1186 | joystick: { 1187 | getGamepadMappingString: ((guid:string) -> (string)), 1188 | getJoystickCount: (() -> (number)), 1189 | getJoysticks: (() -> ({Joystick})), 1190 | loadGamepadMappings: ((filename:string) -> ())&((mappings:string) -> ()), 1191 | saveGamepadMappings: ((filename:string) -> (string))&(() -> (string)), 1192 | setGamepadMapping: ((guid:string,button:GamepadButton,inputtype:JoystickInputType,inputindex:number,hatdir:JoystickHat) -> (boolean))&((guid:string,axis:GamepadAxis,inputtype:JoystickInputType,inputindex:number,hatdir:JoystickHat) -> (boolean)), 1193 | }, 1194 | } & { 1195 | keyboard: { 1196 | getKeyFromScancode: ((scancode:Scancode) -> (KeyConstant)), 1197 | getScancodeFromKey: ((key:KeyConstant) -> (Scancode)), 1198 | hasKeyRepeat: (() -> (boolean)), 1199 | hasScreenKeyboard: (() -> (boolean)), 1200 | hasTextInput: (() -> (boolean)), 1201 | isDown: ((key:KeyConstant) -> (boolean))&((key:KeyConstant,...KeyConstant) -> (boolean)), 1202 | isScancodeDown: ((scancode:Scancode,...Scancode) -> (boolean)), 1203 | setKeyRepeat: ((enable:boolean) -> ()), 1204 | setTextInput: ((enable:boolean) -> ())&((enable:boolean,x:number,y:number,w:number,h:number) -> ()), 1205 | }, 1206 | } & { 1207 | math: { 1208 | colorFromBytes: ((rb:number,gb:number,bb:number,ab:number) -> (number,number,number,number)), 1209 | colorToBytes: ((r:number,g:number,b:number,a:number) -> (number,number,number,number)), 1210 | gammaToLinear: ((r:number,g:number,b:number) -> (number,number,number))&((color:{[any]: any}) -> (number,number,number))&((c:number) -> (number)), 1211 | getRandomSeed: (() -> (number,number)), 1212 | getRandomState: (() -> (string)), 1213 | isConvex: ((vertices:{number}) -> (boolean))&((x1:number,y1:number,x2:number,y2:number,...number) -> (boolean)), 1214 | linearToGamma: ((lr:number,lg:number,lb:number) -> (number,number,number))&((color:{number}) -> (number,number,number))&((lc:number) -> (number)), 1215 | newBezierCurve: ((vertices:{number}) -> (BezierCurve))&((x1:number,y1:number,x2:number,y2:number,...number) -> (BezierCurve)), 1216 | newRandomGenerator: (() -> (RandomGenerator))&((seed:number) -> (RandomGenerator))&((low:number,high:number) -> (RandomGenerator)), 1217 | newTransform: (() -> (Transform))&((x:number,y:number,angle:number,sx:number,sy:number,ox:number,oy:number,kx:number,ky:number) -> (Transform)), 1218 | noise: ((x:number) -> (number))&((x:number,y:number) -> (number))&((x:number,y:number,z:number) -> (number))&((x:number,y:number,z:number,w:number) -> (number)), 1219 | random: (() -> (number))&((max:number) -> (number))&((min:number,max:number) -> (number)), 1220 | randomNormal: ((stddev:number,mean:number) -> (number)), 1221 | setRandomSeed: ((seed:number) -> ())&((low:number,high:number) -> ()), 1222 | setRandomState: ((state:string) -> ()), 1223 | triangulate: ((polygon:{[any]: any}) -> ({[any]: any}))&((x1:number,y1:number,x2:number,y2:number,x3:number,y3:number) -> ({[any]: any})), 1224 | }, 1225 | } & { 1226 | mouse: { 1227 | getCursor: (() -> (Cursor)), 1228 | getPosition: (() -> (number,number)), 1229 | getRelativeMode: (() -> (boolean)), 1230 | getSystemCursor: ((ctype:CursorType) -> (Cursor)), 1231 | getX: (() -> (number)), 1232 | getY: (() -> (number)), 1233 | isCursorSupported: (() -> (boolean)), 1234 | isDown: ((button:number,...number) -> (boolean)), 1235 | isGrabbed: (() -> (boolean)), 1236 | isVisible: (() -> (boolean)), 1237 | newCursor: ((imageData:ImageData,hotx:number,hoty:number) -> (Cursor))&((filename:string,hotx:number,hoty:number) -> (Cursor))&((fileData:FileData,hotx:number,hoty:number) -> (Cursor)), 1238 | setCursor: ((cursor:Cursor) -> ())&(() -> ()), 1239 | setGrabbed: ((grab:boolean) -> ()), 1240 | setPosition: ((x:number,y:number) -> ()), 1241 | setRelativeMode: ((enable:boolean) -> ()), 1242 | setVisible: ((visible:boolean) -> ()), 1243 | setX: ((x:number) -> ()), 1244 | setY: ((y:number) -> ()), 1245 | }, 1246 | } & { 1247 | physics: { 1248 | getDistance: ((fixture1:Fixture,fixture2:Fixture) -> (number,number,number,number,number)), 1249 | getMeter: (() -> (number)), 1250 | newBody: ((world:World,x:number,y:number,type:BodyType) -> (Body)), 1251 | newChainShape: ((loop:boolean,x1:number,y1:number,x2:number,y2:number,...number) -> (ChainShape))&((loop:boolean,points:{number}) -> (ChainShape)), 1252 | newCircleShape: ((radius:number) -> (CircleShape))&((x:number,y:number,radius:number) -> (CircleShape)), 1253 | newDistanceJoint: ((body1:Body,body2:Body,x1:number,y1:number,x2:number,y2:number,collideConnected:boolean) -> (DistanceJoint)), 1254 | newEdgeShape: ((x1:number,y1:number,x2:number,y2:number) -> (EdgeShape)), 1255 | newFixture: ((body:Body,shape:Shape,density:number) -> (Fixture)), 1256 | newFrictionJoint: ((body1:Body,body2:Body,x:number,y:number,collideConnected:boolean) -> (FrictionJoint))&((body1:Body,body2:Body,x1:number,y1:number,x2:number,y2:number,collideConnected:boolean) -> (FrictionJoint)), 1257 | newGearJoint: ((joint1:Joint,joint2:Joint,ratio:number,collideConnected:boolean) -> (GearJoint)), 1258 | newMotorJoint: ((body1:Body,body2:Body,correctionFactor:number) -> (MotorJoint))&((body1:Body,body2:Body,correctionFactor:number,collideConnected:boolean) -> (MotorJoint)), 1259 | newMouseJoint: ((body:Body,x:number,y:number) -> (MouseJoint)), 1260 | newPolygonShape: ((x1:number,y1:number,x2:number,y2:number,x3:number,y3:number,...number) -> (PolygonShape))&((vertices:{number}) -> (PolygonShape)), 1261 | newPrismaticJoint: ((body1:Body,body2:Body,x:number,y:number,ax:number,ay:number,collideConnected:boolean) -> (PrismaticJoint))&((body1:Body,body2:Body,x1:number,y1:number,x2:number,y2:number,ax:number,ay:number,collideConnected:boolean) -> (PrismaticJoint))&((body1:Body,body2:Body,x1:number,y1:number,x2:number,y2:number,ax:number,ay:number,collideConnected:boolean,referenceAngle:number) -> (PrismaticJoint)), 1262 | newPulleyJoint: ((body1:Body,body2:Body,gx1:number,gy1:number,gx2:number,gy2:number,x1:number,y1:number,x2:number,y2:number,ratio:number,collideConnected:boolean) -> (PulleyJoint)), 1263 | newRectangleShape: ((width:number,height:number) -> (PolygonShape))&((x:number,y:number,width:number,height:number,angle:number) -> (PolygonShape)), 1264 | newRevoluteJoint: ((body1:Body,body2:Body,x:number,y:number,collideConnected:boolean) -> (RevoluteJoint))&((body1:Body,body2:Body,x1:number,y1:number,x2:number,y2:number,collideConnected:boolean,referenceAngle:number) -> (RevoluteJoint)), 1265 | newRopeJoint: ((body1:Body,body2:Body,x1:number,y1:number,x2:number,y2:number,maxLength:number,collideConnected:boolean) -> (RopeJoint)), 1266 | newWeldJoint: ((body1:Body,body2:Body,x:number,y:number,collideConnected:boolean) -> (WeldJoint))&((body1:Body,body2:Body,x1:number,y1:number,x2:number,y2:number,collideConnected:boolean) -> (WeldJoint))&((body1:Body,body2:Body,x1:number,y1:number,x2:number,y2:number,collideConnected:boolean,referenceAngle:number) -> (WeldJoint)), 1267 | newWheelJoint: ((body1:Body,body2:Body,x:number,y:number,ax:number,ay:number,collideConnected:boolean) -> (WheelJoint))&((body1:Body,body2:Body,x1:number,y1:number,x2:number,y2:number,ax:number,ay:number,collideConnected:boolean) -> (WheelJoint)), 1268 | newWorld: ((xg:number,yg:number,sleep:boolean) -> (World)), 1269 | setMeter: ((scale:number) -> ()), 1270 | }, 1271 | } & { 1272 | sound: { 1273 | newDecoder: ((file:File,buffer:number) -> (Decoder))&((filename:string,buffer:number) -> (Decoder)), 1274 | newSoundData: ((filename:string) -> (SoundData))&((file:File) -> (SoundData))&((decoder:Decoder) -> (SoundData))&((samples:number,rate:number,bits:number,channels:number) -> (SoundData)), 1275 | }, 1276 | } & { 1277 | system: { 1278 | getClipboardText: (() -> (string)), 1279 | getOS: (() -> (string)), 1280 | getPowerInfo: (() -> (PowerState,number,number)), 1281 | getProcessorCount: (() -> (number)), 1282 | hasBackgroundMusic: (() -> (boolean)), 1283 | openURL: ((url:string) -> (boolean)), 1284 | setClipboardText: ((text:string) -> ()), 1285 | vibrate: ((seconds:number) -> ()), 1286 | }, 1287 | } & { 1288 | thread: { 1289 | getChannel: ((name:string) -> (Channel)), 1290 | newChannel: (() -> (Channel)), 1291 | newThread: ((filename:string) -> (Thread))&((fileData:FileData) -> (Thread))&((codestring:string) -> (Thread)), 1292 | }, 1293 | } & { 1294 | timer: { 1295 | getAverageDelta: (() -> (number)), 1296 | getDelta: (() -> (number)), 1297 | getFPS: (() -> (number)), 1298 | getTime: (() -> (number)), 1299 | sleep: ((s:number) -> ()), 1300 | step: (() -> (number)), 1301 | }, 1302 | } & { 1303 | touch: { 1304 | getPosition: ((id:userdata) -> (number,number)), 1305 | getPressure: ((id:userdata) -> (number)), 1306 | getTouches: (() -> ({userdata})), 1307 | }, 1308 | } & { 1309 | video: { 1310 | newVideoStream: ((filename:string) -> (VideoStream))&((file:File) -> (VideoStream)), 1311 | }, 1312 | } & { 1313 | window: { 1314 | close: (() -> ()), 1315 | fromPixels: ((pixelvalue:number) -> (number))&((px:number,py:number) -> (number,number)), 1316 | getDPIScale: (() -> (number)), 1317 | getDesktopDimensions: ((displayindex:number) -> (number,number)), 1318 | getDisplayCount: (() -> (number)), 1319 | getDisplayName: ((displayindex:number) -> (string)), 1320 | getDisplayOrientation: ((displayindex:number) -> (DisplayOrientation)), 1321 | getFullscreen: (() -> (boolean,FullscreenType)), 1322 | getFullscreenModes: ((displayindex:number) -> ({width:number,height:number,})), 1323 | getIcon: (() -> (ImageData)), 1324 | getMode: (() -> (number,number,{fullscreen:boolean,fullscreentype:FullscreenType,vsync:boolean,msaa:number,resizable:boolean,borderless:boolean,centered:boolean,display:number,minwidth:number,minheight:number,highdpi:boolean,refreshrate:number,x:number,y:number,srgb:boolean,})), 1325 | getPosition: (() -> (number,number,number)), 1326 | getSafeArea: (() -> (number,number,number,number)), 1327 | getTitle: (() -> (string)), 1328 | getVSync: (() -> (number)), 1329 | hasFocus: (() -> (boolean)), 1330 | hasMouseFocus: (() -> (boolean)), 1331 | isDisplaySleepEnabled: (() -> (boolean)), 1332 | isMaximized: (() -> (boolean)), 1333 | isMinimized: (() -> (boolean)), 1334 | isOpen: (() -> (boolean)), 1335 | isVisible: (() -> (boolean)), 1336 | maximize: (() -> ()), 1337 | minimize: (() -> ()), 1338 | requestAttention: ((continuous:boolean) -> ()), 1339 | restore: (() -> ()), 1340 | setDisplaySleepEnabled: ((enable:boolean) -> ()), 1341 | setFullscreen: ((fullscreen:boolean) -> (boolean))&((fullscreen:boolean,fstype:FullscreenType) -> (boolean)), 1342 | setIcon: ((imagedata:ImageData) -> (boolean)), 1343 | setMode: ((width:number,height:number,flags:{fullscreen:boolean?,fullscreentype:FullscreenType?,vsync:boolean?,msaa:number?,stencil:boolean?,depth:number?,resizable:boolean?,borderless:boolean?,centered:boolean?,display:number?,minwidth:number?,minheight:number?,highdpi:boolean?,x:number?,y:number?,usedpiscale:boolean?,srgb:boolean?,}) -> (boolean)), 1344 | setPosition: ((x:number,y:number,displayindex:number) -> ()), 1345 | setTitle: ((title:string) -> ()), 1346 | setVSync: ((vsync:number) -> ()), 1347 | showMessageBox: ((title:string,message:string,type:MessageBoxType,attachtowindow:boolean) -> (boolean))&((title:string,message:string,buttonlist:{[any]: any},type:MessageBoxType,attachtowindow:boolean) -> (number)), 1348 | toPixels: ((value:number) -> (number))&((x:number,y:number) -> (number,number)), 1349 | updateMode: ((width:number,height:number,settings:{fullscreen:boolean,fullscreentype:FullscreenType,vsync:boolean,msaa:number,resizable:boolean,borderless:boolean,centered:boolean,display:number,minwidth:number,minheight:number,highdpi:boolean,x:number,y:number,}) -> (boolean)), 1350 | } 1351 | } -------------------------------------------------------------------------------- /static/main.luau: -------------------------------------------------------------------------------- 1 | function love.load() 2 | -- This will run once when the game loads 3 | end 4 | 5 | function love.update(dt) 6 | -- This will run every frame 7 | end 8 | 9 | function love.draw() 10 | -- This will run every time a new frame will be drawn 11 | end -------------------------------------------------------------------------------- /static/vscode_settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "luau-lsp.require.mode": "relativeToFile", 3 | "luau-lsp.types.definitionFiles": ["globals.d.luau"], 4 | "luau-lsp.platform.type": "roblox", 5 | "luau-lsp.sourcemap.enabled": false 6 | } 7 | --------------------------------------------------------------------------------