diff --git a/server/block/block.go b/server/block/block.go index 044f65a81..14287ee21 100644 --- a/server/block/block.go +++ b/server/block/block.go @@ -54,6 +54,14 @@ type LightDiffuser interface { LightDiffusionLevel() uint8 } +// NonSuffocating represents a block that, despite being fully solid, never suffocates an entity standing +// inside it. This is distinct from LightDiffuser: a block may block all light while still being safe to +// stand inside, such as tinted glass. +type NonSuffocating interface { + // SuffocationImmune returns true if the block never causes suffocation damage to entities inside it. + SuffocationImmune() bool +} + // RedstoneWireStepDowner represents a block with custom behaviour for redstone wire providing power when travelling // down it. type RedstoneWireStepDowner interface { diff --git a/server/block/hash.go b/server/block/hash.go index 12c33d96d..a46a00eb5 100644 --- a/server/block/hash.go +++ b/server/block/hash.go @@ -210,6 +210,7 @@ const ( hashSulfurBricks hashTNT hashTerracotta + hashTintedGlass hashTorch hashTuff hashTuffBricks @@ -1055,6 +1056,10 @@ func (Terracotta) Hash() (uint64, uint64) { return hashTerracotta, 0 } +func (TintedGlass) Hash() (uint64, uint64) { + return hashTintedGlass, 0 +} + func (t Torch) Hash() (uint64, uint64) { return hashTorch, uint64(t.Facing) | uint64(t.Type.Uint8())<<3 } diff --git a/server/block/register.go b/server/block/register.go index 4522a98cd..084c586a1 100644 --- a/server/block/register.go +++ b/server/block/register.go @@ -134,6 +134,7 @@ func init() { world.RegisterBlock(PolishedSulfur{}) world.RegisterBlock(TNT{}) world.RegisterBlock(Terracotta{}) + world.RegisterBlock(TintedGlass{}) world.RegisterBlock(Tuff{}) world.RegisterBlock(Tuff{Chiseled: true}) world.RegisterBlock(TuffBricks{}) @@ -429,6 +430,7 @@ func init() { world.RegisterItem(PolishedSulfur{}) world.RegisterItem(TNT{}) world.RegisterItem(Terracotta{}) + world.RegisterItem(TintedGlass{}) world.RegisterItem(Tuff{}) world.RegisterItem(Tuff{Chiseled: true}) world.RegisterItem(TuffBricks{}) diff --git a/server/block/tinted_glass.go b/server/block/tinted_glass.go new file mode 100644 index 000000000..576735bdf --- /dev/null +++ b/server/block/tinted_glass.go @@ -0,0 +1,29 @@ +package block + +// TintedGlass is a decorative, solid block that is visually see-through but, unlike regular glass, blocks +// all light passing through it. +type TintedGlass struct { + solid + clicksAndSticks +} + +// SuffocationImmune always returns true. Tinted glass blocks light entirely but, like regular glass, never +// suffocates an entity standing inside it. +func (TintedGlass) SuffocationImmune() bool { + return true +} + +// BreakInfo ... +func (g TintedGlass) BreakInfo() BreakInfo { + return newBreakInfo(0.3, alwaysHarvestable, nothingEffective, oneOf(g)).withBlastResistance(0.3) +} + +// EncodeItem ... +func (TintedGlass) EncodeItem() (name string, meta int16) { + return "minecraft:tinted_glass", 0 +} + +// EncodeBlock ... +func (TintedGlass) EncodeBlock() (string, map[string]any) { + return "minecraft:tinted_glass", nil +} diff --git a/server/player/player.go b/server/player/player.go index 71953a306..5e58a608b 100644 --- a/server/player/player.go +++ b/server/player/player.go @@ -2844,6 +2844,9 @@ func (p *Player) insideOfSolid() bool { // Transparent. return false } + if immune, ok := b.(block.NonSuffocating); ok && immune.SuffocationImmune() { + return false + } for _, blockBox := range b.Model().BBox(pos, p.tx) { if blockBox.Translate(pos.Vec3()).IntersectsWith(box) { return true