Skip to content

Commit

Permalink
player/player.go and item/goat_horn.go: Create a new transaction in t…
Browse files Browse the repository at this point in the history
…ime.AfterFunc. These instances are no longer permitted.
  • Loading branch information
Sandertv committed Nov 22, 2024
1 parent 47b1fb8 commit edae343
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 26 deletions.
33 changes: 19 additions & 14 deletions server/item/goat_horn.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,29 @@ func (GoatHorn) Cooldown() time.Duration {
func (g GoatHorn) Use(tx *world.Tx, user User, ctx *UseContext) bool {
tx.PlaySound(user.Position(), sound.GoatHorn{Horn: g.Type})
time.AfterFunc(time.Second, func() {
if !user.UsingItem() {
// We aren't using the goat horn anymore.
return
}

held, _ := user.HeldItems()
if _, ok := held.Item().(GoatHorn); !ok {
// We aren't holding the goat horn anymore.
return
}

// The goat horn is forcefully released by the server after a second. If the client released the item itself,
// before a second, this shouldn't do anything.
user.ReleaseItem()
user.H().ExecWorld(g.releaseItem)
})
return true
}

// releaseItem releases the goat horn item if a user is still using it.
func (g GoatHorn) releaseItem(_ *world.Tx, e world.Entity) {
user := e.(User)
if !user.UsingItem() {
// We aren't using the goat horn anymore.
return
}
held, _ := user.HeldItems()
if _, ok := held.Item().(GoatHorn); !ok {
// We aren't holding the goat horn anymore.
return
}
// The goat horn is forcefully released by the server after a second. If the
// client released the item itself, before a second, this shouldn't do
// anything.
user.ReleaseItem()
}

// EncodeItem ...
func (g GoatHorn) EncodeItem() (name string, meta int16) {
return "minecraft:goat_horn", int16(g.Type.Uint8())
Expand Down
32 changes: 20 additions & 12 deletions server/player/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -802,22 +802,30 @@ func (p *Player) kill(src world.DamageSource) {

p.deathPos, p.deathDimension = &pos, p.tx.World().Dimension()

// Wait a little before removing the entity. The client displays a death animation while the player is dying.
// Wait a little before removing the entity. The client displays a death
// animation while the player is dying.
time.AfterFunc(time.Millisecond*1100, func() {
if p.session() == session.Nop {
_ = p.Close()
return
}
if p.Dead() {
p.SetInvisible()
// We have an actual client connected to this player: We change its position server side so that in
// the future, the client won't respawn on the death location when disconnecting. The client should
// not see the movement itself yet, though.
p.data.Pos = p.tx.World().Spawn().Vec3()
}
p.H().ExecWorld(finishDying)
})
}

// finishDying completes the death of a player, removing it from the world.
func finishDying(_ *world.Tx, e world.Entity) {
p := e.(*Player)
if p.session() == session.Nop {
_ = p.Close()
return
}
if p.Dead() {
p.SetInvisible()
// We have an actual client connected to this player: We change its
// position server side so that in the future, the client won't respawn
// on the death location when disconnecting. The client should not see
// the movement itself yet, though.
p.data.Pos = p.tx.World().Spawn().Vec3()
}
}

// dropItems drops all items and experience of the Player on the ground in random directions.
func (p *Player) dropItems() {
pos := p.Position()
Expand Down

0 comments on commit edae343

Please sign in to comment.