Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented beds #606

Open
wants to merge 63 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 53 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
3346de4
explosion/explosion.go: Third attempt at implementing explosions.
T14Raptor Jul 12, 2022
800702d
Merge remote-tracking branch 'origin/master' into feature/explosions
T14Raptor Jul 14, 2022
b172c4d
"Explodable" api
T14Raptor Jul 14, 2022
11882b2
Moved explosions to block package
T14Raptor Jul 14, 2022
61f945c
Merge branch 'master' into feature/explosions
JustTalDevelops Jul 15, 2022
4a3db7d
Merge remote-tracking branch 'origin/master' into feature/explosions
JustTalDevelops Jul 15, 2022
c8c1965
improvements
T14Raptor Jul 15, 2022
fd081cf
block: Added blast resistances for each block.
JustTalDevelops Jul 15, 2022
4da01aa
Merge remote-tracking branch 'origin/feature/explosions' into feature…
JustTalDevelops Jul 15, 2022
f0886fb
block/break_info.go: Improve doc.
JustTalDevelops Jul 15, 2022
a134491
Update server/block/explosion.go
JustTalDevelops Jul 15, 2022
489570f
block/explosion.go: Use `box` for consistency.
JustTalDevelops Jul 15, 2022
b982885
Merge remote-tracking branch 'origin/feature/explosions' into feature…
JustTalDevelops Jul 15, 2022
97b9cf6
block/break_info.go: Don't multiply hardness by 5.
T14Raptor Jul 15, 2022
83e7e71
Merge remote-tracking branch 'origin/feature/explosions' into feature…
T14Raptor Jul 15, 2022
294f673
block/break_info.go: Correct doc.
T14Raptor Jul 15, 2022
020bf23
block/explosion.go: Fix SpawnFire logic.
JustTalDevelops Jul 15, 2022
c026aa5
damage/source.go: Doc SourceExplosion.
JustTalDevelops Jul 15, 2022
011b7f4
player/player.go: Implement ExplodableEntity.
T14Raptor Jul 15, 2022
9cd90fe
Merge remote-tracking branch 'origin/feature/explosions' into feature…
T14Raptor Jul 15, 2022
7a9f47a
player/player.go: Directly set velocity.
JustTalDevelops Jul 15, 2022
d6fabcc
player/player.go: Revert "Directly set velocity".
JustTalDevelops Jul 15, 2022
659a0ca
block/explosion.go: Change Radius field back to Size.
T14Raptor Jul 16, 2022
1c01f45
Merge remote-tracking branch 'origin/feature/explosions' into feature…
T14Raptor Jul 16, 2022
e5e5fa9
Fixes
T14Raptor Jul 16, 2022
cc79531
block/explosions.go: Fixed exposure?
T14Raptor Jul 18, 2022
cb9b588
Merge remote-tracking branch 'origin/master' into feature/explosions
T14Raptor Jul 18, 2022
3a4180a
Merge branch 'master' into feature/explosions
JustTalDevelops Jul 26, 2022
c4f7ec8
block/block.go: Blame GitHub!
JustTalDevelops Jul 26, 2022
cb209b1
block/explosion.go: Divide blast resistance by 5.
T14Raptor Jul 26, 2022
c29385b
player/player.go: Fixed explosion knockback when in creative.
T14Raptor Jul 26, 2022
a2c0bfd
Merge branch 'master' into feature/explosions
JustTalDevelops Jul 26, 2022
3d79496
dragonfly: Implemented beds.
JustTalDevelops Jul 27, 2022
7657f9b
Merge branch 'feature/explosions' into feature/beds
JustTalDevelops Jul 27, 2022
f0066e0
player/player.go: Various fixes.
JustTalDevelops Jul 27, 2022
32dfed3
Merge remote-tracking branch 'origin/feature/beds' into feature/beds
JustTalDevelops Jul 27, 2022
1ad385d
player/player.go: Various fixes.
JustTalDevelops Jul 28, 2022
700621a
Merge branch 'master' into feature/beds
DaPigGuy Jul 30, 2022
2f738e4
fix post merge issues
DaPigGuy Jul 30, 2022
2833785
fix post merge issues pt II
DaPigGuy Jul 30, 2022
9267c86
Update server/block/bed.go
JustTalDevelops Jul 30, 2022
7c9edbb
Merge branch 'master' into feature/beds
JustTalDevelops Jul 31, 2022
ed4d6aa
block/bed.go: Various fixes.
JustTalDevelops Jul 31, 2022
fda1e53
player/handler.go: Added HandleSleepReminder.
JustTalDevelops Jul 31, 2022
9fa633d
block/break_info.go: Removed PostBreakable in favour of `withBreakHan…
JustTalDevelops Jul 31, 2022
742e8f6
block/bed.go: Moved to own function.
JustTalDevelops Jul 31, 2022
0b80371
block/bed.go: Implement MaxCounter.
JustTalDevelops Jul 31, 2022
4370276
player/player.go: Potentially fix beds?
JustTalDevelops Jul 31, 2022
cf846ef
player/player.go: Actually fix beds.
JustTalDevelops Jul 31, 2022
d531be3
Update server/block/bed.go
JustTalDevelops Aug 1, 2022
ccc2a0d
Merge remote-tracking branch 'origin/master' into feature/beds
JustTalDevelops Aug 1, 2022
b931883
Merge remote-tracking branch 'origin/feature/beds' into feature/beds
JustTalDevelops Aug 1, 2022
c20ff84
block/bed.go: Use sourceWaterDisplacer.
JustTalDevelops Aug 1, 2022
5159a59
Merge branch 'master' into feature/beds
DaPigGuy Aug 3, 2022
1162229
fix formatting
DaPigGuy Aug 3, 2022
09abef4
block/bed.go: Various improvements.
JustTalDevelops Aug 19, 2022
9d31e87
world/world.go: Allocate a smaller slice of sleepers.
JustTalDevelops Aug 19, 2022
c6983cf
Merge branch 'master' into feature/beds
JustTalDevelops Aug 19, 2022
e4b90d0
Merge branch 'master' into feature/beds
JustTalDevelops Aug 20, 2022
e03b968
Merge branch 'master' into feature/beds
JustTalDevelops Aug 21, 2022
2f24392
Merge branch 'master' into feature/beds
DaPigGuy Dec 16, 2022
7c00325
fix merge issues
DaPigGuy Dec 16, 2022
29b63a9
world/sleep.go: Various improvements.
JustTalDevelops Dec 16, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
232 changes: 232 additions & 0 deletions server/block/bed.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
package block

import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/block/model"
"github.com/df-mc/dragonfly/server/internal/nbtconv"
"github.com/df-mc/dragonfly/server/item"
"github.com/df-mc/dragonfly/server/world"
"github.com/go-gl/mathgl/mgl64"
"github.com/sandertv/gophertunnel/minecraft/text"
)

// Bed is a block, allowing players to sleep to set their spawns and skip the night.
type Bed struct {
transparent
sourceWaterDisplacer

// Colour is the colour of the bed.
Colour item.Colour
// Facing is the direction that the bed is facing.
Facing cube.Direction
// Head is true if the bed is the head side.
Head bool
// User is the user that is using the bed.
User item.User
JustTalDevelops marked this conversation as resolved.
Show resolved Hide resolved
}

// MaxCount always returns 1.
func (Bed) MaxCount() int {
return 1
}

// Model ...
func (Bed) Model() world.BlockModel {
return model.Bed{}
}

// SideClosed ...
func (Bed) SideClosed(cube.Pos, cube.Pos, *world.World) bool {
return false
}

// BreakInfo ...
func (b Bed) BreakInfo() BreakInfo {
return newBreakInfo(0.2, alwaysHarvestable, nothingEffective, oneOf(b)).withBreakHandler(func(pos cube.Pos, w *world.World, _ item.User) {
headSide, _, ok := b.head(pos, w)
if !ok {
return
}
if s, ok := headSide.User.(world.Sleeper); ok {
s.Wake()
}
})
}

// UseOnBlock ...
func (b Bed) UseOnBlock(pos cube.Pos, face cube.Face, _ mgl64.Vec3, w *world.World, user item.User, ctx *item.UseContext) (used bool) {
if pos, _, used = firstReplaceable(w, pos, face, b); !used {
return
}
if _, ok := w.Block(pos.Side(cube.FaceDown)).Model().(model.Solid); !ok {
return
}

b.Facing = user.Facing()

side, sidePos := b, pos.Side(b.Facing.Face())
side.Head = true

if !replaceableWith(w, sidePos, side) {
return
}
if _, ok := w.Block(sidePos.Side(cube.FaceDown)).Model().(model.Solid); !ok {
return
}

ctx.IgnoreBBox = true
place(w, sidePos, side, user, ctx)
place(w, pos, b, user, ctx)
return placed(ctx)
}

// Activate ...
func (b Bed) Activate(pos cube.Pos, _ cube.Face, w *world.World, u item.User, _ *item.UseContext) bool {
s, ok := u.(world.Sleeper)
if !ok {
return false
}

if w.Dimension() != world.Overworld {
w.SetBlock(pos, nil, nil)
ExplosionConfig{
Size: 5,
SpawnFire: true,
}.Explode(w, pos.Vec3Centre())
return true
}

_, sidePos, ok := b.side(pos, w)
if !ok {
return false
}

userPos := s.Position()
if sidePos.Vec3Middle().Sub(userPos).Len() > 4 && pos.Vec3Middle().Sub(userPos).Len() > 4 {
s.Messaget(text.Colourf("<grey>%s</grey>", "%tile.bed.tooFar"))
JustTalDevelops marked this conversation as resolved.
Show resolved Hide resolved
return true
}

headSide, headPos, ok := b.head(pos, w)
JustTalDevelops marked this conversation as resolved.
Show resolved Hide resolved
if !ok {
return false
}
if _, ok = w.Liquid(headPos); ok {
return false
}

w.SetPlayerSpawn(s.UUID(), headPos)

time := w.Time() % world.TimeFull
if (time < world.TimeNight || time >= world.TimeSunrise) && !w.ThunderingAt(pos) {
s.Messaget(text.Colourf("<grey>%s</grey>", "%tile.bed.respawnSet"))
s.Messaget(text.Colourf("<grey>%s</grey>", "%tile.bed.noSleep"))
JustTalDevelops marked this conversation as resolved.
Show resolved Hide resolved
return true
}
if headSide.User != nil {
s.Messaget(text.Colourf("<grey>%s</grey>", "%tile.bed.respawnSet"))
s.Messaget(text.Colourf("<grey>%s</grey>", "%tile.bed.occupied"))
JustTalDevelops marked this conversation as resolved.
Show resolved Hide resolved
return true
}

s.Sleep(headPos)
return true
}

// EntityLand ...
func (b Bed) EntityLand(_ cube.Pos, _ *world.World, e world.Entity) {
JustTalDevelops marked this conversation as resolved.
Show resolved Hide resolved
if s, ok := e.(sneakingEntity); ok && s.Sneaking() {
// If the entity is sneaking, the fall distance and velocity stay the same.
return
}
if f, ok := e.(fallDistanceEntity); ok {
f.SetFallDistance(f.FallDistance() * 0.5)
}
if v, ok := e.(velocityEntity); ok {
vel := v.Velocity()
vel[1] = vel[1] * -3 / 4
v.SetVelocity(vel)
}
}

// sneakingEntity represents an entity that can sneak.
type sneakingEntity interface {
// Sneaking returns true if the entity is currently sneaking.
Sneaking() bool
}

// velocityEntity represents an entity that can maintain a velocity.
type velocityEntity interface {
// Velocity returns the current velocity of the entity.
Velocity() mgl64.Vec3
// SetVelocity sets the velocity of the entity.
SetVelocity(mgl64.Vec3)
}

// NeighbourUpdateTick ...
func (b Bed) NeighbourUpdateTick(pos, _ cube.Pos, w *world.World) {
if _, _, ok := b.side(pos, w); !ok {
w.SetBlock(pos, nil, nil)
}
}

// EncodeItem ...
func (b Bed) EncodeItem() (name string, meta int16) {
return "minecraft:bed", int16(b.Colour.Uint8())
}

// EncodeBlock ...
func (b Bed) EncodeBlock() (name string, properties map[string]interface{}) {
return "minecraft:bed", map[string]interface{}{
"facing_bit": int32(horizontalDirection(b.Facing)),
"occupied_bit": boolByte(b.User != nil),
"head_bit": boolByte(b.Head),
}
}

// EncodeNBT ...
func (b Bed) EncodeNBT() map[string]interface{} {
return map[string]interface{}{
"id": "Bed",
"color": b.Colour.Uint8(),
}
}

// DecodeNBT ...
func (b Bed) DecodeNBT(data map[string]interface{}) interface{} {
b.Colour = item.Colours()[nbtconv.Map[uint8](data, "color")]
return b
}

// head returns the head side of the bed. If neither side is a head side, the third return value is false.
func (b Bed) head(pos cube.Pos, w *world.World) (Bed, cube.Pos, bool) {
headSide, headPos, ok := b.side(pos, w)
if !ok {
return Bed{}, cube.Pos{}, false
}
if b.Head {
headSide, headPos = b, pos
}
return headSide, headPos, true
}

// side returns the other side of the bed. If the other side is not a bed, the third return value is false.
func (b Bed) side(pos cube.Pos, w *world.World) (Bed, cube.Pos, bool) {
face := b.Facing.Face()
if b.Head {
face = face.Opposite()
}

sidePos := pos.Side(face)
o, ok := w.Block(sidePos).(Bed)
return o, sidePos, ok
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably check that only one side is the head

Suggested change
return o, sidePos, ok
return o, sidePos, ok && b.Head != o.Head

}

// allBeds returns all possible beds.
func allBeds() (beds []world.Block) {
for _, d := range cube.Directions() {
beds = append(beds, Bed{Facing: d})
beds = append(beds, Bed{Facing: d, Head: true})
}
return
}
9 changes: 9 additions & 0 deletions server/block/break_info.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package block

import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/item"
"github.com/df-mc/dragonfly/server/item/enchantment"
"github.com/df-mc/dragonfly/server/world"
Expand Down Expand Up @@ -83,6 +84,8 @@ type BreakInfo struct {
Effective func(t item.Tool) bool
// Drops is a function called to get the drops of the block if it is broken using the item passed.
Drops func(t item.Tool, enchantments []item.Enchantment) []item.Stack
// BreakHandler is called after the block has broken.
BreakHandler func(pos cube.Pos, w *world.World, u item.User)
// XPDrops is the range of XP a block can drop when broken.
XPDrops XPDropRange
// BlastResistance is the blast resistance of the block, which influences the block's ability to withstand an
Expand Down Expand Up @@ -114,6 +117,12 @@ func (b BreakInfo) withBlastResistance(res float64) BreakInfo {
return b
}

// withBreakHandler sets the BreakHandler field of the BreakInfo struct to the passed value.
func (b BreakInfo) withBreakHandler(handler func(pos cube.Pos, w *world.World, u item.User)) BreakInfo {
b.BreakHandler = handler
return b
}

// XPDropRange holds the min & max XP drop amounts of blocks.
type XPDropRange [2]int

Expand Down
2 changes: 2 additions & 0 deletions server/block/farmland.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ func (f Farmland) EntityLand(pos cube.Pos, w *world.World, e world.Entity, dista
type fallDistanceEntity interface {
// ResetFallDistance resets the entities fall distance.
ResetFallDistance()
// SetFallDistance sets the entities fall distance.
SetFallDistance(float64)
JustTalDevelops marked this conversation as resolved.
Show resolved Hide resolved
// FallDistance returns the entities fall distance.
FallDistance() float64
}
Expand Down
5 changes: 5 additions & 0 deletions server/block/hash.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions server/block/model/bed.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package model

import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)

// Bed is a model used for beds. This model works for both parts of the bed.
type Bed struct{}

func (b Bed) BBox(cube.Pos, *world.World) []cube.BBox {
return []cube.BBox{cube.Box(0, 0, 0, 1, 0.5625, 1)}
}

// FaceSolid ...
func (Bed) FaceSolid(cube.Pos, cube.Face, *world.World) bool {
return false
}
2 changes: 2 additions & 0 deletions server/block/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ func init() {
registerAll(allAnvils())
registerAll(allBarrels())
registerAll(allBasalt())
registerAll(allBeds())
registerAll(allBeetroot())
registerAll(allBlastFurnaces())
registerAll(allBoneBlock())
Expand Down Expand Up @@ -344,6 +345,7 @@ func init() {
world.RegisterItem(Anvil{Type: t})
}
for _, c := range item.Colours() {
world.RegisterItem(Bed{Colour: c})
world.RegisterItem(Carpet{Colour: c})
world.RegisterItem(ConcretePowder{Colour: c})
world.RegisterItem(Concrete{Colour: c})
Expand Down
4 changes: 4 additions & 0 deletions server/player/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ type Handler interface {
// HandleSignEdit handles the player editing a sign. It is called for every keystroke while editing a sign and
// has both the old text passed and the text after the edit. This typically only has a change of one character.
HandleSignEdit(ctx *event.Context, oldText, newText string)
// HandleSleepReminder handles the player broadcasting a sleeping reminder. It is called in vanilla to remind other
// players to sleep in order to advance the day.
HandleSleepReminder(ctx *event.Context)
JustTalDevelops marked this conversation as resolved.
Show resolved Hide resolved
// HandleItemDamage handles the event wherein the item either held by the player or as armour takes
// damage through usage.
// The type of the item may be checked to determine whether it was armour or a tool used. The damage to
Expand Down Expand Up @@ -157,6 +160,7 @@ func (NopHandler) HandleBlockBreak(*event.Context, cube.Pos, *[]item.Stack)
func (NopHandler) HandleBlockPlace(*event.Context, cube.Pos, world.Block) {}
func (NopHandler) HandleBlockPick(*event.Context, cube.Pos, world.Block) {}
func (NopHandler) HandleSignEdit(*event.Context, string, string) {}
func (NopHandler) HandleSleepReminder(*event.Context) {}
func (NopHandler) HandleItemPickup(*event.Context, item.Stack) {}
func (NopHandler) HandleItemUse(*event.Context) {}
func (NopHandler) HandleItemUseOnBlock(*event.Context, cube.Pos, cube.Face, mgl64.Vec3) {}
Expand Down