2022-04-18 10:04:39 +10:00
|
|
|
use std::collections::BTreeSet;
|
|
|
|
|
|
|
|
use heck::{ToPascalCase, ToShoutySnakeCase};
|
|
|
|
use proc_macro2::TokenStream;
|
2022-12-20 01:25:26 +11:00
|
|
|
use quote::{quote, ToTokens};
|
2022-04-18 10:04:39 +10:00
|
|
|
use serde::Deserialize;
|
Reorganize Project (#321)
## Description
- `valence` and `valence_protocol` have been divided into smaller crates
in order to parallelize the build and improve IDE responsiveness. In the
process, code architecture has been made clearer by removing circular
dependencies between modules. `valence` is now just a shell around the
other crates.
- `workspace.packages` and `workspace.dependencies` are now used. This
makes dependency managements and crate configuration much easier.
- `valence_protocol` is no more. Most things from `valence_protocol`
ended up in `valence_core`. We won't advertise `valence_core` as a
general-purpose protocol library since it contains too much
valence-specific stuff. Closes #308.
- Networking code (login, initial TCP connection handling, etc.) has
been extracted into the `valence_network` crate. The API has been
expanded and improved with better defaults. Player counts and initial
connections to the server are now tracked separately. Player counts
function by default without any user configuration.
- Some crates like `valence_anvil`, `valence_network`,
`valence_player_list`, `valence_inventory`, etc. are now optional. They
can be enabled/disabled with feature flags and `DefaultPlugins` just
like bevy.
- Whole-server unit tests have been moved to `valence/src/tests` in
order to avoid [cyclic
dev-dependencies](https://github.com/rust-lang/cargo/issues/4242).
- Tools like `valence_stresser` and `packet_inspector` have been moved
to a new `tools` directory. Renamed `valence_stresser` to `stresser`.
Closes #241.
- Moved all benches to `valence/benches/` to make them easier to run and
organize.
Ignoring transitive dependencies and `valence_core`, here's what the
dependency graph looks like now:
```mermaid
graph TD
network --> client
client --> instance
biome --> registry
dimension --> registry
instance --> biome
instance --> dimension
instance --> entity
player_list --> client
inventory --> client
anvil --> instance
entity --> block
```
### Issues
- Inventory tests inspect many private implementation details of the
inventory module, forcing us to mark things as `pub` and
`#[doc(hidden)]`. It would be ideal if the tests only looked at
observable behavior.
- Consider moving packets in `valence_core` elsewhere. `Particle` wants
to use `BlockState`, but that's defined in `valence_block`, so we can't
use it without causing cycles.
- Unsure what exactly should go in `valence::prelude`.
- This could use some more tests of course, but I'm holding off on that
until I'm confident this is the direction we want to take things.
## TODOs
- [x] Update examples.
- [x] Update benches.
- [x] Update main README.
- [x] Add short READMEs to crates.
- [x] Test new schedule to ensure behavior is the same.
- [x] Update tools.
- [x] Copy lints to all crates.
- [x] Fix docs, clippy, etc.
2023-04-22 07:43:59 +10:00
|
|
|
use valence_build_utils::{ident, rerun_if_changed, write_generated_file};
|
2022-04-18 10:04:39 +10:00
|
|
|
|
2022-07-29 01:15:23 +10:00
|
|
|
#[derive(Deserialize, Clone, Debug)]
|
|
|
|
struct TopLevel {
|
|
|
|
blocks: Vec<Block>,
|
2022-08-07 09:46:07 +10:00
|
|
|
shapes: Vec<Shape>,
|
2023-02-19 05:16:01 +11:00
|
|
|
block_entity_types: Vec<BlockEntityKind>,
|
2022-07-29 01:15:23 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize, Clone, Debug)]
|
|
|
|
struct Block {
|
|
|
|
id: u16,
|
2022-10-06 03:28:08 +11:00
|
|
|
item_id: u16,
|
2023-02-24 16:21:27 +11:00
|
|
|
wall_variant_id: Option<u16>,
|
2022-07-29 01:15:23 +10:00
|
|
|
translation_key: String,
|
|
|
|
name: String,
|
|
|
|
properties: Vec<Property>,
|
|
|
|
default_state_id: u16,
|
|
|
|
states: Vec<State>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Block {
|
|
|
|
pub fn min_state_id(&self) -> u16 {
|
|
|
|
self.states.iter().map(|s| s.id).min().unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn max_state_id(&self) -> u16 {
|
|
|
|
self.states.iter().map(|s| s.id).max().unwrap()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-19 05:16:01 +11:00
|
|
|
#[derive(Deserialize, Clone, Debug)]
|
|
|
|
struct BlockEntityKind {
|
|
|
|
id: u32,
|
|
|
|
ident: String,
|
|
|
|
name: String,
|
|
|
|
}
|
|
|
|
|
2022-07-29 01:15:23 +10:00
|
|
|
#[derive(Deserialize, Clone, Debug)]
|
|
|
|
struct Property {
|
|
|
|
name: String,
|
|
|
|
values: Vec<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize, Clone, Debug)]
|
|
|
|
struct State {
|
|
|
|
id: u16,
|
|
|
|
luminance: u8,
|
|
|
|
opaque: bool,
|
2022-10-16 21:50:57 +11:00
|
|
|
replaceable: bool,
|
2022-07-29 01:15:23 +10:00
|
|
|
collision_shapes: Vec<u16>,
|
2023-02-19 05:16:01 +11:00
|
|
|
block_entity_type: Option<u32>,
|
2022-07-29 01:15:23 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize, Clone, Debug)]
|
2022-08-07 09:46:07 +10:00
|
|
|
struct Shape {
|
2022-07-29 01:15:23 +10:00
|
|
|
min_x: f64,
|
|
|
|
min_y: f64,
|
|
|
|
min_z: f64,
|
|
|
|
max_x: f64,
|
|
|
|
max_y: f64,
|
|
|
|
max_z: f64,
|
|
|
|
}
|
|
|
|
|
Reorganize Project (#321)
## Description
- `valence` and `valence_protocol` have been divided into smaller crates
in order to parallelize the build and improve IDE responsiveness. In the
process, code architecture has been made clearer by removing circular
dependencies between modules. `valence` is now just a shell around the
other crates.
- `workspace.packages` and `workspace.dependencies` are now used. This
makes dependency managements and crate configuration much easier.
- `valence_protocol` is no more. Most things from `valence_protocol`
ended up in `valence_core`. We won't advertise `valence_core` as a
general-purpose protocol library since it contains too much
valence-specific stuff. Closes #308.
- Networking code (login, initial TCP connection handling, etc.) has
been extracted into the `valence_network` crate. The API has been
expanded and improved with better defaults. Player counts and initial
connections to the server are now tracked separately. Player counts
function by default without any user configuration.
- Some crates like `valence_anvil`, `valence_network`,
`valence_player_list`, `valence_inventory`, etc. are now optional. They
can be enabled/disabled with feature flags and `DefaultPlugins` just
like bevy.
- Whole-server unit tests have been moved to `valence/src/tests` in
order to avoid [cyclic
dev-dependencies](https://github.com/rust-lang/cargo/issues/4242).
- Tools like `valence_stresser` and `packet_inspector` have been moved
to a new `tools` directory. Renamed `valence_stresser` to `stresser`.
Closes #241.
- Moved all benches to `valence/benches/` to make them easier to run and
organize.
Ignoring transitive dependencies and `valence_core`, here's what the
dependency graph looks like now:
```mermaid
graph TD
network --> client
client --> instance
biome --> registry
dimension --> registry
instance --> biome
instance --> dimension
instance --> entity
player_list --> client
inventory --> client
anvil --> instance
entity --> block
```
### Issues
- Inventory tests inspect many private implementation details of the
inventory module, forcing us to mark things as `pub` and
`#[doc(hidden)]`. It would be ideal if the tests only looked at
observable behavior.
- Consider moving packets in `valence_core` elsewhere. `Particle` wants
to use `BlockState`, but that's defined in `valence_block`, so we can't
use it without causing cycles.
- Unsure what exactly should go in `valence::prelude`.
- This could use some more tests of course, but I'm holding off on that
until I'm confident this is the direction we want to take things.
## TODOs
- [x] Update examples.
- [x] Update benches.
- [x] Update main README.
- [x] Add short READMEs to crates.
- [x] Test new schedule to ensure behavior is the same.
- [x] Update tools.
- [x] Copy lints to all crates.
- [x] Fix docs, clippy, etc.
2023-04-22 07:43:59 +10:00
|
|
|
pub fn main() -> anyhow::Result<()> {
|
|
|
|
rerun_if_changed(["../../extracted/blocks.json"]);
|
|
|
|
|
|
|
|
write_generated_file(build()?, "block.rs")
|
|
|
|
}
|
|
|
|
|
|
|
|
fn build() -> anyhow::Result<TokenStream> {
|
2023-02-19 05:16:01 +11:00
|
|
|
let TopLevel {
|
|
|
|
blocks,
|
|
|
|
shapes,
|
|
|
|
block_entity_types,
|
Reorganize Project (#321)
## Description
- `valence` and `valence_protocol` have been divided into smaller crates
in order to parallelize the build and improve IDE responsiveness. In the
process, code architecture has been made clearer by removing circular
dependencies between modules. `valence` is now just a shell around the
other crates.
- `workspace.packages` and `workspace.dependencies` are now used. This
makes dependency managements and crate configuration much easier.
- `valence_protocol` is no more. Most things from `valence_protocol`
ended up in `valence_core`. We won't advertise `valence_core` as a
general-purpose protocol library since it contains too much
valence-specific stuff. Closes #308.
- Networking code (login, initial TCP connection handling, etc.) has
been extracted into the `valence_network` crate. The API has been
expanded and improved with better defaults. Player counts and initial
connections to the server are now tracked separately. Player counts
function by default without any user configuration.
- Some crates like `valence_anvil`, `valence_network`,
`valence_player_list`, `valence_inventory`, etc. are now optional. They
can be enabled/disabled with feature flags and `DefaultPlugins` just
like bevy.
- Whole-server unit tests have been moved to `valence/src/tests` in
order to avoid [cyclic
dev-dependencies](https://github.com/rust-lang/cargo/issues/4242).
- Tools like `valence_stresser` and `packet_inspector` have been moved
to a new `tools` directory. Renamed `valence_stresser` to `stresser`.
Closes #241.
- Moved all benches to `valence/benches/` to make them easier to run and
organize.
Ignoring transitive dependencies and `valence_core`, here's what the
dependency graph looks like now:
```mermaid
graph TD
network --> client
client --> instance
biome --> registry
dimension --> registry
instance --> biome
instance --> dimension
instance --> entity
player_list --> client
inventory --> client
anvil --> instance
entity --> block
```
### Issues
- Inventory tests inspect many private implementation details of the
inventory module, forcing us to mark things as `pub` and
`#[doc(hidden)]`. It would be ideal if the tests only looked at
observable behavior.
- Consider moving packets in `valence_core` elsewhere. `Particle` wants
to use `BlockState`, but that's defined in `valence_block`, so we can't
use it without causing cycles.
- Unsure what exactly should go in `valence::prelude`.
- This could use some more tests of course, but I'm holding off on that
until I'm confident this is the direction we want to take things.
## TODOs
- [x] Update examples.
- [x] Update benches.
- [x] Update main README.
- [x] Add short READMEs to crates.
- [x] Test new schedule to ensure behavior is the same.
- [x] Update tools.
- [x] Copy lints to all crates.
- [x] Fix docs, clippy, etc.
2023-04-22 07:43:59 +10:00
|
|
|
} = serde_json::from_str(include_str!("../../extracted/blocks.json"))?;
|
2022-04-18 10:04:39 +10:00
|
|
|
|
2022-07-29 01:15:23 +10:00
|
|
|
let max_state_id = blocks.iter().map(|b| b.max_state_id()).max().unwrap();
|
2022-04-18 10:04:39 +10:00
|
|
|
|
2022-08-07 09:50:50 +10:00
|
|
|
let kind_to_translation_key_arms = blocks
|
|
|
|
.iter()
|
|
|
|
.map(|b| {
|
2023-04-28 21:53:10 +10:00
|
|
|
let kind = ident(b.name.replace('.', "_").to_pascal_case());
|
2022-08-07 09:50:50 +10:00
|
|
|
let translation_key = &b.translation_key;
|
|
|
|
quote! {
|
|
|
|
Self::#kind => #translation_key,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
2022-07-29 01:15:23 +10:00
|
|
|
let state_to_kind_arms = blocks
|
2022-04-18 10:04:39 +10:00
|
|
|
.iter()
|
|
|
|
.map(|b| {
|
2023-04-28 21:53:10 +10:00
|
|
|
let name = ident(b.name.replace('.', "_").to_pascal_case());
|
2022-12-20 01:25:26 +11:00
|
|
|
let mut token_stream = TokenStream::new();
|
|
|
|
|
|
|
|
let min_id = b.min_state_id();
|
|
|
|
let max_id = b.max_state_id();
|
|
|
|
|
|
|
|
if min_id == max_id {
|
|
|
|
quote!(#min_id).to_tokens(&mut token_stream);
|
|
|
|
} else {
|
|
|
|
for id in min_id..max_id {
|
|
|
|
quote!(#id | ).to_tokens(&mut token_stream);
|
|
|
|
}
|
|
|
|
quote!(#max_id).to_tokens(&mut token_stream);
|
2022-04-18 10:04:39 +10:00
|
|
|
}
|
2022-12-20 01:25:26 +11:00
|
|
|
quote!(=> BlockKind::#name,).to_tokens(&mut token_stream);
|
|
|
|
token_stream
|
2022-04-18 10:04:39 +10:00
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
2022-08-07 09:46:07 +10:00
|
|
|
let state_to_luminance_arms = blocks
|
|
|
|
.iter()
|
|
|
|
.flat_map(|b| {
|
|
|
|
b.states.iter().filter(|s| s.luminance != 0).map(|s| {
|
|
|
|
let id = s.id;
|
|
|
|
let luminance = s.luminance;
|
|
|
|
quote! {
|
|
|
|
#id => #luminance,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
|
|
|
let state_to_opaque_arms = blocks
|
|
|
|
.iter()
|
|
|
|
.flat_map(|b| {
|
|
|
|
b.states.iter().filter(|s| !s.opaque).map(|s| {
|
|
|
|
let id = s.id;
|
|
|
|
quote! {
|
|
|
|
#id => false,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
2022-10-16 21:50:57 +11:00
|
|
|
let state_to_replaceable_arms = blocks
|
|
|
|
.iter()
|
|
|
|
.flat_map(|b| {
|
|
|
|
b.states.iter().filter(|s| s.replaceable).map(|s| {
|
|
|
|
let id = s.id;
|
|
|
|
quote! {
|
|
|
|
#id => true,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
2022-08-07 09:46:07 +10:00
|
|
|
let shapes = shapes.iter().map(|s| {
|
|
|
|
let min_x = s.min_x;
|
|
|
|
let min_y = s.min_y;
|
|
|
|
let min_z = s.min_z;
|
|
|
|
let max_x = s.max_x;
|
|
|
|
let max_y = s.max_y;
|
|
|
|
let max_z = s.max_z;
|
|
|
|
quote! {
|
Use a struct to store block collision shapes (#334)
## Description
Created a new CollisionShape struct for blocks (was previously an [f64;
6]).
## Test Plan
Explain the steps necessary to test your changes. If you used a
playground, include the code in the details below.
Steps:
1. Run the following code
<details>
<summary>Playground</summary>
```rust
use valence_block;
fn main() {
let shapes = valence_block::BlockState::STONE.collision_shapes();
println!("{:?}", shapes.collect::<Vec<_>>());
// [CollisionShape { min_x: 0.0, min_y: 0.0, min_z: 0.0, max_x: 1.0, max_y: 1.0, max_z: 1.0 }]
let shapes = valence_block::BlockState::OAK_STAIRS.collision_shapes();
println!("{:?}", shapes.collect::<Vec<_>>());
// [CollisionShape { min_x: 0.0, min_y: 0.0, min_z: 0.0, max_x: 1.0, max_y: 0.5, max_z: 1.0 }, CollisionShape { min_x: 0.0, min_y: 0.5, min_z: 0.0, max_x: 1.0, max_y: 1.0, max_z: 0.5 }]
}
```
</details>
2023-05-22 18:29:59 +10:00
|
|
|
Aabb {
|
|
|
|
min: dvec3(#min_x, #min_y, #min_z),
|
|
|
|
max: dvec3(#max_x, #max_y, #max_z),
|
|
|
|
}
|
2022-08-07 09:46:07 +10:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
let shape_count = shapes.len();
|
|
|
|
|
|
|
|
let state_to_collision_shapes_arms = blocks
|
|
|
|
.iter()
|
|
|
|
.flat_map(|b| {
|
|
|
|
b.states.iter().map(|s| {
|
|
|
|
let id = s.id;
|
|
|
|
let collision_shapes = &s.collision_shapes;
|
|
|
|
quote! {
|
|
|
|
#id => &[#(#collision_shapes),*],
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
2022-04-18 10:04:39 +10:00
|
|
|
let get_arms = blocks
|
|
|
|
.iter()
|
2022-07-29 01:15:23 +10:00
|
|
|
.filter(|&b| !b.properties.is_empty())
|
2022-04-18 10:04:39 +10:00
|
|
|
.map(|b| {
|
2023-04-28 21:53:10 +10:00
|
|
|
let block_kind_name = ident(b.name.replace('.', "_").to_pascal_case());
|
2022-04-18 10:04:39 +10:00
|
|
|
|
|
|
|
let arms = b
|
2022-07-29 01:15:23 +10:00
|
|
|
.properties
|
2022-04-18 10:04:39 +10:00
|
|
|
.iter()
|
|
|
|
.map(|p| {
|
2023-04-28 21:53:10 +10:00
|
|
|
let prop_name = ident(p.name.replace('.', "_").to_pascal_case());
|
2022-07-29 01:15:23 +10:00
|
|
|
let min_state_id = b.min_state_id();
|
2022-04-18 10:04:39 +10:00
|
|
|
let product: u16 = b
|
2022-07-29 01:15:23 +10:00
|
|
|
.properties
|
2022-04-18 10:04:39 +10:00
|
|
|
.iter()
|
2022-07-29 01:15:23 +10:00
|
|
|
.rev()
|
2022-04-18 10:04:39 +10:00
|
|
|
.take_while(|&other| p.name != other.name)
|
2022-07-29 01:15:23 +10:00
|
|
|
.map(|p| p.values.len() as u16)
|
2022-04-18 10:04:39 +10:00
|
|
|
.product();
|
|
|
|
|
2022-07-29 01:15:23 +10:00
|
|
|
let values_count = p.values.len() as u16;
|
2022-04-18 10:04:39 +10:00
|
|
|
|
2022-07-29 01:15:23 +10:00
|
|
|
let arms = p.values.iter().enumerate().map(|(i, v)| {
|
2022-04-18 10:04:39 +10:00
|
|
|
let value_idx = i as u16;
|
2023-04-28 21:53:10 +10:00
|
|
|
let value_name = ident(v.replace('.', "_").to_pascal_case());
|
2022-04-18 10:04:39 +10:00
|
|
|
quote! {
|
|
|
|
#value_idx => Some(PropValue::#value_name),
|
|
|
|
}
|
|
|
|
}).collect::<TokenStream>();
|
|
|
|
|
|
|
|
quote! {
|
2022-04-29 17:48:41 +10:00
|
|
|
PropName::#prop_name => match (self.0 - #min_state_id) / #product % #values_count {
|
2022-04-18 10:04:39 +10:00
|
|
|
#arms
|
|
|
|
_ => unreachable!(),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
|
|
|
quote! {
|
2022-07-29 01:15:23 +10:00
|
|
|
BlockKind::#block_kind_name => match name {
|
2022-04-18 10:04:39 +10:00
|
|
|
#arms
|
|
|
|
_ => None,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
|
|
|
let set_arms = blocks
|
|
|
|
.iter()
|
2022-07-29 01:15:23 +10:00
|
|
|
.filter(|&b| !b.properties.is_empty())
|
2022-04-18 10:04:39 +10:00
|
|
|
.map(|b| {
|
2023-04-28 21:53:10 +10:00
|
|
|
let block_kind_name = ident(b.name.replace('.', "_").to_pascal_case());
|
2022-04-18 10:04:39 +10:00
|
|
|
|
|
|
|
let arms = b
|
2022-07-29 01:15:23 +10:00
|
|
|
.properties
|
2022-04-18 10:04:39 +10:00
|
|
|
.iter()
|
|
|
|
.map(|p| {
|
2023-04-28 21:53:10 +10:00
|
|
|
let prop_name = ident(p.name.replace('.', "_").to_pascal_case());
|
2022-07-29 01:15:23 +10:00
|
|
|
let min_state_id = b.min_state_id();
|
2022-04-18 10:04:39 +10:00
|
|
|
let product: u16 = b
|
2022-07-29 01:15:23 +10:00
|
|
|
.properties
|
2022-04-18 10:04:39 +10:00
|
|
|
.iter()
|
2022-07-29 01:15:23 +10:00
|
|
|
.rev()
|
2022-04-18 10:04:39 +10:00
|
|
|
.take_while(|&other| p.name != other.name)
|
2022-07-29 01:15:23 +10:00
|
|
|
.map(|p| p.values.len() as u16)
|
2022-04-18 10:04:39 +10:00
|
|
|
.product();
|
|
|
|
|
2022-07-29 01:15:23 +10:00
|
|
|
let values_count = p.values.len() as u16;
|
2022-04-18 10:04:39 +10:00
|
|
|
|
|
|
|
let arms = p
|
2022-07-29 01:15:23 +10:00
|
|
|
.values
|
2022-04-18 10:04:39 +10:00
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(i, v)| {
|
|
|
|
let val_idx = i as u16;
|
2023-04-28 21:53:10 +10:00
|
|
|
let val_name = ident(v.replace('.', "_").to_pascal_case());
|
2022-04-18 10:04:39 +10:00
|
|
|
quote! {
|
|
|
|
PropValue::#val_name =>
|
2022-04-29 17:48:41 +10:00
|
|
|
Self(self.0 - (self.0 - #min_state_id) / #product % #values_count * #product
|
2022-04-18 10:04:39 +10:00
|
|
|
+ #val_idx * #product),
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
|
|
|
quote! {
|
|
|
|
PropName::#prop_name => match val {
|
|
|
|
#arms
|
|
|
|
_ => self,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
|
|
|
quote! {
|
2022-07-29 01:15:23 +10:00
|
|
|
BlockKind::#block_kind_name => match name {
|
2022-04-18 10:04:39 +10:00
|
|
|
#arms
|
|
|
|
_ => self,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
|
|
|
let default_block_states = blocks
|
|
|
|
.iter()
|
|
|
|
.map(|b| {
|
2023-04-28 21:53:10 +10:00
|
|
|
let name = ident(b.name.replace('.', "_").to_shouty_snake_case());
|
2022-07-29 01:15:23 +10:00
|
|
|
let state = b.default_state_id;
|
2022-04-18 10:04:39 +10:00
|
|
|
let doc = format!("The default block state for `{}`.", b.name);
|
|
|
|
quote! {
|
|
|
|
#[doc = #doc]
|
|
|
|
pub const #name: BlockState = BlockState(#state);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
2023-02-24 16:21:27 +11:00
|
|
|
let state_to_wall_variant_arms = blocks
|
|
|
|
.iter()
|
|
|
|
.filter(|b| b.wall_variant_id.is_some())
|
|
|
|
.map(|b| {
|
2023-04-28 21:53:10 +10:00
|
|
|
let block_name = ident(b.name.replace('.', "_").to_shouty_snake_case());
|
2023-02-24 16:21:27 +11:00
|
|
|
let wall_block_name = ident(
|
|
|
|
blocks[b.wall_variant_id.unwrap() as usize]
|
|
|
|
.name
|
2023-04-28 21:53:10 +10:00
|
|
|
.replace('.', "_")
|
2023-02-24 16:21:27 +11:00
|
|
|
.to_shouty_snake_case(),
|
|
|
|
);
|
|
|
|
quote! {
|
|
|
|
BlockState::#block_name => Some(BlockState::#wall_block_name),
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
2023-02-19 05:16:01 +11:00
|
|
|
let state_to_block_entity_type_arms = blocks
|
|
|
|
.iter()
|
|
|
|
.flat_map(|b| {
|
|
|
|
b.states.iter().filter_map(|s| {
|
|
|
|
let id = s.id;
|
|
|
|
let block_entity_type = s.block_entity_type?;
|
|
|
|
Some(quote! {
|
|
|
|
#id => Some(#block_entity_type),
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
2022-07-29 01:15:23 +10:00
|
|
|
let kind_to_state_arms = blocks
|
2022-04-18 10:04:39 +10:00
|
|
|
.iter()
|
|
|
|
.map(|b| {
|
2023-04-28 21:53:10 +10:00
|
|
|
let kind = ident(b.name.replace('.', "_").to_pascal_case());
|
|
|
|
let state = ident(b.name.replace('.', "_").to_shouty_snake_case());
|
2022-04-18 10:04:39 +10:00
|
|
|
quote! {
|
2022-07-06 12:21:52 +10:00
|
|
|
BlockKind::#kind => BlockState::#state,
|
2022-04-18 10:04:39 +10:00
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
2022-07-06 12:21:52 +10:00
|
|
|
let block_kind_variants = blocks
|
2022-04-18 10:04:39 +10:00
|
|
|
.iter()
|
2023-04-28 21:53:10 +10:00
|
|
|
.map(|b| ident(b.name.replace('.', "_").to_pascal_case()))
|
2022-04-18 10:04:39 +10:00
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
2022-07-06 12:21:52 +10:00
|
|
|
let block_kind_from_str_arms = blocks
|
2022-04-18 10:04:39 +10:00
|
|
|
.iter()
|
|
|
|
.map(|b| {
|
|
|
|
let name = &b.name;
|
2023-04-28 21:53:10 +10:00
|
|
|
let name_ident = ident(name.replace('.', "_").to_pascal_case());
|
2022-04-18 10:04:39 +10:00
|
|
|
quote! {
|
2022-07-06 12:21:52 +10:00
|
|
|
#name => Some(BlockKind::#name_ident),
|
2022-04-18 10:04:39 +10:00
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
2022-07-06 12:21:52 +10:00
|
|
|
let block_kind_to_str_arms = blocks
|
2022-04-18 10:04:39 +10:00
|
|
|
.iter()
|
|
|
|
.map(|b| {
|
|
|
|
let name = &b.name;
|
2023-04-28 21:53:10 +10:00
|
|
|
let name_ident = ident(name.replace('.', "_").to_pascal_case());
|
2022-04-18 10:04:39 +10:00
|
|
|
quote! {
|
2022-07-06 12:21:52 +10:00
|
|
|
BlockKind::#name_ident => #name,
|
2022-04-18 10:04:39 +10:00
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
2022-07-06 12:21:52 +10:00
|
|
|
let block_kind_props_arms = blocks
|
2022-04-18 10:04:39 +10:00
|
|
|
.iter()
|
2022-07-29 01:15:23 +10:00
|
|
|
.filter(|&b| !b.properties.is_empty())
|
2022-04-18 10:04:39 +10:00
|
|
|
.map(|b| {
|
2023-04-28 21:53:10 +10:00
|
|
|
let name = ident(b.name.replace('.', "_").to_pascal_case());
|
|
|
|
let prop_names = b
|
|
|
|
.properties
|
|
|
|
.iter()
|
|
|
|
.map(|p| ident(p.name.replace('.', "_").to_pascal_case()));
|
2022-04-18 10:04:39 +10:00
|
|
|
|
|
|
|
quote! {
|
|
|
|
Self::#name => &[#(PropName::#prop_names,)*],
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
2022-10-06 03:28:08 +11:00
|
|
|
let block_kind_to_item_kind_arms = blocks
|
|
|
|
.iter()
|
|
|
|
.map(|block| {
|
2023-04-28 21:53:10 +10:00
|
|
|
let name = ident(block.name.replace('.', "_").to_pascal_case());
|
2022-10-06 03:28:08 +11:00
|
|
|
let item_id = block.item_id;
|
|
|
|
|
|
|
|
quote! {
|
|
|
|
BlockKind::#name => #item_id,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
|
|
|
let block_kind_from_item_kind_arms = blocks
|
|
|
|
.iter()
|
|
|
|
.filter(|block| block.item_id != 0)
|
|
|
|
.map(|block| {
|
2023-04-28 21:53:10 +10:00
|
|
|
let name = ident(block.name.replace('.', "_").to_pascal_case());
|
2022-10-06 03:28:08 +11:00
|
|
|
let item_id = block.item_id;
|
|
|
|
|
|
|
|
quote! {
|
|
|
|
#item_id => Some(BlockKind::#name),
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
2022-12-31 01:18:24 +11:00
|
|
|
let block_kind_from_raw_arms = blocks
|
|
|
|
.iter()
|
|
|
|
.map(|block| {
|
2023-04-28 21:53:10 +10:00
|
|
|
let name = ident(block.name.replace('.', "_").to_pascal_case());
|
2022-12-31 01:18:24 +11:00
|
|
|
let id = block.id;
|
|
|
|
|
|
|
|
quote! {
|
|
|
|
#id => Some(BlockKind::#name),
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
2023-02-19 05:16:01 +11:00
|
|
|
let block_entity_kind_variants = block_entity_types
|
|
|
|
.iter()
|
|
|
|
.map(|block_entity| {
|
2023-04-28 21:53:10 +10:00
|
|
|
let name = ident(block_entity.name.replace('.', "_").to_pascal_case());
|
2023-02-19 05:16:01 +11:00
|
|
|
let doc = format!(
|
|
|
|
"The block entity type `{}` (ID {}).",
|
|
|
|
block_entity.name, block_entity.id
|
|
|
|
);
|
|
|
|
quote! {
|
|
|
|
#[doc = #doc]
|
|
|
|
#name,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
|
|
|
let block_entity_kind_from_id_arms = block_entity_types
|
|
|
|
.iter()
|
|
|
|
.map(|block_entity| {
|
|
|
|
let id = block_entity.id;
|
2023-04-28 21:53:10 +10:00
|
|
|
let name = ident(block_entity.name.replace('.', "_").to_pascal_case());
|
2023-02-19 05:16:01 +11:00
|
|
|
|
|
|
|
quote! {
|
|
|
|
#id => Some(Self::#name),
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
|
|
|
let block_entity_kind_to_id_arms = block_entity_types
|
|
|
|
.iter()
|
|
|
|
.map(|block_entity| {
|
|
|
|
let id = block_entity.id;
|
2023-04-28 21:53:10 +10:00
|
|
|
let name = ident(block_entity.name.replace('.', "_").to_pascal_case());
|
2023-02-19 05:16:01 +11:00
|
|
|
|
|
|
|
quote! {
|
|
|
|
Self::#name => #id,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
|
|
|
let block_entity_kind_from_ident_arms = block_entity_types
|
|
|
|
.iter()
|
|
|
|
.map(|block_entity| {
|
2023-04-28 21:53:10 +10:00
|
|
|
let name = ident(block_entity.name.replace('.', "_").to_pascal_case());
|
2023-02-19 05:16:01 +11:00
|
|
|
let ident = &block_entity.ident;
|
|
|
|
|
|
|
|
quote! {
|
|
|
|
#ident => Some(Self::#name),
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
|
|
|
let block_entity_kind_to_ident_arms = block_entity_types
|
|
|
|
.iter()
|
|
|
|
.map(|block_entity| {
|
2023-04-28 21:53:10 +10:00
|
|
|
let name = ident(block_entity.name.replace('.', "_").to_pascal_case());
|
2023-02-19 05:16:01 +11:00
|
|
|
let ident = &block_entity.ident;
|
|
|
|
|
|
|
|
quote! {
|
2023-04-01 08:58:47 +11:00
|
|
|
Self::#name => ident!(#ident),
|
2023-02-19 05:16:01 +11:00
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
2022-07-06 12:21:52 +10:00
|
|
|
let block_kind_count = blocks.len();
|
2022-04-18 10:04:39 +10:00
|
|
|
|
|
|
|
let prop_names = blocks
|
|
|
|
.iter()
|
2022-07-29 01:15:23 +10:00
|
|
|
.flat_map(|b| b.properties.iter().map(|p| p.name.as_str()))
|
2022-04-18 10:04:39 +10:00
|
|
|
.collect::<BTreeSet<_>>();
|
|
|
|
|
|
|
|
let prop_name_variants = prop_names
|
|
|
|
.iter()
|
2023-04-28 21:53:10 +10:00
|
|
|
.map(|&name| ident(name.replace('.', "_").to_pascal_case()))
|
2022-04-18 10:04:39 +10:00
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
let prop_name_from_str_arms = prop_names
|
|
|
|
.iter()
|
|
|
|
.map(|&name| {
|
2023-04-28 21:53:10 +10:00
|
|
|
let ident = ident(name.replace('.', "_").to_pascal_case());
|
2022-04-18 10:04:39 +10:00
|
|
|
quote! {
|
|
|
|
#name => Some(PropName::#ident),
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
|
|
|
let prop_name_to_str_arms = prop_names
|
|
|
|
.iter()
|
|
|
|
.map(|&name| {
|
2023-04-28 21:53:10 +10:00
|
|
|
let ident = ident(name.replace('.', "_").to_pascal_case());
|
2022-04-18 10:04:39 +10:00
|
|
|
quote! {
|
|
|
|
PropName::#ident => #name,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
2022-04-29 17:48:41 +10:00
|
|
|
let prop_name_count = prop_names.len();
|
2022-04-18 10:04:39 +10:00
|
|
|
|
|
|
|
let prop_values = blocks
|
|
|
|
.iter()
|
2022-07-29 01:15:23 +10:00
|
|
|
.flat_map(|b| b.properties.iter().flat_map(|p| &p.values))
|
|
|
|
.map(|s| s.as_str())
|
2022-04-18 10:04:39 +10:00
|
|
|
.collect::<BTreeSet<_>>();
|
|
|
|
|
|
|
|
let prop_value_variants = prop_values
|
|
|
|
.iter()
|
2023-04-28 21:53:10 +10:00
|
|
|
.map(|val| ident(val.replace('.', "_").to_pascal_case()))
|
2022-04-18 10:04:39 +10:00
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
let prop_value_from_str_arms = prop_values
|
|
|
|
.iter()
|
|
|
|
.map(|val| {
|
2023-04-28 21:53:10 +10:00
|
|
|
let ident = ident(val.replace('.', "_").to_pascal_case());
|
2022-04-18 10:04:39 +10:00
|
|
|
quote! {
|
|
|
|
#val => Some(PropValue::#ident),
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
|
|
|
let prop_value_to_str_arms = prop_values
|
|
|
|
.iter()
|
|
|
|
.map(|val| {
|
2023-04-28 21:53:10 +10:00
|
|
|
let ident = ident(val.replace('.', "_").to_pascal_case());
|
2022-04-18 10:04:39 +10:00
|
|
|
quote! {
|
|
|
|
PropValue::#ident => #val,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
|
|
|
let prop_value_from_u16_arms = prop_values
|
|
|
|
.iter()
|
|
|
|
.filter_map(|v| v.parse::<u16>().ok())
|
|
|
|
.map(|n| {
|
|
|
|
let ident = ident(n.to_string());
|
|
|
|
quote! {
|
|
|
|
#n => Some(PropValue::#ident),
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
|
|
|
let prop_value_to_u16_arms = prop_values
|
|
|
|
.iter()
|
|
|
|
.filter_map(|v| v.parse::<u16>().ok())
|
|
|
|
.map(|n| {
|
|
|
|
let ident = ident(n.to_string());
|
|
|
|
quote! {
|
|
|
|
PropValue::#ident => Some(#n),
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<TokenStream>();
|
|
|
|
|
2022-07-29 01:15:23 +10:00
|
|
|
let prop_value_count = prop_values.len();
|
2022-04-18 10:04:39 +10:00
|
|
|
|
2022-07-28 00:10:35 +10:00
|
|
|
Ok(quote! {
|
Use a struct to store block collision shapes (#334)
## Description
Created a new CollisionShape struct for blocks (was previously an [f64;
6]).
## Test Plan
Explain the steps necessary to test your changes. If you used a
playground, include the code in the details below.
Steps:
1. Run the following code
<details>
<summary>Playground</summary>
```rust
use valence_block;
fn main() {
let shapes = valence_block::BlockState::STONE.collision_shapes();
println!("{:?}", shapes.collect::<Vec<_>>());
// [CollisionShape { min_x: 0.0, min_y: 0.0, min_z: 0.0, max_x: 1.0, max_y: 1.0, max_z: 1.0 }]
let shapes = valence_block::BlockState::OAK_STAIRS.collision_shapes();
println!("{:?}", shapes.collect::<Vec<_>>());
// [CollisionShape { min_x: 0.0, min_y: 0.0, min_z: 0.0, max_x: 1.0, max_y: 0.5, max_z: 1.0 }, CollisionShape { min_x: 0.0, min_y: 0.5, min_z: 0.0, max_x: 1.0, max_y: 1.0, max_z: 0.5 }]
}
```
</details>
2023-05-22 18:29:59 +10:00
|
|
|
use valence_core::aabb::Aabb;
|
|
|
|
use glam::dvec3;
|
|
|
|
|
2022-07-29 01:15:23 +10:00
|
|
|
/// Represents the state of a block. This does not include block entity data such as
|
2022-04-18 10:04:39 +10:00
|
|
|
/// the text on a sign, the design on a banner, or the content of a spawner.
|
2022-04-18 17:34:12 +10:00
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
|
2022-04-18 10:04:39 +10:00
|
|
|
pub struct BlockState(u16);
|
|
|
|
|
|
|
|
impl BlockState {
|
|
|
|
/// Returns the default block state for a given block type.
|
2022-07-06 12:21:52 +10:00
|
|
|
pub const fn from_kind(kind: BlockKind) -> Self {
|
|
|
|
match kind {
|
2022-07-29 01:15:23 +10:00
|
|
|
#kind_to_state_arms
|
2022-04-18 10:04:39 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Constructs a block state from a raw block state ID.
|
|
|
|
///
|
|
|
|
/// If the given ID is invalid, `None` is returned.
|
|
|
|
pub const fn from_raw(id: u16) -> Option<Self> {
|
2022-07-29 01:15:23 +10:00
|
|
|
if id <= #max_state_id {
|
2022-04-18 10:04:39 +10:00
|
|
|
Some(Self(id))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-07 09:46:07 +10:00
|
|
|
/// Returns the [`BlockKind`] of this block state.
|
|
|
|
pub const fn to_kind(self) -> BlockKind {
|
|
|
|
match self.0 {
|
|
|
|
#state_to_kind_arms
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-18 10:04:39 +10:00
|
|
|
/// Converts this block state to its underlying raw block state ID.
|
|
|
|
///
|
|
|
|
/// The original block state can be recovered with [`BlockState::from_raw`].
|
|
|
|
pub const fn to_raw(self) -> u16 {
|
|
|
|
self.0
|
|
|
|
}
|
|
|
|
|
2022-06-23 01:06:54 +10:00
|
|
|
/// Returns the maximum block state ID.
|
|
|
|
pub const fn max_raw() -> u16 {
|
2022-07-29 01:15:23 +10:00
|
|
|
#max_state_id
|
2022-06-23 01:06:54 +10:00
|
|
|
}
|
|
|
|
|
2023-02-24 16:21:27 +11:00
|
|
|
/// Returns the wall variant of the block state.
|
|
|
|
///
|
|
|
|
/// If the given block state doesn't have a wall variant, `None` is returned.
|
|
|
|
pub const fn wall_block_id(self) -> Option<Self> {
|
|
|
|
match self {
|
|
|
|
#state_to_wall_variant_arms
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-18 10:04:39 +10:00
|
|
|
/// Gets the value of the property with the given name from this block.
|
2022-04-18 10:06:13 +10:00
|
|
|
///
|
2022-04-18 10:04:39 +10:00
|
|
|
/// If this block does not have the property, then `None` is returned.
|
|
|
|
pub const fn get(self, name: PropName) -> Option<PropValue> {
|
2022-07-06 12:21:52 +10:00
|
|
|
match self.to_kind() {
|
2022-04-18 10:04:39 +10:00
|
|
|
#get_arms
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-29 01:15:23 +10:00
|
|
|
/// Sets the value of a property on this block, returning the modified block.
|
2022-04-18 10:06:13 +10:00
|
|
|
///
|
2022-04-18 10:04:39 +10:00
|
|
|
/// If this block does not have the given property or the property value is invalid,
|
2022-07-29 01:15:23 +10:00
|
|
|
/// then the original block is returned unchanged.
|
2022-04-18 10:04:39 +10:00
|
|
|
#[must_use]
|
|
|
|
pub const fn set(self, name: PropName, val: PropValue) -> Self {
|
2022-07-06 12:21:52 +10:00
|
|
|
match self.to_kind() {
|
2022-04-18 10:04:39 +10:00
|
|
|
#set_arms
|
|
|
|
_ => self,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-20 16:40:33 +10:00
|
|
|
/// If this block is `air`, `cave_air` or `void_air`.
|
|
|
|
pub const fn is_air(self) -> bool {
|
|
|
|
matches!(
|
2022-10-30 07:56:48 +11:00
|
|
|
self,
|
|
|
|
BlockState::AIR | BlockState::CAVE_AIR | BlockState::VOID_AIR
|
2022-04-20 16:40:33 +10:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: is_solid
|
|
|
|
|
|
|
|
/// If this block is water or lava.
|
|
|
|
pub const fn is_liquid(self) -> bool {
|
2022-07-06 12:21:52 +10:00
|
|
|
matches!(self.to_kind(), BlockKind::Water | BlockKind::Lava)
|
2022-04-20 16:40:33 +10:00
|
|
|
}
|
|
|
|
|
2022-08-07 09:46:07 +10:00
|
|
|
pub const fn is_opaque(self) -> bool {
|
|
|
|
match self.0 {
|
|
|
|
#state_to_opaque_arms
|
|
|
|
_ => true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-16 21:50:57 +11:00
|
|
|
pub const fn is_replaceable(self) -> bool {
|
|
|
|
match self.0 {
|
|
|
|
#state_to_replaceable_arms
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Use a struct to store block collision shapes (#334)
## Description
Created a new CollisionShape struct for blocks (was previously an [f64;
6]).
## Test Plan
Explain the steps necessary to test your changes. If you used a
playground, include the code in the details below.
Steps:
1. Run the following code
<details>
<summary>Playground</summary>
```rust
use valence_block;
fn main() {
let shapes = valence_block::BlockState::STONE.collision_shapes();
println!("{:?}", shapes.collect::<Vec<_>>());
// [CollisionShape { min_x: 0.0, min_y: 0.0, min_z: 0.0, max_x: 1.0, max_y: 1.0, max_z: 1.0 }]
let shapes = valence_block::BlockState::OAK_STAIRS.collision_shapes();
println!("{:?}", shapes.collect::<Vec<_>>());
// [CollisionShape { min_x: 0.0, min_y: 0.0, min_z: 0.0, max_x: 1.0, max_y: 0.5, max_z: 1.0 }, CollisionShape { min_x: 0.0, min_y: 0.5, min_z: 0.0, max_x: 1.0, max_y: 1.0, max_z: 0.5 }]
}
```
</details>
2023-05-22 18:29:59 +10:00
|
|
|
const SHAPES: [Aabb; #shape_count] = [
|
2022-08-07 09:46:07 +10:00
|
|
|
#(#shapes,)*
|
|
|
|
];
|
|
|
|
|
Use a struct to store block collision shapes (#334)
## Description
Created a new CollisionShape struct for blocks (was previously an [f64;
6]).
## Test Plan
Explain the steps necessary to test your changes. If you used a
playground, include the code in the details below.
Steps:
1. Run the following code
<details>
<summary>Playground</summary>
```rust
use valence_block;
fn main() {
let shapes = valence_block::BlockState::STONE.collision_shapes();
println!("{:?}", shapes.collect::<Vec<_>>());
// [CollisionShape { min_x: 0.0, min_y: 0.0, min_z: 0.0, max_x: 1.0, max_y: 1.0, max_z: 1.0 }]
let shapes = valence_block::BlockState::OAK_STAIRS.collision_shapes();
println!("{:?}", shapes.collect::<Vec<_>>());
// [CollisionShape { min_x: 0.0, min_y: 0.0, min_z: 0.0, max_x: 1.0, max_y: 0.5, max_z: 1.0 }, CollisionShape { min_x: 0.0, min_y: 0.5, min_z: 0.0, max_x: 1.0, max_y: 1.0, max_z: 0.5 }]
}
```
</details>
2023-05-22 18:29:59 +10:00
|
|
|
pub fn collision_shapes(self) -> impl ExactSizeIterator<Item = Aabb> + FusedIterator + Clone {
|
2022-08-07 09:46:07 +10:00
|
|
|
let shape_idxs: &'static [u16] = match self.0 {
|
|
|
|
#state_to_collision_shapes_arms
|
|
|
|
_ => &[],
|
|
|
|
};
|
|
|
|
|
2022-11-14 01:10:42 +11:00
|
|
|
shape_idxs.into_iter().map(|idx| Self::SHAPES[*idx as usize])
|
2022-08-07 09:46:07 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
pub const fn luminance(self) -> u8 {
|
|
|
|
match self.0 {
|
|
|
|
#state_to_luminance_arms
|
|
|
|
_ => 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-19 05:16:01 +11:00
|
|
|
pub const fn block_entity_kind(self) -> Option<BlockEntityKind> {
|
|
|
|
let kind = match self.0 {
|
|
|
|
#state_to_block_entity_type_arms
|
|
|
|
_ => None
|
|
|
|
};
|
|
|
|
|
|
|
|
match kind {
|
|
|
|
Some(id) => BlockEntityKind::from_id(id),
|
|
|
|
None => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-18 10:04:39 +10:00
|
|
|
#default_block_states
|
|
|
|
}
|
|
|
|
|
2022-07-11 22:08:02 +10:00
|
|
|
/// An enumeration of all block kinds.
|
2022-04-18 10:04:39 +10:00
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
2022-07-06 12:21:52 +10:00
|
|
|
pub enum BlockKind {
|
|
|
|
#(#block_kind_variants,)*
|
2022-04-18 10:04:39 +10:00
|
|
|
}
|
|
|
|
|
2022-07-06 12:21:52 +10:00
|
|
|
impl BlockKind {
|
2022-07-11 22:08:02 +10:00
|
|
|
/// Construct a block kind from its snake_case name.
|
2022-04-18 10:04:39 +10:00
|
|
|
///
|
2022-07-11 22:08:02 +10:00
|
|
|
/// Returns `None` if the name is invalid.
|
2022-10-06 03:28:08 +11:00
|
|
|
pub fn from_str(name: &str) -> Option<Self> {
|
2022-04-18 10:04:39 +10:00
|
|
|
match name {
|
2022-07-06 12:21:52 +10:00
|
|
|
#block_kind_from_str_arms
|
2022-04-18 10:04:39 +10:00
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-11 22:08:02 +10:00
|
|
|
/// Get the snake_case name of this block kind.
|
2022-04-18 10:04:39 +10:00
|
|
|
pub const fn to_str(self) -> &'static str {
|
|
|
|
match self {
|
2022-07-06 12:21:52 +10:00
|
|
|
#block_kind_to_str_arms
|
2022-04-18 10:04:39 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-11 22:08:02 +10:00
|
|
|
/// Returns the default block state for a given block kind.
|
2022-04-18 10:04:39 +10:00
|
|
|
pub const fn to_state(self) -> BlockState {
|
2022-07-06 12:21:52 +10:00
|
|
|
BlockState::from_kind(self)
|
2022-04-18 10:04:39 +10:00
|
|
|
}
|
|
|
|
|
2022-07-11 22:08:02 +10:00
|
|
|
/// Returns a slice of all properties this block kind has.
|
2022-04-18 10:04:39 +10:00
|
|
|
pub const fn props(self) -> &'static [PropName] {
|
|
|
|
match self {
|
2022-07-06 12:21:52 +10:00
|
|
|
#block_kind_props_arms
|
2022-04-18 10:04:39 +10:00
|
|
|
_ => &[],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-07 09:50:50 +10:00
|
|
|
pub const fn translation_key(self) -> &'static str {
|
|
|
|
match self {
|
|
|
|
#kind_to_translation_key_arms
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-06 03:28:08 +11:00
|
|
|
/// Converts a block kind to its corresponding item kind.
|
|
|
|
///
|
|
|
|
/// [`ItemKind::Air`] is used to indicate the absence of an item.
|
|
|
|
pub const fn to_item_kind(self) -> ItemKind {
|
|
|
|
let id = match self {
|
|
|
|
#block_kind_to_item_kind_arms
|
|
|
|
};
|
|
|
|
|
|
|
|
// TODO: unwrap() is not const yet.
|
|
|
|
match ItemKind::from_raw(id) {
|
|
|
|
Some(k) => k,
|
|
|
|
None => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Constructs a block kind from an item kind.
|
|
|
|
///
|
|
|
|
/// If the given item does not have a corresponding block, `None` is returned.
|
|
|
|
pub const fn from_item_kind(item: ItemKind) -> Option<Self> {
|
|
|
|
// The "default" blocks are ordered before the other variants.
|
|
|
|
// For instance, `torch` comes before `wall_torch` so this match
|
|
|
|
// should do the correct thing.
|
|
|
|
#[allow(unreachable_patterns)]
|
|
|
|
match item.to_raw() {
|
|
|
|
#block_kind_from_item_kind_arms
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-31 01:18:24 +11:00
|
|
|
/// Constructs a block kind from a raw block kind ID.
|
|
|
|
///
|
|
|
|
/// If the given ID is invalid, `None` is returned.
|
|
|
|
pub const fn from_raw(id: u16) -> Option<Self> {
|
|
|
|
match id {
|
|
|
|
#block_kind_from_raw_arms
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Converts this block kind to its underlying raw block state ID.
|
|
|
|
///
|
|
|
|
/// The original block kind can be recovered with [`BlockKind::from_raw`].
|
|
|
|
pub const fn to_raw(self) -> u16 {
|
|
|
|
self as u16
|
|
|
|
}
|
|
|
|
|
2022-07-11 22:08:02 +10:00
|
|
|
/// An array of all block kinds.
|
2022-07-06 12:21:52 +10:00
|
|
|
pub const ALL: [Self; #block_kind_count] = [#(Self::#block_kind_variants,)*];
|
2022-04-18 10:04:39 +10:00
|
|
|
}
|
|
|
|
|
2022-07-11 22:08:02 +10:00
|
|
|
/// The default block kind is `air`.
|
2022-07-06 12:21:52 +10:00
|
|
|
impl Default for BlockKind {
|
2022-04-18 10:04:39 +10:00
|
|
|
fn default() -> Self {
|
|
|
|
Self::Air
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Contains all possible block state property names.
|
|
|
|
///
|
|
|
|
/// For example, `waterlogged`, `facing`, and `half` are all property names.
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
|
|
|
pub enum PropName {
|
|
|
|
#(#prop_name_variants,)*
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PropName {
|
|
|
|
/// Construct a property name from its snake_case name.
|
|
|
|
///
|
|
|
|
/// Returns `None` if the given name is not valid.
|
|
|
|
pub fn from_str(name: &str) -> Option<Self> {
|
2022-07-29 01:15:23 +10:00
|
|
|
// TODO: match on str in const fn.
|
2022-04-18 10:04:39 +10:00
|
|
|
match name {
|
|
|
|
#prop_name_from_str_arms
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the snake_case name of this property name.
|
|
|
|
pub const fn to_str(self) -> &'static str {
|
|
|
|
match self {
|
|
|
|
#prop_name_to_str_arms
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// An array of all property names.
|
2022-04-29 17:48:41 +10:00
|
|
|
pub const ALL: [Self; #prop_name_count] = [#(Self::#prop_name_variants,)*];
|
2022-04-18 10:04:39 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Contains all possible values that a block property might have.
|
|
|
|
///
|
|
|
|
/// For example, `upper`, `true`, and `2` are all property values.
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
|
|
|
pub enum PropValue {
|
|
|
|
#(#prop_value_variants,)*
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PropValue {
|
|
|
|
/// Construct a property value from its snake_case name.
|
|
|
|
///
|
|
|
|
/// Returns `None` if the given name is not valid.
|
|
|
|
pub fn from_str(name: &str) -> Option<Self> {
|
|
|
|
match name {
|
|
|
|
#prop_value_from_str_arms
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the snake_case name of this property value.
|
|
|
|
pub const fn to_str(self) -> &'static str {
|
|
|
|
match self {
|
|
|
|
#prop_value_to_str_arms
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Converts a `u16` into a numeric property value.
|
|
|
|
/// Returns `None` if the given number does not have a
|
|
|
|
/// corresponding property value.
|
|
|
|
pub const fn from_u16(n: u16) -> Option<Self> {
|
|
|
|
match n {
|
|
|
|
#prop_value_from_u16_arms
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Converts this property value into a `u16` if it is numeric.
|
|
|
|
/// Returns `None` otherwise.
|
|
|
|
pub const fn to_u16(self) -> Option<u16> {
|
|
|
|
match self {
|
|
|
|
#prop_value_to_u16_arms
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
/// Converts a `bool` to a `True` or `False` property value.
|
2022-04-18 10:04:39 +10:00
|
|
|
pub const fn from_bool(b: bool) -> Self {
|
|
|
|
if b {
|
|
|
|
Self::True
|
|
|
|
} else {
|
|
|
|
Self::False
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-29 01:15:23 +10:00
|
|
|
/// Converts a `True` or `False` property value to a `bool`.
|
|
|
|
///
|
2022-05-16 19:36:14 +10:00
|
|
|
/// Returns `None` if this property value is not `True` or `False`
|
2022-04-18 10:04:39 +10:00
|
|
|
pub const fn to_bool(self) -> Option<bool> {
|
|
|
|
match self {
|
|
|
|
Self::True => Some(true),
|
|
|
|
Self::False => Some(false),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// An array of all property values.
|
2022-07-29 01:15:23 +10:00
|
|
|
pub const ALL: [Self; #prop_value_count] = [#(Self::#prop_value_variants,)*];
|
2022-04-18 10:04:39 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
impl From<bool> for PropValue {
|
|
|
|
fn from(b: bool) -> Self {
|
|
|
|
Self::from_bool(b)
|
|
|
|
}
|
|
|
|
}
|
2023-02-19 05:16:01 +11:00
|
|
|
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
|
|
|
pub enum BlockEntityKind {
|
|
|
|
#block_entity_kind_variants
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BlockEntityKind {
|
|
|
|
pub const fn from_id(num: u32) -> Option<Self> {
|
|
|
|
match num {
|
|
|
|
#block_entity_kind_from_id_arms
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub const fn id(self) -> u32 {
|
|
|
|
match self {
|
|
|
|
#block_entity_kind_to_id_arms
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn from_ident(ident: Ident<&str>) -> Option<Self> {
|
|
|
|
match ident.as_str() {
|
|
|
|
#block_entity_kind_from_ident_arms
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn ident(self) -> Ident<&'static str> {
|
|
|
|
match self {
|
|
|
|
#block_entity_kind_to_ident_arms
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Encode for BlockEntityKind {
|
Reorganize Project (#321)
## Description
- `valence` and `valence_protocol` have been divided into smaller crates
in order to parallelize the build and improve IDE responsiveness. In the
process, code architecture has been made clearer by removing circular
dependencies between modules. `valence` is now just a shell around the
other crates.
- `workspace.packages` and `workspace.dependencies` are now used. This
makes dependency managements and crate configuration much easier.
- `valence_protocol` is no more. Most things from `valence_protocol`
ended up in `valence_core`. We won't advertise `valence_core` as a
general-purpose protocol library since it contains too much
valence-specific stuff. Closes #308.
- Networking code (login, initial TCP connection handling, etc.) has
been extracted into the `valence_network` crate. The API has been
expanded and improved with better defaults. Player counts and initial
connections to the server are now tracked separately. Player counts
function by default without any user configuration.
- Some crates like `valence_anvil`, `valence_network`,
`valence_player_list`, `valence_inventory`, etc. are now optional. They
can be enabled/disabled with feature flags and `DefaultPlugins` just
like bevy.
- Whole-server unit tests have been moved to `valence/src/tests` in
order to avoid [cyclic
dev-dependencies](https://github.com/rust-lang/cargo/issues/4242).
- Tools like `valence_stresser` and `packet_inspector` have been moved
to a new `tools` directory. Renamed `valence_stresser` to `stresser`.
Closes #241.
- Moved all benches to `valence/benches/` to make them easier to run and
organize.
Ignoring transitive dependencies and `valence_core`, here's what the
dependency graph looks like now:
```mermaid
graph TD
network --> client
client --> instance
biome --> registry
dimension --> registry
instance --> biome
instance --> dimension
instance --> entity
player_list --> client
inventory --> client
anvil --> instance
entity --> block
```
### Issues
- Inventory tests inspect many private implementation details of the
inventory module, forcing us to mark things as `pub` and
`#[doc(hidden)]`. It would be ideal if the tests only looked at
observable behavior.
- Consider moving packets in `valence_core` elsewhere. `Particle` wants
to use `BlockState`, but that's defined in `valence_block`, so we can't
use it without causing cycles.
- Unsure what exactly should go in `valence::prelude`.
- This could use some more tests of course, but I'm holding off on that
until I'm confident this is the direction we want to take things.
## TODOs
- [x] Update examples.
- [x] Update benches.
- [x] Update main README.
- [x] Add short READMEs to crates.
- [x] Test new schedule to ensure behavior is the same.
- [x] Update tools.
- [x] Copy lints to all crates.
- [x] Fix docs, clippy, etc.
2023-04-22 07:43:59 +10:00
|
|
|
fn encode(&self, w: impl Write) -> anyhow::Result<()> {
|
2023-02-19 05:16:01 +11:00
|
|
|
VarInt(self.id() as i32).encode(w)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Decode<'a> for BlockEntityKind {
|
Reorganize Project (#321)
## Description
- `valence` and `valence_protocol` have been divided into smaller crates
in order to parallelize the build and improve IDE responsiveness. In the
process, code architecture has been made clearer by removing circular
dependencies between modules. `valence` is now just a shell around the
other crates.
- `workspace.packages` and `workspace.dependencies` are now used. This
makes dependency managements and crate configuration much easier.
- `valence_protocol` is no more. Most things from `valence_protocol`
ended up in `valence_core`. We won't advertise `valence_core` as a
general-purpose protocol library since it contains too much
valence-specific stuff. Closes #308.
- Networking code (login, initial TCP connection handling, etc.) has
been extracted into the `valence_network` crate. The API has been
expanded and improved with better defaults. Player counts and initial
connections to the server are now tracked separately. Player counts
function by default without any user configuration.
- Some crates like `valence_anvil`, `valence_network`,
`valence_player_list`, `valence_inventory`, etc. are now optional. They
can be enabled/disabled with feature flags and `DefaultPlugins` just
like bevy.
- Whole-server unit tests have been moved to `valence/src/tests` in
order to avoid [cyclic
dev-dependencies](https://github.com/rust-lang/cargo/issues/4242).
- Tools like `valence_stresser` and `packet_inspector` have been moved
to a new `tools` directory. Renamed `valence_stresser` to `stresser`.
Closes #241.
- Moved all benches to `valence/benches/` to make them easier to run and
organize.
Ignoring transitive dependencies and `valence_core`, here's what the
dependency graph looks like now:
```mermaid
graph TD
network --> client
client --> instance
biome --> registry
dimension --> registry
instance --> biome
instance --> dimension
instance --> entity
player_list --> client
inventory --> client
anvil --> instance
entity --> block
```
### Issues
- Inventory tests inspect many private implementation details of the
inventory module, forcing us to mark things as `pub` and
`#[doc(hidden)]`. It would be ideal if the tests only looked at
observable behavior.
- Consider moving packets in `valence_core` elsewhere. `Particle` wants
to use `BlockState`, but that's defined in `valence_block`, so we can't
use it without causing cycles.
- Unsure what exactly should go in `valence::prelude`.
- This could use some more tests of course, but I'm holding off on that
until I'm confident this is the direction we want to take things.
## TODOs
- [x] Update examples.
- [x] Update benches.
- [x] Update main README.
- [x] Add short READMEs to crates.
- [x] Test new schedule to ensure behavior is the same.
- [x] Update tools.
- [x] Copy lints to all crates.
- [x] Fix docs, clippy, etc.
2023-04-22 07:43:59 +10:00
|
|
|
fn decode(r: &mut &'a [u8]) -> anyhow::Result<Self> {
|
2023-02-19 05:16:01 +11:00
|
|
|
let id = VarInt::decode(r)?;
|
|
|
|
Self::from_id(id.0 as u32).with_context(|| format!("id {}", id.0))
|
|
|
|
}
|
|
|
|
}
|
2022-07-28 00:10:35 +10:00
|
|
|
})
|
2022-04-18 10:04:39 +10:00
|
|
|
}
|