blocks: versioned block states, fixes world on fire #467 (#469)

Since the unflattening in 1.13.x, block IDs are no longer stable across versions, and
can be shifted by the addition of new block states. To get the right block IDs across
multiple protocol versions, add a new `offsets` token to `define_blocks!`, which
is similar to `offset` (used post-flattening, compare to `data` used pre-flattening),
but accepts a protocol_version argument to enable block states _per-version_:

* Add 'offsets' for protocol_version-specific blockstates

As part of this change, by_vanilla_id is now a method of a VanillaIDMap instance,
instead of a method of Block, so it can know the protocol version. Previously, the
ID map was lazily computed statically, once, but this change allows it to be
computed based on protocol version:

* Move by_vanilla_id to VanillaIDMap instance

Tools to help debug blocks:

* Add DEBUG_BLOCKS environment variable to dump block states
* Add dump_block command-line tool

The block `offset`s were previously only correct for 1.13.2, to take advantage of
the new version-specific `offsets` capability, blocks were updated for 1.14.x:

1.14+ (protocol_version >= 477):
* Add NoteBlock instruments
* Add FlowerPot and RedFlowerVariant cornflower, wither rose, lily of the valley
* Add StandingSign wood variants
* Add WallSign tree variants
* Add StoneSlab smooth stone, cut sandstone, cut red sandstone

This fixes #467, where grass was misinterpreted as fire on 1.14+ because of the
ID shifts caused by NoteBlock, among other block misassignments (though not 100%).
This commit is contained in:
iceiix 2021-01-13 19:50:05 -08:00 committed by GitHub
parent bb4fb9eb8b
commit 8ca12a69ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 357 additions and 153 deletions

View File

@ -0,0 +1,21 @@
use std::collections::HashMap;
use std::env;
use steven_blocks::VanillaIDMap;
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() < 3 {
println!(
"usage: {} protocol_version id\nrun with DEBUG_BLOCKS=1 to dump all",
args[0]
);
return;
}
let protocol_version = str::parse::<i32>(&args[1]).unwrap();
let id = str::parse::<usize>(&args[2]).unwrap();
let id_map = VanillaIDMap::new(protocol_version);
let block = id_map.by_vanilla_id(id, &HashMap::new());
println!("{:?}", block);
}

View File

@ -7,7 +7,6 @@ extern crate steven_shared as shared;
use crate::shared::{Axis, Direction, Position};
use cgmath::Point3;
use collision::Aabb3;
use lazy_static::lazy_static;
use std::collections::HashMap;
pub mod material;
@ -43,10 +42,50 @@ macro_rules! create_ids {
);
}
struct VanillaIDMap {
#[derive(Default)]
pub struct VanillaIDMap {
flat: Vec<Option<Block>>,
hier: Vec<Option<Block>>,
modded: HashMap<String, [Option<Block>; 16]>,
protocol_version: i32,
}
impl VanillaIDMap {
pub fn new(protocol_version: i32) -> VanillaIDMap {
gen_id_map(protocol_version)
}
pub fn by_vanilla_id(
&self,
id: usize,
modded_block_ids: &HashMap<usize, String>, // TODO: remove and add to constructor, but have to mutate in Server
) -> Block {
if self.protocol_version >= 404 {
self.flat
.get(id)
.and_then(|v| *v)
.unwrap_or(Block::Missing {})
// TODO: support modded 1.13.2+ blocks after https://github.com/iceiix/stevenarella/pull/145
} else {
if let Some(block) = self.hier.get(id).and_then(|v| *v) {
block
} else {
let data = id & 0xf;
if let Some(name) = modded_block_ids.get(&(id >> 4)) {
if let Some(blocks_by_data) = self.modded.get(name) {
blocks_by_data[data].unwrap_or(Block::Missing {})
} else {
//info!("Modded block not supported yet: {}:{} -> {}", id >> 4, data, name);
Block::Missing {}
}
} else {
Block::Missing {}
}
}
}
}
}
macro_rules! define_blocks {
@ -61,6 +100,7 @@ macro_rules! define_blocks {
},
$(data $datafunc:expr,)?
$(offset $offsetfunc:expr,)?
$(offsets $offsetsfunc:expr,)?
$(material $mat:expr,)?
model $model:expr,
$(variant $variant:expr,)?
@ -117,12 +157,17 @@ macro_rules! define_blocks {
}
#[allow(unused_variables, unreachable_code)]
pub fn get_flat_offset(&self) -> Option<usize> {
#[allow(clippy::redundant_closure_call)] // TODO: fix 'try not to call a closure in the expression where it is declared'
pub fn get_flat_offset(&self, protocol_version: i32) -> Option<usize> {
match *self {
$(
Block::$name {
$($fname,)?
} => {
$(
let offset: Option<usize> = ($offsetsfunc)(protocol_version).map(|v| v);
return offset;
)?
$(
let offset: Option<usize> = ($offsetfunc).map(|v| v);
return offset;
@ -153,30 +198,6 @@ macro_rules! define_blocks {
}
}
pub fn by_vanilla_id(id: usize, protocol_version: i32, modded_block_ids: &HashMap<usize, String>) -> Block {
if protocol_version >= 404 {
VANILLA_ID_MAP.flat.get(id).and_then(|v| *v).unwrap_or(Block::Missing{})
// TODO: support modded 1.13.2+ blocks after https://github.com/iceiix/stevenarella/pull/145
} else {
if let Some(block) = VANILLA_ID_MAP.hier.get(id).and_then(|v| *v) {
block
} else {
let data = id & 0xf;
if let Some(name) = modded_block_ids.get(&(id >> 4)) {
if let Some(blocks_by_data) = VANILLA_ID_MAP.modded.get(name) {
blocks_by_data[data].unwrap_or(Block::Missing{})
} else {
//info!("Modded block not supported yet: {}:{} -> {}", id >> 4, data, name);
Block::Missing{}
}
} else {
Block::Missing{}
}
}
}
}
#[allow(unused_variables, unreachable_code)]
pub fn get_material(&self) -> Material {
match *self {
@ -294,6 +315,7 @@ macro_rules! define_blocks {
$(
#[allow(non_snake_case)]
pub fn $name(
protocol_version: i32,
blocks_flat: &mut Vec<Option<Block>>,
blocks_hier: &mut Vec<Option<Block>>,
blocks_modded: &mut HashMap<String, [Option<Block>; 16]>,
@ -390,6 +412,7 @@ macro_rules! define_blocks {
}),*
);
let mut last_offset: isize = -1;
let debug_blocks = std::env::var("DEBUG_BLOCKS").is_ok();
for block in iter {
let internal_id = block.get_internal_id();
let hier_data: Option<usize> = block.get_hierarchical_data();
@ -414,16 +437,16 @@ macro_rules! define_blocks {
None
};
let offset = block.get_flat_offset();
let offset = block.get_flat_offset(protocol_version);
if let Some(offset) = offset {
let id = *flat_id + offset;
/*
if let Some(vanilla_id) = vanilla_id {
println!("{} block state = {:?} hierarchical {}:{} offset={}", id, block, vanilla_id >> 4, vanilla_id & 0xF, offset);
} else {
println!("{} block state = {:?} hierarchical none, offset={}", id, block, offset);
if debug_blocks {
if let Some(vanilla_id) = vanilla_id {
println!("{} block state = {:?} hierarchical {}:{} offset={}", id, block, vanilla_id >> 4, vanilla_id & 0xF, offset);
} else {
println!("{} block state = {:?} hierarchical none, offset={}", id, block, offset);
}
}
*/
if offset as isize > last_offset {
last_offset = offset as isize;
}
@ -444,11 +467,11 @@ macro_rules! define_blocks {
}
if let Some(vanilla_id) = vanilla_id {
/*
if offset.is_none() {
println!("(no flat) block state = {:?} hierarchical {}:{}", block, vanilla_id >> 4, vanilla_id & 0xF);
if debug_blocks {
if offset.is_none() {
println!("(no flat) block state = {:?} hierarchical {}:{}", block, vanilla_id >> 4, vanilla_id & 0xF);
}
}
*/
if (*blocks_hier).len() <= vanilla_id {
(*blocks_hier).resize(vanilla_id + 1, None);
@ -474,26 +497,24 @@ macro_rules! define_blocks {
)+
}
lazy_static! {
static ref VANILLA_ID_MAP: VanillaIDMap = {
let mut blocks_flat = vec![];
let mut blocks_hier = vec![];
let mut blocks_modded: HashMap<String, [Option<Block>; 16]> = HashMap::new();
let mut flat_id = 0;
let mut last_internal_id = 0;
let mut hier_block_id = 0;
pub fn gen_id_map(protocol_version: i32) -> VanillaIDMap {
let mut blocks_flat = vec![];
let mut blocks_hier = vec![];
let mut blocks_modded: HashMap<String, [Option<Block>; 16]> = HashMap::new();
let mut flat_id = 0;
let mut last_internal_id = 0;
let mut hier_block_id = 0;
$(
block_registration_functions::$name(protocol_version,
&mut blocks_flat,
&mut blocks_hier,
&mut blocks_modded,
&mut flat_id,
&mut last_internal_id,
&mut hier_block_id);
)+
$(
block_registration_functions::$name(&mut blocks_flat,
&mut blocks_hier,
&mut blocks_modded,
&mut flat_id,
&mut last_internal_id,
&mut hier_block_id);
)+
VanillaIDMap { flat: blocks_flat, hier: blocks_hier, modded: blocks_modded }
};
VanillaIDMap { flat: blocks_flat, hier: blocks_hier, modded: blocks_modded, protocol_version }
}
);
}
@ -843,13 +864,20 @@ define_blocks! {
NoteBlockInstrument::Bell,
NoteBlockInstrument::Guitar,
NoteBlockInstrument::Chime,
NoteBlockInstrument::Xylophone
NoteBlockInstrument::Xylophone,
NoteBlockInstrument::IronXylophone,
NoteBlockInstrument::CowBell,
NoteBlockInstrument::Didgeridoo,
NoteBlockInstrument::Bit,
NoteBlockInstrument::Banjo,
NoteBlockInstrument::Pling
],
note: u8 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24],
powered: bool = [true, false],
},
data if instrument == NoteBlockInstrument::Harp && note == 0 && powered { Some(0) } else { None },
offset Some(instrument.offset() * (25 * 2) + ((note as usize) << 1) + if powered { 0 } else { 1 }),
offsets |protocol_version| (instrument.offsets(protocol_version)
.map(|offset| offset * (25 * 2) + ((note as usize) << 1) + if powered { 0 } else { 1 })),
model { ("minecraft", "noteblock") },
}
Bed {
@ -1169,10 +1197,14 @@ define_blocks! {
RedFlowerVariant::OrangeTulip,
RedFlowerVariant::WhiteTulip,
RedFlowerVariant::PinkTulip,
RedFlowerVariant::OxeyeDaisy
RedFlowerVariant::OxeyeDaisy,
RedFlowerVariant::Cornflower,
RedFlowerVariant::WitherRose,
RedFlowerVariant::LilyOfTheValley
],
},
data Some(variant.data()),
offsets |protocol_version| (variant.offsets(protocol_version)),
material material::NON_SOLID,
model { ("minecraft", variant.as_string()) },
collision vec![],
@ -1540,9 +1572,28 @@ define_blocks! {
Rotation::SouthSouthEast
],
waterlogged: bool = [true, false],
wood: TreeVariant = [
TreeVariant::Oak,
TreeVariant::Spruce,
TreeVariant::Birch,
TreeVariant::Jungle,
TreeVariant::Acacia,
TreeVariant::DarkOak
],
},
data if wood == TreeVariant::Oak && !waterlogged { Some(rotation.data()) } else { None },
offsets |protocol_version| {
let o = rotation.data() * 2 + if waterlogged { 0 } else { 1 };
if protocol_version >= 477 {
Some(wood.offset() * 2 * 16 + o)
} else {
if wood == TreeVariant::Oak {
Some(o)
} else {
None
}
}
},
data if !waterlogged { Some(rotation.data()) } else { None },
offset Some(rotation.data() * 2 + if waterlogged { 0 } else { 1 }),
material material::INVISIBLE,
model { ("minecraft", "standing_sign") },
collision vec![],
@ -1643,9 +1694,28 @@ define_blocks! {
Direction::East
],
waterlogged: bool = [true, false],
wood: TreeVariant = [
TreeVariant::Oak,
TreeVariant::Spruce,
TreeVariant::Birch,
TreeVariant::Jungle,
TreeVariant::Acacia,
TreeVariant::DarkOak
],
},
data if wood == TreeVariant::Oak && !waterlogged { Some(facing.index()) } else { None },
offsets |protocol_version| {
let o = if waterlogged { 0 } else { 1 } + facing.horizontal_offset() * 2;
if protocol_version >= 477 {
Some(wood.offset() * 2 * 4 + o)
} else {
if wood == TreeVariant::Oak {
Some(o)
} else {
None
}
}
},
data if !waterlogged { Some(facing.index()) } else { None },
offset Some(if waterlogged { 0 } else { 1 } + facing.horizontal_offset() * 2),
material material::INVISIBLE,
model { ("minecraft", "wall_sign") },
variant format!("facing={}", facing.as_string()),
@ -3115,12 +3185,17 @@ define_blocks! {
FlowerPotVariant::OrangeTulip,
FlowerPotVariant::WhiteTulip,
FlowerPotVariant::PinkTulip,
FlowerPotVariant::Oxeye
FlowerPotVariant::Oxeye,
FlowerPotVariant::Cornflower,
FlowerPotVariant::LilyOfTheValley,
FlowerPotVariant::WitherRose
],
legacy_data: u8 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
},
data if contents == FlowerPotVariant::Empty { Some(legacy_data as usize) } else { None },
offset if legacy_data != 0 { None } else { Some(contents.offset()) },
offsets |protocol_version | {
if legacy_data != 0 { None } else { contents.offsets(protocol_version) }
},
material material::NON_SOLID,
model { ("minecraft", "flower_pot") },
}
@ -4116,7 +4191,9 @@ define_blocks! {
type_: BlockHalf = [BlockHalf::Top, BlockHalf::Bottom, BlockHalf::Double],
variant: StoneSlabVariant = [
StoneSlabVariant::Stone,
StoneSlabVariant::SmoothStone,
StoneSlabVariant::Sandstone,
StoneSlabVariant::CutSandstone,
StoneSlabVariant::PetrifiedWood,
StoneSlabVariant::Cobblestone,
StoneSlabVariant::Brick,
@ -4124,12 +4201,15 @@ define_blocks! {
StoneSlabVariant::NetherBrick,
StoneSlabVariant::Quartz,
StoneSlabVariant::RedSandstone,
StoneSlabVariant::CutRedSandstone,
StoneSlabVariant::Purpur
],
waterlogged: bool = [true, false],
},
data None::<usize>,
offset Some(if waterlogged { 0 } else { 1 } + type_.offset() * 2 + variant.offset() * (2 * 3)),
offsets |protocol_version| {
variant.offsets(protocol_version).map(|o| if waterlogged { 0 } else { 1 } + type_.offset() * 2 + o * (2 * 3))
},
material material::NON_SOLID,
model { ("minecraft", format!("{}_slab", variant.as_string()) ) },
variant format!("type={}", type_.as_string()),
@ -6342,6 +6422,12 @@ pub enum NoteBlockInstrument {
Guitar,
Chime,
Xylophone,
IronXylophone,
CowBell,
Didgeridoo,
Bit,
Banjo,
Pling,
}
impl NoteBlockInstrument {
@ -6357,21 +6443,42 @@ impl NoteBlockInstrument {
NoteBlockInstrument::Guitar => "guitar",
NoteBlockInstrument::Chime => "chime",
NoteBlockInstrument::Xylophone => "xylophone",
NoteBlockInstrument::IronXylophone => "iron_xylophone",
NoteBlockInstrument::CowBell => "cow_bell",
NoteBlockInstrument::Didgeridoo => "didgeridoo",
NoteBlockInstrument::Bit => "bit",
NoteBlockInstrument::Banjo => "banjo",
NoteBlockInstrument::Pling => "pling",
}
}
fn offset(self) -> usize {
fn offsets(self, protocol_version: i32) -> Option<usize> {
match self {
NoteBlockInstrument::Harp => 0,
NoteBlockInstrument::BaseDrum => 1,
NoteBlockInstrument::Snare => 2,
NoteBlockInstrument::Hat => 3,
NoteBlockInstrument::Bass => 4,
NoteBlockInstrument::Flute => 5,
NoteBlockInstrument::Bell => 6,
NoteBlockInstrument::Guitar => 7,
NoteBlockInstrument::Chime => 8,
NoteBlockInstrument::Xylophone => 9,
NoteBlockInstrument::Harp => Some(0),
NoteBlockInstrument::BaseDrum => Some(1),
NoteBlockInstrument::Snare => Some(2),
NoteBlockInstrument::Hat => Some(3),
NoteBlockInstrument::Bass => Some(4),
NoteBlockInstrument::Flute => Some(5),
NoteBlockInstrument::Bell => Some(6),
NoteBlockInstrument::Guitar => Some(7),
NoteBlockInstrument::Chime => Some(8),
NoteBlockInstrument::Xylophone => Some(9),
_ => {
if protocol_version >= 477 {
match self {
NoteBlockInstrument::IronXylophone => Some(10),
NoteBlockInstrument::CowBell => Some(11),
NoteBlockInstrument::Didgeridoo => Some(12),
NoteBlockInstrument::Bit => Some(13),
NoteBlockInstrument::Banjo => Some(14),
NoteBlockInstrument::Pling => Some(15),
_ => unreachable!(),
}
} else {
None
}
}
}
}
}
@ -6642,6 +6749,9 @@ pub enum RedFlowerVariant {
WhiteTulip,
PinkTulip,
OxeyeDaisy,
Cornflower,
WitherRose,
LilyOfTheValley,
}
impl RedFlowerVariant {
@ -6656,6 +6766,9 @@ impl RedFlowerVariant {
RedFlowerVariant::WhiteTulip => "white_tulip",
RedFlowerVariant::PinkTulip => "pink_tulip",
RedFlowerVariant::OxeyeDaisy => "oxeye_daisy",
RedFlowerVariant::Cornflower => "cornflower",
RedFlowerVariant::WitherRose => "wither_rose",
RedFlowerVariant::LilyOfTheValley => "lily_of_the_valley",
}
}
@ -6670,6 +6783,36 @@ impl RedFlowerVariant {
RedFlowerVariant::WhiteTulip => 6,
RedFlowerVariant::PinkTulip => 7,
RedFlowerVariant::OxeyeDaisy => 8,
// TODO: shouldn't be available protocol_version < 477
RedFlowerVariant::Cornflower => 9,
RedFlowerVariant::WitherRose => 10,
RedFlowerVariant::LilyOfTheValley => 11,
}
}
fn offsets(self, protocol_version: i32) -> Option<usize> {
match self {
RedFlowerVariant::Poppy => Some(0),
RedFlowerVariant::BlueOrchid => Some(1),
RedFlowerVariant::Allium => Some(2),
RedFlowerVariant::AzureBluet => Some(3),
RedFlowerVariant::RedTulip => Some(4),
RedFlowerVariant::OrangeTulip => Some(5),
RedFlowerVariant::WhiteTulip => Some(6),
RedFlowerVariant::PinkTulip => Some(7),
RedFlowerVariant::OxeyeDaisy => Some(8),
_ => {
if protocol_version >= 477 {
match self {
RedFlowerVariant::Cornflower => Some(9),
RedFlowerVariant::WitherRose => Some(10),
RedFlowerVariant::LilyOfTheValley => Some(11),
_ => unreachable!(),
}
} else {
None
}
}
}
}
}
@ -6840,7 +6983,9 @@ impl PistonType {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum StoneSlabVariant {
Stone,
SmoothStone,
Sandstone,
CutSandstone,
PetrifiedWood,
Cobblestone,
Brick,
@ -6848,6 +6993,7 @@ pub enum StoneSlabVariant {
NetherBrick,
Quartz,
RedSandstone,
CutRedSandstone,
Purpur,
}
@ -6855,7 +7001,9 @@ impl StoneSlabVariant {
pub fn as_string(self) -> &'static str {
match self {
StoneSlabVariant::Stone => "stone",
StoneSlabVariant::SmoothStone => "smooth_stone",
StoneSlabVariant::Sandstone => "sandstone",
StoneSlabVariant::CutSandstone => "cut_sandstone",
StoneSlabVariant::PetrifiedWood => "wood_old",
StoneSlabVariant::Cobblestone => "cobblestone",
StoneSlabVariant::Brick => "brick",
@ -6863,6 +7011,7 @@ impl StoneSlabVariant {
StoneSlabVariant::NetherBrick => "nether_brick",
StoneSlabVariant::Quartz => "quartz",
StoneSlabVariant::RedSandstone => "red_sandstone",
StoneSlabVariant::CutRedSandstone => "cut_red_sandstone",
StoneSlabVariant::Purpur => "purpur",
}
}
@ -6879,21 +7028,43 @@ impl StoneSlabVariant {
StoneSlabVariant::StoneBrick => 5,
StoneSlabVariant::NetherBrick => 6,
StoneSlabVariant::Quartz => 7,
_ => unimplemented!(),
}
}
fn offset(self) -> usize {
match self {
StoneSlabVariant::Stone => 0,
StoneSlabVariant::Sandstone => 1,
StoneSlabVariant::PetrifiedWood => 2,
StoneSlabVariant::Cobblestone => 3,
StoneSlabVariant::Brick => 4,
StoneSlabVariant::StoneBrick => 5,
StoneSlabVariant::NetherBrick => 6,
StoneSlabVariant::Quartz => 7,
StoneSlabVariant::RedSandstone => 8,
StoneSlabVariant::Purpur => 9,
fn offsets(self, protocol_version: i32) -> Option<usize> {
if protocol_version >= 477 {
match self {
StoneSlabVariant::Stone => Some(0),
StoneSlabVariant::SmoothStone => Some(1),
StoneSlabVariant::Sandstone => Some(2),
StoneSlabVariant::CutSandstone => Some(3),
StoneSlabVariant::PetrifiedWood => Some(4),
StoneSlabVariant::Cobblestone => Some(5),
StoneSlabVariant::Brick => Some(6),
StoneSlabVariant::StoneBrick => Some(7),
StoneSlabVariant::NetherBrick => Some(8),
StoneSlabVariant::Quartz => Some(9),
StoneSlabVariant::RedSandstone => Some(10),
StoneSlabVariant::CutRedSandstone => Some(11),
StoneSlabVariant::Purpur => Some(12),
}
} else {
match self {
StoneSlabVariant::Stone => Some(0),
StoneSlabVariant::SmoothStone => None,
StoneSlabVariant::Sandstone => Some(1),
StoneSlabVariant::CutSandstone => None,
StoneSlabVariant::PetrifiedWood => Some(2),
StoneSlabVariant::Cobblestone => Some(3),
StoneSlabVariant::Brick => Some(4),
StoneSlabVariant::StoneBrick => Some(5),
StoneSlabVariant::NetherBrick => Some(6),
StoneSlabVariant::Quartz => Some(7),
StoneSlabVariant::RedSandstone => Some(8),
StoneSlabVariant::CutRedSandstone => None,
StoneSlabVariant::Purpur => Some(9),
}
}
}
}
@ -7391,6 +7562,9 @@ pub enum FlowerPotVariant {
WhiteTulip,
PinkTulip,
Oxeye,
Cornflower,
LilyOfTheValley,
WitherRose,
}
impl FlowerPotVariant {
@ -7418,33 +7592,59 @@ impl FlowerPotVariant {
FlowerPotVariant::WhiteTulip => "white_tulip",
FlowerPotVariant::PinkTulip => "pink_tulip",
FlowerPotVariant::Oxeye => "oxeye_daisy",
FlowerPotVariant::Cornflower => "cornflower",
FlowerPotVariant::LilyOfTheValley => "lily_of_the_valley",
FlowerPotVariant::WitherRose => "wither_rose",
}
}
pub fn offset(self) -> usize {
pub fn offsets(self, protocol_version: i32) -> Option<usize> {
match self {
FlowerPotVariant::Empty => 0,
FlowerPotVariant::OakSapling => 1,
FlowerPotVariant::SpruceSapling => 2,
FlowerPotVariant::BirchSapling => 3,
FlowerPotVariant::JungleSapling => 4,
FlowerPotVariant::AcaciaSapling => 5,
FlowerPotVariant::DarkOakSapling => 6,
FlowerPotVariant::Fern => 7,
FlowerPotVariant::Dandelion => 8,
FlowerPotVariant::Poppy => 9,
FlowerPotVariant::BlueOrchid => 10,
FlowerPotVariant::Allium => 11,
FlowerPotVariant::AzureBluet => 12,
FlowerPotVariant::RedTulip => 13,
FlowerPotVariant::OrangeTulip => 14,
FlowerPotVariant::WhiteTulip => 15,
FlowerPotVariant::PinkTulip => 16,
FlowerPotVariant::Oxeye => 17,
FlowerPotVariant::RedMushroom => 18,
FlowerPotVariant::BrownMushroom => 19,
FlowerPotVariant::DeadBush => 20,
FlowerPotVariant::Cactus => 21,
FlowerPotVariant::Empty => Some(0),
FlowerPotVariant::OakSapling => Some(1),
FlowerPotVariant::SpruceSapling => Some(2),
FlowerPotVariant::BirchSapling => Some(3),
FlowerPotVariant::JungleSapling => Some(4),
FlowerPotVariant::AcaciaSapling => Some(5),
FlowerPotVariant::DarkOakSapling => Some(6),
FlowerPotVariant::Fern => Some(7),
FlowerPotVariant::Dandelion => Some(8),
FlowerPotVariant::Poppy => Some(9),
FlowerPotVariant::BlueOrchid => Some(10),
FlowerPotVariant::Allium => Some(11),
FlowerPotVariant::AzureBluet => Some(12),
FlowerPotVariant::RedTulip => Some(13),
FlowerPotVariant::OrangeTulip => Some(14),
FlowerPotVariant::WhiteTulip => Some(15),
FlowerPotVariant::PinkTulip => Some(16),
FlowerPotVariant::Oxeye => Some(17),
FlowerPotVariant::Cornflower => {
if protocol_version >= 477 {
Some(18)
} else {
None
}
}
FlowerPotVariant::LilyOfTheValley => {
if protocol_version >= 477 {
Some(19)
} else {
None
}
}
FlowerPotVariant::WitherRose => {
if protocol_version >= 477 {
Some(20)
} else {
None
}
}
FlowerPotVariant::RedMushroom => Some(if protocol_version >= 477 { 21 } else { 18 }),
FlowerPotVariant::BrownMushroom => Some(if protocol_version >= 477 { 22 } else { 19 }),
FlowerPotVariant::DeadBush => Some(if protocol_version >= 477 { 23 } else { 20 }),
FlowerPotVariant::Cactus => Some(if protocol_version >= 477 { 24 } else { 21 }),
}
}
}

View File

@ -1950,11 +1950,9 @@ impl Server {
fn on_block_change(&mut self, location: Position, id: i32) {
self.world.set_block(
location,
block::Block::by_vanilla_id(
id as usize,
self.protocol_version,
&self.world.modded_block_ids,
),
self.world
.id_map
.by_vanilla_id(id as usize, &self.world.modded_block_ids),
)
}
@ -1988,11 +1986,9 @@ impl Server {
self.world.set_block(
Position::new(sx + lx as i32, sy + ly as i32, sz + lz as i32),
block::Block::by_vanilla_id(
block_raw_id as usize,
self.protocol_version,
&self.world.modded_block_ids,
),
self.world
.id_map
.by_vanilla_id(block_raw_id as usize, &self.world.modded_block_ids),
);
}
}
@ -2010,11 +2006,9 @@ impl Server {
record.y as i32,
oz + (record.xz & 0xF) as i32,
),
block::Block::by_vanilla_id(
record.block_id.0 as usize,
self.protocol_version,
&self.world.modded_block_ids,
),
self.world
.id_map
.by_vanilla_id(record.block_id.0 as usize, &self.world.modded_block_ids),
);
}
}
@ -2040,11 +2034,9 @@ impl Server {
self.world.set_block(
Position::new(x, y, z),
block::Block::by_vanilla_id(
id as usize,
self.protocol_version,
&self.world.modded_block_ids,
),
self.world
.id_map
.by_vanilla_id(id as usize, &self.world.modded_block_ids),
);
}
}

View File

@ -46,6 +46,7 @@ pub struct World {
protocol_version: i32,
pub modded_block_ids: HashMap<usize, String>,
pub id_map: block::VanillaIDMap,
}
#[derive(Clone, Debug)]
@ -91,8 +92,10 @@ struct LightUpdate {
impl World {
pub fn new(protocol_version: i32) -> World {
let id_map = block::VanillaIDMap::new(protocol_version);
World {
protocol_version,
id_map,
..Default::default()
}
}
@ -686,11 +689,8 @@ impl World {
let id = data.read_u16::<byteorder::LittleEndian>()?;
section.blocks.set(
bi,
block::Block::by_vanilla_id(
id as usize,
self.protocol_version,
&self.modded_block_ids,
),
self.id_map
.by_vanilla_id(id as usize, &self.modded_block_ids),
);
// Spawn block entities
@ -938,11 +938,8 @@ impl World {
| (block_meta[i].get(bi) as u16);
section.blocks.set(
bi,
block::Block::by_vanilla_id(
id as usize,
self.protocol_version,
&self.modded_block_ids,
),
self.id_map
.by_vanilla_id(id as usize, &self.modded_block_ids),
);
// Spawn block entities
@ -1056,11 +1053,9 @@ impl World {
let count = VarInt::read_from(&mut data)?.0;
for i in 0..count {
let id = VarInt::read_from(&mut data)?.0;
let bl = block::Block::by_vanilla_id(
id as usize,
self.protocol_version,
&self.modded_block_ids,
);
let bl = self
.id_map
.by_vanilla_id(id as usize, &self.modded_block_ids);
mappings.insert(i as usize, bl);
}
}
@ -1077,11 +1072,7 @@ impl World {
.get(&id)
.cloned()
// TODO: fix or_fun_call, but do not re-borrow self
.unwrap_or(block::Block::by_vanilla_id(
id,
self.protocol_version,
&self.modded_block_ids,
)),
.unwrap_or(self.id_map.by_vanilla_id(id, &self.modded_block_ids)),
);
// Spawn block entities
let b = section.blocks.get(bi);