mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 14:26:04 +00:00
make blockstate good
This commit is contained in:
parent
48b2a37aa0
commit
9d4f738d4e
20 changed files with 6407 additions and 20554 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -215,6 +215,7 @@ version = "0.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"azalea-block-macros",
|
"azalea-block-macros",
|
||||||
"azalea-buf",
|
"azalea-buf",
|
||||||
|
"azalea-registry",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -6,13 +6,11 @@ name = "azalea-block"
|
||||||
repository = "https://github.com/mat-1/azalea/tree/main/azalea-block"
|
repository = "https://github.com/mat-1/azalea/tree/main/azalea-block"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
|
||||||
[features]
|
|
||||||
full-debug = ["azalea-block-macros/full-debug"]
|
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
azalea-block-macros = {path = "./azalea-block-macros", version = "^0.5.0" }
|
azalea-block-macros = { path = "./azalea-block-macros", version = "^0.5.0" }
|
||||||
azalea-buf = {path = "../azalea-buf", version = "^0.5.0" }
|
azalea-buf = { path = "../azalea-buf", version = "^0.5.0" }
|
||||||
|
azalea-registry = { version = "0.5.0", path = "../azalea-registry" }
|
||||||
|
|
|
@ -1,12 +1,49 @@
|
||||||
# Azalea Block
|
|
||||||
|
|
||||||
Representation of Minecraft block states.
|
Representation of Minecraft block states.
|
||||||
|
|
||||||
There's two main things here, the `BlockState` enum and the `Block` trait.
|
There's three block types, used for different things. You can (mostly) freely convert between them with `.into()`.
|
||||||
`BlockState` is a simple enum with every possible block state as variant, and `Block` is a heavier trait which lets you access information about a block more easily.
|
|
||||||
|
|
||||||
Every block is a struct that implements `Block`. You can freely convert between `BlockState` and `Block` with .into().
|
## BlockState struct
|
||||||
|
|
||||||
If you don't want the `Block` trait, set default-features to false.
|
[`BlockState`] is a struct containing the numerical protocol ID of a block state. This is how blocks are stored in the world.
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
# use azalea_block::BlockState;
|
||||||
|
let block_state: BlockState = azalea_registry::Block::Jukebox.into();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Block trait
|
||||||
|
|
||||||
|
The [`Block`] trait represents a type of a block. With the the [`Block`] trait, you can get some extra things like the string block ID and some information about the block's behavior. Also, the structs that implement the trait contain the block attributes as fields so it's more convenient to get them. Note that this is often used as `Box<dyn Block>`.
|
||||||
|
If for some reason you don't want the `Block` trait, set default-features to false.
|
||||||
|
|
||||||
|
```
|
||||||
|
# use azalea_block::{Block, BlockState};
|
||||||
|
# let block_state: BlockState = azalea_registry::Block::Jukebox.into();
|
||||||
|
if let Some(jukebox) = Box::<dyn Block>::from(block_state).downcast_ref::<azalea_block::JukeboxBlock>() {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
```
|
||||||
|
# use azalea_block::BlockState;
|
||||||
|
let block_state: BlockState = azalea_block::CobblestoneWallBlock {
|
||||||
|
east: azalea_block::EastWall::Low,
|
||||||
|
north: azalea_block::NorthWall::Low,
|
||||||
|
south: azalea_block::SouthWall::Low,
|
||||||
|
west: azalea_block::WestWall::Low,
|
||||||
|
up: false,
|
||||||
|
waterlogged: false,
|
||||||
|
}
|
||||||
|
.into();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## azalea_registry::Block enum
|
||||||
|
|
||||||
|
This one technically isn't from the `azalea-block` crate, but it's still very relevant. It's an enum that contains every block type as a variant *without* containing any state data (like `BlockState` and the `Block` trait). Converting this into any other block type will use the default state for that block.
|
||||||
|
|
||||||
|
```
|
||||||
|
# use azalea_block::BlockState;
|
||||||
|
let block_state: BlockState = azalea_registry::Block::Jukebox.into();
|
||||||
|
```
|
||||||
|
|
||||||
Also, by default the `Debug` implementation for `BlockState` only logs the name of the block and not the name of the enum variant. If you want that, enable the `full-debug` feature (though it's not recommended).
|
|
||||||
|
|
|
@ -6,9 +6,6 @@ name = "azalea-block-macros"
|
||||||
repository = "https://github.com/mat-1/azalea/tree/main/azalea-block/azalea-block-macros"
|
repository = "https://github.com/mat-1/azalea/tree/main/azalea-block/azalea-block-macros"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
|
||||||
[features]
|
|
||||||
full-debug = []
|
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
|
use proc_macro2::TokenTree;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
@ -234,7 +235,7 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
|
||||||
let mut properties_map = HashMap::new();
|
let mut properties_map = HashMap::new();
|
||||||
let mut property_struct_names_to_names = HashMap::new();
|
let mut property_struct_names_to_names = HashMap::new();
|
||||||
|
|
||||||
let mut state_id: usize = 0;
|
let mut state_id: u32 = 0;
|
||||||
|
|
||||||
for property in &input.property_definitions.properties {
|
for property in &input.property_definitions.properties {
|
||||||
let property_type_name: Ident;
|
let property_type_name: Ident;
|
||||||
|
@ -282,8 +283,8 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
|
||||||
#property_enum_variants
|
#property_enum_variants
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<usize> for #property_type_name {
|
impl From<u32> for #property_type_name {
|
||||||
fn from(value: usize) -> Self {
|
fn from(value: u32) -> Self {
|
||||||
match value {
|
match value {
|
||||||
#property_from_number_variants
|
#property_from_number_variants
|
||||||
_ => panic!("Invalid property value: {}", value),
|
_ => panic!("Invalid property value: {}", value),
|
||||||
|
@ -305,7 +306,11 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
|
||||||
|
|
||||||
let mut block_state_enum_variants = quote! {};
|
let mut block_state_enum_variants = quote! {};
|
||||||
let mut block_structs = quote! {};
|
let mut block_structs = quote! {};
|
||||||
|
|
||||||
let mut from_state_to_block_match = quote! {};
|
let mut from_state_to_block_match = quote! {};
|
||||||
|
let mut from_registry_block_to_block_match = quote! {};
|
||||||
|
let mut from_registry_block_to_blockstate_match = quote! {};
|
||||||
|
|
||||||
for block in &input.block_definitions.blocks {
|
for block in &input.block_definitions.blocks {
|
||||||
let block_property_names = &block
|
let block_property_names = &block
|
||||||
.properties_and_defaults
|
.properties_and_defaults
|
||||||
|
@ -403,30 +408,18 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
|
||||||
let mut from_block_to_state_match_inner = quote! {};
|
let mut from_block_to_state_match_inner = quote! {};
|
||||||
|
|
||||||
let first_state_id = state_id;
|
let first_state_id = state_id;
|
||||||
|
let mut default_state_id = None;
|
||||||
|
|
||||||
// if there's no properties, then the block is just a single state
|
// if there's no properties, then the block is just a single state
|
||||||
if block_properties_vec.is_empty() {
|
if block_properties_vec.is_empty() {
|
||||||
block_state_enum_variants.extend(quote! {
|
block_state_enum_variants.extend(quote! {
|
||||||
#block_name_pascal_case,
|
#block_name_pascal_case,
|
||||||
});
|
});
|
||||||
|
default_state_id = Some(state_id);
|
||||||
state_id += 1;
|
state_id += 1;
|
||||||
}
|
}
|
||||||
for combination in combinations_of(&block_properties_vec) {
|
for combination in combinations_of(&block_properties_vec) {
|
||||||
state_id += 1;
|
let mut is_default = true;
|
||||||
let variant_name = Ident::new(
|
|
||||||
&format!(
|
|
||||||
"{}_{}",
|
|
||||||
block_name_pascal_case,
|
|
||||||
combination
|
|
||||||
.iter()
|
|
||||||
.map(|v| v[0..1].to_uppercase() + &v[1..])
|
|
||||||
.collect::<String>()
|
|
||||||
),
|
|
||||||
proc_macro2::Span::call_site(),
|
|
||||||
);
|
|
||||||
block_state_enum_variants.extend(quote! {
|
|
||||||
#variant_name,
|
|
||||||
});
|
|
||||||
|
|
||||||
// face: properties::Face::Floor,
|
// face: properties::Face::Floor,
|
||||||
// facing: properties::Facing::North,
|
// facing: properties::Facing::North,
|
||||||
|
@ -439,6 +432,18 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
|
||||||
let variant =
|
let variant =
|
||||||
Ident::new(&combination[i].to_string(), proc_macro2::Span::call_site());
|
Ident::new(&combination[i].to_string(), proc_macro2::Span::call_site());
|
||||||
|
|
||||||
|
// this terrible code just gets the property default as a string
|
||||||
|
let property_default_as_string = if let TokenTree::Ident(i) =
|
||||||
|
property.default.clone().into_iter().last().unwrap()
|
||||||
|
{
|
||||||
|
i.to_string()
|
||||||
|
} else {
|
||||||
|
panic!()
|
||||||
|
};
|
||||||
|
if property_default_as_string != combination[i] {
|
||||||
|
is_default = false;
|
||||||
|
}
|
||||||
|
|
||||||
let property_type = if property.is_enum {
|
let property_type = if property.is_enum {
|
||||||
quote! {#property_struct_name_ident::#variant}
|
quote! {#property_struct_name_ident::#variant}
|
||||||
} else {
|
} else {
|
||||||
|
@ -453,10 +458,21 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
|
||||||
from_block_to_state_match_inner.extend(quote! {
|
from_block_to_state_match_inner.extend(quote! {
|
||||||
#block_struct_name {
|
#block_struct_name {
|
||||||
#from_block_to_state_combination_match_inner
|
#from_block_to_state_combination_match_inner
|
||||||
} => BlockState::#variant_name,
|
} => BlockState { id: #state_id },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if is_default {
|
||||||
|
default_state_id = Some(state_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state_id += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(default_state_id) = default_state_id else {
|
||||||
|
let defaults = properties_with_name.iter().map(|p| if let TokenTree::Ident(i) = p.default.clone().into_iter().last().unwrap() { i.to_string() } else { panic!() }).collect::<Vec<_>>();
|
||||||
|
panic!("Couldn't get default state id for {}, combinations={:?}, defaults={:?}", block_name_pascal_case.to_string(), block_properties_vec, defaults)
|
||||||
|
};
|
||||||
|
|
||||||
// 7035..=7058 => {
|
// 7035..=7058 => {
|
||||||
// let b = b - 7035;
|
// let b = b - 7035;
|
||||||
// &AcaciaButtonBlock {
|
// &AcaciaButtonBlock {
|
||||||
|
@ -466,7 +482,7 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
let mut from_state_to_block_inner = quote! {};
|
let mut from_state_to_block_inner = quote! {};
|
||||||
let mut division = 1usize;
|
let mut division = 1u32;
|
||||||
for i in (0..properties_with_name.len()).rev() {
|
for i in (0..properties_with_name.len()).rev() {
|
||||||
let PropertyWithNameAndDefault {
|
let PropertyWithNameAndDefault {
|
||||||
property_type: property_struct_name_ident,
|
property_type: property_struct_name_ident,
|
||||||
|
@ -475,11 +491,12 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
|
||||||
} = &properties_with_name[i];
|
} = &properties_with_name[i];
|
||||||
|
|
||||||
let property_variants = &block_properties_vec[i];
|
let property_variants = &block_properties_vec[i];
|
||||||
let property_variants_count = property_variants.len();
|
let property_variants_count = property_variants.len() as u32;
|
||||||
let conversion_code = {
|
let conversion_code = {
|
||||||
if &property_struct_name_ident.to_string() == "bool" {
|
if &property_struct_name_ident.to_string() == "bool" {
|
||||||
assert_eq!(property_variants_count, 2);
|
assert_eq!(property_variants_count, 2);
|
||||||
quote! {(b / #division) % #property_variants_count != 0}
|
// this is not a mistake, it starts with true for some reason
|
||||||
|
quote! {(b / #division) % #property_variants_count == 0}
|
||||||
} else {
|
} else {
|
||||||
quote! {#property_struct_name_ident::from((b / #division) % #property_variants_count)}
|
quote! {#property_struct_name_ident::from((b / #division) % #property_variants_count)}
|
||||||
}
|
}
|
||||||
|
@ -500,6 +517,12 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
from_registry_block_to_block_match.extend(quote! {
|
||||||
|
azalea_registry::Block::#block_name_pascal_case => Box::new(#block_struct_name::default()),
|
||||||
|
});
|
||||||
|
from_registry_block_to_blockstate_match.extend(quote! {
|
||||||
|
azalea_registry::Block::#block_name_pascal_case => BlockState { id: #default_state_id },
|
||||||
|
});
|
||||||
|
|
||||||
let mut block_default_fields = quote! {};
|
let mut block_default_fields = quote! {};
|
||||||
for PropertyWithNameAndDefault {
|
for PropertyWithNameAndDefault {
|
||||||
|
@ -515,10 +538,10 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
|
||||||
let block_id = block.name.to_string();
|
let block_id = block.name.to_string();
|
||||||
|
|
||||||
let from_block_to_state_match = if block.properties_and_defaults.is_empty() {
|
let from_block_to_state_match = if block.properties_and_defaults.is_empty() {
|
||||||
quote! { BlockState::#block_name_pascal_case }
|
quote! { BlockState { id: #first_state_id } }
|
||||||
} else {
|
} else {
|
||||||
quote! {
|
quote! {
|
||||||
match b {
|
match self {
|
||||||
#from_block_to_state_match_inner
|
#from_block_to_state_match_inner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -537,11 +560,14 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
|
||||||
fn id(&self) -> &'static str {
|
fn id(&self) -> &'static str {
|
||||||
#block_id
|
#block_id
|
||||||
}
|
}
|
||||||
|
fn as_blockstate(&self) -> BlockState {
|
||||||
|
#from_block_to_state_match
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<#block_struct_name> for BlockState {
|
impl From<#block_struct_name> for BlockState {
|
||||||
fn from(b: #block_struct_name) -> Self {
|
fn from(b: #block_struct_name) -> Self {
|
||||||
#from_block_to_state_match
|
b.as_blockstate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,26 +587,29 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
|
||||||
let mut generated = quote! {
|
let mut generated = quote! {
|
||||||
#property_enums
|
#property_enums
|
||||||
|
|
||||||
#[repr(u32)]
|
/// A representation of a state a block can be in. (for example, a stone
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
/// block only has one state but each possible stair rotation is a
|
||||||
// the Debug impl is very large and slows down compilation
|
/// different state).
|
||||||
#[cfg_attr(feature = "full-debug", derive(Debug))]
|
#[derive(Copy, Clone, PartialEq, Eq, Default)]
|
||||||
pub enum BlockState {
|
pub struct BlockState {
|
||||||
#block_state_enum_variants
|
/// The protocol ID for the block state. IDs may change every
|
||||||
|
/// version, so you shouldn't hard-code them or store them in databases.
|
||||||
|
pub id: u32
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlockState {
|
impl BlockState {
|
||||||
/// Returns the highest possible state
|
pub const AIR: BlockState = BlockState { id: 0 };
|
||||||
|
|
||||||
|
/// Returns the highest possible state ID.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn max_state() -> u32 {
|
pub fn max_state() -> u32 {
|
||||||
#last_state_id
|
#last_state_id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "full-debug"))]
|
|
||||||
impl std::fmt::Debug for BlockState {
|
impl std::fmt::Debug for BlockState {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "BlockState ({})", Box::<dyn Block>::from(*self).id())
|
write!(f, "BlockState(id: {}, {:?})", self.id, Box::<dyn Block>::from(*self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -589,14 +618,30 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
|
||||||
#block_structs
|
#block_structs
|
||||||
|
|
||||||
impl From<BlockState> for Box<dyn Block> {
|
impl From<BlockState> for Box<dyn Block> {
|
||||||
fn from(b: BlockState) -> Self {
|
fn from(block_state: BlockState) -> Self {
|
||||||
let b = b as usize;
|
let b = block_state.id;
|
||||||
match b {
|
match b {
|
||||||
#from_state_to_block_match
|
#from_state_to_block_match
|
||||||
_ => panic!("Invalid block state: {}", b),
|
_ => panic!("Invalid block state: {}", b),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl From<azalea_registry::Block> for Box<dyn Block> {
|
||||||
|
fn from(block: azalea_registry::Block) -> Self {
|
||||||
|
match block {
|
||||||
|
#from_registry_block_to_block_match
|
||||||
|
_ => unreachable!("There should always be a block struct for every azalea_registry::Block variant")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<azalea_registry::Block> for BlockState {
|
||||||
|
fn from(block: azalea_registry::Block) -> Self {
|
||||||
|
match block {
|
||||||
|
#from_registry_block_to_blockstate_match
|
||||||
|
_ => unreachable!("There should always be a block state for every azalea_registry::Block variant")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
generated.into()
|
generated.into()
|
||||||
|
|
|
@ -1,9 +1,18 @@
|
||||||
|
use std::any::Any;
|
||||||
|
|
||||||
use crate::BlockBehavior;
|
use crate::BlockBehavior;
|
||||||
use azalea_block_macros::make_block_states;
|
use azalea_block_macros::make_block_states;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
pub trait Block {
|
pub trait Block: Debug + Any {
|
||||||
fn behavior(&self) -> BlockBehavior;
|
fn behavior(&self) -> BlockBehavior;
|
||||||
fn id(&self) -> &'static str;
|
fn id(&self) -> &'static str;
|
||||||
|
fn as_blockstate(&self) -> BlockState;
|
||||||
|
}
|
||||||
|
impl dyn Block {
|
||||||
|
pub fn downcast_ref<T: Block>(&self) -> Option<&T> {
|
||||||
|
(self as &dyn Any).downcast_ref::<T>()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
make_block_states! {
|
make_block_states! {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#![doc = include_str!("../README.md")]
|
#![doc = include_str!("../README.md")]
|
||||||
|
#![feature(trait_upcasting)]
|
||||||
|
|
||||||
mod behavior;
|
mod behavior;
|
||||||
mod blocks;
|
mod blocks;
|
||||||
|
@ -6,10 +7,7 @@ mod blocks;
|
||||||
use azalea_buf::{BufReadError, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable};
|
use azalea_buf::{BufReadError, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable};
|
||||||
pub use behavior::BlockBehavior;
|
pub use behavior::BlockBehavior;
|
||||||
pub use blocks::*;
|
pub use blocks::*;
|
||||||
use std::{
|
use std::io::{Cursor, Write};
|
||||||
io::{Cursor, Write},
|
|
||||||
mem,
|
|
||||||
};
|
|
||||||
|
|
||||||
impl BlockState {
|
impl BlockState {
|
||||||
/// Transmutes a u32 to a block state.
|
/// Transmutes a u32 to a block state.
|
||||||
|
@ -17,8 +15,8 @@ impl BlockState {
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// The `state_id` should be a valid block state.
|
/// The `state_id` should be a valid block state.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn from_u32_unsafe(state_id: u32) -> Self {
|
pub unsafe fn from_u32_unchecked(state_id: u32) -> Self {
|
||||||
mem::transmute::<u32, BlockState>(state_id)
|
BlockState { id: state_id }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -33,7 +31,7 @@ impl TryFrom<u32> for BlockState {
|
||||||
/// Safely converts a state id to a block state.
|
/// Safely converts a state id to a block state.
|
||||||
fn try_from(state_id: u32) -> Result<Self, Self::Error> {
|
fn try_from(state_id: u32) -> Result<Self, Self::Error> {
|
||||||
if Self::is_valid_state(state_id) {
|
if Self::is_valid_state(state_id) {
|
||||||
Ok(unsafe { Self::from_u32_unsafe(state_id) })
|
Ok(unsafe { Self::from_u32_unchecked(state_id) })
|
||||||
} else {
|
} else {
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
|
@ -50,7 +48,7 @@ impl McBufReadable for BlockState {
|
||||||
}
|
}
|
||||||
impl McBufWritable for BlockState {
|
impl McBufWritable for BlockState {
|
||||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||||
u32::var_write_into(&(*self as u32), buf)
|
u32::var_write_into(&self.id, buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +58,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_from_u32() {
|
fn test_from_u32() {
|
||||||
assert_eq!(BlockState::try_from(0).unwrap(), BlockState::Air);
|
assert_eq!(BlockState::try_from(0).unwrap(), BlockState::AIR);
|
||||||
|
|
||||||
assert!(BlockState::try_from(BlockState::max_state()).is_ok());
|
assert!(BlockState::try_from(BlockState::max_state()).is_ok());
|
||||||
assert!(BlockState::try_from(BlockState::max_state() + 1).is_err());
|
assert!(BlockState::try_from(BlockState::max_state() + 1).is_err());
|
||||||
|
@ -68,19 +66,34 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_from_blockstate() {
|
fn test_from_blockstate() {
|
||||||
let block: Box<dyn Block> = Box::<dyn Block>::from(BlockState::Air);
|
let block: Box<dyn Block> = Box::<dyn Block>::from(BlockState::AIR);
|
||||||
assert_eq!(block.id(), "air");
|
assert_eq!(block.id(), "air");
|
||||||
|
|
||||||
let block: Box<dyn Block> = Box::<dyn Block>::from(BlockState::FloweringAzalea);
|
let block: Box<dyn Block> =
|
||||||
|
Box::<dyn Block>::from(BlockState::from(azalea_registry::Block::FloweringAzalea));
|
||||||
assert_eq!(block.id(), "flowering_azalea");
|
assert_eq!(block.id(), "flowering_azalea");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "full-debug"))]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_debug_blockstate() {
|
fn test_debug_blockstate() {
|
||||||
assert_eq!(
|
let formatted = format!(
|
||||||
format!("{:?}", BlockState::FloweringAzalea),
|
"{:?}",
|
||||||
"BlockState (flowering_azalea)"
|
BlockState::from(azalea_registry::Block::FloweringAzalea)
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
formatted.ends_with(", FloweringAzaleaBlock)"),
|
||||||
|
"{}",
|
||||||
|
formatted
|
||||||
|
);
|
||||||
|
|
||||||
|
let formatted = format!(
|
||||||
|
"{:?}",
|
||||||
|
BlockState::from(azalea_registry::Block::BigDripleafStem)
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
formatted.ends_with(", BigDripleafStemBlock { facing: North, waterlogged: false })"),
|
||||||
|
"{}",
|
||||||
|
formatted
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -378,7 +378,8 @@ impl Client {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # fn example(client: &azalea::Client) {
|
/// # use azalea_world::entity::WorldName;
|
||||||
|
/// # fn example(client: &azalea_client::Client) {
|
||||||
/// let world_name = client.component::<WorldName>();
|
/// let world_name = client.component::<WorldName>();
|
||||||
/// # }
|
/// # }
|
||||||
pub fn component<T: Component + Clone>(&self) -> T {
|
pub fn component<T: Component + Clone>(&self) -> T {
|
||||||
|
|
|
@ -15,6 +15,7 @@ impl Client {
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # use azalea_world::entity::WorldName;
|
||||||
/// # fn example(mut client: azalea_client::Client) {
|
/// # fn example(mut client: azalea_client::Client) {
|
||||||
/// let is_logged_in = client
|
/// let is_logged_in = client
|
||||||
/// .query::<Option<&WorldName>>(&mut client.ecs.lock())
|
/// .query::<Option<&WorldName>>(&mut client.ecs.lock())
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -79,7 +79,7 @@ impl<'a> Iterator for BlockCollisions<'a> {
|
||||||
let block_state: BlockState = chunk
|
let block_state: BlockState = chunk
|
||||||
.read()
|
.read()
|
||||||
.get(&(&pos).into(), self.world.chunks.min_y)
|
.get(&(&pos).into(), self.world.chunks.min_y)
|
||||||
.unwrap_or(BlockState::Air);
|
.unwrap_or(BlockState::AIR);
|
||||||
|
|
||||||
// TODO: continue if self.only_suffocating_blocks and the block is not
|
// TODO: continue if self.only_suffocating_blocks and the block is not
|
||||||
// suffocating
|
// suffocating
|
||||||
|
|
|
@ -75,7 +75,7 @@ fn travel(
|
||||||
let block_state_below = world
|
let block_state_below = world
|
||||||
.chunks
|
.chunks
|
||||||
.get_block_state(&block_pos_below)
|
.get_block_state(&block_pos_below)
|
||||||
.unwrap_or(BlockState::Air);
|
.unwrap_or(BlockState::AIR);
|
||||||
let block_below: Box<dyn Block> = block_state_below.into();
|
let block_below: Box<dyn Block> = block_state_below.into();
|
||||||
let block_friction = block_below.behavior().friction;
|
let block_friction = block_below.behavior().friction;
|
||||||
|
|
||||||
|
@ -412,7 +412,7 @@ mod tests {
|
||||||
.id();
|
.id();
|
||||||
let block_state = partial_world.chunks.set_block_state(
|
let block_state = partial_world.chunks.set_block_state(
|
||||||
&BlockPos { x: 0, y: 69, z: 0 },
|
&BlockPos { x: 0, y: 69, z: 0 },
|
||||||
BlockState::Stone,
|
azalea_registry::Block::Stone.into(),
|
||||||
&mut world_lock.write().chunks,
|
&mut world_lock.write().chunks,
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -469,7 +469,11 @@ mod tests {
|
||||||
.id();
|
.id();
|
||||||
let block_state = partial_world.chunks.set_block_state(
|
let block_state = partial_world.chunks.set_block_state(
|
||||||
&BlockPos { x: 0, y: 69, z: 0 },
|
&BlockPos { x: 0, y: 69, z: 0 },
|
||||||
BlockState::StoneSlab_BottomFalse,
|
azalea_block::StoneSlabBlock {
|
||||||
|
kind: azalea_block::Type::Bottom,
|
||||||
|
waterlogged: false,
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
&mut world_lock.write().chunks,
|
&mut world_lock.write().chunks,
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -518,7 +522,11 @@ mod tests {
|
||||||
.id();
|
.id();
|
||||||
let block_state = world_lock.write().chunks.set_block_state(
|
let block_state = world_lock.write().chunks.set_block_state(
|
||||||
&BlockPos { x: 0, y: 69, z: 0 },
|
&BlockPos { x: 0, y: 69, z: 0 },
|
||||||
BlockState::StoneSlab_TopFalse,
|
azalea_block::StoneSlabBlock {
|
||||||
|
kind: azalea_block::Type::Top,
|
||||||
|
waterlogged: false,
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
block_state.is_some(),
|
block_state.is_some(),
|
||||||
|
@ -566,7 +574,15 @@ mod tests {
|
||||||
.id();
|
.id();
|
||||||
let block_state = world_lock.write().chunks.set_block_state(
|
let block_state = world_lock.write().chunks.set_block_state(
|
||||||
&BlockPos { x: 0, y: 69, z: 0 },
|
&BlockPos { x: 0, y: 69, z: 0 },
|
||||||
BlockState::CobblestoneWall_LowLowLowFalseFalseLow,
|
azalea_block::CobblestoneWallBlock {
|
||||||
|
east: azalea_block::EastWall::Low,
|
||||||
|
north: azalea_block::NorthWall::Low,
|
||||||
|
south: azalea_block::SouthWall::Low,
|
||||||
|
west: azalea_block::WestWall::Low,
|
||||||
|
up: false,
|
||||||
|
waterlogged: false,
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
block_state.is_some(),
|
block_state.is_some(),
|
||||||
|
|
|
@ -37,7 +37,7 @@ impl McBufReadable for BlockStateWithPosition {
|
||||||
|
|
||||||
impl McBufWritable for BlockStateWithPosition {
|
impl McBufWritable for BlockStateWithPosition {
|
||||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||||
let data = (self.state as u64) << 12
|
let data = (self.state.id as u64) << 12
|
||||||
| (u64::from(self.pos.x) << 8 | u64::from(self.pos.z) << 4 | u64::from(self.pos.y));
|
| (u64::from(self.pos.x) << 8 | u64::from(self.pos.z) << 4 | u64::from(self.pos.y));
|
||||||
u64::var_write_into(&data, buf)?;
|
u64::var_write_into(&data, buf)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -343,20 +343,20 @@ impl Section {
|
||||||
.states
|
.states
|
||||||
.get(pos.x as usize, pos.y as usize, pos.z as usize);
|
.get(pos.x as usize, pos.y as usize, pos.z as usize);
|
||||||
// if there's an unknown block assume it's air
|
// if there's an unknown block assume it's air
|
||||||
BlockState::try_from(state).unwrap_or(BlockState::Air)
|
BlockState::try_from(state).unwrap_or(BlockState::AIR)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_and_set(&mut self, pos: ChunkSectionBlockPos, state: BlockState) -> BlockState {
|
fn get_and_set(&mut self, pos: ChunkSectionBlockPos, state: BlockState) -> BlockState {
|
||||||
let previous_state =
|
let previous_state =
|
||||||
self.states
|
self.states
|
||||||
.get_and_set(pos.x as usize, pos.y as usize, pos.z as usize, state as u32);
|
.get_and_set(pos.x as usize, pos.y as usize, pos.z as usize, state.id);
|
||||||
// if there's an unknown block assume it's air
|
// if there's an unknown block assume it's air
|
||||||
BlockState::try_from(previous_state).unwrap_or(BlockState::Air)
|
BlockState::try_from(previous_state).unwrap_or(BlockState::AIR)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set(&mut self, pos: ChunkSectionBlockPos, state: BlockState) {
|
fn set(&mut self, pos: ChunkSectionBlockPos, state: BlockState) {
|
||||||
self.states
|
self.states
|
||||||
.set(pos.x as usize, pos.y as usize, pos.z as usize, state as u32);
|
.set(pos.x as usize, pos.y as usize, pos.z as usize, state.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2368,7 +2368,7 @@ impl Default for EndermanMetadataBundle {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
carry_state: CarryState(BlockState::Air),
|
carry_state: CarryState(BlockState::AIR),
|
||||||
creepy: Creepy(false),
|
creepy: Creepy(false),
|
||||||
stared_at: StaredAt(false),
|
stared_at: StaredAt(false),
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,7 @@ pub fn on_pos(offset: f32, chunk_storage: &ChunkStorage, pos: &Position) -> Bloc
|
||||||
// TODO: check if block below is a fence, wall, or fence gate
|
// TODO: check if block below is a fence, wall, or fence gate
|
||||||
let block_pos = pos.down(1);
|
let block_pos = pos.down(1);
|
||||||
let block_state = chunk_storage.get_block_state(&block_pos);
|
let block_state = chunk_storage.get_block_state(&block_pos);
|
||||||
if block_state == Some(BlockState::Air) {
|
if block_state == Some(BlockState::AIR) {
|
||||||
let block_pos_below = block_pos.down(1);
|
let block_pos_below = block_pos.down(1);
|
||||||
let block_state_below = chunk_storage.get_block_state(&block_pos_below);
|
let block_state_below = chunk_storage.get_block_state(&block_pos_below);
|
||||||
if let Some(_block_state_below) = block_state_below {
|
if let Some(_block_state_below) = block_state_below {
|
||||||
|
|
|
@ -165,12 +165,12 @@ mod tests {
|
||||||
);
|
);
|
||||||
partial_world.chunks.set_block_state(
|
partial_world.chunks.set_block_state(
|
||||||
&BlockPos::new(0, 0, 0),
|
&BlockPos::new(0, 0, 0),
|
||||||
BlockState::Stone,
|
azalea_registry::Block::Stone.into(),
|
||||||
&mut chunk_storage,
|
&mut chunk_storage,
|
||||||
);
|
);
|
||||||
partial_world.chunks.set_block_state(
|
partial_world.chunks.set_block_state(
|
||||||
&BlockPos::new(0, 1, 0),
|
&BlockPos::new(0, 1, 0),
|
||||||
BlockState::Air,
|
BlockState::AIR,
|
||||||
&mut chunk_storage,
|
&mut chunk_storage,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -190,12 +190,12 @@ mod tests {
|
||||||
);
|
);
|
||||||
partial_world.chunks.set_block_state(
|
partial_world.chunks.set_block_state(
|
||||||
&BlockPos::new(0, 0, 0),
|
&BlockPos::new(0, 0, 0),
|
||||||
BlockState::Stone,
|
azalea_registry::Block::Stone.into(),
|
||||||
&mut chunk_storage,
|
&mut chunk_storage,
|
||||||
);
|
);
|
||||||
partial_world.chunks.set_block_state(
|
partial_world.chunks.set_block_state(
|
||||||
&BlockPos::new(0, 1, 0),
|
&BlockPos::new(0, 1, 0),
|
||||||
BlockState::Air,
|
BlockState::AIR,
|
||||||
&mut chunk_storage,
|
&mut chunk_storage,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -215,22 +215,22 @@ mod tests {
|
||||||
);
|
);
|
||||||
partial_world.chunks.set_block_state(
|
partial_world.chunks.set_block_state(
|
||||||
&BlockPos::new(0, 0, 0),
|
&BlockPos::new(0, 0, 0),
|
||||||
BlockState::Stone,
|
azalea_registry::Block::Stone.into(),
|
||||||
&mut chunk_storage,
|
&mut chunk_storage,
|
||||||
);
|
);
|
||||||
partial_world.chunks.set_block_state(
|
partial_world.chunks.set_block_state(
|
||||||
&BlockPos::new(0, 1, 0),
|
&BlockPos::new(0, 1, 0),
|
||||||
BlockState::Air,
|
BlockState::AIR,
|
||||||
&mut chunk_storage,
|
&mut chunk_storage,
|
||||||
);
|
);
|
||||||
partial_world.chunks.set_block_state(
|
partial_world.chunks.set_block_state(
|
||||||
&BlockPos::new(0, 2, 0),
|
&BlockPos::new(0, 2, 0),
|
||||||
BlockState::Air,
|
BlockState::AIR,
|
||||||
&mut chunk_storage,
|
&mut chunk_storage,
|
||||||
);
|
);
|
||||||
partial_world.chunks.set_block_state(
|
partial_world.chunks.set_block_state(
|
||||||
&BlockPos::new(0, 3, 0),
|
&BlockPos::new(0, 3, 0),
|
||||||
BlockState::Air,
|
BlockState::AIR,
|
||||||
&mut chunk_storage,
|
&mut chunk_storage,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -367,7 +367,7 @@ impl From<EntityDataValue> for UpdateMetadataError {
|
||||||
elif type_name == 'ItemStack':
|
elif type_name == 'ItemStack':
|
||||||
default = f'Slot::Present({default})' if default != 'Empty' else 'Slot::Empty'
|
default = f'Slot::Present({default})' if default != 'Empty' else 'Slot::Empty'
|
||||||
elif type_name == 'BlockState':
|
elif type_name == 'BlockState':
|
||||||
default = f'{default}' if default != 'Empty' else 'BlockState::Air'
|
default = f'{default}' if default != 'Empty' else 'BlockState::AIR'
|
||||||
elif type_name == 'OptionalFormattedText':
|
elif type_name == 'OptionalFormattedText':
|
||||||
default = f'Some({default})' if default != 'Empty' else 'None'
|
default = f'Some({default})' if default != 'Empty' else 'None'
|
||||||
elif type_name == 'CompoundTag':
|
elif type_name == 'CompoundTag':
|
||||||
|
|
|
@ -7,8 +7,8 @@ COLLISION_BLOCKS_RS_DIR = get_dir_location(
|
||||||
'../azalea-physics/src/collision/blocks.rs')
|
'../azalea-physics/src/collision/blocks.rs')
|
||||||
|
|
||||||
|
|
||||||
def generate_block_shapes(blocks: dict, shapes: dict, aabbs: dict, block_states_report, block_datas_burger, mappings: Mappings):
|
def generate_block_shapes(blocks_pixlyzer: dict, shapes: dict, aabbs: dict, block_states_report, block_datas_burger, mappings: Mappings):
|
||||||
blocks, shapes = simplify_shapes(blocks, shapes, aabbs)
|
blocks, shapes = simplify_shapes(blocks_pixlyzer, shapes, aabbs)
|
||||||
|
|
||||||
code = generate_block_shapes_code(
|
code = generate_block_shapes_code(
|
||||||
blocks, shapes, block_states_report, block_datas_burger, mappings)
|
blocks, shapes, block_states_report, block_datas_burger, mappings)
|
||||||
|
@ -28,8 +28,7 @@ def simplify_shapes(blocks: dict, shapes: dict, aabbs: dict):
|
||||||
|
|
||||||
used_shape_ids = set()
|
used_shape_ids = set()
|
||||||
# determine the used shape ids
|
# determine the used shape ids
|
||||||
for block_id, block_data in blocks.items():
|
for _block_id, block_data in blocks.items():
|
||||||
block_id = block_id.split(':')[-1]
|
|
||||||
block_shapes = [state.get('collision_shape')
|
block_shapes = [state.get('collision_shape')
|
||||||
for state in block_data['states'].values()]
|
for state in block_data['states'].values()]
|
||||||
for s in block_shapes:
|
for s in block_shapes:
|
||||||
|
@ -73,9 +72,9 @@ def generate_block_shapes_code(blocks: dict, shapes: dict, block_states_report,
|
||||||
for (shape_id, shape) in sorted(shapes.items(), key=lambda shape: int(shape[0])):
|
for (shape_id, shape) in sorted(shapes.items(), key=lambda shape: int(shape[0])):
|
||||||
generated_shape_code += generate_code_for_shape(shape_id, shape)
|
generated_shape_code += generate_code_for_shape(shape_id, shape)
|
||||||
|
|
||||||
# BlockState::PurpurStairs_NorthTopStraightTrue => &SHAPE24,
|
# 1..100 | 200..300 => &SHAPE1,
|
||||||
generated_match_inner_code = ''
|
generated_match_inner_code = ''
|
||||||
shape_ids_to_variants = {}
|
shape_ids_to_block_state_ids = {}
|
||||||
for block_id, shape_ids in blocks.items():
|
for block_id, shape_ids in blocks.items():
|
||||||
if isinstance(shape_ids, int):
|
if isinstance(shape_ids, int):
|
||||||
shape_ids = [shape_ids]
|
shape_ids = [shape_ids]
|
||||||
|
@ -83,23 +82,34 @@ def generate_block_shapes_code(blocks: dict, shapes: dict, block_states_report,
|
||||||
block_data_burger = block_datas_burger[block_id]
|
block_data_burger = block_datas_burger[block_id]
|
||||||
|
|
||||||
for possible_state, shape_id in zip(block_report_data['states'], shape_ids):
|
for possible_state, shape_id in zip(block_report_data['states'], shape_ids):
|
||||||
variant_values = []
|
block_state_id = possible_state['id']
|
||||||
for value in tuple(possible_state.get('properties', {}).values()):
|
|
||||||
variant_values.append(to_camel_case(value))
|
|
||||||
|
|
||||||
if variant_values == []:
|
if shape_id not in shape_ids_to_block_state_ids:
|
||||||
variant_name = to_camel_case(block_id)
|
shape_ids_to_block_state_ids[shape_id] = []
|
||||||
else:
|
shape_ids_to_block_state_ids[shape_id].append(block_state_id)
|
||||||
variant_name = f'{to_camel_case(block_id)}_{"".join(variant_values)}'
|
|
||||||
|
|
||||||
if shape_id not in shape_ids_to_variants:
|
|
||||||
shape_ids_to_variants[shape_id] = []
|
|
||||||
shape_ids_to_variants[shape_id].append(
|
|
||||||
f'BlockState::{variant_name}')
|
|
||||||
# shape 1 is the most common so we have a _ => &SHAPE1 at the end
|
# shape 1 is the most common so we have a _ => &SHAPE1 at the end
|
||||||
del shape_ids_to_variants[1]
|
del shape_ids_to_block_state_ids[1]
|
||||||
for shape_id, variants in shape_ids_to_variants.items():
|
for shape_id, block_state_ids in shape_ids_to_block_state_ids.items():
|
||||||
generated_match_inner_code += f'{"|".join(variants)} => &SHAPE{shape_id},\n'
|
|
||||||
|
# convert them into ranges (so like 1|2|3 is 1..=3 instead)
|
||||||
|
block_state_ids_ranges = []
|
||||||
|
range_start_block_state_id = None
|
||||||
|
last_block_state_id = None
|
||||||
|
for block_state_id in sorted(block_state_ids):
|
||||||
|
if range_start_block_state_id is None:
|
||||||
|
range_start_block_state_id = block_state_id
|
||||||
|
|
||||||
|
if last_block_state_id is not None:
|
||||||
|
# check if the range is done
|
||||||
|
if block_state_id - 1 != last_block_state_id:
|
||||||
|
block_state_ids_ranges.append(f'{range_start_block_state_id}..={last_block_state_id}' if range_start_block_state_id != last_block_state_id else str(range_start_block_state_id))
|
||||||
|
range_start_block_state_id = block_state_id
|
||||||
|
|
||||||
|
last_block_state_id = block_state_id
|
||||||
|
|
||||||
|
block_state_ids_ranges.append(f'{range_start_block_state_id}..={last_block_state_id}' if range_start_block_state_id != last_block_state_id else str(range_start_block_state_id))
|
||||||
|
generated_match_inner_code += f'{"|".join(block_state_ids_ranges)} => &SHAPE{shape_id},\n'
|
||||||
|
generated_match_inner_code += '_ => &SHAPE1'
|
||||||
|
|
||||||
return f'''
|
return f'''
|
||||||
//! Autogenerated block collisions for every block
|
//! Autogenerated block collisions for every block
|
||||||
|
@ -123,8 +133,8 @@ pub trait BlockWithShape {{
|
||||||
|
|
||||||
impl BlockWithShape for BlockState {{
|
impl BlockWithShape for BlockState {{
|
||||||
fn shape(&self) -> &'static VoxelShape {{
|
fn shape(&self) -> &'static VoxelShape {{
|
||||||
match self {{
|
match self.id {{
|
||||||
{generated_match_inner_code}_ => &SHAPE1
|
{generated_match_inner_code}
|
||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -4,6 +4,7 @@ from lib.download import get_server_jar, get_burger, get_client_jar, get_pixlyze
|
||||||
from lib.utils import get_dir_location
|
from lib.utils import get_dir_location
|
||||||
from zipfile import ZipFile
|
from zipfile import ZipFile
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import requests
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
import re
|
import re
|
||||||
|
@ -114,7 +115,20 @@ def get_pixlyzer_data(version_id: str, category: str):
|
||||||
|
|
||||||
target_dir = get_dir_location(f'downloads/pixlyzer-{version_id}')
|
target_dir = get_dir_location(f'downloads/pixlyzer-{version_id}')
|
||||||
|
|
||||||
if not os.path.exists(get_dir_location(target_dir)):
|
# TODO: right now this False is hard-coded, it should retry with this
|
||||||
|
# enabled if # initially getting the data fails
|
||||||
|
if False or (os.path.exists(target_dir) and not os.path.exists(f'{target_dir}/{category}.min.json')):
|
||||||
|
print('Downloading', category, 'from pixlyzer-data.')
|
||||||
|
data = requests.get(f'https://gitlab.com/Bixilon/pixlyzer-data/-/raw/master/version/{version_id}/{category}.min.json?inline=false').text
|
||||||
|
try:
|
||||||
|
os.mkdir(target_dir)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
with open(f'{target_dir}/{category}.min.json', 'w') as f:
|
||||||
|
f.write(data)
|
||||||
|
return json.loads(data)
|
||||||
|
|
||||||
|
if not os.path.exists(target_dir):
|
||||||
pixlyzer_dir = get_pixlyzer()
|
pixlyzer_dir = get_pixlyzer()
|
||||||
|
|
||||||
# for some reason pixlyzer doesn't work right unless the mvn clean
|
# for some reason pixlyzer doesn't work right unless the mvn clean
|
||||||
|
@ -231,7 +245,6 @@ def get_pixlyzer_data(version_id: str, category: str):
|
||||||
with open(f'{target_dir}/{category}.min.json', 'r') as f:
|
with open(f'{target_dir}/{category}.min.json', 'r') as f:
|
||||||
return json.load(f)
|
return json.load(f)
|
||||||
|
|
||||||
|
|
||||||
def get_file_from_jar(version_id: str, file_dir: str):
|
def get_file_from_jar(version_id: str, file_dir: str):
|
||||||
get_client_jar(version_id)
|
get_client_jar(version_id)
|
||||||
with ZipFile(get_dir_location(f'downloads/client-{version_id}.jar')) as z:
|
with ZipFile(get_dir_location(f'downloads/client-{version_id}.jar')) as z:
|
||||||
|
|
Loading…
Add table
Reference in a new issue