From 0db5f5c6fa54d0867294cf8b6e5edd23f96fa80a Mon Sep 17 00:00:00 2001 From: Isaac <78173025+Zac8668@users.noreply.github.com> Date: Thu, 24 Feb 2022 20:50:25 -0300 Subject: [PATCH 01/21] Autotiling (#382) * First logic * Solved warnings * Added Autotiling It is almost done, just need to account for tile subdivisions, and add autotile mask bitmasks as an attribute. * Fixed formatting * Added tileset bitmasks field Added the bitmasks field for the tileset and some support to tile subdivisions * Minor changes * Added random choosing --- src/editor/actions.rs | 5 +++ src/editor/tools/placement.rs | 61 ++++++++++++++++++++++++++++++++--- src/json/map/tiled.rs | 1 + src/map/mod.rs | 39 ++++++++++++++++++++++ 4 files changed, 102 insertions(+), 4 deletions(-) diff --git a/src/editor/actions.rs b/src/editor/actions.rs index e748d26d8e..62553fb716 100644 --- a/src/editor/actions.rs +++ b/src/editor/actions.rs @@ -614,6 +614,7 @@ impl UndoableAction for ImportAction { autotile_mask: tileset.autotile_mask.clone(), tile_attributes: tileset.tile_attributes.clone(), properties: tileset.properties.clone(), + bitmasks: None, }; map.tilesets.insert(tileset.id.clone(), tileset); @@ -776,6 +777,8 @@ impl UndoableAction for UpdateTilesetAction { self.old_autotile_mask = Some(tileset.autotile_mask.clone()); tileset.autotile_mask = self.autotile_mask.clone(); + + tileset.bitmasks = tileset.get_bitmasks(); } else { return Err(Error::new_const( ErrorKind::EditorAction, @@ -804,6 +807,8 @@ impl UndoableAction for UpdateTilesetAction { } else { return Err(Error::new_const(ErrorKind::EditorAction, &"UpdateTilesetAction (Undo): No old autotile mask stored in action. Undo was probably called on an action that was never applied")); } + + tileset.bitmasks = tileset.get_bitmasks(); } else { return Err(Error::new_const( ErrorKind::EditorAction, diff --git a/src/editor/tools/placement.rs b/src/editor/tools/placement.rs index 24cf58ea48..843ea90afa 100644 --- a/src/editor/tools/placement.rs +++ b/src/editor/tools/placement.rs @@ -5,12 +5,14 @@ use super::{EditorAction, EditorContext, EditorTool, EditorToolParams}; use crate::{ editor::EditorCamera, map::{Map, MapLayerKind}, + rand::ChooseRandom, Resources, }; #[derive(Default)] pub struct TilePlacementTool { params: EditorToolParams, + coords: Option, } impl TilePlacementTool { @@ -21,7 +23,10 @@ impl TilePlacementTool { is_continuous: true, }; - TilePlacementTool { params } + TilePlacementTool { + params, + coords: None, + } } } @@ -64,10 +69,58 @@ impl EditorTool for TilePlacementTool { if self.is_available(map, ctx) { if let Some(tileset_id) = &ctx.selected_tileset { - let _tileset = map.tilesets.get(tileset_id).unwrap(); + let cursor_world_position = scene::find_node_by_type::() + .unwrap() + .to_world_space(ctx.cursor_position); + let coords = map.to_coords(cursor_world_position); + + if self.coords != Some(coords) { + let tileset = map.tilesets.get(tileset_id).unwrap(); + + // Do autotile resolution here and set `res` to an `EditorAction::SelectTile` if + // selected tile should be changed according to context. + + //Get self surrounding tiles + let mut surrounding_tiles: Vec = vec![]; + for y in 0..3 { + for x in 0..3 { + if let Some(layer) = &ctx.selected_layer { + let is_some = map + .get_tile(layer, coords.x + x - 1, coords.y + y - 1) + .is_some(); + surrounding_tiles.push(is_some); + } + } + } + + //Get bitmask value from self surrounding tiles + let mut bitmask = 0; + for (i, b) in surrounding_tiles.iter().enumerate() { + if *b && i < 4 { + bitmask += 2_u32.pow(i as u32); + } else if *b && i > 4 { + bitmask += 2_u32.pow(i as u32 - 1); + } + } + + let mut tile_ids = Vec::new(); + if let Some(bitmasks) = &tileset.bitmasks { + for (i, tileset_bitmask) in bitmasks.iter().enumerate() { + if *tileset_bitmask == bitmask && bitmask != 0 { + tile_ids.push(i as u32); + } + } + } + + if let Some(id) = tile_ids.choose() { + res = Some(EditorAction::SelectTile { + tileset_id: tileset_id.to_owned(), + id: *id, + }); + } + } - // Do autotile resolution here and set `res` to an `EditorAction::SelectTile` if - // selected tile should be changed according to context. + self.coords = Some(coords); } } diff --git a/src/json/map/tiled.rs b/src/json/map/tiled.rs index 9ea3561cde..cb6f114718 100644 --- a/src/json/map/tiled.rs +++ b/src/json/map/tiled.rs @@ -192,6 +192,7 @@ impl TiledMap { autotile_mask, tile_attributes, properties, + bitmasks: None, }; tilesets.insert(tiled_tileset.name, tileset); diff --git a/src/map/mod.rs b/src/map/mod.rs index f7d7e50e76..a755080a4e 100644 --- a/src/map/mod.rs +++ b/src/map/mod.rs @@ -651,6 +651,8 @@ pub struct MapTileset { pub tile_attributes: HashMap>, #[serde(default, skip_serializing_if = "HashMap::is_empty")] pub properties: HashMap, + #[serde(skip)] + pub bitmasks: Option>, } impl MapTileset { @@ -687,6 +689,7 @@ impl MapTileset { autotile_mask, tile_attributes: HashMap::new(), properties: HashMap::new(), + bitmasks: None, } } @@ -699,4 +702,40 @@ impl MapTileset { pub fn default_tile_subdivisions() -> UVec2 { uvec2(3, 3) } + + pub fn get_bitmasks(&self) -> Option> { + //Get autotile mask bitmasks + let tsub_x = self.tile_subdivisions.x as usize; + let tsub_y = self.tile_subdivisions.y as usize; + let atmsk_width = self.grid_size.x as usize * tsub_x; + + let mut bitmasks_vec: Vec> = + vec![vec![]; self.autotile_mask.len() / (tsub_x * tsub_y)]; + let mut bitmasks: Vec = vec![0; self.autotile_mask.len() / (tsub_x * tsub_y)]; + + let mut trow_off = 0; + for i in 0..self.autotile_mask.len() / atmsk_width { + if i != 0 && i % tsub_y == 0 { + trow_off += atmsk_width / tsub_x; + } + let row = self.autotile_mask[i * atmsk_width..i * atmsk_width + atmsk_width].to_vec(); + + for x in 0..row.len() / tsub_x { + let tile_row = row[x * tsub_x..x * tsub_x + tsub_x].to_vec(); + + bitmasks_vec[x + trow_off].extend(tile_row); + } + } + + for (n, surrounding_tiles) in bitmasks_vec.iter().enumerate() { + for (i, b) in surrounding_tiles.iter().enumerate() { + if *b && i < 4 { + bitmasks[n] += 2_u32.pow(i as u32); + } else if *b && i > 4 { + bitmasks[n] += 2_u32.pow(i as u32 - 1); + } + } + } + Some(bitmasks) + } } From fef6c7d79e892b91d7dba4c1df5a9ebb85eb298c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Orhun=20Parmaks=C4=B1z?= Date: Wed, 2 Mar 2022 20:46:12 +0200 Subject: [PATCH 02/21] Disable debug builds (#397) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cb3cb3c368..f2770e1474 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,7 +57,7 @@ jobs: - { os: macos-latest, target: "aarch64-apple-darwin" } - { os: windows-latest, target: "x86_64-pc-windows-msvc" } - { os: windows-latest, target: "i686-pc-windows-msvc" } - profile: ["", --release] + profile: ["--release"] steps: - name: Checkout From 48ca6fd4432ac935a7eefc75431ecd801b8a85de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Orhun=20Parmaks=C4=B1z?= Date: Wed, 2 Mar 2022 20:46:27 +0200 Subject: [PATCH 03/21] Include licenses folder in release archives (#395) * Include licenses folder in release archives * Include the main license file in releases --- .github/workflows/release.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 10be084adc..e20ac8b42e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -78,7 +78,8 @@ jobs: cp target/${{ matrix.config.target }}/release/fishfight.exe $release_dir/ strip $release_dir/fishfight.exe find assets -name "*.schema.json" -exec rm -f {} \; - cp -R assets/ mods/ $release_dir/ + cp -R assets/ mods/ licenses/ $release_dir/ + cp LICENSE $release_dir/licenses/ 7z a -tzip $artifact_path $release_dir/ - name: Prepare artifacts [Unix] @@ -92,7 +93,8 @@ jobs: cp target/${{ matrix.config.target }}/release/fishfight $release_dir/ strip $release_dir/fishfight || true find assets -name "*.schema.json" -exec rm -f {} \; - cp -R assets mods $release_dir + cp -R assets mods licenses $release_dir + cp LICENSE $release_dir/licenses tar -czvf $artifact_path $release_dir/ - name: Deploy | Upload artifacts From b21ba5c6a4cffdc09d9e35f87560f3bc9080504c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Orhun=20Parmaks=C4=B1z?= Date: Wed, 2 Mar 2022 20:46:36 +0200 Subject: [PATCH 04/21] Update license copyright years (#396) --- LICENSE | 2 +- licenses/LICENSE-APACHE | 2 +- licenses/LICENSE-MIT | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/LICENSE b/LICENSE index 071b523f47..867afb0be2 100644 --- a/LICENSE +++ b/LICENSE @@ -5,4 +5,4 @@ Fish Fight source code is dual-licensed under either at your option. -Fish Fight media assets are Copyright (c) 2020-2021 The Fish Fight Game Developers and licensed as [CC BY-NC](https://creativecommons.org/licenses/by-nc/4.0/). +Fish Fight media assets are Copyright (c) 2020-2022 The Fish Fight Game Developers and licensed as [CC BY-NC](https://creativecommons.org/licenses/by-nc/4.0/). diff --git a/licenses/LICENSE-APACHE b/licenses/LICENSE-APACHE index 5bc9139c95..39429f1e3b 100644 --- a/licenses/LICENSE-APACHE +++ b/licenses/LICENSE-APACHE @@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work. same "printed page" as the copyright notice for easier identification within third-party archives. -Copyright (c) 2020-2021 The Fish Fight Game Developers +Copyright (c) 2020-2022 The Fish Fight Game Developers Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/licenses/LICENSE-MIT b/licenses/LICENSE-MIT index bd34cbeaf8..3011f8b12d 100644 --- a/licenses/LICENSE-MIT +++ b/licenses/LICENSE-MIT @@ -1,4 +1,4 @@ -Copyright (c) 2020-2021 The Fish Fight Game Developers +Copyright (c) 2020-2022 The Fish Fight Game Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), From 6dfc4ba6b929411333c3069f5a5bcd07ceff81f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Orhun=20Parmaks=C4=B1z?= Date: Fri, 4 Mar 2022 13:38:48 +0200 Subject: [PATCH 05/21] Add RELEASE.md (#399) --- RELEASE.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 RELEASE.md diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000000..c0e291d096 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,10 @@ +# Creating a Release + +[GitHub releases](https://github.com/fishfight/FishFight/releases) are automated via [GitHub actions](./.github/workflows/release.yml) and triggered by pushing a tag. + +1. Bump the version in [Cargo.toml](Cargo.toml). +2. Update [Cargo.lock](Cargo.lock) by building the project. (`cargo build`) +3. Commit and push the changes. (i.e. submit a pull request) +4. Either [draft a new release](https://github.com/fishfight/FishFight/releases/new) from the GitHub interface or create a new tag and push it via the command line. +5. While naming the release, do not include the version in the title. (e.g. "Level Editor") +6. Add release notes and highlights. From be03813d3cf913a690b0633b96f5d27a0b04d90d Mon Sep 17 00:00:00 2001 From: zTecna <98235607+zTecna@users.noreply.github.com> Date: Fri, 4 Mar 2022 08:39:19 -0300 Subject: [PATCH 06/21] Add Lionfishy character (#398) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Create PlayerLionfishy(96x80).png * Add Lionfishy character Co-authored-by: Orhun Parmaksız --- assets/player_characters.json | 11 ++++++++++- assets/textures.json | 11 ++++++++++- .../textures/player/PlayerLionfishy(96x80).png | Bin 0 -> 40044 bytes 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 assets/textures/player/PlayerLionfishy(96x80).png diff --git a/assets/player_characters.json b/assets/player_characters.json index 84f796d3e7..2fa5963641 100644 --- a/assets/player_characters.json +++ b/assets/player_characters.json @@ -34,5 +34,14 @@ "x": 0.0, "y": 16.0 } + }, + { + "id": "lionfishy", + "name": "Lionfishy", + "texture": "player_lionfishy", + "offset": { + "x": 0.0, + "y": 16.0 + } } -] \ No newline at end of file +] diff --git a/assets/textures.json b/assets/textures.json index c75c9439f6..bc697f4845 100644 --- a/assets/textures.json +++ b/assets/textures.json @@ -193,6 +193,15 @@ "y": 80 } }, + { + "id": "player_lionfishy", + "path": "textures/player/PlayerLionfishy(96x80).png", + "type": "spritesheet", + "sprite_size": { + "x": 96, + "y": 80 + } + }, { "id": "pirate_hat", "path": "textures/items/hats/pirate hat.png", @@ -487,4 +496,4 @@ "y": 144 } } -] \ No newline at end of file +] diff --git a/assets/textures/player/PlayerLionfishy(96x80).png b/assets/textures/player/PlayerLionfishy(96x80).png new file mode 100644 index 0000000000000000000000000000000000000000..95663ee6c00d19750b9e68f35b4f767829a56b14 GIT binary patch literal 40044 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 NXZ6m!Ic*j6zX69lf8qcD literal 0 HcmV?d00001 From 71b56a3baccb1dbe04fa2d14a8dfee5f6542e54a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Orhun=20Parmaks=C4=B1z?= Date: Fri, 4 Mar 2022 13:39:28 +0200 Subject: [PATCH 07/21] Update badge links in README.md (#400) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 31c02809b1..b37d3c60b7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Fish Fight -[![Build Status](https://img.shields.io/github/workflow/status/fishfight/FishFight/Compilation%20check?logo=github&labelColor=1e1c24&color=8bcfcf)](https://github.com/fishfight/FishFight/actions) [![Documentation](https://img.shields.io/badge/documentation-fishfight.github.io-green.svg?labelColor=1e1c24&color=f3ee7a)](https://fishfight.github.io/FishFight/) [![License](https://img.shields.io/badge/License-MIT%20or%20Apache%202-green.svg?label=license&labelColor=1e1c24&color=34925e)](./LICENSE) [![Discord](https://img.shields.io/badge/chat-on%20discord-green.svg?logo=discord&logoColor=fff&labelColor=1e1c24&color=8d5b3f)](https://discord.gg/4smxjcheE5) +[![Build Status](https://img.shields.io/github/workflow/status/fishfight/FishFight/Continuous%20integration?logo=github&labelColor=1e1c24&color=8bcfcf)](https://github.com/fishfight/FishFight/actions) [![Documentation](https://img.shields.io/badge/documentation-fishfight.github.io-green.svg?labelColor=1e1c24&color=f3ee7a)](https://fishfight.github.io/FishFight/) [![License](https://img.shields.io/badge/License-MIT%20or%20Apache%202-green.svg?label=license&labelColor=1e1c24&color=34925e)](./LICENSE) [![Discord](https://img.shields.io/badge/chat-on%20discord-green.svg?logo=discord&logoColor=fff&labelColor=1e1c24&color=8d5b3f)](https://discord.gg/4smxjcheE5) ![Fish Fight Preview](https://user-images.githubusercontent.com/24392180/151969075-399e9fea-e2de-4340-96a4-0a0e5b79c281.gif) From 8fd0850fb259810758101bde40256f446c8a48d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Orhun=20Parmaks=C4=B1z?= Date: Fri, 4 Mar 2022 14:10:19 +0200 Subject: [PATCH 08/21] Prepare for v0.4.2 release (#401) --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- RELEASE.md | 2 +- core/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 53db8a3fe2..69e27277ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -176,7 +176,7 @@ dependencies = [ [[package]] name = "fishfight" -version = "0.4.1" +version = "0.4.2" dependencies = [ "ff-particles", "fishfight-core", @@ -191,7 +191,7 @@ dependencies = [ [[package]] name = "fishfight-core" -version = "0.4.1" +version = "0.4.2" dependencies = [ "async-trait", "fishsticks", diff --git a/Cargo.toml b/Cargo.toml index 0b26f952e5..9a8c0ad183 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fishfight" -version = "0.4.1" +version = "0.4.2" description = "A tactical 2D shooter" authors = ["Fish Fight Contributors"] license = "MIT OR Apache-2.0" diff --git a/RELEASE.md b/RELEASE.md index c0e291d096..13ad090a9d 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -2,7 +2,7 @@ [GitHub releases](https://github.com/fishfight/FishFight/releases) are automated via [GitHub actions](./.github/workflows/release.yml) and triggered by pushing a tag. -1. Bump the version in [Cargo.toml](Cargo.toml). +1. Bump the version in [Cargo.toml](Cargo.toml) and [core/Cargo.toml](core/Cargo.toml). 2. Update [Cargo.lock](Cargo.lock) by building the project. (`cargo build`) 3. Commit and push the changes. (i.e. submit a pull request) 4. Either [draft a new release](https://github.com/fishfight/FishFight/releases/new) from the GitHub interface or create a new tag and push it via the command line. diff --git a/core/Cargo.toml b/core/Cargo.toml index 538ea4a1eb..c038bce70e 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fishfight-core" -version = "0.4.1" +version = "0.4.2" authors = ["Fish Fight Contributors"] license = "MIT OR Apache-2.0" edition = "2021" From 84a9d4be88ada0a8b278f5cdd5ac85a2110ea48b Mon Sep 17 00:00:00 2001 From: zTecna <98235607+zTecna@users.noreply.github.com> Date: Sat, 5 Mar 2022 21:15:46 -0300 Subject: [PATCH 09/21] Add Catty character (#402) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Create PlayerCatfishy(96x80).png * new player i missed the name * Add Catsharky character * Rename Catsharky to Catty Co-authored-by: Orhun Parmaksız --- assets/player_characters.json | 9 +++++++++ assets/textures.json | 9 +++++++++ assets/textures/player/PlayerCatty(96x80).png | Bin 0 -> 37037 bytes 3 files changed, 18 insertions(+) create mode 100644 assets/textures/player/PlayerCatty(96x80).png diff --git a/assets/player_characters.json b/assets/player_characters.json index 2fa5963641..4dfb0412b5 100644 --- a/assets/player_characters.json +++ b/assets/player_characters.json @@ -43,5 +43,14 @@ "x": 0.0, "y": 16.0 } + }, + { + "id": "catty", + "name": "Catty", + "texture": "player_catty", + "offset": { + "x": 0.0, + "y": 16.0 + } } ] diff --git a/assets/textures.json b/assets/textures.json index bc697f4845..b5252a1a36 100644 --- a/assets/textures.json +++ b/assets/textures.json @@ -202,6 +202,15 @@ "y": 80 } }, + { + "id": "player_catty", + "path": "textures/player/PlayerCatty(96x80).png", + "type": "spritesheet", + "sprite_size": { + "x": 96, + "y": 80 + } + }, { "id": "pirate_hat", "path": "textures/items/hats/pirate hat.png", diff --git a/assets/textures/player/PlayerCatty(96x80).png b/assets/textures/player/PlayerCatty(96x80).png new file mode 100644 index 0000000000000000000000000000000000000000..9e018a741de4631566ca302c956bb64b9ee481b9 GIT binary patch literal 37037 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 LZB7)MoQwNk+`HJ! literal 0 HcmV?d00001 From a0c798d3a09a438417fb4002b893a60053195bba Mon Sep 17 00:00:00 2001 From: lenscas Date: Mon, 21 Feb 2022 21:32:18 +0100 Subject: [PATCH 10/21] first idea for query --- Cargo.lock | 530 +++++++++++++++++++++++++++++++++++++- Cargo.toml | 22 +- core/Cargo.toml | 21 +- core/src/lib.rs | 1 + core/src/query_builder.rs | 85 ++++++ src/player/events.rs | 7 +- 6 files changed, 642 insertions(+), 24 deletions(-) create mode 100644 core/src/query_builder.rs diff --git a/Cargo.lock b/Cargo.lock index 69e27277ea..8ed4b7e260 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "adler32" version = "1.2.0" @@ -66,12 +72,27 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bstr" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +dependencies = [ + "memchr", +] + [[package]] name = "bumpalo" version = "3.9.1" @@ -90,6 +111,27 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "bzip2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6afcd980b5f3a45017c57e57a2fcccbb351cc43a356ce117ef760ef8052b89b0" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "cc" version = "1.0.73" @@ -102,12 +144,51 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chunked_transfer" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e" + [[package]] name = "color_quant" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "const_fn" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" + +[[package]] +name = "cookie" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" +dependencies = [ + "percent-encoding", + "time 0.2.27", + "version_check", +] + +[[package]] +name = "cookie_store" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3818dfca4b0cb5211a659bbcbb94225b7127407b2b135e650d717bfb78ab10d3" +dependencies = [ + "cookie", + "idna", + "log", + "publicsuffix", + "serde", + "serde_json", + "time 0.2.27", + "url", +] + [[package]] name = "core-foundation" version = "0.6.4" @@ -164,6 +245,30 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "erased-serde" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56047058e1ab118075ca22f9ecd737bcc961aa3566a3019cb71388afa280bd8a" +dependencies = [ + "serde", +] + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + [[package]] name = "ff-particles" version = "0.1.2" @@ -186,6 +291,7 @@ dependencies = [ "macroquad-platformer", "serde", "serde_json", + "tealr", "wasm-bindgen", ] @@ -200,6 +306,7 @@ dependencies = [ "macroquad", "serde", "serde_json", + "tealr", "toml", "wasm-bindgen", ] @@ -213,6 +320,18 @@ dependencies = [ "gilrs", ] +[[package]] +name = "flate2" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" +dependencies = [ + "cfg-if", + "crc32fast", + "libc", + "miniz_oxide 0.4.4", +] + [[package]] name = "fnv" version = "1.0.7" @@ -229,6 +348,16 @@ dependencies = [ "ttf-parser", ] +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + [[package]] name = "getrandom" version = "0.2.4" @@ -307,7 +436,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d4e8eb4d5dd2ea100ffbb4eb6814f4294a7362fcafbc5c1c4c015b41d16f424" dependencies = [ "hashbrown 0.12.0", - "spin", + "spin 0.9.2", ] [[package]] @@ -316,6 +445,17 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a164bb2ceaeff4f42542bdb847c41517c78a60f5649671b2a07312b6e117549" +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "image" version = "0.23.14" @@ -331,6 +471,15 @@ dependencies = [ "png", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + [[package]] name = "io-kit-sys" version = "0.1.0" @@ -341,6 +490,15 @@ dependencies = [ "mach", ] +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.1" @@ -398,6 +556,24 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "lua-src" +version = "544.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7341ba039a781c4982ca20761c55f44e07bfefd496a45b1e929763d88f5fc68b" +dependencies = [ + "cc", +] + +[[package]] +name = "luajit-src" +version = "210.3.2+resty1085a4d" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e27456f513225a9edd22fc0a5f526323f6adb3099c4de87a84ceb842d93ba4" +dependencies = [ + "cc", +] + [[package]] name = "mach" version = "0.2.3" @@ -438,12 +614,24 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f5cecfede1e530599c8686f7f2d609489101d3d63741a6dc423afc997ce3fcc8" +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + [[package]] name = "maybe-uninit" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + [[package]] name = "memoffset" version = "0.6.5" @@ -477,6 +665,33 @@ dependencies = [ "adler32", ] +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + +[[package]] +name = "mlua" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4235d7e740d73d7429df6f176c81b248f05c39d67264d45a7d8cecb67c227f6f" +dependencies = [ + "bstr", + "cc", + "erased-serde", + "lua-src", + "luajit-src", + "num-traits", + "once_cell", + "pkg-config", + "serde", +] + [[package]] name = "ndk-sys" version = "0.2.2" @@ -552,6 +767,12 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + [[package]] name = "pkg-config" version = "0.3.24" @@ -567,9 +788,15 @@ dependencies = [ "bitflags", "crc32fast", "deflate", - "miniz_oxide", + "miniz_oxide 0.3.7", ] +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + [[package]] name = "proc-macro2" version = "1.0.36" @@ -579,6 +806,25 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "publicsuffix" +version = "1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b4ce31ff0a27d93c8de1849cf58162283752f065a90d508f1105fa6c9a213f" +dependencies = [ + "idna", + "url", +] + +[[package]] +name = "qstring" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" +dependencies = [ + "percent-encoding", +] + [[package]] name = "quad-alsa-sys" version = "0.3.2" @@ -616,6 +862,39 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted", + "web-sys", + "winapi", +] + [[package]] name = "rustc_version" version = "0.2.3" @@ -625,6 +904,19 @@ dependencies = [ "semver", ] +[[package]] +name = "rustls" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +dependencies = [ + "base64", + "log", + "ring", + "sct", + "webpki", +] + [[package]] name = "rusty-xinput" version = "1.2.0" @@ -703,6 +995,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "sct" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "semver" version = "0.9.0" @@ -773,12 +1075,27 @@ dependencies = [ "maybe-uninit", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "spin" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5" +[[package]] +name = "standback" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" +dependencies = [ + "version_check", +] + [[package]] name = "stdweb" version = "0.4.20" @@ -841,6 +1158,130 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "tealr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c2083c3a84a14059f3031f1cf9c7cc0488de7786d951829d21b37904af8007e" +dependencies = [ + "bstr", + "itertools", + "mlua", + "serde", + "tealr_derive", +] + +[[package]] +name = "tealr_derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe296f304b273503665edb7f6823ac5d1b21fa43fab23c6c5f83abb12a79a86d" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "tempfile", + "ureq", + "zip", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "time" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" +dependencies = [ + "const_fn", + "libc", + "standback", + "stdweb", + "time-macros", + "version_check", + "winapi", +] + +[[package]] +name = "time-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" +dependencies = [ + "proc-macro-hack", + "time-macros-impl", +] + +[[package]] +name = "time-macros-impl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "standback", + "syn", +] + +[[package]] +name = "tinyvec" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + [[package]] name = "toml" version = "0.5.8" @@ -856,12 +1297,64 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ae2f58a822f08abdaf668897e96a5656fe72f5a9ce66422423e8849384872e6" +[[package]] +name = "unicode-bidi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" + +[[package]] +name = "unicode-normalization" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-xid" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "ureq" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b8b063c2d59218ae09f22b53c42eaad0d53516457905f5235ca4bc9e99daa71" +dependencies = [ + "base64", + "chunked_transfer", + "cookie", + "cookie_store", + "log", + "once_cell", + "qstring", + "rustls", + "url", + "webpki", + "webpki-roots", +] + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + [[package]] name = "uuid" version = "0.8.2" @@ -950,6 +1443,25 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" +dependencies = [ + "webpki", +] + [[package]] name = "winapi" version = "0.3.9" @@ -971,3 +1483,17 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "zip" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ab48844d61251bb3835145c521d88aa4031d7139e8485990f60ca911fa0815" +dependencies = [ + "byteorder", + "bzip2", + "crc32fast", + "flate2", + "thiserror", + "time 0.1.43", +] diff --git a/Cargo.toml b/Cargo.toml index 9a8c0ad183..72ffacad9d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,10 @@ [package] -name = "fishfight" -version = "0.4.2" -description = "A tactical 2D shooter" authors = ["Fish Fight Contributors"] -license = "MIT OR Apache-2.0" +description = "A tactical 2D shooter" edition = "2021" +license = "MIT OR Apache-2.0" +name = "fishfight" +version = "0.4.2" [target.'cfg(target_arch = "wasm32")'.lib] crate-type = ["cdylib"] @@ -19,16 +19,16 @@ members = ["core"] opt-level = 3 [dependencies] -core = { path = "./core", package = "fishfight-core" } +core = {path = "./core", package = "fishfight-core"} # ultimate = { path = "../FishFight-ultimate", package = "fishfight-ultimate", optional = true } -ff-particles = { version = "0.1", features = ["serde"] } -fishsticks = { git = "https://github.com/fishfight/fishsticks", default-features = false, features = ["gilrs"] } -macroquad = { version = "0.3.10" } -macroquad-platformer = "0.1" +ff-particles = {version = "0.1", features = ["serde"]} +fishsticks = {git = "https://github.com/fishfight/fishsticks", default-features = false, features = ["gilrs"]} hecs = "0.7.1" -serde = { version = "1.0", features = ["derive"] } +macroquad = {version = "0.3.10"} +macroquad-platformer = "0.1" +serde = {version = "1.0", features = ["derive"]} serde_json = "1.0" +tealr = {version = "0.8.2", features = ["mlua", "mlua_vendored", "mlua_luajit", "mlua_serialize", "derive"]} [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = "0.2.74" - diff --git a/core/Cargo.toml b/core/Cargo.toml index c038bce70e..86cb2da7f8 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -1,19 +1,20 @@ [package] -name = "fishfight-core" -version = "0.4.2" authors = ["Fish Fight Contributors"] -license = "MIT OR Apache-2.0" edition = "2021" +license = "MIT OR Apache-2.0" +name = "fishfight-core" +version = "0.4.2" [dependencies] -fishsticks = { git = "https://github.com/fishfight/fishsticks", default-features = false, features = ["gilrs"] } -macroquad = { version = "0.3.10" } +async-trait = "0.1.52" +fishsticks = {git = "https://github.com/fishfight/fishsticks", default-features = false, features = ["gilrs"]} hecs = "0.7.1" -serde = { version = "1.0", package = "serde", features = ["derive"] } -serde_json = { version = "1.0" } +macroquad = {version = "0.3.10"} +serde = {version = "1.0", package = "serde", features = ["derive"]} +serde_json = {version = "1.0"} +tealr = {version = "0.8.2", features = ["mlua", "mlua_vendored", "mlua_luajit", "mlua_serialize", "derive"]} toml = "0.5" -async-trait = "0.1.52" [target.'cfg(target_arch = "wasm32")'.dependencies] -getrandom = { version = "0.2", features = ["js"] } -wasm-bindgen = "0.2.74" \ No newline at end of file +getrandom = {version = "0.2", features = ["js"]} +wasm-bindgen = "0.2.74" diff --git a/core/src/lib.rs b/core/src/lib.rs index ed8f3cc21a..06ae4ac1c6 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -7,6 +7,7 @@ pub mod json; pub mod math; pub mod network; pub mod noise; +pub mod query_builder; pub mod text; mod channel; diff --git a/core/src/query_builder.rs b/core/src/query_builder.rs new file mode 100644 index 0000000000..8cf5862246 --- /dev/null +++ b/core/src/query_builder.rs @@ -0,0 +1,85 @@ +use std::marker::PhantomData; + +use hecs::{Query, QueryBorrow, QueryMut, World}; + +pub struct BuildStart(); +pub struct Builder1(PhantomData); +pub struct Builder2(PhantomData<(A, B)>); +pub struct Builder3(PhantomData<(A, B, C)>); +pub struct Builder4(PhantomData<(A, B, C, D)>); +pub struct Builder5(PhantomData<(A, B, C, D, E)>); +pub struct Builder6(PhantomData<(A, B, C, D, E, F)>); +pub struct Builder7(PhantomData<(A, B, C, D, E, F, G)>); +pub struct Builder8(PhantomData<(A, B, C, D, E, F, G, H)>); +pub struct Builder9(PhantomData<(A, B, C, D, E, F, G, H, I)>); +pub struct Builder10(PhantomData<(A, B, C, D, E, F, G, H, I, J)>); +pub struct Builder11( + PhantomData<(A, B, C, D, E, F, G, H, I, J, K)>, +); +pub struct Builder12( + PhantomData<(A, B, C, D, E, F, G, H, I, J, K, L)>, +); +pub struct Builder13( + PhantomData<(A, B, C, D, E, F, G, H, I, J, K, L, M)>, +); +pub struct Builder14( + PhantomData<(A, B, C, D, E, F, G, H, I, J, K, L, M, N)>, +); +pub struct Builder15( + PhantomData<(A, B, C, D, E, F, G, H, I, J, K, L, M, N, P)>, +); + +impl Default for BuildStart { + fn default() -> Self { + Self::new() + } +} + +impl BuildStart { + pub fn new() -> Self { + Self() + } + pub fn query(world: &World) -> QueryBorrow<'_, ()> { + world.query() + } + pub fn query_mut(world: &mut World) -> QueryMut<'_, ()> { + world.query_mut() + } + pub fn with(self) -> Builder1 { + Builder1(PhantomData) + } +} + +impl Builder1 { + pub fn query(self, world: &World) -> QueryBorrow<'_, T> { + world.query() + } + pub fn query_mut(self, world: &mut World) -> QueryMut<'_, T> { + world.query_mut() + } + pub fn with(self) -> Builder2 + where + (T, N): Query, + { + Builder2(PhantomData) + } +} + +impl Builder2 +where + (A, B): Query, +{ + pub fn query(self, world: &World) -> QueryBorrow<'_, (A, B)> { + world.query() + } + pub fn query_mut(self, world: &mut World) -> QueryMut<'_, (A, B)> { + println!("QUERY!"); + world.query_mut() + } + pub fn with(self) -> Builder3 + where + (A, B, N): Query, + { + Builder3(PhantomData) + } +} diff --git a/src/player/events.rs b/src/player/events.rs index 4913ccc822..b68ba8fcfa 100644 --- a/src/player/events.rs +++ b/src/player/events.rs @@ -67,7 +67,12 @@ impl From<&PlayerEvent> for PlayerEventKind { } pub fn update_player_events(world: &mut World) { - for (_, (player, events)) in world.query_mut::<(&mut Player, &mut PlayerEventQueue)>() { + let query = core::query_builder::BuildStart::new() + .with::<&mut Player>() + .with::<&mut PlayerEventQueue>() + .query_mut(world); + for (_, (player, events)) in query { + // world.query_mut::<(&mut Player, &mut PlayerEventQueue)>() { let dt = get_frame_time(); events.queue.push(PlayerEvent::Update { dt }); From 68b5fbbac128bdcff83aa00b27401289a25bfc45 Mon Sep 17 00:00:00 2001 From: lenscas Date: Mon, 7 Mar 2022 18:52:10 +0100 Subject: [PATCH 11/21] start port to heavy lua and hecs --- Cargo.lock | 443 +++++++++++++++++++++-- Cargo.toml | 5 +- core/Cargo.toml | 7 +- core/src/lib.rs | 3 +- core/src/query_builder.rs | 253 ++++++++++++- core/src/test.rs | 127 +++++++ mods/active_mods.json | 3 +- mods/test_lua_mod_one/fishfight_mod.json | 7 + mods/test_lua_mod_one/main.lua | 7 + mods/test_lua_mod_one/second_file.lua | 1 + rust-toolchain.toml | 2 + src/game/mod.rs | 2 +- src/lua.rs | 94 +++++ src/main.rs | 5 + src/physics.rs | 4 +- src/player/events.rs | 7 +- src/resources.rs | 15 +- 17 files changed, 930 insertions(+), 55 deletions(-) create mode 100644 core/src/test.rs create mode 100644 mods/test_lua_mod_one/fishfight_mod.json create mode 100644 mods/test_lua_mod_one/main.lua create mode 100644 mods/test_lua_mod_one/second_file.lua create mode 100644 rust-toolchain.toml create mode 100644 src/lua.rs diff --git a/Cargo.lock b/Cargo.lock index 8ed4b7e260..a2d2de9865 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,6 +31,24 @@ dependencies = [ "version_check", ] +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + [[package]] name = "async-trait" version = "0.1.52" @@ -245,6 +263,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + [[package]] name = "either" version = "1.6.1" @@ -287,6 +311,7 @@ dependencies = [ "fishfight-core", "fishsticks", "hecs", + "hv-lua", "macroquad", "macroquad-platformer", "serde", @@ -303,6 +328,9 @@ dependencies = [ "fishsticks", "getrandom", "hecs", + "hv-alchemy", + "hv-cell", + "hv-lua", "macroquad", "serde", "serde_json", @@ -422,20 +450,18 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.12.0" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" dependencies = [ "ahash 0.7.6", ] [[package]] name = "hecs" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d4e8eb4d5dd2ea100ffbb4eb6814f4294a7362fcafbc5c1c4c015b41d16f424" +version = "0.7.1" dependencies = [ - "hashbrown 0.12.0", + "hashbrown 0.11.2", "spin 0.9.2", ] @@ -445,6 +471,106 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a164bb2ceaeff4f42542bdb847c41517c78a60f5649671b2a07312b6e117549" +[[package]] +name = "hv-alchemy" +version = "0.1.0" +dependencies = [ + "hashbrown 0.11.2", + "hv-atom", + "hv-cell", + "lazy_static", + "spin 0.9.2", + "static_assertions", +] + +[[package]] +name = "hv-atom" +version = "0.1.0" + +[[package]] +name = "hv-cell" +version = "0.1.0" +dependencies = [ + "hv-guarded-borrow", +] + +[[package]] +name = "hv-elastic" +version = "0.4.1" +dependencies = [ + "hecs", + "hv-cell", + "hv-guarded-borrow", + "hv-stampede", + "static_assertions", + "thiserror", +] + +[[package]] +name = "hv-guarded-borrow" +version = "0.1.1" +dependencies = [ + "hecs", +] + +[[package]] +name = "hv-lua" +version = "0.6.6" +dependencies = [ + "bstr", + "cc", + "erased-serde", + "hecs", + "hv-alchemy", + "hv-cell", + "hv-elastic", + "hv-guarded-borrow", + "hv-lua-derive", + "hv-math", + "lua-src", + "luajit-src", + "nalgebra", + "num-traits", + "once_cell", + "parry3d", + "pkg-config", + "rustc-hash", + "serde", + "static_assertions", +] + +[[package]] +name = "hv-lua-derive" +version = "0.6.0" +dependencies = [ + "itertools", + "once_cell", + "proc-macro-error", + "proc-macro2", + "quote", + "regex", + "syn", +] + +[[package]] +name = "hv-math" +version = "0.1.0" +dependencies = [ + "approx", + "hv-alchemy", + "nalgebra", + "nalgebra-glm", + "serde", +] + +[[package]] +name = "hv-stampede" +version = "0.2.1" +dependencies = [ + "bumpalo", + "spin 0.9.2", +] + [[package]] name = "idna" version = "0.2.3" @@ -466,7 +592,7 @@ dependencies = [ "byteorder", "color_quant", "num-iter", - "num-rational", + "num-rational 0.3.2", "num-traits", "png", ] @@ -519,6 +645,9 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] [[package]] name = "lewton" @@ -528,7 +657,7 @@ checksum = "8d542c1a317036c45c2aa1cf10cc9d403ca91eb2d333ef1a4917e5cb10628bd0" dependencies = [ "byteorder", "ogg", - "smallvec", + "smallvec 0.6.14", ] [[package]] @@ -537,6 +666,12 @@ version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06e509672465a0504304aa87f9f176f2b2b716ed8fb105ebe5c02dc6dce96a94" +[[package]] +name = "libm" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33a33a362ce288760ec6a508b94caaec573ae7d3bbbd91b87aa0bad4456839db" + [[package]] name = "libudev-sys" version = "0.1.4" @@ -547,6 +682,15 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "lock_api" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.14" @@ -620,6 +764,15 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" +[[package]] +name = "matrixmultiply" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add85d4dd35074e6fedc608f8c8f513a3548619a9024b751949ef0e8e45a4d84" +dependencies = [ + "rawpointer", +] + [[package]] name = "maybe-uninit" version = "2.0.0" @@ -676,20 +829,45 @@ dependencies = [ ] [[package]] -name = "mlua" -version = "0.6.6" +name = "nalgebra" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4235d7e740d73d7429df6f176c81b248f05c39d67264d45a7d8cecb67c227f6f" +checksum = "d506eb7e08d6329505faa8a3a00a5dcc6de9f76e0c77e4b75763ae3c770831ff" dependencies = [ - "bstr", - "cc", - "erased-serde", - "lua-src", - "luajit-src", + "approx", + "matrixmultiply", + "nalgebra-macros", + "num-complex", + "num-rational 0.4.0", "num-traits", - "once_cell", - "pkg-config", + "rand", + "rand_distr", "serde", + "simba", + "typenum", +] + +[[package]] +name = "nalgebra-glm" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cec137f377549720ff9fbbcd1413a12bbb03b4feea3192cee987e8493158748" +dependencies = [ + "approx", + "nalgebra", + "num-traits", + "simba", +] + +[[package]] +name = "nalgebra-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01fcc0b8149b4632adc89ac3b7b31a12fb6099a0317a4eb2ebff574ef7de7218" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -711,6 +889,27 @@ dependencies = [ "memoffset", ] +[[package]] +name = "num-complex" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26873667bbbb7c5182d4a37c1add32cdf09f841af72da53318fdb81543c15085" +dependencies = [ + "num-traits", + "serde", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "num-integer" version = "0.1.44" @@ -743,6 +942,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-rational" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.14" @@ -750,6 +960,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -767,6 +978,32 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" +[[package]] +name = "parry3d" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "067fa44bf7f7cc4022756ef9796c5f8d67c7a63041df71e6eeb09ad08ab1ece8" +dependencies = [ + "approx", + "bitflags", + "downcast-rs", + "either", + "nalgebra", + "num-derive", + "num-traits", + "rustc-hash", + "serde", + "simba", + "slab", + "smallvec 1.8.0", +] + +[[package]] +name = "paste" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5" + [[package]] name = "percent-encoding" version = "2.1.0" @@ -791,6 +1028,36 @@ dependencies = [ "miniz_oxide 0.3.7", ] +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro-hack" version = "0.5.19" @@ -862,6 +1129,52 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_distr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + [[package]] name = "redox_syscall" version = "0.2.10" @@ -871,6 +1184,23 @@ dependencies = [ "bitflags", ] +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + [[package]] name = "remove_dir_all" version = "0.5.3" @@ -895,6 +1225,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.2.3" @@ -934,6 +1270,15 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" +[[package]] +name = "safe_arch" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "794821e4ccb0d9f979512f9c1973480123f9bd62a90d74ab0f9426fcf8f4a529" +dependencies = [ + "bytemuck", +] + [[package]] name = "sapp-android" version = "0.1.14" @@ -995,6 +1340,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "sct" version = "0.6.1" @@ -1066,6 +1417,25 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" +[[package]] +name = "simba" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0b7840f121a46d63066ee7a99fc81dcabbc6105e437cae43528cea199b5a05f" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "paste", + "wide", +] + +[[package]] +name = "slab" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" + [[package]] name = "smallvec" version = "0.6.14" @@ -1075,6 +1445,12 @@ dependencies = [ "maybe-uninit", ] +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" + [[package]] name = "spin" version = "0.5.2" @@ -1086,6 +1462,9 @@ name = "spin" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5" +dependencies = [ + "lock_api", +] [[package]] name = "standback" @@ -1096,6 +1475,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "stdweb" version = "0.4.20" @@ -1161,12 +1546,10 @@ dependencies = [ [[package]] name = "tealr" version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c2083c3a84a14059f3031f1cf9c7cc0488de7786d951829d21b37904af8007e" dependencies = [ "bstr", + "hv-lua", "itertools", - "mlua", "serde", "tealr_derive", ] @@ -1174,8 +1557,6 @@ dependencies = [ [[package]] name = "tealr_derive" version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe296f304b273503665edb7f6823ac5d1b21fa43fab23c6c5f83abb12a79a86d" dependencies = [ "proc-macro2", "quote", @@ -1297,6 +1678,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ae2f58a822f08abdaf668897e96a5656fe72f5a9ce66422423e8849384872e6" +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + [[package]] name = "unicode-bidi" version = "0.3.7" @@ -1462,6 +1849,16 @@ dependencies = [ "webpki", ] +[[package]] +name = "wide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3aba2d1dac31ac7cae82847ac5b8be822aee8f99a4e100f279605016b185c5f" +dependencies = [ + "bytemuck", + "safe_arch", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 72ffacad9d..57179777df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,12 +23,13 @@ core = {path = "./core", package = "fishfight-core"} # ultimate = { path = "../FishFight-ultimate", package = "fishfight-ultimate", optional = true } ff-particles = {version = "0.1", features = ["serde"]} fishsticks = {git = "https://github.com/fishfight/fishsticks", default-features = false, features = ["gilrs"]} -hecs = "0.7.1" +hecs = {path = "../hv-dev/hv-ecs"} +hv-lua = {path = "../hv-dev/hv-lua"}#imported so its macro's work macroquad = {version = "0.3.10"} macroquad-platformer = "0.1" serde = {version = "1.0", features = ["derive"]} serde_json = "1.0" -tealr = {version = "0.8.2", features = ["mlua", "mlua_vendored", "mlua_luajit", "mlua_serialize", "derive"]} +tealr = {path = "../tealr/tealr", features = ["mlua", "hv_lua", "mlua_vendored", "mlua_luajit", "mlua_serialize", "mlua_send", "derive"]} [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = "0.2.74" diff --git a/core/Cargo.toml b/core/Cargo.toml index 86cb2da7f8..9b65fc6f60 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -8,11 +8,14 @@ version = "0.4.2" [dependencies] async-trait = "0.1.52" fishsticks = {git = "https://github.com/fishfight/fishsticks", default-features = false, features = ["gilrs"]} -hecs = "0.7.1" +hecs = {path = "../../hv-dev/hv-ecs"} +hv-alchemy = {path = "../../hv-dev/hv/crates/hv-alchemy"} +hv-cell = {path = "../../hv-dev/hv/crates/hv-cell"} +hv-lua = {path = "../../hv-dev/hv-lua"}#imported so its macro's work macroquad = {version = "0.3.10"} serde = {version = "1.0", package = "serde", features = ["derive"]} serde_json = {version = "1.0"} -tealr = {version = "0.8.2", features = ["mlua", "mlua_vendored", "mlua_luajit", "mlua_serialize", "derive"]} +tealr = {path = "../../tealr/tealr", features = ["mlua", "hv_lua", "mlua_macros", "mlua_vendored", "mlua_luajit", "mlua_serialize", "derive"]} toml = "0.5" [target.'cfg(target_arch = "wasm32")'.dependencies] diff --git a/core/src/lib.rs b/core/src/lib.rs index 06ae4ac1c6..4ca1ca1182 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -7,7 +7,6 @@ pub mod json; pub mod math; pub mod network; pub mod noise; -pub mod query_builder; pub mod text; mod channel; @@ -21,3 +20,5 @@ pub use transform::Transform; pub use async_trait::async_trait; pub use serde; pub use serde_json; + +pub mod test; diff --git a/core/src/query_builder.rs b/core/src/query_builder.rs index 8cf5862246..df140e65b7 100644 --- a/core/src/query_builder.rs +++ b/core/src/query_builder.rs @@ -1,11 +1,31 @@ -use std::marker::PhantomData; +use std::{ + fmt::Display, + marker::PhantomData, + sync::{Arc, Mutex, PoisonError}, +}; -use hecs::{Query, QueryBorrow, QueryMut, World}; +use hecs::{Entity, Query, QueryBorrow, QueryMut, World}; +#[derive(Clone)] pub struct BuildStart(); pub struct Builder1(PhantomData); +impl Clone for Builder1 { + fn clone(&self) -> Self { + Self(PhantomData) + } +} pub struct Builder2(PhantomData<(A, B)>); +impl Clone for Builder2 { + fn clone(&self) -> Self { + Self(PhantomData) + } +} pub struct Builder3(PhantomData<(A, B, C)>); +impl Clone for Builder3 { + fn clone(&self) -> Self { + Self(PhantomData) + } +} pub struct Builder4(PhantomData<(A, B, C, D)>); pub struct Builder5(PhantomData<(A, B, C, D, E)>); pub struct Builder6(PhantomData<(A, B, C, D, E, F)>); @@ -51,16 +71,13 @@ impl BuildStart { } impl Builder1 { - pub fn query(self, world: &World) -> QueryBorrow<'_, T> { + pub fn query<'a, 'world>(&'a self, world: &'world World) -> QueryBorrow<'world, T> { world.query() } - pub fn query_mut(self, world: &mut World) -> QueryMut<'_, T> { + pub fn query_mut<'a, 'world>(&'a self, world: &'world mut World) -> QueryMut<'world, T> { world.query_mut() } - pub fn with(self) -> Builder2 - where - (T, N): Query, - { + pub fn with(self) -> Builder2 { Builder2(PhantomData) } } @@ -69,17 +86,227 @@ impl Builder2 where (A, B): Query, { - pub fn query(self, world: &World) -> QueryBorrow<'_, (A, B)> { + pub fn query<'a, 'world>(&'a self, world: &'world World) -> QueryBorrow<'world, (A, B)> { world.query() } - pub fn query_mut(self, world: &mut World) -> QueryMut<'_, (A, B)> { + pub fn query_mut<'a, 'world>(&'a self, world: &'world mut World) -> QueryMut<'world, (A, B)> { + world.query_mut() + } + pub fn with(self) -> Builder3 { + Builder3(PhantomData) + } +} + +impl Builder3 +where + (A, B, C): Query, +{ + pub fn query(self, world: &World) -> QueryBorrow<'_, (A, B, C)> { + world.query() + } + pub fn query_mut(self, world: &mut World) -> QueryMut<'_, (A, B, C)> { println!("QUERY!"); world.query_mut() } - pub fn with(self) -> Builder3 + //added for completions sake but.. not actually going to do much + pub fn with(self) -> Builder4 where - (A, B, N): Query, + (A, B, C, N): Query, { - Builder3(PhantomData) + Builder4(PhantomData) + } +} + +use tealr::{ + mlu::{ + mlua::{Error, ToLua, UserData}, + TealData, TypedFunction, + }, + new_type, TypeName, +}; + +#[derive(Clone, TypeName)] +pub struct LuaWorld(Arc>); + +impl LuaWorld { + fn lock(&self) -> Result, QueryError> { + self.0.lock().map_err(QueryError::from) + } +} + +impl UserData for LuaWorld { + fn add_methods<'lua, M: tealr::mlu::mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + let mut x = ::tealr::mlu::UserDataWrapper::from_user_data_methods(methods); + ::add_methods(&mut x); + } +} +impl TealData for LuaWorld { + fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { + methods.add_function( + "start_query", + |lua, function: tealr::mlu::mlua::Function| lua.scope(|v| Ok(())), + ) + } +} + +impl TypeName for BuildStart { + fn get_type_parts() -> std::borrow::Cow<'static, [tealr::NamePart]> { + new_type!(QueryBuilder) + } +} +//for simplicity sake, lets get rid of the types for now. +impl TypeName for Builder1 { + fn get_type_parts() -> std::borrow::Cow<'static, [tealr::NamePart]> { + new_type!(QueryBuilder1) + } +} +//for simplicity sake, lets get rid of the types for now. +impl TypeName for Builder2 { + fn get_type_parts() -> std::borrow::Cow<'static, [tealr::NamePart]> { + new_type!(QueryBuilder2) + } +} + +//for simplicity sake, lets get rid of the types for now. +impl TypeName for Builder3 { + fn get_type_parts() -> std::borrow::Cow<'static, [tealr::NamePart]> { + new_type!(QueryBuilder3) + } +} +impl UserData for BuildStart { + fn add_methods<'lua, M: tealr::mlu::mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + let mut x = ::tealr::mlu::UserDataWrapper::from_user_data_methods(methods); + ::add_methods(&mut x); + } +} + +#[derive(Debug)] +pub enum QueryError { + PoisonedWorld, +} + +impl Display for QueryError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "The world mutex got poisoned. This shouldn't happen. PANIC!" + ) + } +} +impl From> for QueryError { + fn from(_: PoisonError) -> Self { + QueryError::PoisonedWorld + } +} +impl From for Error { + fn from(x: QueryError) -> Self { + Error::external(x) + } +} + +#[derive(Clone, Copy, TypeName)] +pub struct LuaEntity(Entity); + +impl TealData for LuaEntity {} +impl UserData for LuaEntity { + fn add_methods<'lua, M: tealr::mlu::mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + let mut x = ::tealr::mlu::UserDataWrapper::from_user_data_methods(methods); + ::add_methods(&mut x); + } +} + +impl std::error::Error for QueryError {} + +impl TealData for BuildStart { + fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { + methods.add_method( + "query", + |_, + _, + (luaworld, func): ( + LuaWorld, + TypedFunction, + )| { + let unlocked = luaworld.0.lock().map_err(QueryError::from)?; + let mut x = BuildStart::query(&unlocked); + let mut res = Vec::new(); + for (v, _) in &mut x { + res.push(func.call(LuaEntity(v))?) + } + //BuildStart::query() + Ok(res) + }, + ); + methods.add_method("with_integer", |_, this, ()| { + Ok(this.to_owned().with::<&mut i64>()) + }) + } +} +impl<'a, T: 'a> UserData for Builder1<&'a mut T> +where + &'a mut T: Query, + T: ToOwned, + ::Owned: ToLua<'static>, +{ + fn add_methods<'lua, M: tealr::mlu::mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + let mut x = ::tealr::mlu::UserDataWrapper::from_user_data_methods(methods); + ::add_methods(&mut x); + } +} +impl<'a, A: 'a> TealData for Builder1<&'a mut A> +where + &'a mut A: Query, + A: ToOwned, + ::Owned: ToLua<'static>, +{ + fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { + methods.add_method("with_string", |_, this, ()| { + let x = this.to_owned(); + let x = x.with::<&mut String>(); + Ok(x) + }) + } +} + +impl<'a, A: 'a, B: 'a> UserData for Builder2<&mut A, &mut B> +where + (&'a mut A, &'a mut B): Query, + A: ToOwned, + B: ToOwned, + ::Owned: ToLua<'static>, + ::Owned: ToLua<'static>, +{ + fn add_methods<'lua, M: tealr::mlu::mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + let mut x = ::tealr::mlu::UserDataWrapper::from_user_data_methods(methods); + ::add_methods(&mut x); + } +} +impl TealData for Builder2 +where + (A, B): Query, + A: ToOwned, + B: ToOwned, + ::Owned: ToLua<'static>, + ::Owned: ToLua<'static>, +{ + fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { + methods.add_method( + "query", + |lua, + this, + (world, func): ( + LuaWorld, + tealr::mlu::TypedFunction, + )| { + let z = world.lock()?; + let mut x = this.query(&z); + let mut res = Vec::new(); + for (v, x) in &mut x { + res.push(func.call(LuaEntity(v))?) + } + //BuildStart::query() + Ok(res) + }, + ) } } diff --git a/core/src/test.rs b/core/src/test.rs new file mode 100644 index 0000000000..11d9e473e0 --- /dev/null +++ b/core/src/test.rs @@ -0,0 +1,127 @@ +use std::{error::Error, sync::Arc}; + +use hecs::{Entity, World}; +use hv_alchemy::Type; +use hv_cell::AtomicRefCell; +use tealr::mlu::mlua::{ + chunk, + hv::{types, LuaUserDataTypeExt, LuaUserDataTypeTypeExt}, + Lua, UserData, UserDataFields, UserDataMethods, +}; + +#[derive(Debug, Clone, Copy)] +struct I32Component(i32); +impl UserData for I32Component { + #[allow(clippy::unit_arg)] + fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("value", |_, this| Ok(this.0)); + fields.add_field_method_set("value", |_, this, value| Ok(this.0 = value)); + } + fn on_metatable_init(t: Type) { + t.add_clone().add_copy().mark_component(); + } + + // The following methods are a bit like implementing `UserData` on `Type`, the userdata + // type object of `Self`. This one just lets you construct an `I32Component` from Lua given a + // value convertible to an `i32`. + fn add_type_methods<'lua, M: UserDataMethods<'lua, Type>>(methods: &mut M) { + methods.add_function("new", |_, i: i32| Ok(Self(i))); + } + + // We want to generate the necessary vtables for accessing this type as a component in the ECS. + // The `LuaUserDataTypeTypeExt` extension trait provides convenient methods for registering the + // required traits for this (`.mark_component_type()` is shorthand for + // `.add::()`.) + fn on_type_metatable_init(t: Type>) { + t.mark_component_type(); + } +} +#[derive(Debug, Clone, Copy)] +struct BoolComponent(bool); +impl UserData for BoolComponent { + #[allow(clippy::unit_arg)] + fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("value", |_, this| Ok(this.0)); + fields.add_field_method_set("value", |_, this, value| Ok(this.0 = value)); + } + fn on_metatable_init(t: Type) { + t.add_clone().add_copy().mark_component(); + } + + // The following methods are a bit like implementing `UserData` on `Type`, the userdata + // type object of `Self`. This one just lets you construct an `BoolComponent` from Lua given a + // value convertible to an `i32`. + fn add_type_methods<'lua, M: UserDataMethods<'lua, Type>>(methods: &mut M) { + methods.add_function("new", |_, i: bool| Ok(Self(i))); + } + + // We want to generate the necessary vtables for accessing this type as a component in the ECS. + // The `LuaUserDataTypeTypeExt` extension trait provides convenient methods for registering the + // required traits for this (`.mark_component_type()` is shorthand for + // `.add::()`.) + fn on_type_metatable_init(t: Type>) { + t.mark_component_type(); + } +} + +pub fn test() -> Result<(), Box> { + let lua = Lua::new(); + let hv = types(&lua)?; + let i32_ty = lua.create_userdata_type::()?; + let bool_ty = lua.create_userdata_type::()?; + + let world = Arc::new(AtomicRefCell::new(World::new())); + // Clone the world so that it doesn't become owned by Lua. We still want a copy! + let world_clone = world.clone(); + + let chunk = chunk! { + print("Hello from lua!") + // Drag in the `hv` table we created above, and also the `I32Component` and `BoolComponent` types, + // presumptuously calling them `I32` and `Bool` just because they're wrappers around the fact we + // can't just slap a primitive in there and call it a day. + local hv = $hv + local Query = hv.ecs.Query + local I32, Bool = $i32_ty, $bool_ty + + local world = $world_clone + // Spawn an entity, dynamically adding components to it taken from userdata! Works with copy, + // clone, *and* non-clone types (non-clone types will be moved out of the userdata and the userdata + // object marked as destructed) + print("make new entity with I32(5) and Bool(true)") + local entity = world:spawn { I32.new(5), Bool.new(true) } + print("Query it") + // Dynamic query functionality, using our fork's `hecs::DynamicQuery`. + local query = Query.new { Query.write(I32), Query.read(Bool) } + // Querying takes a closure in order to enforce scope - the queryitem will panic if used outside that + // scope. + world:query_one(query, entity, function(item) + print("Got item:",item) + // Querying allows us to access components of our item as userdata objects through the same interface + // we defined above! + print("asserting if still true") + assert(item:take(Bool).value == true) + local i = item:take(I32) + print("asserting if still 5") + assert(i.value == 5) + print("time to set it to 6") + i.value = 6 + assert(i.value == 6) + end) + print("Returning it from lua, back to rust") + // Return the entity we spawned back to Rust so we can examine it there. + return entity + }; + let entity: Entity = lua.load(chunk).eval()?; + + // Look! It worked! + let borrowed = world.borrow(); + println!("Querying from rust and asserting_eq"); + let mut q = borrowed + .query_one::<(&I32Component, &BoolComponent)>(entity) + .ok(); + assert_eq!( + q.as_mut().and_then(|q| q.get()).map(|(i, b)| (i.0, b.0)), + Some((6, true)) + ); + Ok(()) +} diff --git a/mods/active_mods.json b/mods/active_mods.json index dc3adf275f..e28d9734ae 100644 --- a/mods/active_mods.json +++ b/mods/active_mods.json @@ -1,4 +1,5 @@ [ "test_mod_one", - "test_mod_two" + "test_mod_two", + "test_lua_mod_one" ] \ No newline at end of file diff --git a/mods/test_lua_mod_one/fishfight_mod.json b/mods/test_lua_mod_one/fishfight_mod.json new file mode 100644 index 0000000000..b2f0016ff9 --- /dev/null +++ b/mods/test_lua_mod_one/fishfight_mod.json @@ -0,0 +1,7 @@ +{ + "id": "test_lua_mod_one", + "name": "Test Lua Mod One", + "description": "This is a mod meant for testing the lua integration", + "version": "0.1.0", + "kind": "full" +} \ No newline at end of file diff --git a/mods/test_lua_mod_one/main.lua b/mods/test_lua_mod_one/main.lua new file mode 100644 index 0000000000..dbdb89afe1 --- /dev/null +++ b/mods/test_lua_mod_one/main.lua @@ -0,0 +1,7 @@ +print("Hello from lua mod!") +require "second_file" +return { + fixed_update_physics_bodies = function() + print("Hello from fixed_update_physics_body") + end +} \ No newline at end of file diff --git a/mods/test_lua_mod_one/second_file.lua b/mods/test_lua_mod_one/second_file.lua new file mode 100644 index 0000000000..5e22194f1d --- /dev/null +++ b/mods/test_lua_mod_one/second_file.lua @@ -0,0 +1 @@ +print("This is a second lua file that got opened. LETS GO!") \ No newline at end of file diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000000..5d56faf9ae --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" diff --git a/src/game/mod.rs b/src/game/mod.rs index 5d0956d4a0..45e8cb4583 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -11,6 +11,7 @@ use macroquad::prelude::*; use macroquad::ui::root_ui; use hecs::{Entity, World}; +use tealr::mlu::mlua::Lua; use core::input::is_gamepad_btn_pressed; use core::Result; @@ -63,7 +64,6 @@ pub struct Game { impl Game { pub fn new(mode: GameMode, map: Map, player_params: &[PlayerParams]) -> Result { let mut world = World::default(); - { let camera = GameCamera::new(map.get_size()); storage::store(camera); diff --git a/src/lua.rs b/src/lua.rs new file mode 100644 index 0000000000..ff5e475042 --- /dev/null +++ b/src/lua.rs @@ -0,0 +1,94 @@ +use std::{error::Error, os::unix::prelude::OsStrExt, path::Path}; + +use hv_lua::{chunk, Function, Lua}; +use macroquad::prelude::collections::storage; + +use crate::Resources; + +const LUA_ENTRY: &str = "main"; + +pub(crate) fn init_lua(mod_dir: &Path) -> Result> { + let lua = Lua::new(); + let dir = mod_dir.as_os_str().as_bytes().to_owned(); + { + let globals = lua.globals(); + //a table containing all the mods + globals.set("mods", lua.create_table()?)?; + + //we don't want users to simply use `require` to load their files as that will either result in conflicts or annoying path names + //to drive this point home, I rename the `require` function here and add 2 other functions to load mod files + let req = globals.get::<_, Function>("require")?; + globals.set("require_lib", req)?; + globals.set("require", hv_lua::Nil)?; + + //this function allows people to load a file from arbitrary mods + //this allows "library only" mods to exist. + //there will also be a function that loads from the current mod. However, that one needs to be defined when loading the mod + let load_any_mod_file = lua.create_function( + move |lua, (from_mod, path): (hv_lua::String, hv_lua::String)| { + //TODO: a way to go from `mod id` to `mod folder` + let req = lua.globals().get::<_, Function>("require_lib")?; + let mut full_path = Vec::new(); + full_path.extend_from_slice(&dir); + full_path.extend_from_slice(b"."); + full_path.extend_from_slice(from_mod.as_bytes()); + full_path.extend_from_slice(b"."); + full_path.extend_from_slice(path.as_bytes()); + let full_path = lua.create_string(&full_path)?; + req.call::<_, hv_lua::Value>(full_path) + }, + )?; + globals.set("require_from", load_any_mod_file)?; + } + Ok(lua) +} + +pub(crate) fn load_lua>(mod_name: P, lua: &Lua) -> Result<(), Box> { + //I want to use a lua string but... those get turned into `nil` for some reason? + //probably a bug in mlua/hv-lua that needs to be tackled + let name = String::from_utf8_lossy(mod_name.as_ref()); + //a nice copy so the error message can easily specify what mod it failed to load + let name2 = String::from_utf8_lossy(mod_name.as_ref()); + let entry = LUA_ENTRY.to_string(); + let chunk = chunk! { + local name = $name + local entry = $entry + + function require(load_path) + return require_from(name , load_path) + end + local function init_mod() + return require(entry) + end + local mod_res = { + mod = init_mod() + } + mod_res["require"] = require + mods[name] = mod_res + require = nil + }; + lua.load(chunk) + .set_name(&format!("Load mod: {:?}", name2))? + .exec()?; + + Ok(()) +} + +pub(crate) fn run_event(event_name: &'static str) -> Result<(), Box> { + let res = storage::get_mut::(); + let lua = &res.lua; + let thread_name = format!("Event: {}", event_name); + let chunk = chunk! { + local event_name = $event_name + for mod_name, mod in pairs(mods) do + local event = mod.mod[event_name] + if event and type(event) == "function" then + require = mod.require + event() + end + end + require = nil + }; + lua.load(chunk).set_name(&thread_name)?.exec()?; + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index c5669aa1b5..99a4f7e55b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,6 +24,8 @@ pub mod resources; pub mod drawables; +mod lua; + pub use drawables::*; pub use physics::*; @@ -200,6 +202,9 @@ async fn init_game() -> Result { #[macroquad::main(window_conf)] async fn main() -> std::result::Result<(), Box> { + // println!("Starting embedded lua test"); + // core::test::test()?; + // println!("Ended embedded lua test"); use events::iter_events; let assets_dir = env::var(ASSETS_DIR_ENV_VAR).unwrap_or_else(|_| "./assets".to_string()); diff --git a/src/physics.rs b/src/physics.rs index a9f0c0e47e..a124e49951 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; use hecs::World; -use crate::{CollisionWorld, Map}; +use crate::{lua::run_event, CollisionWorld, Map, Resources}; use core::Transform; pub const GRAVITY: f32 = 2.5; @@ -187,6 +187,8 @@ pub fn fixed_update_physics_bodies(world: &mut World) { transform.position = collision_world.actor_pos(body.actor) - body.offset; } } + let _ = run_event("fixed_update_physics_bodies") + .map_err(|v| eprintln!("Ran into an error:\n{}", v)); } pub fn debug_draw_physics_bodies(world: &mut World) { diff --git a/src/player/events.rs b/src/player/events.rs index b68ba8fcfa..4913ccc822 100644 --- a/src/player/events.rs +++ b/src/player/events.rs @@ -67,12 +67,7 @@ impl From<&PlayerEvent> for PlayerEventKind { } pub fn update_player_events(world: &mut World) { - let query = core::query_builder::BuildStart::new() - .with::<&mut Player>() - .with::<&mut PlayerEventQueue>() - .query_mut(world); - for (_, (player, events)) in query { - // world.query_mut::<(&mut Player, &mut PlayerEventQueue)>() { + for (_, (player, events)) in world.query_mut::<(&mut Player, &mut PlayerEventQueue)>() { let dt = get_frame_time(); events.queue.push(PlayerEvent::Update { dt }); diff --git a/src/resources.rs b/src/resources.rs index ab4ea407c1..3bf6ffe67a 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, fs, path::Path}; +use std::{collections::HashMap, fs, os::unix::prelude::OsStrExt, path::Path}; use macroquad::{ audio::{load_sound, Sound}, @@ -15,8 +15,8 @@ use core::error::ErrorKind; use core::text::ToStringHelper; use core::{formaterr, Result}; -use crate::gui::GuiResources; -use crate::map::DecorationMetadata; +use crate::{gui::GuiResources, lua::init_lua}; +use crate::{lua::load_lua, map::DecorationMetadata}; use crate::player::PlayerCharacterMetadata; use crate::{items::MapItemMetadata, map::Map}; @@ -361,13 +361,14 @@ pub struct Resources { pub decoration: HashMap, pub items: HashMap, pub player_characters: HashMap, + pub lua: hv_lua::Lua, } impl Resources { pub async fn new>(assets_dir: P, mods_dir: P) -> Result { let assets_dir = assets_dir.as_ref(); let mods_dir = mods_dir.as_ref(); - + let lua = init_lua(mods_dir).unwrap(); let mut resources = Resources { assets_dir: assets_dir.to_string_helper(), mods_dir: mods_dir.to_string_helper(), @@ -381,6 +382,7 @@ impl Resources { maps: Vec::new(), items: HashMap::new(), player_characters: HashMap::new(), + lua, }; load_resources_from(assets_dir, &mut resources).await?; @@ -667,8 +669,11 @@ async fn load_mods>(mods_dir: P, resources: &mut Resources) -> Re } if !has_unmet_dependencies { + let name = mod_dir_path.file_name().unwrap().as_bytes().to_owned(); load_resources_from(mod_dir_path, resources).await?; - + if meta.kind == ModKind::Full { + load_lua(name, &resources.lua).unwrap(); + } #[cfg(debug_assertions)] println!("Loaded mod {} (v{})", &meta.id, &meta.version); From 8edc55b9d69d2c0cd8da83ed0e58bec61b3f802c Mon Sep 17 00:00:00 2001 From: lenscas Date: Mon, 7 Mar 2022 19:37:39 +0100 Subject: [PATCH 12/21] update to point to git for dependencies --- Cargo.lock | 12 ++++++++++++ Cargo.toml | 6 +++--- core/Cargo.toml | 10 +++++----- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a2d2de9865..8199be97ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -460,6 +460,7 @@ dependencies = [ [[package]] name = "hecs" version = "0.7.1" +source = "git+https://github.com/sdleffler/hv-dev#1ee2ef316a34e5561ace279ec9ca4b5c00621053" dependencies = [ "hashbrown 0.11.2", "spin 0.9.2", @@ -474,6 +475,7 @@ checksum = "8a164bb2ceaeff4f42542bdb847c41517c78a60f5649671b2a07312b6e117549" [[package]] name = "hv-alchemy" version = "0.1.0" +source = "git+https://github.com/sdleffler/hv-dev#1ee2ef316a34e5561ace279ec9ca4b5c00621053" dependencies = [ "hashbrown 0.11.2", "hv-atom", @@ -486,10 +488,12 @@ dependencies = [ [[package]] name = "hv-atom" version = "0.1.0" +source = "git+https://github.com/sdleffler/hv-dev#1ee2ef316a34e5561ace279ec9ca4b5c00621053" [[package]] name = "hv-cell" version = "0.1.0" +source = "git+https://github.com/sdleffler/hv-dev#1ee2ef316a34e5561ace279ec9ca4b5c00621053" dependencies = [ "hv-guarded-borrow", ] @@ -497,6 +501,7 @@ dependencies = [ [[package]] name = "hv-elastic" version = "0.4.1" +source = "git+https://github.com/sdleffler/hv-dev#1ee2ef316a34e5561ace279ec9ca4b5c00621053" dependencies = [ "hecs", "hv-cell", @@ -509,6 +514,7 @@ dependencies = [ [[package]] name = "hv-guarded-borrow" version = "0.1.1" +source = "git+https://github.com/sdleffler/hv-dev#1ee2ef316a34e5561ace279ec9ca4b5c00621053" dependencies = [ "hecs", ] @@ -516,6 +522,7 @@ dependencies = [ [[package]] name = "hv-lua" version = "0.6.6" +source = "git+https://github.com/sdleffler/hv-dev#1ee2ef316a34e5561ace279ec9ca4b5c00621053" dependencies = [ "bstr", "cc", @@ -542,6 +549,7 @@ dependencies = [ [[package]] name = "hv-lua-derive" version = "0.6.0" +source = "git+https://github.com/sdleffler/hv-dev#1ee2ef316a34e5561ace279ec9ca4b5c00621053" dependencies = [ "itertools", "once_cell", @@ -555,6 +563,7 @@ dependencies = [ [[package]] name = "hv-math" version = "0.1.0" +source = "git+https://github.com/sdleffler/hv-dev#1ee2ef316a34e5561ace279ec9ca4b5c00621053" dependencies = [ "approx", "hv-alchemy", @@ -566,6 +575,7 @@ dependencies = [ [[package]] name = "hv-stampede" version = "0.2.1" +source = "git+https://github.com/sdleffler/hv-dev#1ee2ef316a34e5561ace279ec9ca4b5c00621053" dependencies = [ "bumpalo", "spin 0.9.2", @@ -1546,6 +1556,7 @@ dependencies = [ [[package]] name = "tealr" version = "0.8.2" +source = "git+https://github.com/lenscas/tealr?branch=temporary/feature/add_support_for_hv_lua#5ef6ba2d98b5ca93f1ef5a4d809bc1ad10d1273b" dependencies = [ "bstr", "hv-lua", @@ -1557,6 +1568,7 @@ dependencies = [ [[package]] name = "tealr_derive" version = "0.8.2" +source = "git+https://github.com/lenscas/tealr?branch=temporary/feature/add_support_for_hv_lua#5ef6ba2d98b5ca93f1ef5a4d809bc1ad10d1273b" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 57179777df..d1598ed21d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,13 +23,13 @@ core = {path = "./core", package = "fishfight-core"} # ultimate = { path = "../FishFight-ultimate", package = "fishfight-ultimate", optional = true } ff-particles = {version = "0.1", features = ["serde"]} fishsticks = {git = "https://github.com/fishfight/fishsticks", default-features = false, features = ["gilrs"]} -hecs = {path = "../hv-dev/hv-ecs"} -hv-lua = {path = "../hv-dev/hv-lua"}#imported so its macro's work +hecs = {git = "https://github.com/sdleffler/hv-dev"} +hv-lua = {git = "https://github.com/sdleffler/hv-dev"}#imported so its macro's work macroquad = {version = "0.3.10"} macroquad-platformer = "0.1" serde = {version = "1.0", features = ["derive"]} serde_json = "1.0" -tealr = {path = "../tealr/tealr", features = ["mlua", "hv_lua", "mlua_vendored", "mlua_luajit", "mlua_serialize", "mlua_send", "derive"]} +tealr = {git = "https://github.com/lenscas/tealr", branch = "temporary/feature/add_support_for_hv_lua", features = ["mlua", "hv_lua", "mlua_vendored", "mlua_luajit", "mlua_serialize", "mlua_send", "derive"]} [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = "0.2.74" diff --git a/core/Cargo.toml b/core/Cargo.toml index 9b65fc6f60..308e575cdb 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -8,14 +8,14 @@ version = "0.4.2" [dependencies] async-trait = "0.1.52" fishsticks = {git = "https://github.com/fishfight/fishsticks", default-features = false, features = ["gilrs"]} -hecs = {path = "../../hv-dev/hv-ecs"} -hv-alchemy = {path = "../../hv-dev/hv/crates/hv-alchemy"} -hv-cell = {path = "../../hv-dev/hv/crates/hv-cell"} -hv-lua = {path = "../../hv-dev/hv-lua"}#imported so its macro's work +hecs = {git = "https://github.com/sdleffler/hv-dev"} +hv-alchemy = {git = "https://github.com/sdleffler/hv-dev"} +hv-cell = {git = "https://github.com/sdleffler/hv-dev"} +hv-lua = {git = "https://github.com/sdleffler/hv-dev"}#imported so its macro's work macroquad = {version = "0.3.10"} serde = {version = "1.0", package = "serde", features = ["derive"]} serde_json = {version = "1.0"} -tealr = {path = "../../tealr/tealr", features = ["mlua", "hv_lua", "mlua_macros", "mlua_vendored", "mlua_luajit", "mlua_serialize", "derive"]} +tealr = {git = "https://github.com/lenscas/tealr", branch = "temporary/feature/add_support_for_hv_lua", features = ["mlua", "hv_lua", "mlua_macros", "mlua_vendored", "mlua_luajit", "mlua_serialize", "derive"]} toml = "0.5" [target.'cfg(target_arch = "wasm32")'.dependencies] From 89a0d2e753642f5706b53a838fddc0d503a5900e Mon Sep 17 00:00:00 2001 From: lenscas Date: Tue, 8 Mar 2022 16:59:08 +0100 Subject: [PATCH 13/21] start exposing world to lua --- Cargo.lock | 1 + Cargo.toml | 1 + core/src/test.rs | 4 +- mods/test_lua_mod_one/fishfight_mod.json | 2 +- mods/test_lua_mod_one/main.lua | 23 +++++- src/drawables/animated_sprite.rs | 6 +- src/drawables/mod.rs | 12 ++- src/ecs.rs | 9 ++- src/effects/active/mod.rs | 5 +- src/effects/active/projectiles.rs | 7 +- src/effects/active/triggered.rs | 7 +- src/game/mod.rs | 17 +++-- src/lua.rs | 85 +++++++++++++++------ src/map/sproinger.rs | 5 +- src/network.rs | 15 ++-- src/particles.rs | 8 +- src/physics.rs | 94 +++++++++++++----------- src/player/animation.rs | 6 +- src/player/controller.rs | 5 +- src/player/events.rs | 6 +- src/player/inventory.rs | 10 ++- src/player/mod.rs | 5 +- src/player/state.rs | 11 ++- src/resources.rs | 4 +- 24 files changed, 235 insertions(+), 113 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8199be97ef..41cd27fac8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -311,6 +311,7 @@ dependencies = [ "fishfight-core", "fishsticks", "hecs", + "hv-cell", "hv-lua", "macroquad", "macroquad-platformer", diff --git a/Cargo.toml b/Cargo.toml index d1598ed21d..3b06e86755 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ core = {path = "./core", package = "fishfight-core"} ff-particles = {version = "0.1", features = ["serde"]} fishsticks = {git = "https://github.com/fishfight/fishsticks", default-features = false, features = ["gilrs"]} hecs = {git = "https://github.com/sdleffler/hv-dev"} +hv-cell = {git = "https://github.com/sdleffler/hv-dev"} hv-lua = {git = "https://github.com/sdleffler/hv-dev"}#imported so its macro's work macroquad = {version = "0.3.10"} macroquad-platformer = "0.1" diff --git a/core/src/test.rs b/core/src/test.rs index 11d9e473e0..e59ac3c502 100644 --- a/core/src/test.rs +++ b/core/src/test.rs @@ -10,7 +10,7 @@ use tealr::mlu::mlua::{ }; #[derive(Debug, Clone, Copy)] -struct I32Component(i32); +pub struct I32Component(i32); impl UserData for I32Component { #[allow(clippy::unit_arg)] fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { @@ -37,7 +37,7 @@ impl UserData for I32Component { } } #[derive(Debug, Clone, Copy)] -struct BoolComponent(bool); +pub struct BoolComponent(bool); impl UserData for BoolComponent { #[allow(clippy::unit_arg)] fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { diff --git a/mods/test_lua_mod_one/fishfight_mod.json b/mods/test_lua_mod_one/fishfight_mod.json index b2f0016ff9..79308e437d 100644 --- a/mods/test_lua_mod_one/fishfight_mod.json +++ b/mods/test_lua_mod_one/fishfight_mod.json @@ -1,5 +1,5 @@ { - "id": "test_lua_mod_one", + "id": "test_lua_mod_one_id_is_different", "name": "Test Lua Mod One", "description": "This is a mod meant for testing the lua integration", "version": "0.1.0", diff --git a/mods/test_lua_mod_one/main.lua b/mods/test_lua_mod_one/main.lua index dbdb89afe1..ebfa7a2a7d 100644 --- a/mods/test_lua_mod_one/main.lua +++ b/mods/test_lua_mod_one/main.lua @@ -1,7 +1,26 @@ print("Hello from lua mod!") require "second_file" +local entity; return { - fixed_update_physics_bodies = function() - print("Hello from fixed_update_physics_body") + init = function(world) + print "Run init" + entity = world:spawn { I32.new(5), Bool.new(true) } + end, + fixed_update_physics_bodies = function(world) + local Query = hv.ecs.Query + local query = Query.new { Query.write(I32), Query.read(Bool) } + world:query_one(query, entity, function(item) + print("Got item:",item) + --Querying allows us to access components of our item as userdata objects through the same interface + --we defined above! + print("asserting if still true") + assert(item:take(Bool).value == true) + local i = item:take(I32) + print("asserting if still bigger than 5") + assert(i.value >= 5) + print("time to increment by 1") + i.value = i.value + 1 + print("Current value:", i.value) + end) end } \ No newline at end of file diff --git a/src/drawables/animated_sprite.rs b/src/drawables/animated_sprite.rs index 948ae0d44e..42ac2eb024 100644 --- a/src/drawables/animated_sprite.rs +++ b/src/drawables/animated_sprite.rs @@ -1,8 +1,9 @@ -use std::borrow::BorrowMut; use std::collections::HashMap; use std::iter::FromIterator; use std::ops::Mul; +use std::{borrow::BorrowMut, sync::Arc}; +use hv_cell::AtomicRefCell; use macroquad::color; use macroquad::experimental::animation::Animation as MQAnimation; use macroquad::experimental::collections::storage; @@ -258,7 +259,8 @@ impl AnimatedSprite { } } -pub fn update_animated_sprites(world: &mut World) { +pub fn update_animated_sprites(world: Arc>) { + let mut world = AtomicRefCell::borrow_mut(world.as_ref()); for (_, drawable) in world.query_mut::<&mut Drawable>() { match drawable.kind.borrow_mut() { DrawableKind::AnimatedSprite(sprite) => { diff --git a/src/drawables/mod.rs b/src/drawables/mod.rs index 4c3388253a..93d9412256 100644 --- a/src/drawables/mod.rs +++ b/src/drawables/mod.rs @@ -2,8 +2,12 @@ mod animated_sprite; mod sprite; pub use animated_sprite::*; +use hv_cell::AtomicRefCell; pub use sprite::*; -use std::borrow::{Borrow, BorrowMut}; +use std::{ + borrow::{Borrow, BorrowMut}, + sync::Arc, +}; use macroquad::prelude::*; @@ -129,7 +133,8 @@ pub enum DrawableKind { AnimatedSpriteSet(AnimatedSpriteSet), } -pub fn draw_drawables(world: &mut World) { +pub fn draw_drawables(world: Arc>) { + let mut world = AtomicRefCell::borrow_mut(world.as_ref()); let mut ordered = world .query_mut::<&Drawable>() .into_iter() @@ -165,7 +170,8 @@ pub fn draw_drawables(world: &mut World) { } } -pub fn debug_draw_drawables(world: &mut World) { +pub fn debug_draw_drawables(world: Arc>) { + let mut world = AtomicRefCell::borrow_mut(world.as_ref()); let mut ordered = world .query_mut::<&Drawable>() .into_iter() diff --git a/src/ecs.rs b/src/ecs.rs index 1be6ae683a..6c6b627321 100644 --- a/src/ecs.rs +++ b/src/ecs.rs @@ -1,6 +1,9 @@ +use std::sync::Arc; + use hecs::{Entity, World}; +use hv_cell::AtomicRefCell; -pub type SystemFn = fn(&mut World); +pub type SystemFn = fn(Arc>); /// This is used as a component to signify ownership pub struct Owner(pub Entity); @@ -53,9 +56,9 @@ impl Scheduler { SchedulerBuilder::default() } - pub fn execute(&mut self, world: &mut World) { + pub fn execute(&mut self, world: Arc>) { for f in &mut self.steps { - f(world); + f(world.clone()); } } } diff --git a/src/effects/active/mod.rs b/src/effects/active/mod.rs index b80d691fe5..e7b6fae3c8 100644 --- a/src/effects/active/mod.rs +++ b/src/effects/active/mod.rs @@ -1,4 +1,5 @@ use hecs::{Entity, World}; +use hv_cell::AtomicRefCell; use macroquad::audio::play_sound_once; use macroquad::color; @@ -9,6 +10,7 @@ use serde::{Deserialize, Serialize}; use core::math::{deg_to_rad, rotate_vector, IsZero}; use core::Result; +use std::sync::Arc; use crate::Resources; use crate::{PassiveEffectInstance, PassiveEffectMetadata}; @@ -284,7 +286,8 @@ pub enum ActiveEffectKind { }, } -pub fn debug_draw_active_effects(world: &mut World) { +pub fn debug_draw_active_effects(world: Arc>) { + let mut world = AtomicRefCell::borrow_mut(world.as_ref()); let mut to_remove = Vec::new(); let dt = get_frame_time(); diff --git a/src/effects/active/projectiles.rs b/src/effects/active/projectiles.rs index dcbd69e46c..5809cccb9b 100644 --- a/src/effects/active/projectiles.rs +++ b/src/effects/active/projectiles.rs @@ -1,6 +1,8 @@ +use hv_cell::AtomicRefCell; use macroquad::experimental::collections::storage; use macroquad::prelude::*; use std::f32::consts::PI; +use std::sync::Arc; use hecs::{Entity, World}; use macroquad_platformer::Tile; @@ -203,7 +205,8 @@ enum ProjectileCollision { Map, } -pub fn fixed_update_projectiles(world: &mut World) { +pub fn fixed_update_projectiles(world: Arc>) { + let mut world = AtomicRefCell::borrow_mut(world.as_ref()); let bodies = world .query::<(&Transform, &PhysicsBody)>() .iter() @@ -272,7 +275,7 @@ pub fn fixed_update_projectiles(world: &mut World) { if let Some(collision_kind) = collision { match collision_kind { ProjectileCollision::Player(damage_to_entity) => { - on_player_damage(world, damage_from_entity, damage_to_entity); + on_player_damage(&mut world, damage_from_entity, damage_to_entity); } ProjectileCollision::Trigger(trigger_entity) => { let mut effect = world.get_mut::(trigger_entity).unwrap(); diff --git a/src/effects/active/triggered.rs b/src/effects/active/triggered.rs index c934e08067..2641412038 100644 --- a/src/effects/active/triggered.rs +++ b/src/effects/active/triggered.rs @@ -1,3 +1,4 @@ +use hv_cell::AtomicRefCell; use macroquad::experimental::collections::storage; use macroquad::prelude::*; @@ -7,6 +8,7 @@ use serde::{Deserialize, Serialize}; use core::math::deg_to_rad; use core::{Result, Transform}; +use std::sync::Arc; use crate::effects::active::spawn_active_effect; use crate::particles::{ParticleEmitter, ParticleEmitterMetadata}; @@ -156,7 +158,8 @@ pub fn spawn_triggered_effect( const KICK_FORCE: f32 = 15.0; const KICK_DELAY: f32 = 0.22; -pub fn fixed_update_triggered_effects(world: &mut World) { +pub fn fixed_update_triggered_effects(world: Arc>) { + let mut world = AtomicRefCell::borrow_mut(world.as_ref()); let dt = get_frame_time(); let mut to_trigger = Vec::new(); @@ -266,7 +269,7 @@ pub fn fixed_update_triggered_effects(world: &mut World) { for (e, _, owner, origin, effects) in to_trigger.drain(0..) { for params in effects { - if let Err(err) = spawn_active_effect(world, owner, origin, params) { + if let Err(err) = spawn_active_effect(&mut world, owner, origin, params) { #[cfg(debug_assertions)] println!("WARNING: {}", err); } diff --git a/src/game/mod.rs b/src/game/mod.rs index 45e8cb4583..c819745d81 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -5,20 +5,22 @@ pub use camera::GameCamera; use fishsticks::{Button, GamepadContext}; +use hv_cell::AtomicRefCell; use macroquad::experimental::collections::storage; use macroquad::experimental::scene::{Node, RefMut}; use macroquad::prelude::*; use macroquad::ui::root_ui; use hecs::{Entity, World}; -use tealr::mlu::mlua::Lua; use core::input::is_gamepad_btn_pressed; use core::Result; +use std::sync::Arc; use crate::debug; use crate::ecs::Scheduler; use crate::gui::{self, GAME_MENU_RESULT_MAIN_MENU, GAME_MENU_RESULT_QUIT}; +use crate::lua::run_event; use crate::physics::{debug_draw_physics_bodies, fixed_update_physics_bodies}; use crate::player::{ draw_weapons_hud, spawn_player, update_player_animations, update_player_camera_box, @@ -51,7 +53,7 @@ pub enum GameMode { } pub struct Game { - world: World, + world: Arc>, #[allow(dead_code)] players: Vec, updates: Scheduler, @@ -149,7 +151,8 @@ impl Game { .with_thread_local(debug_draw_rigid_bodies) .with_thread_local(debug_draw_active_effects) .build(); - + let world = Arc::new(AtomicRefCell::new(world)); + let _ = run_event("init", world.clone()); let res = Game { world, players, @@ -164,7 +167,7 @@ impl Game { } fn on_update(&mut self) { - self.updates.execute(&mut self.world); + self.updates.execute(self.world.clone()); #[cfg(debug_assertions)] if is_key_pressed(macroquad::prelude::KeyCode::U) { @@ -182,7 +185,7 @@ impl Game { } fn on_fixed_update(&mut self) { - self.fixed_updates.execute(&mut self.world); + self.fixed_updates.execute(self.world.clone()); } fn on_draw(&mut self) { @@ -194,11 +197,11 @@ impl Game { map.draw(None, true); } - self.draws.execute(&mut self.world); + self.draws.execute(self.world.clone()); #[cfg(debug_assertions)] if debug::is_debug_draw_enabled() { - self.debug_draws.execute(&mut self.world); + self.debug_draws.execute(self.world.clone()); } if gui::is_game_menu_open() { diff --git a/src/lua.rs b/src/lua.rs index ff5e475042..80ab707b24 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -1,6 +1,9 @@ -use std::{error::Error, os::unix::prelude::OsStrExt, path::Path}; +use core::test::{BoolComponent, I32Component}; +use std::{error::Error, os::unix::prelude::OsStrExt, path::Path, sync::Arc}; -use hv_lua::{chunk, Function, Lua}; +use hecs::World; +use hv_cell::AtomicRefCell; +use hv_lua::{chunk, hv::types, Function, Lua, Table}; use macroquad::prelude::collections::storage; use crate::Resources; @@ -9,11 +12,16 @@ const LUA_ENTRY: &str = "main"; pub(crate) fn init_lua(mod_dir: &Path) -> Result> { let lua = Lua::new(); + let hv = types(&lua)?; + let i32_ty = lua.create_userdata_type::()?; + let bool_ty = lua.create_userdata_type::()?; let dir = mod_dir.as_os_str().as_bytes().to_owned(); { let globals = lua.globals(); //a table containing all the mods globals.set("mods", lua.create_table()?)?; + //this table is used to have quick access to every event that needs to run. + globals.set("events", lua.create_table()?)?; //we don't want users to simply use `require` to load their files as that will either result in conflicts or annoying path names //to drive this point home, I rename the `require` function here and add 2 other functions to load mod files @@ -21,17 +29,27 @@ pub(crate) fn init_lua(mod_dir: &Path) -> Result> { globals.set("require_lib", req)?; globals.set("require", hv_lua::Nil)?; + globals.set("hv", hv)?; + globals.set("I32", i32_ty)?; + globals.set("Bool", bool_ty)?; + //this function allows people to load a file from arbitrary mods //this allows "library only" mods to exist. //there will also be a function that loads from the current mod. However, that one needs to be defined when loading the mod let load_any_mod_file = lua.create_function( move |lua, (from_mod, path): (hv_lua::String, hv_lua::String)| { //TODO: a way to go from `mod id` to `mod folder` - let req = lua.globals().get::<_, Function>("require_lib")?; + let globals = lua.globals(); + let req = globals.get::<_, Function>("require_lib")?; + let mod_folder = globals + .get::<_, Table>("mods")? + .get::<_, Table>(from_mod)? + .get::<_, hv_lua::String>("dir_name")?; + let mut full_path = Vec::new(); full_path.extend_from_slice(&dir); full_path.extend_from_slice(b"."); - full_path.extend_from_slice(from_mod.as_bytes()); + full_path.extend_from_slice(mod_folder.as_bytes()); full_path.extend_from_slice(b"."); full_path.extend_from_slice(path.as_bytes()); let full_path = lua.create_string(&full_path)?; @@ -43,15 +61,19 @@ pub(crate) fn init_lua(mod_dir: &Path) -> Result> { Ok(lua) } -pub(crate) fn load_lua>(mod_name: P, lua: &Lua) -> Result<(), Box> { - //I want to use a lua string but... those get turned into `nil` for some reason? - //probably a bug in mlua/hv-lua that needs to be tackled - let name = String::from_utf8_lossy(mod_name.as_ref()); - //a nice copy so the error message can easily specify what mod it failed to load - let name2 = String::from_utf8_lossy(mod_name.as_ref()); +pub(crate) fn load_lua>( + mod_id: String, + mod_folder: P, + lua: &Lua, +) -> Result<(), Box> { + let name = mod_id; + let name_to_transfer = name.clone(); + //ideally, we use a lua string but... those don't get transferred properly for some reason.... + let dir = String::from_utf8_lossy(mod_folder.as_ref()); let entry = LUA_ENTRY.to_string(); let chunk = chunk! { - local name = $name + local name = $name_to_transfer + local dir = $dir local entry = $entry function require(load_path) @@ -60,31 +82,50 @@ pub(crate) fn load_lua>(mod_name: P, lua: &Lua) -> Result<(), Box local function init_mod() return require(entry) end - local mod_res = { - mod = init_mod() + local mod_config = { + dir_name = dir, + require = require, + mod_id = name } - mod_res["require"] = require - mods[name] = mod_res + mods[name] = mod_config + + local mod_events = init_mod() + mod_config["events"] = mod_events + if type(mod_events) == "table" then + for k, _ in pairs(mod_events) do + local event_list = events[k] or {} + table.insert(event_list, mod_config) + events[k] = event_list + end + end require = nil }; lua.load(chunk) - .set_name(&format!("Load mod: {:?}", name2))? + .set_name(&format!("Load mod: {:?}", name))? .exec()?; Ok(()) } -pub(crate) fn run_event(event_name: &'static str) -> Result<(), Box> { +pub(crate) fn run_event( + event_name: &'static str, + world: Arc>, +) -> Result<(), Box> { let res = storage::get_mut::(); let lua = &res.lua; let thread_name = format!("Event: {}", event_name); let chunk = chunk! { + local world = $world local event_name = $event_name - for mod_name, mod in pairs(mods) do - local event = mod.mod[event_name] - if event and type(event) == "function" then - require = mod.require - event() + local events_to_run = events[event_name] or {} + for _ , mod_config in ipairs(events_to_run) do + require = mod_config.require + event = mod_config.events[event_name] + if type(event) == "function" then + local isSuccess, err = pcall(event,world) + if not isSuccess then + io.stderr:write("Error while calling: `",event_name, "` from mod: `",mod_config.mod_id,"` Error:\n",err,"\n") + end end end require = nil diff --git a/src/map/sproinger.rs b/src/map/sproinger.rs index 6f515bc681..bb5dffed59 100644 --- a/src/map/sproinger.rs +++ b/src/map/sproinger.rs @@ -1,7 +1,9 @@ +use hv_cell::AtomicRefCell; use macroquad::audio::play_sound_once; use macroquad::experimental::collections::storage; use macroquad::prelude::*; use std::collections::HashMap; +use std::sync::Arc; use hecs::{Entity, World}; @@ -82,7 +84,8 @@ pub fn spawn_sproinger(world: &mut World, position: Vec2) -> Result { Ok(entity) } -pub fn fixed_update_sproingers(world: &mut World) { +pub fn fixed_update_sproingers(world: Arc>) { + let mut world = AtomicRefCell::borrow_mut(world.as_ref()); let dt = get_frame_time(); let bodies = world diff --git a/src/network.rs b/src/network.rs index 860b4884ac..78ccc39c22 100644 --- a/src/network.rs +++ b/src/network.rs @@ -1,23 +1,26 @@ //! This module holds the networking core, used +use std::sync::Arc; + use hecs::World; +use hv_cell::AtomicRefCell; -pub fn update_network_client(world: &mut World) { +pub fn update_network_client(world: Arc>) { update_network_common(world); } -pub fn fixed_update_network_client(world: &mut World) { +pub fn fixed_update_network_client(world: Arc>) { fixed_update_network_common(world); } -pub fn update_network_host(world: &mut World) { +pub fn update_network_host(world: Arc>) { update_network_common(world); } -pub fn fixed_update_network_host(world: &mut World) { +pub fn fixed_update_network_host(world: Arc>) { fixed_update_network_common(world); } -fn update_network_common(_world: &mut World) {} +fn update_network_common(_world: Arc>) {} -fn fixed_update_network_common(_world: &mut World) {} +fn fixed_update_network_common(_world: Arc>) {} diff --git a/src/particles.rs b/src/particles.rs index dedd948a30..2bca244364 100644 --- a/src/particles.rs +++ b/src/particles.rs @@ -1,6 +1,7 @@ +use hv_cell::AtomicRefCell; use macroquad::experimental::collections::storage; use macroquad::prelude::*; -use std::collections::HashMap; +use std::{collections::HashMap, sync::Arc}; use ff_particles::EmittersCache; @@ -165,7 +166,8 @@ pub fn update_one_particle_emitter( } } -pub fn update_particle_emitters(world: &mut World) { +pub fn update_particle_emitters(world: Arc>) { + let mut world = AtomicRefCell::borrow_mut(world.as_ref()); for (_, (transform, emitter)) in world.query_mut::<(&Transform, &mut ParticleEmitter)>() { update_one_particle_emitter(transform.position, transform.rotation, emitter); } @@ -177,7 +179,7 @@ pub fn update_particle_emitters(world: &mut World) { } } -pub fn draw_particles(_world: &mut World) { +pub fn draw_particles(_world: Arc>) { let mut particles = storage::get_mut::(); for cache in particles.cache_map.values_mut() { diff --git a/src/physics.rs b/src/physics.rs index a124e49951..d76443ca00 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -1,3 +1,4 @@ +use hv_cell::AtomicRefCell; use macroquad::color; use macroquad::experimental::collections::storage; use macroquad::prelude::*; @@ -8,8 +9,9 @@ use serde::{Deserialize, Serialize}; use hecs::World; -use crate::{lua::run_event, CollisionWorld, Map, Resources}; +use crate::{lua::run_event, CollisionWorld, Map}; use core::Transform; +use std::sync::Arc; pub const GRAVITY: f32 = 2.5; pub const TERMINAL_VELOCITY: f32 = 10.0; @@ -131,67 +133,71 @@ impl PhysicsBody { } } -pub fn fixed_update_physics_bodies(world: &mut World) { - let mut collision_world = storage::get_mut::(); +pub fn fixed_update_physics_bodies(world: Arc>) { + { + let mut world = AtomicRefCell::borrow_mut(world.as_ref()); + let mut collision_world = storage::get_mut::(); - for (_, (transform, body)) in world.query_mut::<(&mut Transform, &mut PhysicsBody)>() { - collision_world.set_actor_position(body.actor, transform.position + body.offset); + for (_, (transform, body)) in world.query_mut::<(&mut Transform, &mut PhysicsBody)>() { + collision_world.set_actor_position(body.actor, transform.position + body.offset); - if !body.is_deactivated { - let position = collision_world.actor_pos(body.actor); + if !body.is_deactivated { + let position = collision_world.actor_pos(body.actor); - { - let position = position + vec2(0.0, 1.0); + { + let position = position + vec2(0.0, 1.0); - body.was_on_ground = body.is_on_ground; + body.was_on_ground = body.is_on_ground; - body.is_on_ground = collision_world.collide_check(body.actor, position); + body.is_on_ground = collision_world.collide_check(body.actor, position); - // FIXME: Using this to set `is_on_ground` caused weird glitching behavior when jumping up through platforms - let tile = collision_world.collide_solids( - position, - body.size.x as i32, - body.size.y as i32, - ); + // FIXME: Using this to set `is_on_ground` caused weird glitching behavior when jumping up through platforms + let tile = collision_world.collide_solids( + position, + body.size.x as i32, + body.size.y as i32, + ); - body.is_on_platform = tile == Tile::JumpThrough; - } + body.is_on_platform = tile == Tile::JumpThrough; + } - if !body.is_on_ground && body.has_mass { - body.velocity.y += body.gravity; + if !body.is_on_ground && body.has_mass { + body.velocity.y += body.gravity; - if body.velocity.y > TERMINAL_VELOCITY { - body.velocity.y = TERMINAL_VELOCITY; + if body.velocity.y > TERMINAL_VELOCITY { + body.velocity.y = TERMINAL_VELOCITY; + } } - } - if !collision_world.move_h(body.actor, body.velocity.x) { - body.velocity.x *= -body.bouncyness; - } + if !collision_world.move_h(body.actor, body.velocity.x) { + body.velocity.x *= -body.bouncyness; + } - if !collision_world.move_v(body.actor, body.velocity.y) { - body.velocity.y *= -body.bouncyness; - } + if !collision_world.move_v(body.actor, body.velocity.y) { + body.velocity.y *= -body.bouncyness; + } - if body.can_rotate { - apply_rotation(transform, &mut body.velocity, body.is_on_ground); - } + if body.can_rotate { + apply_rotation(transform, &mut body.velocity, body.is_on_ground); + } - if body.is_on_ground && body.has_friction { - body.velocity.x *= FRICTION_LERP; - if body.velocity.x.abs() <= STOP_THRESHOLD { - body.velocity.x = 0.0; + if body.is_on_ground && body.has_friction { + body.velocity.x *= FRICTION_LERP; + if body.velocity.x.abs() <= STOP_THRESHOLD { + body.velocity.x = 0.0; + } } - } - transform.position = collision_world.actor_pos(body.actor) - body.offset; + transform.position = collision_world.actor_pos(body.actor) - body.offset; + } } } - let _ = run_event("fixed_update_physics_bodies") + let _ = run_event("fixed_update_physics_bodies", world) .map_err(|v| eprintln!("Ran into an error:\n{}", v)); } -pub fn debug_draw_physics_bodies(world: &mut World) { +pub fn debug_draw_physics_bodies(world: Arc>) { + let world = AtomicRefCell::borrow(world.as_ref()); for (_, (transform, body)) in world.query::<(&Transform, &PhysicsBody)>().iter() { if !body.is_deactivated { let rect = body.as_rect(transform.position); @@ -257,7 +263,8 @@ impl RigidBody { } } -pub fn fixed_update_rigid_bodies(world: &mut World) { +pub fn fixed_update_rigid_bodies(world: Arc>) { + let mut world = AtomicRefCell::borrow_mut(world.as_ref()); for (_, (transform, body)) in world.query_mut::<(&mut Transform, &mut RigidBody)>() { transform.position += body.velocity; @@ -267,7 +274,8 @@ pub fn fixed_update_rigid_bodies(world: &mut World) { } } -pub fn debug_draw_rigid_bodies(world: &mut World) { +pub fn debug_draw_rigid_bodies(world: Arc>) { + let world = AtomicRefCell::borrow(world.as_ref()); for (_, (transform, body)) in world.query::<(&Transform, &RigidBody)>().iter() { let rect = body.as_rect(transform.position); diff --git a/src/player/animation.rs b/src/player/animation.rs index 967d609dfb..4cbfbc838c 100644 --- a/src/player/animation.rs +++ b/src/player/animation.rs @@ -1,3 +1,6 @@ +use std::sync::Arc; + +use hv_cell::AtomicRefCell; use macroquad::prelude::*; use hecs::World; @@ -349,7 +352,8 @@ impl PlayerAnimations { } } -pub fn update_player_animations(world: &mut World) { +pub fn update_player_animations(world: Arc>) { + let mut world = AtomicRefCell::borrow_mut(world.as_ref()); for (_, (player, inventory, body, drawable)) in world.query_mut::<(&Player, &mut PlayerInventory, &PhysicsBody, &mut Drawable)>() { diff --git a/src/player/controller.rs b/src/player/controller.rs index 13db86d20e..fdfdbe338c 100644 --- a/src/player/controller.rs +++ b/src/player/controller.rs @@ -1,10 +1,12 @@ use hecs::World; +use hv_cell::AtomicRefCell; use macroquad::prelude::*; use core::network::PlayerId; use core::input::{collect_local_input, GameInputScheme, PlayerInput}; +use std::sync::Arc; #[derive(Debug, Clone)] pub enum PlayerControllerKind { @@ -78,7 +80,8 @@ impl PlayerController { } } -pub fn update_player_controllers(world: &mut World) { +pub fn update_player_controllers(world: Arc>) { + let mut world = AtomicRefCell::borrow_mut(world.as_ref()); for (_, controller) in world.query_mut::<&mut PlayerController>() { let input = match &controller.kind { PlayerControllerKind::LocalInput(input_scheme) => collect_local_input(*input_scheme), diff --git a/src/player/events.rs b/src/player/events.rs index 4913ccc822..07652a8db7 100644 --- a/src/player/events.rs +++ b/src/player/events.rs @@ -1,4 +1,7 @@ +use std::sync::Arc; + use hecs::{Entity, World}; +use hv_cell::AtomicRefCell; use macroquad::time::get_frame_time; use crate::player::{Player, PlayerState}; @@ -66,7 +69,8 @@ impl From<&PlayerEvent> for PlayerEventKind { } } -pub fn update_player_events(world: &mut World) { +pub fn update_player_events(world: Arc>) { + let mut world = AtomicRefCell::borrow_mut(world.as_ref()); for (_, (player, events)) in world.query_mut::<(&mut Player, &mut PlayerEventQueue)>() { let dt = get_frame_time(); diff --git a/src/player/inventory.rs b/src/player/inventory.rs index ae801413a7..a1d9461da2 100644 --- a/src/player/inventory.rs +++ b/src/player/inventory.rs @@ -1,8 +1,10 @@ +use hv_cell::AtomicRefCell; use macroquad::prelude::*; use hecs::{Entity, With, Without, World}; use core::Transform; +use std::sync::Arc; use crate::items::{ fire_weapon, ItemDepleteBehavior, ItemDropBehavior, Weapon, EFFECT_ANIMATED_SPRITE_ID, @@ -52,7 +54,8 @@ impl PlayerInventory { } } -pub fn update_player_inventory(world: &mut World) { +pub fn update_player_inventory(world: Arc>) { + let mut world = AtomicRefCell::borrow_mut(world.as_ref()); let mut item_colliders = world .query::>>() .iter() @@ -424,7 +427,7 @@ pub fn update_player_inventory(world: &mut World) { } for (entity, owner) in to_fire.drain(0..) { - if let Err(err) = fire_weapon(world, entity, owner) { + if let Err(err) = fire_weapon(&mut world, entity, owner) { #[cfg(debug_assertions)] println!("WARNING: {}", err); } @@ -456,7 +459,8 @@ const HUD_USE_COUNT_COLOR_EMPTY: Color = Color { a: 0.8, }; -pub fn draw_weapons_hud(world: &mut World) { +pub fn draw_weapons_hud(world: Arc>) { + let world = AtomicRefCell::borrow(world.as_ref()); for (_, (transform, inventory)) in world.query::<(&Transform, &PlayerInventory)>().iter() { if let Some(weapon_entity) = inventory.weapon { let weapon = world.get::(weapon_entity).unwrap(); diff --git a/src/player/mod.rs b/src/player/mod.rs index 0eae96af33..cafc7f33e8 100644 --- a/src/player/mod.rs +++ b/src/player/mod.rs @@ -1,9 +1,11 @@ +use hv_cell::AtomicRefCell; use macroquad::experimental::collections::storage; use macroquad::prelude::*; use hecs::{Entity, World}; use core::Transform; +use std::sync::Arc; use crate::{ AnimatedSprite, AnimatedSpriteMetadata, AnimatedSpriteParams, CollisionWorld, Drawable, @@ -94,7 +96,8 @@ impl Player { } } -pub fn update_player_camera_box(world: &mut World) { +pub fn update_player_camera_box(world: Arc>) { + let mut world = AtomicRefCell::borrow_mut(world.as_ref()); for (_, (transform, player)) in world.query_mut::<(&Transform, &mut Player)>() { let rect = Rect::new(transform.position.x, transform.position.y, 32.0, 60.0); diff --git a/src/player/state.rs b/src/player/state.rs index efdd436426..f40773e2bb 100644 --- a/src/player/state.rs +++ b/src/player/state.rs @@ -1,3 +1,4 @@ +use hv_cell::AtomicRefCell; use macroquad::audio::play_sound_once; use macroquad::experimental::collections::storage; use macroquad::prelude::*; @@ -5,6 +6,7 @@ use macroquad::prelude::*; use hecs::{Entity, World}; use core::Transform; +use std::sync::Arc; use crate::player::{ Player, PlayerAttributes, PlayerController, PlayerEventQueue, JUMP_SOUND_ID, LAND_SOUND_ID, @@ -33,7 +35,8 @@ impl Default for PlayerState { } } -pub fn update_player_states(world: &mut World) { +pub fn update_player_states(world: Arc>) { + let mut world = AtomicRefCell::borrow_mut(world.as_ref()); let query = world.query_mut::<( &mut Transform, &mut Player, @@ -190,9 +193,9 @@ pub fn update_player_states(world: &mut World) { } } -pub fn update_player_passive_effects(world: &mut World) { +pub fn update_player_passive_effects(world: Arc>) { let mut function_calls = Vec::new(); - + let mut world = AtomicRefCell::borrow_mut(world.as_ref()); for (entity, (player, events)) in world.query::<(&mut Player, &mut PlayerEventQueue)>().iter() { let dt = get_frame_time(); @@ -228,7 +231,7 @@ pub fn update_player_passive_effects(world: &mut World) { } for (f, player_entity, item_entity, event) in function_calls.drain(0..) { - f(world, player_entity, item_entity, event); + f(&mut world, player_entity, item_entity, event); } } diff --git a/src/resources.rs b/src/resources.rs index 3bf6ffe67a..fe528c63c2 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -669,10 +669,10 @@ async fn load_mods>(mods_dir: P, resources: &mut Resources) -> Re } if !has_unmet_dependencies { - let name = mod_dir_path.file_name().unwrap().as_bytes().to_owned(); + let path = mod_dir_path.file_name().unwrap().as_bytes().to_owned(); load_resources_from(mod_dir_path, resources).await?; if meta.kind == ModKind::Full { - load_lua(name, &resources.lua).unwrap(); + load_lua(meta.id.to_owned(), path, &resources.lua).unwrap(); } #[cfg(debug_assertions)] println!("Loaded mod {} (v{})", &meta.id, &meta.version); From ba7f3a731f7e159bda09dbb104c8d0cf9765e724 Mon Sep 17 00:00:00 2001 From: lenscas Date: Wed, 9 Mar 2022 13:57:49 +0100 Subject: [PATCH 14/21] improve ease of exposing component types --- core/src/lib.rs | 1 + core/src/lua/create_component.rs | 168 +++++++++++++++++++++++++++++++ core/src/lua/mod.rs | 112 +++++++++++++++++++++ mods/test_lua_mod_one/main.lua | 4 + src/lua.rs | 117 +++------------------ src/resources.rs | 13 ++- 6 files changed, 308 insertions(+), 107 deletions(-) create mode 100644 core/src/lua/create_component.rs create mode 100644 core/src/lua/mod.rs diff --git a/core/src/lib.rs b/core/src/lib.rs index 4ca1ca1182..6a65e05041 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -21,4 +21,5 @@ pub use async_trait::async_trait; pub use serde; pub use serde_json; +pub mod lua; pub mod test; diff --git a/core/src/lua/create_component.rs b/core/src/lua/create_component.rs new file mode 100644 index 0000000000..fdfc34c8d4 --- /dev/null +++ b/core/src/lua/create_component.rs @@ -0,0 +1,168 @@ +use std::borrow::Cow; + +use hv_lua::{FromLua, ToLua}; +use tealr::{NamePart, TealType, TypeName}; + +///This trait is used to limit what types can be set in the create_type_component_container macro +///It doesn't really have a use outside of that. +pub trait Component { + fn is_component() {} +} + +#[derive(Debug, Clone, Copy)] +pub struct CopyComponent(T); +impl Component for CopyComponent {} +impl hv_lua::UserData for CopyComponent +where + T: for<'a> ToLua<'a> + for<'a> FromLua<'a>, +{ + #[allow(clippy::unit_arg)] + fn add_fields<'lua, F: hv_lua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("value", |_, this| Ok(this.0)); + fields.add_field_method_set("value", |_, this, value| Ok(this.0 = value)); + } + fn on_metatable_init(t: hv_alchemy::Type) { + use hv_lua::hv::LuaUserDataTypeExt; + t.add_clone().add_copy().mark_component(); + } + fn add_type_methods<'lua, M: hv_lua::UserDataMethods<'lua, hv_alchemy::Type>>( + methods: &mut M, + ) { + methods.add_function("new", |_, i: T| Ok(Self(i))); + } + fn on_type_metatable_init(t: hv_alchemy::Type>) { + use hv_lua::hv::LuaUserDataTypeTypeExt; + t.mark_component_type(); + } +} +impl tealr::TypeName for CopyComponent { + fn get_type_parts() -> std::borrow::Cow<'static, [tealr::NamePart]> { + let name = tealr::NamePart::Type(TealType { + name: Cow::Borrowed("Component"), + type_kind: tealr::KindOfType::External, + generics: None, + }); + let mut type_name = vec![name, NamePart::Symbol(Cow::Borrowed("<"))]; + type_name.append(&mut T::get_type_parts().into_owned()); + type_name.push(NamePart::Symbol(Cow::Borrowed(">"))); + Cow::Owned(type_name) + } +} +impl tealr::TypeBody for CopyComponent { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + get_type_body_component::(gen) + } +} + +#[derive(Debug, Clone, Copy)] +pub struct CloneComponent(T); +impl Component for CloneComponent {} +impl hv_lua::UserData for CloneComponent +where + T: for<'a> ToLua<'a> + for<'a> FromLua<'a>, +{ + #[allow(clippy::unit_arg)] + fn add_fields<'lua, F: hv_lua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("value", |_, this| Ok(this.0.clone())); + fields.add_field_method_set("value", |_, this, value| Ok(this.0 = value)); + } + fn on_metatable_init(t: hv_alchemy::Type) { + use hv_lua::hv::LuaUserDataTypeExt; + t.add_clone().mark_component(); + } + fn add_type_methods<'lua, M: hv_lua::UserDataMethods<'lua, hv_alchemy::Type>>( + methods: &mut M, + ) { + methods.add_function("new", |_, i: T| Ok(Self(i))); + } + fn on_type_metatable_init(t: hv_alchemy::Type>) { + use hv_lua::hv::LuaUserDataTypeTypeExt; + t.mark_component_type(); + } +} +impl tealr::TypeName for CloneComponent { + fn get_type_parts() -> std::borrow::Cow<'static, [tealr::NamePart]> { + let name = tealr::NamePart::Type(TealType { + name: Cow::Borrowed("Component"), + type_kind: tealr::KindOfType::External, + generics: None, + }); + let mut type_name = vec![name, NamePart::Symbol(Cow::Borrowed("<"))]; + type_name.append(&mut T::get_type_parts().into_owned()); + type_name.push(NamePart::Symbol(Cow::Borrowed(">"))); + Cow::Owned(type_name) + } +} +impl tealr::TypeBody for CloneComponent { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + get_type_body_component::(gen) + } +} + +fn get_type_body_component(gen: &mut tealr::TypeGenerator) { + let mut signature = vec![NamePart::Symbol(Cow::Borrowed("function("))]; + signature.append(&mut T::get_type_parts().into_owned()); + signature.push(NamePart::Symbol(Cow::Borrowed("):"))); + signature.append(&mut SelfType::get_type_parts().into_owned()); + + gen.methods.push(tealr::ExportedFunction { + name: Cow::Borrowed("new").into(), + signature: Cow::Owned(signature), + is_meta_method: false, + }); + gen.fields.push(( + Cow::Borrowed("value"), + tealr::type_parts_to_str(::get_type_parts()), + )); +} + +#[macro_export] +macro_rules! create_type_component_container { + ($name:ident with $($field_name:ident of $type_name:ty,)+) => { + #[derive(Debug, Clone)] + pub struct $name<'lua>(hv_lua::Table<'lua>); + impl<'lua> hv_lua::ToLua<'lua> for $name<'lua> { + fn to_lua( + self, + lua: &'lua hv_lua::Lua, + ) -> std::result::Result, hv_lua::Error> { + self.0.to_lua(lua) + } + } + impl<'lua> tealr::TypeName for $name<'lua> { + fn get_type_parts() -> std::borrow::Cow<'static, [tealr::NamePart]> { + use tealr::new_type; + new_type!(Components) + } + } + impl<'lua> tealr::TypeBody for $name<'lua> { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + $( + <$type_name as $crate::lua::Component>::is_component(); + gen.fields.push( + ( + std::borrow::Cow::Borrowed( + stringify!($field_name) + ), + tealr::type_parts_to_str( + <$type_name as tealr::TypeName>::get_type_parts() + ) + ) + ); + )* + + } + } + impl<'lua> $name<'lua> { + pub fn new(lua: &'lua hv_lua::Lua) -> Result> { + let table = lua.create_table()?; + use $crate::lua::Component; + $( + <$type_name as Component>::is_component(); + table.set(stringify!($field_name),lua.create_userdata_type::<$type_name>()?)?; + )* + Ok(Self(table)) + } + } + }; +} diff --git a/core/src/lua/mod.rs b/core/src/lua/mod.rs new file mode 100644 index 0000000000..fe375126ce --- /dev/null +++ b/core/src/lua/mod.rs @@ -0,0 +1,112 @@ +mod create_component; +pub use create_component::{CloneComponent, Component, CopyComponent}; + +use std::{error::Error, os::unix::prelude::OsStrExt, path::Path}; + +use hv_lua::{chunk, hv::types, Function, Lua, Table, Value}; + +const LUA_ENTRY: &str = "main"; + +crate::create_type_component_container!( + TypeContainer with + I32 of CopyComponent, + Bool of CopyComponent, +); + +pub fn init_lua Result>>( + mod_dir: &Path, + register_types: RegisterTypes, +) -> Result> { + let lua = Lua::new(); + let hv = types(&lua)?; + let component_types = register_types(&lua)?; + let dir = mod_dir.as_os_str().as_bytes().to_owned(); + { + let globals = lua.globals(); + //a table containing all the mods + globals.set("mods", lua.create_table()?)?; + //this table is used to have quick access to every event that needs to run. + globals.set("events", lua.create_table()?)?; + + //we don't want users to simply use `require` to load their files as that will either result in conflicts or annoying path names + //to drive this point home, I rename the `require` function here and add 2 other functions to load mod files + let req = globals.get::<_, Function>("require")?; + globals.set("require_lib", req)?; + globals.set("require", hv_lua::Nil)?; + + globals.set("hv", hv)?; + globals.set("type_components", component_types)?; + + //this function allows people to load a file from arbitrary mods + //this allows "library only" mods to exist. + //there will also be a function that loads from the current mod. However, that one needs to be defined when loading the mod + let load_any_mod_file = lua.create_function( + move |lua, (from_mod, path): (hv_lua::String, hv_lua::String)| { + //TODO: a way to go from `mod id` to `mod folder` + let globals = lua.globals(); + let req = globals.get::<_, Function>("require_lib")?; + let mod_folder = globals + .get::<_, Table>("mods")? + .get::<_, Table>(from_mod)? + .get::<_, hv_lua::String>("dir_name")?; + + let mut full_path = Vec::new(); + full_path.extend_from_slice(&dir); + full_path.extend_from_slice(b"."); + full_path.extend_from_slice(mod_folder.as_bytes()); + full_path.extend_from_slice(b"."); + full_path.extend_from_slice(path.as_bytes()); + let full_path = lua.create_string(&full_path)?; + req.call::<_, hv_lua::Value>(full_path) + }, + )?; + globals.set("require_from", load_any_mod_file)?; + } + Ok(lua) +} + +pub fn load_lua>( + mod_id: String, + mod_folder: P, + lua: &Lua, +) -> Result<(), Box> { + let name = mod_id; + let name_to_transfer = name.clone(); + //ideally, we use a lua string but... those don't get transferred properly for some reason.... + let dir = String::from_utf8_lossy(mod_folder.as_ref()); + let entry = LUA_ENTRY.to_string(); + let chunk = chunk! { + local name = $name_to_transfer + local dir = $dir + local entry = $entry + + function require(load_path) + return require_from(name , load_path) + end + local function init_mod() + return require(entry) + end + local mod_config = { + dir_name = dir, + require = require, + mod_id = name + } + mods[name] = mod_config + + local mod_events = init_mod() + mod_config["events"] = mod_events + if type(mod_events) == "table" then + for k, _ in pairs(mod_events) do + local event_list = events[k] or {} + table.insert(event_list, mod_config) + events[k] = event_list + end + end + require = nil + }; + lua.load(chunk) + .set_name(&format!("Load mod: {:?}", name))? + .exec()?; + + Ok(()) +} diff --git a/mods/test_lua_mod_one/main.lua b/mods/test_lua_mod_one/main.lua index ebfa7a2a7d..1d5b4abbf7 100644 --- a/mods/test_lua_mod_one/main.lua +++ b/mods/test_lua_mod_one/main.lua @@ -4,10 +4,14 @@ local entity; return { init = function(world) print "Run init" + local I32 = type_components.I32 + local Bool = type_components.Bool entity = world:spawn { I32.new(5), Bool.new(true) } end, fixed_update_physics_bodies = function(world) local Query = hv.ecs.Query + local I32 = type_components.I32 + local Bool = type_components.Bool local query = Query.new { Query.write(I32), Query.read(Bool) } world:query_one(query, entity, function(item) print("Got item:",item) diff --git a/src/lua.rs b/src/lua.rs index 80ab707b24..5aa2cdd1a4 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -1,112 +1,12 @@ -use core::test::{BoolComponent, I32Component}; -use std::{error::Error, os::unix::prelude::OsStrExt, path::Path, sync::Arc}; +use std::{error::Error, sync::Arc}; use hecs::World; use hv_cell::AtomicRefCell; -use hv_lua::{chunk, hv::types, Function, Lua, Table}; +use hv_lua::{chunk, Lua, Value}; use macroquad::prelude::collections::storage; use crate::Resources; -const LUA_ENTRY: &str = "main"; - -pub(crate) fn init_lua(mod_dir: &Path) -> Result> { - let lua = Lua::new(); - let hv = types(&lua)?; - let i32_ty = lua.create_userdata_type::()?; - let bool_ty = lua.create_userdata_type::()?; - let dir = mod_dir.as_os_str().as_bytes().to_owned(); - { - let globals = lua.globals(); - //a table containing all the mods - globals.set("mods", lua.create_table()?)?; - //this table is used to have quick access to every event that needs to run. - globals.set("events", lua.create_table()?)?; - - //we don't want users to simply use `require` to load their files as that will either result in conflicts or annoying path names - //to drive this point home, I rename the `require` function here and add 2 other functions to load mod files - let req = globals.get::<_, Function>("require")?; - globals.set("require_lib", req)?; - globals.set("require", hv_lua::Nil)?; - - globals.set("hv", hv)?; - globals.set("I32", i32_ty)?; - globals.set("Bool", bool_ty)?; - - //this function allows people to load a file from arbitrary mods - //this allows "library only" mods to exist. - //there will also be a function that loads from the current mod. However, that one needs to be defined when loading the mod - let load_any_mod_file = lua.create_function( - move |lua, (from_mod, path): (hv_lua::String, hv_lua::String)| { - //TODO: a way to go from `mod id` to `mod folder` - let globals = lua.globals(); - let req = globals.get::<_, Function>("require_lib")?; - let mod_folder = globals - .get::<_, Table>("mods")? - .get::<_, Table>(from_mod)? - .get::<_, hv_lua::String>("dir_name")?; - - let mut full_path = Vec::new(); - full_path.extend_from_slice(&dir); - full_path.extend_from_slice(b"."); - full_path.extend_from_slice(mod_folder.as_bytes()); - full_path.extend_from_slice(b"."); - full_path.extend_from_slice(path.as_bytes()); - let full_path = lua.create_string(&full_path)?; - req.call::<_, hv_lua::Value>(full_path) - }, - )?; - globals.set("require_from", load_any_mod_file)?; - } - Ok(lua) -} - -pub(crate) fn load_lua>( - mod_id: String, - mod_folder: P, - lua: &Lua, -) -> Result<(), Box> { - let name = mod_id; - let name_to_transfer = name.clone(); - //ideally, we use a lua string but... those don't get transferred properly for some reason.... - let dir = String::from_utf8_lossy(mod_folder.as_ref()); - let entry = LUA_ENTRY.to_string(); - let chunk = chunk! { - local name = $name_to_transfer - local dir = $dir - local entry = $entry - - function require(load_path) - return require_from(name , load_path) - end - local function init_mod() - return require(entry) - end - local mod_config = { - dir_name = dir, - require = require, - mod_id = name - } - mods[name] = mod_config - - local mod_events = init_mod() - mod_config["events"] = mod_events - if type(mod_events) == "table" then - for k, _ in pairs(mod_events) do - local event_list = events[k] or {} - table.insert(event_list, mod_config) - events[k] = event_list - end - end - require = nil - }; - lua.load(chunk) - .set_name(&format!("Load mod: {:?}", name))? - .exec()?; - - Ok(()) -} - pub(crate) fn run_event( event_name: &'static str, world: Arc>, @@ -133,3 +33,16 @@ pub(crate) fn run_event( lua.load(chunk).set_name(&thread_name)?.exec()?; Ok(()) } +use core::lua::CopyComponent; + +use core::create_type_component_container; +create_type_component_container!( + TypeComponentContainer with + I32 of CopyComponent, + Bool of CopyComponent, +); + +pub(crate) fn register_types(lua: &Lua) -> Result> { + use hv_lua::ToLua; + Ok(TypeComponentContainer::new(lua)?.to_lua(lua)?) +} diff --git a/src/resources.rs b/src/resources.rs index fe528c63c2..01af47f07a 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -10,13 +10,16 @@ use ff_particles::EmitterConfig; use serde::{Deserialize, Serialize}; -use core::data::{deserialize_json_bytes, deserialize_json_file}; -use core::error::ErrorKind; use core::text::ToStringHelper; +use core::{ + data::{deserialize_json_bytes, deserialize_json_file}, + lua::init_lua, +}; +use core::{error::ErrorKind, lua::load_lua}; use core::{formaterr, Result}; -use crate::{gui::GuiResources, lua::init_lua}; -use crate::{lua::load_lua, map::DecorationMetadata}; +use crate::map::DecorationMetadata; +use crate::{gui::GuiResources, lua::register_types}; use crate::player::PlayerCharacterMetadata; use crate::{items::MapItemMetadata, map::Map}; @@ -368,7 +371,7 @@ impl Resources { pub async fn new>(assets_dir: P, mods_dir: P) -> Result { let assets_dir = assets_dir.as_ref(); let mods_dir = mods_dir.as_ref(); - let lua = init_lua(mods_dir).unwrap(); + let lua = init_lua(mods_dir, register_types).unwrap(); let mut resources = Resources { assets_dir: assets_dir.to_string_helper(), mods_dir: mods_dir.to_string_helper(), From e0f8d0342dcdc7fd53f999da7e103112cec56cf0 Mon Sep 17 00:00:00 2001 From: lenscas Date: Wed, 9 Mar 2022 19:02:27 +0100 Subject: [PATCH 15/21] update tealr so more type info is available --- Cargo.lock | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 41cd27fac8..de3c962d0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1557,9 +1557,12 @@ dependencies = [ [[package]] name = "tealr" version = "0.8.2" -source = "git+https://github.com/lenscas/tealr?branch=temporary/feature/add_support_for_hv_lua#5ef6ba2d98b5ca93f1ef5a4d809bc1ad10d1273b" +source = "git+https://github.com/lenscas/tealr?branch=temporary/feature/add_support_for_hv_lua#ca12ea91b2047a7fc72f7650e861b006b7bb89f4" dependencies = [ "bstr", + "hecs", + "hv-elastic", + "hv-guarded-borrow", "hv-lua", "itertools", "serde", @@ -1569,7 +1572,7 @@ dependencies = [ [[package]] name = "tealr_derive" version = "0.8.2" -source = "git+https://github.com/lenscas/tealr?branch=temporary/feature/add_support_for_hv_lua#5ef6ba2d98b5ca93f1ef5a4d809bc1ad10d1273b" +source = "git+https://github.com/lenscas/tealr?branch=temporary/feature/add_support_for_hv_lua#ca12ea91b2047a7fc72f7650e861b006b7bb89f4" dependencies = [ "proc-macro2", "quote", From 71fc6335601fbad40ab9dd3033fd6556b929a86b Mon Sep 17 00:00:00 2001 From: lenscas Date: Thu, 10 Mar 2022 15:58:21 +0100 Subject: [PATCH 16/21] start making some types compatible with lua --- core/src/lua/mod.rs | 12 ++ core/src/lua/wrapped_types.rs | 241 +++++++++++++++++++++++++++++ core/src/transform.rs | 46 +++++- src/drawables/animated_sprite.rs | 102 ++++++++++++- src/lua.rs | 25 +++ src/particles.rs | 147 +++++++++++++++++- src/physics.rs | 255 ++++++++++++++++++++++++++++++- 7 files changed, 812 insertions(+), 16 deletions(-) create mode 100644 core/src/lua/wrapped_types.rs diff --git a/core/src/lua/mod.rs b/core/src/lua/mod.rs index fe375126ce..97cfe012a2 100644 --- a/core/src/lua/mod.rs +++ b/core/src/lua/mod.rs @@ -1,4 +1,5 @@ mod create_component; +pub mod wrapped_types; pub use create_component::{CloneComponent, Component, CopyComponent}; use std::{error::Error, os::unix::prelude::OsStrExt, path::Path}; @@ -110,3 +111,14 @@ pub fn load_lua>( Ok(()) } + +pub fn get_table(value: hv_lua::Value) -> Result { + match value { + hv_lua::Value::Table(x) => Ok(x), + v => Err(hv_lua::Error::FromLuaConversionError { + from: v.type_name(), + to: "table", + message: None, + }), + } +} diff --git a/core/src/lua/wrapped_types.rs b/core/src/lua/wrapped_types.rs new file mode 100644 index 0000000000..bba3b6a722 --- /dev/null +++ b/core/src/lua/wrapped_types.rs @@ -0,0 +1,241 @@ +use std::borrow::Cow; + +use hv_lua::{FromLua, ToLua, UserData, Value}; +use macroquad::prelude::{Color, Rect, Vec2}; +use tealr::{ + mlu::{TealData, UserDataWrapper}, + TypeBody, TypeName, +}; + +#[derive(Clone)] +pub struct Vec2Lua { + pub x: f32, + pub y: f32, +} +impl From for Vec2Lua { + fn from(x: Vec2) -> Self { + Self { x: x.x, y: x.y } + } +} +impl From for Vec2 { + fn from(x: Vec2Lua) -> Self { + Self::new(x.x, x.y) + } +} +impl<'lua> ToLua<'lua> for Vec2Lua { + fn to_lua(self, lua: &'lua hv_lua::Lua) -> hv_lua::Result> { + let position = lua.create_table()?; + position.set("x", self.x)?; + position.set("y", self.y)?; + lua.pack(position) + } +} + +impl<'lua> FromLua<'lua> for Vec2Lua { + fn from_lua(lua_value: hv_lua::Value<'lua>, _: &'lua hv_lua::Lua) -> hv_lua::Result { + let value = match lua_value { + hv_lua::Value::Table(x) => x, + x => { + return Err(hv_lua::Error::FromLuaConversionError { + from: x.type_name(), + to: "Table", + message: None, + }) + } + }; + let x = value.get("x")?; + let y = value.get("y")?; + Ok(Self { x, y }) + } +} + +impl TypeName for Vec2Lua { + fn get_type_parts() -> Cow<'static, [tealr::NamePart]> { + tealr::new_type!(Vec, External) + } +} +impl TypeBody for Vec2Lua { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields + .push((Cow::Borrowed("x"), Cow::Borrowed("number"))); + gen.fields + .push((Cow::Borrowed("y"), Cow::Borrowed("number"))); + } +} + +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct ColorLua { + pub r: f32, + pub g: f32, + pub b: f32, + pub a: f32, +} +impl TypeName for ColorLua { + fn get_type_parts() -> Cow<'static, [tealr::NamePart]> { + tealr::new_type!(Color, External) + } +} +impl From for ColorLua { + fn from(color: Color) -> Self { + Self { + r: color.r, + g: color.g, + b: color.b, + a: color.a, + } + } +} + +impl From for Color { + fn from(color: ColorLua) -> Self { + Self { + r: color.r, + g: color.g, + b: color.b, + a: color.a, + } + } +} +impl<'lua> FromLua<'lua> for ColorLua { + fn from_lua(lua_value: hv_lua::Value<'lua>, _: &'lua hv_lua::Lua) -> hv_lua::Result { + let v = match lua_value { + Value::Table(x) => x, + x => { + return Err(hv_lua::Error::FromLuaConversionError { + from: x.type_name(), + to: "table", + message: None, + }) + } + }; + Ok(Self { + r: v.get("r")?, + g: v.get("g")?, + b: v.get("b")?, + a: v.get("a")?, + }) + } +} +impl<'lua> ToLua<'lua> for ColorLua { + fn to_lua(self, lua: &'lua hv_lua::Lua) -> hv_lua::Result> { + let table = lua.create_table()?; + table.set("r", self.r)?; + table.set("g", self.g)?; + table.set("b", self.b)?; + table.set("a", self.a)?; + lua.pack(table) + } +} + +#[derive(Clone)] +pub struct RectLua(Rect); +impl From for Rect { + fn from(r: RectLua) -> Self { + r.0 + } +} +impl From for RectLua { + fn from(x: Rect) -> Self { + Self(x) + } +} +impl TypeName for RectLua { + fn get_type_parts() -> Cow<'static, [tealr::NamePart]> { + tealr::new_type!(Rect, External) + } +} +impl UserData for RectLua { + fn add_fields<'lua, F: hv_lua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("x", |lua, this| this.0.x.to_lua(lua)); + fields.add_field_method_get("y", |lua, this| this.0.y.to_lua(lua)); + fields.add_field_method_get("w", |lua, this| this.0.w.to_lua(lua)); + fields.add_field_method_get("h", |lua, this| this.0.h.to_lua(lua)); + fields.add_field_method_set("x", |_, this, value| { + this.0.x = value; + Ok(()) + }); + fields.add_field_method_set("y", |_, this, value| { + this.0.y = value; + Ok(()) + }); + fields.add_field_method_set("w", |_, this, value| { + this.0.w = value; + Ok(()) + }); + fields.add_field_method_set("h", |_, this, value| { + this.0.h = value; + Ok(()) + }); + } + + fn add_methods<'lua, M: hv_lua::UserDataMethods<'lua, Self>>(methods: &mut M) { + let mut wrapper = UserDataWrapper::from_user_data_methods(methods); + ::add_methods(&mut wrapper) + } +} +impl TealData for RectLua { + fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { + methods.add_method("point", |lua, this, ()| { + Vec2Lua::from(this.0.point()).to_lua(lua) + }); + methods.add_method("size", |lua, this, ()| { + Vec2Lua::from(this.0.size()).to_lua(lua) + }); + methods.add_method("left", |lua, this, ()| this.0.left().to_lua(lua)); + methods.add_method("right", |lua, this, ()| this.0.right().to_lua(lua)); + methods.add_method("top", |lua, this, ()| this.0.top().to_lua(lua)); + methods.add_method("bottom", |lua, this, ()| this.0.bottom().to_lua(lua)); + methods.add_method_mut("move_to", |_, this, vec: Vec2Lua| { + this.0.move_to(vec.into()); + Ok(()) + }); + methods.add_method_mut("scale", |_, this, (sx, sy)| { + this.0.scale(sx, sy); + Ok(()) + }); + methods.add_method("contains", |lua, this, point: Vec2Lua| { + this.0.contains(point.into()).to_lua(lua) + }); + methods.add_method("overlaps", |lua, this, other: RectLua| { + this.0.overlaps(&other.into()).to_lua(lua) + }); + methods.add_method("combine_with", |lua, this, other: RectLua| { + RectLua::from(this.0.combine_with(other.into())).to_lua(lua) + }); + methods.add_method("intersect", |lua, this, other: RectLua| { + this.0 + .intersect(other.into()) + .map(RectLua::from) + .to_lua(lua) + }); + methods.add_method("offset", |lua, this, offset: Vec2Lua| { + RectLua::from(this.0.offset(offset.into())).to_lua(lua) + }); + } +} +impl TypeBody for RectLua { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.is_user_data = true; + ::add_methods(gen); + gen.fields.push(( + Cow::Borrowed("x"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("y"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("w"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("h"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("x"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + } +} diff --git a/core/src/transform.rs b/core/src/transform.rs index f52e1babcd..bc8edad296 100644 --- a/core/src/transform.rs +++ b/core/src/transform.rs @@ -1,6 +1,11 @@ +use std::borrow::Cow; + +use hv_lua::{FromLua, ToLua}; use macroquad::prelude::*; +use tealr::TypeBody; -#[derive(Debug, Default)] +use crate::lua::wrapped_types::Vec2Lua; +#[derive(Debug, Default, tealr::TypeName, Clone)] pub struct Transform { pub position: Vec2, pub rotation: f32, @@ -20,3 +25,42 @@ impl From for Transform { } } } +impl<'lua> ToLua<'lua> for Transform { + fn to_lua(self, lua: &'lua hv_lua::Lua) -> hv_lua::Result> { + let transform = lua.create_table()?; + let position = Vec2Lua::from(self.position).to_lua(lua)?; + transform.set("position", position)?; + transform.set("rotation", self.rotation)?; + lua.pack(transform) + } +} + +impl<'lua> FromLua<'lua> for Transform { + fn from_lua( + value: hv_lua::Value<'lua>, + _: &'lua hv_lua::Lua, + ) -> std::result::Result { + let value = match value { + hv_lua::Value::Table(x) => x, + x => { + return Err(hv_lua::Error::FromLuaConversionError { + from: x.type_name(), + to: "Table", + message: None, + }) + } + }; + let position = value.get::<_, Vec2Lua>("position")?.into(); + let rotation = value.get("rotation")?; + + Ok(Self { position, rotation }) + } +} +impl TypeBody for Transform { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields + .push((Cow::Borrowed("position"), Cow::Borrowed("Vec2"))); + gen.fields + .push((Cow::Borrowed("rotation"), Cow::Borrowed("number"))); + } +} diff --git a/src/drawables/animated_sprite.rs b/src/drawables/animated_sprite.rs index 42ac2eb024..3617ea6742 100644 --- a/src/drawables/animated_sprite.rs +++ b/src/drawables/animated_sprite.rs @@ -1,3 +1,5 @@ +use core::lua::wrapped_types::ColorLua; +use std::borrow::Cow; use std::collections::HashMap; use std::iter::FromIterator; use std::ops::Mul; @@ -12,8 +14,9 @@ use macroquad::prelude::*; use hecs::World; use serde::{Deserialize, Serialize}; +use tealr::{TypeBody, TypeName}; -use core::Transform; +use core::{lua::wrapped_types::Vec2Lua, Transform}; use crate::{Drawable, DrawableKind, Resources}; @@ -70,12 +73,24 @@ impl From for Tween { } } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, tealr::TypeName)] pub struct Keyframe { pub frame: u32, #[serde(with = "core::json::vec2_def")] pub translation: Vec2, } +impl TypeBody for Keyframe { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("frame"), + tealr::type_parts_to_str(u32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("translation"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + } +} pub struct AnimatedSpriteParams { pub frame_size: Option, @@ -535,7 +550,7 @@ impl From<&[(&str, AnimatedSprite)]> for AnimatedSpriteSet { } } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, tealr::TypeName)] pub struct AnimationMetadata { pub id: String, pub row: u32, @@ -547,6 +562,35 @@ pub struct AnimationMetadata { pub is_looping: bool, } +impl TypeBody for AnimationMetadata { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("id"), + tealr::type_parts_to_str(String::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("row"), + tealr::type_parts_to_str(u32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("frames"), + tealr::type_parts_to_str(u32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("fps"), + tealr::type_parts_to_str(u32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("tweens"), + tealr::type_parts_to_str(Vec::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_looping"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + } +} + impl From for MQAnimation { fn from(a: AnimationMetadata) -> Self { MQAnimation { @@ -558,13 +602,25 @@ impl From for MQAnimation { } } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, tealr::TypeName)] pub struct TweenMetadata { pub id: String, pub keyframes: Vec, } +impl TypeBody for TweenMetadata { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("id"), + tealr::type_parts_to_str(String::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("keyframes"), + tealr::type_parts_to_str(Vec::::get_type_parts()), + )); + } +} -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, tealr::TypeName)] pub struct AnimatedSpriteMetadata { #[serde(rename = "texture")] pub texture_id: String, @@ -590,3 +646,39 @@ pub struct AnimatedSpriteMetadata { #[serde(default)] pub is_deactivated: bool, } +impl TypeBody for AnimatedSpriteMetadata { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("texture_id"), + tealr::type_parts_to_str(String::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("scale"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("offset"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("pivot"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("tint"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("animations"), + tealr::type_parts_to_str(Vec::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("autoplay_id"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_deactivated"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + } +} diff --git a/src/lua.rs b/src/lua.rs index 5aa2cdd1a4..d52e853387 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -4,6 +4,9 @@ use hecs::World; use hv_cell::AtomicRefCell; use hv_lua::{chunk, Lua, Value}; use macroquad::prelude::collections::storage; +use macroquad_platformer::Actor; +use tealr::mlu::TealData; +use tealr::TypeName; use crate::Resources; @@ -46,3 +49,25 @@ pub(crate) fn register_types(lua: &Lua) -> Result> { use hv_lua::ToLua; Ok(TypeComponentContainer::new(lua)?.to_lua(lua)?) } + +use hv_lua as mlua; + +#[derive(Clone, Copy, tealr::MluaUserData)] +pub struct ActorLua(Actor); +impl TypeName for ActorLua { + fn get_type_parts() -> std::borrow::Cow<'static, [tealr::NamePart]> { + tealr::new_type!(Actor, External) + } +} +impl TealData for ActorLua {} + +impl From for Actor { + fn from(a: ActorLua) -> Self { + a.0 + } +} +impl From for ActorLua { + fn from(a: Actor) -> Self { + Self(a) + } +} diff --git a/src/particles.rs b/src/particles.rs index 2bca244364..6c80ce895b 100644 --- a/src/particles.rs +++ b/src/particles.rs @@ -1,7 +1,11 @@ use hv_cell::AtomicRefCell; use macroquad::experimental::collections::storage; use macroquad::prelude::*; -use std::{collections::HashMap, sync::Arc}; +use mlua::{ToLua, UserData, UserDataMethods}; +use std::{borrow::Cow, collections::HashMap, sync::Arc}; +use tealr::mlu::UserDataWrapper; +use tealr::TypeName; +use tealr::{mlu::TealData, TypeBody}; use ff_particles::EmittersCache; @@ -9,12 +13,12 @@ use hecs::World; use serde::{Deserialize, Serialize}; -use core::math::IsZero; use core::Transform; +use core::{lua::wrapped_types::Vec2Lua, math::IsZero}; use crate::{AnimatedSpriteMetadata, Resources}; -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, tealr::TypeName)] pub struct ParticleEmitterMetadata { /// The id of the particle effect. #[serde(rename = "particle_effect")] @@ -43,7 +47,26 @@ pub struct ParticleEmitterMetadata { #[serde(default, skip_serializing_if = "core::json::is_false")] pub should_autostart: bool, } - +impl TypeBody for ParticleEmitterMetadata { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields + .push((Cow::Borrowed("particle_effect"), Cow::Borrowed("String"))); + gen.fields + .push((Cow::Borrowed("offset"), Cow::Borrowed("Vec2"))); + gen.fields + .push((Cow::Borrowed("delay"), Cow::Borrowed("number"))); + gen.fields + .push((Cow::Borrowed("interval"), Cow::Borrowed("number"))); + gen.fields + .push((Cow::Borrowed("emissions"), Cow::Borrowed("integer"))); + gen.fields.push(( + Cow::Borrowed("animations"), + Cow::Borrowed("AnimatedSpriteMetaData"), + )); + gen.fields + .push((Cow::Borrowed("should_autostart"), Cow::Borrowed("boolean"))); + } +} impl Default for ParticleEmitterMetadata { fn default() -> Self { ParticleEmitterMetadata { @@ -57,7 +80,9 @@ impl Default for ParticleEmitterMetadata { } } } +use hv_lua as mlua; +#[derive(Clone, tealr::TypeName)] pub struct ParticleEmitter { pub particle_effect_id: String, pub offset: Vec2, @@ -107,6 +132,120 @@ impl ParticleEmitter { } } +impl UserData for ParticleEmitter { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("particle_effect_id", |lua, this| { + this.particle_effect_id.clone().to_lua(lua) + }); + fields.add_field_method_get("offset", |lua, this| Vec2Lua::from(this.offset).to_lua(lua)); + fields.add_field_method_get("delay", |lua, this| this.delay.to_lua(lua)); + fields.add_field_method_get("emissions", |lua, this| this.emissions.to_lua(lua)); + fields.add_field_method_get("interval", |lua, this| this.interval.to_lua(lua)); + fields.add_field_method_get("emission_cnt", |lua, this| this.emission_cnt.to_lua(lua)); + fields.add_field_method_get("delay_timer", |lua, this| this.delay_timer.to_lua(lua)); + fields.add_field_method_get("interval_timer", |lua, this| { + this.interval_timer.to_lua(lua) + }); + fields.add_field_method_get("is_active", |lua, this| this.is_active.to_lua(lua)); + + fields.add_field_method_set("particle_effect_id", |_, this, value| { + this.particle_effect_id = value; + Ok(()) + }); + fields.add_field_method_set("offset", |_, this, value: Vec2Lua| { + this.offset = value.into(); + Ok(()) + }); + fields.add_field_method_set("delay", |_, this, value| { + this.delay = value; + Ok(()) + }); + fields.add_field_method_set("emissions", |_, this, value| { + this.emissions = value; + Ok(()) + }); + fields.add_field_method_set("interval", |_, this, value| { + this.interval = value; + Ok(()) + }); + fields.add_field_method_set("emission_cnt", |_, this, value| { + this.emission_cnt = value; + Ok(()) + }); + fields.add_field_method_set("delay_timer", |_, this, value| { + this.delay_timer = value; + Ok(()) + }); + fields.add_field_method_set("interval_timer", |_, this, value| { + this.interval_timer = value; + Ok(()) + }); + fields.add_field_method_set("is_active", |_, this, value| { + this.is_active = value; + Ok(()) + }); + } + + fn add_methods<'lua, T: UserDataMethods<'lua, Self>>(methods: &mut T) { + let mut wrapper = UserDataWrapper::from_user_data_methods(methods); + ::add_methods(&mut wrapper) + } +} +impl TypeBody for ParticleEmitter { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.is_user_data = true; + ::add_methods(gen); + gen.fields.push(( + Cow::Borrowed("particle_effect_id"), + tealr::type_parts_to_str(String::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("offset"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("delay"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("emissions"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("interval"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("emission_cnt"), + tealr::type_parts_to_str(u32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("delay_timer"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("interval_timer"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_active"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + } +} + +impl TealData for ParticleEmitter { + fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { + methods.add_method("get_offset", |lua, this, (flip_x, flip_y): (bool, bool)| { + Vec2Lua::from(this.get_offset(flip_x, flip_y)).to_lua(lua) + }); + methods.add_method_mut("activate", |_, this, ()| { + this.activate(); + Ok(()) + }) + } +} + impl From for ParticleEmitter { fn from(params: ParticleEmitterMetadata) -> Self { ParticleEmitter::new(params) diff --git a/src/physics.rs b/src/physics.rs index d76443ca00..e77f2726c7 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -1,4 +1,5 @@ use hv_cell::AtomicRefCell; +use hv_lua::{FromLua, ToLua}; use macroquad::color; use macroquad::experimental::collections::storage; use macroquad::prelude::*; @@ -8,10 +9,17 @@ use macroquad_platformer::{Actor, Tile}; use serde::{Deserialize, Serialize}; use hecs::World; - -use crate::{lua::run_event, CollisionWorld, Map}; -use core::Transform; -use std::sync::Arc; +use tealr::{TypeBody, TypeName}; + +use crate::{ + lua::{run_event, ActorLua}, + CollisionWorld, Map, +}; +use core::{ + lua::{get_table, wrapped_types::Vec2Lua}, + Transform, +}; +use std::{borrow::Cow, sync::Arc}; pub const GRAVITY: f32 = 2.5; pub const TERMINAL_VELOCITY: f32 = 10.0; @@ -56,7 +64,7 @@ pub fn create_collision_world(map: &Map) -> CollisionWorld { const FRICTION_LERP: f32 = 0.96; const STOP_THRESHOLD: f32 = 1.0; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, TypeName)] pub struct PhysicsBodyParams { pub size: Vec2, pub offset: Vec2, @@ -81,9 +89,79 @@ impl Default for PhysicsBodyParams { } } +impl<'lua> FromLua<'lua> for PhysicsBodyParams { + fn from_lua(lua_value: hv_lua::Value<'lua>, _: &'lua hv_lua::Lua) -> hv_lua::Result { + let table = match lua_value { + hv_lua::Value::Table(x) => x, + x => { + return Err(hv_lua::Error::FromLuaConversionError { + from: x.type_name(), + to: "table", + message: None, + }) + } + }; + Ok(Self { + size: table.get::<_, Vec2Lua>("size")?.into(), + offset: table.get::<_, Vec2Lua>("offset")?.into(), + has_mass: table.get("has_mass")?, + has_friction: table.get("has_friction")?, + can_rotate: table.get("can_rotate")?, + bouncyness: table.get("bouncyness")?, + gravity: table.get("gravity")?, + }) + } +} +impl<'lua> ToLua<'lua> for PhysicsBodyParams { + fn to_lua(self, lua: &'lua hv_lua::Lua) -> hv_lua::Result> { + let table = lua.create_table()?; + table.set("size", Vec2Lua::from(self.size))?; + table.set("offset", Vec2Lua::from(self.offset))?; + table.set("has_mass", self.has_mass)?; + table.set("has_friction", self.has_friction)?; + table.set("can_rotate", self.can_rotate)?; + table.set("bouncyness", self.bouncyness)?; + table.set("gravity", self.gravity)?; + lua.pack(table) + } +} +impl TypeBody for PhysicsBodyParams { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("size"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("offset"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("has_mass"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("has_friction"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("can_rotate"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("bouncyness"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("gravity"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + } +} + /// Regular simulated physics bodies. /// Note that rotation is abstract, only set on the transform to be used for draws. The colliders /// are axis-aligned and will not be affected by rotation. +#[derive(Clone, tealr::TypeName)] pub struct PhysicsBody { pub actor: Actor, pub offset: Vec2, @@ -101,6 +179,110 @@ pub struct PhysicsBody { pub is_deactivated: bool, pub gravity: f32, } +impl<'lua> FromLua<'lua> for PhysicsBody { + fn from_lua(lua_value: hv_lua::Value<'lua>, _: &'lua hv_lua::Lua) -> hv_lua::Result { + let table = match lua_value { + hv_lua::Value::Table(x) => x, + x => { + return Err(hv_lua::Error::FromLuaConversionError { + from: x.type_name(), + to: "table", + message: None, + }) + } + }; + Ok(Self { + actor: table.get::<_, ActorLua>("actor")?.into(), + offset: table.get::<_, Vec2Lua>("offset")?.into(), + size: table.get::<_, Vec2Lua>("size")?.into(), + velocity: table.get::<_, Vec2Lua>("velocity")?.into(), + is_on_ground: table.get("is_on_ground")?, + was_on_ground: table.get("was_on_ground")?, + is_on_platform: table.get("is_on_platform")?, + has_mass: table.get("has_mass")?, + has_friction: table.get("has_friction")?, + can_rotate: table.get("can_rotate")?, + bouncyness: table.get("bouncyness")?, + is_deactivated: table.get("is_deactivated")?, + gravity: table.get("gravity")?, + }) + } +} +impl TypeBody for PhysicsBody { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("actor"), + tealr::type_parts_to_str(ActorLua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("offset"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("size"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("velocity"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_on_ground"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("was_on_ground"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_on_platform"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("has_mass"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("has_friction"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("can_rotate"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("bouncyness"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_deactivated"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("gravity"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + } +} +impl<'lua> ToLua<'lua> for PhysicsBody { + fn to_lua(self, lua: &'lua hv_lua::Lua) -> hv_lua::Result> { + let table = lua.create_table()?; + table.set("actor", ActorLua::from(self.actor))?; + table.set("offset", Vec2Lua::from(self.offset))?; + table.set("size", Vec2Lua::from(self.size))?; + table.set("velocity", Vec2Lua::from(self.velocity))?; + table.set("is_on_ground", self.is_on_ground)?; + table.set("was_on_ground", self.was_on_ground)?; + table.set("is_on_platform", self.is_on_platform)?; + table.set("has_mass", self.has_mass)?; + table.set("has_friction", self.has_friction)?; + table.set("can_rotate", self.can_rotate)?; + table.set("bouncyness", self.bouncyness)?; + table.set("is_deactivated", self.is_deactivated)?; + table.set("gravity", self.gravity)?; + lua.pack(table) + } +} impl PhysicsBody { pub fn new>>( @@ -215,7 +397,7 @@ pub fn debug_draw_physics_bodies(world: Arc>) { } } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, TypeName)] pub struct RigidBodyParams { #[serde(with = "core::json::vec2_def")] pub offset: Vec2, @@ -235,9 +417,27 @@ impl Default for RigidBodyParams { } } +impl TypeBody for RigidBodyParams { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("offset"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("size"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("can_rotate"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + } +} + /// Simple physics bodies that has a velocity and optional rotation. /// Note that rotation is abstract, only set on the transform to be used for draws. The colliders /// are axis-aligned and will not be affected by rotation. +#[derive(Clone, TypeName)] pub struct RigidBody { pub offset: Vec2, pub size: Vec2, @@ -245,6 +445,49 @@ pub struct RigidBody { pub can_rotate: bool, } +impl<'lua> FromLua<'lua> for RigidBody { + fn from_lua(lua_value: hv_lua::Value<'lua>, _: &'lua hv_lua::Lua) -> hv_lua::Result { + let table = get_table(lua_value)?; + Ok(Self { + offset: table.get::<_, Vec2Lua>("offset")?.into(), + size: table.get::<_, Vec2Lua>("size")?.into(), + velocity: table.get::<_, Vec2Lua>("velocity")?.into(), + can_rotate: table.get("can_rotate")?, + }) + } +} +impl<'lua> ToLua<'lua> for RigidBody { + fn to_lua(self, lua: &'lua hv_lua::Lua) -> hv_lua::Result> { + let table = lua.create_table()?; + table.set("offset", Vec2Lua::from(self.offset))?; + table.set("size", Vec2Lua::from(self.size))?; + table.set("velocity", Vec2Lua::from(self.velocity))?; + table.set("can_rotate", self.can_rotate)?; + lua.pack(table) + } +} + +impl TypeBody for RigidBody { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("offset"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("size"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("velocity"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("can_rotate"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + } +} + impl RigidBody { pub fn new>>(velocity: V, params: RigidBodyParams) -> Self { let velocity = velocity.into().unwrap_or_default(); From 1614cbbce8e98b7f7931e8b081ffe03ca47248d8 Mon Sep 17 00:00:00 2001 From: lenscas Date: Fri, 11 Mar 2022 18:10:45 +0100 Subject: [PATCH 17/21] make more types sharable with lua --- core/src/lua/wrapped_types.rs | 27 +- src/drawables/animated_sprite.rs | 467 +++++++++++++++++++++++++++++- src/drawables/mod.rs | 79 ++++- src/drawables/sprite.rs | 167 ++++++++++- src/effects/active/mod.rs | 205 ++++++++++++- src/effects/active/projectiles.rs | 164 ++++++++++- src/effects/active/triggered.rs | 42 ++- src/effects/passive/mod.rs | 54 +++- src/player/events.rs | 7 +- 9 files changed, 1191 insertions(+), 21 deletions(-) diff --git a/core/src/lua/wrapped_types.rs b/core/src/lua/wrapped_types.rs index bba3b6a722..6a90ea0292 100644 --- a/core/src/lua/wrapped_types.rs +++ b/core/src/lua/wrapped_types.rs @@ -1,10 +1,10 @@ use std::borrow::Cow; use hv_lua::{FromLua, ToLua, UserData, Value}; -use macroquad::prelude::{Color, Rect, Vec2}; +use macroquad::prelude::{Color, Rect, Texture2D, Vec2}; use tealr::{ mlu::{TealData, UserDataWrapper}, - TypeBody, TypeName, + new_type, TypeBody, TypeName, }; #[derive(Clone)] @@ -239,3 +239,26 @@ impl TypeBody for RectLua { )); } } + +#[derive(Clone)] +pub struct Texture2DLua(Texture2D); +impl TypeName for Texture2DLua { + fn get_type_parts() -> Cow<'static, [tealr::NamePart]> { + new_type!(Texture2D, External) + } +} +impl UserData for Texture2DLua {} +impl TypeBody for Texture2DLua { + fn get_type_body(_: &mut tealr::TypeGenerator) {} +} + +impl From for Texture2D { + fn from(x: Texture2DLua) -> Self { + x.0 + } +} +impl From for Texture2DLua { + fn from(x: Texture2D) -> Self { + Self(x) + } +} diff --git a/src/drawables/animated_sprite.rs b/src/drawables/animated_sprite.rs index 3617ea6742..24baec20e0 100644 --- a/src/drawables/animated_sprite.rs +++ b/src/drawables/animated_sprite.rs @@ -1,4 +1,5 @@ -use core::lua::wrapped_types::ColorLua; +use core::lua::get_table; +use core::lua::wrapped_types::{ColorLua, RectLua, Texture2DLua}; use std::borrow::Cow; use std::collections::HashMap; use std::iter::FromIterator; @@ -6,6 +7,7 @@ use std::ops::Mul; use std::{borrow::BorrowMut, sync::Arc}; use hv_cell::AtomicRefCell; +use hv_lua::{FromLua, LuaSerdeExt, ToLua, UserData, Value}; use macroquad::color; use macroquad::experimental::animation::Animation as MQAnimation; use macroquad::experimental::collections::storage; @@ -14,13 +16,14 @@ use macroquad::prelude::*; use hecs::World; use serde::{Deserialize, Serialize}; +use tealr::mlu::{TealData, UserDataWrapper}; use tealr::{TypeBody, TypeName}; use core::{lua::wrapped_types::Vec2Lua, Transform}; use crate::{Drawable, DrawableKind, Resources}; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, TypeName)] pub struct Animation { pub id: String, pub row: u32, @@ -30,6 +33,60 @@ pub struct Animation { pub is_looping: bool, } +impl<'lua> FromLua<'lua> for Animation { + fn from_lua(lua_value: hv_lua::Value<'lua>, _: &'lua hv_lua::Lua) -> hv_lua::Result { + let table = get_table(lua_value)?; + Ok(Self { + id: table.get("id")?, + row: table.get("row")?, + frames: table.get("frames")?, + fps: table.get("fps")?, + tweens: table.get("tweens")?, + is_looping: table.get("is_looping")?, + }) + } +} +impl<'lua> ToLua<'lua> for Animation { + fn to_lua(self, lua: &'lua hv_lua::Lua) -> hv_lua::Result> { + let table = lua.create_table()?; + table.set("id", self.id)?; + table.set("row", self.row)?; + table.set("frames", self.frames)?; + table.set("fps", self.fps)?; + table.set("tweens", self.tweens)?; + table.set("is_looping", self.is_looping)?; + lua.pack(table) + } +} +impl TypeBody for Animation { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("id"), + tealr::type_parts_to_str(String::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("row"), + tealr::type_parts_to_str(u32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("frames"), + tealr::type_parts_to_str(u32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("fps"), + tealr::type_parts_to_str(u32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("tweens"), + tealr::type_parts_to_str(HashMap::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_looping"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + } +} + impl From for Animation { fn from(meta: AnimationMetadata) -> Self { let tweens = HashMap::from_iter( @@ -49,12 +106,47 @@ impl From for Animation { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, TypeName)] pub struct Tween { pub keyframes: Vec, pub current_translation: Vec2, } +impl<'lua> FromLua<'lua> for Tween { + fn from_lua(lua_value: hv_lua::Value<'lua>, lua: &'lua hv_lua::Lua) -> hv_lua::Result { + let table = get_table(lua_value)?; + Ok(Self { + keyframes: lua.from_value(table.get::<_, Value>("keyframes")?)?, + current_translation: table.get::<_, Vec2Lua>("current_translation")?.into(), + }) + } +} + +impl<'lua> ToLua<'lua> for Tween { + fn to_lua(self, lua: &'lua hv_lua::Lua) -> hv_lua::Result> { + let table = lua.create_table()?; + table.set("keyframes", lua.to_value(&self.keyframes)?)?; + table.set( + "current_translation", + Vec2Lua::from(self.current_translation), + )?; + lua.pack(table) + } +} + +impl TypeBody for Tween { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("keyframes"), + tealr::type_parts_to_str(Vec::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("current_translation"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + } +} + impl From for Tween { fn from(meta: TweenMetadata) -> Self { let mut keyframes = meta.keyframes; @@ -92,6 +184,7 @@ impl TypeBody for Keyframe { } } +#[derive(Clone, TypeName)] pub struct AnimatedSpriteParams { pub frame_size: Option, pub scale: f32, @@ -103,6 +196,76 @@ pub struct AnimatedSpriteParams { pub autoplay_id: Option, } +impl<'lua> FromLua<'lua> for AnimatedSpriteParams { + fn from_lua(lua_value: Value<'lua>, _: &'lua hv_lua::Lua) -> hv_lua::Result { + let table = get_table(lua_value)?; + Ok(Self { + frame_size: table + .get::<_, Option>("frame_size")? + .map(Vec2::from), + scale: table.get("scale")?, + offset: table.get::<_, Vec2Lua>("offset")?.into(), + pivot: table.get::<_, Option>("pivot")?.map(Vec2::from), + tint: table.get::<_, ColorLua>("tint")?.into(), + is_flipped_x: table.get("is_flipped_x")?, + is_flipped_y: table.get("is_flipped_y")?, + autoplay_id: table.get("autoplay_id")?, + }) + } +} + +impl<'lua> ToLua<'lua> for AnimatedSpriteParams { + fn to_lua(self, lua: &'lua hv_lua::Lua) -> hv_lua::Result> { + let table = lua.create_table()?; + table.set("frame_size", self.frame_size.map(Vec2Lua::from))?; + table.set("scale", self.scale)?; + table.set("offset", Vec2Lua::from(self.offset))?; + table.set("pivot", self.pivot.map(Vec2Lua::from))?; + table.set("tint", ColorLua::from(self.tint))?; + table.set("is_flipped_x", self.is_flipped_x)?; + table.set("is_flipped_y", self.is_flipped_y)?; + table.set("autoplay_id", self.autoplay_id)?; + lua.pack(table) + } +} + +impl TypeBody for AnimatedSpriteParams { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("frame_size"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("scale"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("offset"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("pivot"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("tint"), + tealr::type_parts_to_str(ColorLua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_flipped_x"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_flipped_y"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("autoplay_id"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + } +} + impl Default for AnimatedSpriteParams { fn default() -> Self { AnimatedSpriteParams { @@ -131,13 +294,17 @@ impl From for AnimatedSpriteParams { } } -#[derive(Clone)] +#[derive(Clone, TypeName)] pub enum QueuedAnimationAction { Play(String), PlayIndex(usize), WaitThen(f32, Box), Deactivate, } +impl UserData for QueuedAnimationAction {} +impl TypeBody for QueuedAnimationAction { + fn get_type_body(_: &mut tealr::TypeGenerator) {} +} impl QueuedAnimationAction { pub fn wait_then(delay: f32, action: QueuedAnimationAction) -> Self { @@ -145,7 +312,7 @@ impl QueuedAnimationAction { } } -#[derive(Clone)] +#[derive(Clone, TypeName)] pub struct AnimatedSprite { pub texture: Texture2D, pub frame_size: Vec2, @@ -165,6 +332,202 @@ pub struct AnimatedSprite { pub wait_timer: f32, } +impl UserData for AnimatedSprite { + fn add_fields<'lua, F: hv_lua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("texture", |_, this| Ok(Texture2DLua::from(this.texture))); + fields.add_field_method_get("frame_size", |_, this| Ok(Vec2Lua::from(this.frame_size))); + fields.add_field_method_get("scale", |_, this| Ok(this.scale)); + fields.add_field_method_get("offset", |_, this| Ok(Vec2Lua::from(this.offset))); + fields.add_field_method_get("pivot", |_, this| Ok(this.pivot.map(Vec2Lua::from))); + fields.add_field_method_get("tint", |_, this| Ok(ColorLua::from(this.tint))); + fields.add_field_method_get("animations", |_, this| Ok(this.animations.clone())); + fields.add_field_method_get("current_index", |_, this| Ok(this.current_index)); + fields.add_field_method_get("queued_action", |_, this| Ok(this.queued_action.clone())); + fields.add_field_method_get("current_frame", |_, this| Ok(this.current_frame)); + fields.add_field_method_get("frame_timer", |_, this| Ok(this.frame_timer)); + fields.add_field_method_get("is_playing", |_, this| Ok(this.is_playing)); + fields.add_field_method_get("is_flipped_x", |_, this| Ok(this.is_flipped_x)); + fields.add_field_method_get("is_flipped_y", |_, this| Ok(this.is_flipped_y)); + fields.add_field_method_get("is_deactivated", |_, this| Ok(this.is_deactivated)); + fields.add_field_method_get("wait_timer", |_, this| Ok(this.wait_timer)); + fields.add_field_method_set("texture", |_, this, value: Texture2DLua| { + this.texture = value.into(); + Ok(()) + }); + fields.add_field_method_set("frame_size", |_, this, value: Vec2Lua| { + this.frame_size = value.into(); + Ok(()) + }); + fields.add_field_method_set("scale", |_, this, value| { + this.scale = value; + Ok(()) + }); + fields.add_field_method_set("offset", |_, this, value: Vec2Lua| { + this.offset = value.into(); + Ok(()) + }); + fields.add_field_method_set("pivot", |_, this, value: Option| { + this.pivot = value.map(Into::into); + Ok(()) + }); + fields.add_field_method_set("tint", |_, this, value: ColorLua| { + this.tint = value.into(); + Ok(()) + }); + fields.add_field_method_set("animations", |_, this, value| { + this.animations = value; + Ok(()) + }); + fields.add_field_method_set("current_index", |_, this, value| { + this.current_index = value; + Ok(()) + }); + fields.add_field_method_set("queued_action", |_, this, value| { + this.queued_action = value; + Ok(()) + }); + fields.add_field_method_set("current_frame", |_, this, value| { + this.current_frame = value; + Ok(()) + }); + fields.add_field_method_set("frame_timer", |_, this, value| { + this.frame_timer = value; + Ok(()) + }); + fields.add_field_method_set("is_playing", |_, this, value| { + this.is_playing = value; + Ok(()) + }); + fields.add_field_method_set("is_flipped_x", |_, this, value| { + this.is_flipped_x = value; + Ok(()) + }); + fields.add_field_method_set("is_flipped_y", |_, this, value| { + this.is_flipped_y = value; + Ok(()) + }); + fields.add_field_method_set("is_deactivated", |_, this, value| { + this.is_deactivated = value; + Ok(()) + }); + fields.add_field_method_set("wait_timer", |_, this, value| { + this.wait_timer = value; + Ok(()) + }); + } + + fn add_methods<'lua, M: hv_lua::UserDataMethods<'lua, Self>>(methods: &mut M) { + let mut wrapper = UserDataWrapper::from_user_data_methods(methods); + ::add_methods(&mut wrapper) + } +} +impl TealData for AnimatedSprite { + fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { + methods.add_method("get_animation", |_, this, value: String| { + Ok(this.get_animation(&value).map(ToOwned::to_owned)) + }); + methods.add_method("current_animation", |_, this, ()| { + Ok(this.current_animation().to_owned()) + }); + methods.add_method("size", |_, this, ()| Ok(Vec2Lua::from(this.size()))); + methods.add_method("source_rect", |_, this, ()| { + Ok(RectLua::from(this.source_rect())) + }); + methods.add_method("as_index", |_, this, value: String| { + Ok(this.as_index(&value)) + }); + methods.add_method_mut("set_animation_index", |_, this, (index, should_restart)| { + this.set_animation_index(index, should_restart); + Ok(()) + }); + methods.add_method_mut( + "set_animation", + |_, this, (id, should_restart): (String, _)| { + this.set_animation(&id, should_restart); + Ok(()) + }, + ); + methods.add_method_mut("queue_action", |_, this, value| { + this.queue_action(value); + Ok(()) + }); + methods.add_method_mut("restart", |_, this, ()| { + this.restart(); + Ok(()) + }); + } +} +impl TypeBody for AnimatedSprite { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.is_user_data = true; + ::add_methods(gen); + gen.fields.push(( + Cow::Borrowed("texture"), + tealr::type_parts_to_str(Texture2DLua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("frame_size"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("scale"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("offset"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("pivot"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("tint"), + tealr::type_parts_to_str(ColorLua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("animations"), + tealr::type_parts_to_str(Vec::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("current_index"), + tealr::type_parts_to_str(usize::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("queued_action"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("current_frame"), + tealr::type_parts_to_str(u32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("frame_timer"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_playing"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_flipped_x"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_flipped_y"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_deactivated"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("wait_timer"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + } +} + impl AnimatedSprite { pub fn new(texture_id: &str, animations: &[Animation], params: AnimatedSpriteParams) -> Self { let animations = animations.to_vec(); @@ -428,12 +791,104 @@ pub fn debug_draw_one_animated_sprite(position: Vec2, sprite: &AnimatedSprite) { } } -#[derive(Default)] +#[derive(Default, Clone, TypeName)] pub struct AnimatedSpriteSet { pub draw_order: Vec, pub map: HashMap, } +impl UserData for AnimatedSpriteSet { + fn add_fields<'lua, F: hv_lua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("draw_order", |_, this| Ok(this.draw_order.clone())); + fields.add_field_method_get("map", |_, this| Ok(this.map.clone())); + } + + fn add_methods<'lua, M: hv_lua::UserDataMethods<'lua, Self>>(methods: &mut M) { + let mut wrapper = UserDataWrapper::from_user_data_methods(methods); + ::add_methods(&mut wrapper) + } +} +impl TealData for AnimatedSpriteSet { + fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { + methods.add_method("is_empty", |_, this, ()| Ok(this.is_empty())); + methods.add_method("size", |_, this, ()| Ok(Vec2Lua::from(this.size()))); + methods.add_method_mut( + "set_animation", + |_, this, (sprite_id, id, should_restart): (String, String, _)| { + this.set_animation(&sprite_id, &id, should_restart); + Ok(()) + }, + ); + methods.add_method_mut( + "set_animation_index", + |_, this, (sprite_id, index, should_restart): (String, _, _)| { + this.set_animation_index(&sprite_id, index, should_restart); + Ok(()) + }, + ); + methods.add_method_mut( + "set_queued_action", + |_, this, (sprite_id, action): (String, _)| { + this.set_queued_action(&sprite_id, action); + Ok(()) + }, + ); + methods.add_method_mut("set_all", |_, this, (id, should_restart): (String, _)| { + this.set_all(&id, should_restart); + Ok(()) + }); + methods.add_method_mut("set_all_to_index", |_, this, (index, should_restart)| { + this.set_all_to_index(index, should_restart); + Ok(()) + }); + methods.add_method_mut("queue_action_on_all", |_, this, value| { + this.queue_action_on_all(value); + Ok(()) + }); + methods.add_method_mut("restart_all", |_, this, ()| { + this.restart_all(); + Ok(()) + }); + methods.add_method_mut("flip_all_x", |_, this, value| { + this.flip_all_x(value); + Ok(()) + }); + methods.add_method_mut("flip_all_y", |_, this, value| { + this.flip_all_y(value); + Ok(()) + }); + methods.add_method_mut("activate_all", |_, this, ()| { + this.activate_all(); + Ok(()) + }); + methods.add_method_mut("deactivate_all", |_, this, ()| { + this.deactivate_all(); + Ok(()) + }); + methods.add_method_mut("play_all", |_, this, ()| { + this.play_all(); + Ok(()) + }); + methods.add_method_mut("stop_all", |_, this, ()| { + this.stop_all(); + Ok(()) + }); + } +} +impl TypeBody for AnimatedSpriteSet { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.is_user_data = true; + ::add_methods(gen); + gen.fields.push(( + Cow::Borrowed("draw_order"), + tealr::type_parts_to_str(Vec::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("map"), + tealr::type_parts_to_str(HashMap::::get_type_parts()), + )); + } +} impl AnimatedSpriteSet { pub fn is_empty(&self) -> bool { self.draw_order.is_empty() diff --git a/src/drawables/mod.rs b/src/drawables/mod.rs index 93d9412256..d2b0270147 100644 --- a/src/drawables/mod.rs +++ b/src/drawables/mod.rs @@ -3,20 +3,26 @@ mod sprite; pub use animated_sprite::*; use hv_cell::AtomicRefCell; +use hv_lua::{FromLua, ToLua, UserData}; pub use sprite::*; use std::{ - borrow::{Borrow, BorrowMut}, + borrow::{Borrow, BorrowMut, Cow}, sync::Arc, }; +use tealr::{ + mlu::{TealData, UserDataWrapper}, + TypeBody, TypeName, +}; use macroquad::prelude::*; use hecs::World; -use core::Transform; +use core::{lua::get_table, Transform}; /// This is a wrapper type for all the different types of drawable sprites, used so that we can /// access them all in one query and draw them, ordered, in one pass, according to `draw_order`. +#[derive(Clone, TypeName)] pub struct Drawable { /// This is used to specify draw order on a sprite /// This will be used, primarily, by `Player` to draw equipped items in the right order, relative @@ -27,6 +33,36 @@ pub struct Drawable { pub kind: DrawableKind, } +impl<'lua> FromLua<'lua> for Drawable { + fn from_lua(lua_value: hv_lua::Value<'lua>, _: &'lua hv_lua::Lua) -> hv_lua::Result { + let table = get_table(lua_value)?; + Ok(Self { + draw_order: table.get("draw_order")?, + kind: table.get("kind")?, + }) + } +} +impl<'lua> ToLua<'lua> for Drawable { + fn to_lua(self, lua: &'lua hv_lua::Lua) -> hv_lua::Result> { + let table = lua.create_table()?; + table.set("draw_order", self.draw_order)?; + table.set("kind", self.kind)?; + lua.pack(table) + } +} +impl TypeBody for Drawable { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("draw_order"), + tealr::type_parts_to_str(u32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("kind"), + tealr::type_parts_to_str(DrawableKind::get_type_parts()), + )); + } +} + impl Drawable { pub fn new_sprite(draw_order: u32, texture_id: &str, params: SpriteParams) -> Self { let sprite = Sprite::new(texture_id, params); @@ -126,12 +162,51 @@ impl Drawable { } } +#[derive(Clone, TypeName)] pub enum DrawableKind { Sprite(Sprite), SpriteSet(SpriteSet), AnimatedSprite(AnimatedSprite), AnimatedSpriteSet(AnimatedSpriteSet), } +impl UserData for DrawableKind { + fn add_methods<'lua, M: hv_lua::UserDataMethods<'lua, Self>>(methods: &mut M) { + let mut wrapper = UserDataWrapper::from_user_data_methods(methods); + ::add_methods(&mut wrapper) + } +} +impl TealData for DrawableKind { + fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { + methods.add_method("try_get_sprite", |_, this, ()| { + if let DrawableKind::Sprite(x) = this { + Ok((true, Some(x.to_owned()))) + } else { + Ok((false, None)) + } + }); + methods.add_method("try_get_sprite_set", |_, this, ()| { + if let DrawableKind::SpriteSet(x) = this { + Ok((true, Some(x.to_owned()))) + } else { + Ok((false, None)) + } + }); + methods.add_method("try_get_animated_sprite", |_, this, ()| { + if let DrawableKind::AnimatedSprite(x) = this { + Ok((true, Some(x.to_owned()))) + } else { + Ok((false, None)) + } + }); + methods.add_method("try_get_animated_sprite_set", |_, this, ()| { + if let DrawableKind::AnimatedSpriteSet(x) = this { + Ok((true, Some(x.to_owned()))) + } else { + Ok((false, None)) + } + }); + } +} pub fn draw_drawables(world: Arc>) { let mut world = AtomicRefCell::borrow_mut(world.as_ref()); diff --git a/src/drawables/sprite.rs b/src/drawables/sprite.rs index 222cfc48a9..da7b3ddb08 100644 --- a/src/drawables/sprite.rs +++ b/src/drawables/sprite.rs @@ -1,19 +1,24 @@ -use std::collections::HashMap; +use core::lua::get_table; +use core::lua::wrapped_types::{ColorLua, Vec2Lua}; use std::iter::FromIterator; use std::ops::Div; +use std::{borrow::Cow, collections::HashMap}; +use hv_lua::{FromLua, ToLua, UserData}; use macroquad::color; use macroquad::experimental::collections::storage; use macroquad::prelude::*; use serde::{Deserialize, Serialize}; +use tealr::mlu::{TealData, UserDataWrapper}; +use tealr::{TypeBody, TypeName}; use core::Transform; use crate::Resources; /// Parameters for `Sprite` component. -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, tealr::TypeName)] pub struct SpriteMetadata { /// The id of the texture that will be used #[serde(rename = "texture")] @@ -58,6 +63,43 @@ pub struct SpriteMetadata { pub is_deactivated: bool, } +impl TypeBody for SpriteMetadata { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("texture"), + tealr::type_parts_to_str(String::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("index"), + tealr::type_parts_to_str(usize::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("scale"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("offset"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("pivot"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("size"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("tint"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_deactivated"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + } +} + impl Default for SpriteMetadata { fn default() -> Self { SpriteMetadata { @@ -73,7 +115,7 @@ impl Default for SpriteMetadata { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, TypeName)] pub struct Sprite { pub texture: Texture2D, pub source_rect: Rect, @@ -86,6 +128,12 @@ pub struct Sprite { pub is_deactivated: bool, } +impl UserData for Sprite {} +impl TealData for Sprite {} +impl TypeBody for Sprite { + fn get_type_body(_: &mut tealr::TypeGenerator) {} +} + impl Sprite { pub fn new(texture_id: &str, params: SpriteParams) -> Self { let texture_res = { @@ -146,7 +194,7 @@ impl Sprite { } } -#[derive(Clone)] +#[derive(Clone, TypeName)] pub struct SpriteParams { pub sprite_size: Option, pub index: usize, @@ -160,6 +208,87 @@ pub struct SpriteParams { pub is_deactivated: bool, } +impl<'lua> FromLua<'lua> for SpriteParams { + fn from_lua(lua_value: hv_lua::Value<'lua>, _: &'lua hv_lua::Lua) -> hv_lua::Result { + let table = get_table(lua_value)?; + Ok(Self { + sprite_size: table + .get::<_, Option>("sprite_size")? + .map(Vec2::from), + index: table.get("index")?, + scale: table.get("scale")?, + offset: table.get::<_, Vec2Lua>("offset")?.into(), + pivot: table.get::<_, Option>("pivot")?.map(Vec2::from), + size: table.get::<_, Option>("size")?.map(Vec2::from), + tint: table.get::<_, Option>("tint")?.map(Color::from), + is_flipped_x: table.get("is_flipped_x")?, + is_flipped_y: table.get("is_flipped_y")?, + is_deactivated: table.get("is_deactivated")?, + }) + } +} +impl<'lua> ToLua<'lua> for SpriteParams { + fn to_lua(self, lua: &'lua hv_lua::Lua) -> hv_lua::Result> { + let table = lua.create_table()?; + table.set("sprite_size", self.sprite_size.map(Vec2Lua::from))?; + table.set("index", self.index)?; + table.set("scale", self.scale)?; + table.set("offset", Vec2Lua::from(self.offset))?; + table.set("pivot", self.pivot.map(Vec2Lua::from))?; + table.set("size", self.size.map(Vec2Lua::from))?; + table.set("tint", self.tint.map(ColorLua::from))?; + table.set("is_flipped_x", self.is_flipped_x)?; + table.set("is_flipped_y", self.is_flipped_y)?; + table.set("is_deactivated", self.is_deactivated)?; + lua.pack(table) + } +} + +impl TypeBody for SpriteParams { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("sprite_size"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("index"), + tealr::type_parts_to_str(usize::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("scale"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("offset"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("pivot"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("size"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("tint"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_flipped_x"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_flipped_y"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_deactivated"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + } +} + impl Default for SpriteParams { fn default() -> Self { SpriteParams { @@ -228,7 +357,7 @@ pub fn debug_draw_one_sprite(position: Vec2, sprite: &Sprite) { } } -#[derive(Debug)] +#[derive(Debug, Clone, TypeName)] pub struct SpriteSet { pub draw_order: Vec, pub map: HashMap, @@ -248,6 +377,34 @@ impl From<&[(&str, Sprite)]> for SpriteSet { } } +impl UserData for SpriteSet { + fn add_methods<'lua, M: hv_lua::UserDataMethods<'lua, Self>>(methods: &mut M) { + let mut wrapper = UserDataWrapper::from_user_data_methods(methods); + ::add_methods(&mut wrapper) + } +} +impl TealData for SpriteSet { + fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { + methods.add_method("is_empty", |_, this, ()| Ok(this.is_empty())); + methods.add_method_mut("flip_all_x", |_, this, state| { + this.flip_all_x(state); + Ok(()) + }); + methods.add_method_mut("flip_all_x", |_, this, state| { + this.flip_all_y(state); + Ok(()) + }); + methods.add_method_mut("activate_all", |_, this, ()| { + this.activate_all(); + Ok(()) + }); + methods.add_method_mut("deactivate_all", |_, this, ()| { + this.deactivate_all(); + Ok(()) + }); + } +} + impl SpriteSet { pub fn is_empty(&self) -> bool { self.draw_order.is_empty() diff --git a/src/effects/active/mod.rs b/src/effects/active/mod.rs index e7b6fae3c8..b6bc133552 100644 --- a/src/effects/active/mod.rs +++ b/src/effects/active/mod.rs @@ -6,7 +6,9 @@ use macroquad::color; use macroquad::experimental::collections::storage; use macroquad::prelude::*; +use mlua::{FromLua, ToLua}; use serde::{Deserialize, Serialize}; +use tealr::mlu::TealData; use core::math::{deg_to_rad, rotate_vector, IsZero}; use core::Result; @@ -30,17 +32,25 @@ pub use projectiles::ProjectileKind; const COLLIDER_DEBUG_DRAW_TTL: f32 = 0.5; +use hv_lua as mlua; +use tealr::{MluaTealDerive, TypeName}; +#[derive(Clone, MluaTealDerive)] struct CircleCollider { r: f32, ttl_timer: f32, } +impl TealData for CircleCollider {} + +#[derive(Clone, MluaTealDerive)] struct RectCollider { w: f32, h: f32, ttl_timer: f32, } +impl TealData for RectCollider {} + pub fn spawn_active_effect( world: &mut World, owner: Entity, @@ -199,7 +209,7 @@ pub fn spawn_active_effect( /// This holds all the common parameters, available to all implementations, as well as specialized /// parameters, in the `ActiveEffectKind`. -#[derive(Clone, Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize, TypeName)] pub struct ActiveEffectMetadata { /// This holds all the specialized parameters for the effect, dependent on the implementation, /// specified by its variant. It is flattened into this struct in JSON. @@ -220,12 +230,117 @@ pub struct ActiveEffectMetadata { pub delay: f32, } +impl<'lua> FromLua<'lua> for ActiveEffectMetadata { + fn from_lua(lua_value: mlua::Value<'lua>, _: &'lua mlua::Lua) -> mlua::Result { + let table = core::lua::get_table(lua_value)?; + Ok(Self { + kind: Box::new(table.get::<_, ActiveEffectKind>("kind")?), + sound_effect_id: table.get("sound_effect_id")?, + delay: table.get("delay")?, + }) + } +} + +impl<'lua> ToLua<'lua> for ActiveEffectMetadata { + fn to_lua(self, lua: &'lua mlua::Lua) -> mlua::Result> { + let table = lua.create_table()?; + table.set("kind", *self.kind)?; + table.set("sound_effect_id", self.sound_effect_id)?; + table.set("delay", self.delay)?; + lua.pack(table) + } +} + +#[derive(Clone, MluaTealDerive)] +struct ActiveEffectKindCircleCollider { + radius: f32, + passive_effects: Vec, + is_lethal: bool, + is_explosion: bool, +} +impl TealData for ActiveEffectKindCircleCollider { + fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { + methods.add_method("to_active_effect_kind", |_, this, ()| { + Ok(ActiveEffectKind::CircleCollider { + radius: this.radius, + passive_effects: this.passive_effects.to_owned(), + is_lethal: this.is_lethal, + is_explosion: this.is_explosion, + }) + }) + } +} + +#[derive(Clone, MluaTealDerive)] +struct ActiveEffectKindRectCollider { + width: f32, + height: f32, + /// If `true` the effect will do damage to any player it hits + is_lethal: bool, + /// This contains any passive effects that will be spawned on collision + passive_effects: Vec, +} + +impl TealData for ActiveEffectKindRectCollider { + fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { + methods.add_method("to_active_effect_kind", |_, this, ()| { + Ok(ActiveEffectKind::RectCollider { + width: this.width, + height: this.height, + is_lethal: this.is_lethal, + passive_effects: this.passive_effects.to_owned(), + }) + }) + } +} +#[derive(Clone, MluaTealDerive)] +struct ActiveEffectKindTriggeredEffect { + meta: Box, +} +impl TealData for ActiveEffectKindTriggeredEffect { + fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { + methods.add_method("to_active_effect_kind", |_, this, ()| { + Ok(ActiveEffectKind::TriggeredEffect { + meta: this.meta.to_owned(), + }) + }) + } +} + +#[derive(Clone, MluaTealDerive)] +struct ActiveEffectKindProjectile { + kind: ProjectileKind, + speed: f32, + range: f32, + spread: f32, + /// If `true` the effect will do damage to any player it hits + is_lethal: bool, + /// This contains any passive effects that will be spawned on collision + passive_effects: Vec, + /// Particle effects that will be attached to the projectile + particles: Vec, +} +impl TealData for ActiveEffectKindProjectile { + fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { + methods.add_method("to_active_effect_kind", |_, this, ()| { + Ok(ActiveEffectKind::Projectile { + kind: this.kind.to_owned(), + speed: this.speed, + range: this.range, + spread: this.spread, + is_lethal: this.is_lethal, + passive_effects: this.passive_effects.to_owned(), + particles: this.particles.to_owned(), + }) + }) + } +} /// This should hold implementations of the commonly used weapon effects, that see usage spanning /// many different weapon implementations. /// /// The effects that have the `Collider` suffix denote effects that do an immediate collider check, /// upon attack, using the weapons `effect_offset` as origin. -#[derive(Clone, Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize, MluaTealDerive)] #[serde(tag = "type", rename_all = "snake_case")] pub enum ActiveEffectKind { /// Check for hits with a `Circle` collider. @@ -286,6 +401,92 @@ pub enum ActiveEffectKind { }, } +impl TealData for ActiveEffectKind { + fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { + methods.add_method("try_get_circle_collider", |_, this, ()| { + if let ActiveEffectKind::CircleCollider { + radius, + passive_effects, + is_lethal, + is_explosion, + } = this + { + Ok(( + true, + Some(ActiveEffectKindCircleCollider { + radius: *radius, + passive_effects: passive_effects.to_owned(), + is_lethal: *is_lethal, + is_explosion: *is_explosion, + }), + )) + } else { + Ok((false, None)) + } + }); + methods.add_method("try_get_rect_collider", |_, this, ()| { + if let ActiveEffectKind::RectCollider { + width, + height, + is_lethal, + passive_effects, + } = this + { + Ok(( + true, + Some(ActiveEffectKindRectCollider { + width: *width, + height: *height, + is_lethal: *is_lethal, + passive_effects: passive_effects.to_owned(), + }), + )) + } else { + Ok((false, None)) + } + }); + methods.add_method("try_get_triggered_effect", |_, this, ()| { + if let ActiveEffectKind::TriggeredEffect { meta } = this { + Ok(( + true, + Some(ActiveEffectKindTriggeredEffect { + meta: meta.to_owned(), + }), + )) + } else { + Ok((false, None)) + } + }); + methods.add_method("try_get_triggered_projectile", |_, this, ()| { + if let ActiveEffectKind::Projectile { + kind, + speed, + range, + spread, + is_lethal, + passive_effects, + particles, + } = this + { + Ok(( + true, + Some(ActiveEffectKindProjectile { + kind: kind.to_owned(), + speed: *speed, + range: *range, + spread: *spread, + is_lethal: *is_lethal, + passive_effects: passive_effects.to_owned(), + particles: particles.to_owned(), + }), + )) + } else { + Ok((false, None)) + } + }) + } +} + pub fn debug_draw_active_effects(world: Arc>) { let mut world = AtomicRefCell::borrow_mut(world.as_ref()); let mut to_remove = Vec::new(); diff --git a/src/effects/active/projectiles.rs b/src/effects/active/projectiles.rs index 5809cccb9b..b02f92229d 100644 --- a/src/effects/active/projectiles.rs +++ b/src/effects/active/projectiles.rs @@ -1,8 +1,14 @@ +use core::lua::get_table; +use core::lua::wrapped_types::{ColorLua, Vec2Lua}; use hv_cell::AtomicRefCell; use macroquad::experimental::collections::storage; use macroquad::prelude::*; +use mlua::{FromLua, ToLua}; +use std::borrow::Cow; use std::f32::consts::PI; use std::sync::Arc; +use tealr::mlu::TealData; +use tealr::{MluaTealDerive, TypeBody, TypeName}; use hecs::{Entity, World}; use macroquad_platformer::Tile; @@ -19,7 +25,58 @@ use core::Transform; const PROJECTILE_DRAW_ORDER: u32 = 1; -#[derive(Debug, Clone, Serialize, Deserialize)] +use hv_lua as mlua; + +#[derive(Clone, MluaTealDerive)] +struct Circle { + radius: f32, + color: ColorLua, +} +impl TealData for Circle { + fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { + methods.add_method("to_projectile_kind", |_, this, ()| { + Ok(ProjectileKind::Circle { + radius: this.radius, + color: this.color.to_owned().into(), + }) + }) + } +} + +#[derive(Clone, MluaTealDerive)] +struct Rectangle { + width: f32, + height: f32, + color: ColorLua, +} +impl TealData for Rectangle { + fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { + methods.add_method("to_projectile_kind", |_, this, ()| { + Ok(ProjectileKind::Rect { + width: this.width, + height: this.height, + color: this.color.to_owned().into(), + }) + }) + } +} +#[derive(Clone, MluaTealDerive)] +struct Sprite { + params: SpriteMetadata, + can_rotate: bool, +} +impl TealData for Sprite { + fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { + methods.add_method("to_projectile_kind", |_, this, ()| { + Ok(ProjectileKind::Sprite { + params: this.params.to_owned(), + can_rotate: this.can_rotate, + }) + }) + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, MluaTealDerive)] #[serde(tag = "type", rename_all = "snake_case")] pub enum ProjectileKind { Circle { @@ -42,7 +99,57 @@ pub enum ProjectileKind { can_rotate: bool, }, } +impl TealData for ProjectileKind { + fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { + methods.add_method("try_get_circle", |_, this, ()| { + if let ProjectileKind::Circle { radius, color } = this { + Ok(( + true, + Some(Circle { + radius: radius.to_owned(), + color: color.to_owned().into(), + }), + )) + } else { + Ok((false, None)) + } + }); + methods.add_method("try_get_rect", |_, this, ()| { + if let ProjectileKind::Rect { + width, + height, + color, + } = this + { + Ok(( + true, + Some(Rectangle { + width: *width, + height: *height, + color: color.to_owned().into(), + }), + )) + } else { + Ok((false, None)) + } + }); + methods.add_method("try_get_sprite", |_, this, ()| { + if let ProjectileKind::Sprite { can_rotate, params } = this { + Ok(( + true, + Some(Sprite { + can_rotate: *can_rotate, + params: params.to_owned(), + }), + )) + } else { + Ok((false, None)) + } + }); + } +} +#[derive(Clone, TypeName)] pub struct Projectile { pub kind: ProjectileKind, pub owner: Entity, @@ -52,6 +159,61 @@ pub struct Projectile { pub passive_effects: Vec, } +impl<'lua> FromLua<'lua> for Projectile { + fn from_lua(lua_value: mlua::Value<'lua>, _: &'lua mlua::Lua) -> mlua::Result { + let table = get_table(lua_value)?; + Ok(Self { + kind: table.get("kind")?, + owner: table.get("owner")?, + origin: table.get::<_, Vec2Lua>("origin")?.into(), + range: table.get("range")?, + is_lethal: table.get("is_lethal")?, + passive_effects: table.get("passive_effects")?, + }) + } +} +impl<'lua> ToLua<'lua> for Projectile { + fn to_lua(self, lua: &'lua mlua::Lua) -> mlua::Result> { + let table = lua.create_table()?; + table.set("kind", self.kind)?; + table.set("owner", self.owner)?; + table.set("origin", Vec2Lua::from(self.origin))?; + table.set("range", self.range)?; + table.set("is_lethal", self.is_lethal)?; + table.set("passive_effects", self.passive_effects)?; + lua.pack(table) + } +} + +impl TypeBody for Projectile { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("kind"), + tealr::type_parts_to_str(ProjectileKind::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("owner"), + tealr::type_parts_to_str(Entity::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("origin"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("range"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_lethal"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("passive_effects"), + tealr::type_parts_to_str(Vec::::get_type_parts()), + )); + } +} + impl Projectile { pub fn new( owner: Entity, diff --git a/src/effects/active/triggered.rs b/src/effects/active/triggered.rs index 2641412038..a00a11c913 100644 --- a/src/effects/active/triggered.rs +++ b/src/effects/active/triggered.rs @@ -1,11 +1,14 @@ use hv_cell::AtomicRefCell; +use hv_lua::{FromLua, ToLua}; use macroquad::experimental::collections::storage; use macroquad::prelude::*; use hecs::{Entity, World}; use serde::{Deserialize, Serialize}; +use tealr::{TypeBody, TypeName}; +use core::lua::get_table; use core::math::deg_to_rad; use core::{Result, Transform}; use std::sync::Arc; @@ -20,7 +23,7 @@ use crate::{Drawable, PhysicsBodyParams}; const TRIGGERED_EFFECT_DRAW_ORDER: u32 = 5; /// The various collision types that can trigger a `TriggeredEffect`. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, TypeName)] #[serde(rename_all = "snake_case")] pub enum TriggeredEffectTrigger { /// The player that deployed the effect @@ -34,7 +37,21 @@ pub enum TriggeredEffectTrigger { /// Projectile hit Projectile, } +impl<'lua> FromLua<'lua> for TriggeredEffectTrigger { + fn from_lua(lua_value: hv_lua::Value<'lua>, lua: &'lua hv_lua::Lua) -> hv_lua::Result { + hv_lua::LuaSerdeExt::from_value(lua, lua_value) + } +} +impl<'lua> ToLua<'lua> for TriggeredEffectTrigger { + fn to_lua(self, lua: &'lua hv_lua::Lua) -> hv_lua::Result> { + hv_lua::LuaSerdeExt::to_value(lua, &self) + } +} +impl TypeBody for TriggeredEffectTrigger { + fn get_type_body(_: &mut tealr::TypeGenerator) {} +} +#[derive(Clone, TypeName)] pub struct TriggeredEffect { pub owner: Entity, pub trigger: Vec, @@ -56,6 +73,29 @@ pub struct TriggeredEffect { pub timed_trigger_timer: f32, } +impl<'lua> FromLua<'lua> for TriggeredEffect { + fn from_lua(lua_value: hv_lua::Value<'lua>, lua: &'lua hv_lua::Lua) -> hv_lua::Result { + let table = get_table(lua_value)?; + Ok(Self { + owner: table.get("owner")?, + trigger: table.get("trigger")?, + effects: table.get("effects")?, + activation_delay: table.get("activation_delay")?, + trigger_delay: table.get("trigger_delay")?, + timed_trigger: table.get("timed_trigger")?, + is_kickable: table.get("is_kickable")?, + should_override_delay: table.get("should_override_delay")?, + should_collide_with_platforms: table.get("should_collide_with_platforms")?, + is_triggered: table.get("is_triggered")?, + triggered_by: table.get("triggered_by")?, + kick_delay_timer: table.get("kick_delay_timer")?, + activation_timer: table.get("activation_timer")?, + trigger_delay_timer: table.get("trigger_delay_timer")?, + timed_trigger_timer: table.get("timed_trigger_timer")?, + }) + } +} + impl TriggeredEffect { pub fn new(owner: Entity, meta: TriggeredEffectMetadata) -> Self { TriggeredEffect { diff --git a/src/effects/passive/mod.rs b/src/effects/passive/mod.rs index 1efed2b452..827e06b159 100644 --- a/src/effects/passive/mod.rs +++ b/src/effects/passive/mod.rs @@ -1,10 +1,13 @@ +use std::borrow::Cow; use std::collections::HashMap; +use hv_lua::{FromLua, ToLua}; use macroquad::prelude::*; use serde::{Deserialize, Serialize}; use hecs::{Entity, World}; +use tealr::{TypeBody, TypeName}; mod turtle_shell; @@ -96,7 +99,7 @@ impl PassiveEffectInstance { } } -#[derive(Clone, Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize, TypeName)] pub struct PassiveEffectMetadata { pub name: String, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -128,3 +131,52 @@ pub struct PassiveEffectMetadata { #[serde(default, skip_serializing_if = "Option::is_none")] pub duration: Option, } + +impl<'lua> FromLua<'lua> for PassiveEffectMetadata { + fn from_lua(lua_value: hv_lua::Value<'lua>, lua: &'lua hv_lua::Lua) -> hv_lua::Result { + hv_lua::LuaSerdeExt::from_value(lua, lua_value) + } +} + +impl<'lua> ToLua<'lua> for PassiveEffectMetadata { + fn to_lua(self, lua: &'lua hv_lua::Lua) -> hv_lua::Result> { + hv_lua::LuaSerdeExt::to_value(lua, &self) + } +} + +impl TypeBody for PassiveEffectMetadata { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("name"), + tealr::type_parts_to_str(String::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("function_id"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("activated_on"), + tealr::type_parts_to_str(Vec::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("particle_effect"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("event_particle_effect"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("blocks_damage"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("uses"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("duration"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + } +} diff --git a/src/player/events.rs b/src/player/events.rs index 07652a8db7..fbfb75cb22 100644 --- a/src/player/events.rs +++ b/src/player/events.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use hecs::{Entity, World}; use hv_cell::AtomicRefCell; use macroquad::time::get_frame_time; +use tealr::{TypeBody, TypeName}; use crate::player::{Player, PlayerState}; use serde::{Deserialize, Serialize}; @@ -43,7 +44,7 @@ pub enum PlayerEvent { } /// This is used in JSON to specify which event types an effect should apply to -#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, TypeName)] #[serde(rename_all = "snake_case")] pub enum PlayerEventKind { Update, @@ -54,6 +55,10 @@ pub enum PlayerEventKind { Collision, } +impl TypeBody for PlayerEventKind { + fn get_type_body(gen: &mut tealr::TypeGenerator) {} +} + impl From<&PlayerEvent> for PlayerEventKind { fn from(params: &PlayerEvent) -> Self { use PlayerEvent::*; From a19dba933727bf5c74bde9cb2f56a82fd0a18dc8 Mon Sep 17 00:00:00 2001 From: lenscas Date: Thu, 17 Mar 2022 21:30:42 +0100 Subject: [PATCH 18/21] share last types with lua --- Cargo.lock | 5 +- core/src/lua/create_component.rs | 11 -- core/src/lua/mod.rs | 2 +- core/src/lua/wrapped_types.rs | 29 ++- mods/test_lua_mod_one/main.lua | 37 ++-- src/ecs.rs | 8 + src/effects/active/triggered.rs | 93 ++++++++- src/effects/passive/mod.rs | 241 +++++++++++++++++++++++- src/items.rs | 314 ++++++++++++++++++++++++++++++- src/lua.rs | 20 +- src/particles.rs | 15 +- src/player/events.rs | 35 +++- src/player/inventory.rs | 83 +++++++- src/player/mod.rs | 105 ++++++++++- src/player/state.rs | 56 +++--- 15 files changed, 981 insertions(+), 73 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index de3c962d0b..5ef6124af6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1557,10 +1557,11 @@ dependencies = [ [[package]] name = "tealr" version = "0.8.2" -source = "git+https://github.com/lenscas/tealr?branch=temporary/feature/add_support_for_hv_lua#ca12ea91b2047a7fc72f7650e861b006b7bb89f4" +source = "git+https://github.com/lenscas/tealr?branch=temporary/feature/add_support_for_hv_lua#e0a96b3a6862ae55cb9fa93b6e93e4764987ade3" dependencies = [ "bstr", "hecs", + "hv-cell", "hv-elastic", "hv-guarded-borrow", "hv-lua", @@ -1572,7 +1573,7 @@ dependencies = [ [[package]] name = "tealr_derive" version = "0.8.2" -source = "git+https://github.com/lenscas/tealr?branch=temporary/feature/add_support_for_hv_lua#ca12ea91b2047a7fc72f7650e861b006b7bb89f4" +source = "git+https://github.com/lenscas/tealr?branch=temporary/feature/add_support_for_hv_lua#e0a96b3a6862ae55cb9fa93b6e93e4764987ade3" dependencies = [ "proc-macro2", "quote", diff --git a/core/src/lua/create_component.rs b/core/src/lua/create_component.rs index fdfc34c8d4..b06895c00b 100644 --- a/core/src/lua/create_component.rs +++ b/core/src/lua/create_component.rs @@ -3,15 +3,8 @@ use std::borrow::Cow; use hv_lua::{FromLua, ToLua}; use tealr::{NamePart, TealType, TypeName}; -///This trait is used to limit what types can be set in the create_type_component_container macro -///It doesn't really have a use outside of that. -pub trait Component { - fn is_component() {} -} - #[derive(Debug, Clone, Copy)] pub struct CopyComponent(T); -impl Component for CopyComponent {} impl hv_lua::UserData for CopyComponent where T: for<'a> ToLua<'a> + for<'a> FromLua<'a>, @@ -56,7 +49,6 @@ impl tealr::TypeBody for CopyComponent { #[derive(Debug, Clone, Copy)] pub struct CloneComponent(T); -impl Component for CloneComponent {} impl hv_lua::UserData for CloneComponent where T: for<'a> ToLua<'a> + for<'a> FromLua<'a>, @@ -138,7 +130,6 @@ macro_rules! create_type_component_container { impl<'lua> tealr::TypeBody for $name<'lua> { fn get_type_body(gen: &mut tealr::TypeGenerator) { $( - <$type_name as $crate::lua::Component>::is_component(); gen.fields.push( ( std::borrow::Cow::Borrowed( @@ -156,9 +147,7 @@ macro_rules! create_type_component_container { impl<'lua> $name<'lua> { pub fn new(lua: &'lua hv_lua::Lua) -> Result> { let table = lua.create_table()?; - use $crate::lua::Component; $( - <$type_name as Component>::is_component(); table.set(stringify!($field_name),lua.create_userdata_type::<$type_name>()?)?; )* Ok(Self(table)) diff --git a/core/src/lua/mod.rs b/core/src/lua/mod.rs index 97cfe012a2..c721dc9c0f 100644 --- a/core/src/lua/mod.rs +++ b/core/src/lua/mod.rs @@ -1,6 +1,6 @@ mod create_component; pub mod wrapped_types; -pub use create_component::{CloneComponent, Component, CopyComponent}; +pub use create_component::{CloneComponent, CopyComponent}; use std::{error::Error, os::unix::prelude::OsStrExt, path::Path}; diff --git a/core/src/lua/wrapped_types.rs b/core/src/lua/wrapped_types.rs index 6a90ea0292..d67745fa1c 100644 --- a/core/src/lua/wrapped_types.rs +++ b/core/src/lua/wrapped_types.rs @@ -1,7 +1,10 @@ use std::borrow::Cow; use hv_lua::{FromLua, ToLua, UserData, Value}; -use macroquad::prelude::{Color, Rect, Texture2D, Vec2}; +use macroquad::{ + audio::Sound, + prelude::{Color, Rect, Texture2D, Vec2}, +}; use tealr::{ mlu::{TealData, UserDataWrapper}, new_type, TypeBody, TypeName, @@ -262,3 +265,27 @@ impl From for Texture2DLua { Self(x) } } + +#[derive(Clone)] +pub struct SoundLua(Sound); +impl TypeName for SoundLua { + fn get_type_parts() -> Cow<'static, [tealr::NamePart]> { + new_type!(Sound, External) + } +} +impl UserData for SoundLua {} +impl TealData for SoundLua {} +impl TypeBody for SoundLua { + fn get_type_body(_: &mut tealr::TypeGenerator) {} +} + +impl From for SoundLua { + fn from(s: Sound) -> Self { + Self(s) + } +} +impl From for Sound { + fn from(x: SoundLua) -> Self { + x.0 + } +} diff --git a/mods/test_lua_mod_one/main.lua b/mods/test_lua_mod_one/main.lua index 1d5b4abbf7..b76b31e48e 100644 --- a/mods/test_lua_mod_one/main.lua +++ b/mods/test_lua_mod_one/main.lua @@ -7,24 +7,27 @@ return { local I32 = type_components.I32 local Bool = type_components.Bool entity = world:spawn { I32.new(5), Bool.new(true) } + for k,v in pairs(type_components) do + print(k,v) + end end, fixed_update_physics_bodies = function(world) - local Query = hv.ecs.Query - local I32 = type_components.I32 - local Bool = type_components.Bool - local query = Query.new { Query.write(I32), Query.read(Bool) } - world:query_one(query, entity, function(item) - print("Got item:",item) - --Querying allows us to access components of our item as userdata objects through the same interface - --we defined above! - print("asserting if still true") - assert(item:take(Bool).value == true) - local i = item:take(I32) - print("asserting if still bigger than 5") - assert(i.value >= 5) - print("time to increment by 1") - i.value = i.value + 1 - print("Current value:", i.value) - end) + -- local Query = hv.ecs.Query + -- local I32 = type_components.I32 + -- local Bool = type_components.Bool + -- local query = Query.new { Query.write(I32), Query.read(Bool) } + -- world:query_one(query, entity, function(item) + -- print("Got item:",item) + -- -- Querying allows us to access components of our item as userdata objects through the same interface + -- -- we defined above! + -- print("asserting if still true") + -- assert(item:take(Bool).value == true) + -- local i = item:take(I32) + -- print("asserting if still bigger than 5") + -- assert(i.value >= 5) + -- print("time to increment by 1") + -- i.value = i.value + 1 + -- print("Current value:", i.value) + -- end) end } \ No newline at end of file diff --git a/src/ecs.rs b/src/ecs.rs index 6c6b627321..c385c4a9dc 100644 --- a/src/ecs.rs +++ b/src/ecs.rs @@ -2,12 +2,20 @@ use std::sync::Arc; use hecs::{Entity, World}; use hv_cell::AtomicRefCell; +use hv_lua::UserData; +use tealr::{mlu::TealData, TypeBody, TypeName}; pub type SystemFn = fn(Arc>); /// This is used as a component to signify ownership +#[derive(Clone, TypeName)] pub struct Owner(pub Entity); +impl UserData for Owner {} +impl TealData for Owner {} +impl TypeBody for Owner { + fn get_type_body(_: &mut tealr::TypeGenerator) {} +} /// Placeholder until we implement threading #[derive(Default)] pub struct SchedulerBuilder { diff --git a/src/effects/active/triggered.rs b/src/effects/active/triggered.rs index a00a11c913..b93eb0f44c 100644 --- a/src/effects/active/triggered.rs +++ b/src/effects/active/triggered.rs @@ -11,6 +11,7 @@ use tealr::{TypeBody, TypeName}; use core::lua::get_table; use core::math::deg_to_rad; use core::{Result, Transform}; +use std::borrow::Cow; use std::sync::Arc; use crate::effects::active::spawn_active_effect; @@ -74,7 +75,7 @@ pub struct TriggeredEffect { } impl<'lua> FromLua<'lua> for TriggeredEffect { - fn from_lua(lua_value: hv_lua::Value<'lua>, lua: &'lua hv_lua::Lua) -> hv_lua::Result { + fn from_lua(lua_value: hv_lua::Value<'lua>, _: &'lua hv_lua::Lua) -> hv_lua::Result { let table = get_table(lua_value)?; Ok(Self { owner: table.get("owner")?, @@ -96,6 +97,96 @@ impl<'lua> FromLua<'lua> for TriggeredEffect { } } +impl<'lua> ToLua<'lua> for TriggeredEffect { + fn to_lua(self, lua: &'lua hv_lua::Lua) -> hv_lua::Result> { + let table = lua.create_table()?; + table.set("owner", self.owner)?; + table.set("trigger", self.trigger)?; + table.set("effects", self.effects)?; + table.set("activation_delay", self.activation_delay)?; + table.set("trigger_delay", self.trigger_delay)?; + table.set("timed_trigger", self.timed_trigger)?; + table.set("is_kickable", self.is_kickable)?; + table.set("should_override_delay", self.should_override_delay)?; + table.set( + "should_collide_with_platforms", + self.should_collide_with_platforms, + )?; + table.set("is_triggered", self.is_triggered)?; + table.set("triggered_by", self.triggered_by)?; + table.set("kick_delay_timer", self.kick_delay_timer)?; + table.set("activation_timer", self.activation_timer)?; + table.set("trigger_delay_timer", self.trigger_delay_timer)?; + table.set("timed_trigger_timer", self.timed_trigger_timer)?; + lua.pack(table) + } +} + +impl TypeBody for TriggeredEffect { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("owner"), + tealr::type_parts_to_str(Entity::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("trigger"), + tealr::type_parts_to_str(Vec::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("effects"), + tealr::type_parts_to_str(Vec::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("activation_delay"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("trigger_delay"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("timed_trigger"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_kickable"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("should_override_delay"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("should_collide_with_platforms"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_triggered"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("triggered_by"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("kick_delay_timer"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("activation_timer"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("trigger_delay_timer"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("timed_trigger_timer"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + } +} + impl TriggeredEffect { pub fn new(owner: Entity, meta: TriggeredEffectMetadata) -> Self { TriggeredEffect { diff --git a/src/effects/passive/mod.rs b/src/effects/passive/mod.rs index 827e06b159..3e0c1fe5dc 100644 --- a/src/effects/passive/mod.rs +++ b/src/effects/passive/mod.rs @@ -1,12 +1,15 @@ use std::borrow::Cow; use std::collections::HashMap; +use std::sync::Arc; -use hv_lua::{FromLua, ToLua}; +use hv_cell::AtomicRefCell; +use hv_lua::{FromLua, Function, RegistryKey, Table, ToLua, UserData}; use macroquad::prelude::*; use serde::{Deserialize, Serialize}; use hecs::{Entity, World}; +use tealr::mlu::{TealData, TypedFunction, UserDataWrapper}; use tealr::{TypeBody, TypeName}; mod turtle_shell; @@ -36,6 +39,108 @@ pub fn get_passive_effect(id: &str) -> &PassiveEffectFn { pub type PassiveEffectFn = fn(world: &mut World, player_entity: Entity, item_entity: Option, event: PlayerEvent); +#[derive(Clone)] +pub enum PassiveEffectFnContainer { + SimpleFn(PassiveEffectFn), + ///we are going to keep the functions inside the lua vm. So, this is just a way to find the function back + LuaFnPointer(Arc), +} + +impl From for PassiveEffectFnContainer { + fn from(value: PassiveEffectFn) -> Self { + Self::SimpleFn(value) + } +} + +impl PassiveEffectFnContainer { + pub fn call_get_lua( + &self, + world: Arc>, + player_entity: Entity, + item_entity: Option, + event: PlayerEvent, + ) -> hv_lua::Result<()> { + match self { + PassiveEffectFnContainer::SimpleFn(x) => { + x(&mut world.borrow_mut(), player_entity, item_entity, event); + Ok(()) + } + PassiveEffectFnContainer::LuaFnPointer(_) => { + todo!("Tried calling a PassiveEffectFnContainer::LuaFnPointer. This should not yet be possible") + } + } + } + pub fn call( + &self, + lua: &hv_lua::Lua, + world: Arc>, + player_entity: Entity, + item_entity: Option, + event: PlayerEvent, + ) -> hv_lua::Result<()> { + match self { + PassiveEffectFnContainer::SimpleFn(x) => { + x(&mut world.borrow_mut(), player_entity, item_entity, event); + Ok(()) + } + PassiveEffectFnContainer::LuaFnPointer(key) => { + let data = lua.registry_value::(key)?; + let globals = lua.globals(); + let old_require = globals.get::<_, Option>("require")?; + let new_require = data.get::<_, Function>("require")?; + let function = data.get::<_, TypedFunction< + ( + Arc>, + Entity, + Option, + PlayerEvent, + ), + (), + >>("function")?; + globals.set("require", new_require)?; + let res = function.call((world, player_entity, item_entity, event)); + //if this fails then the `require` function isn't the same one as which we started with + //this could be a problem, however I think it is unlikely to happen as this value comes from the lua instance already. + //Also, if the value of `old_require` is None then this doesn't matter. + globals.set("require", old_require)?; + res + } + } + } +} + +impl TypeName for PassiveEffectFnContainer { + fn get_type_parts() -> Cow<'static, [tealr::NamePart]> { + //this is a lie + //however, I want to make it so the user doesn't need to know about this thing not being a function + //right now, it already acts like one as you can just call it on the lua side + //once https://github.com/sdleffler/hv-lua/pull/2 is merged, it should also be possible that it can be created by a normal function + //this should make it even more similar. + + //after that, the only thing that should be different is how it converts to a string, and the result of the typeof function + //both of those don't have a good solution, but only the `typeof` thing might be relevant. + tealr::mlu::TypedFunction::<(World,Entity,Option,PlayerEvent),()>::get_type_parts() + } +} + +impl UserData for PassiveEffectFnContainer { + fn add_methods<'lua, M: hv_lua::UserDataMethods<'lua, Self>>(methods: &mut M) { + let mut wrapper = UserDataWrapper::from_user_data_methods(methods); + ::add_methods(&mut wrapper) + } +} + +impl TealData for PassiveEffectFnContainer { + fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { + methods.add_meta_method( + tealr::mlu::mlua::MetaMethod::Call, + |lua, this, (world, player_entity, item_entity, event)| { + this.call(lua, world, player_entity, item_entity, event) + }, + ) + } +} + pub fn init_passive_effects() { let effects = unsafe { get_passive_effects_map() }; @@ -45,9 +150,10 @@ pub fn init_passive_effects() { ); } +#[derive(Clone, TypeName)] pub struct PassiveEffectInstance { pub name: String, - pub function: Option, + pub function: Option, pub activated_on: Vec, pub particle_effect_id: Option, pub event_particle_effect_id: Option, @@ -59,9 +165,137 @@ pub struct PassiveEffectInstance { pub duration_timer: f32, } +impl UserData for PassiveEffectInstance { + fn add_methods<'lua, M: hv_lua::UserDataMethods<'lua, Self>>(methods: &mut M) { + let mut wrapper = UserDataWrapper::from_user_data_methods(methods); + ::add_methods(&mut wrapper) + } + fn add_fields<'lua, F: hv_lua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("name", |_, this| Ok(this.name.to_owned())); + fields.add_field_method_get("function", |_, this| Ok(this.function.to_owned())); + fields.add_field_method_get("activated_on", |_, this| Ok(this.activated_on.to_owned())); + fields.add_field_method_get("particle_effect_id", |_, this| { + Ok(this.particle_effect_id.to_owned()) + }); + fields.add_field_method_get("event_particle_effect_id", |_, this| { + Ok(this.event_particle_effect_id.to_owned()) + }); + fields.add_field_method_get("blocks_damage", |_, this| Ok(this.blocks_damage)); + fields.add_field_method_get("uses", |_, this| Ok(this.uses)); + fields.add_field_method_get("item", |_, this| Ok(this.item)); + fields.add_field_method_get("use_cnt", |_, this| Ok(this.use_cnt)); + fields.add_field_method_get("duration", |_, this| Ok(this.duration)); + fields.add_field_method_get("duration_timer", |_, this| Ok(this.duration_timer)); + fields.add_field_method_set("name", |_, this, value| { + this.name = value; + Ok(()) + }); + fields.add_field_method_set("function", |_, this, value| { + this.function = value; + Ok(()) + }); + fields.add_field_method_set("activated_on", |_, this, value| { + this.activated_on = value; + Ok(()) + }); + fields.add_field_method_set("particle_effect_id", |_, this, value| { + this.particle_effect_id = value; + Ok(()) + }); + fields.add_field_method_set("event_particle_effect_id", |_, this, value| { + this.event_particle_effect_id = value; + Ok(()) + }); + fields.add_field_method_set("blocks_damage", |_, this, value| { + this.blocks_damage = value; + Ok(()) + }); + fields.add_field_method_set("uses", |_, this, value| { + this.uses = value; + Ok(()) + }); + fields.add_field_method_set("item", |_, this, value| { + this.item = value; + Ok(()) + }); + fields.add_field_method_set("use_cnt", |_, this, value| { + this.use_cnt = value; + Ok(()) + }); + fields.add_field_method_set("duration", |_, this, value| { + this.duration = value; + Ok(()) + }); + fields.add_field_method_set("duration_timer", |_, this, value| { + this.duration_timer = value; + Ok(()) + }); + } +} +impl TealData for PassiveEffectInstance { + fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { + methods.add_method_mut("update", |_, this, dt| { + this.update(dt); + Ok(()) + }); + methods.add_method("is_depleted", |_, this, ()| Ok(this.is_depleted())); + } +} + +impl TypeBody for PassiveEffectInstance { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.is_user_data = true; + ::add_methods(gen); + gen.fields.push(( + Cow::Borrowed("name"), + tealr::type_parts_to_str(String::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("function"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("activated_on"), + tealr::type_parts_to_str(Vec::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("particle_effect_id"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("event_particle_effect_id"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("blocks_damage"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("uses"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("item"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("use_cnt"), + tealr::type_parts_to_str(u32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("duration"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("duration_timer"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + } +} + impl PassiveEffectInstance { pub fn new(item: Option, meta: PassiveEffectMetadata) -> Self { - let function = meta.function_id.map(|id| *get_passive_effect(&id)); + let function = meta.function_id.map(|id| (*get_passive_effect(&id)).into()); PassiveEffectInstance { name: meta.name, @@ -98,7 +332,6 @@ impl PassiveEffectInstance { false } } - #[derive(Clone, Serialize, Deserialize, TypeName)] pub struct PassiveEffectMetadata { pub name: String, diff --git a/src/items.rs b/src/items.rs index 1ec8200205..1fb4749019 100644 --- a/src/items.rs +++ b/src/items.rs @@ -2,18 +2,23 @@ //! Proto-mods, eventually some of the items will move to some sort of a wasm runtime use hecs::{Entity, World}; +use hv_lua::{FromLua, ToLua}; use macroquad::audio::{play_sound_once, Sound}; use macroquad::experimental::collections::storage; use macroquad::prelude::*; use serde::{Deserialize, Serialize}; +use tealr::{TypeBody, TypeName}; use crate::{ ActiveEffectMetadata, AnimatedSprite, AnimatedSpriteMetadata, CollisionWorld, Drawable, PassiveEffectMetadata, PhysicsBody, QueuedAnimationAction, Resources, }; +use core::lua::get_table; +use core::lua::wrapped_types::{SoundLua, Vec2Lua}; use core::{Result, Transform}; +use std::borrow::Cow; use crate::effects::active::spawn_active_effect; use crate::particles::{ParticleEmitter, ParticleEmitterMetadata}; @@ -29,7 +34,7 @@ pub const GROUND_ANIMATION_ID: &str = "ground"; pub const ATTACK_ANIMATION_ID: &str = "attack"; /// This dictates what happens to an item when it is dropped, either manually or on death. -#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, TypeName)] #[serde(rename_all = "snake_case")] pub enum ItemDropBehavior { /// Clear all state and restore default parameters @@ -40,6 +45,21 @@ pub enum ItemDropBehavior { Destroy, } +impl<'lua> FromLua<'lua> for ItemDropBehavior { + fn from_lua(lua_value: hv_lua::Value<'lua>, lua: &'lua hv_lua::Lua) -> hv_lua::Result { + hv_lua::LuaSerdeExt::from_value(lua, lua_value) + } +} + +impl<'lua> ToLua<'lua> for ItemDropBehavior { + fn to_lua(self, lua: &'lua hv_lua::Lua) -> hv_lua::Result> { + hv_lua::LuaSerdeExt::to_value(lua, &self) + } +} +impl TypeBody for ItemDropBehavior { + fn get_type_body(_: &mut tealr::TypeGenerator) {} +} + impl Default for ItemDropBehavior { fn default() -> Self { ItemDropBehavior::ClearState @@ -48,7 +68,7 @@ impl Default for ItemDropBehavior { /// This dictates what happens to an item when it is depleted, either by exceeding its duration, /// in the case of `Equipment`, or by depleting `uses`, if specified, in the case of a `Weapon` -#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, TypeName)] #[serde(rename_all = "snake_case")] pub enum ItemDepleteBehavior { /// Keep the item on depletion (do nothing) @@ -59,6 +79,21 @@ pub enum ItemDepleteBehavior { Destroy, } +impl<'lua> FromLua<'lua> for ItemDepleteBehavior { + fn from_lua(lua_value: hv_lua::Value<'lua>, lua: &'lua hv_lua::Lua) -> hv_lua::Result { + hv_lua::LuaSerdeExt::from_value(lua, lua_value) + } +} + +impl<'lua> ToLua<'lua> for ItemDepleteBehavior { + fn to_lua(self, lua: &'lua hv_lua::Lua) -> hv_lua::Result> { + hv_lua::LuaSerdeExt::to_value(lua, &self) + } +} +impl TypeBody for ItemDepleteBehavior { + fn get_type_body(_: &mut tealr::TypeGenerator) {} +} + impl Default for ItemDepleteBehavior { fn default() -> Self { ItemDepleteBehavior::Keep @@ -89,6 +124,7 @@ pub struct ItemParams { pub is_hat: bool, } +#[derive(Clone, TypeName)] pub struct Item { pub id: String, pub name: String, @@ -103,6 +139,92 @@ pub struct Item { pub use_cnt: u32, } +impl<'lua> FromLua<'lua> for Item { + fn from_lua(lua_value: hv_lua::Value<'lua>, _: &'lua hv_lua::Lua) -> hv_lua::Result { + let table = get_table(lua_value)?; + Ok(Self { + id: table.get("id")?, + name: table.get("name")?, + effects: table.get("effects")?, + uses: table.get("uses")?, + duration: table.get("duration")?, + mount_offset: table.get::<_, Vec2Lua>("mount_offset")?.into(), + drop_behavior: table.get("drop_behavior")?, + deplete_behavior: table.get("deplete_behavior")?, + is_hat: table.get("is_hat")?, + duration_timer: table.get("duration_timer")?, + use_cnt: table.get("use_cnt")?, + }) + } +} + +impl<'lua> ToLua<'lua> for Item { + fn to_lua(self, lua: &'lua hv_lua::Lua) -> hv_lua::Result> { + let table = lua.create_table()?; + table.set("id", self.id)?; + table.set("name", self.name)?; + table.set("effects", self.effects)?; + table.set("uses", self.uses)?; + table.set("duration", self.duration)?; + table.set("mount_offset", Vec2Lua::from(self.mount_offset))?; + table.set("drop_behavior", self.drop_behavior)?; + table.set("deplete_behavior", self.deplete_behavior)?; + table.set("is_hat", self.is_hat)?; + table.set("duration_timer", self.duration_timer)?; + table.set("use_cnt", self.use_cnt)?; + lua.pack(table) + } +} + +impl TypeBody for Item { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("id"), + tealr::type_parts_to_str(String::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("name"), + tealr::type_parts_to_str(String::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("effects"), + tealr::type_parts_to_str(Vec::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("uses"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("duration"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("mount_offset"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("drop_behavior"), + tealr::type_parts_to_str(ItemDropBehavior::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("deplete_behavior"), + tealr::type_parts_to_str(ItemDepleteBehavior::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_hat"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("duration_timer"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("use_cnt"), + tealr::type_parts_to_str(u32::get_type_parts()), + )); + } +} + impl Item { pub fn new(id: &str, params: ItemParams) -> Self { Item { @@ -136,6 +258,34 @@ pub struct ItemMetadata { pub is_hat: bool, } +impl<'lua> FromLua<'lua> for ItemMetadata { + fn from_lua(lua_value: hv_lua::Value<'lua>, lua: &'lua hv_lua::Lua) -> hv_lua::Result { + hv_lua::LuaSerdeExt::from_value(lua, lua_value) + } +} +impl<'lua> ToLua<'lua> for ItemMetadata { + fn to_lua(self, lua: &'lua hv_lua::Lua) -> hv_lua::Result> { + hv_lua::LuaSerdeExt::to_value(lua, &self) + } +} + +impl TypeBody for ItemMetadata { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("effects"), + tealr::type_parts_to_str(Vec::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("duration"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_hat"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + } +} + #[derive(Clone, Serialize, Deserialize)] pub struct MapItemMetadata { pub id: String, @@ -340,6 +490,7 @@ impl Default for WeaponParams { } } +#[derive(Clone, TypeName)] pub struct Weapon { pub id: String, pub name: String, @@ -357,6 +508,112 @@ pub struct Weapon { pub use_cnt: u32, } +impl<'lua> FromLua<'lua> for Weapon { + fn from_lua(lua_value: hv_lua::Value<'lua>, _: &'lua hv_lua::Lua) -> hv_lua::Result { + let table = get_table(lua_value)?; + Ok(Self { + id: table.get("id")?, + name: table.get("name")?, + effects: table.get("effects")?, + sound_effect: table + .get::<_, Option>("sound_effect")? + .map(From::from), + recoil: table.get("recoil")?, + cooldown: table.get("cooldown")?, + attack_duration: table.get("attack_duration")?, + uses: table.get("uses")?, + mount_offset: table.get::<_, Vec2Lua>("mount_offset")?.into(), + effect_offset: table.get::<_, Vec2Lua>("effect_offset")?.into(), + drop_behavior: table.get("drop_behavior")?, + deplete_behavior: table.get("deplete_behavior")?, + cooldown_timer: table.get("cooldown_timer")?, + use_cnt: table.get("use_cnt")?, + }) + } +} + +impl<'lua> ToLua<'lua> for Weapon { + fn to_lua(self, lua: &'lua hv_lua::Lua) -> hv_lua::Result> { + let table = lua.create_table()?; + table.set("id", self.id)?; + table.set("name", self.name)?; + table.set("effects", self.effects)?; + table.set("sound_effect", self.sound_effect.map(SoundLua::from))?; + table.set("recoil", self.recoil)?; + table.set("cooldown", self.cooldown)?; + table.set("attack_duration", self.attack_duration)?; + table.set("uses", self.uses)?; + table.set("mount_offset", Vec2Lua::from(self.mount_offset))?; + table.set("effect_offset", Vec2Lua::from(self.effect_offset))?; + table.set("drop_behavior", self.drop_behavior)?; + table.set("deplete_behavior", self.deplete_behavior)?; + table.set("cooldown_timer", self.cooldown_timer)?; + table.set("use_cnt", self.use_cnt)?; + lua.pack(table) + } +} + +impl TypeBody for Weapon { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("id"), + tealr::type_parts_to_str(String::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("name"), + tealr::type_parts_to_str(String::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("effects"), + tealr::type_parts_to_str(Vec::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("sound_effect"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("recoil"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("cooldown"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("attack_duration"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("uses"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("mount_offset"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("effect_offset"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("drop_behavior"), + tealr::type_parts_to_str(ItemDropBehavior::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("deplete_behavior"), + tealr::type_parts_to_str(ItemDepleteBehavior::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("cooldown_timer"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("use_cnt"), + tealr::type_parts_to_str(u32::get_type_parts()), + )); + } +} + impl Weapon { pub fn new( id: &str, @@ -540,6 +797,59 @@ pub struct WeaponMetadata { pub effect_sprite: Option, } +impl<'lua> FromLua<'lua> for WeaponMetadata { + fn from_lua(lua_value: hv_lua::Value<'lua>, lua: &'lua hv_lua::Lua) -> hv_lua::Result { + hv_lua::LuaSerdeExt::from_value(lua, lua_value) + } +} + +impl<'lua> ToLua<'lua> for WeaponMetadata { + fn to_lua(self, lua: &'lua hv_lua::Lua) -> hv_lua::Result> { + hv_lua::LuaSerdeExt::to_value(lua, &self) + } +} + +impl TypeBody for WeaponMetadata { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("effects"), + tealr::type_parts_to_str(Vec::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("particles"), + tealr::type_parts_to_str(Vec::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("sound_effect_id"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("effect_offset"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("uses"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("cooldown"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("attack_duration"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("recoil"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("effect_sprite"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + } +} + impl Default for WeaponMetadata { fn default() -> Self { WeaponMetadata { diff --git a/src/lua.rs b/src/lua.rs index d52e853387..c5ecf80c7e 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -8,7 +8,10 @@ use macroquad_platformer::Actor; use tealr::mlu::TealData; use tealr::TypeName; -use crate::Resources; +use crate::effects::active::projectiles::Projectile; +use crate::effects::active::triggered::TriggeredEffect; +use crate::player::{Player, PlayerEventQueue, PlayerInventory}; +use crate::{Item, Owner, PhysicsBody, Resources, RigidBody}; pub(crate) fn run_event( event_name: &'static str, @@ -36,13 +39,24 @@ pub(crate) fn run_event( lua.load(chunk).set_name(&thread_name)?.exec()?; Ok(()) } -use core::lua::CopyComponent; +use core::lua::{CloneComponent, CopyComponent}; -use core::create_type_component_container; +use core::{create_type_component_container, Transform}; create_type_component_container!( TypeComponentContainer with I32 of CopyComponent, Bool of CopyComponent, + Transform of CloneComponent, + PhysicsBody of CloneComponent, + RigidBody of CloneComponent, + Projectile of CloneComponent, + TriggeredEffect of CloneComponent, + Item of CloneComponent, + Owner of Owner, + PlayerInventory of CloneComponent, + PlayerEventQueue of CloneComponent, + Player of CloneComponent, + ); pub(crate) fn register_types(lua: &Lua) -> Result> { diff --git a/src/particles.rs b/src/particles.rs index 6c80ce895b..17e71df891 100644 --- a/src/particles.rs +++ b/src/particles.rs @@ -1,7 +1,7 @@ use hv_cell::AtomicRefCell; use macroquad::experimental::collections::storage; use macroquad::prelude::*; -use mlua::{ToLua, UserData, UserDataMethods}; +use mlua::{FromLua, ToLua, UserData, UserDataMethods}; use std::{borrow::Cow, collections::HashMap, sync::Arc}; use tealr::mlu::UserDataWrapper; use tealr::TypeName; @@ -67,6 +67,19 @@ impl TypeBody for ParticleEmitterMetadata { .push((Cow::Borrowed("should_autostart"), Cow::Borrowed("boolean"))); } } + +impl<'lua> FromLua<'lua> for ParticleEmitterMetadata { + fn from_lua(lua_value: mlua::Value<'lua>, lua: &'lua mlua::Lua) -> mlua::Result { + mlua::LuaSerdeExt::from_value(lua, lua_value) + } +} + +impl<'lua> ToLua<'lua> for ParticleEmitterMetadata { + fn to_lua(self, lua: &'lua mlua::Lua) -> mlua::Result> { + mlua::LuaSerdeExt::to_value(lua, &self) + } +} + impl Default for ParticleEmitterMetadata { fn default() -> Self { ParticleEmitterMetadata { diff --git a/src/player/events.rs b/src/player/events.rs index fbfb75cb22..ac7a47446a 100644 --- a/src/player/events.rs +++ b/src/player/events.rs @@ -3,23 +3,46 @@ use std::sync::Arc; use hecs::{Entity, World}; use hv_cell::AtomicRefCell; use macroquad::time::get_frame_time; -use tealr::{TypeBody, TypeName}; +use mlua::{FromLua, ToLua, UserData}; +use tealr::{mlu::TealData, TypeBody, TypeName}; use crate::player::{Player, PlayerState}; use serde::{Deserialize, Serialize}; -#[derive(Default)] +#[derive(Clone, Default)] pub struct PlayerEventQueue { pub queue: Vec, } +impl TypeName for PlayerEventQueue { + fn get_type_parts() -> std::borrow::Cow<'static, [tealr::NamePart]> { + Vec::::get_type_parts() + } +} + +impl<'lua> FromLua<'lua> for PlayerEventQueue { + fn from_lua(lua_value: mlua::Value<'lua>, lua: &'lua mlua::Lua) -> mlua::Result { + Ok(Self { + queue: <_>::from_lua(lua_value, lua)?, + }) + } +} + +impl<'lua> ToLua<'lua> for PlayerEventQueue { + fn to_lua(self, lua: &'lua mlua::Lua) -> mlua::Result> { + self.queue.to_lua(lua) + } +} impl PlayerEventQueue { pub fn new() -> Self { PlayerEventQueue { queue: Vec::new() } } } +use hv_lua as mlua; -#[derive(Clone)] +use tealr::MluaTealDerive; + +#[derive(Clone, MluaTealDerive)] pub enum PlayerEvent { Update { dt: f32, @@ -42,6 +65,7 @@ pub enum PlayerEvent { collision_with: Entity, }, } +impl TealData for PlayerEvent {} /// This is used in JSON to specify which event types an effect should apply to #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, TypeName)] @@ -55,8 +79,11 @@ pub enum PlayerEventKind { Collision, } +impl UserData for PlayerEventKind {} +impl TealData for PlayerEventKind {} + impl TypeBody for PlayerEventKind { - fn get_type_body(gen: &mut tealr::TypeGenerator) {} + fn get_type_body(_: &mut tealr::TypeGenerator) {} } impl From<&PlayerEvent> for PlayerEventKind { diff --git a/src/player/inventory.rs b/src/player/inventory.rs index a1d9461da2..36085664c2 100644 --- a/src/player/inventory.rs +++ b/src/player/inventory.rs @@ -1,9 +1,14 @@ use hv_cell::AtomicRefCell; +use hv_lua::{FromLua, ToLua}; use macroquad::prelude::*; use hecs::{Entity, With, Without, World}; +use tealr::{TypeBody, TypeName}; +use core::lua::get_table; +use core::lua::wrapped_types::Vec2Lua; use core::Transform; +use std::borrow::Cow; use std::sync::Arc; use crate::items::{ @@ -16,7 +21,7 @@ use crate::{Drawable, Item, Owner, PassiveEffectInstance, PhysicsBody}; const THROW_FORCE: f32 = 5.0; -#[derive(Default)] +#[derive(Clone, TypeName, Default)] pub struct PlayerInventory { pub weapon_mount: Vec2, pub weapon_mount_offset: Vec2, @@ -29,6 +34,82 @@ pub struct PlayerInventory { pub hat: Option, } +impl<'lua> FromLua<'lua> for PlayerInventory { + fn from_lua(lua_value: hv_lua::Value<'lua>, _: &'lua hv_lua::Lua) -> hv_lua::Result { + let table = get_table(lua_value)?; + Ok(Self { + weapon_mount: table.get::<_, Vec2Lua>("weapon_mount")?.into(), + weapon_mount_offset: table.get::<_, Vec2Lua>("weapon_mount_offset")?.into(), + item_mount: table.get::<_, Vec2Lua>("item_mount")?.into(), + item_mount_offset: table.get::<_, Vec2Lua>("item_mount_offset")?.into(), + hat_mount: table.get::<_, Vec2Lua>("hat_mount")?.into(), + hat_mount_offset: table.get::<_, Vec2Lua>("hat_mount_offset")?.into(), + weapon: table.get("weapon")?, + items: table.get("items")?, + hat: table.get("hat")?, + }) + } +} +impl<'lua> ToLua<'lua> for PlayerInventory { + fn to_lua(self, lua: &'lua hv_lua::Lua) -> hv_lua::Result> { + let table = lua.create_table()?; + table.set("weapon_mount", Vec2Lua::from(self.weapon_mount))?; + table.set( + "weapon_mount_offset", + Vec2Lua::from(self.weapon_mount_offset), + )?; + table.set("item_mount", Vec2Lua::from(self.item_mount))?; + table.set("item_mount_offset", Vec2Lua::from(self.item_mount_offset))?; + table.set("hat_mount", Vec2Lua::from(self.hat_mount))?; + table.set("hat_mount_offset", Vec2Lua::from(self.hat_mount_offset))?; + table.set("weapon", self.weapon)?; + table.set("items", self.items)?; + table.set("hat", self.hat)?; + lua.pack(table) + } +} + +impl TypeBody for PlayerInventory { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("weapon_mount"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("weapon_mount_offset"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("item_mount"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("item_mount_offset"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("hat_mount"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("hat_mount_offset"), + tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("weapon"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("items"), + tealr::type_parts_to_str(Vec::::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("hat"), + tealr::type_parts_to_str(Option::::get_type_parts()), + )); + } +} + impl PlayerInventory { pub fn new(weapon_mount: Vec2, item_mount: Vec2, hat_mount: Vec2) -> Self { PlayerInventory { diff --git a/src/player/mod.rs b/src/player/mod.rs index cafc7f33e8..dd08a8abe6 100644 --- a/src/player/mod.rs +++ b/src/player/mod.rs @@ -1,11 +1,13 @@ use hv_cell::AtomicRefCell; +use hv_lua::{FromLua, ToLua}; use macroquad::experimental::collections::storage; use macroquad::prelude::*; use hecs::{Entity, World}; +use tealr::{TypeBody, TypeName}; -use core::Transform; -use std::sync::Arc; +use core::{lua::wrapped_types::RectLua, Transform}; +use std::{borrow::Cow, sync::Arc}; use crate::{ AnimatedSprite, AnimatedSpriteMetadata, AnimatedSpriteParams, CollisionWorld, Drawable, @@ -58,6 +60,7 @@ pub struct PlayerParams { pub character: PlayerCharacterMetadata, } +#[derive(Clone, TypeName)] pub struct Player { pub index: u8, pub state: PlayerState, @@ -74,6 +77,104 @@ pub struct Player { pub passive_effects: Vec, } +impl<'lua> FromLua<'lua> for Player { + fn from_lua(lua_value: hv_lua::Value<'lua>, lua: &'lua hv_lua::Lua) -> hv_lua::Result { + let table = core::lua::get_table(lua_value)?; + Ok(Self { + index: table.get("index")?, + state: table.get("state")?, + damage_from_left: table.get("damage_from_left")?, + is_facing_left: table.get("is_facing_left")?, + is_upside_down: table.get("is_upside_down")?, + is_attacking: table.get("is_attacking")?, + jump_frame_counter: table.get("jump_frame_counter")?, + pickup_grace_timer: table.get("pickup_grace_timer")?, + incapacitation_timer: table.get("incapacitation_timer")?, + attack_timer: table.get("attack_timer")?, + respawn_timer: table.get("respawn_timer")?, + camera_box: table.get::<_, RectLua>("camera_box")?.into(), + passive_effects: table.get("passive_effects")?, + }) + } +} + +impl<'lua> ToLua<'lua> for Player { + fn to_lua(self, lua: &'lua hv_lua::Lua) -> hv_lua::Result> { + let table = lua.create_table()?; + table.set("index", self.index)?; + table.set("state", self.state)?; + table.set("damage_from_left", self.damage_from_left)?; + table.set("is_facing_left", self.is_facing_left)?; + table.set("is_upside_down", self.is_upside_down)?; + table.set("is_attacking", self.is_attacking)?; + table.set("jump_frame_counter", self.jump_frame_counter)?; + table.set("pickup_grace_timer", self.pickup_grace_timer)?; + table.set("incapacitation_timer", self.incapacitation_timer)?; + table.set("attack_timer", self.attack_timer)?; + table.set("respawn_timer", self.respawn_timer)?; + table.set("camera_box", RectLua::from(self.camera_box))?; + table.set("passive_effects", self.passive_effects)?; + lua.pack(table) + } +} + +impl TypeBody for Player { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("index"), + tealr::type_parts_to_str(u8::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("state"), + tealr::type_parts_to_str(PlayerState::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("damage_from_left"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_facing_left"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_upside_down"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("is_attacking"), + tealr::type_parts_to_str(bool::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("jump_frame_counter"), + tealr::type_parts_to_str(u16::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("pickup_grace_timer"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("incapacitation_timer"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("attack_timer"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("respawn_timer"), + tealr::type_parts_to_str(f32::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("camera_box"), + tealr::type_parts_to_str(RectLua::get_type_parts()), + )); + gen.fields.push(( + Cow::Borrowed("passive_effects"), + tealr::type_parts_to_str(Vec::::get_type_parts()), + )); + } +} + impl Player { pub fn new(index: u8, position: Vec2) -> Self { let camera_box = Rect::new(position.x - 30.0, position.y - 150.0, 100.0, 210.0); diff --git a/src/player/state.rs b/src/player/state.rs index f40773e2bb..9df1da2331 100644 --- a/src/player/state.rs +++ b/src/player/state.rs @@ -1,9 +1,12 @@ use hv_cell::AtomicRefCell; +use hv_lua::UserData; use macroquad::audio::play_sound_once; use macroquad::experimental::collections::storage; use macroquad::prelude::*; use hecs::{Entity, World}; +use tealr::mlu::TealData; +use tealr::TypeName; use core::Transform; use std::sync::Arc; @@ -18,7 +21,7 @@ const SLIDE_STOP_THRESHOLD: f32 = 2.0; const JUMP_FRAME_COUNT: u16 = 8; const PLATFORM_JUMP_FORCE_MULTIPLIER: f32 = 0.2; -#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, TypeName)] pub enum PlayerState { None, Jumping, @@ -29,6 +32,9 @@ pub enum PlayerState { Dead, } +impl UserData for PlayerState {} +impl TealData for PlayerState {} + impl Default for PlayerState { fn default() -> Self { PlayerState::None @@ -195,35 +201,39 @@ pub fn update_player_states(world: Arc>) { pub fn update_player_passive_effects(world: Arc>) { let mut function_calls = Vec::new(); - let mut world = AtomicRefCell::borrow_mut(world.as_ref()); - for (entity, (player, events)) in world.query::<(&mut Player, &mut PlayerEventQueue)>().iter() { - let dt = get_frame_time(); + { + let world = AtomicRefCell::borrow_mut(world.as_ref()); + for (entity, (player, events)) in + world.query::<(&mut Player, &mut PlayerEventQueue)>().iter() + { + let dt = get_frame_time(); - for effect in &mut player.passive_effects { - effect.duration_timer += dt; - } + for effect in &mut player.passive_effects { + effect.duration_timer += dt; + } - player - .passive_effects - .retain(|effect| !effect.is_depleted()); + player + .passive_effects + .retain(|effect| !effect.is_depleted()); - events.queue.push(PlayerEvent::Update { dt }); + events.queue.push(PlayerEvent::Update { dt }); - for event in events.queue.iter() { - let kind = event.into(); + for event in events.queue.iter() { + let kind = event.into(); - for effect in &mut player.passive_effects { - if effect.activated_on.contains(&kind) { - effect.use_cnt += 1; + for effect in &mut player.passive_effects { + if effect.activated_on.contains(&kind) { + effect.use_cnt += 1; - if let Some(item_entity) = effect.item { - let mut item = world.get_mut::(item_entity).unwrap(); + if let Some(item_entity) = effect.item { + let mut item = world.get_mut::(item_entity).unwrap(); - item.use_cnt += 1; - } + item.use_cnt += 1; + } - if let Some(f) = &effect.function { - function_calls.push((*f, entity, effect.item, event.clone())); + if let Some(f) = &effect.function { + function_calls.push((f.to_owned(), entity, effect.item, event.clone())); + } } } } @@ -231,7 +241,7 @@ pub fn update_player_passive_effects(world: Arc>) { } for (f, player_entity, item_entity, event) in function_calls.drain(0..) { - f(&mut world, player_entity, item_entity, event); + f.call_get_lua(world.clone(), player_entity, item_entity, event); } } From 43be776c140b3da0a0056fdca2764f2f4705dd94 Mon Sep 17 00:00:00 2001 From: lenscas Date: Fri, 18 Mar 2022 01:26:15 +0100 Subject: [PATCH 19/21] fix type doc problems --- Cargo.lock | 4 +- core/src/lua/create_component.rs | 9 +- core/src/lua/wrapped_types.rs | 46 +++--- core/src/transform.rs | 6 +- src/drawables/animated_sprite.rs | 264 +++++++++++------------------- src/drawables/mod.rs | 12 +- src/drawables/sprite.rs | 104 ++++-------- src/ecs.rs | 4 +- src/effects/active/mod.rs | 24 ++- src/effects/active/projectiles.rs | 38 ++--- src/effects/active/triggered.rs | 66 +++----- src/effects/passive/mod.rs | 82 ++++------ src/items.rs | 182 ++++++++------------ src/main.rs | 64 +++++++- src/particles.rs | 64 +++----- src/physics.rs | 162 ++++++------------ src/player/events.rs | 2 +- src/player/inventory.rs | 46 ++---- src/player/mod.rs | 74 +++------ src/player/state.rs | 7 +- 20 files changed, 506 insertions(+), 754 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5ef6124af6..6dc36676ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1557,7 +1557,7 @@ dependencies = [ [[package]] name = "tealr" version = "0.8.2" -source = "git+https://github.com/lenscas/tealr?branch=temporary/feature/add_support_for_hv_lua#e0a96b3a6862ae55cb9fa93b6e93e4764987ade3" +source = "git+https://github.com/lenscas/tealr?branch=temporary/feature/add_support_for_hv_lua#d706d1918a4efb77d6693d416af20da04f473055" dependencies = [ "bstr", "hecs", @@ -1573,7 +1573,7 @@ dependencies = [ [[package]] name = "tealr_derive" version = "0.8.2" -source = "git+https://github.com/lenscas/tealr?branch=temporary/feature/add_support_for_hv_lua#e0a96b3a6862ae55cb9fa93b6e93e4764987ade3" +source = "git+https://github.com/lenscas/tealr?branch=temporary/feature/add_support_for_hv_lua#d706d1918a4efb77d6693d416af20da04f473055" dependencies = [ "proc-macro2", "quote", diff --git a/core/src/lua/create_component.rs b/core/src/lua/create_component.rs index b06895c00b..83321e39e3 100644 --- a/core/src/lua/create_component.rs +++ b/core/src/lua/create_component.rs @@ -43,6 +43,7 @@ impl tealr::TypeName for CopyComponent { } impl tealr::TypeBody for CopyComponent { fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.is_user_data = true; get_type_body_component::(gen) } } @@ -104,7 +105,7 @@ fn get_type_body_component(gen: &mut tealr::Typ }); gen.fields.push(( Cow::Borrowed("value"), - tealr::type_parts_to_str(::get_type_parts()), + ::get_type_parts(), )); } @@ -130,14 +131,14 @@ macro_rules! create_type_component_container { impl<'lua> tealr::TypeBody for $name<'lua> { fn get_type_body(gen: &mut tealr::TypeGenerator) { $( + println!("pushing field: {}",stringify!($type_name)); gen.fields.push( ( std::borrow::Cow::Borrowed( stringify!($field_name) ), - tealr::type_parts_to_str( - <$type_name as tealr::TypeName>::get_type_parts() - ) + <$type_name as tealr::TypeName>::get_type_parts() + ) ); )* diff --git a/core/src/lua/wrapped_types.rs b/core/src/lua/wrapped_types.rs index d67745fa1c..e83b61bfd4 100644 --- a/core/src/lua/wrapped_types.rs +++ b/core/src/lua/wrapped_types.rs @@ -54,15 +54,13 @@ impl<'lua> FromLua<'lua> for Vec2Lua { impl TypeName for Vec2Lua { fn get_type_parts() -> Cow<'static, [tealr::NamePart]> { - tealr::new_type!(Vec, External) + tealr::new_type!(Vec2, External) } } impl TypeBody for Vec2Lua { fn get_type_body(gen: &mut tealr::TypeGenerator) { - gen.fields - .push((Cow::Borrowed("x"), Cow::Borrowed("number"))); - gen.fields - .push((Cow::Borrowed("y"), Cow::Borrowed("number"))); + gen.fields.push((Cow::Borrowed("x"), f32::get_type_parts())); + gen.fields.push((Cow::Borrowed("y"), f32::get_type_parts())); } } @@ -73,6 +71,16 @@ pub struct ColorLua { pub b: f32, pub a: f32, } + +impl TypeBody for ColorLua { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push((Cow::Borrowed("r"), f32::get_type_parts())); + gen.fields.push((Cow::Borrowed("g"), f32::get_type_parts())); + gen.fields.push((Cow::Borrowed("b"), f32::get_type_parts())); + gen.fields.push((Cow::Borrowed("a"), f32::get_type_parts())); + } +} + impl TypeName for ColorLua { fn get_type_parts() -> Cow<'static, [tealr::NamePart]> { tealr::new_type!(Color, External) @@ -220,26 +228,10 @@ impl TypeBody for RectLua { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.is_user_data = true; ::add_methods(gen); - gen.fields.push(( - Cow::Borrowed("x"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("y"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("w"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("h"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("x"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); + gen.fields.push((Cow::Borrowed("x"), f32::get_type_parts())); + gen.fields.push((Cow::Borrowed("y"), f32::get_type_parts())); + gen.fields.push((Cow::Borrowed("w"), f32::get_type_parts())); + gen.fields.push((Cow::Borrowed("h"), f32::get_type_parts())); } } @@ -276,7 +268,9 @@ impl TypeName for SoundLua { impl UserData for SoundLua {} impl TealData for SoundLua {} impl TypeBody for SoundLua { - fn get_type_body(_: &mut tealr::TypeGenerator) {} + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.is_user_data = true; + } } impl From for SoundLua { diff --git a/core/src/transform.rs b/core/src/transform.rs index bc8edad296..fae67844bf 100644 --- a/core/src/transform.rs +++ b/core/src/transform.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use hv_lua::{FromLua, ToLua}; use macroquad::prelude::*; -use tealr::TypeBody; +use tealr::{TypeBody, TypeName}; use crate::lua::wrapped_types::Vec2Lua; #[derive(Debug, Default, tealr::TypeName, Clone)] @@ -59,8 +59,8 @@ impl<'lua> FromLua<'lua> for Transform { impl TypeBody for Transform { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields - .push((Cow::Borrowed("position"), Cow::Borrowed("Vec2"))); + .push((Cow::Borrowed("position"), Vec2Lua::get_type_parts())); gen.fields - .push((Cow::Borrowed("rotation"), Cow::Borrowed("number"))); + .push((Cow::Borrowed("rotation"), f32::get_type_parts())); } } diff --git a/src/drawables/animated_sprite.rs b/src/drawables/animated_sprite.rs index 24baec20e0..294e085d89 100644 --- a/src/drawables/animated_sprite.rs +++ b/src/drawables/animated_sprite.rs @@ -60,30 +60,20 @@ impl<'lua> ToLua<'lua> for Animation { } impl TypeBody for Animation { fn get_type_body(gen: &mut tealr::TypeGenerator) { - gen.fields.push(( - Cow::Borrowed("id"), - tealr::type_parts_to_str(String::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("row"), - tealr::type_parts_to_str(u32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("frames"), - tealr::type_parts_to_str(u32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("fps"), - tealr::type_parts_to_str(u32::get_type_parts()), - )); + gen.fields + .push((Cow::Borrowed("id"), String::get_type_parts())); + gen.fields + .push((Cow::Borrowed("row"), u32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("frames"), u32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("fps"), u32::get_type_parts())); gen.fields.push(( Cow::Borrowed("tweens"), - tealr::type_parts_to_str(HashMap::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_looping"), - tealr::type_parts_to_str(bool::get_type_parts()), + HashMap::::get_type_parts(), )); + gen.fields + .push((Cow::Borrowed("is_looping"), bool::get_type_parts())); } } @@ -138,11 +128,11 @@ impl TypeBody for Tween { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields.push(( Cow::Borrowed("keyframes"), - tealr::type_parts_to_str(Vec::::get_type_parts()), + Vec::::get_type_parts(), )); gen.fields.push(( Cow::Borrowed("current_translation"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + Vec2Lua::get_type_parts(), )); } } @@ -173,14 +163,10 @@ pub struct Keyframe { } impl TypeBody for Keyframe { fn get_type_body(gen: &mut tealr::TypeGenerator) { - gen.fields.push(( - Cow::Borrowed("frame"), - tealr::type_parts_to_str(u32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("translation"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); + gen.fields + .push((Cow::Borrowed("frame"), u32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("translation"), Vec2Lua::get_type_parts())); } } @@ -233,35 +219,23 @@ impl TypeBody for AnimatedSpriteParams { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields.push(( Cow::Borrowed("frame_size"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("scale"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("offset"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("pivot"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("tint"), - tealr::type_parts_to_str(ColorLua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_flipped_x"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_flipped_y"), - tealr::type_parts_to_str(bool::get_type_parts()), + Option::::get_type_parts(), )); + gen.fields + .push((Cow::Borrowed("scale"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("pivot"), Option::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("tint"), ColorLua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("is_flipped_x"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("is_flipped_y"), bool::get_type_parts())); gen.fields.push(( Cow::Borrowed("autoplay_id"), - tealr::type_parts_to_str(Option::::get_type_parts()), + Option::::get_type_parts(), )); } } @@ -461,70 +435,42 @@ impl TypeBody for AnimatedSprite { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.is_user_data = true; ::add_methods(gen); - gen.fields.push(( - Cow::Borrowed("texture"), - tealr::type_parts_to_str(Texture2DLua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("frame_size"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("scale"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("offset"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("pivot"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("tint"), - tealr::type_parts_to_str(ColorLua::get_type_parts()), - )); + gen.fields + .push((Cow::Borrowed("texture"), Texture2DLua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("frame_size"), Vec2Lua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("scale"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("pivot"), Option::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("tint"), ColorLua::get_type_parts())); gen.fields.push(( Cow::Borrowed("animations"), - tealr::type_parts_to_str(Vec::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("current_index"), - tealr::type_parts_to_str(usize::get_type_parts()), + Vec::::get_type_parts(), )); + gen.fields + .push((Cow::Borrowed("current_index"), usize::get_type_parts())); gen.fields.push(( Cow::Borrowed("queued_action"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("current_frame"), - tealr::type_parts_to_str(u32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("frame_timer"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_playing"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_flipped_x"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_flipped_y"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_deactivated"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("wait_timer"), - tealr::type_parts_to_str(f32::get_type_parts()), + Option::::get_type_parts(), )); + gen.fields + .push((Cow::Borrowed("current_frame"), u32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("frame_timer"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("is_playing"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("is_flipped_x"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("is_flipped_y"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("is_deactivated"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("wait_timer"), f32::get_type_parts())); } } @@ -879,13 +825,11 @@ impl TypeBody for AnimatedSpriteSet { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.is_user_data = true; ::add_methods(gen); - gen.fields.push(( - Cow::Borrowed("draw_order"), - tealr::type_parts_to_str(Vec::::get_type_parts()), - )); + gen.fields + .push((Cow::Borrowed("draw_order"), Vec::::get_type_parts())); gen.fields.push(( Cow::Borrowed("map"), - tealr::type_parts_to_str(HashMap::::get_type_parts()), + HashMap::::get_type_parts(), )); } } @@ -1019,30 +963,20 @@ pub struct AnimationMetadata { impl TypeBody for AnimationMetadata { fn get_type_body(gen: &mut tealr::TypeGenerator) { - gen.fields.push(( - Cow::Borrowed("id"), - tealr::type_parts_to_str(String::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("row"), - tealr::type_parts_to_str(u32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("frames"), - tealr::type_parts_to_str(u32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("fps"), - tealr::type_parts_to_str(u32::get_type_parts()), - )); + gen.fields + .push((Cow::Borrowed("id"), String::get_type_parts())); + gen.fields + .push((Cow::Borrowed("row"), u32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("frames"), u32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("fps"), u32::get_type_parts())); gen.fields.push(( Cow::Borrowed("tweens"), - tealr::type_parts_to_str(Vec::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_looping"), - tealr::type_parts_to_str(bool::get_type_parts()), + Vec::::get_type_parts(), )); + gen.fields + .push((Cow::Borrowed("is_looping"), bool::get_type_parts())); } } @@ -1064,13 +998,11 @@ pub struct TweenMetadata { } impl TypeBody for TweenMetadata { fn get_type_body(gen: &mut tealr::TypeGenerator) { - gen.fields.push(( - Cow::Borrowed("id"), - tealr::type_parts_to_str(String::get_type_parts()), - )); + gen.fields + .push((Cow::Borrowed("id"), String::get_type_parts())); gen.fields.push(( Cow::Borrowed("keyframes"), - tealr::type_parts_to_str(Vec::::get_type_parts()), + Vec::::get_type_parts(), )); } } @@ -1103,37 +1035,25 @@ pub struct AnimatedSpriteMetadata { } impl TypeBody for AnimatedSpriteMetadata { fn get_type_body(gen: &mut tealr::TypeGenerator) { - gen.fields.push(( - Cow::Borrowed("texture_id"), - tealr::type_parts_to_str(String::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("scale"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("offset"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("pivot"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("tint"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); + gen.fields + .push((Cow::Borrowed("texture_id"), String::get_type_parts())); + gen.fields + .push((Cow::Borrowed("scale"), Option::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("pivot"), Option::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("tint"), Option::::get_type_parts())); gen.fields.push(( Cow::Borrowed("animations"), - tealr::type_parts_to_str(Vec::::get_type_parts()), + Vec::::get_type_parts(), )); gen.fields.push(( Cow::Borrowed("autoplay_id"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_deactivated"), - tealr::type_parts_to_str(bool::get_type_parts()), + Option::::get_type_parts(), )); + gen.fields + .push((Cow::Borrowed("is_deactivated"), bool::get_type_parts())); } } diff --git a/src/drawables/mod.rs b/src/drawables/mod.rs index d2b0270147..adbc8b71b3 100644 --- a/src/drawables/mod.rs +++ b/src/drawables/mod.rs @@ -52,14 +52,10 @@ impl<'lua> ToLua<'lua> for Drawable { } impl TypeBody for Drawable { fn get_type_body(gen: &mut tealr::TypeGenerator) { - gen.fields.push(( - Cow::Borrowed("draw_order"), - tealr::type_parts_to_str(u32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("kind"), - tealr::type_parts_to_str(DrawableKind::get_type_parts()), - )); + gen.fields + .push((Cow::Borrowed("draw_order"), u32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("kind"), DrawableKind::get_type_parts())); } } diff --git a/src/drawables/sprite.rs b/src/drawables/sprite.rs index da7b3ddb08..73979c50d7 100644 --- a/src/drawables/sprite.rs +++ b/src/drawables/sprite.rs @@ -65,38 +65,22 @@ pub struct SpriteMetadata { impl TypeBody for SpriteMetadata { fn get_type_body(gen: &mut tealr::TypeGenerator) { - gen.fields.push(( - Cow::Borrowed("texture"), - tealr::type_parts_to_str(String::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("index"), - tealr::type_parts_to_str(usize::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("scale"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("offset"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("pivot"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("size"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("tint"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_deactivated"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); + gen.fields + .push((Cow::Borrowed("texture"), String::get_type_parts())); + gen.fields + .push((Cow::Borrowed("index"), usize::get_type_parts())); + gen.fields + .push((Cow::Borrowed("scale"), Option::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("pivot"), Option::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("size"), Option::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("tint"), Option::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("is_deactivated"), bool::get_type_parts())); } } @@ -248,44 +232,26 @@ impl TypeBody for SpriteParams { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields.push(( Cow::Borrowed("sprite_size"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("index"), - tealr::type_parts_to_str(usize::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("scale"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("offset"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("pivot"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("size"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("tint"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_flipped_x"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_flipped_y"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_deactivated"), - tealr::type_parts_to_str(bool::get_type_parts()), + Option::::get_type_parts(), )); + gen.fields + .push((Cow::Borrowed("index"), usize::get_type_parts())); + gen.fields + .push((Cow::Borrowed("scale"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("pivot"), Option::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("size"), Option::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("tint"), Option::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("is_flipped_x"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("is_flipped_y"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("is_deactivated"), bool::get_type_parts())); } } diff --git a/src/ecs.rs b/src/ecs.rs index c385c4a9dc..82d688b03f 100644 --- a/src/ecs.rs +++ b/src/ecs.rs @@ -14,7 +14,9 @@ pub struct Owner(pub Entity); impl UserData for Owner {} impl TealData for Owner {} impl TypeBody for Owner { - fn get_type_body(_: &mut tealr::TypeGenerator) {} + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.is_user_data = true; + } } /// Placeholder until we implement threading #[derive(Default)] diff --git a/src/effects/active/mod.rs b/src/effects/active/mod.rs index b6bc133552..1f5382fb0e 100644 --- a/src/effects/active/mod.rs +++ b/src/effects/active/mod.rs @@ -12,6 +12,7 @@ use tealr::mlu::TealData; use core::math::{deg_to_rad, rotate_vector, IsZero}; use core::Result; +use std::borrow::Cow; use std::sync::Arc; use crate::Resources; @@ -33,7 +34,7 @@ pub use projectiles::ProjectileKind; const COLLIDER_DEBUG_DRAW_TTL: f32 = 0.5; use hv_lua as mlua; -use tealr::{MluaTealDerive, TypeName}; +use tealr::{MluaTealDerive, TypeBody, TypeName}; #[derive(Clone, MluaTealDerive)] struct CircleCollider { r: f32, @@ -230,6 +231,19 @@ pub struct ActiveEffectMetadata { pub delay: f32, } +impl TypeBody for ActiveEffectMetadata { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields + .push((Cow::Borrowed("kind"), ActiveEffectKind::get_type_parts())); + gen.fields.push(( + Cow::Borrowed("sound_effect_id"), + Option::::get_type_parts(), + )); + gen.fields + .push((Cow::Borrowed("delay"), f32::get_type_parts())); + } +} + impl<'lua> FromLua<'lua> for ActiveEffectMetadata { fn from_lua(lua_value: mlua::Value<'lua>, _: &'lua mlua::Lua) -> mlua::Result { let table = core::lua::get_table(lua_value)?; @@ -252,7 +266,7 @@ impl<'lua> ToLua<'lua> for ActiveEffectMetadata { } #[derive(Clone, MluaTealDerive)] -struct ActiveEffectKindCircleCollider { +pub struct ActiveEffectKindCircleCollider { radius: f32, passive_effects: Vec, is_lethal: bool, @@ -272,7 +286,7 @@ impl TealData for ActiveEffectKindCircleCollider { } #[derive(Clone, MluaTealDerive)] -struct ActiveEffectKindRectCollider { +pub struct ActiveEffectKindRectCollider { width: f32, height: f32, /// If `true` the effect will do damage to any player it hits @@ -294,7 +308,7 @@ impl TealData for ActiveEffectKindRectCollider { } } #[derive(Clone, MluaTealDerive)] -struct ActiveEffectKindTriggeredEffect { +pub struct ActiveEffectKindTriggeredEffect { meta: Box, } impl TealData for ActiveEffectKindTriggeredEffect { @@ -308,7 +322,7 @@ impl TealData for ActiveEffectKindTriggeredEffect { } #[derive(Clone, MluaTealDerive)] -struct ActiveEffectKindProjectile { +pub struct ActiveEffectKindProjectile { kind: ProjectileKind, speed: f32, range: f32, diff --git a/src/effects/active/projectiles.rs b/src/effects/active/projectiles.rs index b02f92229d..d845589e75 100644 --- a/src/effects/active/projectiles.rs +++ b/src/effects/active/projectiles.rs @@ -28,7 +28,7 @@ const PROJECTILE_DRAW_ORDER: u32 = 1; use hv_lua as mlua; #[derive(Clone, MluaTealDerive)] -struct Circle { +pub struct Circle { radius: f32, color: ColorLua, } @@ -44,7 +44,7 @@ impl TealData for Circle { } #[derive(Clone, MluaTealDerive)] -struct Rectangle { +pub struct Rectangle { width: f32, height: f32, color: ColorLua, @@ -61,7 +61,7 @@ impl TealData for Rectangle { } } #[derive(Clone, MluaTealDerive)] -struct Sprite { +pub struct Sprite { params: SpriteMetadata, can_rotate: bool, } @@ -187,29 +187,19 @@ impl<'lua> ToLua<'lua> for Projectile { impl TypeBody for Projectile { fn get_type_body(gen: &mut tealr::TypeGenerator) { - gen.fields.push(( - Cow::Borrowed("kind"), - tealr::type_parts_to_str(ProjectileKind::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("owner"), - tealr::type_parts_to_str(Entity::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("origin"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("range"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_lethal"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); + gen.fields + .push((Cow::Borrowed("kind"), ProjectileKind::get_type_parts())); + gen.fields + .push((Cow::Borrowed("owner"), Entity::get_type_parts())); + gen.fields + .push((Cow::Borrowed("origin"), Vec2Lua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("range"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("is_lethal"), bool::get_type_parts())); gen.fields.push(( Cow::Borrowed("passive_effects"), - tealr::type_parts_to_str(Vec::::get_type_parts()), + Vec::::get_type_parts(), )); } } diff --git a/src/effects/active/triggered.rs b/src/effects/active/triggered.rs index b93eb0f44c..aa78c87a71 100644 --- a/src/effects/active/triggered.rs +++ b/src/effects/active/triggered.rs @@ -124,66 +124,48 @@ impl<'lua> ToLua<'lua> for TriggeredEffect { impl TypeBody for TriggeredEffect { fn get_type_body(gen: &mut tealr::TypeGenerator) { - gen.fields.push(( - Cow::Borrowed("owner"), - tealr::type_parts_to_str(Entity::get_type_parts()), - )); + gen.fields + .push((Cow::Borrowed("owner"), Entity::get_type_parts())); gen.fields.push(( Cow::Borrowed("trigger"), - tealr::type_parts_to_str(Vec::::get_type_parts()), + Vec::::get_type_parts(), )); gen.fields.push(( Cow::Borrowed("effects"), - tealr::type_parts_to_str(Vec::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("activation_delay"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("trigger_delay"), - tealr::type_parts_to_str(f32::get_type_parts()), + Vec::::get_type_parts(), )); + gen.fields + .push((Cow::Borrowed("activation_delay"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("trigger_delay"), f32::get_type_parts())); gen.fields.push(( Cow::Borrowed("timed_trigger"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_kickable"), - tealr::type_parts_to_str(bool::get_type_parts()), + Option::::get_type_parts(), )); + gen.fields + .push((Cow::Borrowed("is_kickable"), bool::get_type_parts())); gen.fields.push(( Cow::Borrowed("should_override_delay"), - tealr::type_parts_to_str(bool::get_type_parts()), + bool::get_type_parts(), )); gen.fields.push(( Cow::Borrowed("should_collide_with_platforms"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_triggered"), - tealr::type_parts_to_str(bool::get_type_parts()), + bool::get_type_parts(), )); + gen.fields + .push((Cow::Borrowed("is_triggered"), bool::get_type_parts())); gen.fields.push(( Cow::Borrowed("triggered_by"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("kick_delay_timer"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("activation_timer"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("trigger_delay_timer"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("timed_trigger_timer"), - tealr::type_parts_to_str(f32::get_type_parts()), + Option::::get_type_parts(), )); + gen.fields + .push((Cow::Borrowed("kick_delay_timer"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("activation_timer"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("trigger_delay_timer"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("timed_trigger_timer"), f32::get_type_parts())); } } diff --git a/src/effects/passive/mod.rs b/src/effects/passive/mod.rs index 3e0c1fe5dc..5d13484650 100644 --- a/src/effects/passive/mod.rs +++ b/src/effects/passive/mod.rs @@ -246,50 +246,36 @@ impl TypeBody for PassiveEffectInstance { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.is_user_data = true; ::add_methods(gen); - gen.fields.push(( - Cow::Borrowed("name"), - tealr::type_parts_to_str(String::get_type_parts()), - )); + gen.fields + .push((Cow::Borrowed("name"), String::get_type_parts())); gen.fields.push(( Cow::Borrowed("function"), - tealr::type_parts_to_str(Option::::get_type_parts()), + Option::::get_type_parts(), )); gen.fields.push(( Cow::Borrowed("activated_on"), - tealr::type_parts_to_str(Vec::::get_type_parts()), + Vec::::get_type_parts(), )); gen.fields.push(( Cow::Borrowed("particle_effect_id"), - tealr::type_parts_to_str(Option::::get_type_parts()), + Option::::get_type_parts(), )); gen.fields.push(( Cow::Borrowed("event_particle_effect_id"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("blocks_damage"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("uses"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("item"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("use_cnt"), - tealr::type_parts_to_str(u32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("duration"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("duration_timer"), - tealr::type_parts_to_str(f32::get_type_parts()), + Option::::get_type_parts(), )); + gen.fields + .push((Cow::Borrowed("blocks_damage"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("uses"), Option::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("item"), Option::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("use_cnt"), u32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("duration"), Option::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("duration_timer"), f32::get_type_parts())); } } @@ -379,37 +365,29 @@ impl<'lua> ToLua<'lua> for PassiveEffectMetadata { impl TypeBody for PassiveEffectMetadata { fn get_type_body(gen: &mut tealr::TypeGenerator) { - gen.fields.push(( - Cow::Borrowed("name"), - tealr::type_parts_to_str(String::get_type_parts()), - )); + gen.fields + .push((Cow::Borrowed("name"), String::get_type_parts())); gen.fields.push(( Cow::Borrowed("function_id"), - tealr::type_parts_to_str(Option::::get_type_parts()), + Option::::get_type_parts(), )); gen.fields.push(( Cow::Borrowed("activated_on"), - tealr::type_parts_to_str(Vec::::get_type_parts()), + Vec::::get_type_parts(), )); gen.fields.push(( Cow::Borrowed("particle_effect"), - tealr::type_parts_to_str(Option::::get_type_parts()), + Option::::get_type_parts(), )); gen.fields.push(( Cow::Borrowed("event_particle_effect"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("blocks_damage"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("uses"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("duration"), - tealr::type_parts_to_str(Option::::get_type_parts()), + Option::::get_type_parts(), )); + gen.fields + .push((Cow::Borrowed("blocks_damage"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("uses"), Option::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("duration"), Option::::get_type_parts())); } } diff --git a/src/items.rs b/src/items.rs index 1fb4749019..28233dcba4 100644 --- a/src/items.rs +++ b/src/items.rs @@ -178,50 +178,34 @@ impl<'lua> ToLua<'lua> for Item { impl TypeBody for Item { fn get_type_body(gen: &mut tealr::TypeGenerator) { - gen.fields.push(( - Cow::Borrowed("id"), - tealr::type_parts_to_str(String::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("name"), - tealr::type_parts_to_str(String::get_type_parts()), - )); + gen.fields + .push((Cow::Borrowed("id"), String::get_type_parts())); + gen.fields + .push((Cow::Borrowed("name"), String::get_type_parts())); gen.fields.push(( Cow::Borrowed("effects"), - tealr::type_parts_to_str(Vec::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("uses"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("duration"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("mount_offset"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + Vec::::get_type_parts(), )); + gen.fields + .push((Cow::Borrowed("uses"), Option::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("duration"), Option::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("mount_offset"), Vec2Lua::get_type_parts())); gen.fields.push(( Cow::Borrowed("drop_behavior"), - tealr::type_parts_to_str(ItemDropBehavior::get_type_parts()), + ItemDropBehavior::get_type_parts(), )); gen.fields.push(( Cow::Borrowed("deplete_behavior"), - tealr::type_parts_to_str(ItemDepleteBehavior::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_hat"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("duration_timer"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("use_cnt"), - tealr::type_parts_to_str(u32::get_type_parts()), - )); + ItemDepleteBehavior::get_type_parts(), + )); + gen.fields + .push((Cow::Borrowed("is_hat"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("duration_timer"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("use_cnt"), u32::get_type_parts())); } } @@ -244,7 +228,7 @@ impl Item { } /// This holds the parameters used when constructing an `Equipment` -#[derive(Clone, Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize, TypeName)] pub struct ItemMetadata { /// The effects that will be instantiated when the item is equipped #[serde(default)] @@ -273,16 +257,12 @@ impl TypeBody for ItemMetadata { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields.push(( Cow::Borrowed("effects"), - tealr::type_parts_to_str(Vec::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("duration"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_hat"), - tealr::type_parts_to_str(bool::get_type_parts()), + Vec::::get_type_parts(), )); + gen.fields + .push((Cow::Borrowed("duration"), Option::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("is_hat"), bool::get_type_parts())); } } @@ -555,62 +535,42 @@ impl<'lua> ToLua<'lua> for Weapon { impl TypeBody for Weapon { fn get_type_body(gen: &mut tealr::TypeGenerator) { - gen.fields.push(( - Cow::Borrowed("id"), - tealr::type_parts_to_str(String::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("name"), - tealr::type_parts_to_str(String::get_type_parts()), - )); + gen.fields + .push((Cow::Borrowed("id"), String::get_type_parts())); + gen.fields + .push((Cow::Borrowed("name"), String::get_type_parts())); gen.fields.push(( Cow::Borrowed("effects"), - tealr::type_parts_to_str(Vec::::get_type_parts()), + Vec::::get_type_parts(), )); gen.fields.push(( Cow::Borrowed("sound_effect"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("recoil"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("cooldown"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("attack_duration"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("uses"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("mount_offset"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("effect_offset"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); + Option::::get_type_parts(), + )); + gen.fields + .push((Cow::Borrowed("recoil"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("cooldown"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("attack_duration"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("uses"), Option::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("mount_offset"), Vec2Lua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("effect_offset"), Vec2Lua::get_type_parts())); gen.fields.push(( Cow::Borrowed("drop_behavior"), - tealr::type_parts_to_str(ItemDropBehavior::get_type_parts()), + ItemDropBehavior::get_type_parts(), )); gen.fields.push(( Cow::Borrowed("deplete_behavior"), - tealr::type_parts_to_str(ItemDepleteBehavior::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("cooldown_timer"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("use_cnt"), - tealr::type_parts_to_str(u32::get_type_parts()), + ItemDepleteBehavior::get_type_parts(), )); + gen.fields + .push((Cow::Borrowed("cooldown_timer"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("use_cnt"), u32::get_type_parts())); } } @@ -813,39 +773,29 @@ impl TypeBody for WeaponMetadata { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields.push(( Cow::Borrowed("effects"), - tealr::type_parts_to_str(Vec::::get_type_parts()), + Vec::::get_type_parts(), )); gen.fields.push(( Cow::Borrowed("particles"), - tealr::type_parts_to_str(Vec::::get_type_parts()), + Vec::::get_type_parts(), )); gen.fields.push(( Cow::Borrowed("sound_effect_id"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("effect_offset"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("uses"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("cooldown"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("attack_duration"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("recoil"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); + Option::::get_type_parts(), + )); + gen.fields + .push((Cow::Borrowed("effect_offset"), Vec2Lua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("uses"), Option::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("cooldown"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("attack_duration"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("recoil"), f32::get_type_parts())); gen.fields.push(( Cow::Borrowed("effect_sprite"), - tealr::type_parts_to_str(Option::::get_type_parts()), + Option::::get_type_parts(), )); } } diff --git a/src/main.rs b/src/main.rs index 99a4f7e55b..1baf1952f3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,8 @@ use fishsticks::GamepadContext; +use hecs::{DynamicQuery, Entity, World}; +use core::lua::wrapped_types::{ColorLua, RectLua, SoundLua, Texture2DLua, Vec2Lua}; +use core::lua::CloneComponent; use std::env; use std::path::PathBuf; @@ -33,8 +36,8 @@ use editor::{Editor, EditorCamera, EditorInputScheme}; use map::{Map, MapLayerKind, MapObjectKind}; -use core::network::Api; use core::Result; +use core::{network::Api, Transform}; pub use core::Config; pub use items::Item; @@ -49,9 +52,19 @@ pub use player::PlayerEvent; pub use ecs::Owner; +use crate::effects::active::projectiles::{Projectile, Rectangle}; +use crate::effects::active::triggered::TriggeredEffect; +use crate::effects::active::{ + ActiveEffectKindCircleCollider, ActiveEffectKindProjectile, ActiveEffectKindRectCollider, + ActiveEffectKindTriggeredEffect, ProjectileKind, +}; use crate::effects::passive::init_passive_effects; +use crate::effects::TriggeredEffectTrigger; use crate::game::GameMode; +use crate::items::{ItemDepleteBehavior, ItemDropBehavior, ItemMetadata, Weapon}; +use crate::lua::ActorLua; use crate::particles::Particles; +use crate::player::{Player, PlayerEventKind, PlayerEventQueue, PlayerInventory, PlayerState}; use crate::resources::load_resources; pub use effects::{ ActiveEffectKind, ActiveEffectMetadata, PassiveEffectInstance, PassiveEffectMetadata, @@ -202,6 +215,55 @@ async fn init_game() -> Result { #[macroquad::main(window_conf)] async fn main() -> std::result::Result<(), Box> { + let types = tealr::TypeWalker::new() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::>(); + println!("time to generate the json files"); + std::fs::write("./test.json", serde_json::to_string_pretty(&types).unwrap()).unwrap(); + std::fs::write("./test.d.tl", types.generate_global("test").unwrap()).unwrap(); + println!("Wrote all!"); // println!("Starting embedded lua test"); // core::test::test()?; // println!("Ended embedded lua test"); diff --git a/src/particles.rs b/src/particles.rs index 17e71df891..d3da634b55 100644 --- a/src/particles.rs +++ b/src/particles.rs @@ -50,21 +50,21 @@ pub struct ParticleEmitterMetadata { impl TypeBody for ParticleEmitterMetadata { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields - .push((Cow::Borrowed("particle_effect"), Cow::Borrowed("String"))); + .push((Cow::Borrowed("particle_effect"), String::get_type_parts())); gen.fields - .push((Cow::Borrowed("offset"), Cow::Borrowed("Vec2"))); + .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); gen.fields - .push((Cow::Borrowed("delay"), Cow::Borrowed("number"))); + .push((Cow::Borrowed("delay"), f32::get_type_parts())); gen.fields - .push((Cow::Borrowed("interval"), Cow::Borrowed("number"))); + .push((Cow::Borrowed("interval"), f32::get_type_parts())); gen.fields - .push((Cow::Borrowed("emissions"), Cow::Borrowed("integer"))); + .push((Cow::Borrowed("emissions"), Option::::get_type_parts())); gen.fields.push(( Cow::Borrowed("animations"), - Cow::Borrowed("AnimatedSpriteMetaData"), + Option::::get_type_parts(), )); gen.fields - .push((Cow::Borrowed("should_autostart"), Cow::Borrowed("boolean"))); + .push((Cow::Borrowed("should_autostart"), bool::get_type_parts())); } } @@ -210,40 +210,24 @@ impl TypeBody for ParticleEmitter { ::add_methods(gen); gen.fields.push(( Cow::Borrowed("particle_effect_id"), - tealr::type_parts_to_str(String::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("offset"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("delay"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("emissions"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("interval"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("emission_cnt"), - tealr::type_parts_to_str(u32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("delay_timer"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("interval_timer"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_active"), - tealr::type_parts_to_str(bool::get_type_parts()), + String::get_type_parts(), )); + gen.fields + .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("delay"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("emissions"), Option::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("interval"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("emission_cnt"), u32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("delay_timer"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("interval_timer"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("is_active"), bool::get_type_parts())); } } diff --git a/src/physics.rs b/src/physics.rs index e77f2726c7..b8663a96bf 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -127,34 +127,20 @@ impl<'lua> ToLua<'lua> for PhysicsBodyParams { } impl TypeBody for PhysicsBodyParams { fn get_type_body(gen: &mut tealr::TypeGenerator) { - gen.fields.push(( - Cow::Borrowed("size"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("offset"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("has_mass"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("has_friction"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("can_rotate"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("bouncyness"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("gravity"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); + gen.fields + .push((Cow::Borrowed("size"), Vec2Lua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("has_mass"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("has_friction"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("can_rotate"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("bouncyness"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("gravity"), f32::get_type_parts())); } } @@ -210,58 +196,32 @@ impl<'lua> FromLua<'lua> for PhysicsBody { } impl TypeBody for PhysicsBody { fn get_type_body(gen: &mut tealr::TypeGenerator) { - gen.fields.push(( - Cow::Borrowed("actor"), - tealr::type_parts_to_str(ActorLua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("offset"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("size"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("velocity"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_on_ground"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("was_on_ground"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_on_platform"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("has_mass"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("has_friction"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("can_rotate"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("bouncyness"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_deactivated"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("gravity"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); + gen.fields + .push((Cow::Borrowed("actor"), ActorLua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("size"), Vec2Lua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("velocity"), Vec2Lua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("is_on_ground"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("was_on_ground"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("is_on_platform"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("has_mass"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("has_friction"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("can_rotate"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("bouncyness"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("is_deactivated"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("gravity"), f32::get_type_parts())); } } impl<'lua> ToLua<'lua> for PhysicsBody { @@ -419,18 +379,12 @@ impl Default for RigidBodyParams { impl TypeBody for RigidBodyParams { fn get_type_body(gen: &mut tealr::TypeGenerator) { - gen.fields.push(( - Cow::Borrowed("offset"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("size"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("can_rotate"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); + gen.fields + .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("size"), Vec2Lua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("can_rotate"), bool::get_type_parts())); } } @@ -469,22 +423,14 @@ impl<'lua> ToLua<'lua> for RigidBody { impl TypeBody for RigidBody { fn get_type_body(gen: &mut tealr::TypeGenerator) { - gen.fields.push(( - Cow::Borrowed("offset"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("size"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("velocity"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("can_rotate"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); + gen.fields + .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("size"), Vec2Lua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("velocity"), Vec2Lua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("can_rotate"), bool::get_type_parts())); } } diff --git a/src/player/events.rs b/src/player/events.rs index ac7a47446a..bcc0ba4e30 100644 --- a/src/player/events.rs +++ b/src/player/events.rs @@ -16,7 +16,7 @@ pub struct PlayerEventQueue { impl TypeName for PlayerEventQueue { fn get_type_parts() -> std::borrow::Cow<'static, [tealr::NamePart]> { - Vec::::get_type_parts() + Vec::::get_type_parts() } } diff --git a/src/player/inventory.rs b/src/player/inventory.rs index 36085664c2..e45a83b7b0 100644 --- a/src/player/inventory.rs +++ b/src/player/inventory.rs @@ -71,42 +71,28 @@ impl<'lua> ToLua<'lua> for PlayerInventory { impl TypeBody for PlayerInventory { fn get_type_body(gen: &mut tealr::TypeGenerator) { - gen.fields.push(( - Cow::Borrowed("weapon_mount"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); + gen.fields + .push((Cow::Borrowed("weapon_mount"), Vec2Lua::get_type_parts())); gen.fields.push(( Cow::Borrowed("weapon_mount_offset"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("item_mount"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), + Vec2Lua::get_type_parts(), )); + gen.fields + .push((Cow::Borrowed("item_mount"), Vec2Lua::get_type_parts())); gen.fields.push(( Cow::Borrowed("item_mount_offset"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("hat_mount"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("hat_mount_offset"), - tealr::type_parts_to_str(Vec2Lua::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("weapon"), - tealr::type_parts_to_str(Option::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("items"), - tealr::type_parts_to_str(Vec::::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("hat"), - tealr::type_parts_to_str(Option::::get_type_parts()), + Vec2Lua::get_type_parts(), )); + gen.fields + .push((Cow::Borrowed("hat_mount"), Vec2Lua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("hat_mount_offset"), Vec2Lua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("weapon"), Option::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("items"), Vec::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("hat"), Option::::get_type_parts())); } } diff --git a/src/player/mod.rs b/src/player/mod.rs index dd08a8abe6..4d32b6b284 100644 --- a/src/player/mod.rs +++ b/src/player/mod.rs @@ -120,57 +120,33 @@ impl<'lua> ToLua<'lua> for Player { impl TypeBody for Player { fn get_type_body(gen: &mut tealr::TypeGenerator) { - gen.fields.push(( - Cow::Borrowed("index"), - tealr::type_parts_to_str(u8::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("state"), - tealr::type_parts_to_str(PlayerState::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("damage_from_left"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_facing_left"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_upside_down"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("is_attacking"), - tealr::type_parts_to_str(bool::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("jump_frame_counter"), - tealr::type_parts_to_str(u16::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("pickup_grace_timer"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("incapacitation_timer"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("attack_timer"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("respawn_timer"), - tealr::type_parts_to_str(f32::get_type_parts()), - )); - gen.fields.push(( - Cow::Borrowed("camera_box"), - tealr::type_parts_to_str(RectLua::get_type_parts()), - )); + gen.fields + .push((Cow::Borrowed("index"), u8::get_type_parts())); + gen.fields + .push((Cow::Borrowed("state"), PlayerState::get_type_parts())); + gen.fields + .push((Cow::Borrowed("damage_from_left"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("is_facing_left"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("is_upside_down"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("is_attacking"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("jump_frame_counter"), u16::get_type_parts())); + gen.fields + .push((Cow::Borrowed("pickup_grace_timer"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("incapacitation_timer"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("attack_timer"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("respawn_timer"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("camera_box"), RectLua::get_type_parts())); gen.fields.push(( Cow::Borrowed("passive_effects"), - tealr::type_parts_to_str(Vec::::get_type_parts()), + Vec::::get_type_parts(), )); } } diff --git a/src/player/state.rs b/src/player/state.rs index 9df1da2331..516f28ea12 100644 --- a/src/player/state.rs +++ b/src/player/state.rs @@ -6,7 +6,7 @@ use macroquad::prelude::*; use hecs::{Entity, World}; use tealr::mlu::TealData; -use tealr::TypeName; +use tealr::{TypeBody, TypeName}; use core::Transform; use std::sync::Arc; @@ -34,6 +34,11 @@ pub enum PlayerState { impl UserData for PlayerState {} impl TealData for PlayerState {} +impl TypeBody for PlayerState { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.is_user_data = true; + } +} impl Default for PlayerState { fn default() -> Self { From 891fdf24a821df023ee689cb4b801ad777639fff Mon Sep 17 00:00:00 2001 From: lenscas Date: Fri, 18 Mar 2022 18:29:44 +0100 Subject: [PATCH 20/21] start exposing type methods --- Cargo.lock | 6 +- Cargo.toml | 1 + core/src/lua/create_component.rs | 2 +- core/src/lua/wrapped_types.rs | 23 ++++++- src/drawables/animated_sprite.rs | 46 +++++++++++++- src/drawables/mod.rs | 30 +++++++++- src/drawables/sprite.rs | 99 +++++++++++++++++++++++++++++-- src/effects/active/projectiles.rs | 6 +- src/lua.rs | 15 ++++- src/main.rs | 30 ++++++++-- src/particles.rs | 20 ++++++- src/player/mod.rs | 2 +- 12 files changed, 257 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6dc36676ad..31dbec6182 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -311,6 +311,7 @@ dependencies = [ "fishfight-core", "fishsticks", "hecs", + "hv-alchemy", "hv-cell", "hv-lua", "macroquad", @@ -1557,10 +1558,11 @@ dependencies = [ [[package]] name = "tealr" version = "0.8.2" -source = "git+https://github.com/lenscas/tealr?branch=temporary/feature/add_support_for_hv_lua#d706d1918a4efb77d6693d416af20da04f473055" +source = "git+https://github.com/lenscas/tealr?branch=temporary/feature/add_support_for_hv_lua#826a9be0a64eea0b523639294e8e8e50f4751e02" dependencies = [ "bstr", "hecs", + "hv-alchemy", "hv-cell", "hv-elastic", "hv-guarded-borrow", @@ -1573,7 +1575,7 @@ dependencies = [ [[package]] name = "tealr_derive" version = "0.8.2" -source = "git+https://github.com/lenscas/tealr?branch=temporary/feature/add_support_for_hv_lua#d706d1918a4efb77d6693d416af20da04f473055" +source = "git+https://github.com/lenscas/tealr?branch=temporary/feature/add_support_for_hv_lua#826a9be0a64eea0b523639294e8e8e50f4751e02" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 3b06e86755..daa49942fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ core = {path = "./core", package = "fishfight-core"} ff-particles = {version = "0.1", features = ["serde"]} fishsticks = {git = "https://github.com/fishfight/fishsticks", default-features = false, features = ["gilrs"]} hecs = {git = "https://github.com/sdleffler/hv-dev"} +hv-alchemy = {git = "https://github.com/sdleffler/hv-dev"} hv-cell = {git = "https://github.com/sdleffler/hv-dev"} hv-lua = {git = "https://github.com/sdleffler/hv-dev"}#imported so its macro's work macroquad = {version = "0.3.10"} diff --git a/core/src/lua/create_component.rs b/core/src/lua/create_component.rs index 83321e39e3..2395559ed6 100644 --- a/core/src/lua/create_component.rs +++ b/core/src/lua/create_component.rs @@ -137,7 +137,7 @@ macro_rules! create_type_component_container { std::borrow::Cow::Borrowed( stringify!($field_name) ), - <$type_name as tealr::TypeName>::get_type_parts() + <$type_name as tealr::TypeName>::get_marker_type_parts() ) ); diff --git a/core/src/lua/wrapped_types.rs b/core/src/lua/wrapped_types.rs index e83b61bfd4..e4fedc9a94 100644 --- a/core/src/lua/wrapped_types.rs +++ b/core/src/lua/wrapped_types.rs @@ -6,7 +6,7 @@ use macroquad::{ prelude::{Color, Rect, Texture2D, Vec2}, }; use tealr::{ - mlu::{TealData, UserDataWrapper}, + mlu::{MaybeSend, TealData, UserDataWrapper}, new_type, TypeBody, TypeName, }; @@ -183,8 +183,25 @@ impl UserData for RectLua { let mut wrapper = UserDataWrapper::from_user_data_methods(methods); ::add_methods(&mut wrapper) } + fn add_type_methods<'lua, M: hv_lua::UserDataMethods<'lua, hv_alchemy::Type>>( + methods: &mut M, + ) where + Self: 'static + MaybeSend, + { + let mut wrapper = UserDataWrapper::from_user_data_methods(methods); + ::add_type_methods(&mut wrapper) + } } impl TealData for RectLua { + fn add_type_methods<'lua, M: tealr::mlu::TealDataMethods<'lua, hv_alchemy::Type>>( + methods: &mut M, + ) where + Self: 'static + MaybeSend, + { + methods.add_function("new", |_, (x, y, w, h)| { + Ok(RectLua::from(Rect::new(x, y, w, h))) + }) + } fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { methods.add_method("point", |lua, this, ()| { Vec2Lua::from(this.0.point()).to_lua(lua) @@ -233,6 +250,10 @@ impl TypeBody for RectLua { gen.fields.push((Cow::Borrowed("w"), f32::get_type_parts())); gen.fields.push((Cow::Borrowed("h"), f32::get_type_parts())); } + fn get_type_body_marker(gen: &mut tealr::TypeGenerator) { + gen.is_user_data = true; + ::add_type_methods(gen); + } } #[derive(Clone)] diff --git a/src/drawables/animated_sprite.rs b/src/drawables/animated_sprite.rs index 294e085d89..6b297f6254 100644 --- a/src/drawables/animated_sprite.rs +++ b/src/drawables/animated_sprite.rs @@ -16,7 +16,7 @@ use macroquad::prelude::*; use hecs::World; use serde::{Deserialize, Serialize}; -use tealr::mlu::{TealData, UserDataWrapper}; +use tealr::mlu::{MaybeSend, TealData, UserDataWrapper}; use tealr::{TypeBody, TypeName}; use core::{lua::wrapped_types::Vec2Lua, Transform}; @@ -394,6 +394,14 @@ impl UserData for AnimatedSprite { let mut wrapper = UserDataWrapper::from_user_data_methods(methods); ::add_methods(&mut wrapper) } + fn add_type_methods<'lua, M: hv_lua::UserDataMethods<'lua, hv_alchemy::Type>>( + methods: &mut M, + ) where + Self: 'static + MaybeSend, + { + let mut wrapper = UserDataWrapper::from_user_data_methods(methods); + ::add_type_methods(&mut wrapper) + } } impl TealData for AnimatedSprite { fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { @@ -430,6 +438,15 @@ impl TealData for AnimatedSprite { Ok(()) }); } + fn add_type_methods<'lua, M: tealr::mlu::TealDataMethods<'lua, hv_alchemy::Type>>( + methods: &mut M, + ) where + Self: 'static + tealr::mlu::MaybeSend, + { + methods.add_function("new",|_,(texture_id, animations,params): (String, Vec, AnimatedSpriteParams)|{ + Ok(AnimatedSprite::new(&texture_id, &animations, params)) + }) + } } impl TypeBody for AnimatedSprite { fn get_type_body(gen: &mut tealr::TypeGenerator) { @@ -472,6 +489,10 @@ impl TypeBody for AnimatedSprite { gen.fields .push((Cow::Borrowed("wait_timer"), f32::get_type_parts())); } + fn get_type_body_marker(gen: &mut tealr::TypeGenerator) { + gen.is_user_data = true; + ::add_type_methods(gen); + } } impl AnimatedSprite { @@ -820,6 +841,13 @@ impl TealData for AnimatedSpriteSet { Ok(()) }); } + fn add_type_methods<'lua, M: tealr::mlu::TealDataMethods<'lua, hv_alchemy::Type>>( + methods: &mut M, + ) where + Self: 'static + MaybeSend, + { + methods.add_function("new_default", |_, ()| Ok(Self::default())) + } } impl TypeBody for AnimatedSpriteSet { fn get_type_body(gen: &mut tealr::TypeGenerator) { @@ -832,6 +860,10 @@ impl TypeBody for AnimatedSpriteSet { HashMap::::get_type_parts(), )); } + fn get_type_body_marker(gen: &mut tealr::TypeGenerator) { + gen.is_user_data = true; + ::add_type_methods(gen); + } } impl AnimatedSpriteSet { pub fn is_empty(&self) -> bool { @@ -996,6 +1028,18 @@ pub struct TweenMetadata { pub id: String, pub keyframes: Vec, } + +impl<'lua> FromLua<'lua> for TweenMetadata { + fn from_lua(lua_value: Value<'lua>, lua: &'lua hv_lua::Lua) -> hv_lua::Result { + LuaSerdeExt::from_value(lua, lua_value) + } +} +impl<'lua> ToLua<'lua> for TweenMetadata { + fn to_lua(self, lua: &'lua hv_lua::Lua) -> hv_lua::Result> { + LuaSerdeExt::to_value(lua, &self) + } +} + impl TypeBody for TweenMetadata { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields diff --git a/src/drawables/mod.rs b/src/drawables/mod.rs index adbc8b71b3..623fbebb70 100644 --- a/src/drawables/mod.rs +++ b/src/drawables/mod.rs @@ -10,7 +10,7 @@ use std::{ sync::Arc, }; use tealr::{ - mlu::{TealData, UserDataWrapper}, + mlu::{MaybeSend, TealData, UserDataWrapper}, TypeBody, TypeName, }; @@ -170,6 +170,14 @@ impl UserData for DrawableKind { let mut wrapper = UserDataWrapper::from_user_data_methods(methods); ::add_methods(&mut wrapper) } + fn add_type_methods<'lua, M: hv_lua::UserDataMethods<'lua, hv_alchemy::Type>>( + methods: &mut M, + ) where + Self: 'static + MaybeSend, + { + let mut wrapper = UserDataWrapper::from_user_data_methods(methods); + ::add_type_methods(&mut wrapper) + } } impl TealData for DrawableKind { fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { @@ -202,6 +210,26 @@ impl TealData for DrawableKind { } }); } + fn add_type_methods<'lua, M: tealr::mlu::TealDataMethods<'lua, hv_alchemy::Type>>( + methods: &mut M, + ) where + Self: 'static + tealr::mlu::MaybeSend, + { + methods.add_function("new_sprite", |_, v| Ok(Self::Sprite(v))); + methods.add_function("new_sprite", |_, v| Ok(Self::AnimatedSprite(v))); + methods.add_function("new_sprite", |_, v| Ok(Self::AnimatedSpriteSet(v))); + methods.add_function("new_sprite", |_, v| Ok(Self::SpriteSet(v))); + } +} +impl TypeBody for DrawableKind { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.is_user_data = true; + ::add_methods(gen); + } + fn get_type_body_marker(gen: &mut tealr::TypeGenerator) { + gen.is_user_data = true; + ::add_type_methods(gen); + } } pub fn draw_drawables(world: Arc>) { diff --git a/src/drawables/sprite.rs b/src/drawables/sprite.rs index 73979c50d7..1d40351ba6 100644 --- a/src/drawables/sprite.rs +++ b/src/drawables/sprite.rs @@ -1,5 +1,5 @@ use core::lua::get_table; -use core::lua::wrapped_types::{ColorLua, Vec2Lua}; +use core::lua::wrapped_types::{ColorLua, RectLua, Texture2DLua, Vec2Lua}; use std::iter::FromIterator; use std::ops::Div; use std::{borrow::Cow, collections::HashMap}; @@ -10,7 +10,7 @@ use macroquad::experimental::collections::storage; use macroquad::prelude::*; use serde::{Deserialize, Serialize}; -use tealr::mlu::{TealData, UserDataWrapper}; +use tealr::mlu::{MaybeSend, TealData, UserDataWrapper}; use tealr::{TypeBody, TypeName}; use core::Transform; @@ -112,10 +112,78 @@ pub struct Sprite { pub is_deactivated: bool, } -impl UserData for Sprite {} -impl TealData for Sprite {} +impl UserData for Sprite { + fn add_fields<'lua, F: hv_lua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("texture", |_, this| Ok(Texture2DLua::from(this.texture))); + fields.add_field_method_get("source_rect", |_, this| Ok(RectLua::from(this.source_rect))); + fields.add_field_method_get("tint", |_, this| Ok(ColorLua::from(this.tint))); + fields.add_field_method_get("scale", |_, this| Ok(this.scale)); + fields.add_field_method_get("offset", |_, this| Ok(Vec2Lua::from(this.offset))); + fields.add_field_method_get("pivot", |_, this| Ok(this.pivot.map(Vec2Lua::from))); + fields.add_field_method_get("is_flipped_x", |_, this| Ok(this.is_flipped_x)); + fields.add_field_method_get("is_flipped_y", |_, this| Ok(this.is_flipped_y)); + fields.add_field_method_get("is_deactivated", |_, this| Ok(this.is_deactivated)); + } + fn add_methods<'lua, M: hv_lua::UserDataMethods<'lua, Self>>(methods: &mut M) { + let mut wrapper = UserDataWrapper::from_user_data_methods(methods); + ::add_methods(&mut wrapper) + } + fn add_type_methods<'lua, M: hv_lua::UserDataMethods<'lua, hv_alchemy::Type>>( + methods: &mut M, + ) where + Self: 'static + MaybeSend, + { + let mut wrapper = UserDataWrapper::from_user_data_methods(methods); + ::add_type_methods(&mut wrapper) + } +} +impl TealData for Sprite { + fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { + methods.add_method("size", |_, this, ()| Ok(Vec2Lua::from(this.size()))); + methods.add_method_mut("set_scale", |_, this, scale| { + this.set_scale(scale); + Ok(()) + }) + } + + fn add_type_methods<'lua, M: tealr::mlu::TealDataMethods<'lua, hv_alchemy::Type>>( + methods: &mut M, + ) where + Self: 'static + MaybeSend, + { + methods.add_function("new", |_, (texture, params): (String, SpriteParams)| { + Ok(Self::new(&texture, params)) + }) + } +} impl TypeBody for Sprite { - fn get_type_body(_: &mut tealr::TypeGenerator) {} + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.is_user_data = true; + ::add_methods(gen); + gen.fields + .push((Cow::Borrowed("texture"), Texture2DLua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("source_rect"), RectLua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("tint"), ColorLua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("scale"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); + gen.fields + .push((Cow::Borrowed("pivot"), Option::::get_type_parts())); + gen.fields + .push((Cow::Borrowed("is_flipped_x"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("is_flipped_y"), bool::get_type_parts())); + gen.fields + .push((Cow::Borrowed("is_deactivated"), bool::get_type_parts())); + } + + fn get_type_body_marker(gen: &mut tealr::TypeGenerator) { + gen.is_user_data = true; + ::add_type_methods(gen); + } } impl Sprite { @@ -348,6 +416,14 @@ impl UserData for SpriteSet { let mut wrapper = UserDataWrapper::from_user_data_methods(methods); ::add_methods(&mut wrapper) } + fn add_type_methods<'lua, M: hv_lua::UserDataMethods<'lua, hv_alchemy::Type>>( + methods: &mut M, + ) where + Self: 'static + MaybeSend, + { + let mut wrapper = UserDataWrapper::from_user_data_methods(methods); + ::add_type_methods(&mut wrapper) + } } impl TealData for SpriteSet { fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { @@ -369,6 +445,19 @@ impl TealData for SpriteSet { Ok(()) }); } + fn add_type_methods<'lua, M: tealr::mlu::TealDataMethods<'lua, hv_alchemy::Type>>( + _methods: &mut M, + ) where + Self: 'static + MaybeSend, + { + } +} + +impl TypeBody for SpriteSet { + fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.is_user_data = true; + ::add_methods(gen); + } } impl SpriteSet { diff --git a/src/effects/active/projectiles.rs b/src/effects/active/projectiles.rs index d845589e75..4538bf9d18 100644 --- a/src/effects/active/projectiles.rs +++ b/src/effects/active/projectiles.rs @@ -61,11 +61,11 @@ impl TealData for Rectangle { } } #[derive(Clone, MluaTealDerive)] -pub struct Sprite { +pub struct SpriteProjectile { params: SpriteMetadata, can_rotate: bool, } -impl TealData for Sprite { +impl TealData for SpriteProjectile { fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { methods.add_method("to_projectile_kind", |_, this, ()| { Ok(ProjectileKind::Sprite { @@ -137,7 +137,7 @@ impl TealData for ProjectileKind { if let ProjectileKind::Sprite { can_rotate, params } = this { Ok(( true, - Some(Sprite { + Some(SpriteProjectile { can_rotate: *can_rotate, params: params.to_owned(), }), diff --git a/src/lua.rs b/src/lua.rs index c5ecf80c7e..dd99863809 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -1,3 +1,4 @@ +use core::lua::wrapped_types::RectLua; use std::{error::Error, sync::Arc}; use hecs::World; @@ -10,8 +11,12 @@ use tealr::TypeName; use crate::effects::active::projectiles::Projectile; use crate::effects::active::triggered::TriggeredEffect; +use crate::particles::ParticleEmitter; use crate::player::{Player, PlayerEventQueue, PlayerInventory}; -use crate::{Item, Owner, PhysicsBody, Resources, RigidBody}; +use crate::{ + AnimatedSprite, AnimatedSpriteSet, DrawableKind, Item, Owner, PhysicsBody, Resources, + RigidBody, Sprite, +}; pub(crate) fn run_event( event_name: &'static str, @@ -56,6 +61,12 @@ create_type_component_container!( PlayerInventory of CloneComponent, PlayerEventQueue of CloneComponent, Player of CloneComponent, + RectLua of RectLua, + ParticleEmitter of ParticleEmitter, + AnimatedSprite of AnimatedSprite, + AnimatedSpriteSet of AnimatedSpriteSet, + DrawableKind of DrawableKind, + Sprite of Sprite, ); @@ -64,8 +75,6 @@ pub(crate) fn register_types(lua: &Lua) -> Result> { Ok(TypeComponentContainer::new(lua)?.to_lua(lua)?) } -use hv_lua as mlua; - #[derive(Clone, Copy, tealr::MluaUserData)] pub struct ActorLua(Actor); impl TypeName for ActorLua { diff --git a/src/main.rs b/src/main.rs index 1baf1952f3..42407d50ad 100644 --- a/src/main.rs +++ b/src/main.rs @@ -63,8 +63,8 @@ use crate::effects::TriggeredEffectTrigger; use crate::game::GameMode; use crate::items::{ItemDepleteBehavior, ItemDropBehavior, ItemMetadata, Weapon}; use crate::lua::ActorLua; -use crate::particles::Particles; -use crate::player::{Player, PlayerEventKind, PlayerEventQueue, PlayerInventory, PlayerState}; +use crate::particles::{ParticleEmitter, ParticleEmitterMetadata, Particles}; +use crate::player::{Player, PlayerEventKind, PlayerInventory, PlayerState}; use crate::resources::load_resources; pub use effects::{ ActiveEffectKind, ActiveEffectMetadata, PassiveEffectInstance, PassiveEffectMetadata, @@ -217,6 +217,7 @@ async fn init_game() -> Result { async fn main() -> std::result::Result<(), Box> { let types = tealr::TypeWalker::new() .process_type::() + .process_type::() .process_type::() .process_type::() .process_type::() @@ -247,19 +248,40 @@ async fn main() -> std::result::Result<(), Box> { .process_type::() .process_type::() .process_type::() + .process_type::() .process_type::() .process_type::() .process_type::() + .process_type::() .process_type::() .process_type::() .process_type::() - .process_type::() + .process_type::() .process_type::() .process_type::() .process_type::() .process_type::() .process_type::() - .process_type::>(); + .process_type::() + .process_type::() + .process_type::>() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type_as_marker::>() + .process_type_as_marker::() + .process_type_as_marker::() + .process_type_as_marker::() + .process_type_as_marker::() + .process_type_as_marker::() + .process_type_as_marker::() + .process_type_as_marker::() + .process_type_as_marker::(); println!("time to generate the json files"); std::fs::write("./test.json", serde_json::to_string_pretty(&types).unwrap()).unwrap(); std::fs::write("./test.d.tl", types.generate_global("test").unwrap()).unwrap(); diff --git a/src/particles.rs b/src/particles.rs index d3da634b55..3730f8ee68 100644 --- a/src/particles.rs +++ b/src/particles.rs @@ -1,9 +1,10 @@ +use hv_alchemy::Type; use hv_cell::AtomicRefCell; use macroquad::experimental::collections::storage; use macroquad::prelude::*; use mlua::{FromLua, ToLua, UserData, UserDataMethods}; use std::{borrow::Cow, collections::HashMap, sync::Arc}; -use tealr::mlu::UserDataWrapper; +use tealr::mlu::{MaybeSend, UserDataWrapper}; use tealr::TypeName; use tealr::{mlu::TealData, TypeBody}; @@ -203,6 +204,13 @@ impl UserData for ParticleEmitter { let mut wrapper = UserDataWrapper::from_user_data_methods(methods); ::add_methods(&mut wrapper) } + fn add_type_methods<'lua, M: UserDataMethods<'lua, Type>>(methods: &mut M) + where + Self: 'static + MaybeSend, + { + let mut wrapper = UserDataWrapper::from_user_data_methods(methods); + ::add_type_methods(&mut wrapper) + } } impl TypeBody for ParticleEmitter { fn get_type_body(gen: &mut tealr::TypeGenerator) { @@ -229,6 +237,10 @@ impl TypeBody for ParticleEmitter { gen.fields .push((Cow::Borrowed("is_active"), bool::get_type_parts())); } + fn get_type_body_marker(gen: &mut tealr::TypeGenerator) { + gen.is_user_data = true; + ::add_type_methods(gen); + } } impl TealData for ParticleEmitter { @@ -241,6 +253,12 @@ impl TealData for ParticleEmitter { Ok(()) }) } + fn add_type_methods<'lua, M: tealr::mlu::TealDataMethods<'lua, Type>>(methods: &mut M) + where + Self: 'static + tealr::mlu::MaybeSend, + { + methods.add_function("new", |_, meta| Ok(ParticleEmitter::new(meta))) + } } impl From for ParticleEmitter { diff --git a/src/player/mod.rs b/src/player/mod.rs index 4d32b6b284..6272b4f693 100644 --- a/src/player/mod.rs +++ b/src/player/mod.rs @@ -78,7 +78,7 @@ pub struct Player { } impl<'lua> FromLua<'lua> for Player { - fn from_lua(lua_value: hv_lua::Value<'lua>, lua: &'lua hv_lua::Lua) -> hv_lua::Result { + fn from_lua(lua_value: hv_lua::Value<'lua>, _: &'lua hv_lua::Lua) -> hv_lua::Result { let table = core::lua::get_table(lua_value)?; Ok(Self { index: table.get("index")?, From fd180b30152510afda45375017430ac83b1da0d2 Mon Sep 17 00:00:00 2001 From: lenscas Date: Tue, 22 Mar 2022 20:43:15 +0100 Subject: [PATCH 21/21] update tealr and make use of TealData fields --- Cargo.lock | 4 +- Cargo.toml | 2 +- core/Cargo.toml | 1 + core/src/lua/create_component.rs | 32 ++++-- core/src/lua/wrapped_types.rs | 96 ++++++++-------- core/src/transform.rs | 4 +- src/drawables/animated_sprite.rs | 178 +++++++++++++----------------- src/drawables/mod.rs | 4 +- src/drawables/sprite.rs | 113 ++++++++++--------- src/effects/active/mod.rs | 10 +- src/effects/active/projectiles.rs | 16 +-- src/effects/active/triggered.rs | 50 +++++---- src/effects/passive/mod.rs | 67 ++++------- src/items.rs | 126 ++++++++++++--------- src/particles.rs | 151 ++++++++++++------------- src/physics.rs | 66 ++++++----- src/player/inventory.rs | 42 ++++--- src/player/mod.rs | 54 +++++---- 18 files changed, 526 insertions(+), 490 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 31dbec6182..9eb9391ac9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1558,7 +1558,7 @@ dependencies = [ [[package]] name = "tealr" version = "0.8.2" -source = "git+https://github.com/lenscas/tealr?branch=temporary/feature/add_support_for_hv_lua#826a9be0a64eea0b523639294e8e8e50f4751e02" +source = "git+https://github.com/lenscas/tealr?branch=temporary/feature/add_support_for_hv_lua#b3a40117c84e3dda58fb5c4eda95f88651953887" dependencies = [ "bstr", "hecs", @@ -1575,7 +1575,7 @@ dependencies = [ [[package]] name = "tealr_derive" version = "0.8.2" -source = "git+https://github.com/lenscas/tealr?branch=temporary/feature/add_support_for_hv_lua#826a9be0a64eea0b523639294e8e8e50f4751e02" +source = "git+https://github.com/lenscas/tealr?branch=temporary/feature/add_support_for_hv_lua#b3a40117c84e3dda58fb5c4eda95f88651953887" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index daa49942fd..6155c6a0cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,6 @@ macroquad-platformer = "0.1" serde = {version = "1.0", features = ["derive"]} serde_json = "1.0" tealr = {git = "https://github.com/lenscas/tealr", branch = "temporary/feature/add_support_for_hv_lua", features = ["mlua", "hv_lua", "mlua_vendored", "mlua_luajit", "mlua_serialize", "mlua_send", "derive"]} - +#tealr = {path = "../tealr/tealr", features = ["mlua", "hv_lua", "mlua_vendored", "mlua_luajit", "mlua_serialize", "mlua_send", "derive"]} [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = "0.2.74" diff --git a/core/Cargo.toml b/core/Cargo.toml index 308e575cdb..1d36b55684 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -16,6 +16,7 @@ macroquad = {version = "0.3.10"} serde = {version = "1.0", package = "serde", features = ["derive"]} serde_json = {version = "1.0"} tealr = {git = "https://github.com/lenscas/tealr", branch = "temporary/feature/add_support_for_hv_lua", features = ["mlua", "hv_lua", "mlua_macros", "mlua_vendored", "mlua_luajit", "mlua_serialize", "derive"]} +#tealr = {path = "../../tealr/tealr", features = ["mlua", "hv_lua", "mlua_vendored", "mlua_luajit", "mlua_serialize", "mlua_send", "derive"]} toml = "0.5" [target.'cfg(target_arch = "wasm32")'.dependencies] diff --git a/core/src/lua/create_component.rs b/core/src/lua/create_component.rs index 2395559ed6..1b6fbb534d 100644 --- a/core/src/lua/create_component.rs +++ b/core/src/lua/create_component.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use hv_lua::{FromLua, ToLua}; -use tealr::{NamePart, TealType, TypeName}; +use tealr::{NameContainer, NamePart, TealType, TypeName}; #[derive(Debug, Clone, Copy)] pub struct CopyComponent(T); @@ -44,7 +44,12 @@ impl tealr::TypeName for CopyComponent { impl tealr::TypeBody for CopyComponent { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.is_user_data = true; - get_type_body_component::(gen) + get_body_component::(gen); + //dbg!(gen); + } + fn get_type_body_marker(gen: &mut tealr::TypeGenerator) { + gen.is_user_data = true; + get_type_body_component::(gen); } } @@ -88,8 +93,18 @@ impl tealr::TypeName for CloneComponent { } impl tealr::TypeBody for CloneComponent { fn get_type_body(gen: &mut tealr::TypeGenerator) { - get_type_body_component::(gen) + get_body_component::(gen); } + fn get_type_body_marker(gen: &mut tealr::TypeGenerator) { + get_type_body_component::(gen); + } +} + +fn get_body_component(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + "value".as_bytes().to_vec().into(), + ::get_type_parts(), + )); } fn get_type_body_component(gen: &mut tealr::TypeGenerator) { @@ -97,18 +112,12 @@ fn get_type_body_component(gen: &mut tealr::Typ signature.append(&mut T::get_type_parts().into_owned()); signature.push(NamePart::Symbol(Cow::Borrowed("):"))); signature.append(&mut SelfType::get_type_parts().into_owned()); - gen.methods.push(tealr::ExportedFunction { name: Cow::Borrowed("new").into(), signature: Cow::Owned(signature), is_meta_method: false, }); - gen.fields.push(( - Cow::Borrowed("value"), - ::get_type_parts(), - )); } - #[macro_export] macro_rules! create_type_component_container { ($name:ident with $($field_name:ident of $type_name:ty,)+) => { @@ -134,9 +143,8 @@ macro_rules! create_type_component_container { println!("pushing field: {}",stringify!($type_name)); gen.fields.push( ( - std::borrow::Cow::Borrowed( - stringify!($field_name) - ), + + stringify!($field_name).as_bytes().to_vec().into(), <$type_name as tealr::TypeName>::get_marker_type_parts() ) diff --git a/core/src/lua/wrapped_types.rs b/core/src/lua/wrapped_types.rs index e4fedc9a94..5cf48df440 100644 --- a/core/src/lua/wrapped_types.rs +++ b/core/src/lua/wrapped_types.rs @@ -59,8 +59,10 @@ impl TypeName for Vec2Lua { } impl TypeBody for Vec2Lua { fn get_type_body(gen: &mut tealr::TypeGenerator) { - gen.fields.push((Cow::Borrowed("x"), f32::get_type_parts())); - gen.fields.push((Cow::Borrowed("y"), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("x").into(), f32::get_type_parts())); + gen.fields + .push((Cow::Borrowed("y").into(), f32::get_type_parts())); } } @@ -74,10 +76,14 @@ pub struct ColorLua { impl TypeBody for ColorLua { fn get_type_body(gen: &mut tealr::TypeGenerator) { - gen.fields.push((Cow::Borrowed("r"), f32::get_type_parts())); - gen.fields.push((Cow::Borrowed("g"), f32::get_type_parts())); - gen.fields.push((Cow::Borrowed("b"), f32::get_type_parts())); - gen.fields.push((Cow::Borrowed("a"), f32::get_type_parts())); + gen.fields + .push(("r".as_bytes().to_vec().into(), f32::get_type_parts())); + gen.fields + .push(("g".as_bytes().to_vec().into(), f32::get_type_parts())); + gen.fields + .push(("b".as_bytes().to_vec().into(), f32::get_type_parts())); + gen.fields + .push(("a".as_bytes().to_vec().into(), f32::get_type_parts())); } } @@ -157,26 +163,8 @@ impl TypeName for RectLua { } impl UserData for RectLua { fn add_fields<'lua, F: hv_lua::UserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("x", |lua, this| this.0.x.to_lua(lua)); - fields.add_field_method_get("y", |lua, this| this.0.y.to_lua(lua)); - fields.add_field_method_get("w", |lua, this| this.0.w.to_lua(lua)); - fields.add_field_method_get("h", |lua, this| this.0.h.to_lua(lua)); - fields.add_field_method_set("x", |_, this, value| { - this.0.x = value; - Ok(()) - }); - fields.add_field_method_set("y", |_, this, value| { - this.0.y = value; - Ok(()) - }); - fields.add_field_method_set("w", |_, this, value| { - this.0.w = value; - Ok(()) - }); - fields.add_field_method_set("h", |_, this, value| { - this.0.h = value; - Ok(()) - }); + let mut wrapper = UserDataWrapper::from_user_data_fields(fields); + ::add_fields(&mut wrapper) } fn add_methods<'lua, M: hv_lua::UserDataMethods<'lua, Self>>(methods: &mut M) { @@ -203,16 +191,12 @@ impl TealData for RectLua { }) } fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { - methods.add_method("point", |lua, this, ()| { - Vec2Lua::from(this.0.point()).to_lua(lua) - }); - methods.add_method("size", |lua, this, ()| { - Vec2Lua::from(this.0.size()).to_lua(lua) - }); - methods.add_method("left", |lua, this, ()| this.0.left().to_lua(lua)); - methods.add_method("right", |lua, this, ()| this.0.right().to_lua(lua)); - methods.add_method("top", |lua, this, ()| this.0.top().to_lua(lua)); - methods.add_method("bottom", |lua, this, ()| this.0.bottom().to_lua(lua)); + methods.add_method("point", |lua, this, ()| Ok(Vec2Lua::from(this.0.point()))); + methods.add_method("size", |lua, this, ()| Ok(Vec2Lua::from(this.0.size()))); + methods.add_method("left", |lua, this, ()| Ok(this.0.left())); + methods.add_method("right", |lua, this, ()| Ok(this.0.right())); + methods.add_method("top", |lua, this, ()| Ok(this.0.top())); + methods.add_method("bottom", |lua, this, ()| Ok(this.0.bottom())); methods.add_method_mut("move_to", |_, this, vec: Vec2Lua| { this.0.move_to(vec.into()); Ok(()) @@ -222,33 +206,49 @@ impl TealData for RectLua { Ok(()) }); methods.add_method("contains", |lua, this, point: Vec2Lua| { - this.0.contains(point.into()).to_lua(lua) + Ok(this.0.contains(point.into())) }); methods.add_method("overlaps", |lua, this, other: RectLua| { - this.0.overlaps(&other.into()).to_lua(lua) + Ok(this.0.overlaps(&other.into())) }); methods.add_method("combine_with", |lua, this, other: RectLua| { - RectLua::from(this.0.combine_with(other.into())).to_lua(lua) + Ok(RectLua::from(this.0.combine_with(other.into()))) }); methods.add_method("intersect", |lua, this, other: RectLua| { - this.0 - .intersect(other.into()) - .map(RectLua::from) - .to_lua(lua) + Ok(this.0.intersect(other.into()).map(RectLua::from)) }); methods.add_method("offset", |lua, this, offset: Vec2Lua| { - RectLua::from(this.0.offset(offset.into())).to_lua(lua) + Ok(RectLua::from(this.0.offset(offset.into()))) + }); + } + fn add_fields<'lua, F: tealr::mlu::TealDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("x", |lua, this| Ok(this.0.x)); + fields.add_field_method_get("y", |lua, this| Ok(this.0.y)); + fields.add_field_method_get("w", |lua, this| Ok(this.0.w)); + fields.add_field_method_get("h", |lua, this| Ok(this.0.h)); + fields.add_field_method_set("x", |_, this, value| { + this.0.x = value; + Ok(()) + }); + fields.add_field_method_set("y", |_, this, value| { + this.0.y = value; + Ok(()) + }); + fields.add_field_method_set("w", |_, this, value| { + this.0.w = value; + Ok(()) + }); + fields.add_field_method_set("h", |_, this, value| { + this.0.h = value; + Ok(()) }); } } impl TypeBody for RectLua { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.is_user_data = true; + ::add_fields(gen); ::add_methods(gen); - gen.fields.push((Cow::Borrowed("x"), f32::get_type_parts())); - gen.fields.push((Cow::Borrowed("y"), f32::get_type_parts())); - gen.fields.push((Cow::Borrowed("w"), f32::get_type_parts())); - gen.fields.push((Cow::Borrowed("h"), f32::get_type_parts())); } fn get_type_body_marker(gen: &mut tealr::TypeGenerator) { gen.is_user_data = true; diff --git a/core/src/transform.rs b/core/src/transform.rs index fae67844bf..58e67c008a 100644 --- a/core/src/transform.rs +++ b/core/src/transform.rs @@ -59,8 +59,8 @@ impl<'lua> FromLua<'lua> for Transform { impl TypeBody for Transform { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields - .push((Cow::Borrowed("position"), Vec2Lua::get_type_parts())); + .push((Cow::Borrowed("position").into(), Vec2Lua::get_type_parts())); gen.fields - .push((Cow::Borrowed("rotation"), f32::get_type_parts())); + .push((Cow::Borrowed("rotation").into(), f32::get_type_parts())); } } diff --git a/src/drawables/animated_sprite.rs b/src/drawables/animated_sprite.rs index 6b297f6254..af795da1ac 100644 --- a/src/drawables/animated_sprite.rs +++ b/src/drawables/animated_sprite.rs @@ -61,19 +61,19 @@ impl<'lua> ToLua<'lua> for Animation { impl TypeBody for Animation { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields - .push((Cow::Borrowed("id"), String::get_type_parts())); + .push((Cow::Borrowed("id").into(), String::get_type_parts())); gen.fields - .push((Cow::Borrowed("row"), u32::get_type_parts())); + .push((Cow::Borrowed("row").into(), u32::get_type_parts())); gen.fields - .push((Cow::Borrowed("frames"), u32::get_type_parts())); + .push((Cow::Borrowed("frames").into(), u32::get_type_parts())); gen.fields - .push((Cow::Borrowed("fps"), u32::get_type_parts())); + .push((Cow::Borrowed("fps").into(), u32::get_type_parts())); gen.fields.push(( - Cow::Borrowed("tweens"), + Cow::Borrowed("tweens").into(), HashMap::::get_type_parts(), )); gen.fields - .push((Cow::Borrowed("is_looping"), bool::get_type_parts())); + .push((Cow::Borrowed("is_looping").into(), bool::get_type_parts())); } } @@ -127,11 +127,11 @@ impl<'lua> ToLua<'lua> for Tween { impl TypeBody for Tween { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields.push(( - Cow::Borrowed("keyframes"), + Cow::Borrowed("keyframes").into(), Vec::::get_type_parts(), )); gen.fields.push(( - Cow::Borrowed("current_translation"), + Cow::Borrowed("current_translation").into(), Vec2Lua::get_type_parts(), )); } @@ -164,9 +164,11 @@ pub struct Keyframe { impl TypeBody for Keyframe { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields - .push((Cow::Borrowed("frame"), u32::get_type_parts())); - gen.fields - .push((Cow::Borrowed("translation"), Vec2Lua::get_type_parts())); + .push((Cow::Borrowed("frame").into(), u32::get_type_parts())); + gen.fields.push(( + Cow::Borrowed("translation").into(), + Vec2Lua::get_type_parts(), + )); } } @@ -218,23 +220,25 @@ impl<'lua> ToLua<'lua> for AnimatedSpriteParams { impl TypeBody for AnimatedSpriteParams { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields.push(( - Cow::Borrowed("frame_size"), + Cow::Borrowed("frame_size").into(), Option::::get_type_parts(), )); gen.fields - .push((Cow::Borrowed("scale"), f32::get_type_parts())); - gen.fields - .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); + .push((Cow::Borrowed("scale").into(), f32::get_type_parts())); gen.fields - .push((Cow::Borrowed("pivot"), Option::::get_type_parts())); + .push((Cow::Borrowed("offset").into(), Vec2Lua::get_type_parts())); + gen.fields.push(( + Cow::Borrowed("pivot").into(), + Option::::get_type_parts(), + )); gen.fields - .push((Cow::Borrowed("tint"), ColorLua::get_type_parts())); + .push((Cow::Borrowed("tint").into(), ColorLua::get_type_parts())); gen.fields - .push((Cow::Borrowed("is_flipped_x"), bool::get_type_parts())); + .push((Cow::Borrowed("is_flipped_x").into(), bool::get_type_parts())); gen.fields - .push((Cow::Borrowed("is_flipped_y"), bool::get_type_parts())); + .push((Cow::Borrowed("is_flipped_y").into(), bool::get_type_parts())); gen.fields.push(( - Cow::Borrowed("autoplay_id"), + Cow::Borrowed("autoplay_id").into(), Option::::get_type_parts(), )); } @@ -308,6 +312,25 @@ pub struct AnimatedSprite { impl UserData for AnimatedSprite { fn add_fields<'lua, F: hv_lua::UserDataFields<'lua, Self>>(fields: &mut F) { + let mut wrapper = UserDataWrapper::from_user_data_fields(fields); + ::add_fields(&mut wrapper) + } + + fn add_methods<'lua, M: hv_lua::UserDataMethods<'lua, Self>>(methods: &mut M) { + let mut wrapper = UserDataWrapper::from_user_data_methods(methods); + ::add_methods(&mut wrapper) + } + fn add_type_methods<'lua, M: hv_lua::UserDataMethods<'lua, hv_alchemy::Type>>( + methods: &mut M, + ) where + Self: 'static + MaybeSend, + { + let mut wrapper = UserDataWrapper::from_user_data_methods(methods); + ::add_type_methods(&mut wrapper) + } +} +impl TealData for AnimatedSprite { + fn add_fields<'lua, F: tealr::mlu::TealDataFields<'lua, Self>>(fields: &mut F) { fields.add_field_method_get("texture", |_, this| Ok(Texture2DLua::from(this.texture))); fields.add_field_method_get("frame_size", |_, this| Ok(Vec2Lua::from(this.frame_size))); fields.add_field_method_get("scale", |_, this| Ok(this.scale)); @@ -389,21 +412,6 @@ impl UserData for AnimatedSprite { Ok(()) }); } - - fn add_methods<'lua, M: hv_lua::UserDataMethods<'lua, Self>>(methods: &mut M) { - let mut wrapper = UserDataWrapper::from_user_data_methods(methods); - ::add_methods(&mut wrapper) - } - fn add_type_methods<'lua, M: hv_lua::UserDataMethods<'lua, hv_alchemy::Type>>( - methods: &mut M, - ) where - Self: 'static + MaybeSend, - { - let mut wrapper = UserDataWrapper::from_user_data_methods(methods); - ::add_type_methods(&mut wrapper) - } -} -impl TealData for AnimatedSprite { fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { methods.add_method("get_animation", |_, this, value: String| { Ok(this.get_animation(&value).map(ToOwned::to_owned)) @@ -451,43 +459,8 @@ impl TealData for AnimatedSprite { impl TypeBody for AnimatedSprite { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.is_user_data = true; + ::add_fields(gen); ::add_methods(gen); - gen.fields - .push((Cow::Borrowed("texture"), Texture2DLua::get_type_parts())); - gen.fields - .push((Cow::Borrowed("frame_size"), Vec2Lua::get_type_parts())); - gen.fields - .push((Cow::Borrowed("scale"), f32::get_type_parts())); - gen.fields - .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); - gen.fields - .push((Cow::Borrowed("pivot"), Option::::get_type_parts())); - gen.fields - .push((Cow::Borrowed("tint"), ColorLua::get_type_parts())); - gen.fields.push(( - Cow::Borrowed("animations"), - Vec::::get_type_parts(), - )); - gen.fields - .push((Cow::Borrowed("current_index"), usize::get_type_parts())); - gen.fields.push(( - Cow::Borrowed("queued_action"), - Option::::get_type_parts(), - )); - gen.fields - .push((Cow::Borrowed("current_frame"), u32::get_type_parts())); - gen.fields - .push((Cow::Borrowed("frame_timer"), f32::get_type_parts())); - gen.fields - .push((Cow::Borrowed("is_playing"), bool::get_type_parts())); - gen.fields - .push((Cow::Borrowed("is_flipped_x"), bool::get_type_parts())); - gen.fields - .push((Cow::Borrowed("is_flipped_y"), bool::get_type_parts())); - gen.fields - .push((Cow::Borrowed("is_deactivated"), bool::get_type_parts())); - gen.fields - .push((Cow::Borrowed("wait_timer"), f32::get_type_parts())); } fn get_type_body_marker(gen: &mut tealr::TypeGenerator) { gen.is_user_data = true; @@ -766,8 +739,8 @@ pub struct AnimatedSpriteSet { impl UserData for AnimatedSpriteSet { fn add_fields<'lua, F: hv_lua::UserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("draw_order", |_, this| Ok(this.draw_order.clone())); - fields.add_field_method_get("map", |_, this| Ok(this.map.clone())); + let mut wrapper = UserDataWrapper::from_user_data_fields(fields); + ::add_fields(&mut wrapper) } fn add_methods<'lua, M: hv_lua::UserDataMethods<'lua, Self>>(methods: &mut M) { @@ -776,6 +749,10 @@ impl UserData for AnimatedSpriteSet { } } impl TealData for AnimatedSpriteSet { + fn add_fields<'lua, F: tealr::mlu::TealDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("draw_order", |_, this| Ok(this.draw_order.clone())); + fields.add_field_method_get("map", |_, this| Ok(this.map.clone())); + } fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { methods.add_method("is_empty", |_, this, ()| Ok(this.is_empty())); methods.add_method("size", |_, this, ()| Ok(Vec2Lua::from(this.size()))); @@ -852,13 +829,8 @@ impl TealData for AnimatedSpriteSet { impl TypeBody for AnimatedSpriteSet { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.is_user_data = true; + ::add_fields(gen); ::add_methods(gen); - gen.fields - .push((Cow::Borrowed("draw_order"), Vec::::get_type_parts())); - gen.fields.push(( - Cow::Borrowed("map"), - HashMap::::get_type_parts(), - )); } fn get_type_body_marker(gen: &mut tealr::TypeGenerator) { gen.is_user_data = true; @@ -996,19 +968,19 @@ pub struct AnimationMetadata { impl TypeBody for AnimationMetadata { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields - .push((Cow::Borrowed("id"), String::get_type_parts())); + .push((Cow::Borrowed("id").into(), String::get_type_parts())); gen.fields - .push((Cow::Borrowed("row"), u32::get_type_parts())); + .push((Cow::Borrowed("row").into(), u32::get_type_parts())); gen.fields - .push((Cow::Borrowed("frames"), u32::get_type_parts())); + .push((Cow::Borrowed("frames").into(), u32::get_type_parts())); gen.fields - .push((Cow::Borrowed("fps"), u32::get_type_parts())); + .push((Cow::Borrowed("fps").into(), u32::get_type_parts())); gen.fields.push(( - Cow::Borrowed("tweens"), + Cow::Borrowed("tweens").into(), Vec::::get_type_parts(), )); gen.fields - .push((Cow::Borrowed("is_looping"), bool::get_type_parts())); + .push((Cow::Borrowed("is_looping").into(), bool::get_type_parts())); } } @@ -1043,9 +1015,9 @@ impl<'lua> ToLua<'lua> for TweenMetadata { impl TypeBody for TweenMetadata { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields - .push((Cow::Borrowed("id"), String::get_type_parts())); + .push((Cow::Borrowed("id").into(), String::get_type_parts())); gen.fields.push(( - Cow::Borrowed("keyframes"), + Cow::Borrowed("keyframes").into(), Vec::::get_type_parts(), )); } @@ -1080,24 +1052,32 @@ pub struct AnimatedSpriteMetadata { impl TypeBody for AnimatedSpriteMetadata { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields - .push((Cow::Borrowed("texture_id"), String::get_type_parts())); - gen.fields - .push((Cow::Borrowed("scale"), Option::::get_type_parts())); - gen.fields - .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); - gen.fields - .push((Cow::Borrowed("pivot"), Option::::get_type_parts())); + .push((Cow::Borrowed("texture_id").into(), String::get_type_parts())); + gen.fields.push(( + Cow::Borrowed("scale").into(), + Option::::get_type_parts(), + )); gen.fields - .push((Cow::Borrowed("tint"), Option::::get_type_parts())); + .push((Cow::Borrowed("offset").into(), Vec2Lua::get_type_parts())); gen.fields.push(( - Cow::Borrowed("animations"), + Cow::Borrowed("pivot").into(), + Option::::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("tint").into(), + Option::::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("animations").into(), Vec::::get_type_parts(), )); gen.fields.push(( - Cow::Borrowed("autoplay_id"), + Cow::Borrowed("autoplay_id").into(), Option::::get_type_parts(), )); - gen.fields - .push((Cow::Borrowed("is_deactivated"), bool::get_type_parts())); + gen.fields.push(( + Cow::Borrowed("is_deactivated").into(), + bool::get_type_parts(), + )); } } diff --git a/src/drawables/mod.rs b/src/drawables/mod.rs index 623fbebb70..b4dc28da80 100644 --- a/src/drawables/mod.rs +++ b/src/drawables/mod.rs @@ -53,9 +53,9 @@ impl<'lua> ToLua<'lua> for Drawable { impl TypeBody for Drawable { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields - .push((Cow::Borrowed("draw_order"), u32::get_type_parts())); + .push((Cow::Borrowed("draw_order").into(), u32::get_type_parts())); gen.fields - .push((Cow::Borrowed("kind"), DrawableKind::get_type_parts())); + .push((Cow::Borrowed("kind").into(), DrawableKind::get_type_parts())); } } diff --git a/src/drawables/sprite.rs b/src/drawables/sprite.rs index 1d40351ba6..19cf57fccf 100644 --- a/src/drawables/sprite.rs +++ b/src/drawables/sprite.rs @@ -66,21 +66,31 @@ pub struct SpriteMetadata { impl TypeBody for SpriteMetadata { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields - .push((Cow::Borrowed("texture"), String::get_type_parts())); + .push((Cow::Borrowed("texture").into(), String::get_type_parts())); gen.fields - .push((Cow::Borrowed("index"), usize::get_type_parts())); - gen.fields - .push((Cow::Borrowed("scale"), Option::::get_type_parts())); - gen.fields - .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); - gen.fields - .push((Cow::Borrowed("pivot"), Option::::get_type_parts())); - gen.fields - .push((Cow::Borrowed("size"), Option::::get_type_parts())); - gen.fields - .push((Cow::Borrowed("tint"), Option::::get_type_parts())); + .push((Cow::Borrowed("index").into(), usize::get_type_parts())); + gen.fields.push(( + Cow::Borrowed("scale").into(), + Option::::get_type_parts(), + )); gen.fields - .push((Cow::Borrowed("is_deactivated"), bool::get_type_parts())); + .push((Cow::Borrowed("offset").into(), Vec2Lua::get_type_parts())); + gen.fields.push(( + Cow::Borrowed("pivot").into(), + Option::::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("size").into(), + Option::::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("tint").into(), + Option::::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("is_deactivated").into(), + bool::get_type_parts(), + )); } } @@ -114,15 +124,8 @@ pub struct Sprite { impl UserData for Sprite { fn add_fields<'lua, F: hv_lua::UserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("texture", |_, this| Ok(Texture2DLua::from(this.texture))); - fields.add_field_method_get("source_rect", |_, this| Ok(RectLua::from(this.source_rect))); - fields.add_field_method_get("tint", |_, this| Ok(ColorLua::from(this.tint))); - fields.add_field_method_get("scale", |_, this| Ok(this.scale)); - fields.add_field_method_get("offset", |_, this| Ok(Vec2Lua::from(this.offset))); - fields.add_field_method_get("pivot", |_, this| Ok(this.pivot.map(Vec2Lua::from))); - fields.add_field_method_get("is_flipped_x", |_, this| Ok(this.is_flipped_x)); - fields.add_field_method_get("is_flipped_y", |_, this| Ok(this.is_flipped_y)); - fields.add_field_method_get("is_deactivated", |_, this| Ok(this.is_deactivated)); + let mut wrapper = UserDataWrapper::from_user_data_fields(fields); + ::add_fields(&mut wrapper) } fn add_methods<'lua, M: hv_lua::UserDataMethods<'lua, Self>>(methods: &mut M) { let mut wrapper = UserDataWrapper::from_user_data_methods(methods); @@ -138,6 +141,17 @@ impl UserData for Sprite { } } impl TealData for Sprite { + fn add_fields<'lua, F: tealr::mlu::TealDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("texture", |_, this| Ok(Texture2DLua::from(this.texture))); + fields.add_field_method_get("source_rect", |_, this| Ok(RectLua::from(this.source_rect))); + fields.add_field_method_get("tint", |_, this| Ok(ColorLua::from(this.tint))); + fields.add_field_method_get("scale", |_, this| Ok(this.scale)); + fields.add_field_method_get("offset", |_, this| Ok(Vec2Lua::from(this.offset))); + fields.add_field_method_get("pivot", |_, this| Ok(this.pivot.map(Vec2Lua::from))); + fields.add_field_method_get("is_flipped_x", |_, this| Ok(this.is_flipped_x)); + fields.add_field_method_get("is_flipped_y", |_, this| Ok(this.is_flipped_y)); + fields.add_field_method_get("is_deactivated", |_, this| Ok(this.is_deactivated)); + } fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { methods.add_method("size", |_, this, ()| Ok(Vec2Lua::from(this.size()))); methods.add_method_mut("set_scale", |_, this, scale| { @@ -159,25 +173,8 @@ impl TealData for Sprite { impl TypeBody for Sprite { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.is_user_data = true; + ::add_fields(gen); ::add_methods(gen); - gen.fields - .push((Cow::Borrowed("texture"), Texture2DLua::get_type_parts())); - gen.fields - .push((Cow::Borrowed("source_rect"), RectLua::get_type_parts())); - gen.fields - .push((Cow::Borrowed("tint"), ColorLua::get_type_parts())); - gen.fields - .push((Cow::Borrowed("scale"), f32::get_type_parts())); - gen.fields - .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); - gen.fields - .push((Cow::Borrowed("pivot"), Option::::get_type_parts())); - gen.fields - .push((Cow::Borrowed("is_flipped_x"), bool::get_type_parts())); - gen.fields - .push((Cow::Borrowed("is_flipped_y"), bool::get_type_parts())); - gen.fields - .push((Cow::Borrowed("is_deactivated"), bool::get_type_parts())); } fn get_type_body_marker(gen: &mut tealr::TypeGenerator) { @@ -299,27 +296,35 @@ impl<'lua> ToLua<'lua> for SpriteParams { impl TypeBody for SpriteParams { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields.push(( - Cow::Borrowed("sprite_size"), + Cow::Borrowed("sprite_size").into(), Option::::get_type_parts(), )); gen.fields - .push((Cow::Borrowed("index"), usize::get_type_parts())); + .push((Cow::Borrowed("index").into(), usize::get_type_parts())); gen.fields - .push((Cow::Borrowed("scale"), f32::get_type_parts())); + .push((Cow::Borrowed("scale").into(), f32::get_type_parts())); gen.fields - .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); - gen.fields - .push((Cow::Borrowed("pivot"), Option::::get_type_parts())); - gen.fields - .push((Cow::Borrowed("size"), Option::::get_type_parts())); - gen.fields - .push((Cow::Borrowed("tint"), Option::::get_type_parts())); - gen.fields - .push((Cow::Borrowed("is_flipped_x"), bool::get_type_parts())); + .push((Cow::Borrowed("offset").into(), Vec2Lua::get_type_parts())); + gen.fields.push(( + Cow::Borrowed("pivot").into(), + Option::::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("size").into(), + Option::::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("tint").into(), + Option::::get_type_parts(), + )); gen.fields - .push((Cow::Borrowed("is_flipped_y"), bool::get_type_parts())); + .push((Cow::Borrowed("is_flipped_x").into(), bool::get_type_parts())); gen.fields - .push((Cow::Borrowed("is_deactivated"), bool::get_type_parts())); + .push((Cow::Borrowed("is_flipped_y").into(), bool::get_type_parts())); + gen.fields.push(( + Cow::Borrowed("is_deactivated").into(), + bool::get_type_parts(), + )); } } diff --git a/src/effects/active/mod.rs b/src/effects/active/mod.rs index 1f5382fb0e..c7136be50a 100644 --- a/src/effects/active/mod.rs +++ b/src/effects/active/mod.rs @@ -233,14 +233,16 @@ pub struct ActiveEffectMetadata { impl TypeBody for ActiveEffectMetadata { fn get_type_body(gen: &mut tealr::TypeGenerator) { - gen.fields - .push((Cow::Borrowed("kind"), ActiveEffectKind::get_type_parts())); gen.fields.push(( - Cow::Borrowed("sound_effect_id"), + Cow::Borrowed("kind").into(), + ActiveEffectKind::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("sound_effect_id").into(), Option::::get_type_parts(), )); gen.fields - .push((Cow::Borrowed("delay"), f32::get_type_parts())); + .push((Cow::Borrowed("delay").into(), f32::get_type_parts())); } } diff --git a/src/effects/active/projectiles.rs b/src/effects/active/projectiles.rs index 4538bf9d18..6ad734390c 100644 --- a/src/effects/active/projectiles.rs +++ b/src/effects/active/projectiles.rs @@ -187,18 +187,20 @@ impl<'lua> ToLua<'lua> for Projectile { impl TypeBody for Projectile { fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("kind").into(), + ProjectileKind::get_type_parts(), + )); gen.fields - .push((Cow::Borrowed("kind"), ProjectileKind::get_type_parts())); - gen.fields - .push((Cow::Borrowed("owner"), Entity::get_type_parts())); + .push((Cow::Borrowed("owner").into(), Entity::get_type_parts())); gen.fields - .push((Cow::Borrowed("origin"), Vec2Lua::get_type_parts())); + .push((Cow::Borrowed("origin").into(), Vec2Lua::get_type_parts())); gen.fields - .push((Cow::Borrowed("range"), f32::get_type_parts())); + .push((Cow::Borrowed("range").into(), f32::get_type_parts())); gen.fields - .push((Cow::Borrowed("is_lethal"), bool::get_type_parts())); + .push((Cow::Borrowed("is_lethal").into(), bool::get_type_parts())); gen.fields.push(( - Cow::Borrowed("passive_effects"), + Cow::Borrowed("passive_effects").into(), Vec::::get_type_parts(), )); } diff --git a/src/effects/active/triggered.rs b/src/effects/active/triggered.rs index aa78c87a71..3cb8433dd1 100644 --- a/src/effects/active/triggered.rs +++ b/src/effects/active/triggered.rs @@ -125,47 +125,57 @@ impl<'lua> ToLua<'lua> for TriggeredEffect { impl TypeBody for TriggeredEffect { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields - .push((Cow::Borrowed("owner"), Entity::get_type_parts())); + .push((Cow::Borrowed("owner").into(), Entity::get_type_parts())); gen.fields.push(( - Cow::Borrowed("trigger"), + Cow::Borrowed("trigger").into(), Vec::::get_type_parts(), )); gen.fields.push(( - Cow::Borrowed("effects"), + Cow::Borrowed("effects").into(), Vec::::get_type_parts(), )); + gen.fields.push(( + Cow::Borrowed("activation_delay").into(), + f32::get_type_parts(), + )); gen.fields - .push((Cow::Borrowed("activation_delay"), f32::get_type_parts())); - gen.fields - .push((Cow::Borrowed("trigger_delay"), f32::get_type_parts())); + .push((Cow::Borrowed("trigger_delay").into(), f32::get_type_parts())); gen.fields.push(( - Cow::Borrowed("timed_trigger"), + Cow::Borrowed("timed_trigger").into(), Option::::get_type_parts(), )); gen.fields - .push((Cow::Borrowed("is_kickable"), bool::get_type_parts())); + .push((Cow::Borrowed("is_kickable").into(), bool::get_type_parts())); gen.fields.push(( - Cow::Borrowed("should_override_delay"), + Cow::Borrowed("should_override_delay").into(), bool::get_type_parts(), )); gen.fields.push(( - Cow::Borrowed("should_collide_with_platforms"), + Cow::Borrowed("should_collide_with_platforms").into(), bool::get_type_parts(), )); gen.fields - .push((Cow::Borrowed("is_triggered"), bool::get_type_parts())); + .push((Cow::Borrowed("is_triggered").into(), bool::get_type_parts())); gen.fields.push(( - Cow::Borrowed("triggered_by"), + Cow::Borrowed("triggered_by").into(), Option::::get_type_parts(), )); - gen.fields - .push((Cow::Borrowed("kick_delay_timer"), f32::get_type_parts())); - gen.fields - .push((Cow::Borrowed("activation_timer"), f32::get_type_parts())); - gen.fields - .push((Cow::Borrowed("trigger_delay_timer"), f32::get_type_parts())); - gen.fields - .push((Cow::Borrowed("timed_trigger_timer"), f32::get_type_parts())); + gen.fields.push(( + Cow::Borrowed("kick_delay_timer").into(), + f32::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("activation_timer").into(), + f32::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("trigger_delay_timer").into(), + f32::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("timed_trigger_timer").into(), + f32::get_type_parts(), + )); } } diff --git a/src/effects/passive/mod.rs b/src/effects/passive/mod.rs index 5d13484650..7614236928 100644 --- a/src/effects/passive/mod.rs +++ b/src/effects/passive/mod.rs @@ -171,6 +171,12 @@ impl UserData for PassiveEffectInstance { ::add_methods(&mut wrapper) } fn add_fields<'lua, F: hv_lua::UserDataFields<'lua, Self>>(fields: &mut F) { + let mut wrapper = UserDataWrapper::from_user_data_fields(fields); + ::add_fields(&mut wrapper) + } +} +impl TealData for PassiveEffectInstance { + fn add_fields<'lua, F: tealr::mlu::TealDataFields<'lua, Self>>(fields: &mut F) { fields.add_field_method_get("name", |_, this| Ok(this.name.to_owned())); fields.add_field_method_get("function", |_, this| Ok(this.function.to_owned())); fields.add_field_method_get("activated_on", |_, this| Ok(this.activated_on.to_owned())); @@ -231,8 +237,6 @@ impl UserData for PassiveEffectInstance { Ok(()) }); } -} -impl TealData for PassiveEffectInstance { fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { methods.add_method_mut("update", |_, this, dt| { this.update(dt); @@ -245,37 +249,8 @@ impl TealData for PassiveEffectInstance { impl TypeBody for PassiveEffectInstance { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.is_user_data = true; + ::add_fields(gen); ::add_methods(gen); - gen.fields - .push((Cow::Borrowed("name"), String::get_type_parts())); - gen.fields.push(( - Cow::Borrowed("function"), - Option::::get_type_parts(), - )); - gen.fields.push(( - Cow::Borrowed("activated_on"), - Vec::::get_type_parts(), - )); - gen.fields.push(( - Cow::Borrowed("particle_effect_id"), - Option::::get_type_parts(), - )); - gen.fields.push(( - Cow::Borrowed("event_particle_effect_id"), - Option::::get_type_parts(), - )); - gen.fields - .push((Cow::Borrowed("blocks_damage"), bool::get_type_parts())); - gen.fields - .push((Cow::Borrowed("uses"), Option::::get_type_parts())); - gen.fields - .push((Cow::Borrowed("item"), Option::::get_type_parts())); - gen.fields - .push((Cow::Borrowed("use_cnt"), u32::get_type_parts())); - gen.fields - .push((Cow::Borrowed("duration"), Option::::get_type_parts())); - gen.fields - .push((Cow::Borrowed("duration_timer"), f32::get_type_parts())); } } @@ -366,28 +341,34 @@ impl<'lua> ToLua<'lua> for PassiveEffectMetadata { impl TypeBody for PassiveEffectMetadata { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields - .push((Cow::Borrowed("name"), String::get_type_parts())); + .push((Cow::Borrowed("name").into(), String::get_type_parts())); gen.fields.push(( - Cow::Borrowed("function_id"), + Cow::Borrowed("function_id").into(), Option::::get_type_parts(), )); gen.fields.push(( - Cow::Borrowed("activated_on"), + Cow::Borrowed("activated_on").into(), Vec::::get_type_parts(), )); gen.fields.push(( - Cow::Borrowed("particle_effect"), + Cow::Borrowed("particle_effect").into(), Option::::get_type_parts(), )); gen.fields.push(( - Cow::Borrowed("event_particle_effect"), + Cow::Borrowed("event_particle_effect").into(), Option::::get_type_parts(), )); - gen.fields - .push((Cow::Borrowed("blocks_damage"), bool::get_type_parts())); - gen.fields - .push((Cow::Borrowed("uses"), Option::::get_type_parts())); - gen.fields - .push((Cow::Borrowed("duration"), Option::::get_type_parts())); + gen.fields.push(( + Cow::Borrowed("blocks_damage").into(), + bool::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("uses").into(), + Option::::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("duration").into(), + Option::::get_type_parts(), + )); } } diff --git a/src/items.rs b/src/items.rs index 28233dcba4..e2ceffa4ed 100644 --- a/src/items.rs +++ b/src/items.rs @@ -179,33 +179,41 @@ impl<'lua> ToLua<'lua> for Item { impl TypeBody for Item { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields - .push((Cow::Borrowed("id"), String::get_type_parts())); + .push((Cow::Borrowed("id").into(), String::get_type_parts())); gen.fields - .push((Cow::Borrowed("name"), String::get_type_parts())); + .push((Cow::Borrowed("name").into(), String::get_type_parts())); gen.fields.push(( - Cow::Borrowed("effects"), + Cow::Borrowed("effects").into(), Vec::::get_type_parts(), )); - gen.fields - .push((Cow::Borrowed("uses"), Option::::get_type_parts())); - gen.fields - .push((Cow::Borrowed("duration"), Option::::get_type_parts())); - gen.fields - .push((Cow::Borrowed("mount_offset"), Vec2Lua::get_type_parts())); gen.fields.push(( - Cow::Borrowed("drop_behavior"), + Cow::Borrowed("uses").into(), + Option::::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("duration").into(), + Option::::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("mount_offset").into(), + Vec2Lua::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("drop_behavior").into(), ItemDropBehavior::get_type_parts(), )); gen.fields.push(( - Cow::Borrowed("deplete_behavior"), + Cow::Borrowed("deplete_behavior").into(), ItemDepleteBehavior::get_type_parts(), )); gen.fields - .push((Cow::Borrowed("is_hat"), bool::get_type_parts())); - gen.fields - .push((Cow::Borrowed("duration_timer"), f32::get_type_parts())); + .push((Cow::Borrowed("is_hat").into(), bool::get_type_parts())); + gen.fields.push(( + Cow::Borrowed("duration_timer").into(), + f32::get_type_parts(), + )); gen.fields - .push((Cow::Borrowed("use_cnt"), u32::get_type_parts())); + .push((Cow::Borrowed("use_cnt").into(), u32::get_type_parts())); } } @@ -256,13 +264,15 @@ impl<'lua> ToLua<'lua> for ItemMetadata { impl TypeBody for ItemMetadata { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields.push(( - Cow::Borrowed("effects"), + Cow::Borrowed("effects").into(), Vec::::get_type_parts(), )); + gen.fields.push(( + Cow::Borrowed("duration").into(), + Option::::get_type_parts(), + )); gen.fields - .push((Cow::Borrowed("duration"), Option::::get_type_parts())); - gen.fields - .push((Cow::Borrowed("is_hat"), bool::get_type_parts())); + .push((Cow::Borrowed("is_hat").into(), bool::get_type_parts())); } } @@ -536,41 +546,51 @@ impl<'lua> ToLua<'lua> for Weapon { impl TypeBody for Weapon { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields - .push((Cow::Borrowed("id"), String::get_type_parts())); + .push((Cow::Borrowed("id").into(), String::get_type_parts())); gen.fields - .push((Cow::Borrowed("name"), String::get_type_parts())); + .push((Cow::Borrowed("name").into(), String::get_type_parts())); gen.fields.push(( - Cow::Borrowed("effects"), + Cow::Borrowed("effects").into(), Vec::::get_type_parts(), )); gen.fields.push(( - Cow::Borrowed("sound_effect"), + Cow::Borrowed("sound_effect").into(), Option::::get_type_parts(), )); gen.fields - .push((Cow::Borrowed("recoil"), f32::get_type_parts())); + .push((Cow::Borrowed("recoil").into(), f32::get_type_parts())); gen.fields - .push((Cow::Borrowed("cooldown"), f32::get_type_parts())); - gen.fields - .push((Cow::Borrowed("attack_duration"), f32::get_type_parts())); - gen.fields - .push((Cow::Borrowed("uses"), Option::::get_type_parts())); - gen.fields - .push((Cow::Borrowed("mount_offset"), Vec2Lua::get_type_parts())); - gen.fields - .push((Cow::Borrowed("effect_offset"), Vec2Lua::get_type_parts())); + .push((Cow::Borrowed("cooldown").into(), f32::get_type_parts())); gen.fields.push(( - Cow::Borrowed("drop_behavior"), + Cow::Borrowed("attack_duration").into(), + f32::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("uses").into(), + Option::::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("mount_offset").into(), + Vec2Lua::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("effect_offset").into(), + Vec2Lua::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("drop_behavior").into(), ItemDropBehavior::get_type_parts(), )); gen.fields.push(( - Cow::Borrowed("deplete_behavior"), + Cow::Borrowed("deplete_behavior").into(), ItemDepleteBehavior::get_type_parts(), )); + gen.fields.push(( + Cow::Borrowed("cooldown_timer").into(), + f32::get_type_parts(), + )); gen.fields - .push((Cow::Borrowed("cooldown_timer"), f32::get_type_parts())); - gen.fields - .push((Cow::Borrowed("use_cnt"), u32::get_type_parts())); + .push((Cow::Borrowed("use_cnt").into(), u32::get_type_parts())); } } @@ -772,29 +792,35 @@ impl<'lua> ToLua<'lua> for WeaponMetadata { impl TypeBody for WeaponMetadata { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields.push(( - Cow::Borrowed("effects"), + Cow::Borrowed("effects").into(), Vec::::get_type_parts(), )); gen.fields.push(( - Cow::Borrowed("particles"), + Cow::Borrowed("particles").into(), Vec::::get_type_parts(), )); gen.fields.push(( - Cow::Borrowed("sound_effect_id"), + Cow::Borrowed("sound_effect_id").into(), Option::::get_type_parts(), )); + gen.fields.push(( + Cow::Borrowed("effect_offset").into(), + Vec2Lua::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("uses").into(), + Option::::get_type_parts(), + )); gen.fields - .push((Cow::Borrowed("effect_offset"), Vec2Lua::get_type_parts())); - gen.fields - .push((Cow::Borrowed("uses"), Option::::get_type_parts())); - gen.fields - .push((Cow::Borrowed("cooldown"), f32::get_type_parts())); - gen.fields - .push((Cow::Borrowed("attack_duration"), f32::get_type_parts())); + .push((Cow::Borrowed("cooldown").into(), f32::get_type_parts())); + gen.fields.push(( + Cow::Borrowed("attack_duration").into(), + f32::get_type_parts(), + )); gen.fields - .push((Cow::Borrowed("recoil"), f32::get_type_parts())); + .push((Cow::Borrowed("recoil").into(), f32::get_type_parts())); gen.fields.push(( - Cow::Borrowed("effect_sprite"), + Cow::Borrowed("effect_sprite").into(), Option::::get_type_parts(), )); } diff --git a/src/particles.rs b/src/particles.rs index 3730f8ee68..9309cc6e69 100644 --- a/src/particles.rs +++ b/src/particles.rs @@ -50,22 +50,28 @@ pub struct ParticleEmitterMetadata { } impl TypeBody for ParticleEmitterMetadata { fn get_type_body(gen: &mut tealr::TypeGenerator) { + gen.fields.push(( + Cow::Borrowed("particle_effect").into(), + String::get_type_parts(), + )); gen.fields - .push((Cow::Borrowed("particle_effect"), String::get_type_parts())); - gen.fields - .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); - gen.fields - .push((Cow::Borrowed("delay"), f32::get_type_parts())); + .push((Cow::Borrowed("offset").into(), Vec2Lua::get_type_parts())); gen.fields - .push((Cow::Borrowed("interval"), f32::get_type_parts())); + .push((Cow::Borrowed("delay").into(), f32::get_type_parts())); gen.fields - .push((Cow::Borrowed("emissions"), Option::::get_type_parts())); + .push((Cow::Borrowed("interval").into(), f32::get_type_parts())); + gen.fields.push(( + Cow::Borrowed("emissions").into(), + Option::::get_type_parts(), + )); gen.fields.push(( - Cow::Borrowed("animations"), + Cow::Borrowed("animations").into(), Option::::get_type_parts(), )); - gen.fields - .push((Cow::Borrowed("should_autostart"), bool::get_type_parts())); + gen.fields.push(( + Cow::Borrowed("should_autostart").into(), + bool::get_type_parts(), + )); } } @@ -148,56 +154,8 @@ impl ParticleEmitter { impl UserData for ParticleEmitter { fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("particle_effect_id", |lua, this| { - this.particle_effect_id.clone().to_lua(lua) - }); - fields.add_field_method_get("offset", |lua, this| Vec2Lua::from(this.offset).to_lua(lua)); - fields.add_field_method_get("delay", |lua, this| this.delay.to_lua(lua)); - fields.add_field_method_get("emissions", |lua, this| this.emissions.to_lua(lua)); - fields.add_field_method_get("interval", |lua, this| this.interval.to_lua(lua)); - fields.add_field_method_get("emission_cnt", |lua, this| this.emission_cnt.to_lua(lua)); - fields.add_field_method_get("delay_timer", |lua, this| this.delay_timer.to_lua(lua)); - fields.add_field_method_get("interval_timer", |lua, this| { - this.interval_timer.to_lua(lua) - }); - fields.add_field_method_get("is_active", |lua, this| this.is_active.to_lua(lua)); - - fields.add_field_method_set("particle_effect_id", |_, this, value| { - this.particle_effect_id = value; - Ok(()) - }); - fields.add_field_method_set("offset", |_, this, value: Vec2Lua| { - this.offset = value.into(); - Ok(()) - }); - fields.add_field_method_set("delay", |_, this, value| { - this.delay = value; - Ok(()) - }); - fields.add_field_method_set("emissions", |_, this, value| { - this.emissions = value; - Ok(()) - }); - fields.add_field_method_set("interval", |_, this, value| { - this.interval = value; - Ok(()) - }); - fields.add_field_method_set("emission_cnt", |_, this, value| { - this.emission_cnt = value; - Ok(()) - }); - fields.add_field_method_set("delay_timer", |_, this, value| { - this.delay_timer = value; - Ok(()) - }); - fields.add_field_method_set("interval_timer", |_, this, value| { - this.interval_timer = value; - Ok(()) - }); - fields.add_field_method_set("is_active", |_, this, value| { - this.is_active = value; - Ok(()) - }); + let mut wrapper = UserDataWrapper::from_user_data_fields(fields); + ::add_fields(&mut wrapper) } fn add_methods<'lua, T: UserDataMethods<'lua, Self>>(methods: &mut T) { @@ -215,27 +173,8 @@ impl UserData for ParticleEmitter { impl TypeBody for ParticleEmitter { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.is_user_data = true; + ::add_fields(gen); ::add_methods(gen); - gen.fields.push(( - Cow::Borrowed("particle_effect_id"), - String::get_type_parts(), - )); - gen.fields - .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); - gen.fields - .push((Cow::Borrowed("delay"), f32::get_type_parts())); - gen.fields - .push((Cow::Borrowed("emissions"), Option::::get_type_parts())); - gen.fields - .push((Cow::Borrowed("interval"), f32::get_type_parts())); - gen.fields - .push((Cow::Borrowed("emission_cnt"), u32::get_type_parts())); - gen.fields - .push((Cow::Borrowed("delay_timer"), f32::get_type_parts())); - gen.fields - .push((Cow::Borrowed("interval_timer"), f32::get_type_parts())); - gen.fields - .push((Cow::Borrowed("is_active"), bool::get_type_parts())); } fn get_type_body_marker(gen: &mut tealr::TypeGenerator) { gen.is_user_data = true; @@ -246,7 +185,7 @@ impl TypeBody for ParticleEmitter { impl TealData for ParticleEmitter { fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { methods.add_method("get_offset", |lua, this, (flip_x, flip_y): (bool, bool)| { - Vec2Lua::from(this.get_offset(flip_x, flip_y)).to_lua(lua) + Ok(Vec2Lua::from(this.get_offset(flip_x, flip_y))) }); methods.add_method_mut("activate", |_, this, ()| { this.activate(); @@ -259,6 +198,56 @@ impl TealData for ParticleEmitter { { methods.add_function("new", |_, meta| Ok(ParticleEmitter::new(meta))) } + fn add_fields<'lua, F: tealr::mlu::TealDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("particle_effect_id", |lua, this| { + Ok(this.particle_effect_id.clone()) + }); + fields.add_field_method_get("offset", |lua, this| Ok(Vec2Lua::from(this.offset))); + fields.add_field_method_get("delay", |lua, this| Ok(this.delay)); + fields.add_field_method_get("emissions", |lua, this| Ok(this.emissions)); + fields.add_field_method_get("interval", |lua, this| Ok(this.interval)); + fields.add_field_method_get("emission_cnt", |lua, this| Ok(this.emission_cnt)); + fields.add_field_method_get("delay_timer", |lua, this| Ok(this.delay_timer)); + fields.add_field_method_get("interval_timer", |lua, this| Ok(this.interval_timer)); + fields.add_field_method_get("is_active", |lua, this| Ok(this.is_active)); + + fields.add_field_method_set("particle_effect_id", |_, this, value| { + this.particle_effect_id = value; + Ok(()) + }); + fields.add_field_method_set("offset", |_, this, value: Vec2Lua| { + this.offset = value.into(); + Ok(()) + }); + fields.add_field_method_set("delay", |_, this, value| { + this.delay = value; + Ok(()) + }); + fields.add_field_method_set("emissions", |_, this, value| { + this.emissions = value; + Ok(()) + }); + fields.add_field_method_set("interval", |_, this, value| { + this.interval = value; + Ok(()) + }); + fields.add_field_method_set("emission_cnt", |_, this, value| { + this.emission_cnt = value; + Ok(()) + }); + fields.add_field_method_set("delay_timer", |_, this, value| { + this.delay_timer = value; + Ok(()) + }); + fields.add_field_method_set("interval_timer", |_, this, value| { + this.interval_timer = value; + Ok(()) + }); + fields.add_field_method_set("is_active", |_, this, value| { + this.is_active = value; + Ok(()) + }); + } } impl From for ParticleEmitter { diff --git a/src/physics.rs b/src/physics.rs index b8663a96bf..f53e69b86a 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -128,19 +128,19 @@ impl<'lua> ToLua<'lua> for PhysicsBodyParams { impl TypeBody for PhysicsBodyParams { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields - .push((Cow::Borrowed("size"), Vec2Lua::get_type_parts())); + .push((Cow::Borrowed("size").into(), Vec2Lua::get_type_parts())); gen.fields - .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); + .push((Cow::Borrowed("offset").into(), Vec2Lua::get_type_parts())); gen.fields - .push((Cow::Borrowed("has_mass"), bool::get_type_parts())); + .push((Cow::Borrowed("has_mass").into(), bool::get_type_parts())); gen.fields - .push((Cow::Borrowed("has_friction"), bool::get_type_parts())); + .push((Cow::Borrowed("has_friction").into(), bool::get_type_parts())); gen.fields - .push((Cow::Borrowed("can_rotate"), bool::get_type_parts())); + .push((Cow::Borrowed("can_rotate").into(), bool::get_type_parts())); gen.fields - .push((Cow::Borrowed("bouncyness"), f32::get_type_parts())); + .push((Cow::Borrowed("bouncyness").into(), f32::get_type_parts())); gen.fields - .push((Cow::Borrowed("gravity"), f32::get_type_parts())); + .push((Cow::Borrowed("gravity").into(), f32::get_type_parts())); } } @@ -197,31 +197,37 @@ impl<'lua> FromLua<'lua> for PhysicsBody { impl TypeBody for PhysicsBody { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields - .push((Cow::Borrowed("actor"), ActorLua::get_type_parts())); + .push((Cow::Borrowed("actor").into(), ActorLua::get_type_parts())); gen.fields - .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); + .push((Cow::Borrowed("offset").into(), Vec2Lua::get_type_parts())); gen.fields - .push((Cow::Borrowed("size"), Vec2Lua::get_type_parts())); + .push((Cow::Borrowed("size").into(), Vec2Lua::get_type_parts())); gen.fields - .push((Cow::Borrowed("velocity"), Vec2Lua::get_type_parts())); + .push((Cow::Borrowed("velocity").into(), Vec2Lua::get_type_parts())); gen.fields - .push((Cow::Borrowed("is_on_ground"), bool::get_type_parts())); + .push((Cow::Borrowed("is_on_ground").into(), bool::get_type_parts())); + gen.fields.push(( + Cow::Borrowed("was_on_ground").into(), + bool::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("is_on_platform").into(), + bool::get_type_parts(), + )); gen.fields - .push((Cow::Borrowed("was_on_ground"), bool::get_type_parts())); + .push((Cow::Borrowed("has_mass").into(), bool::get_type_parts())); gen.fields - .push((Cow::Borrowed("is_on_platform"), bool::get_type_parts())); + .push((Cow::Borrowed("has_friction").into(), bool::get_type_parts())); gen.fields - .push((Cow::Borrowed("has_mass"), bool::get_type_parts())); + .push((Cow::Borrowed("can_rotate").into(), bool::get_type_parts())); gen.fields - .push((Cow::Borrowed("has_friction"), bool::get_type_parts())); + .push((Cow::Borrowed("bouncyness").into(), f32::get_type_parts())); + gen.fields.push(( + Cow::Borrowed("is_deactivated").into(), + bool::get_type_parts(), + )); gen.fields - .push((Cow::Borrowed("can_rotate"), bool::get_type_parts())); - gen.fields - .push((Cow::Borrowed("bouncyness"), f32::get_type_parts())); - gen.fields - .push((Cow::Borrowed("is_deactivated"), bool::get_type_parts())); - gen.fields - .push((Cow::Borrowed("gravity"), f32::get_type_parts())); + .push((Cow::Borrowed("gravity").into(), f32::get_type_parts())); } } impl<'lua> ToLua<'lua> for PhysicsBody { @@ -380,11 +386,11 @@ impl Default for RigidBodyParams { impl TypeBody for RigidBodyParams { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields - .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); + .push((Cow::Borrowed("offset").into(), Vec2Lua::get_type_parts())); gen.fields - .push((Cow::Borrowed("size"), Vec2Lua::get_type_parts())); + .push((Cow::Borrowed("size").into(), Vec2Lua::get_type_parts())); gen.fields - .push((Cow::Borrowed("can_rotate"), bool::get_type_parts())); + .push((Cow::Borrowed("can_rotate").into(), bool::get_type_parts())); } } @@ -424,13 +430,13 @@ impl<'lua> ToLua<'lua> for RigidBody { impl TypeBody for RigidBody { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields - .push((Cow::Borrowed("offset"), Vec2Lua::get_type_parts())); + .push((Cow::Borrowed("offset").into(), Vec2Lua::get_type_parts())); gen.fields - .push((Cow::Borrowed("size"), Vec2Lua::get_type_parts())); + .push((Cow::Borrowed("size").into(), Vec2Lua::get_type_parts())); gen.fields - .push((Cow::Borrowed("velocity"), Vec2Lua::get_type_parts())); + .push((Cow::Borrowed("velocity").into(), Vec2Lua::get_type_parts())); gen.fields - .push((Cow::Borrowed("can_rotate"), bool::get_type_parts())); + .push((Cow::Borrowed("can_rotate").into(), bool::get_type_parts())); } } diff --git a/src/player/inventory.rs b/src/player/inventory.rs index e45a83b7b0..006acb6644 100644 --- a/src/player/inventory.rs +++ b/src/player/inventory.rs @@ -71,28 +71,40 @@ impl<'lua> ToLua<'lua> for PlayerInventory { impl TypeBody for PlayerInventory { fn get_type_body(gen: &mut tealr::TypeGenerator) { - gen.fields - .push((Cow::Borrowed("weapon_mount"), Vec2Lua::get_type_parts())); gen.fields.push(( - Cow::Borrowed("weapon_mount_offset"), + Cow::Borrowed("weapon_mount").into(), Vec2Lua::get_type_parts(), )); - gen.fields - .push((Cow::Borrowed("item_mount"), Vec2Lua::get_type_parts())); gen.fields.push(( - Cow::Borrowed("item_mount_offset"), + Cow::Borrowed("weapon_mount_offset").into(), + Vec2Lua::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("item_mount").into(), + Vec2Lua::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("item_mount_offset").into(), Vec2Lua::get_type_parts(), )); gen.fields - .push((Cow::Borrowed("hat_mount"), Vec2Lua::get_type_parts())); - gen.fields - .push((Cow::Borrowed("hat_mount_offset"), Vec2Lua::get_type_parts())); - gen.fields - .push((Cow::Borrowed("weapon"), Option::::get_type_parts())); - gen.fields - .push((Cow::Borrowed("items"), Vec::::get_type_parts())); - gen.fields - .push((Cow::Borrowed("hat"), Option::::get_type_parts())); + .push((Cow::Borrowed("hat_mount").into(), Vec2Lua::get_type_parts())); + gen.fields.push(( + Cow::Borrowed("hat_mount_offset").into(), + Vec2Lua::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("weapon").into(), + Option::::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("items").into(), + Vec::::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("hat").into(), + Option::::get_type_parts(), + )); } } diff --git a/src/player/mod.rs b/src/player/mod.rs index 6272b4f693..cdeb99db5e 100644 --- a/src/player/mod.rs +++ b/src/player/mod.rs @@ -121,31 +121,45 @@ impl<'lua> ToLua<'lua> for Player { impl TypeBody for Player { fn get_type_body(gen: &mut tealr::TypeGenerator) { gen.fields - .push((Cow::Borrowed("index"), u8::get_type_parts())); + .push((Cow::Borrowed("index").into(), u8::get_type_parts())); gen.fields - .push((Cow::Borrowed("state"), PlayerState::get_type_parts())); - gen.fields - .push((Cow::Borrowed("damage_from_left"), bool::get_type_parts())); - gen.fields - .push((Cow::Borrowed("is_facing_left"), bool::get_type_parts())); - gen.fields - .push((Cow::Borrowed("is_upside_down"), bool::get_type_parts())); - gen.fields - .push((Cow::Borrowed("is_attacking"), bool::get_type_parts())); - gen.fields - .push((Cow::Borrowed("jump_frame_counter"), u16::get_type_parts())); - gen.fields - .push((Cow::Borrowed("pickup_grace_timer"), f32::get_type_parts())); - gen.fields - .push((Cow::Borrowed("incapacitation_timer"), f32::get_type_parts())); + .push((Cow::Borrowed("state").into(), PlayerState::get_type_parts())); + gen.fields.push(( + Cow::Borrowed("damage_from_left").into(), + bool::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("is_facing_left").into(), + bool::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("is_upside_down").into(), + bool::get_type_parts(), + )); gen.fields - .push((Cow::Borrowed("attack_timer"), f32::get_type_parts())); + .push((Cow::Borrowed("is_attacking").into(), bool::get_type_parts())); + gen.fields.push(( + Cow::Borrowed("jump_frame_counter").into(), + u16::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("pickup_grace_timer").into(), + f32::get_type_parts(), + )); + gen.fields.push(( + Cow::Borrowed("incapacitation_timer").into(), + f32::get_type_parts(), + )); gen.fields - .push((Cow::Borrowed("respawn_timer"), f32::get_type_parts())); + .push((Cow::Borrowed("attack_timer").into(), f32::get_type_parts())); gen.fields - .push((Cow::Borrowed("camera_box"), RectLua::get_type_parts())); + .push((Cow::Borrowed("respawn_timer").into(), f32::get_type_parts())); + gen.fields.push(( + Cow::Borrowed("camera_box").into(), + RectLua::get_type_parts(), + )); gen.fields.push(( - Cow::Borrowed("passive_effects"), + Cow::Borrowed("passive_effects").into(), Vec::::get_type_parts(), )); }