up3
Build and deploy / Build (push) Has been cancelled
Build and deploy / Update Contributors (push) Has been cancelled
Build and deploy / Deploy (push) Has been cancelled
Build and deploy / Build (push) Has been cancelled
Build and deploy / Update Contributors (push) Has been cancelled
Build and deploy / Deploy (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,280 @@
|
||||
package block
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/df-mc/dragonfly/server/block/cube"
|
||||
"github.com/df-mc/dragonfly/server/block/model"
|
||||
"github.com/df-mc/dragonfly/server/internal/sliceutil"
|
||||
"github.com/df-mc/dragonfly/server/item"
|
||||
"github.com/df-mc/dragonfly/server/world"
|
||||
"github.com/go-gl/mathgl/mgl64"
|
||||
"math"
|
||||
)
|
||||
|
||||
// Wall is a block similar to fences that prevents players from jumping over and is thinner than the usual block. It is
|
||||
// available for many blocks and all types connect together as if they were the same type.
|
||||
type Wall struct {
|
||||
transparent
|
||||
sourceWaterDisplacer
|
||||
|
||||
// Block is the block to use for the type of wall.
|
||||
Block world.Block
|
||||
// NorthConnection is the type of connection in the north direction of the post.
|
||||
NorthConnection WallConnectionType
|
||||
// EastConnection is the type of connection in the east direction of the post.
|
||||
EastConnection WallConnectionType
|
||||
// SouthConnection is the type of connection in the south direction of the post.
|
||||
SouthConnection WallConnectionType
|
||||
// WestConnection is the type of connection in the west direction of the post.
|
||||
WestConnection WallConnectionType
|
||||
// Post is if the wall is extended to the full height of a block or not.
|
||||
Post bool
|
||||
}
|
||||
|
||||
// EncodeItem ...
|
||||
func (w Wall) EncodeItem() (string, int16) {
|
||||
name := encodeWallBlock(w.Block)
|
||||
return "minecraft:" + name + "_wall", 0
|
||||
}
|
||||
|
||||
// EncodeBlock ...
|
||||
func (w Wall) EncodeBlock() (string, map[string]any) {
|
||||
properties := map[string]any{
|
||||
"wall_connection_type_north": w.NorthConnection.String(),
|
||||
"wall_connection_type_east": w.EastConnection.String(),
|
||||
"wall_connection_type_south": w.SouthConnection.String(),
|
||||
"wall_connection_type_west": w.WestConnection.String(),
|
||||
"wall_post_bit": boolByte(w.Post),
|
||||
}
|
||||
name := encodeWallBlock(w.Block)
|
||||
return "minecraft:" + name + "_wall", properties
|
||||
}
|
||||
|
||||
// Model ...
|
||||
func (w Wall) Model() world.BlockModel {
|
||||
return model.Wall{
|
||||
NorthConnection: w.NorthConnection.Height(),
|
||||
EastConnection: w.EastConnection.Height(),
|
||||
SouthConnection: w.SouthConnection.Height(),
|
||||
WestConnection: w.WestConnection.Height(),
|
||||
Post: w.Post,
|
||||
}
|
||||
}
|
||||
|
||||
// BreakInfo ...
|
||||
func (w Wall) BreakInfo() BreakInfo {
|
||||
breakable, ok := w.Block.(Breakable)
|
||||
if !ok {
|
||||
panic("wall block is not breakable")
|
||||
}
|
||||
return newBreakInfo(breakable.BreakInfo().Hardness, pickaxeHarvestable, pickaxeEffective, oneOf(w)).withBlastResistance(breakable.BreakInfo().BlastResistance)
|
||||
}
|
||||
|
||||
// NeighbourUpdateTick ...
|
||||
func (w Wall) NeighbourUpdateTick(pos, _ cube.Pos, tx *world.Tx) {
|
||||
w, connectionsUpdated := w.calculateConnections(tx, pos)
|
||||
w, postUpdated := w.calculatePost(tx, pos)
|
||||
if connectionsUpdated || postUpdated {
|
||||
tx.SetBlock(pos, w, nil)
|
||||
}
|
||||
}
|
||||
|
||||
// UseOnBlock ...
|
||||
func (w Wall) UseOnBlock(pos cube.Pos, face cube.Face, _ mgl64.Vec3, tx *world.Tx, user item.User, ctx *item.UseContext) (used bool) {
|
||||
pos, _, used = firstReplaceable(tx, pos, face, w)
|
||||
if !used {
|
||||
return
|
||||
}
|
||||
w, _ = w.calculateConnections(tx, pos)
|
||||
w, _ = w.calculatePost(tx, pos)
|
||||
place(tx, pos, w, user, ctx)
|
||||
return placed(ctx)
|
||||
}
|
||||
|
||||
// SideClosed ...
|
||||
func (Wall) SideClosed(cube.Pos, cube.Pos, *world.Tx) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// ConnectionType returns the connection type of the wall in the given direction.
|
||||
func (w Wall) ConnectionType(direction cube.Direction) WallConnectionType {
|
||||
switch direction {
|
||||
case cube.North:
|
||||
return w.NorthConnection
|
||||
case cube.East:
|
||||
return w.EastConnection
|
||||
case cube.South:
|
||||
return w.SouthConnection
|
||||
case cube.West:
|
||||
return w.WestConnection
|
||||
}
|
||||
panic("unknown direction")
|
||||
}
|
||||
|
||||
// WithConnectionType returns the wall with the given connection type in the given direction.
|
||||
func (w Wall) WithConnectionType(direction cube.Direction, connection WallConnectionType) Wall {
|
||||
switch direction {
|
||||
case cube.North:
|
||||
w.NorthConnection = connection
|
||||
case cube.East:
|
||||
w.EastConnection = connection
|
||||
case cube.South:
|
||||
w.SouthConnection = connection
|
||||
case cube.West:
|
||||
w.WestConnection = connection
|
||||
}
|
||||
return w
|
||||
}
|
||||
|
||||
// calculateConnections calculates the correct connections for the wall at a given position in a world. The updated wall
|
||||
// is returned and a bool to determine if any changes were made.
|
||||
func (w Wall) calculateConnections(tx *world.Tx, pos cube.Pos) (Wall, bool) {
|
||||
var updated bool
|
||||
abovePos := pos.Add(cube.Pos{0, 1, 0})
|
||||
above := tx.Block(abovePos)
|
||||
for _, face := range cube.HorizontalFaces() {
|
||||
sidePos := pos.Side(face)
|
||||
side := tx.Block(sidePos)
|
||||
// A wall can only connect to a block if the side is solid, with the only exception being thin blocks (such as
|
||||
// glass panes and iron bars) as well as the sides of fence gates.
|
||||
connected := side.Model().FaceSolid(sidePos, face.Opposite(), tx)
|
||||
if !connected {
|
||||
if _, ok := tx.Block(sidePos).(Wall); ok {
|
||||
connected = true
|
||||
} else if gate, ok := tx.Block(sidePos).(WoodFenceGate); ok {
|
||||
connected = gate.Facing.Face().Axis() != face.Axis()
|
||||
} else if _, ok := tx.Block(sidePos).Model().(model.Thin); ok {
|
||||
connected = true
|
||||
}
|
||||
}
|
||||
var connectionType WallConnectionType
|
||||
if connected {
|
||||
// If the wall is connected to the side, it has the possibility of having a tall connection. This is
|
||||
// calculated by checking for any overlapping blocks in the area of the connection.
|
||||
connectionType = ShortWallConnection()
|
||||
boxes := above.Model().BBox(abovePos, tx)
|
||||
for _, bb := range boxes {
|
||||
if bb.Min().Y() == 0 {
|
||||
xOverlap := bb.Min().X() < 0.75 && bb.Max().X() > 0.25
|
||||
zOverlap := bb.Min().Z() < 0.75 && bb.Max().Z() > 0.25
|
||||
var tall bool
|
||||
switch face {
|
||||
case cube.FaceNorth:
|
||||
tall = xOverlap && bb.Max().Z() > 0.75
|
||||
case cube.FaceEast:
|
||||
tall = bb.Min().X() < 0.25 && zOverlap
|
||||
case cube.FaceSouth:
|
||||
tall = xOverlap && bb.Min().Z() < 0.25
|
||||
case cube.FaceWest:
|
||||
tall = bb.Max().X() > 0.75 && zOverlap
|
||||
}
|
||||
if tall {
|
||||
connectionType = TallWallConnection()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if w.ConnectionType(face.Direction()) != connectionType {
|
||||
updated = true
|
||||
w = w.WithConnectionType(face.Direction(), connectionType)
|
||||
}
|
||||
}
|
||||
return w, updated
|
||||
}
|
||||
|
||||
// calculatePost calculates the correct post bit for the wall at a given position in a world. The updated wall is
|
||||
// returned and a bool to determine if any changes were made.
|
||||
func (w Wall) calculatePost(tx *world.Tx, pos cube.Pos) (Wall, bool) {
|
||||
var updated bool
|
||||
abovePos := pos.Add(cube.Pos{0, 1, 0})
|
||||
above := tx.Block(abovePos)
|
||||
connections := len(sliceutil.Filter(cube.HorizontalFaces(), func(face cube.Face) bool {
|
||||
return w.ConnectionType(face.Direction()) != NoWallConnection()
|
||||
}))
|
||||
var post bool
|
||||
switch above := above.(type) {
|
||||
case Lantern:
|
||||
// Lanterns only make a wall become a post when placed on the wall and not hanging from above.
|
||||
post = !above.Hanging
|
||||
case Sign:
|
||||
// Signs only make a wall become a post when placed on the wall and not placed on the side of a block.
|
||||
post = !above.Attach.hanging
|
||||
case Torch:
|
||||
// Torches only make a wall become a post when placed on the wall and not placed on the side of a block.
|
||||
post = above.Facing == cube.FaceDown
|
||||
case WoodTrapdoor:
|
||||
// Trapdoors only make a wall become a post when they are opened and not closed and above a connection.
|
||||
if above.Open {
|
||||
switch above.Facing {
|
||||
case cube.North:
|
||||
post = w.NorthConnection != NoWallConnection()
|
||||
case cube.East:
|
||||
post = w.EastConnection != NoWallConnection()
|
||||
case cube.South:
|
||||
post = w.SouthConnection != NoWallConnection()
|
||||
case cube.West:
|
||||
post = w.WestConnection != NoWallConnection()
|
||||
}
|
||||
}
|
||||
case Wall:
|
||||
// A wall only make a wall become a post if it is a post itself.
|
||||
post = above.Post
|
||||
}
|
||||
if !post {
|
||||
// If a wall has two connections that are in different axis then it becomes a post regardless of the above block.
|
||||
if connections < 2 {
|
||||
post = true
|
||||
} else {
|
||||
switch {
|
||||
case w.NorthConnection != NoWallConnection() && w.SouthConnection != NoWallConnection():
|
||||
post = w.EastConnection != NoWallConnection() || w.WestConnection != NoWallConnection()
|
||||
case w.EastConnection != NoWallConnection() && w.WestConnection != NoWallConnection():
|
||||
post = w.NorthConnection != NoWallConnection() || w.SouthConnection != NoWallConnection()
|
||||
default:
|
||||
post = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if w.Post != post {
|
||||
updated = true
|
||||
w.Post = post
|
||||
}
|
||||
return w, updated
|
||||
}
|
||||
|
||||
// allWalls returns a list of all wall types.
|
||||
func allWalls() (walls []world.Block) {
|
||||
for _, block := range WallBlocks() {
|
||||
if _, hash := block.Hash(); hash > math.MaxUint16 {
|
||||
name, _ := block.EncodeBlock()
|
||||
panic(fmt.Errorf("hash of block %s exceeds 16 bytes", name))
|
||||
}
|
||||
for _, north := range WallConnectionTypes() {
|
||||
for _, east := range WallConnectionTypes() {
|
||||
for _, south := range WallConnectionTypes() {
|
||||
for _, west := range WallConnectionTypes() {
|
||||
walls = append(walls, Wall{
|
||||
Block: block,
|
||||
NorthConnection: north,
|
||||
EastConnection: east,
|
||||
SouthConnection: south,
|
||||
WestConnection: west,
|
||||
Post: false,
|
||||
})
|
||||
walls = append(walls, Wall{
|
||||
Block: block,
|
||||
NorthConnection: north,
|
||||
EastConnection: east,
|
||||
SouthConnection: south,
|
||||
WestConnection: west,
|
||||
Post: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user