Skip to content

Commit 6fd4a12

Browse files
authored
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)
1 parent a291cfa commit 6fd4a12

File tree

4 files changed

+123
-14
lines changed

4 files changed

+123
-14
lines changed

blocks/src/lib.rs

Lines changed: 99 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::shared::{Axis, Direction, Position};
77
use collision::Aabb3;
88
use cgmath::Point3;
99
use lazy_static::lazy_static;
10+
use std::collections::HashMap;
1011

1112
pub mod material;
1213
pub use self::material::Material;
@@ -44,12 +45,14 @@ macro_rules! create_ids {
4445
struct VanillaIDMap {
4546
flat: Vec<Option<Block>>,
4647
hier: Vec<Option<Block>>,
48+
modded: HashMap<String, [Option<Block>; 16]>,
4749
}
4850

4951
macro_rules! define_blocks {
5052
(
5153
$(
5254
$name:ident {
55+
$(modid $modid:expr,)*
5356
props {
5457
$(
5558
$fname:ident : $ftype:ty = [$($val:expr),+],
@@ -133,11 +136,43 @@ macro_rules! define_blocks {
133136
}
134137
}
135138

136-
pub fn by_vanilla_id(id: usize, protocol_version: i32) -> Block {
139+
#[allow(unused_variables, unreachable_code)]
140+
pub fn get_modid(&self) -> Option<&str> {
141+
match *self {
142+
$(
143+
Block::$name {
144+
$($fname,)*
145+
} => {
146+
$(
147+
return Some($modid);
148+
)*
149+
None
150+
}
151+
)+
152+
}
153+
}
154+
155+
pub fn by_vanilla_id(id: usize, protocol_version: i32, modded_block_ids: &HashMap<usize, String>) -> Block {
137156
if protocol_version >= 404 {
138157
VANILLA_ID_MAP.flat.get(id).and_then(|v| *v).unwrap_or(Block::Missing{})
158+
// TODO: support modded 1.13.2+ blocks after https://github.com/iceiix/stevenarella/pull/145
139159
} else {
140-
VANILLA_ID_MAP.hier.get(id).and_then(|v| *v).unwrap_or(Block::Missing{})
160+
if let Some(block) = VANILLA_ID_MAP.hier.get(id).and_then(|v| *v) {
161+
block
162+
} else {
163+
let data = id & 0xf;
164+
165+
if let Some(name) = modded_block_ids.get(&(id >> 4)) {
166+
if let Some(blocks_by_data) = VANILLA_ID_MAP.modded.get(name) {
167+
blocks_by_data[data].unwrap_or(Block::Missing{})
168+
} else {
169+
//println!("Modded block not supported yet: {}:{} -> {}", id >> 4, data, name);
170+
Block::Missing{}
171+
}
172+
} else {
173+
Block::Missing{}
174+
}
175+
}
141176
}
142177
}
143178

@@ -257,6 +292,7 @@ macro_rules! define_blocks {
257292
static ref VANILLA_ID_MAP: VanillaIDMap = {
258293
let mut blocks_flat = vec![];
259294
let mut blocks_hier = vec![];
295+
let mut blocks_modded: HashMap<String, [Option<Block>; 16]> = HashMap::new();
260296
let mut flat_id = 0;
261297
let mut last_internal_id = 0;
262298
let mut hier_block_id = 0;
@@ -353,6 +389,16 @@ macro_rules! define_blocks {
353389
for block in iter {
354390
let internal_id = block.get_internal_id();
355391
let hier_data: Option<usize> = block.get_hierarchical_data();
392+
if let Some(modid) = block.get_modid() {
393+
let hier_data = hier_data.unwrap();
394+
if !blocks_modded.contains_key(modid) {
395+
blocks_modded.insert(modid.to_string(), [None; 16]);
396+
}
397+
let block_from_data = blocks_modded.get_mut(modid).unwrap();
398+
block_from_data[hier_data] = Some(block);
399+
continue
400+
}
401+
356402
let vanilla_id =
357403
if let Some(hier_data) = hier_data {
358404
if internal_id != last_internal_id {
@@ -422,7 +468,7 @@ macro_rules! define_blocks {
422468
}
423469
})+
424470

425-
VanillaIDMap { flat: blocks_flat, hier: blocks_hier }
471+
VanillaIDMap { flat: blocks_flat, hier: blocks_hier, modded: blocks_modded }
426472
};
427473
}
428474
);
@@ -1014,6 +1060,56 @@ define_blocks! {
10141060
data Some(color.data()),
10151061
model { ("minecraft", format!("{}_wool", color.as_string()) ) },
10161062
}
1063+
ThermalExpansionRockwool {
1064+
modid "ThermalExpansion:Rockwool",
1065+
props {
1066+
color: ColoredVariant = [
1067+
ColoredVariant::White,
1068+
ColoredVariant::Orange,
1069+
ColoredVariant::Magenta,
1070+
ColoredVariant::LightBlue,
1071+
ColoredVariant::Yellow,
1072+
ColoredVariant::Lime,
1073+
ColoredVariant::Pink,
1074+
ColoredVariant::Gray,
1075+
ColoredVariant::Silver,
1076+
ColoredVariant::Cyan,
1077+
ColoredVariant::Purple,
1078+
ColoredVariant::Blue,
1079+
ColoredVariant::Brown,
1080+
ColoredVariant::Green,
1081+
ColoredVariant::Red,
1082+
ColoredVariant::Black
1083+
],
1084+
},
1085+
data Some(color.data()),
1086+
model { ("minecraft", format!("{}_wool", color.as_string()) ) },
1087+
}
1088+
ThermalFoundationRockwool {
1089+
modid "thermalfoundation:rockwool",
1090+
props {
1091+
color: ColoredVariant = [
1092+
ColoredVariant::White,
1093+
ColoredVariant::Orange,
1094+
ColoredVariant::Magenta,
1095+
ColoredVariant::LightBlue,
1096+
ColoredVariant::Yellow,
1097+
ColoredVariant::Lime,
1098+
ColoredVariant::Pink,
1099+
ColoredVariant::Gray,
1100+
ColoredVariant::Silver,
1101+
ColoredVariant::Cyan,
1102+
ColoredVariant::Purple,
1103+
ColoredVariant::Blue,
1104+
ColoredVariant::Brown,
1105+
ColoredVariant::Green,
1106+
ColoredVariant::Red,
1107+
ColoredVariant::Black
1108+
],
1109+
},
1110+
data Some(color.data()),
1111+
model { ("minecraft", format!("{}_wool", color.as_string()) ) },
1112+
}
10171113
PistonExtension {
10181114
props {
10191115
facing: Direction = [

src/protocol/forge.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ impl Serializable for ModIdMapping {
8585
}
8686
}
8787

88+
pub static BLOCK_NAMESPACE: &'static str = "\u{1}";
89+
pub static ITEM_NAMESPACE: &'static str = "\u{2}";
90+
8891
#[derive(Debug)]
8992
pub enum FmlHs {
9093
ServerHello {

src/server/mod.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -711,17 +711,26 @@ impl Server {
711711

712712
self.write_fmlhs_plugin_message(&HandshakeAck { phase: WaitingServerData });
713713
},
714-
ModIdData { mappings: _, block_substitutions: _, item_substitutions: _ } => {
714+
ModIdData { mappings, block_substitutions: _, item_substitutions: _ } => {
715715
println!("Received FML|HS ModIdData");
716+
for m in mappings.data {
717+
let (namespace, name) = m.name.split_at(1);
718+
if namespace == protocol::forge::BLOCK_NAMESPACE {
719+
self.world.modded_block_ids.insert(m.id.0 as usize, name.to_string());
720+
}
721+
}
716722
self.write_fmlhs_plugin_message(&HandshakeAck { phase: WaitingServerComplete });
717-
// TODO: dynamically register mod blocks
718723
},
719-
RegistryData { has_more, name, ids: _, substitutions: _, dummies: _ } => {
724+
RegistryData { has_more, name, ids, substitutions: _, dummies: _ } => {
720725
println!("Received FML|HS RegistryData for {}", name);
726+
if name == "minecraft:blocks" {
727+
for m in ids.data {
728+
self.world.modded_block_ids.insert(m.id.0 as usize, m.name);
729+
}
730+
}
721731
if !has_more {
722732
self.write_fmlhs_plugin_message(&HandshakeAck { phase: WaitingServerComplete });
723733
}
724-
// TODO: dynamically register mod blocks
725734
},
726735
HandshakeAck { phase } => {
727736
match phase {
@@ -1285,7 +1294,7 @@ impl Server {
12851294
}
12861295

12871296
fn on_block_change(&mut self, location: Position, id: i32) {
1288-
self.world.set_block(location, block::Block::by_vanilla_id(id as usize, self.protocol_version))
1297+
self.world.set_block(location, block::Block::by_vanilla_id(id as usize, self.protocol_version, &self.world.modded_block_ids))
12891298
}
12901299

12911300
fn on_block_change_varint(&mut self, block_change: packet::play::clientbound::BlockChange_VarInt) {
@@ -1309,7 +1318,7 @@ impl Server {
13091318
record.y as i32,
13101319
oz + (record.xz & 0xF) as i32
13111320
),
1312-
block::Block::by_vanilla_id(record.block_id.0 as usize, self.protocol_version)
1321+
block::Block::by_vanilla_id(record.block_id.0 as usize, self.protocol_version, &self.world.modded_block_ids)
13131322
);
13141323
}
13151324
}
@@ -1332,7 +1341,7 @@ impl Server {
13321341

13331342
self.world.set_block(
13341343
Position::new(x, y, z),
1335-
block::Block::by_vanilla_id(id as usize, self.protocol_version)
1344+
block::Block::by_vanilla_id(id as usize, self.protocol_version, &self.world.modded_block_ids)
13361345
);
13371346
}
13381347
}

src/world/mod.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ pub struct World {
4545
block_entity_actions: VecDeque<BlockEntityAction>,
4646

4747
protocol_version: i32,
48+
pub modded_block_ids: HashMap<usize, String>,
4849
}
4950

5051
#[derive(Clone, Debug)]
@@ -619,7 +620,7 @@ impl World {
619620

620621
for bi in 0 .. 4096 {
621622
let id = data.read_u16::<byteorder::LittleEndian>()?;
622-
section.blocks.set(bi, block::Block::by_vanilla_id(id as usize, self.protocol_version));
623+
section.blocks.set(bi, block::Block::by_vanilla_id(id as usize, self.protocol_version, &self.modded_block_ids));
623624

624625
// Spawn block entities
625626
let b = section.blocks.get(bi);
@@ -805,7 +806,7 @@ impl World {
805806

806807
for bi in 0 .. 4096 {
807808
let id = ((block_add[i].get(bi) as u16) << 12) | ((block_types[i][bi] as u16) << 4) | (block_meta[i].get(bi) as u16);
808-
section.blocks.set(bi, block::Block::by_vanilla_id(id as usize, self.protocol_version));
809+
section.blocks.set(bi, block::Block::by_vanilla_id(id as usize, self.protocol_version, &self.modded_block_ids));
809810

810811
// Spawn block entities
811812
let b = section.blocks.get(bi);
@@ -882,7 +883,7 @@ impl World {
882883
let count = VarInt::read_from(&mut data)?.0;
883884
for i in 0 .. count {
884885
let id = VarInt::read_from(&mut data)?.0;
885-
let bl = block::Block::by_vanilla_id(id as usize, self.protocol_version);
886+
let bl = block::Block::by_vanilla_id(id as usize, self.protocol_version, &self.modded_block_ids);
886887
mappings.insert(i as usize, bl);
887888
}
888889
}
@@ -892,7 +893,7 @@ impl World {
892893

893894
for bi in 0 .. 4096 {
894895
let id = m.get(bi);
895-
section.blocks.set(bi, mappings.get(&id).cloned().unwrap_or(block::Block::by_vanilla_id(id, self.protocol_version)));
896+
section.blocks.set(bi, mappings.get(&id).cloned().unwrap_or(block::Block::by_vanilla_id(id, self.protocol_version, &self.modded_block_ids)));
896897
// Spawn block entities
897898
let b = section.blocks.get(bi);
898899
if block_entity::BlockEntityType::get_block_entity(b).is_some() {

0 commit comments

Comments
 (0)