├── .gitignore ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── crates ├── cargo-quill │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── quill-common │ ├── Cargo.toml │ └── src │ │ ├── block.rs │ │ ├── component.rs │ │ ├── components.rs │ │ ├── entities.rs │ │ ├── entities │ │ ├── area_effect_cloud.rs │ │ ├── armor_stand.rs │ │ ├── arrow.rs │ │ ├── bat.rs │ │ ├── bee.rs │ │ ├── blaze.rs │ │ ├── boat.rs │ │ ├── cat.rs │ │ ├── cave_spider.rs │ │ ├── chest_minecart.rs │ │ ├── chicken.rs │ │ ├── cod.rs │ │ ├── command_block_minecart.rs │ │ ├── cow.rs │ │ ├── creeper.rs │ │ ├── dolphin.rs │ │ ├── donkey.rs │ │ ├── dragon_fireball.rs │ │ ├── drowned.rs │ │ ├── egg.rs │ │ ├── elder_guardian.rs │ │ ├── end_crystal.rs │ │ ├── ender_dragon.rs │ │ ├── ender_pearl.rs │ │ ├── enderman.rs │ │ ├── endermite.rs │ │ ├── evoker.rs │ │ ├── evoker_fangs.rs │ │ ├── experience_bottle.rs │ │ ├── experience_orb.rs │ │ ├── eye_of_ender.rs │ │ ├── falling_block.rs │ │ ├── fireball.rs │ │ ├── firework_rocket.rs │ │ ├── fishing_bobber.rs │ │ ├── fox.rs │ │ ├── furnace_minecart.rs │ │ ├── ghast.rs │ │ ├── giant.rs │ │ ├── guardian.rs │ │ ├── hoglin.rs │ │ ├── hopper_minecart.rs │ │ ├── horse.rs │ │ ├── husk.rs │ │ ├── illusioner.rs │ │ ├── iron_golem.rs │ │ ├── item.rs │ │ ├── item_frame.rs │ │ ├── leash_knot.rs │ │ ├── lightning_bolt.rs │ │ ├── llama.rs │ │ ├── llama_spit.rs │ │ ├── magma_cube.rs │ │ ├── minecart.rs │ │ ├── mooshroom.rs │ │ ├── mule.rs │ │ ├── ocelot.rs │ │ ├── painting.rs │ │ ├── panda.rs │ │ ├── parrot.rs │ │ ├── phantom.rs │ │ ├── pig.rs │ │ ├── piglin.rs │ │ ├── piglin_brute.rs │ │ ├── pillager.rs │ │ ├── player.rs │ │ ├── polar_bear.rs │ │ ├── potion.rs │ │ ├── pufferfish.rs │ │ ├── rabbit.rs │ │ ├── ravager.rs │ │ ├── salmon.rs │ │ ├── sheep.rs │ │ ├── shulker.rs │ │ ├── shulker_bullet.rs │ │ ├── silverfish.rs │ │ ├── skeleton.rs │ │ ├── skeleton_horse.rs │ │ ├── slime.rs │ │ ├── small_fireball.rs │ │ ├── snow_golem.rs │ │ ├── snowball.rs │ │ ├── spawner_minecart.rs │ │ ├── spectral_arrow.rs │ │ ├── spider.rs │ │ ├── squid.rs │ │ ├── stray.rs │ │ ├── strider.rs │ │ ├── tnt.rs │ │ ├── tnt_minecart.rs │ │ ├── trader_llama.rs │ │ ├── trident.rs │ │ ├── tropical_fish.rs │ │ ├── turtle.rs │ │ ├── vex.rs │ │ ├── villager.rs │ │ ├── vindicator.rs │ │ ├── wandering_trader.rs │ │ ├── witch.rs │ │ ├── wither.rs │ │ ├── wither_skeleton.rs │ │ ├── wither_skull.rs │ │ ├── wolf.rs │ │ ├── zoglin.rs │ │ ├── zombie.rs │ │ ├── zombie_horse.rs │ │ ├── zombie_villager.rs │ │ └── zombified_piglin.rs │ │ ├── entity.rs │ │ ├── entity_init.rs │ │ ├── events.rs │ │ ├── events │ │ ├── block_interact.rs │ │ └── interact_entity.rs │ │ ├── lib.rs │ │ └── utils.rs ├── quill-plugin-format │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ └── metadata.rs ├── quill-sys-macros │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── quill-sys │ ├── Cargo.toml │ └── src │ │ └── lib.rs └── quill │ ├── Cargo.toml │ └── src │ ├── entities.rs │ ├── entity.rs │ ├── entity_builder.rs │ ├── game.rs │ ├── lib.rs │ ├── query.rs │ └── setup.rs ├── docs └── components.md └── example-plugins ├── block-access ├── Cargo.toml └── src │ └── lib.rs ├── block-place ├── Cargo.toml └── src │ └── lib.rs ├── particle-example ├── Cargo.toml └── src │ └── lib.rs ├── query-entities ├── Cargo.toml └── src │ └── lib.rs └── simple ├── Cargo.toml └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | 4 | .DS_Store -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "crates/quill-common", 4 | "crates/quill-sys-macros", 5 | "crates/quill-sys", 6 | "crates/quill", 7 | "crates/quill-plugin-format", 8 | "crates/cargo-quill", 9 | 10 | "example-plugins/simple", 11 | "example-plugins/query-entities", 12 | "example-plugins/block-access", 13 | "example-plugins/particle-example", 14 | "example-plugins/block-place" 15 | ] 16 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright 2019 Caelum van Ispelen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # quill 2 | 3 | **Notice**: Quill has been moved into the [main Feather repository](https://github.com/feather-rs/feather). Issues and PRs should be made there instead. 4 | 5 | [![Discord](https://img.shields.io/discord/619316022800809995)](https://discordapp.com/invite/4eYmK69) 6 | 7 | A WebAssembly-based plugin API for Minecraft servers. Currently in development. 8 | 9 | Plugins written for [Feather](https://github.com/feather-rs/feather) servers use `quill`. 10 | 11 | ## For Feather developers 12 | See [`docs`](./docs) for information on Quill internals. 13 | -------------------------------------------------------------------------------- /crates/cargo-quill/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cargo-quill" 3 | version = "0.1.0" 4 | authors = ["caelunshun "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | quill-plugin-format = { path = "../quill-plugin-format" } 9 | cargo_metadata = "0.12" 10 | anyhow = "1" 11 | argh = "0.1" 12 | heck = "0.3" 13 | -------------------------------------------------------------------------------- /crates/cargo-quill/src/main.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{bail, Context}; 2 | use argh::FromArgs; 3 | use cargo_metadata::Metadata; 4 | use heck::CamelCase; 5 | use quill_plugin_format::{PluginFile, PluginMetadata, PluginTarget, Triple}; 6 | use std::{ 7 | fs, 8 | path::PathBuf, 9 | process::{Command, Stdio}, 10 | }; 11 | 12 | const WASM_TARGET_FEATURES: &str = "target-feature=+bulk-memory,+mutable-globals,+simd128"; 13 | const WASM_TARGET: &str = "wasm32-wasi"; 14 | 15 | #[derive(Debug, FromArgs)] 16 | /// Cargo subcommand to build and test Quill/Feather plugins. 17 | struct CargoQuill { 18 | #[argh(subcommand)] 19 | subcommand: Subcommand, 20 | } 21 | 22 | #[derive(Debug, FromArgs)] 23 | #[argh(subcommand)] 24 | enum Subcommand { 25 | Build(Build), 26 | } 27 | 28 | #[derive(Debug, FromArgs)] 29 | #[argh(subcommand, name = "build")] 30 | /// Build a Quill plugin. 31 | struct Build { 32 | #[argh(switch)] 33 | /// whether to build in release mode 34 | release: bool, 35 | #[argh(switch)] 36 | /// whether to compile to a native shared library 37 | /// instead of a WebAssembly module 38 | native: bool, 39 | #[argh(option, default = "6")] 40 | /// the compression level to compress the plugin 41 | /// binary. 0 is worst and 9 is best. 42 | compression_level: u32, 43 | } 44 | 45 | impl Build { 46 | pub fn module_extension(&self) -> &'static str { 47 | if !self.native { 48 | "wasm" 49 | } else if cfg!(windows) { 50 | "dll" 51 | } else if cfg!(target_vendor = "apple") { 52 | "dylib" 53 | } else { 54 | // assume Linux / other Unix 55 | "so" 56 | } 57 | } 58 | 59 | pub fn target_dir(&self, cargo_meta: &Metadata) -> PathBuf { 60 | let mut target_dir = cargo_meta.target_directory.clone(); 61 | if !self.native { 62 | target_dir.push(WASM_TARGET); 63 | } 64 | 65 | if self.release { 66 | target_dir.push("release"); 67 | } else { 68 | target_dir.push("debug"); 69 | } 70 | 71 | target_dir 72 | } 73 | 74 | pub fn module_path(&self, cargo_meta: &Metadata, plugin_meta: &PluginMetadata) -> PathBuf { 75 | let target_dir = self.target_dir(&cargo_meta); 76 | let module_filename = plugin_meta.identifier.replace("-", "_"); 77 | 78 | let module_extension = self.module_extension(); 79 | let lib_prefix = if self.native && cfg!(unix) { "lib" } else { "" }; 80 | 81 | target_dir.join(format!( 82 | "{}{}.{}", 83 | lib_prefix, module_filename, module_extension 84 | )) 85 | } 86 | } 87 | 88 | fn main() -> anyhow::Result<()> { 89 | let args: CargoQuill = argh::from_env(); 90 | match args.subcommand { 91 | Subcommand::Build(args) => build(args), 92 | } 93 | } 94 | 95 | fn build(args: Build) -> anyhow::Result<()> { 96 | let cargo_meta = get_cargo_metadata()?; 97 | validate_cargo_metadata(&cargo_meta)?; 98 | 99 | let mut command = cargo_build_command(&args); 100 | let status = command.spawn()?.wait()?; 101 | if !status.success() { 102 | bail!("build failed"); 103 | } 104 | 105 | let meta = find_metadata(&cargo_meta, &args)?; 106 | let module_path = args.module_path(&cargo_meta, &meta); 107 | let module = fs::read(&module_path) 108 | .with_context(|| format!("failed to read {}", module_path.display()))?; 109 | 110 | let file = PluginFile::new(module, meta.clone()); 111 | let target_path = module_path 112 | .parent() 113 | .unwrap() 114 | .join(format!("{}.plugin", meta.identifier)); 115 | fs::write(&target_path, file.encode(args.compression_level))?; 116 | 117 | println!("Wrote plugin file to {}", target_path.display()); 118 | Ok(()) 119 | } 120 | 121 | fn cargo_build_command(args: &Build) -> Command { 122 | let mut cmd = Command::new("cargo"); 123 | cmd.arg("rustc"); 124 | if args.release { 125 | cmd.arg("--release"); 126 | } 127 | 128 | if !args.native { 129 | cmd.args(&["--target", WASM_TARGET]); 130 | cmd.args(&["--", "-C", WASM_TARGET_FEATURES]); 131 | } 132 | 133 | cmd.stdout(Stdio::piped()); 134 | 135 | cmd 136 | } 137 | 138 | fn get_cargo_metadata() -> anyhow::Result { 139 | let cmd = cargo_metadata::MetadataCommand::new(); 140 | let cargo_meta = cmd.exec()?; 141 | Ok(cargo_meta) 142 | } 143 | 144 | fn validate_cargo_metadata(cargo_meta: &Metadata) -> anyhow::Result<()> { 145 | let package = cargo_meta.root_package().context("missing root package")?; 146 | if !package 147 | .targets 148 | .iter() 149 | .any(|t| t.crate_types.contains(&"cdylib".to_owned())) 150 | { 151 | bail!("crate-type = [\"cdylib\"] must be set in the plugin Cargo.toml"); 152 | } 153 | 154 | Ok(()) 155 | } 156 | 157 | fn find_metadata(cargo_meta: &Metadata, args: &Build) -> anyhow::Result { 158 | let package = cargo_meta.root_package().context("missing root package")?; 159 | 160 | let quill_dependency = package 161 | .dependencies 162 | .iter() 163 | .find(|d| d.name == "quill") 164 | .context("plugin does not depend on the `quill` crate")?; 165 | 166 | let target = if args.native { 167 | PluginTarget::Native { 168 | target_triple: Triple::host(), 169 | } 170 | } else { 171 | PluginTarget::Wasm 172 | }; 173 | 174 | let plugin_meta = PluginMetadata { 175 | name: package.name.to_camel_case(), 176 | identifier: package.name.clone(), 177 | version: package.version.to_string(), 178 | api_version: quill_dependency.req.to_string(), 179 | description: package.description.clone(), 180 | authors: package.authors.clone(), 181 | target, 182 | }; 183 | 184 | Ok(plugin_meta) 185 | } 186 | -------------------------------------------------------------------------------- /crates/quill-common/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "quill-common" 3 | version = "0.1.0" 4 | authors = ["caelunshun "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | bincode = "1" 9 | bytemuck = { version = "1", features = ["derive"] } 10 | libcraft-core = { git = "https://github.com/feather-rs/libcraft", rev = "0b49cd0" } 11 | libcraft-particles = { git = "https://github.com/feather-rs/libcraft", rev = "0b49cd0" } 12 | serde = { version = "1", features = ["derive"] } 13 | smartstring = { version = "0.2", features = ["serde"] } 14 | uuid = { version = "0.8", features = ["serde"] } 15 | 16 | [dev-dependencies] 17 | quill = { path = "../quill" } 18 | -------------------------------------------------------------------------------- /crates/quill-common/src/block.rs: -------------------------------------------------------------------------------- 1 | /// Returned from `block_get`. 2 | /// 3 | /// This is an FFI-safe representation of `Option`. 4 | #[repr(transparent)] 5 | pub struct BlockGetResult(u32); 6 | 7 | impl BlockGetResult { 8 | pub fn new(block_id: Option) -> Self { 9 | let tag = block_id.is_some() as u32; 10 | let value = (tag << 16) | block_id.unwrap_or_default() as u32; 11 | Self(value) 12 | } 13 | 14 | /// Gets the ID of the block. 15 | pub fn get(self) -> Option { 16 | if self.0 >> 16 == 0 { 17 | None 18 | } else { 19 | Some(self.0 as u16) 20 | } 21 | } 22 | 23 | pub fn to_u32(self) -> u32 { 24 | self.0 25 | } 26 | } 27 | 28 | #[cfg(test)] 29 | mod tests { 30 | use super::*; 31 | 32 | #[test] 33 | fn block_get_result_some() { 34 | let result = BlockGetResult::new(Some(311)); 35 | assert_eq!(result.get(), Some(311)); 36 | } 37 | 38 | #[test] 39 | fn block_get_result_some_all_bits_set() { 40 | let result = BlockGetResult::new(Some(u16::MAX)); 41 | assert_eq!(result.get(), Some(u16::MAX)); 42 | } 43 | 44 | #[test] 45 | fn block_get_result_none() { 46 | let result = BlockGetResult::new(None); 47 | assert_eq!(result.get(), None); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /crates/quill-common/src/component.rs: -------------------------------------------------------------------------------- 1 | //! Defines the components available to Quill plugins. 2 | 3 | use std::{any::TypeId, borrow::Cow as CloneOnWrite}; 4 | 5 | use libcraft_core::{Gamemode, Position}; 6 | use libcraft_particles::Particle; 7 | use uuid::Uuid; 8 | 9 | use crate::components::*; 10 | use crate::entities::*; 11 | use crate::events::*; 12 | 13 | /// Used to convert dynamic `HostComponent`s to 14 | /// statically-typed generic `T`s. 15 | /// 16 | /// Use with [`HostComponent::visit`]. 17 | pub trait ComponentVisitor { 18 | fn visit(self) -> R; 19 | } 20 | 21 | /// Generates the [`HostComponent`] enum. 22 | /// 23 | /// Adds a method `type_id` that returns the TypeId 24 | /// of the component's type. This is used on the 25 | /// host to construct queries. 26 | macro_rules! host_component_enum { 27 | ( 28 | $(#[$outer:meta])* 29 | pub enum $ident:ident { 30 | $( 31 | $component:ident = $x:literal 32 | ),* $(,)? 33 | } 34 | ) => { 35 | c_enum! { 36 | $(#[$outer])* 37 | pub enum $ident { 38 | $($component = $x,)* 39 | } 40 | } 41 | 42 | impl $ident { 43 | pub fn type_id(self) -> TypeId { 44 | match self { 45 | $(Self::$component => TypeId::of::<$component>(),)* 46 | } 47 | } 48 | 49 | /// Invokes a `ComponentVisitor`'s `visit` 50 | /// method where the type `T` is the type of this component. 51 | pub fn visit(self, visitor: impl ComponentVisitor) -> R { 52 | match self { 53 | $(Self::$component => visitor.visit::<$component>(),)* 54 | } 55 | } 56 | } 57 | } 58 | } 59 | 60 | host_component_enum! { 61 | /// A component that is stored on the host 62 | /// and accessible from plugins. 63 | pub enum HostComponent { 64 | // `Pod` components 65 | Position = 0, 66 | 67 | // Entity marker components 68 | AreaEffectCloud = 100, 69 | ArmorStand = 101, 70 | Arrow = 102, 71 | Bat = 103, 72 | Bee = 104, 73 | Blaze = 105, 74 | Boat = 106, 75 | Cat = 107, 76 | CaveSpider = 108, 77 | Chicken = 109, 78 | Cod = 110, 79 | Cow = 111, 80 | Creeper = 112, 81 | Dolphin = 113, 82 | Donkey = 114, 83 | DragonFireball = 115, 84 | Drowned = 116, 85 | ElderGuardian = 117, 86 | EndCrystal = 118, 87 | EnderDragon = 119, 88 | Enderman = 120, 89 | Endermite = 121, 90 | Evoker = 122, 91 | EvokerFangs = 123, 92 | ExperienceOrb = 124, 93 | EyeOfEnder = 125, 94 | FallingBlock = 126, 95 | FireworkRocket = 127, 96 | Fox = 128, 97 | Ghast = 129, 98 | Giant = 130, 99 | Guardian = 131, 100 | Hoglin = 132, 101 | Horse = 133, 102 | Husk = 134, 103 | Illusioner = 135, 104 | IronGolem = 136, 105 | Item = 137, 106 | ItemFrame = 138, 107 | Fireball = 139, 108 | LeashKnot = 140, 109 | LightningBolt = 141, 110 | Llama = 142, 111 | LlamaSpit = 143, 112 | MagmaCube = 144, 113 | Minecart = 145, 114 | ChestMinecart = 146, 115 | CommandBlockMinecart = 147, 116 | FurnaceMinecart = 148, 117 | HopperMinecart = 149, 118 | SpawnerMinecart = 150, 119 | TntMinecart = 151, 120 | Mule = 152, 121 | Mooshroom = 153, 122 | Ocelot = 154, 123 | Painting = 155, 124 | Panda = 156, 125 | Parrot = 157, 126 | Phantom = 158, 127 | Pig = 159, 128 | Piglin = 160, 129 | Pillager = 161, 130 | PolarBear = 162, 131 | Tnt = 163, 132 | Pufferfish = 164, 133 | Rabbit = 165, 134 | Ravager = 166, 135 | Salmon = 167, 136 | Sheep = 168, 137 | Shulker = 169, 138 | ShulkerBullet = 170, 139 | Silverfish = 171, 140 | Skeleton = 172, 141 | SkeletonHorse = 173, 142 | Slime = 174, 143 | SmallFireball = 175, 144 | SnowGolem = 176, 145 | Snowball = 177, 146 | SpectralArrow = 178, 147 | Spider = 179, 148 | Squid = 180, 149 | Stray = 181, 150 | Strider = 182, 151 | Egg = 183, 152 | EnderPearl = 184, 153 | ExperienceBottle = 185, 154 | Potion = 186, 155 | Trident = 187, 156 | TraderLlama = 188, 157 | TropicalFish = 189, 158 | Turtle = 190, 159 | Vex = 191, 160 | Villager = 192, 161 | Vindicator = 193, 162 | WanderingTrader = 194, 163 | Witch = 195, 164 | Wither = 196, 165 | WitherSkeleton = 197, 166 | WitherSkull = 198, 167 | Wolf = 199, 168 | Zoglin = 200, 169 | Zombie = 201, 170 | ZombieHorse = 202, 171 | ZombieVillager = 203, 172 | ZombifiedPiglin = 204, 173 | Player = 205, 174 | FishingBobber = 206, 175 | PiglinBrute = 207, 176 | 177 | // `bincode` components 178 | Gamemode = 1000, 179 | Uuid = 1001, 180 | OnGround = 1002, 181 | Name = 1003, 182 | CustomName = 1004, 183 | Particle = 1005, 184 | InteractEntityEvent = 1006, 185 | BlockPlacementEvent = 1007, 186 | BlockInteractEvent = 1008 187 | } 188 | } 189 | 190 | /// How a component will be serialized. 191 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 192 | pub enum SerializationMethod { 193 | /// Copy raw bytes with `bytemuck`. 194 | Bytemuck, 195 | /// Serialize into a `Vec` with `bincode. 196 | Bincode, 197 | } 198 | 199 | /// A type that can be used as a component. 200 | /// 201 | /// # Safety 202 | /// `from_bytes` must return `Some(_)` if given 203 | /// any byte slice returned by `to_bytes`. A violation 204 | /// if this contract may result in undefined behavior 205 | /// on the plugin side. 206 | pub unsafe trait Component: Send + Sync + Sized + 'static { 207 | /// How this component will be serialized. 208 | const SERIALIZATION_METHOD: SerializationMethod; 209 | 210 | /// Returns the [`HostComponent`] corresponding to this 211 | /// component. 212 | /// 213 | /// # Contract 214 | /// A sound implementation of this method _must_ 215 | /// return the `HostComponent` corresponding to 216 | /// this type. 217 | fn host_component() -> HostComponent; 218 | 219 | /// Serializes this component to bytes suitable 220 | /// for deserialization by `from_bytes`. 221 | /// 222 | /// Should panic if `Self::SERIALIZATION_METHOD == SerializationMethod::Bytemuck`. 223 | fn to_bytes(&self, target: &mut Vec); 224 | 225 | /// Gets this component as a byte slice. 226 | /// 227 | /// Should panic if `Self::SERIALIZATION_METHOD != SerializationMethod::Bytemuck`. 228 | fn as_bytes(&self) -> &[u8]; 229 | 230 | /// Deserializes this component from bytes 231 | /// returned by [`to_bytes`]. 232 | /// 233 | /// Returns the number of bytes used to deserialize 234 | /// `self`. `bytes` may have a greater length than is needed. 235 | /// 236 | /// # Contract 237 | /// A sound implementation of this method _must_ 238 | /// return `Some(_)` for all values of `bytes` 239 | /// that can be returned by `Self::to_bytes`. 240 | fn from_bytes(bytes: &[u8]) -> Option<(Self, usize)>; 241 | 242 | /// Deserializes this component from bytes returned by [`to_bytes`] 243 | /// without validating correctness. 244 | /// 245 | /// The default implementation of this method calls [`Self::from_bytes`] 246 | /// and then performs an unchecked unwrap. 247 | /// 248 | /// # Safety 249 | /// Behavior is undefined if `bytes` was not previously 250 | /// returned from a call to `Self::to_bytes`. 251 | unsafe fn from_bytes_unchecked(bytes: &[u8]) -> (Self, usize) { 252 | // Do an unchecked unwrap of `from_bytes`. 253 | // This should cause the optimizer to 254 | // remove safety checks in `bincode`, 255 | // which may improve performance on the plugin side. 256 | match Self::from_bytes(bytes) { 257 | Some(this) => this, 258 | None => std::hint::unreachable_unchecked(), 259 | } 260 | } 261 | 262 | /// Serializes `self` into bytes using 263 | /// the appropriate `SerializationMethod`. 264 | fn to_cow_bytes(&self) -> CloneOnWrite<[u8]> { 265 | match Self::SERIALIZATION_METHOD { 266 | SerializationMethod::Bytemuck => CloneOnWrite::Borrowed(self.as_bytes()), 267 | SerializationMethod::Bincode => { 268 | let mut buffer = Vec::new(); 269 | self.to_bytes(&mut buffer); 270 | CloneOnWrite::Owned(buffer) 271 | } 272 | } 273 | } 274 | } 275 | 276 | macro_rules! pod_component_impl { 277 | ($type:ident) => { 278 | unsafe impl crate::component::Component for $type { 279 | const SERIALIZATION_METHOD: crate::component::SerializationMethod = 280 | crate::component::SerializationMethod::Bytemuck; 281 | 282 | fn host_component() -> crate::component::HostComponent { 283 | crate::component::HostComponent::$type 284 | } 285 | 286 | fn to_bytes(&self, _target: &mut Vec) { 287 | unreachable!() 288 | } 289 | 290 | fn as_bytes(&self) -> &[u8] { 291 | bytemuck::cast_slice(std::slice::from_ref(self)) 292 | } 293 | 294 | fn from_bytes(bytes: &[u8]) -> Option<(Self, usize)> { 295 | let this = bytemuck::try_from_bytes(&bytes[..std::mem::size_of::()]) 296 | .ok() 297 | .copied()?; 298 | Some((this, std::mem::size_of::())) 299 | } 300 | } 301 | }; 302 | } 303 | 304 | pod_component_impl!(Position); 305 | 306 | macro_rules! bincode_component_impl { 307 | ($type:ident) => { 308 | unsafe impl crate::Component for $type { 309 | const SERIALIZATION_METHOD: crate::component::SerializationMethod = 310 | crate::component::SerializationMethod::Bincode; 311 | 312 | fn host_component() -> crate::component::HostComponent { 313 | crate::component::HostComponent::$type 314 | } 315 | 316 | fn to_bytes(&self, target: &mut Vec) { 317 | bincode::serialize_into(target, self).expect("failed to serialize component"); 318 | } 319 | 320 | fn as_bytes(&self) -> &[u8] { 321 | unreachable!() 322 | } 323 | 324 | fn from_bytes(bytes: &[u8]) -> Option<(Self, usize)> { 325 | let mut cursor = std::io::Cursor::new(bytes); 326 | let this = bincode::deserialize_from(&mut cursor).ok()?; 327 | Some((this, cursor.position() as usize)) 328 | } 329 | } 330 | }; 331 | } 332 | 333 | bincode_component_impl!(Gamemode); 334 | bincode_component_impl!(Uuid); 335 | bincode_component_impl!(Particle); 336 | bincode_component_impl!(InteractEntityEvent); 337 | bincode_component_impl!(BlockPlacementEvent); 338 | bincode_component_impl!(BlockInteractEvent); 339 | -------------------------------------------------------------------------------- /crates/quill-common/src/components.rs: -------------------------------------------------------------------------------- 1 | //! Components not associated with a specific type of entity. 2 | //! 3 | //! See the [entities module](::quill::entities) for entity-specific 4 | //! components. 5 | 6 | use std::{ 7 | fmt::Display, 8 | ops::{Deref, DerefMut}, 9 | }; 10 | 11 | use serde::{Deserialize, Serialize}; 12 | use smartstring::{LazyCompact, SmartString}; 13 | 14 | /// Whether an entity is touching the ground. 15 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] 16 | pub struct OnGround(pub bool); 17 | 18 | bincode_component_impl!(OnGround); 19 | 20 | /// A player's username. 21 | /// 22 | /// This component is immutable. Do not 23 | /// attempt to change it. 24 | /// 25 | /// Non-player entities cannot have this component. See [`CustomName`] 26 | /// if you need to name an entity. 27 | #[derive(Clone, Debug, Serialize, Deserialize)] 28 | pub struct Name(SmartString); 29 | 30 | bincode_component_impl!(Name); 31 | 32 | impl Name { 33 | pub fn new(string: &str) -> Self { 34 | Self(string.into()) 35 | } 36 | 37 | pub fn as_str(&self) -> &str { 38 | &*self 39 | } 40 | } 41 | 42 | impl Deref for Name { 43 | type Target = str; 44 | 45 | fn deref(&self) -> &Self::Target { 46 | &self.0 47 | } 48 | } 49 | 50 | impl Display for Name { 51 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 52 | self.0.fmt(f) 53 | } 54 | } 55 | 56 | /// An entity's custom name. 57 | /// 58 | /// Adding this component to an entity 59 | /// will give it a custom name, visible on the client. 60 | /// 61 | /// Giving a player a custom name has no effect. 62 | #[derive(Clone, Debug, Serialize, Deserialize)] 63 | pub struct CustomName(SmartString); 64 | 65 | bincode_component_impl!(CustomName); 66 | 67 | impl CustomName { 68 | /// Creates a custom name from a string. 69 | pub fn new(string: &str) -> Self { 70 | Self(string.into()) 71 | } 72 | 73 | pub fn as_str(&self) -> &str { 74 | &*self 75 | } 76 | 77 | pub fn as_mut_str(&mut self) -> &mut str { 78 | &mut *self 79 | } 80 | } 81 | 82 | impl Deref for CustomName { 83 | type Target = str; 84 | 85 | fn deref(&self) -> &Self::Target { 86 | &self.0 87 | } 88 | } 89 | 90 | impl DerefMut for CustomName { 91 | fn deref_mut(&mut self) -> &mut Self::Target { 92 | &mut self.0 93 | } 94 | } 95 | 96 | impl Display for CustomName { 97 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 98 | self.0.fmt(f) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities.rs: -------------------------------------------------------------------------------- 1 | pub mod area_effect_cloud; 2 | pub use area_effect_cloud::AreaEffectCloud; 3 | pub mod armor_stand; 4 | pub use armor_stand::ArmorStand; 5 | pub mod arrow; 6 | pub use arrow::Arrow; 7 | pub mod bat; 8 | pub use bat::Bat; 9 | pub mod bee; 10 | pub use bee::Bee; 11 | pub mod blaze; 12 | pub use blaze::Blaze; 13 | pub mod boat; 14 | pub use boat::Boat; 15 | pub mod cat; 16 | pub use cat::Cat; 17 | pub mod cave_spider; 18 | pub use cave_spider::CaveSpider; 19 | pub mod chicken; 20 | pub use chicken::Chicken; 21 | pub mod cod; 22 | pub use cod::Cod; 23 | pub mod cow; 24 | pub use cow::Cow; 25 | pub mod creeper; 26 | pub use creeper::Creeper; 27 | pub mod dolphin; 28 | pub use dolphin::Dolphin; 29 | pub mod donkey; 30 | pub use donkey::Donkey; 31 | pub mod dragon_fireball; 32 | pub use dragon_fireball::DragonFireball; 33 | pub mod drowned; 34 | pub use drowned::Drowned; 35 | pub mod elder_guardian; 36 | pub use elder_guardian::ElderGuardian; 37 | pub mod end_crystal; 38 | pub use end_crystal::EndCrystal; 39 | pub mod ender_dragon; 40 | pub use ender_dragon::EnderDragon; 41 | pub mod enderman; 42 | pub use enderman::Enderman; 43 | pub mod endermite; 44 | pub use endermite::Endermite; 45 | pub mod evoker; 46 | pub use evoker::Evoker; 47 | pub mod evoker_fangs; 48 | pub use evoker_fangs::EvokerFangs; 49 | pub mod experience_orb; 50 | pub use experience_orb::ExperienceOrb; 51 | pub mod eye_of_ender; 52 | pub use eye_of_ender::EyeOfEnder; 53 | pub mod falling_block; 54 | pub use falling_block::FallingBlock; 55 | pub mod firework_rocket; 56 | pub use firework_rocket::FireworkRocket; 57 | pub mod fox; 58 | pub use fox::Fox; 59 | pub mod ghast; 60 | pub use ghast::Ghast; 61 | pub mod giant; 62 | pub use giant::Giant; 63 | pub mod guardian; 64 | pub use guardian::Guardian; 65 | pub mod hoglin; 66 | pub use hoglin::Hoglin; 67 | pub mod horse; 68 | pub use horse::Horse; 69 | pub mod husk; 70 | pub use husk::Husk; 71 | pub mod illusioner; 72 | pub use illusioner::Illusioner; 73 | pub mod iron_golem; 74 | pub use iron_golem::IronGolem; 75 | pub mod item; 76 | pub use item::Item; 77 | pub mod item_frame; 78 | pub use item_frame::ItemFrame; 79 | pub mod fireball; 80 | pub use fireball::Fireball; 81 | pub mod leash_knot; 82 | pub use leash_knot::LeashKnot; 83 | pub mod lightning_bolt; 84 | pub use lightning_bolt::LightningBolt; 85 | pub mod llama; 86 | pub use llama::Llama; 87 | pub mod llama_spit; 88 | pub use llama_spit::LlamaSpit; 89 | pub mod magma_cube; 90 | pub use magma_cube::MagmaCube; 91 | pub mod minecart; 92 | pub use minecart::Minecart; 93 | pub mod chest_minecart; 94 | pub use chest_minecart::ChestMinecart; 95 | pub mod command_block_minecart; 96 | pub use command_block_minecart::CommandBlockMinecart; 97 | pub mod furnace_minecart; 98 | pub use furnace_minecart::FurnaceMinecart; 99 | pub mod hopper_minecart; 100 | pub use hopper_minecart::HopperMinecart; 101 | pub mod spawner_minecart; 102 | pub use spawner_minecart::SpawnerMinecart; 103 | pub mod tnt_minecart; 104 | pub use tnt_minecart::TntMinecart; 105 | pub mod mule; 106 | pub use mule::Mule; 107 | pub mod mooshroom; 108 | pub use mooshroom::Mooshroom; 109 | pub mod ocelot; 110 | pub use ocelot::Ocelot; 111 | pub mod painting; 112 | pub use painting::Painting; 113 | pub mod panda; 114 | pub use panda::Panda; 115 | pub mod parrot; 116 | pub use parrot::Parrot; 117 | pub mod phantom; 118 | pub use phantom::Phantom; 119 | pub mod pig; 120 | pub use pig::Pig; 121 | pub mod piglin; 122 | pub use piglin::Piglin; 123 | pub mod piglin_brute; 124 | pub use piglin_brute::PiglinBrute; 125 | pub mod pillager; 126 | pub use pillager::Pillager; 127 | pub mod polar_bear; 128 | pub use polar_bear::PolarBear; 129 | pub mod tnt; 130 | pub use tnt::Tnt; 131 | pub mod pufferfish; 132 | pub use pufferfish::Pufferfish; 133 | pub mod rabbit; 134 | pub use rabbit::Rabbit; 135 | pub mod ravager; 136 | pub use ravager::Ravager; 137 | pub mod salmon; 138 | pub use salmon::Salmon; 139 | pub mod sheep; 140 | pub use sheep::Sheep; 141 | pub mod shulker; 142 | pub use shulker::Shulker; 143 | pub mod shulker_bullet; 144 | pub use shulker_bullet::ShulkerBullet; 145 | pub mod silverfish; 146 | pub use silverfish::Silverfish; 147 | pub mod skeleton; 148 | pub use skeleton::Skeleton; 149 | pub mod skeleton_horse; 150 | pub use skeleton_horse::SkeletonHorse; 151 | pub mod slime; 152 | pub use slime::Slime; 153 | pub mod small_fireball; 154 | pub use small_fireball::SmallFireball; 155 | pub mod snow_golem; 156 | pub use snow_golem::SnowGolem; 157 | pub mod snowball; 158 | pub use snowball::Snowball; 159 | pub mod spectral_arrow; 160 | pub use spectral_arrow::SpectralArrow; 161 | pub mod spider; 162 | pub use spider::Spider; 163 | pub mod squid; 164 | pub use squid::Squid; 165 | pub mod stray; 166 | pub use stray::Stray; 167 | pub mod strider; 168 | pub use strider::Strider; 169 | pub mod egg; 170 | pub use egg::Egg; 171 | pub mod ender_pearl; 172 | pub use ender_pearl::EnderPearl; 173 | pub mod experience_bottle; 174 | pub use experience_bottle::ExperienceBottle; 175 | pub mod potion; 176 | pub use potion::Potion; 177 | pub mod trident; 178 | pub use trident::Trident; 179 | pub mod trader_llama; 180 | pub use trader_llama::TraderLlama; 181 | pub mod tropical_fish; 182 | pub use tropical_fish::TropicalFish; 183 | pub mod turtle; 184 | pub use turtle::Turtle; 185 | pub mod vex; 186 | pub use vex::Vex; 187 | pub mod villager; 188 | pub use villager::Villager; 189 | pub mod vindicator; 190 | pub use vindicator::Vindicator; 191 | pub mod wandering_trader; 192 | pub use wandering_trader::WanderingTrader; 193 | pub mod witch; 194 | pub use witch::Witch; 195 | pub mod wither; 196 | pub use wither::Wither; 197 | pub mod wither_skeleton; 198 | pub use wither_skeleton::WitherSkeleton; 199 | pub mod wither_skull; 200 | pub use wither_skull::WitherSkull; 201 | pub mod wolf; 202 | pub use wolf::Wolf; 203 | pub mod zoglin; 204 | pub use zoglin::Zoglin; 205 | pub mod zombie; 206 | pub use zombie::Zombie; 207 | pub mod zombie_horse; 208 | pub use zombie_horse::ZombieHorse; 209 | pub mod zombie_villager; 210 | pub use zombie_villager::ZombieVillager; 211 | pub mod zombified_piglin; 212 | pub use zombified_piglin::ZombifiedPiglin; 213 | pub mod player; 214 | pub use player::Player; 215 | pub mod fishing_bobber; 216 | pub use fishing_bobber::FishingBobber; 217 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/area_effect_cloud.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for area effect cloud entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all area effect clouds: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::AreaEffectCloud}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &AreaEffectCloud)>() { 11 | /// println!("Found a area effect cloud with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct AreaEffectCloud; 18 | 19 | pod_component_impl!(AreaEffectCloud); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/armor_stand.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for armor stand entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all armor stands: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::ArmorStand}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &ArmorStand)>() { 11 | /// println!("Found a armor stand with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct ArmorStand; 18 | 19 | pod_component_impl!(ArmorStand); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/arrow.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for arrow entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all arrows: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Arrow}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Arrow)>() { 11 | /// println!("Found a arrow with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Arrow; 18 | 19 | pod_component_impl!(Arrow); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/bat.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for bat entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all bats: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Bat}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Bat)>() { 11 | /// println!("Found a bat with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Bat; 18 | 19 | pod_component_impl!(Bat); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/bee.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for bee entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all bees: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Bee}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Bee)>() { 11 | /// println!("Found a bee with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Bee; 18 | 19 | pod_component_impl!(Bee); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/blaze.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for blaze entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all blazes: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Blaze}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Blaze)>() { 11 | /// println!("Found a blaze with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Blaze; 18 | 19 | pod_component_impl!(Blaze); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/boat.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for boat entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all boats: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Boat}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Boat)>() { 11 | /// println!("Found a boat with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Boat; 18 | 19 | pod_component_impl!(Boat); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/cat.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for cat entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all cats: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Cat}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Cat)>() { 11 | /// println!("Found a cat with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Cat; 18 | 19 | pod_component_impl!(Cat); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/cave_spider.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for cave spider entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all cave spiders: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::CaveSpider}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &CaveSpider)>() { 11 | /// println!("Found a cave spider with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct CaveSpider; 18 | 19 | pod_component_impl!(CaveSpider); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/chest_minecart.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for chest minecart entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all chest minecarts: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::ChestMinecart}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &ChestMinecart)>() { 11 | /// println!("Found a chest minecart with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct ChestMinecart; 18 | 19 | pod_component_impl!(ChestMinecart); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/chicken.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for chicken entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all chickens: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Chicken}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Chicken)>() { 11 | /// println!("Found a chicken with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Chicken; 18 | 19 | pod_component_impl!(Chicken); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/cod.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for cod entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all cods: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Cod}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Cod)>() { 11 | /// println!("Found a cod with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Cod; 18 | 19 | pod_component_impl!(Cod); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/command_block_minecart.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for command block minecart entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all command block minecarts: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::CommandBlockMinecart}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &CommandBlockMinecart)>() { 11 | /// println!("Found a command block minecart with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct CommandBlockMinecart; 18 | 19 | pod_component_impl!(CommandBlockMinecart); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/cow.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for cow entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all cows: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Cow}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Cow)>() { 11 | /// println!("Found a cow with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Cow; 18 | 19 | pod_component_impl!(Cow); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/creeper.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for creeper entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all creepers: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Creeper}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Creeper)>() { 11 | /// println!("Found a creeper with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Creeper; 18 | 19 | pod_component_impl!(Creeper); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/dolphin.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for dolphin entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all dolphins: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Dolphin}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Dolphin)>() { 11 | /// println!("Found a dolphin with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Dolphin; 18 | 19 | pod_component_impl!(Dolphin); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/donkey.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for donkey entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all donkeys: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Donkey}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Donkey)>() { 11 | /// println!("Found a donkey with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Donkey; 18 | 19 | pod_component_impl!(Donkey); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/dragon_fireball.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for dragon fireball entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all dragon fireballs: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::DragonFireball}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &DragonFireball)>() { 11 | /// println!("Found a dragon fireball with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct DragonFireball; 18 | 19 | pod_component_impl!(DragonFireball); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/drowned.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for drowned entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all drowneds: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Drowned}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Drowned)>() { 11 | /// println!("Found a drowned with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Drowned; 18 | 19 | pod_component_impl!(Drowned); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/egg.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for egg entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all eggs: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Egg}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Egg)>() { 11 | /// println!("Found a egg with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Egg; 18 | 19 | pod_component_impl!(Egg); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/elder_guardian.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for elder guardian entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all elder guardians: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::ElderGuardian}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &ElderGuardian)>() { 11 | /// println!("Found a elder guardian with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct ElderGuardian; 18 | 19 | pod_component_impl!(ElderGuardian); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/end_crystal.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for end crystal entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all end crystals: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::EndCrystal}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &EndCrystal)>() { 11 | /// println!("Found a end crystal with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct EndCrystal; 18 | 19 | pod_component_impl!(EndCrystal); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/ender_dragon.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for ender dragon entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all ender dragons: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::EnderDragon}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &EnderDragon)>() { 11 | /// println!("Found a ender dragon with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct EnderDragon; 18 | 19 | pod_component_impl!(EnderDragon); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/ender_pearl.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for ender pearl entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all ender pearls: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::EnderPearl}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &EnderPearl)>() { 11 | /// println!("Found a ender pearl with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct EnderPearl; 18 | 19 | pod_component_impl!(EnderPearl); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/enderman.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for enderman entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all endermans: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Enderman}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Enderman)>() { 11 | /// println!("Found a enderman with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Enderman; 18 | 19 | pod_component_impl!(Enderman); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/endermite.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for endermite entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all endermites: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Endermite}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Endermite)>() { 11 | /// println!("Found a endermite with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Endermite; 18 | 19 | pod_component_impl!(Endermite); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/evoker.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for evoker entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all evokers: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Evoker}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Evoker)>() { 11 | /// println!("Found a evoker with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Evoker; 18 | 19 | pod_component_impl!(Evoker); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/evoker_fangs.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for evoker fangs entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all evoker fangss: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::EvokerFangs}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &EvokerFangs)>() { 11 | /// println!("Found a evoker fangs with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct EvokerFangs; 18 | 19 | pod_component_impl!(EvokerFangs); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/experience_bottle.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for experience bottle entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all experience bottles: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::ExperienceBottle}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &ExperienceBottle)>() { 11 | /// println!("Found a experience bottle with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct ExperienceBottle; 18 | 19 | pod_component_impl!(ExperienceBottle); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/experience_orb.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for experience orb entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all experience orbs: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::ExperienceOrb}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &ExperienceOrb)>() { 11 | /// println!("Found a experience orb with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct ExperienceOrb; 18 | 19 | pod_component_impl!(ExperienceOrb); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/eye_of_ender.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for eye of ender entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all eye of enders: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::EyeOfEnder}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &EyeOfEnder)>() { 11 | /// println!("Found a eye of ender with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct EyeOfEnder; 18 | 19 | pod_component_impl!(EyeOfEnder); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/falling_block.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for falling block entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all falling blocks: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::FallingBlock}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &FallingBlock)>() { 11 | /// println!("Found a falling block with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct FallingBlock; 18 | 19 | pod_component_impl!(FallingBlock); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/fireball.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for fireball entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all fireballs: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Fireball}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Fireball)>() { 11 | /// println!("Found a fireball with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Fireball; 18 | 19 | pod_component_impl!(Fireball); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/firework_rocket.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for firework rocket entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all firework rockets: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::FireworkRocket}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &FireworkRocket)>() { 11 | /// println!("Found a firework rocket with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct FireworkRocket; 18 | 19 | pod_component_impl!(FireworkRocket); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/fishing_bobber.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for fishing bobber entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all fishing bobbers: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::FishingBobber}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &FishingBobber)>() { 11 | /// println!("Found a fishing bobber with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct FishingBobber; 18 | 19 | pod_component_impl!(FishingBobber); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/fox.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for fox entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all foxs: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Fox}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Fox)>() { 11 | /// println!("Found a fox with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Fox; 18 | 19 | pod_component_impl!(Fox); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/furnace_minecart.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for furnace minecart entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all furnace minecarts: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::FurnaceMinecart}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &FurnaceMinecart)>() { 11 | /// println!("Found a furnace minecart with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct FurnaceMinecart; 18 | 19 | pod_component_impl!(FurnaceMinecart); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/ghast.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for ghast entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all ghasts: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Ghast}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Ghast)>() { 11 | /// println!("Found a ghast with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Ghast; 18 | 19 | pod_component_impl!(Ghast); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/giant.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for giant entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all giants: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Giant}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Giant)>() { 11 | /// println!("Found a giant with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Giant; 18 | 19 | pod_component_impl!(Giant); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/guardian.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for guardian entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all guardians: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Guardian}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Guardian)>() { 11 | /// println!("Found a guardian with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Guardian; 18 | 19 | pod_component_impl!(Guardian); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/hoglin.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for hoglin entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all hoglins: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Hoglin}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Hoglin)>() { 11 | /// println!("Found a hoglin with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Hoglin; 18 | 19 | pod_component_impl!(Hoglin); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/hopper_minecart.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for hopper minecart entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all hopper minecarts: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::HopperMinecart}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &HopperMinecart)>() { 11 | /// println!("Found a hopper minecart with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct HopperMinecart; 18 | 19 | pod_component_impl!(HopperMinecart); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/horse.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for horse entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all horses: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Horse}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Horse)>() { 11 | /// println!("Found a horse with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Horse; 18 | 19 | pod_component_impl!(Horse); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/husk.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for husk entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all husks: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Husk}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Husk)>() { 11 | /// println!("Found a husk with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Husk; 18 | 19 | pod_component_impl!(Husk); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/illusioner.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for illusioner entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all illusioners: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Illusioner}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Illusioner)>() { 11 | /// println!("Found a illusioner with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Illusioner; 18 | 19 | pod_component_impl!(Illusioner); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/iron_golem.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for iron golem entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all iron golems: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::IronGolem}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &IronGolem)>() { 11 | /// println!("Found a iron golem with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct IronGolem; 18 | 19 | pod_component_impl!(IronGolem); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/item.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for item entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all items: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Item}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Item)>() { 11 | /// println!("Found a item with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Item; 18 | 19 | pod_component_impl!(Item); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/item_frame.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for item frame entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all item frames: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::ItemFrame}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &ItemFrame)>() { 11 | /// println!("Found a item frame with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct ItemFrame; 18 | 19 | pod_component_impl!(ItemFrame); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/leash_knot.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for leash knot entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all leash knots: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::LeashKnot}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &LeashKnot)>() { 11 | /// println!("Found a leash knot with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct LeashKnot; 18 | 19 | pod_component_impl!(LeashKnot); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/lightning_bolt.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for lightning bolt entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all lightning bolts: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::LightningBolt}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &LightningBolt)>() { 11 | /// println!("Found a lightning bolt with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct LightningBolt; 18 | 19 | pod_component_impl!(LightningBolt); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/llama.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for llama entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all llamas: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Llama}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Llama)>() { 11 | /// println!("Found a llama with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Llama; 18 | 19 | pod_component_impl!(Llama); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/llama_spit.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for llama spit entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all llama spits: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::LlamaSpit}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &LlamaSpit)>() { 11 | /// println!("Found a llama spit with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct LlamaSpit; 18 | 19 | pod_component_impl!(LlamaSpit); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/magma_cube.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for magma cube entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all magma cubes: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::MagmaCube}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &MagmaCube)>() { 11 | /// println!("Found a magma cube with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct MagmaCube; 18 | 19 | pod_component_impl!(MagmaCube); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/minecart.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for minecart entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all minecarts: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Minecart}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Minecart)>() { 11 | /// println!("Found a minecart with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Minecart; 18 | 19 | pod_component_impl!(Minecart); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/mooshroom.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for mooshroom entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all mooshrooms: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Mooshroom}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Mooshroom)>() { 11 | /// println!("Found a mooshroom with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Mooshroom; 18 | 19 | pod_component_impl!(Mooshroom); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/mule.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for mule entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all mules: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Mule}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Mule)>() { 11 | /// println!("Found a mule with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Mule; 18 | 19 | pod_component_impl!(Mule); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/ocelot.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for ocelot entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all ocelots: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Ocelot}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Ocelot)>() { 11 | /// println!("Found a ocelot with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Ocelot; 18 | 19 | pod_component_impl!(Ocelot); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/painting.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for painting entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all paintings: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Painting}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Painting)>() { 11 | /// println!("Found a painting with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Painting; 18 | 19 | pod_component_impl!(Painting); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/panda.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for panda entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all pandas: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Panda}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Panda)>() { 11 | /// println!("Found a panda with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Panda; 18 | 19 | pod_component_impl!(Panda); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/parrot.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for parrot entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all parrots: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Parrot}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Parrot)>() { 11 | /// println!("Found a parrot with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Parrot; 18 | 19 | pod_component_impl!(Parrot); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/phantom.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for phantom entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all phantoms: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Phantom}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Phantom)>() { 11 | /// println!("Found a phantom with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Phantom; 18 | 19 | pod_component_impl!(Phantom); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/pig.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for pig entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all pigs: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Pig}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Pig)>() { 11 | /// println!("Found a pig with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Pig; 18 | 19 | pod_component_impl!(Pig); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/piglin.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for piglin entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all piglins: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Piglin}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Piglin)>() { 11 | /// println!("Found a piglin with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Piglin; 18 | 19 | pod_component_impl!(Piglin); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/piglin_brute.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for piglin brute entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all piglin brutes: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::PiglinBrute}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &PiglinPrute)>() { 11 | /// println!("Found a piglin brute with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct PiglinBrute; 18 | 19 | pod_component_impl!(PiglinBrute); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/pillager.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for pillager entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all pillagers: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Pillager}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Pillager)>() { 11 | /// println!("Found a pillager with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Pillager; 18 | 19 | pod_component_impl!(Pillager); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/player.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for player entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all players: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Player}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Player)>() { 11 | /// println!("Found a player with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Player; 18 | 19 | pod_component_impl!(Player); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/polar_bear.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for polar bear entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all polar bears: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::PolarBear}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &PolarBear)>() { 11 | /// println!("Found a polar bear with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct PolarBear; 18 | 19 | pod_component_impl!(PolarBear); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/potion.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for potion entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all potions: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Potion}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Potion)>() { 11 | /// println!("Found a potion with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Potion; 18 | 19 | pod_component_impl!(Potion); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/pufferfish.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for pufferfish entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all pufferfishs: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Pufferfish}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Pufferfish)>() { 11 | /// println!("Found a pufferfish with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Pufferfish; 18 | 19 | pod_component_impl!(Pufferfish); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/rabbit.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for rabbit entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all rabbits: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Rabbit}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Rabbit)>() { 11 | /// println!("Found a rabbit with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Rabbit; 18 | 19 | pod_component_impl!(Rabbit); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/ravager.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for ravager entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all ravagers: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Ravager}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Ravager)>() { 11 | /// println!("Found a ravager with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Ravager; 18 | 19 | pod_component_impl!(Ravager); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/salmon.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for salmon entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all salmons: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Salmon}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Salmon)>() { 11 | /// println!("Found a salmon with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Salmon; 18 | 19 | pod_component_impl!(Salmon); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/sheep.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for sheep entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all sheeps: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Sheep}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Sheep)>() { 11 | /// println!("Found a sheep with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Sheep; 18 | 19 | pod_component_impl!(Sheep); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/shulker.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for shulker entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all shulkers: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Shulker}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Shulker)>() { 11 | /// println!("Found a shulker with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Shulker; 18 | 19 | pod_component_impl!(Shulker); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/shulker_bullet.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for shulker bullet entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all shulker bullets: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::ShulkerBullet}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &ShulkerBullet)>() { 11 | /// println!("Found a shulker bullet with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct ShulkerBullet; 18 | 19 | pod_component_impl!(ShulkerBullet); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/silverfish.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for silverfish entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all silverfishs: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Silverfish}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Silverfish)>() { 11 | /// println!("Found a silverfish with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Silverfish; 18 | 19 | pod_component_impl!(Silverfish); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/skeleton.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for skeleton entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all skeletons: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Skeleton}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Skeleton)>() { 11 | /// println!("Found a skeleton with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Skeleton; 18 | 19 | pod_component_impl!(Skeleton); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/skeleton_horse.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for skeleton horse entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all skeleton horses: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::SkeletonHorse}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &SkeletonHorse)>() { 11 | /// println!("Found a skeleton horse with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct SkeletonHorse; 18 | 19 | pod_component_impl!(SkeletonHorse); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/slime.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for slime entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all slimes: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Slime}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Slime)>() { 11 | /// println!("Found a slime with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Slime; 18 | 19 | pod_component_impl!(Slime); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/small_fireball.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for small fireball entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all small fireballs: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::SmallFireball}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &SmallFireball)>() { 11 | /// println!("Found a small fireball with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct SmallFireball; 18 | 19 | pod_component_impl!(SmallFireball); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/snow_golem.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for snow golem entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all snow golems: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::SnowGolem}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &SnowGolem)>() { 11 | /// println!("Found a snow golem with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct SnowGolem; 18 | 19 | pod_component_impl!(SnowGolem); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/snowball.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for snowball entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all snowballs: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Snowball}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Snowball)>() { 11 | /// println!("Found a snowball with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Snowball; 18 | 19 | pod_component_impl!(Snowball); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/spawner_minecart.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for spawner minecart entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all spawner minecarts: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::SpawnerMinecart}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &SpawnerMinecart)>() { 11 | /// println!("Found a spawner minecart with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct SpawnerMinecart; 18 | 19 | pod_component_impl!(SpawnerMinecart); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/spectral_arrow.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for spectral arrow entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all spectral arrows: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::SpectralArrow}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &SpectralArrow)>() { 11 | /// println!("Found a spectral arrow with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct SpectralArrow; 18 | 19 | pod_component_impl!(SpectralArrow); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/spider.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for spider entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all spiders: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Spider}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Spider)>() { 11 | /// println!("Found a spider with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Spider; 18 | 19 | pod_component_impl!(Spider); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/squid.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for squid entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all squids: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Squid}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Squid)>() { 11 | /// println!("Found a squid with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Squid; 18 | 19 | pod_component_impl!(Squid); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/stray.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for stray entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all strays: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Stray}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Stray)>() { 11 | /// println!("Found a stray with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Stray; 18 | 19 | pod_component_impl!(Stray); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/strider.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for strider entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all striders: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Strider}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Strider)>() { 11 | /// println!("Found a strider with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Strider; 18 | 19 | pod_component_impl!(Strider); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/tnt.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for tnt entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all tnts: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Tnt}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Tnt)>() { 11 | /// println!("Found a tnt with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Tnt; 18 | 19 | pod_component_impl!(Tnt); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/tnt_minecart.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for tnt minecart entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all tnt minecarts: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::TntMinecart}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &TntMinecart)>() { 11 | /// println!("Found a tnt minecart with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct TntMinecart; 18 | 19 | pod_component_impl!(TntMinecart); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/trader_llama.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for trader llama entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all trader llamas: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::TraderLlama}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &TraderLlama)>() { 11 | /// println!("Found a trader llama with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct TraderLlama; 18 | 19 | pod_component_impl!(TraderLlama); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/trident.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for trident entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all tridents: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Trident}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Trident)>() { 11 | /// println!("Found a trident with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Trident; 18 | 19 | pod_component_impl!(Trident); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/tropical_fish.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for tropical fish entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all tropical fishs: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::TropicalFish}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &TropicalFish)>() { 11 | /// println!("Found a tropical fish with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct TropicalFish; 18 | 19 | pod_component_impl!(TropicalFish); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/turtle.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for turtle entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all turtles: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Turtle}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Turtle)>() { 11 | /// println!("Found a turtle with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Turtle; 18 | 19 | pod_component_impl!(Turtle); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/vex.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for vex entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all vexs: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Vex}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Vex)>() { 11 | /// println!("Found a vex with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Vex; 18 | 19 | pod_component_impl!(Vex); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/villager.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for villager entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all villagers: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Villager}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Villager)>() { 11 | /// println!("Found a villager with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Villager; 18 | 19 | pod_component_impl!(Villager); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/vindicator.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for vindicator entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all vindicators: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Vindicator}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Vindicator)>() { 11 | /// println!("Found a vindicator with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Vindicator; 18 | 19 | pod_component_impl!(Vindicator); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/wandering_trader.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for wandering trader entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all wandering traders: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::WanderingTrader}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &WanderingTrader)>() { 11 | /// println!("Found a wandering trader with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct WanderingTrader; 18 | 19 | pod_component_impl!(WanderingTrader); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/witch.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for witch entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all witchs: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Witch}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Witch)>() { 11 | /// println!("Found a witch with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Witch; 18 | 19 | pod_component_impl!(Witch); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/wither.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for wither entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all withers: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Wither}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Wither)>() { 11 | /// println!("Found a wither with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Wither; 18 | 19 | pod_component_impl!(Wither); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/wither_skeleton.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for wither skeleton entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all wither skeletons: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::WitherSkeleton}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &WitherSkeleton)>() { 11 | /// println!("Found a wither skeleton with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct WitherSkeleton; 18 | 19 | pod_component_impl!(WitherSkeleton); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/wither_skull.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for wither skull entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all wither skulls: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::WitherSkull}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &WitherSkull)>() { 11 | /// println!("Found a wither skull with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct WitherSkull; 18 | 19 | pod_component_impl!(WitherSkull); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/wolf.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for wolf entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all wolfs: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Wolf}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Wolf)>() { 11 | /// println!("Found a wolf with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Wolf; 18 | 19 | pod_component_impl!(Wolf); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/zoglin.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for zoglin entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all zoglins: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Zoglin}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Zoglin)>() { 11 | /// println!("Found a zoglin with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Zoglin; 18 | 19 | pod_component_impl!(Zoglin); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/zombie.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for zombie entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all zombies: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::Zombie}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &Zombie)>() { 11 | /// println!("Found a zombie with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct Zombie; 18 | 19 | pod_component_impl!(Zombie); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/zombie_horse.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for zombie horse entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all zombie horses: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::ZombieHorse}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &ZombieHorse)>() { 11 | /// println!("Found a zombie horse with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct ZombieHorse; 18 | 19 | pod_component_impl!(ZombieHorse); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/zombie_villager.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for zombie villager entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all zombie villagers: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::ZombieVillager}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &ZombieVillager)>() { 11 | /// println!("Found a zombie villager with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct ZombieVillager; 18 | 19 | pod_component_impl!(ZombieVillager); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entities/zombified_piglin.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | /// Marker component for zombified piglin entities. 3 | /// 4 | /// # Example 5 | /// A system that queries for all zombified piglins: 6 | /// ```no_run 7 | /// use quill::{Game, Position, entities::ZombifiedPiglin}; 8 | /// # struct MyPlugin; 9 | /// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { 10 | /// for (entity, (position, _)) in game.query::<(&Position, &ZombifiedPiglin)>() { 11 | /// println!("Found a zombified piglin with position {:?}", position); 12 | /// } 13 | /// } 14 | /// ``` 15 | #[derive(Debug, Copy, Clone, Zeroable, Pod)] 16 | #[repr(C)] 17 | pub struct ZombifiedPiglin; 18 | 19 | pod_component_impl!(ZombifiedPiglin); 20 | -------------------------------------------------------------------------------- /crates/quill-common/src/entity.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::{Pod, Zeroable}; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | use crate::PointerMut; 5 | 6 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Zeroable, Pod, Serialize, Deserialize)] 7 | #[repr(transparent)] 8 | pub struct EntityId(pub u64); 9 | 10 | /// Returned by `query_begin`. Contains pointers 11 | /// to the data yielded by the query. 12 | #[derive(Copy, Clone, Debug, Zeroable, Pod)] 13 | #[repr(C)] 14 | pub struct QueryData { 15 | /// The number of (entity, component_1, ..., component_n) pairs 16 | /// yielded by this query. 17 | pub num_entities: u64, 18 | /// Pointer to an array of `num_entities` entities. 19 | pub entities_ptr: PointerMut, 20 | /// Pointer to an array of component pointers, one for 21 | /// each component in the call to `query_begin`. Each component 22 | /// pointer points to `num_entities` components of the corresponding type, 23 | /// serialized using the component's `to_bytes` method. 24 | /// 25 | /// Note that each component pointer is 64 bits regardless of target. 26 | pub component_ptrs: PointerMut>, 27 | /// Pointer to an array of `u32`s, one for each component. 28 | /// Each `u32` is the number of bytes in the corresponding 29 | /// component buffer. 30 | pub component_lens: PointerMut, 31 | } 32 | -------------------------------------------------------------------------------- /crates/quill-common/src/entity_init.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | /// Initial state of an entity passed 4 | /// to [`Game::create_entity_builder`](::quill::Game::create_entity_builder). 5 | #[derive(Debug, Serialize, Deserialize)] 6 | pub enum EntityInit { 7 | /// Spawn an area effect cloud. 8 | AreaEffectCloud, 9 | 10 | /// Spawn an armor stand. 11 | ArmorStand, 12 | 13 | /// Spawn an arrow. 14 | Arrow, 15 | 16 | /// Spawn a bat. 17 | Bat, 18 | 19 | /// Spawn a bee. 20 | Bee, 21 | 22 | /// Spawn a blaze. 23 | Blaze, 24 | 25 | /// Spawn a boat. 26 | Boat, 27 | 28 | /// Spawn a cat. 29 | Cat, 30 | 31 | /// Spawn a cave spider. 32 | CaveSpider, 33 | 34 | /// Spawn a chicken. 35 | Chicken, 36 | 37 | /// Spawn a cod. 38 | Cod, 39 | 40 | /// Spawn a cow. 41 | Cow, 42 | 43 | /// Spawn a creeper. 44 | Creeper, 45 | 46 | /// Spawn a dolphin. 47 | Dolphin, 48 | 49 | /// Spawn a donkey. 50 | Donkey, 51 | 52 | /// Spawn a dragon fireball. 53 | DragonFireball, 54 | 55 | /// Spawn a drowned. 56 | Drowned, 57 | 58 | /// Spawn an elder guardian. 59 | ElderGuardian, 60 | 61 | /// Spawn an end crystal. 62 | EndCrystal, 63 | 64 | /// Spawn an ender dragon. 65 | EnderDragon, 66 | 67 | /// Spawn an enderman. 68 | Enderman, 69 | 70 | /// Spawn an endermite. 71 | Endermite, 72 | 73 | /// Spawn an evoker. 74 | Evoker, 75 | 76 | /// Spawn an evoker fangs. 77 | EvokerFangs, 78 | 79 | /// Spawn an experience orb. 80 | ExperienceOrb, 81 | 82 | /// Spawn an eye of ender. 83 | EyeOfEnder, 84 | 85 | /// Spawn a falling block. 86 | FallingBlock, 87 | 88 | /// Spawn a firework rocket. 89 | FireworkRocket, 90 | 91 | /// Spawn a fox. 92 | Fox, 93 | 94 | /// Spawn a ghast. 95 | Ghast, 96 | 97 | /// Spawn a giant. 98 | Giant, 99 | 100 | /// Spawn a guardian. 101 | Guardian, 102 | 103 | /// Spawn a hoglin. 104 | Hoglin, 105 | 106 | /// Spawn a horse. 107 | Horse, 108 | 109 | /// Spawn a husk. 110 | Husk, 111 | 112 | /// Spawn an illusioner. 113 | Illusioner, 114 | 115 | /// Spawn an iron golem. 116 | IronGolem, 117 | 118 | /// Spawn an item. 119 | Item, 120 | 121 | /// Spawn an item frame. 122 | ItemFrame, 123 | 124 | /// Spawn a fireball. 125 | Fireball, 126 | 127 | /// Spawn a leash knot. 128 | LeashKnot, 129 | 130 | /// Spawn a lightning bolt. 131 | LightningBolt, 132 | 133 | /// Spawn a llama. 134 | Llama, 135 | 136 | /// Spawn a llama spit. 137 | LlamaSpit, 138 | 139 | /// Spawn a magma cube. 140 | MagmaCube, 141 | 142 | /// Spawn a minecart. 143 | Minecart, 144 | 145 | /// Spawn a chest minecart. 146 | ChestMinecart, 147 | 148 | /// Spawn a command block minecart. 149 | CommandBlockMinecart, 150 | 151 | /// Spawn a furnace minecart. 152 | FurnaceMinecart, 153 | 154 | /// Spawn a hopper minecart. 155 | HopperMinecart, 156 | 157 | /// Spawn a spawner minecart. 158 | SpawnerMinecart, 159 | 160 | /// Spawn a tnt minecart. 161 | TntMinecart, 162 | 163 | /// Spawn a mule. 164 | Mule, 165 | 166 | /// Spawn a mooshroom. 167 | Mooshroom, 168 | 169 | /// Spawn an ocelot. 170 | Ocelot, 171 | 172 | /// Spawn a painting. 173 | Painting, 174 | 175 | /// Spawn a panda. 176 | Panda, 177 | 178 | /// Spawn a parrot. 179 | Parrot, 180 | 181 | /// Spawn a phantom. 182 | Phantom, 183 | 184 | /// Spawn a pig. 185 | Pig, 186 | 187 | /// Spawn a piglin. 188 | Piglin, 189 | 190 | /// Spawn a piglin brute. 191 | PiglinBrute, 192 | 193 | /// Spawn a pillager. 194 | Pillager, 195 | 196 | /// Spawn a polar bear. 197 | PolarBear, 198 | 199 | /// Spawn a tnt. 200 | Tnt, 201 | 202 | /// Spawn a pufferfish. 203 | Pufferfish, 204 | 205 | /// Spawn a rabbit. 206 | Rabbit, 207 | 208 | /// Spawn a ravager. 209 | Ravager, 210 | 211 | /// Spawn a salmon. 212 | Salmon, 213 | 214 | /// Spawn a sheep. 215 | Sheep, 216 | 217 | /// Spawn a shulker. 218 | Shulker, 219 | 220 | /// Spawn a shulker bullet. 221 | ShulkerBullet, 222 | 223 | /// Spawn a silverfish. 224 | Silverfish, 225 | 226 | /// Spawn a skeleton. 227 | Skeleton, 228 | 229 | /// Spawn a skeleton horse. 230 | SkeletonHorse, 231 | 232 | /// Spawn a slime. 233 | Slime, 234 | 235 | /// Spawn a small fireball. 236 | SmallFireball, 237 | 238 | /// Spawn a snow golem. 239 | SnowGolem, 240 | 241 | /// Spawn a snowball. 242 | Snowball, 243 | 244 | /// Spawn a spectral arrow. 245 | SpectralArrow, 246 | 247 | /// Spawn a spider. 248 | Spider, 249 | 250 | /// Spawn a squid. 251 | Squid, 252 | 253 | /// Spawn a stray. 254 | Stray, 255 | 256 | /// Spawn a strider. 257 | Strider, 258 | 259 | /// Spawn an egg. 260 | Egg, 261 | 262 | /// Spawn an ender pearl. 263 | EnderPearl, 264 | 265 | /// Spawn an experience bottle. 266 | ExperienceBottle, 267 | 268 | /// Spawn a potion. 269 | Potion, 270 | 271 | /// Spawn a trident. 272 | Trident, 273 | 274 | /// Spawn a trader llama. 275 | TraderLlama, 276 | 277 | /// Spawn a tropical fish. 278 | TropicalFish, 279 | 280 | /// Spawn a turtle. 281 | Turtle, 282 | 283 | /// Spawn a vex. 284 | Vex, 285 | 286 | /// Spawn a villager. 287 | Villager, 288 | 289 | /// Spawn a vindicator. 290 | Vindicator, 291 | 292 | /// Spawn a wandering trader. 293 | WanderingTrader, 294 | 295 | /// Spawn a witch. 296 | Witch, 297 | 298 | /// Spawn a wither. 299 | Wither, 300 | 301 | /// Spawn a wither skeleton. 302 | WitherSkeleton, 303 | 304 | /// Spawn a wither skull. 305 | WitherSkull, 306 | 307 | /// Spawn a wolf. 308 | Wolf, 309 | 310 | /// Spawn a zoglin. 311 | Zoglin, 312 | 313 | /// Spawn a zombie. 314 | Zombie, 315 | 316 | /// Spawn a zombie horse. 317 | ZombieHorse, 318 | 319 | /// Spawn a zombie villager. 320 | ZombieVillager, 321 | 322 | /// Spawn a zombified piglin. 323 | ZombifiedPiglin, 324 | 325 | /// Spawn a player. 326 | Player, 327 | 328 | /// Spawn a fishing bobber. 329 | FishingBobber, 330 | } 331 | -------------------------------------------------------------------------------- /crates/quill-common/src/events.rs: -------------------------------------------------------------------------------- 1 | mod block_interact; 2 | mod interact_entity; 3 | 4 | pub use block_interact::{BlockInteractEvent, BlockPlacementEvent}; 5 | pub use interact_entity::InteractEntityEvent; 6 | -------------------------------------------------------------------------------- /crates/quill-common/src/events/block_interact.rs: -------------------------------------------------------------------------------- 1 | use libcraft_core::{BlockFace, BlockPosition, Hand, Vec3f}; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | #[derive(Debug, Serialize, Deserialize, Clone)] 5 | pub struct BlockInteractEvent { 6 | pub hand: Hand, 7 | pub location: BlockPosition, 8 | pub face: BlockFace, 9 | pub cursor_position: Vec3f, 10 | /// If the client thinks its inside a block when the interaction is fired. 11 | pub inside_block: bool, 12 | } 13 | 14 | #[derive(Debug, Serialize, Deserialize, Clone)] 15 | pub struct BlockPlacementEvent { 16 | pub hand: Hand, 17 | pub location: BlockPosition, 18 | pub face: BlockFace, 19 | pub cursor_position: Vec3f, 20 | /// If the client thinks its inside a block when the interaction is fired. 21 | pub inside_block: bool, 22 | } 23 | -------------------------------------------------------------------------------- /crates/quill-common/src/events/interact_entity.rs: -------------------------------------------------------------------------------- 1 | use crate::EntityId; 2 | use libcraft_core::{Hand, InteractionType, Vec3f}; 3 | use serde::{Deserialize, Serialize}; 4 | 5 | #[derive(Debug, Serialize, Deserialize, Clone)] 6 | pub struct InteractEntityEvent { 7 | pub target: EntityId, 8 | pub ty: InteractionType, 9 | pub target_pos: Option, 10 | pub hand: Option, 11 | pub sneaking: bool, 12 | } 13 | -------------------------------------------------------------------------------- /crates/quill-common/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | mod utils; 3 | #[macro_use] 4 | pub mod component; 5 | pub mod block; 6 | pub mod components; 7 | pub mod entities; 8 | pub mod entity; 9 | pub mod entity_init; 10 | pub mod events; 11 | 12 | use std::marker::PhantomData; 13 | 14 | use bytemuck::{Pod, Zeroable}; 15 | 16 | pub use component::{Component, HostComponent}; 17 | pub use entity::EntityId; 18 | 19 | /// Wrapper type that enforces 64-bit pointers 20 | /// for all targets. Needed for ABI compatibility 21 | /// between WASM-compiled and native-compiled plugins. 22 | #[derive(Debug, PartialEq, Eq, Zeroable)] 23 | #[repr(transparent)] 24 | pub struct Pointer { 25 | ptr: u64, 26 | _marker: PhantomData<*const T>, 27 | } 28 | 29 | impl Clone for Pointer { 30 | fn clone(&self) -> Self { 31 | Self { 32 | ptr: self.ptr, 33 | _marker: self._marker, 34 | } 35 | } 36 | } 37 | 38 | impl Copy for Pointer {} 39 | 40 | impl Pointer { 41 | pub fn new(ptr: *const T) -> Self { 42 | Self { 43 | ptr: ptr as usize as u64, 44 | _marker: PhantomData, 45 | } 46 | } 47 | 48 | pub fn as_ptr(self) -> *const T { 49 | self.ptr as usize as *const T 50 | } 51 | } 52 | 53 | impl From<*const T> for Pointer { 54 | fn from(ptr: *const T) -> Self { 55 | Self::new(ptr) 56 | } 57 | } 58 | 59 | // SAFETY: Pointer contains a u64 regardless 60 | // of T. bytemuck won't derive Pod for generic 61 | // types because it cannot guarantee this. 62 | unsafe impl Pod for Pointer {} 63 | 64 | /// Wrapper type that enforces 64-bit pointers 65 | /// for all targets. Needed for ABI compatibility 66 | /// between WASM-compiled and native-compiled plugins. 67 | #[derive(Debug, PartialEq, Eq, Zeroable)] 68 | #[repr(transparent)] 69 | pub struct PointerMut { 70 | ptr: u64, 71 | _marker: PhantomData<*mut T>, 72 | } 73 | 74 | impl Clone for PointerMut { 75 | fn clone(&self) -> Self { 76 | Self { 77 | ptr: self.ptr, 78 | _marker: self._marker, 79 | } 80 | } 81 | } 82 | 83 | impl Copy for PointerMut {} 84 | 85 | impl PointerMut { 86 | pub fn new(ptr: *mut T) -> Self { 87 | Self { 88 | ptr: ptr as usize as u64, 89 | _marker: PhantomData, 90 | } 91 | } 92 | 93 | pub fn as_mut_ptr(self) -> *mut T { 94 | self.ptr as usize as *mut T 95 | } 96 | } 97 | 98 | impl From<*mut T> for PointerMut { 99 | fn from(ptr: *mut T) -> Self { 100 | Self::new(ptr) 101 | } 102 | } 103 | 104 | // SAFETY: see impl Pod for Pointer. 105 | unsafe impl Pod for PointerMut {} 106 | -------------------------------------------------------------------------------- /crates/quill-common/src/utils.rs: -------------------------------------------------------------------------------- 1 | macro_rules! c_enum { 2 | ( 3 | $(#[$outer:meta])* 4 | pub enum $ident:ident { 5 | $($variant:ident = $x:literal),* $(,)? 6 | } 7 | ) => { 8 | $(#[$outer])* 9 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, ::serde::Serialize, ::serde::Deserialize)] 10 | #[repr(u32)] 11 | pub enum $ident { 12 | $( 13 | $variant = $x, 14 | )* 15 | } 16 | 17 | impl $ident { 18 | pub fn from_u32(x: u32) -> Option { 19 | match x { 20 | $( 21 | $x => Some(Self::$variant), 22 | )* 23 | _ => None, 24 | } 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /crates/quill-plugin-format/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "quill-plugin-format" 3 | version = "0.1.0" 4 | authors = ["caelunshun "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | anyhow = "1" 9 | tar = "0.4" 10 | flate2 = "1" 11 | serde = { version = "1", features = ["derive"] } 12 | serde_json = "1" 13 | serde_with = "1" 14 | target-lexicon = "0.11" 15 | -------------------------------------------------------------------------------- /crates/quill-plugin-format/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Defines the file format used for compiled [`quill`](https://github.com/feather-rs/quill) 2 | //! plugins. 3 | //! 4 | //! Currently, the file format is based on gzipped `tar` files. 5 | mod metadata; 6 | 7 | use std::{ 8 | borrow::Cow, 9 | io::{Cursor, Read, Write}, 10 | }; 11 | 12 | use anyhow::{anyhow, bail}; 13 | use flate2::Compression; 14 | use tar::Header; 15 | 16 | pub use metadata::{PluginMetadata, PluginTarget}; 17 | 18 | use target_lexicon::OperatingSystem; 19 | pub use target_lexicon::Triple; 20 | 21 | const METADATA_PATH: &str = "metadata.json"; 22 | 23 | /// A plugin definition stored in the Quill file format. 24 | pub struct PluginFile<'a> { 25 | module: Cow<'a, [u8]>, 26 | metadata: PluginMetadata, 27 | } 28 | 29 | impl<'a> PluginFile<'a> { 30 | pub fn new(module: impl Into>, metadata: PluginMetadata) -> Self { 31 | Self { 32 | module: module.into(), 33 | metadata, 34 | } 35 | } 36 | 37 | /// Returns the plugin's module. 38 | /// 39 | /// If the plugin is a WebAssembly plugin, 40 | /// then this is the WASM bytecode. 41 | /// 42 | /// If the plugin is a native plugin, then 43 | /// this is the contents of the shared library 44 | /// containing the plugin. 45 | pub fn module(&self) -> &[u8] { 46 | &*self.module 47 | } 48 | 49 | pub fn metadata(&self) -> &PluginMetadata { 50 | &self.metadata 51 | } 52 | 53 | /// Writes this plugin into a `Vec`. 54 | /// 55 | /// `compression_level` should be between 0 (worst) and 9 (best, but slow). 56 | pub fn encode(&self, compression_level: u32) -> Vec { 57 | let vec = Vec::new(); 58 | let mut archive_builder = tar::Builder::new(flate2::write::GzEncoder::new( 59 | vec, 60 | Compression::new(compression_level), 61 | )); 62 | 63 | self.write_metadata(&mut archive_builder); 64 | self.write_module(&mut archive_builder).unwrap(); 65 | 66 | archive_builder 67 | .into_inner() 68 | .expect("write to Vec failed") 69 | .finish() 70 | .expect("compression failed") 71 | } 72 | 73 | fn write_metadata(&self, archive_builder: &mut tar::Builder) { 74 | let metadata = serde_json::to_string_pretty(&self.metadata) 75 | .expect("failed to serialize PluginMetadata"); 76 | 77 | let mut header = Header::new_gnu(); 78 | header.set_size(metadata.len() as u64); 79 | header.set_mode(0o644); 80 | 81 | archive_builder 82 | .append_data( 83 | &mut header, 84 | METADATA_PATH, 85 | Cursor::new(metadata.into_bytes()), 86 | ) 87 | .expect("write to Vec failed"); 88 | } 89 | 90 | fn write_module(&self, archive_builder: &mut tar::Builder) -> anyhow::Result<()> { 91 | let mut header = Header::new_gnu(); 92 | header.set_size(self.module.len() as u64); 93 | header.set_mode(0o644); 94 | 95 | let path = get_module_path(&self.metadata.target)?; 96 | 97 | archive_builder 98 | .append_data(&mut header, path, Cursor::new(self.module())) 99 | .expect("write to Vec failed"); 100 | 101 | Ok(()) 102 | } 103 | } 104 | 105 | impl PluginFile<'static> { 106 | /// Deserializes a plugin file. 107 | pub fn decode(data: impl Read) -> anyhow::Result { 108 | let mut archive = tar::Archive::new(flate2::read::GzDecoder::new(data)); 109 | 110 | // Current limitation: the metadata must appear 111 | // in the tarball before the WASM module. 112 | 113 | let mut metadata = None; 114 | let mut module = None; 115 | let mut module_path = None; 116 | for entry in archive.entries()? { 117 | let entry = entry?; 118 | 119 | match &*entry.path()?.to_string_lossy() { 120 | s if s == METADATA_PATH => { 121 | let meta = Self::decode_metadata(entry)?; 122 | module_path = Some(get_module_path(&meta.target)?); 123 | metadata = Some(meta); 124 | } 125 | s if Some(s) == module_path => module = Some(Self::decode_wasm_bytecode(entry)?), 126 | _ => (), 127 | } 128 | } 129 | 130 | let metadata = 131 | metadata.ok_or_else(|| anyhow!("missing plugin metadata ({})", METADATA_PATH))?; 132 | let module = module 133 | .ok_or_else(|| anyhow!("missing module ({:?})", module_path))? 134 | .into(); 135 | Ok(Self { metadata, module }) 136 | } 137 | 138 | fn decode_metadata(reader: impl Read) -> anyhow::Result { 139 | serde_json::from_reader(reader).map_err(anyhow::Error::from) 140 | } 141 | 142 | fn decode_wasm_bytecode(mut reader: impl Read) -> anyhow::Result> { 143 | let mut wasm = Vec::new(); 144 | reader.read_to_end(&mut wasm)?; 145 | Ok(wasm) 146 | } 147 | } 148 | 149 | fn get_module_path(target: &PluginTarget) -> anyhow::Result<&'static str> { 150 | Ok(match target { 151 | PluginTarget::Wasm => "module.wasm", 152 | PluginTarget::Native { target_triple } => match target_triple.operating_system { 153 | OperatingSystem::Linux => "module.so", 154 | OperatingSystem::Darwin => "module.dylib", 155 | OperatingSystem::Windows => "module.dll", 156 | os => bail!("unsupported plugin operating system {:?}", os), 157 | }, 158 | }) 159 | } 160 | 161 | #[cfg(test)] 162 | mod tests { 163 | use super::*; 164 | 165 | #[test] 166 | fn roundtrip_wasm() { 167 | let module = vec![0xFF; 1024]; 168 | let metadata = PluginMetadata { 169 | name: "TestPlugin".to_owned(), 170 | identifier: "test-plugin".to_owned(), 171 | version: "0.1.0".to_owned(), 172 | api_version: "0.1.0".to_owned(), 173 | description: Some("test plugin".to_owned()), 174 | authors: vec!["caelunshun".to_owned()], 175 | target: PluginTarget::Wasm, 176 | }; 177 | let file = PluginFile::new(module.clone(), metadata.clone()); 178 | let encoded = file.encode(8); 179 | let decoded = PluginFile::decode(Cursor::new(encoded)).unwrap(); 180 | 181 | assert_eq!(decoded.metadata(), &metadata); 182 | assert_eq!(decoded.module(), module); 183 | } 184 | 185 | #[test] 186 | fn roundtrip_native() { 187 | let module = vec![0xEE; 1024]; 188 | let metadata = PluginMetadata { 189 | name: "TestPlugin".to_owned(), 190 | identifier: "test-plugin".to_owned(), 191 | version: "0.1.0".to_owned(), 192 | api_version: "0.1.0".to_owned(), 193 | description: Some("test plugin".to_owned()), 194 | authors: vec!["caelunshun".to_owned()], 195 | target: PluginTarget::Native { 196 | target_triple: Triple::host(), 197 | }, 198 | }; 199 | let file = PluginFile::new(module.clone(), metadata.clone()); 200 | let encoded = file.encode(8); 201 | let decoded = PluginFile::decode(Cursor::new(encoded)).unwrap(); 202 | 203 | assert_eq!(decoded.metadata(), &metadata); 204 | assert_eq!(decoded.module(), module); 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /crates/quill-plugin-format/src/metadata.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use serde_with::{serde_as, DisplayFromStr}; 3 | use target_lexicon::Triple; 4 | 5 | /// A plugin's metadata, stored alongside its WASM module. 6 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] 7 | pub struct PluginMetadata { 8 | /// Plugin name, no spaces 9 | pub name: String, 10 | /// Plugin identifier (crate name), snake_case or kebab-case 11 | pub identifier: String, 12 | /// Plugin version 13 | pub version: String, 14 | /// `quill` version used to compile the plugin 15 | pub api_version: String, 16 | 17 | #[serde(default)] 18 | pub description: Option, 19 | #[serde(default)] 20 | pub authors: Vec, 21 | 22 | pub target: PluginTarget, 23 | } 24 | 25 | /// Type of a plugin 26 | #[serde_as] 27 | #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] 28 | #[serde(rename_all = "snake_case")] 29 | pub enum PluginTarget { 30 | Wasm, 31 | Native { 32 | /// The target the plugin has been compiled to. 33 | #[serde_as(as = "DisplayFromStr")] 34 | target_triple: Triple, 35 | }, 36 | } 37 | -------------------------------------------------------------------------------- /crates/quill-sys-macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "quill-sys-macros" 3 | version = "0.1.0" 4 | authors = ["caelunshun "] 5 | edition = "2018" 6 | 7 | [lib] 8 | proc-macro = true 9 | 10 | [dependencies] 11 | proc-macro2 = "1" 12 | syn = { version = "1", features = ["full"] } 13 | quote = "1" 14 | -------------------------------------------------------------------------------- /crates/quill-sys-macros/src/lib.rs: -------------------------------------------------------------------------------- 1 | use quote::quote; 2 | use syn::ForeignItem; 3 | 4 | /// Macro to redefine host functions depending 5 | /// on whether we are compiling to the WebAssembly 6 | /// or the native target. 7 | /// 8 | /// See the `quill-sys` crate-level documentation for more info. 9 | #[proc_macro_attribute] 10 | pub fn host_functions( 11 | _args: proc_macro::TokenStream, 12 | input: proc_macro::TokenStream, 13 | ) -> proc_macro::TokenStream { 14 | let input: syn::ItemForeignMod = syn::parse_macro_input!(input as syn::ItemForeignMod); 15 | 16 | let mut functions = Vec::new(); 17 | for item in &input.items { 18 | let item = match item { 19 | ForeignItem::Fn(f) => f, 20 | _ => panic!("only functions may be defined within the host calls module"), 21 | }; 22 | functions.push(item.clone()); 23 | } 24 | 25 | let mut vtable_entries = Vec::new(); 26 | for function in &functions { 27 | let ident = &function.sig.ident; 28 | let args: Vec<_> = function 29 | .sig 30 | .inputs 31 | .iter() 32 | .map(|arg| match arg { 33 | syn::FnArg::Receiver(_) => panic!("self argument"), 34 | syn::FnArg::Typed(arg) => arg.ty.clone(), 35 | }) 36 | .collect(); 37 | let ret = &function.sig.output; 38 | let ret = match ret { 39 | syn::ReturnType::Default => None, 40 | syn::ReturnType::Type(_, ty) => Some(quote! { -> #ty }), 41 | }; 42 | vtable_entries.push(quote! { 43 | #ident: unsafe extern "C" fn(*const (), #(#args),*) #ret 44 | }); 45 | } 46 | 47 | let vtable = quote! { 48 | struct HostVTable { 49 | #(#vtable_entries,)* 50 | } 51 | }; 52 | 53 | let mut vtable_init_bindings = Vec::new(); 54 | let mut vtable_init = Vec::new(); 55 | for function in &functions { 56 | let ident = &function.sig.ident; 57 | let ident_string = ident.to_string(); 58 | let missing_error = format!("missing vtable entry {}", ident_string); 59 | 60 | vtable_init_bindings.push(quote! { 61 | let #ident = *vtable.get(#ident_string).ok_or_else(|| #missing_error)?; 62 | // Safety: Transmute from a usize to a function pointer. 63 | // This is valid on all targeted native platforms. 64 | let #ident = std::mem::transmute::(#ident); 65 | }); 66 | 67 | vtable_init.push(ident.clone()); 68 | } 69 | 70 | let vtable_init = quote! { 71 | #[doc = "Initializes the host vtable."] 72 | #[doc = "Safety: the host vtable must not already be initialized."] 73 | pub unsafe fn init_host_vtable(vtable: &std::collections::HashMap<&str, usize>) -> Result<(), &'static str> { 74 | #(#vtable_init_bindings)* 75 | HOST_VTABLE = Some(HostVTable { 76 | #(#vtable_init,)* 77 | }); 78 | Ok(()) 79 | } 80 | }; 81 | 82 | let through_vtable_functions: Vec<_> = functions 83 | .iter() 84 | .map(|function| { 85 | let ident = &function.sig.ident; 86 | let args = &function.sig.inputs; 87 | let ret = match &function.sig.output { 88 | syn::ReturnType::Default => None, 89 | syn::ReturnType::Type(_, ty) => Some(quote! { -> #ty }), 90 | }; 91 | let value_args: Vec<_> = args 92 | .iter() 93 | .map(|arg| match arg { 94 | syn::FnArg::Receiver(_) => panic!("host functions cannot take self"), 95 | syn::FnArg::Typed(arg) => arg.pat.clone(), 96 | }) 97 | .collect(); 98 | let attrs = &function.attrs; 99 | quote! { 100 | #(#attrs)* 101 | pub unsafe fn #ident(#args) #ret { 102 | let vtable = HOST_VTABLE.as_ref().expect("vtable not initialized"); 103 | let context = HOST_CONTEXT.expect("context not initialized"); 104 | (vtable.#ident)(context, #(#value_args),*) 105 | } 106 | } 107 | }) 108 | .collect(); 109 | 110 | let attrs = &input.attrs; 111 | 112 | let result = quote! { 113 | #[cfg(target_arch = "wasm32")] 114 | #(#attrs)* 115 | extern "C" { 116 | #(#functions)* 117 | } 118 | 119 | #[cfg(not(target_arch = "wasm32"))] 120 | mod host_functions { 121 | use super::*; 122 | 123 | static mut HOST_VTABLE: Option = None; 124 | static mut HOST_CONTEXT: Option<*const ()> = None; 125 | 126 | #vtable 127 | 128 | #vtable_init 129 | 130 | #[doc = "Sets the host context."] 131 | #[doc = "Safety: can only be called once."] 132 | pub unsafe fn init_host_context(context: *const ()) { 133 | HOST_CONTEXT = Some(context); 134 | } 135 | 136 | #(#through_vtable_functions)* 137 | } 138 | #[cfg(not(target_arch = "wasm32"))] 139 | pub use host_functions::*; 140 | }; 141 | result.into() 142 | } 143 | -------------------------------------------------------------------------------- /crates/quill-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "quill-sys" 3 | version = "0.1.0" 4 | authors = ["caelunshun "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | quill-common = { path = "../quill-common" } 9 | quill-sys-macros = { path = "../quill-sys-macros" } 10 | -------------------------------------------------------------------------------- /crates/quill-sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Raw FFI functions for host calls. 2 | //! 3 | //! # WASM vs Native 4 | //! `quill-sys` exposes the same API on both WASM and native 5 | //! targets, but there are internal differences in how 6 | //! host functions are called. 7 | //! 8 | //! On WASM, host calls are `extern "C"` functions 9 | //! that the linker adds as an import for the WASM module. 10 | //! 11 | //! On native, host calls are defined in a vtable struct 12 | //! containing a function pointer for each call. The exported 13 | //! functions in this crate defer to the vtable to make their host calls. 14 | //! 15 | //! Additionally, on native, `quill-sys` exports a `HOST_CONTEXT` constant 16 | //! which is passed to every host call. The host expects this to be the 17 | //! value passed to the `quill_setup` method. Failing to set this 18 | //! constant correctly before making host calls 19 | //! will result in undefined behavior. 20 | 21 | use std::mem::MaybeUninit; 22 | 23 | use quill_common::{ 24 | block::BlockGetResult, entity::QueryData, EntityId, HostComponent, Pointer, PointerMut, 25 | }; 26 | 27 | // The attribute macro transforms the block into either: 28 | // 1. On WASM, an extern "C" block defining functions imported from the host. 29 | // 2. On native targets, the necessary glue code to use the HOST_VTABLE 30 | // to call host functions. 31 | // The resulting public API is the same for both targets. 32 | #[quill_sys_macros::host_functions] 33 | #[link(wasm_import_module = "quill_01")] 34 | extern "C" { 35 | /// Registers a system. 36 | /// 37 | /// Each tick, the system is invoked 38 | /// by calling the plugin's exported `quill_run_system` method. 39 | /// `quill_run_system` is given the `system_data` pointer passed 40 | /// to this host call. 41 | pub fn register_system(system_data: PointerMut, name_ptr: Pointer, name_len: u32); 42 | 43 | /// Initiates a query. Returns the query data. 44 | /// 45 | /// The returned query buffers are allocated within 46 | /// the plugin's bump allocator. They will be 47 | /// freed automatically after the plugin finishes 48 | /// executing the current system. 49 | pub fn entity_query( 50 | components_ptr: Pointer, 51 | components_len: u32, 52 | query_data: PointerMut>, 53 | ); 54 | 55 | /// Determines whether the given entity exists. 56 | pub fn entity_exists(entity: EntityId) -> bool; 57 | 58 | /// Gets a component for an entity. 59 | /// 60 | /// Sets `bytes_ptr` to a pointer to the serialized 61 | /// component bytes and `bytes_len` to the number of bytes. 62 | /// 63 | /// If the entity does not have the component, 64 | /// then `bytes_ptr` is set to null, and `bytes_len` 65 | /// is left untouched. 66 | pub fn entity_get_component( 67 | entity: EntityId, 68 | component: HostComponent, 69 | bytes_ptr: PointerMut>, 70 | bytes_len: PointerMut, 71 | ); 72 | 73 | /// Sets or replaces a component for an entity. 74 | /// 75 | /// `bytes_ptr` is a pointer to the serialized 76 | /// component. 77 | /// 78 | /// This will overwrite any existing component of the same type. 79 | /// 80 | /// Does nothing if `entity` does not exist. 81 | pub fn entity_set_component( 82 | entity: EntityId, 83 | component: HostComponent, 84 | bytes_ptr: Pointer, 85 | bytes_len: u32, 86 | ); 87 | 88 | /// Sends a message to an entity. 89 | /// 90 | /// The given message should be in the JSON format. 91 | /// 92 | /// Does nothing if the entity does not exist or it does not have the `Chat` component. 93 | pub fn entity_send_message(entity: EntityId, message_ptr: Pointer, message_len: u32); 94 | 95 | /// Creates an empty entity builder. 96 | /// 97 | /// This builder is used for creating an ecs-entity 98 | /// 99 | /// **This is NOT specifically for a minecraft entity!** 100 | /// 101 | pub fn entity_builder_new_empty() -> u32; 102 | 103 | /// Creates an entity builder. 104 | /// 105 | /// The builder is initialized with the default 106 | /// components for the given `EntityInit`. 107 | /// 108 | /// `entity_init` is a `bincode`-serialized `EntityInit`. 109 | pub fn entity_builder_new( 110 | position: Pointer, 111 | entity_init_ptr: Pointer, 112 | entity_init_len: u32, 113 | ) -> u32; 114 | 115 | /// Adds a component to an entity builder. 116 | /// 117 | /// `bytes` is the serialized component. 118 | pub fn entity_builder_add_component( 119 | builder: u32, 120 | component: HostComponent, 121 | bytes_ptr: Pointer, 122 | bytes_len: u32, 123 | ); 124 | 125 | /// Creates an entity from an entity builder. 126 | /// 127 | /// Returns the new entity. 128 | /// 129 | /// `builder` is consumed after this call. 130 | /// Reusing it is undefined behavior. 131 | pub fn entity_builder_finish(builder: u32) -> EntityId; 132 | 133 | /// Gets the block at the given position. 134 | /// 135 | /// Returns `None` if the block's chunk is unloaded 136 | /// or if the Y coordinate is out of bounds. 137 | pub fn block_get(x: i32, y: i32, z: i32) -> BlockGetResult; 138 | 139 | /// Sets the block at the given position. 140 | /// 141 | /// Returns `true` if successful and `false` 142 | /// if the block's chunk is not loaded or 143 | /// the Y coordinate is out of bounds. 144 | /// 145 | /// `block` is the vanilla ID of the block. 146 | pub fn block_set(x: i32, y: i32, z: i32, block: u16) -> bool; 147 | 148 | /// Fills the given chunk section with `block`. 149 | /// 150 | /// Replaces all existing blocks in the section. 151 | /// 152 | /// This is an optimized bulk operation that will be significantly 153 | /// faster than calling [`block_set`] on each block in the chunk section. 154 | /// 155 | /// Returns `true` if successful and `false` if the 156 | /// block's chunk is not loaded or the section index is out of bounds. 157 | pub fn block_fill_chunk_section(chunk_x: i32, section_y: u32, chunk_z: i32, block: u16) 158 | -> bool; 159 | } 160 | -------------------------------------------------------------------------------- /crates/quill/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "quill" 3 | version = "0.1.0" 4 | authors = ["caelunshun "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | libcraft-core = { git = "https://github.com/feather-rs/libcraft", rev = "0b49cd0" } 9 | libcraft-particles = { git = "https://github.com/feather-rs/libcraft", rev = "0b49cd0" } 10 | libcraft-blocks = { git = "https://github.com/feather-rs/libcraft", rev = "0b49cd0" } 11 | bincode = "1" 12 | bytemuck = "1" 13 | quill-sys = { path = "../quill-sys" } 14 | quill-common = { path = "../quill-common" } 15 | thiserror = "1" 16 | uuid = "0.8" 17 | 18 | -------------------------------------------------------------------------------- /crates/quill/src/entities.rs: -------------------------------------------------------------------------------- 1 | //! Defines components for all Minecraft entities. 2 | //! 3 | //! # Marker components 4 | //! Each entity has a "marker component": 5 | //! just a struct (often with no fields) 6 | //! that signifies the type of an entity. 7 | //! 8 | //! For example, all horse entities have the [`Horse`] 9 | //! marker component. 10 | //! 11 | //! For certain entities, these components also 12 | //! contain data. For example, the [`Item`] marker 13 | //! component (for item entities) has an `ItemStack` 14 | //! field that indicates the type of the item. 15 | 16 | #[doc(inline)] 17 | pub use quill_common::entities::*; 18 | -------------------------------------------------------------------------------- /crates/quill/src/entity.rs: -------------------------------------------------------------------------------- 1 | use std::{marker::PhantomData, ptr}; 2 | 3 | use quill_common::{Component, Pointer, PointerMut}; 4 | 5 | /// Unique internal ID of an entity. 6 | /// 7 | /// Can be passed to [`Game::entity`] to get an [`Entity`] 8 | /// handle. 9 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 10 | #[repr(transparent)] 11 | pub struct EntityId(pub(crate) quill_common::EntityId); 12 | 13 | /// Error returned by [`Entity::get`] when 14 | /// the entity is missing a component. 15 | #[derive(Debug, thiserror::Error)] 16 | #[error("entity does not have component of type {0}")] 17 | pub struct MissingComponent(&'static str); 18 | 19 | /// A handle to an entity. 20 | /// 21 | /// Allows access to the entity's components, like 22 | /// position and UUID. 23 | /// 24 | /// Use [`Game::entity`] to get an `Entity` instance. 25 | /// 26 | /// An `Entity` be sent or shared between threads. However, 27 | /// an [`EntityId`] can. 28 | #[derive(Debug)] 29 | #[repr(C)] 30 | pub struct Entity { 31 | id: EntityId, 32 | _not_send_sync: PhantomData<*mut ()>, 33 | } 34 | 35 | impl Entity { 36 | pub(crate) fn new(id: EntityId) -> Self { 37 | Self { 38 | id, 39 | _not_send_sync: PhantomData, 40 | } 41 | } 42 | 43 | /// Gets a component of this entity. Returns 44 | /// `Err(MissingComponent)` if the entity does not have this component. 45 | /// 46 | /// # Examples 47 | /// ```no_run 48 | /// use quill::{Position, Entity}; 49 | /// # let entity: Entity = unreachable!(); 50 | /// let position = entity.get::().expect("entity has no position component"); 51 | /// ``` 52 | pub fn get(&self) -> Result { 53 | let host_component = T::host_component(); 54 | unsafe { 55 | let mut bytes_ptr = Pointer::new(ptr::null()); 56 | let mut bytes_len = 0u32; 57 | quill_sys::entity_get_component( 58 | self.id.0, 59 | host_component, 60 | PointerMut::new(&mut bytes_ptr), 61 | PointerMut::new(&mut bytes_len), 62 | ); 63 | 64 | if bytes_ptr.as_ptr().is_null() { 65 | return Err(MissingComponent(std::any::type_name::())); 66 | } 67 | 68 | let bytes = std::slice::from_raw_parts(bytes_ptr.as_ptr(), bytes_len as usize); 69 | Ok(T::from_bytes_unchecked(bytes).0) 70 | } 71 | } 72 | 73 | /// Sets or replaces a component of this entity. 74 | /// 75 | /// If the entity already has this component, 76 | /// the component is overwritten. 77 | pub fn set(&self, component: T) { 78 | let host_component = T::host_component(); 79 | let bytes = component.to_cow_bytes(); 80 | 81 | unsafe { 82 | quill_sys::entity_set_component( 83 | self.id.0, 84 | host_component, 85 | bytes.as_ptr().into(), 86 | bytes.len() as u32, 87 | ); 88 | } 89 | } 90 | 91 | /// Sends the given message to this entity. 92 | /// 93 | /// The message sends as a "system" message. 94 | /// See [the wiki](https://wiki.vg/Chat) for more details. 95 | pub fn send_message(&self, message: impl AsRef) { 96 | let message = message.as_ref(); 97 | unsafe { 98 | quill_sys::entity_send_message(self.id.0, message.as_ptr().into(), message.len() as u32) 99 | } 100 | } 101 | 102 | /// Gets the unique ID of this entity. 103 | pub fn id(&self) -> EntityId { 104 | self.id 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /crates/quill/src/entity_builder.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | 3 | use quill_common::Component; 4 | 5 | use crate::{Entity, EntityId}; 6 | 7 | /// Builder for an entity. 8 | /// 9 | /// Created via [`Game::create_entity_builder`](crate::Game::create_entity_builder). 10 | /// 11 | /// Add components to the entity with [`add`]. 12 | /// Finish building the entity with [`finish`]. 13 | #[derive(Debug)] 14 | pub struct EntityBuilder { 15 | id: u32, 16 | _not_send_sync: PhantomData<*mut ()>, 17 | } 18 | 19 | impl EntityBuilder { 20 | pub(crate) fn new(id: u32) -> Self { 21 | Self { 22 | id, 23 | _not_send_sync: PhantomData, 24 | } 25 | } 26 | 27 | /// Adds a component to the entity. 28 | /// 29 | /// If the builder already has this component, 30 | /// it is overriden. 31 | pub fn add(&mut self, component: T) -> &mut Self { 32 | let host_component = T::host_component(); 33 | let bytes = component.to_cow_bytes(); 34 | unsafe { 35 | quill_sys::entity_builder_add_component( 36 | self.id, 37 | host_component, 38 | bytes.as_ptr().into(), 39 | bytes.len() as u32, 40 | ); 41 | } 42 | self 43 | } 44 | 45 | /// Adds a component to the entity and returns 46 | /// `self` for method chaining. 47 | /// 48 | /// If the builder already has this component, 49 | /// it is override. 50 | pub fn with(mut self, component: T) -> Self { 51 | self.add(component); 52 | self 53 | } 54 | 55 | /// Finishes building the entity and spawns it. 56 | /// 57 | /// Returns the built entity. 58 | pub fn finish(self) -> Entity { 59 | let id = unsafe { quill_sys::entity_builder_finish(self.id) }; 60 | Entity::new(EntityId(id)) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /crates/quill/src/game.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | 3 | use libcraft_blocks::BlockState; 4 | use libcraft_core::{BlockPosition, ChunkPosition, Position, CHUNK_HEIGHT}; 5 | use libcraft_particles::Particle; 6 | use quill_common::entity_init::EntityInit; 7 | 8 | use crate::{ 9 | query::{Query, QueryIter}, 10 | EntityBuilder, 11 | }; 12 | use crate::{Entity, EntityId}; 13 | 14 | /// Error returned when getting or setting a block fails. 15 | #[derive(Debug, thiserror::Error)] 16 | pub enum BlockAccessError { 17 | #[error("the block's Y coordinate is outside the range [0, 256)")] 18 | YOutOfBounds, 19 | #[error("the block's chunk is not loaded")] 20 | ChunkNotLoaded, 21 | } 22 | 23 | /// Error returned from [`Game::entity`] if the entity 24 | /// did not exist. 25 | #[derive(Debug, thiserror::Error)] 26 | #[error("entity no longer exists - they either died or were unloaded")] 27 | pub struct EntityRemoved; 28 | 29 | /// Provides access to the server's game state for a single world. 30 | /// 31 | /// Includes entities, blocks, chunks, etc. All interaction with 32 | /// the game happens through this struct. 33 | /// 34 | /// A `Game` is passed to systems when they run. 35 | #[derive(Debug)] 36 | pub struct Game { 37 | _not_send_sync: PhantomData<*mut ()>, 38 | } 39 | 40 | impl Game { 41 | /// For Quill internal use only. Do not call. 42 | #[doc(hidden)] 43 | pub fn new() -> Self { 44 | Self { 45 | _not_send_sync: PhantomData, 46 | } 47 | } 48 | 49 | /// Gets an [`Entity`] from its [`EntityId`]. 50 | /// 51 | /// Returns `None` if the entity no longer exists. This 52 | /// could be the case if: 53 | /// * The entity has been unloaded (and possibly saved to disk) 54 | /// * The entity has died 55 | pub fn entity(&self, id: EntityId) -> Result { 56 | unsafe { 57 | if !quill_sys::entity_exists(id.0) { 58 | return Err(EntityRemoved); 59 | } 60 | } 61 | Ok(Entity::new(id)) 62 | } 63 | 64 | /// Creates an empty [`EntityBuilder`](create::EntityBuilder) 65 | /// to add entities to the ecs. 66 | /// 67 | /// The builder isn initialised without any components. 68 | pub fn create_empty_entity_builder(&self) -> EntityBuilder { 69 | let id = unsafe { quill_sys::entity_builder_new_empty() }; 70 | 71 | EntityBuilder::new(id) 72 | } 73 | 74 | /// Creates an [`EntityBuilder`](crate::EntityBuilder) 75 | /// to spawn an entity at the given position. 76 | /// 77 | /// The builder is initialized with the default components 78 | /// for the given `EntityInit`. The default components 79 | /// include (at least): 80 | /// * Position` 81 | /// * `Uuid` 82 | /// * `EntityType` 83 | /// * `Velocity` (set to zero) 84 | /// * the marker component for this entity 85 | #[must_use = "call `finish` on an EntityBuilder to spawn the entity"] 86 | pub fn create_entity_builder(&self, position: Position, entity: EntityInit) -> EntityBuilder { 87 | let entity_init = bincode::serialize(&entity).expect("failed to serialize EntityInit"); 88 | let position: &[u8] = bytemuck::cast_slice(std::slice::from_ref(&position)); 89 | let id = unsafe { 90 | quill_sys::entity_builder_new( 91 | position.as_ptr().into(), 92 | entity_init.as_ptr().into(), 93 | entity_init.len() as u32, 94 | ) 95 | }; 96 | EntityBuilder::new(id) 97 | } 98 | 99 | /// Returns an iterator over all entities 100 | /// with the given components. 101 | /// 102 | /// # Example 103 | /// Iterate over all entities with positions and UUIDs: 104 | /// ```no_run 105 | /// use quill::{Position, Uuid}; 106 | /// # let game: quill::Game = todo!(); 107 | /// for (entity, (position, uuid)) in game.query::<(&Position, &Uuid)>() { 108 | /// println!("Found an entity with position {:?} and UUID {}", position, uuid); 109 | /// } 110 | /// ``` 111 | pub fn query(&self) -> QueryIter { 112 | QueryIter::new() 113 | } 114 | 115 | /// Spawn a particle effect at the position 116 | /// 117 | /// # Example 118 | /// Spawn a flame particle at 0, 0, 0: 119 | /// ```no_run 120 | /// use quill::{Position, Particle, ParticleKind} 121 | /// 122 | /// let position = Position {x: 0.0, y: 0.0, z: 0.0, pitch: 0.0, yaw: 0.0} 123 | /// let particle = Particle { 124 | /// kind: ParticleKind::Flame, 125 | /// offset_x: 0.0, 126 | /// offset_y: 0.0, 127 | /// offset_z: 0.0, 128 | /// count: 1, 129 | /// }; 130 | /// 131 | /// game.spawn_particle(position, particle) 132 | /// ``` 133 | pub fn spawn_particle(&self, position: Position, particle: Particle) { 134 | let mut entity_builder = self.create_empty_entity_builder(); 135 | 136 | entity_builder.add(position); 137 | entity_builder.add(particle); 138 | entity_builder.finish(); 139 | } 140 | 141 | /// Gets the block at `pos`. 142 | /// 143 | /// This function returns an error if the block's 144 | /// chunk is not loaded. Unlike in Bukkit, calling this method 145 | /// will not cause chunks to be loaded. 146 | /// 147 | /// Mutating the returned [`BlockState`](libcraft_blocks::BlockState) 148 | /// will _not_ cause the block to be modified in the world. In other 149 | /// words, the `BlockState` is a copy, not a reference. To update 150 | /// the block, call [`set_block`]. 151 | pub fn block(&self, pos: BlockPosition) -> Result { 152 | check_y_bound(pos)?; 153 | 154 | let result = unsafe { quill_sys::block_get(pos.x, pos.y, pos.z) }; 155 | 156 | result 157 | .get() 158 | .ok_or(BlockAccessError::ChunkNotLoaded) 159 | .map(|block_id| BlockState::from_id(block_id).expect("host gave invalid block ID")) 160 | } 161 | 162 | /// Sets the block at `pos`. 163 | /// 164 | /// This function returns an error if the block's 165 | /// chunk is not loaded. Unlike in Bukkit, calling this method 166 | /// will not cause chunks to be loaded. 167 | pub fn set_block(&self, pos: BlockPosition, block: BlockState) -> Result<(), BlockAccessError> { 168 | check_y_bound(pos)?; 169 | 170 | let was_successful = unsafe { quill_sys::block_set(pos.x, pos.y, pos.z, block.id()) }; 171 | 172 | if was_successful { 173 | Ok(()) 174 | } else { 175 | Err(BlockAccessError::ChunkNotLoaded) 176 | } 177 | } 178 | 179 | /// Efficiently overwrites all blocks in the given chunk section (16x16x16 blocks). 180 | /// 181 | /// All blocks in the chunk section are replaced with `block`. 182 | /// 183 | /// This function returns an error if the block's 184 | /// chunk is not loaded. Unlike in Bukkit, calling this method 185 | /// will not cause chunks to be loaded. 186 | pub fn fill_chunk_section( 187 | &self, 188 | chunk: ChunkPosition, 189 | section_y: u32, 190 | block: BlockState, 191 | ) -> Result<(), BlockAccessError> { 192 | check_section_y(section_y)?; 193 | 194 | let block_id = block.id(); 195 | let was_successful = 196 | unsafe { quill_sys::block_fill_chunk_section(chunk.x, section_y, chunk.z, block_id) }; 197 | 198 | if was_successful { 199 | Ok(()) 200 | } else { 201 | Err(BlockAccessError::ChunkNotLoaded) 202 | } 203 | } 204 | } 205 | 206 | fn check_y_bound(pos: BlockPosition) -> Result<(), BlockAccessError> { 207 | if pos.y < 0 || pos.y >= CHUNK_HEIGHT as i32 { 208 | Err(BlockAccessError::YOutOfBounds) 209 | } else { 210 | Ok(()) 211 | } 212 | } 213 | 214 | fn check_section_y(section_y: u32) -> Result<(), BlockAccessError> { 215 | if section_y >= 16 { 216 | Err(BlockAccessError::YOutOfBounds) 217 | } else { 218 | Ok(()) 219 | } 220 | } 221 | 222 | #[cfg(test)] 223 | mod tests { 224 | use super::*; 225 | 226 | #[test] 227 | fn check_y_bound_in_bounds() { 228 | assert!(check_y_bound(BlockPosition::new(0, 0, 0)).is_ok()); 229 | assert!(check_y_bound(BlockPosition::new(0, 255, 0)).is_ok()); 230 | } 231 | 232 | #[test] 233 | fn check_y_bound_out_of_bounds() { 234 | assert!(matches!( 235 | check_y_bound(BlockPosition::new(0, -1, 0)), 236 | Err(BlockAccessError::YOutOfBounds) 237 | )); 238 | assert!(matches!( 239 | check_y_bound(BlockPosition::new(0, 256, 0)), 240 | Err(BlockAccessError::YOutOfBounds) 241 | )); 242 | } 243 | 244 | #[test] 245 | fn check_section_y_in_bounds() { 246 | assert!(check_section_y(0).is_ok()); 247 | assert!(check_section_y(15).is_ok()); 248 | } 249 | 250 | #[test] 251 | fn check_section_y_out_of_bounds() { 252 | assert!(matches!( 253 | check_section_y(16), 254 | Err(BlockAccessError::YOutOfBounds) 255 | )); 256 | assert!(matches!( 257 | check_section_y(u32::MAX), 258 | Err(BlockAccessError::YOutOfBounds) 259 | )); 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /crates/quill/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! A WebAssembly-based plugin API for Minecraft servers. 2 | 3 | pub mod entities; 4 | mod entity; 5 | mod entity_builder; 6 | mod game; 7 | pub mod query; 8 | mod setup; 9 | 10 | pub use entity::{Entity, EntityId}; 11 | pub use entity_builder::EntityBuilder; 12 | pub use game::Game; 13 | pub use setup::Setup; 14 | 15 | #[doc(inline)] 16 | pub use libcraft_blocks::{BlockKind, BlockState}; 17 | #[doc(inline)] 18 | pub use libcraft_core::{ 19 | BlockPosition, ChunkPosition, Enchantment, EnchantmentKind, Gamemode, Position, 20 | }; 21 | 22 | #[doc(inline)] 23 | pub use libcraft_particles::{Particle, ParticleKind}; 24 | 25 | #[doc(inline)] 26 | pub use quill_common::{components, entity_init::EntityInit, events, Component}; 27 | #[doc(inline)] 28 | pub use uuid::Uuid; 29 | 30 | // Needed for macros 31 | #[doc(hidden)] 32 | pub extern crate bincode; 33 | #[doc(hidden)] 34 | pub extern crate quill_sys as sys; 35 | 36 | /// Implement this trait for your plugin's struct. 37 | pub trait Plugin: Sized { 38 | /// Invoked when the plugin is enabled. 39 | /// 40 | /// Here, you should register systems and initialize 41 | /// any plugin state. 42 | /// 43 | /// # Warning 44 | /// This function is called when your plugin _enabled_. That 45 | /// is not guaranteed to coincide with the time the server starts 46 | /// up. Do not assume that the server has just started when 47 | /// this method is called. 48 | fn enable(game: &mut Game, setup: &mut Setup) -> Self; 49 | 50 | /// Invoked before the plugin is disabled. 51 | /// 52 | /// # Warning 53 | /// Like [`enable`], this method is not necessarily called 54 | /// when the server shuts down. Users may choose to disable 55 | /// plugins at another time. Therefore, do not assume that 56 | /// the server is shutting down when this method is called. 57 | fn disable(self, game: &mut Game); 58 | } 59 | 60 | /// Invoke this macro in your plugin's main.rs. 61 | /// 62 | /// Give it the name of your struct implementing `Plugin`. 63 | /// 64 | /// # Example 65 | /// ```no_run 66 | /// // main.rs 67 | /// use quill::{Plugin, Setup, Game}; 68 | /// 69 | /// quill::plugin!(MyPlugin); 70 | /// 71 | /// pub struct MyPlugin { 72 | /// // plugin state goes here 73 | /// } 74 | /// 75 | /// impl Plugin for MyPlugin { 76 | /// fn enable(game: &mut Game, setup: &mut Setup) -> Self { 77 | /// // Initialize plugin state... 78 | /// Self {} 79 | /// } 80 | /// 81 | /// fn disable(self, game: &mut Game) { 82 | /// // Clean up... 83 | /// } 84 | /// } 85 | /// ``` 86 | #[macro_export] 87 | macro_rules! plugin { 88 | ($plugin:ident) => { 89 | // `static mut` can be used without synchronization because the host 90 | // guarantees it will not invoke plugin systems outside of the main thread. 91 | static mut PLUGIN: Option<$plugin> = None; 92 | 93 | // Exports to the host required for all plugins 94 | #[no_mangle] 95 | #[doc(hidden)] 96 | #[cfg(target_arch = "wasm32")] 97 | pub unsafe extern "C" fn quill_setup() { 98 | let plugin = $plugin::enable(&mut $crate::Game::new(), &mut $crate::Setup::new()); 99 | PLUGIN = Some(plugin); 100 | } 101 | 102 | #[no_mangle] 103 | #[doc(hidden)] 104 | #[cfg(not(target_arch = "wasm32"))] 105 | pub unsafe extern "C" fn quill_setup( 106 | context: *const (), 107 | vtable_ptr: *const u8, 108 | vtable_len: usize, 109 | ) { 110 | // Set up vtable and host context for quill_sys. 111 | let vtable_bytes = ::std::slice::from_raw_parts(vtable_ptr, vtable_len); 112 | let vtable: ::std::collections::HashMap<&str, usize> = 113 | $crate::bincode::deserialize(vtable_bytes).expect("invalid vtable"); 114 | 115 | $crate::sys::init_host_context(context); 116 | $crate::sys::init_host_vtable(&vtable) 117 | .expect("invalid vtable (check that the plugin and host are up to date)"); 118 | 119 | let plugin = $plugin::enable(&mut $crate::Game::new(), &mut $crate::Setup::new()); 120 | PLUGIN = Some(plugin); 121 | } 122 | 123 | #[no_mangle] 124 | #[doc(hidden)] 125 | pub unsafe extern "C" fn quill_allocate(size: usize, align: usize) -> *mut u8 { 126 | std::alloc::alloc(std::alloc::Layout::from_size_align_unchecked(size, align)) 127 | } 128 | 129 | #[no_mangle] 130 | #[doc(hidden)] 131 | pub unsafe extern "C" fn quill_deallocate(ptr: *mut u8, size: usize, align: usize) { 132 | std::alloc::dealloc( 133 | ptr, 134 | std::alloc::Layout::from_size_align_unchecked(size, align), 135 | ) 136 | } 137 | 138 | #[no_mangle] 139 | #[doc(hidden)] 140 | pub unsafe extern "C" fn quill_run_system(data: *mut u8) { 141 | let system = &mut *data.cast::>(); 142 | let plugin = PLUGIN.as_mut().expect("quill_setup never called"); 143 | system(plugin, &mut $crate::Game::new()); 144 | } 145 | 146 | /// Never called by Quill, but this is needed 147 | /// to avoid linker errors with WASI. 148 | #[doc(hidden)] 149 | fn main() {} 150 | }; 151 | } 152 | -------------------------------------------------------------------------------- /crates/quill/src/query.rs: -------------------------------------------------------------------------------- 1 | //! Query for all entities with a certain set of components. 2 | 3 | use std::{marker::PhantomData, mem::MaybeUninit}; 4 | 5 | use quill_common::{entity::QueryData, Component, HostComponent, PointerMut}; 6 | 7 | use crate::{Entity, EntityId}; 8 | 9 | /// A type that can be used for a query. 10 | /// 11 | /// Implemented for tuples of `Query`s as well. 12 | pub trait Query { 13 | type Item; 14 | 15 | fn add_component_types(types: &mut Vec); 16 | 17 | unsafe fn get_unchecked( 18 | data: &QueryData, 19 | component_index: &mut usize, 20 | component_offsets: &mut [usize], 21 | ) -> Self::Item; 22 | } 23 | 24 | impl<'a, T> Query for &'a T 25 | where 26 | T: Component, 27 | [T]: ToOwned, 28 | { 29 | type Item = T; 30 | 31 | fn add_component_types(types: &mut Vec) { 32 | types.push(T::host_component()); 33 | } 34 | 35 | unsafe fn get_unchecked( 36 | data: &QueryData, 37 | component_index: &mut usize, 38 | component_offsets: &mut [usize], 39 | ) -> T { 40 | let component_len = *((data.component_lens.as_mut_ptr()).add(*component_index)) as usize; 41 | let component_ptr = 42 | (*(data.component_ptrs.as_mut_ptr().add(*component_index))).as_mut_ptr(); 43 | 44 | let offset = component_offsets[*component_index]; 45 | let component_ptr = component_ptr.add(offset); 46 | let component_len = component_len - offset; 47 | 48 | let component_bytes = std::slice::from_raw_parts(component_ptr, component_len); 49 | let (value, advance) = T::from_bytes_unchecked(component_bytes); 50 | 51 | component_offsets[*component_index] += advance; 52 | 53 | *component_index += 1; 54 | 55 | value 56 | } 57 | } 58 | 59 | macro_rules! impl_query_tuple { 60 | ($($query:ident),* $(,)?) => { 61 | impl <$($query: Query),*> Query for ($($query,)*) { 62 | type Item = ($($query::Item),*); 63 | fn add_component_types(types: &mut Vec) { 64 | $( 65 | $query::add_component_types(types); 66 | )* 67 | } 68 | 69 | unsafe fn get_unchecked(data: &QueryData, component_index: &mut usize, component_offsets: &mut [usize]) -> Self::Item { 70 | ( 71 | $( 72 | $query::get_unchecked(data, component_index, component_offsets) 73 | ),* 74 | ) 75 | } 76 | } 77 | } 78 | } 79 | 80 | impl_query_tuple!(A, B); 81 | impl_query_tuple!(A, B, C); 82 | impl_query_tuple!(A, B, C, D); 83 | impl_query_tuple!(A, B, C, D, E); 84 | impl_query_tuple!(A, B, C, D, E, F); 85 | impl_query_tuple!(A, B, C, D, E, F, G); 86 | impl_query_tuple!(A, B, C, D, E, F, G, H); 87 | impl_query_tuple!(A, B, C, D, E, F, G, H, I); 88 | impl_query_tuple!(A, B, C, D, E, F, G, H, I, J); 89 | impl_query_tuple!(A, B, C, D, E, F, G, H, I, J, K); 90 | impl_query_tuple!(A, B, C, D, E, F, G, H, I, J, K, L); 91 | impl_query_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M); 92 | 93 | /// An iterator over all entities matching a query. 94 | pub struct QueryIter { 95 | data: QueryData, 96 | entity_index: usize, 97 | component_offsets: Vec, 98 | _marker: PhantomData, 99 | } 100 | 101 | impl QueryIter 102 | where 103 | Q: Query, 104 | { 105 | pub(crate) fn new() -> Self { 106 | let mut component_types = Vec::new(); 107 | Q::add_component_types(&mut component_types); 108 | 109 | let mut data = MaybeUninit::uninit(); 110 | let data = unsafe { 111 | quill_sys::entity_query( 112 | component_types.as_ptr().into(), 113 | component_types.len() as u32, 114 | PointerMut::new(&mut data), 115 | ); 116 | // SAFETY: `entity_query` initializes `query_data`. 117 | data.assume_init() 118 | }; 119 | 120 | let component_offsets = vec![0; component_types.len()]; 121 | 122 | Self { 123 | data, 124 | entity_index: 0, 125 | component_offsets, 126 | _marker: PhantomData, 127 | } 128 | } 129 | } 130 | 131 | impl Iterator for QueryIter 132 | where 133 | Q: Query, 134 | { 135 | type Item = (Entity, Q::Item); 136 | 137 | fn next(&mut self) -> Option { 138 | if self.entity_index >= self.data.num_entities as usize { 139 | return None; 140 | } 141 | 142 | let components = unsafe { 143 | let mut component_index = 0; 144 | Q::get_unchecked( 145 | &self.data, 146 | &mut component_index, 147 | &mut self.component_offsets, 148 | ) 149 | }; 150 | let entity_id = unsafe { *(self.data.entities_ptr.as_mut_ptr()).add(self.entity_index) }; 151 | let entity = Entity::new(EntityId(entity_id)); 152 | 153 | self.entity_index += 1; 154 | 155 | Some((entity, components)) 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /crates/quill/src/setup.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | 3 | use crate::Game; 4 | 5 | /// Struct passed to your plugin's `enable()` function. 6 | /// 7 | /// Allows you to register systems, etc. 8 | pub struct Setup { 9 | _marker: PhantomData, 10 | } 11 | 12 | impl Setup { 13 | /// For Quill internal use only. Do not call. 14 | #[doc(hidden)] 15 | pub fn new() -> Self { 16 | Self { 17 | _marker: PhantomData, 18 | } 19 | } 20 | 21 | /// Registers a function as system to be invoked 22 | /// every tick. 23 | /// 24 | /// The function should take as parameters your 25 | /// plugin instance and an `&mut Game` and return nothing. 26 | pub fn add_system(&mut self, system: T) -> &mut Self { 27 | let system: Box = Box::new(system); 28 | let system_data = Box::leak(Box::new(system)) as *mut Box<_> as *mut u8; 29 | 30 | let name = std::any::type_name::(); 31 | 32 | unsafe { 33 | quill_sys::register_system(system_data.into(), name.as_ptr().into(), name.len() as u32); 34 | } 35 | 36 | self 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /docs/components.md: -------------------------------------------------------------------------------- 1 | # Components and Queries in Quill 2 | 3 | There are two types of components accessed by a plugin: 4 | * "Plain-old-data" components, typically implementing `Copy`. To transfer these to a plugin, 5 | the raw struct bytes are copied into the plugin's memory, and the plugin gets a pointer to that data. 6 | * Opaque components, i.e., those not implementing `Copy`. These typically hold more data. Examples: `Inventory` of , `Window`. 7 | A plugin accesses these components via host calls without ever getting a copy of the component itself. For example, 8 | to get an item from an inventory, a plugin calls `quill_entity_get_inventory_item`. (The high-level `quill` API wraps 9 | this raw call with an `Inventory` struct, but the struct doesn't actually hold the inventory. It's just a marker.) 10 | -------------------------------------------------------------------------------- /example-plugins/block-access/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "block-access" 3 | version = "0.1.0" 4 | authors = ["caelunshun "] 5 | edition = "2018" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | quill = { path = "../../crates/quill" } -------------------------------------------------------------------------------- /example-plugins/block-access/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! A plugin to demonstrate getting and setting blocks in the world. 2 | 3 | use quill::{entities::Player, BlockState, Game, Plugin, Position}; 4 | 5 | quill::plugin!(BlockAccess); 6 | 7 | pub struct BlockAccess; 8 | 9 | impl Plugin for BlockAccess { 10 | fn enable(_game: &mut quill::Game, setup: &mut quill::Setup) -> Self { 11 | setup.add_system(system); 12 | Self 13 | } 14 | 15 | fn disable(self, _game: &mut quill::Game) {} 16 | } 17 | 18 | fn system(_plugin: &mut BlockAccess, game: &mut Game) { 19 | // Set the blocks each player is standing on 20 | // to bedrock. 21 | for (_entity, (_, pos)) in game.query::<(&Player, &Position)>() { 22 | let block_pos = pos.block(); 23 | 24 | game.set_block(block_pos, BlockState::from_id(33).unwrap()) 25 | .ok(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /example-plugins/block-place/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "block-place" 3 | version = "0.1.0" 4 | authors = ["Amber Kowalski "] 5 | edition = "2018" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | quill = { path = "../../crates/quill" } -------------------------------------------------------------------------------- /example-plugins/block-place/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Allows the user to place blocks. 2 | 3 | use quill::{events::BlockPlacementEvent, Game, Plugin}; 4 | 5 | quill::plugin!(BlockPlace); 6 | 7 | pub struct BlockPlace; 8 | 9 | impl Plugin for BlockPlace { 10 | fn enable(_game: &mut quill::Game, setup: &mut quill::Setup) -> Self { 11 | setup.add_system(system); 12 | Self 13 | } 14 | 15 | fn disable(self, _game: &mut quill::Game) {} 16 | } 17 | 18 | fn system(_plugin: &mut BlockPlace, game: &mut Game) { 19 | for (_entity, _event) in game.query::<&BlockPlacementEvent>() { 20 | println!("A client has placed a block!"); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /example-plugins/particle-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "particle-example" 3 | version = "0.1.0" 4 | authors = ["Gijs de Jong "] 5 | edition = "2018" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | quill = { path = "../../crates/quill" } 12 | -------------------------------------------------------------------------------- /example-plugins/particle-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | use quill::{Game, Particle, ParticleKind, Plugin, Position}; 2 | 3 | quill::plugin!(ParticleExample); 4 | 5 | struct ParticleExample {} 6 | 7 | impl Plugin for ParticleExample { 8 | fn enable(_game: &mut quill::Game, setup: &mut quill::Setup) -> Self { 9 | setup.add_system(particle_system); 10 | 11 | ParticleExample {} 12 | } 13 | 14 | fn disable(self, _game: &mut quill::Game) {} 15 | } 16 | 17 | fn particle_system(_plugin: &mut ParticleExample, game: &mut Game) { 18 | let mut position = Position { 19 | x: 0.0, 20 | y: 65.0, 21 | z: 0.0, 22 | pitch: 0.0, 23 | yaw: 0.0, 24 | }; 25 | 26 | let particle = Particle { 27 | kind: ParticleKind::SoulFireFlame, 28 | offset_x: 0.0, 29 | offset_y: 0.0, 30 | offset_z: 0.0, 31 | count: 1, 32 | }; 33 | 34 | game.spawn_particle(position, particle); 35 | 36 | position.x += 1.0; 37 | 38 | let particle2 = Particle { 39 | kind: ParticleKind::Dust { 40 | red: 1.0, 41 | green: 1.0, 42 | blue: 0.0, 43 | scale: 3.5, 44 | }, 45 | offset_x: 0.0, 46 | offset_y: 0.0, 47 | offset_z: 0.0, 48 | count: 1, 49 | }; 50 | 51 | // Initialise an empty ecs-entity builder 52 | let mut builder = game.create_empty_entity_builder(); 53 | 54 | // Add the required components to display a particle effect 55 | builder.add(position); 56 | builder.add(particle2); 57 | 58 | // Finish the builder, this will spawn the ecs-entity in the ecs-world 59 | builder.finish(); 60 | } 61 | -------------------------------------------------------------------------------- /example-plugins/query-entities/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "query-entities" 3 | version = "0.1.0" 4 | authors = ["Caelum van Ispelen "] 5 | edition = "2018" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | quill = { path = "../../crates/quill" } 12 | rand = "0.8" 13 | -------------------------------------------------------------------------------- /example-plugins/query-entities/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! An example plugin that spawns 10,000 entities 2 | //! on startup, then moves them each tick using a query. 3 | 4 | use quill::{entities::PiglinBrute, EntityInit, Game, Plugin, Position}; 5 | use rand::Rng; 6 | 7 | quill::plugin!(QueryEntities); 8 | 9 | struct QueryEntities { 10 | tick_counter: u64, 11 | } 12 | 13 | impl Plugin for QueryEntities { 14 | fn enable(game: &mut quill::Game, setup: &mut quill::Setup) -> Self { 15 | // Spawn 10,000 piglin brutes 16 | for x in 0..100 { 17 | for z in 0..100 { 18 | let pos = Position { 19 | x: (x - 50) as f64 * 12.0, 20 | y: 64.0, 21 | z: (z - 50) as f64 * 12.0, 22 | pitch: rand::thread_rng().gen_range(30.0..330.0), 23 | yaw: rand::thread_rng().gen_range(0.0..360.0), 24 | }; 25 | game.create_entity_builder(pos, EntityInit::PiglinBrute) 26 | .finish(); 27 | } 28 | } 29 | 30 | setup.add_system(query_system); 31 | 32 | Self { tick_counter: 0 } 33 | } 34 | 35 | fn disable(self, _game: &mut quill::Game) {} 36 | } 37 | 38 | fn query_system(plugin: &mut QueryEntities, game: &mut Game) { 39 | // Make the piglin brutes float into the air. 40 | plugin.tick_counter += 1; 41 | for (entity, (position, _piglin_brute)) in game.query::<(&Position, &PiglinBrute)>() { 42 | // Mutable access to components through queries 43 | // is not yet implemented, so we have to set 44 | // the component directly. 45 | entity.set(Position { 46 | y: position.y + 0.1 * ((plugin.tick_counter as f64 / 20.0).sin() + 1.0), 47 | ..position 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /example-plugins/simple/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "simple-plugin" 3 | version = "0.1.0" 4 | authors = ["caelunshun "] 5 | edition = "2018" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | quill = { path = "../../crates/quill" } 12 | rand = "0.8" 13 | -------------------------------------------------------------------------------- /example-plugins/simple/src/lib.rs: -------------------------------------------------------------------------------- 1 | use quill::{ 2 | components::{CustomName, Name}, 3 | entities::Cow, 4 | EntityInit, Game, Gamemode, Plugin, Position, Setup, Uuid, 5 | }; 6 | use rand::Rng; 7 | 8 | quill::plugin!(SimplePlugin); 9 | 10 | struct SimplePlugin { 11 | tick_counter: u64, 12 | } 13 | 14 | impl Plugin for SimplePlugin { 15 | fn enable(_game: &mut Game, setup: &mut Setup) -> Self { 16 | setup.add_system(test_system); 17 | SimplePlugin { tick_counter: 0 } 18 | } 19 | 20 | fn disable(self, _game: &mut Game) {} 21 | } 22 | 23 | fn test_system(plugin: &mut SimplePlugin, game: &mut Game) { 24 | for (entity, (position, name, gamemode, uuid)) in 25 | game.query::<(&Position, &Name, &Gamemode, &Uuid)>() 26 | { 27 | entity.send_message(format!( 28 | "[{}] Hi {}. Your gamemode is {:?} and your position is {:.1?} and your UUID is {}", 29 | plugin.tick_counter, 30 | name, 31 | gamemode, 32 | position, 33 | uuid.to_hyphenated() 34 | )); 35 | 36 | if plugin.tick_counter % 100 == 0 { 37 | entity.send_message("Spawning a mob on you"); 38 | game.create_entity_builder(position, random_mob()) 39 | .with(CustomName::new("Custom name")) 40 | .finish(); 41 | } 42 | } 43 | for (entity, (position, _cow)) in game.query::<(&Position, &Cow)>() { 44 | entity.set(Position { 45 | y: position.y + 0.1, 46 | ..position 47 | }); 48 | } 49 | plugin.tick_counter += 1; 50 | } 51 | 52 | fn random_mob() -> EntityInit { 53 | let mut entities = vec![ 54 | EntityInit::Zombie, 55 | EntityInit::Piglin, 56 | EntityInit::Zoglin, 57 | EntityInit::Skeleton, 58 | EntityInit::Enderman, 59 | EntityInit::Cow, 60 | ]; 61 | let index = rand::thread_rng().gen_range(0..entities.len()); 62 | entities.remove(index) 63 | } 64 | --------------------------------------------------------------------------------