mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added default sprite attribute state
This commit is contained in:
parent
ad8965fdd7
commit
4a89d88e9b
@ -156,50 +156,44 @@ impl Block {
|
||||
|
||||
/* Constructors */
|
||||
|
||||
// TODO: Rename to `filled`
|
||||
#[inline]
|
||||
pub const fn new(kind: BlockKind, color: Rgb<u8>) -> Self {
|
||||
// TODO: we should probably assert this, overwriting the data fields with a
|
||||
// colour is bad news
|
||||
/*
|
||||
#[cfg(debug_assertions)]
|
||||
assert!(kind.is_filled());
|
||||
*/
|
||||
pub(super) const fn from_raw(kind: BlockKind, data: [u8; 3]) -> Self { Self { kind, data } }
|
||||
|
||||
Self {
|
||||
kind,
|
||||
// Colours are only valid for non-fluids
|
||||
data: if kind.is_filled() {
|
||||
[color.r, color.g, color.b]
|
||||
} else {
|
||||
[0; 3]
|
||||
},
|
||||
// TODO: Rename to `filled`, make caller guarantees stronger
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub const fn new(kind: BlockKind, color: Rgb<u8>) -> Self {
|
||||
if kind.is_filled() {
|
||||
Self::from_raw(kind, [color.r, color.g, color.b])
|
||||
} else {
|
||||
// Works because `SpriteKind::Empty` has no attributes
|
||||
let data = (SpriteKind::Empty as u32).to_be_bytes();
|
||||
Self::from_raw(kind, [data[1], data[2], data[3]])
|
||||
}
|
||||
}
|
||||
|
||||
// Only valid if `block_kind` is unfilled, so this is just a private utility
|
||||
// method
|
||||
#[inline]
|
||||
const fn unfilled(kind: BlockKind, sprite: SpriteKind) -> Self {
|
||||
pub fn unfilled(kind: BlockKind, sprite: SpriteKind) -> Self {
|
||||
#[cfg(debug_assertions)]
|
||||
assert!(!kind.is_filled());
|
||||
|
||||
let sprite_bytes = (sprite as u32).to_be_bytes();
|
||||
|
||||
Self {
|
||||
kind,
|
||||
data: [sprite_bytes[1], sprite_bytes[2], sprite_bytes[3]],
|
||||
}
|
||||
Self::from_raw(kind, sprite.to_initial_bytes())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn air(sprite: SpriteKind) -> Self { Self::unfilled(BlockKind::Air, sprite) }
|
||||
pub fn air(sprite: SpriteKind) -> Self { Self::unfilled(BlockKind::Air, sprite) }
|
||||
|
||||
#[inline]
|
||||
pub const fn empty() -> Self { Self::air(SpriteKind::Empty) }
|
||||
pub const fn empty() -> Self {
|
||||
// Works because `SpriteKind::Empty` has no attributes
|
||||
let data = (SpriteKind::Empty as u32).to_be_bytes();
|
||||
Self::from_raw(BlockKind::Air, [data[1], data[2], data[3]])
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn water(sprite: SpriteKind) -> Self { Self::unfilled(BlockKind::Water, sprite) }
|
||||
pub fn water(sprite: SpriteKind) -> Self { Self::unfilled(BlockKind::Water, sprite) }
|
||||
|
||||
/* Sprite decoding */
|
||||
|
||||
@ -258,6 +252,9 @@ impl Block {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(super) const fn data(&self) -> [u8; 3] { self.data }
|
||||
|
||||
#[inline(always)]
|
||||
pub(super) const fn with_data(mut self, data: [u8; 3]) -> Self {
|
||||
self.data = data;
|
||||
@ -428,12 +425,12 @@ impl Block {
|
||||
};
|
||||
|
||||
if self
|
||||
.get_attr::<sprite::LightDisabled>()
|
||||
.map_or(false, |l| l.0)
|
||||
.get_attr::<sprite::LightEnabled>()
|
||||
.map_or(true, |l| l.0)
|
||||
{
|
||||
None
|
||||
} else {
|
||||
Some(glow_level)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
@ -636,7 +633,7 @@ impl Block {
|
||||
|
||||
/// Apply a light toggle to this block, if possible
|
||||
pub fn with_toggle_light(self, enable: bool) -> Option<Self> {
|
||||
self.with_attr(sprite::LightDisabled(!enable)).ok()
|
||||
self.with_attr(sprite::LightEnabled(enable)).ok()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -662,7 +659,7 @@ impl Block {
|
||||
#[must_use]
|
||||
pub fn into_vacant(self) -> Self {
|
||||
if self.is_fluid() {
|
||||
Block::new(self.kind(), Rgb::zero())
|
||||
Block::unfilled(self.kind(), SpriteKind::Empty)
|
||||
} else {
|
||||
// FIXME: Figure out if there's some sensible way to determine what medium to
|
||||
// replace a filled block with if it's removed.
|
||||
@ -698,7 +695,7 @@ mod tests {
|
||||
#[test]
|
||||
fn convert_u32() {
|
||||
for bk in BlockKind::iter() {
|
||||
let block = Block::new(bk, Rgb::new(165, 90, 204)); // Pretty unique bit patterns
|
||||
let block = Block::from_raw(bk, [165, 90, 204]); // Pretty unique bit patterns
|
||||
if bk.is_filled() {
|
||||
assert_eq!(Block::from_u32(block.to_u32()), Some(block));
|
||||
} else {
|
||||
|
@ -286,7 +286,7 @@ impl TerrainChunk {
|
||||
pub fn water(sea_level: i32) -> TerrainChunk {
|
||||
TerrainChunk::new(
|
||||
sea_level,
|
||||
Block::new(BlockKind::Water, Rgb::zero()),
|
||||
Block::water(SpriteKind::Empty),
|
||||
Block::air(SpriteKind::Empty),
|
||||
TerrainChunkMeta::void(),
|
||||
)
|
||||
|
@ -349,7 +349,7 @@ sprites! {
|
||||
SeaDecorPillar = 0x1E,
|
||||
MagicalSeal = 0x1F,
|
||||
},
|
||||
Lamp = 7 has Ori, LightDisabled {
|
||||
Lamp = 7 has Ori, LightEnabled {
|
||||
// Standalone lights
|
||||
Lantern = 0,
|
||||
StreetLamp = 1,
|
||||
@ -362,20 +362,28 @@ sprites! {
|
||||
attributes! {
|
||||
Ori { bits: 4, err: Infallible, from: |bits| Ok(Self(bits as u8)), into: |Ori(x)| x as u16 },
|
||||
Growth { bits: 4, err: Infallible, from: |bits| Ok(Self(bits as u8)), into: |Growth(x)| x as u16 },
|
||||
LightDisabled { bits: 1, err: Infallible, from: |bits| Ok(Self(bits == 1)), into: |LightDisabled(x)| x as u16 },
|
||||
LightEnabled { bits: 1, err: Infallible, from: |bits| Ok(Self(bits == 1)), into: |LightEnabled(x)| x as u16 },
|
||||
}
|
||||
|
||||
// The orientation of the sprite, 0..16
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
|
||||
pub struct Ori(pub u8);
|
||||
|
||||
// The growth of the plant, 0..16
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Growth(pub u8);
|
||||
|
||||
// Whether a light has been toggled off.
|
||||
impl Default for Growth {
|
||||
fn default() -> Self { Self(15) }
|
||||
}
|
||||
|
||||
// Whether a light has been toggled on or off.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct LightDisabled(pub bool);
|
||||
pub struct LightEnabled(pub bool);
|
||||
|
||||
impl Default for LightEnabled {
|
||||
fn default() -> Self { Self(true) }
|
||||
}
|
||||
|
||||
impl SpriteKind {
|
||||
#[inline]
|
||||
|
@ -158,6 +158,15 @@ macro_rules! sprites {
|
||||
},)*
|
||||
}
|
||||
}
|
||||
|
||||
#[inline] pub(super) fn to_initial_bytes(self) -> [u8; 3] {
|
||||
let sprite_bytes = (*self as u32).to_be_bytes();
|
||||
let block = Block::from_raw(super::BlockKind::Air, [sprite_bytes[1], sprite_bytes[2], sprite_bytes[3]]);
|
||||
match self.category() {
|
||||
$(Category::$category_name => block$($(.with_attr($attr::default()).unwrap())*)?,)*
|
||||
}
|
||||
.data()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -170,12 +179,14 @@ pub enum AttributeError<E> {
|
||||
Attribute(E),
|
||||
}
|
||||
|
||||
pub trait Attribute: Sized {
|
||||
/// The unique index assigned to this attribute, used to index offset arrays
|
||||
pub trait Attribute: Default + Sized {
|
||||
/// The unique index assigned to this attribute, used to index offset
|
||||
/// arrays.
|
||||
const INDEX: usize;
|
||||
/// The number of bits required to represent this attribute
|
||||
/// The number of bits required to represent this attribute.
|
||||
const BITS: u8;
|
||||
type Error;
|
||||
/// The error that might occur when decoding the attribute from bits.
|
||||
type Error: core::fmt::Debug;
|
||||
fn from_bits(bits: u16) -> Result<Self, Self::Error>;
|
||||
fn into_bits(self) -> u16;
|
||||
}
|
||||
|
@ -294,7 +294,7 @@ pub fn generate_mesh<'a>(
|
||||
let d = d + 2;
|
||||
let flat = {
|
||||
let mut volume = vol.cached();
|
||||
const AIR: Block = Block::air(common::terrain::sprite::SpriteKind::Empty);
|
||||
const AIR: Block = Block::empty();
|
||||
// TODO: Once we can manage it sensibly, consider using something like
|
||||
// Option<Block> instead of just assuming air.
|
||||
let mut flat = vec![AIR; (w * h * d) as usize];
|
||||
|
@ -142,8 +142,8 @@ impl BlocksOfInterest {
|
||||
_ => {
|
||||
if let Some(sprite) = block.get_sprite() {
|
||||
if sprite.category() == sprite::Category::Lamp {
|
||||
if let Ok(sprite::LightDisabled(disabled)) = block.get_attr() {
|
||||
interactables.push((pos, Interaction::LightToggle(disabled)));
|
||||
if let Ok(sprite::LightEnabled(enabled)) = block.get_attr() {
|
||||
interactables.push((pos, Interaction::LightToggle(!enabled)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ pub struct Colors {
|
||||
pub vein: (u8, u8, u8),
|
||||
}
|
||||
|
||||
const EMPTY_AIR: Block = Block::air(SpriteKind::Empty);
|
||||
const EMPTY_AIR: Block = Block::empty();
|
||||
|
||||
pub struct PathLocals {
|
||||
pub riverless_alt: f32,
|
||||
|
@ -167,7 +167,7 @@ impl Archetype for Keep {
|
||||
make_block(colors.pole.0, colors.pole.1, colors.pole.2).with_priority(important_layer);
|
||||
let flag =
|
||||
make_block(flag_color.0, flag_color.1, flag_color.2).with_priority(important_layer);
|
||||
const AIR: Block = Block::air(SpriteKind::Empty);
|
||||
const AIR: Block = Block::empty();
|
||||
const EMPTY: BlockMask = BlockMask::nothing();
|
||||
let internal = BlockMask::new(AIR, internal_layer);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user