Add support for a modded block: rockwool from Thermal Expansion (#153)
The first in support for modded content, a simple custom block: "rockwool" from the Thermal Expansion and Thermal Foundation mods for Forge: https://ftb.gamepedia.com/Rockwool_(Thermal_Expansion_3) This makes use of the Forge handshake (#88 #134 #144), matching the mod block names from the negotiation to numeric identifiers in the world to steven_blocks. Rockwool was chosen due to ease of implementation, it looks like wool from vanilla (except is fire-proof), and by supporting it the groundwork necessary is laid for more sophisticated mod support. Tested with Thermal Expansion on 1.7.10, 1.10.2 (FTB Beyond), and 1.12.2 Forge servers. * Add `modid` macro token, skipped from vanilla mappings * Add ThermalExpansionRockwool block (1.7.10) * Register modded blocks by modid->[data], and lookup block metadata * Save block IDs from ModIdData/RegistryData to World modded_block_ids * Add namespaced mod ids for ModIdData, \u{1}=block \u{2}=item * Add ThermalFoundation's Rockwool (1.12.2)
This commit is contained in:
parent
480b865363
commit
e9b336192a
|
@ -7,6 +7,7 @@ use crate::shared::{Axis, Direction, Position};
|
|||
use collision::Aabb3;
|
||||
use cgmath::Point3;
|
||||
use lazy_static::lazy_static;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub mod material;
|
||||
pub use self::material::Material;
|
||||
|
@ -44,12 +45,14 @@ macro_rules! create_ids {
|
|||
struct VanillaIDMap {
|
||||
flat: Vec<Option<Block>>,
|
||||
hier: Vec<Option<Block>>,
|
||||
modded: HashMap<String, [Option<Block>; 16]>,
|
||||
}
|
||||
|
||||
macro_rules! define_blocks {
|
||||
(
|
||||
$(
|
||||
$name:ident {
|
||||
$(modid $modid:expr,)*
|
||||
props {
|
||||
$(
|
||||
$fname:ident : $ftype:ty = [$($val:expr),+],
|
||||
|
@ -133,11 +136,43 @@ macro_rules! define_blocks {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn by_vanilla_id(id: usize, protocol_version: i32) -> Block {
|
||||
#[allow(unused_variables, unreachable_code)]
|
||||
pub fn get_modid(&self) -> Option<&str> {
|
||||
match *self {
|
||||
$(
|
||||
Block::$name {
|
||||
$($fname,)*
|
||||
} => {
|
||||
$(
|
||||
return Some($modid);
|
||||
)*
|
||||
None
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
VANILLA_ID_MAP.hier.get(id).and_then(|v| *v).unwrap_or(Block::Missing{})
|
||||
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 {
|
||||
//println!("Modded block not supported yet: {}:{} -> {}", id >> 4, data, name);
|
||||
Block::Missing{}
|
||||
}
|
||||
} else {
|
||||
Block::Missing{}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -257,6 +292,7 @@ macro_rules! define_blocks {
|
|||
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;
|
||||
|
@ -353,6 +389,16 @@ macro_rules! define_blocks {
|
|||
for block in iter {
|
||||
let internal_id = block.get_internal_id();
|
||||
let hier_data: Option<usize> = block.get_hierarchical_data();
|
||||
if let Some(modid) = block.get_modid() {
|
||||
let hier_data = hier_data.unwrap();
|
||||
if !blocks_modded.contains_key(modid) {
|
||||
blocks_modded.insert(modid.to_string(), [None; 16]);
|
||||
}
|
||||
let block_from_data = blocks_modded.get_mut(modid).unwrap();
|
||||
block_from_data[hier_data] = Some(block);
|
||||
continue
|
||||
}
|
||||
|
||||
let vanilla_id =
|
||||
if let Some(hier_data) = hier_data {
|
||||
if internal_id != last_internal_id {
|
||||
|
@ -422,7 +468,7 @@ macro_rules! define_blocks {
|
|||
}
|
||||
})+
|
||||
|
||||
VanillaIDMap { flat: blocks_flat, hier: blocks_hier }
|
||||
VanillaIDMap { flat: blocks_flat, hier: blocks_hier, modded: blocks_modded }
|
||||
};
|
||||
}
|
||||
);
|
||||
|
@ -1014,6 +1060,56 @@ define_blocks! {
|
|||
data Some(color.data()),
|
||||
model { ("minecraft", format!("{}_wool", color.as_string()) ) },
|
||||
}
|
||||
ThermalExpansionRockwool {
|
||||
modid "ThermalExpansion:Rockwool",
|
||||
props {
|
||||
color: ColoredVariant = [
|
||||
ColoredVariant::White,
|
||||
ColoredVariant::Orange,
|
||||
ColoredVariant::Magenta,
|
||||
ColoredVariant::LightBlue,
|
||||
ColoredVariant::Yellow,
|
||||
ColoredVariant::Lime,
|
||||
ColoredVariant::Pink,
|
||||
ColoredVariant::Gray,
|
||||
ColoredVariant::Silver,
|
||||
ColoredVariant::Cyan,
|
||||
ColoredVariant::Purple,
|
||||
ColoredVariant::Blue,
|
||||
ColoredVariant::Brown,
|
||||
ColoredVariant::Green,
|
||||
ColoredVariant::Red,
|
||||
ColoredVariant::Black
|
||||
],
|
||||
},
|
||||
data Some(color.data()),
|
||||
model { ("minecraft", format!("{}_wool", color.as_string()) ) },
|
||||
}
|
||||
ThermalFoundationRockwool {
|
||||
modid "thermalfoundation:rockwool",
|
||||
props {
|
||||
color: ColoredVariant = [
|
||||
ColoredVariant::White,
|
||||
ColoredVariant::Orange,
|
||||
ColoredVariant::Magenta,
|
||||
ColoredVariant::LightBlue,
|
||||
ColoredVariant::Yellow,
|
||||
ColoredVariant::Lime,
|
||||
ColoredVariant::Pink,
|
||||
ColoredVariant::Gray,
|
||||
ColoredVariant::Silver,
|
||||
ColoredVariant::Cyan,
|
||||
ColoredVariant::Purple,
|
||||
ColoredVariant::Blue,
|
||||
ColoredVariant::Brown,
|
||||
ColoredVariant::Green,
|
||||
ColoredVariant::Red,
|
||||
ColoredVariant::Black
|
||||
],
|
||||
},
|
||||
data Some(color.data()),
|
||||
model { ("minecraft", format!("{}_wool", color.as_string()) ) },
|
||||
}
|
||||
PistonExtension {
|
||||
props {
|
||||
facing: Direction = [
|
||||
|
|
|
@ -85,6 +85,9 @@ impl Serializable for ModIdMapping {
|
|||
}
|
||||
}
|
||||
|
||||
pub static BLOCK_NAMESPACE: &'static str = "\u{1}";
|
||||
pub static ITEM_NAMESPACE: &'static str = "\u{2}";
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum FmlHs {
|
||||
ServerHello {
|
||||
|
|
|
@ -711,17 +711,26 @@ impl Server {
|
|||
|
||||
self.write_fmlhs_plugin_message(&HandshakeAck { phase: WaitingServerData });
|
||||
},
|
||||
ModIdData { mappings: _, block_substitutions: _, item_substitutions: _ } => {
|
||||
ModIdData { mappings, block_substitutions: _, item_substitutions: _ } => {
|
||||
println!("Received FML|HS ModIdData");
|
||||
for m in mappings.data {
|
||||
let (namespace, name) = m.name.split_at(1);
|
||||
if namespace == protocol::forge::BLOCK_NAMESPACE {
|
||||
self.world.modded_block_ids.insert(m.id.0 as usize, name.to_string());
|
||||
}
|
||||
}
|
||||
self.write_fmlhs_plugin_message(&HandshakeAck { phase: WaitingServerComplete });
|
||||
// TODO: dynamically register mod blocks
|
||||
},
|
||||
RegistryData { has_more, name, ids: _, substitutions: _, dummies: _ } => {
|
||||
RegistryData { has_more, name, ids, substitutions: _, dummies: _ } => {
|
||||
println!("Received FML|HS RegistryData for {}", name);
|
||||
if name == "minecraft:blocks" {
|
||||
for m in ids.data {
|
||||
self.world.modded_block_ids.insert(m.id.0 as usize, m.name);
|
||||
}
|
||||
}
|
||||
if !has_more {
|
||||
self.write_fmlhs_plugin_message(&HandshakeAck { phase: WaitingServerComplete });
|
||||
}
|
||||
// TODO: dynamically register mod blocks
|
||||
},
|
||||
HandshakeAck { phase } => {
|
||||
match phase {
|
||||
|
@ -1285,7 +1294,7 @@ 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.set_block(location, block::Block::by_vanilla_id(id as usize, self.protocol_version, &self.world.modded_block_ids))
|
||||
}
|
||||
|
||||
fn on_block_change_varint(&mut self, block_change: packet::play::clientbound::BlockChange_VarInt) {
|
||||
|
@ -1309,7 +1318,7 @@ 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)
|
||||
block::Block::by_vanilla_id(record.block_id.0 as usize, self.protocol_version, &self.world.modded_block_ids)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1332,7 +1341,7 @@ impl Server {
|
|||
|
||||
self.world.set_block(
|
||||
Position::new(x, y, z),
|
||||
block::Block::by_vanilla_id(id as usize, self.protocol_version)
|
||||
block::Block::by_vanilla_id(id as usize, self.protocol_version, &self.world.modded_block_ids)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ pub struct World {
|
|||
block_entity_actions: VecDeque<BlockEntityAction>,
|
||||
|
||||
protocol_version: i32,
|
||||
pub modded_block_ids: HashMap<usize, String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -619,7 +620,7 @@ impl World {
|
|||
|
||||
for bi in 0 .. 4096 {
|
||||
let id = data.read_u16::<byteorder::LittleEndian>()?;
|
||||
section.blocks.set(bi, block::Block::by_vanilla_id(id as usize, self.protocol_version));
|
||||
section.blocks.set(bi, block::Block::by_vanilla_id(id as usize, self.protocol_version, &self.modded_block_ids));
|
||||
|
||||
// Spawn block entities
|
||||
let b = section.blocks.get(bi);
|
||||
|
@ -805,7 +806,7 @@ impl World {
|
|||
|
||||
for bi in 0 .. 4096 {
|
||||
let id = ((block_add[i].get(bi) as u16) << 12) | ((block_types[i][bi] as u16) << 4) | (block_meta[i].get(bi) as u16);
|
||||
section.blocks.set(bi, block::Block::by_vanilla_id(id as usize, self.protocol_version));
|
||||
section.blocks.set(bi, block::Block::by_vanilla_id(id as usize, self.protocol_version, &self.modded_block_ids));
|
||||
|
||||
// Spawn block entities
|
||||
let b = section.blocks.get(bi);
|
||||
|
@ -882,7 +883,7 @@ 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);
|
||||
let bl = block::Block::by_vanilla_id(id as usize, self.protocol_version, &self.modded_block_ids);
|
||||
mappings.insert(i as usize, bl);
|
||||
}
|
||||
}
|
||||
|
@ -892,7 +893,7 @@ impl World {
|
|||
|
||||
for bi in 0 .. 4096 {
|
||||
let id = m.get(bi);
|
||||
section.blocks.set(bi, mappings.get(&id).cloned().unwrap_or(block::Block::by_vanilla_id(id, self.protocol_version)));
|
||||
section.blocks.set(bi, mappings.get(&id).cloned().unwrap_or(block::Block::by_vanilla_id(id, self.protocol_version, &self.modded_block_ids)));
|
||||
// Spawn block entities
|
||||
let b = section.blocks.get(bi);
|
||||
if block_entity::BlockEntityType::get_block_entity(b).is_some() {
|
||||
|
|
Loading…
Reference in New Issue