├── .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 | 
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 |
--------------------------------------------------------------------------------